Add bilingual description fields (description_de, description_en)

Species and Cultivar structs + SQL queries now support separate
German and English descriptions for the language toggle feature.
This commit is contained in:
2026-03-15 12:56:59 +01:00
parent e9978f09f4
commit efa05b2d44
3 changed files with 58 additions and 42 deletions
+26 -22
View File
@@ -118,7 +118,8 @@ pub async fn create(pool: &PgPool, req: &CreateCultivar) -> Result<Cultivar> {
sqlx::query_as::<_, Cultivar>(
"INSERT INTO cultivars (id, slug, species_id, name, name_en, name_de, name_scientific,
description, is_organic, perennial, growing_time_days, planting_depth_cm, row_spacing_cm,
description, description_de, description_en,
is_organic, perennial, growing_time_days, planting_depth_cm, row_spacing_cm,
plant_spacing_cm, days_to_germination, germination_temp_c, light_requirement,
stratification_required, stratification_days, scarification_required,
seed_viability_years, storage_temp_c, storage_humidity, storage_notes,
@@ -134,14 +135,15 @@ pub async fn create(pool: &PgPool, req: &CreateCultivar) -> Result<Cultivar> {
pollination_group, self_fertile, rootstock_compatibility,
wikidata_qid, gbif_id, pfaf_url, source_urls)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,
$21,$22,$23,$24,$25,$26,$27,$28,$29::frost_tolerance,$30,$31,$32,$33,$34,$35,
$36,$37,$38,$39,$40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,
$55,$56,$57,$58,$59,$60,$61)
$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31::frost_tolerance,$32,$33,$34,$35,$36,$37,
$38,$39,$40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,
$57,$58,$59,$60,$61,$62,$63)
RETURNING *"
)
.bind(id).bind(&slug).bind(req.species_id).bind(&req.name)
.bind(&req.name_en).bind(&req.name_de).bind(&req.name_scientific)
.bind(&req.description).bind(req.is_organic.unwrap_or(false)).bind(req.perennial.unwrap_or(false))
.bind(&req.description).bind(&req.description_de).bind(&req.description_en)
.bind(req.is_organic.unwrap_or(false)).bind(req.perennial.unwrap_or(false))
.bind(req.growing_time_days).bind(req.planting_depth_cm).bind(req.row_spacing_cm)
.bind(req.plant_spacing_cm).bind(req.days_to_germination).bind(req.germination_temp_c)
.bind(&req.light_requirement).bind(req.stratification_required).bind(req.stratification_days)
@@ -180,27 +182,29 @@ pub async fn update(pool: &PgPool, id: Uuid, req: &CreateCultivar) -> Result<Cul
sqlx::query_as::<_, Cultivar>(
"UPDATE cultivars SET slug=$2, species_id=$3, name=$4, name_en=$5, name_de=$6,
name_scientific=$7, description=$8, is_organic=$9, perennial=$10,
growing_time_days=$11, planting_depth_cm=$12, row_spacing_cm=$13, plant_spacing_cm=$14,
days_to_germination=$15, germination_temp_c=$16, light_requirement=$17,
stratification_required=$18, stratification_days=$19, scarification_required=$20,
seed_viability_years=$21, storage_temp_c=$22, storage_humidity=$23, storage_notes=$24,
min_temp=$25, max_temp=$26, humidity=$27, light=$28, frost_tolerance=$29::frost_tolerance,
min_light_hours_day=$30, optimal_light_hours_day=$31, greenhouse_min_temp_c=$32,
indoor_season_extension_weeks=$33, ventilation_requirement=$34, heating_required=$35,
indoor_sowing_months=$36, direct_sowing_months=$37, transplanting_months=$38,
glasshouse_months=$39, harvesting_months=$40, succession_planting_days=$41,
planting_notes=$42, propagation_methods=$43, cutting_season=$44,
rootstock_species_id=$45, years_to_first_harvest=$46, productive_lifespan_years=$47,
expected_yield_kg_per_m2=$48, yield_unit=$49, expected_yield_value=$50,
harvest_window_days=$51, storage_method=$52, shelf_life_days=$53, cold_storage_days=$54,
pollination_group=$55, self_fertile=$56, rootstock_compatibility=$57,
wikidata_qid=$58, gbif_id=$59, pfaf_url=$60, source_urls=$61, updated_at=NOW()
name_scientific=$7, description=$8, description_de=$9, description_en=$10,
is_organic=$11, perennial=$12,
growing_time_days=$13, planting_depth_cm=$14, row_spacing_cm=$15, plant_spacing_cm=$16,
days_to_germination=$17, germination_temp_c=$18, light_requirement=$19,
stratification_required=$20, stratification_days=$21, scarification_required=$22,
seed_viability_years=$23, storage_temp_c=$24, storage_humidity=$25, storage_notes=$26,
min_temp=$27, max_temp=$28, humidity=$29, light=$30, frost_tolerance=$31::frost_tolerance,
min_light_hours_day=$32, optimal_light_hours_day=$33, greenhouse_min_temp_c=$34,
indoor_season_extension_weeks=$35, ventilation_requirement=$36, heating_required=$37,
indoor_sowing_months=$38, direct_sowing_months=$39, transplanting_months=$40,
glasshouse_months=$41, harvesting_months=$42, succession_planting_days=$43,
planting_notes=$44, propagation_methods=$45, cutting_season=$46,
rootstock_species_id=$47, years_to_first_harvest=$48, productive_lifespan_years=$49,
expected_yield_kg_per_m2=$50, yield_unit=$51, expected_yield_value=$52,
harvest_window_days=$53, storage_method=$54, shelf_life_days=$55, cold_storage_days=$56,
pollination_group=$57, self_fertile=$58, rootstock_compatibility=$59,
wikidata_qid=$60, gbif_id=$61, pfaf_url=$62, source_urls=$63, updated_at=NOW()
WHERE id=$1 RETURNING *"
)
.bind(id).bind(&slug).bind(req.species_id).bind(&req.name)
.bind(&req.name_en).bind(&req.name_de).bind(&req.name_scientific)
.bind(&req.description).bind(req.is_organic.unwrap_or(false)).bind(req.perennial.unwrap_or(false))
.bind(&req.description).bind(&req.description_de).bind(&req.description_en)
.bind(req.is_organic.unwrap_or(false)).bind(req.perennial.unwrap_or(false))
.bind(req.growing_time_days).bind(req.planting_depth_cm).bind(req.row_spacing_cm)
.bind(req.plant_spacing_cm).bind(req.days_to_germination).bind(req.germination_temp_c)
.bind(&req.light_requirement).bind(req.stratification_required).bind(req.stratification_days)
+8
View File
@@ -71,6 +71,8 @@ pub struct Species {
pub name_en: Option<String>,
pub name_de: Option<String>,
pub description: Option<String>,
pub description_de: Option<String>,
pub description_en: Option<String>,
pub soil_moisture: Option<String>,
pub drainage_requirement: Option<String>,
pub organic_matter_pct: Option<f64>,
@@ -147,6 +149,8 @@ pub struct CreateSpecies {
pub name_en: Option<String>,
pub name_de: Option<String>,
pub description: Option<String>,
pub description_de: Option<String>,
pub description_en: Option<String>,
pub soil_moisture: Option<String>,
pub drainage_requirement: Option<String>,
pub ph_min: Option<f64>,
@@ -212,6 +216,8 @@ pub struct Cultivar {
pub name_de: Option<String>,
pub name_scientific: Option<String>,
pub description: Option<String>,
pub description_de: Option<String>,
pub description_en: Option<String>,
pub is_organic: bool,
pub perennial: bool,
pub growing_time_days: Option<i32>,
@@ -278,6 +284,8 @@ pub struct CreateCultivar {
pub name_de: Option<String>,
pub name_scientific: Option<String>,
pub description: Option<String>,
pub description_de: Option<String>,
pub description_en: Option<String>,
pub is_organic: Option<bool>,
pub perennial: Option<bool>,
pub growing_time_days: Option<i32>,
+24 -20
View File
@@ -102,6 +102,7 @@ pub async fn create(pool: &PgPool, req: &CreateSpecies) -> Result<Species> {
sqlx::query_as::<_, Species>(
"INSERT INTO species (id, slug, family_id, name_scientific, name_en, name_de, description,
description_de, description_en,
soil_moisture, drainage_requirement, ph_min, ph_max, soil_texture_preference,
hardiness_zone_usda, hardiness_zone_at, min_temp, max_temp,
drought_tolerance, salt_tolerance, edibility_rating,
@@ -114,15 +115,16 @@ pub async fn create(pool: &PgPool, req: &CreateSpecies) -> Result<Species> {
butterfly_moth_count, caterpillar_host_count, caterpillar_specialist_count,
hoverfly_count, beetle_count, bird_count, mammal_count,
native_status, naturadb_tags)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,
$17,$18,$19,$20,$21,$22,$23,
$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,
$37,$38,$39,$40,$41,$42,$43,
$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,
$19,$20,$21,$22,$23,$24,$25,
$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,
$39,$40,$41,$42,$43,$44,$45,
$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,$57,$58)
RETURNING *"
)
.bind(id).bind(&slug).bind(req.family_id).bind(&req.name_scientific)
.bind(&req.name_en).bind(&req.name_de).bind(&req.description)
.bind(&req.description_de).bind(&req.description_en)
.bind(&req.soil_moisture).bind(&req.drainage_requirement)
.bind(req.ph_min).bind(req.ph_max).bind(&req.soil_texture_preference)
.bind(&req.hardiness_zone_usda).bind(&req.hardiness_zone_at)
@@ -158,26 +160,28 @@ pub async fn update(pool: &PgPool, id: Uuid, req: &CreateSpecies) -> Result<Spec
sqlx::query_as::<_, Species>(
"UPDATE species SET slug=$2, family_id=$3, name_scientific=$4, name_en=$5, name_de=$6,
description=$7, soil_moisture=$8, drainage_requirement=$9, ph_min=$10, ph_max=$11,
soil_texture_preference=$12, hardiness_zone_usda=$13, hardiness_zone_at=$14,
min_temp=$15, max_temp=$16,
drought_tolerance=$17, salt_tolerance=$18,
edibility_rating=$19, food_uses=$20, medicinal_uses=$21, other_uses=$22,
native_range=$23, invasiveness=$24, pollination_type=$25,
plant_layer=$26, nitrogen_fixer=$27, dynamic_accumulator=$28,
dynamic_accumulator_nutrients=$29, attracts_pollinators=$30, attracts_beneficial_insects=$31,
wildlife_value=$32, mulch_plant=$33, ground_cover_quality=$34, allelopathic=$35,
guild_role=$36, succession_stage=$37, heavy_metal_tolerance=$38,
wikidata_qid=$39, gbif_id=$40, eppo_code=$41, pfaf_url=$42, source_urls=$43,
nectar_value=$44, pollen_value=$45, wild_bee_count=$46, wild_bee_specialist_count=$47,
butterfly_moth_count=$48, caterpillar_host_count=$49, caterpillar_specialist_count=$50,
hoverfly_count=$51, beetle_count=$52, bird_count=$53, mammal_count=$54,
native_status=$55, naturadb_tags=$56,
description=$7, description_de=$8, description_en=$9,
soil_moisture=$10, drainage_requirement=$11, ph_min=$12, ph_max=$13,
soil_texture_preference=$14, hardiness_zone_usda=$15, hardiness_zone_at=$16,
min_temp=$17, max_temp=$18,
drought_tolerance=$19, salt_tolerance=$20,
edibility_rating=$21, food_uses=$22, medicinal_uses=$23, other_uses=$24,
native_range=$25, invasiveness=$26, pollination_type=$27,
plant_layer=$28, nitrogen_fixer=$29, dynamic_accumulator=$30,
dynamic_accumulator_nutrients=$31, attracts_pollinators=$32, attracts_beneficial_insects=$33,
wildlife_value=$34, mulch_plant=$35, ground_cover_quality=$36, allelopathic=$37,
guild_role=$38, succession_stage=$39, heavy_metal_tolerance=$40,
wikidata_qid=$41, gbif_id=$42, eppo_code=$43, pfaf_url=$44, source_urls=$45,
nectar_value=$46, pollen_value=$47, wild_bee_count=$48, wild_bee_specialist_count=$49,
butterfly_moth_count=$50, caterpillar_host_count=$51, caterpillar_specialist_count=$52,
hoverfly_count=$53, beetle_count=$54, bird_count=$55, mammal_count=$56,
native_status=$57, naturadb_tags=$58,
updated_at=NOW()
WHERE id=$1 RETURNING *"
)
.bind(id).bind(&slug).bind(req.family_id).bind(&req.name_scientific)
.bind(&req.name_en).bind(&req.name_de).bind(&req.description)
.bind(&req.description_de).bind(&req.description_en)
.bind(&req.soil_moisture).bind(&req.drainage_requirement)
.bind(req.ph_min).bind(req.ph_max).bind(&req.soil_texture_preference)
.bind(&req.hardiness_zone_usda).bind(&req.hardiness_zone_at)