Files
Cibello-app/docs/20-internationalisering.md
T
2026-08-05 19:21:11 +07:00

15 KiB
Raw Blame History

Del 20 Internationalisering: audit, målarkitektur & migreringsplan

Styrande spec: den uppladdade i18n-specifikationen (*_Internationalisering_Claude.md). Detta dokument är den audit + plan som i18n-spec §34 kräver före implementation, samt kvitto på vad som redan är genomfört. Status: klart · 🔨 genomfört i denna leverans · 📋 planerat (fas angiven).

1. Nulägesrapport (audit av kodbasen)

Redan korrekt (byggt språkneutralt från start)

Område i18n-spec Läge
Interna enums (måltid, kök, diet, plats, svårighet, notistyp, plan, creator-nivå …) §4, §16 Engelska maskinidentifierare överallt (dinner, fridge, vegetarian)
Canonical ingredient-IDs §12 Engelska slugs (chicken_breast); aliases[] finns; nameSv/nameEn-kolumner
Ingrediensdensitet §10 density_g_per_ml + grams_per_piece per ingrediens; generell volym↔massa-konvertering vägrar utan densitet (returnerar null)
Nutrition canonical per 100 g + provenance §19 (kJ + natrium/salt-profiler 📋 fas i7)
Allergener som canonical IDs, deterministiska §18 (marknadsregler/visningsprofiler 📋 fas i7)
Högtider datadrivna med market-kod + datumregler §17 season_events(market, date_rule, lead_days …) uppfyller market_events-syftet
Datum: timestamps UTC (timestamptz), bäst före som lokalt kalenderdatum (date) §21
AI: canonical separerat från displaytext i kontrakten (canonicalIngredientId + detectedName) §22, §30
Minne: strukturerad value + key, inte fritextsanning §23 delvis (summarySv finns som cache renderas om vid språkbyte 📋 fas i6)
Recept: struktur (ingrediens-IDs, mängder, tider, temperaturer, DNA) skild från text §13 struktur; översättningstabeller 📋 fas i5
Varumärket som konfiguration §28 🔨 brand.config.json enda platsen; kod svep-verifierad
Store-produkt-IDs språkneutrala §25 🔨 household_monthly m.fl., härledda ur brand-config

Avvikelser som åtgärdas i DENNA leverans (🔨)

  1. Enhetskoder var svenska (msk, tsk, krm, dl, st, portion) brott mot §11. Åtgärd: språkneutrala koder GRAM, KILOGRAM, MILLILITER, DECILITER, LITER, TEASPOON, TABLESPOON, CUP_US, FLUID_OUNCE_US, OUNCE, POUND, COUNT, PORTION, PINCH, SLICE, CLOVE, CAN, PACKAGE i enum/DB/motorer/seed/API/app. Dokumenterad standard (§10): TEASPOON=5 ml, TABLESPOON=15 ml (metrisk), CUP_US=236,59 ml, FL_OZ_US=29,57 ml, OUNCE=28,35 g, POUND=453,59 g, PINCH≈0,5 ml. krm i svenska recept = 1 ml → lagras som MILLILITER; svensk visning ("krm", "msk") sker via översättningslagret.
  2. UserLocalePreferences saknades (§6): ny tabell user_locale_preferences (languageTag BCP 47, regionCode ISO 3166-1, timeZone IANA, measurementSystem METRIC/US_CUSTOMARY/MIXED, temperatureUnit, currencyCode ISO 4217, firstDayOfWeek, use24HourTime) + GET/PATCH /v1/me/locale-preferences; språk ≠ region ≠ enheter.
  3. AAMOS-anrop saknade full lokaliseringskontext (§22): kuvertets metadata har nu localeContext (languageTag, regionCode, timeZone, measurementSystem, temperatureUnit, currencyCode) och skickas från API/worker.
  4. Hårdkodade UI-texter i mobilappen utanför i18n-modulen (§7): options-/etikett- kartor (onboarding, samtycken, måltidstyper, butiksavdelningar, enhetsetiketter, Alert-rubriker) flyttade till översättningsnycklar; t() injicerar {brand}.
  5. Notiser sparade endast färdig text (§26): notifications har nu template_key, variables, locale; renderad text behålls som cache och renderas om vid utskick.
  6. Namnet i koden (§28): all kod avvarumärkad paketscope @app/*, UI via {brand}, tjänste-/könamn ur brand-slug, neutrala standardvärden i config.

Status M1M10

Fas Status Verifiering
M1 Genomförd Alla pengakolumner *_minor (integer) + households.currency_code; E2E: budget i minor + valuta, receptfilter på minor-kostnad
M2 Genomförd ingredient_translations (101 en-rader seedade ur nameEn) + unit_translations (36 rader sv+en) + /v1/i18n/units; en-sök träffar översättningar
M3 Genomförd recipe_translations + recipe_step_translations; TRANSLATE_RECIPE-jobb → deterministisk verifiering (stegantal, bevarade tal, konfidens) → admin publicerar; E2E: en-användare får översatt titel/steg/ingrediensnamn med sv-fallback
M4 Genomförd i18next med Intl-plural (_one/_other), locales/{sv,en}/common.json (175 nycklar, paritetstestad), språkbyte utan omstart (versionsbaserad re-mount), språkval i profilen synkat mot locale-preferenser
M5 Genomförd displayQuantity i shared-types (METRIC/US_CUSTOMARY/MIXED, kvartsavrundning för cups/tsp, ≈-märkning); mobilens formatQuantity konverterar per användarens måttsystem; 15 tester
M6 Genomförd nutrition_display_profiles + allergen_market_rules seedade (EU/SE/GB 14, US 9, CA 12) + /v1/i18n/nutrition-profile med EU-fallback; kJ- och natrium↔salt-hjälpare med tester
M7 Genomförd unaccent + pg_trgm + trigramindex (skapas idempotent i migrate, master-varianten i create-database.sql); sök: "creme"→Crème fraiche, "jordgubar"→Jordgubbar
M8 📋 Kvar (ops) Store-metadata, skärmbilder och prissättning per marknad görs i butikskonsolerna inför lansering produkt-ID:n redan varumärkes- och språkneutrala
M9 📋 Kvar (beslut D-024) Adminpanelen förblir svensk tills internationell ops finns
M10 Genomförd buildMemoryOverview(items, languageTag): rubriker per språk, deterministisk summary-rendering ur strukturerad value med sv-fallback; nya minnen får lokaliserad summary via localeContext

Ursprunglig plan (behålls som referens)

# Åtgärd i18n-spec Fas Kommentar
M1 Pengar i minor units + valuta: alla *_sek-kolumner → *_minor int + currency_code (hushållsnivå), Money-typ i API §20 i5 Typ + hjälpare levererade i shared-types/money.ts; kolumnbyte görs som nästa migration MEDAN databasen är produktionstom ingen datamigrering behövs
M2 ingredient_translations + flytt av nameSv/nameEn → rader; unit_translations i DB (visning finns nu i app-lagret) §1112 i3 Canonical-IDs är redan rätt → ren additiv migration
M3 recipe_translations + recipe_step_translations; AI-utkast med status DRAFT_AI→…→PUBLISHED + automatiska verifieringar (samma IDs/mängder/tider/allergener) §1314 i5 Receptstrukturen är redan språkoberoende
M4 i18next + ICU-plural i mobilen (ersätter interims-t()), namespaces /locales/{lng}/{ns}.json, expo-localization för förslag, språkbyte utan omstart, CI-vakt mot hårdkodad text §5, §78, §31 i4 Nyckelstrukturen är redan namespace-formad (home.*, scan.* …) → mekanisk flytt. Motivering i beslutslogg D-023
M5 Måttvisningstjänst: canonical→display per measurementSystem (ml→cup/tsp, g→oz/lb, °C→°F) med förlustfri lagring (canonical + original + källa + confidence) §910, §30 i5 Konverteringstabellen finns; visningsvalet styrs av locale-prefs
M6 nutrition_display_profiles, allergen_market_rules, kJ + natrium §1819 i7
M7 Sök: unaccent + pg_trgm + alias/synonymtabeller per locale §24 i5 ingredient_aliases-fältet finns redan
M8 Lokaliserad store-metadata, screenshots, prissättning per marknad §25 i8 Produkt-IDs redan neutrala
M9 Adminpanelen till nycklar §7 i8 Beslut: internt verktyg får vara svenskt tills internationell ops finns (D-024)
M10 AAMOS-minne: rendera summaries ur strukturerad value vid läsning i valt språk §23 i6 value är redan strukturerad

2. Berörda filer (denna leverans)

packages/shared-types (enums/units/brand/money/locale) · packages/validation (unit-schema, locale-prefs-schema) · packages/database (unit-enum, user_locale_preferences, notifications-kolumner, seed) · motorerna (enhetsberäkning via kodtabellen) · packages/ai-contracts (localeContext) · apps/api (locale-prefs-routes, kontext till AAMOS, neutrala defaults) · apps/worker (notismallar, kontext) · apps/mobile (unit-etiketter, nya nycklar, brand-injektion) · alla package.json (scope @app/*).

3. Migreringsplan & rollback

Pre-launch utan produktionsdata ⇒ enum-/kolumnbyten görs i basmigrationen (0000 regenererad; loggat i Del 7). Efter lansering gäller i stället spec §29-mönstret: nya kolumner → mapping → dubbelskrivning → verifiering → borttag efter kontroll; varje migration med backup (deploy.sh vägrar utan dump) och nedskriven rollback. Rollback för denna leverans: git-tag före sveper + regenererbar databas.

4. Testplan (§31)

🔨 Nu: enhetstester för alla nya enhetskoder inkl. cup/oz/lb-konvertering och "vägra-utan-densitet"; locale-prefs-API; oförändrade motorresultat (61 befintliga tester gröna efter kodbytet). 📋 i4i8: pseudolokal-test (nycklar aldrig synliga), plural-ICU, formatteringstester (decimal/tusental/datum/valuta) för sv-SE, en-US, en-GB, de-DE, fi-FI, snapshot av receptöversättningsverifieringen, CI-grep-vakt mot hårdkodade strängar.

5. Exit criteria-läge (§33)

Uppfyllda redan: språkneutrala enums, canonical ingredienser, datadrivna högtider, UTC/lokaldatum, AAMOS-kontext, enhetsbyte utan dataförlust (canonical lagring), nytt språk = nya rader (ingen schemaändring), nytt land = data (market-rader). Återstår före internationell lansering: M1M8 ovan uppskattat 23 sprintar, kan ske parallellt med svensk beta eftersom allt är additivt.