Arkitektur för internationalisering i chattbyggda appar: definiera stabila strängnycklar, pluralregler och ett översättningsflöde som förblir konsekvent på webb och mobil.

Det första som går sönder är inte koden. Det är orden.
Chattbyggda appar börjar ofta som snabba prototyper: du skriver "Lägg till en knapp som säger Spara", UI:t dyker upp och du går vidare. Veckor senare vill du ha spanska och tyska, och du upptäcker att de där "tillfälliga" etiketterna är utspridda över skärmar, komponenter, e-post och felmeddelanden.
Textändringar sker också oftare än kodändringar. Produktnamn byts, juridisk text ändras, onboarding skrivs om och support vill ha tydligare felmeddelanden. Om text lever direkt i UI-koden blir varje liten formulering en riskfylld release, och du kommer missa platser där samma idé uttrycks olika.
Här är de tidiga symptomen som signalerar att du bygger upp ett översättningsskuld:
Ett realistiskt exempel: du bygger ett enkelt CRM i Koder.ai. Webbappen säger "Deal stage", mobilappen säger "Pipeline step" och ett fel-toast säger "Invalid status". Även om alla tre översätts kommer användarna känna att appen är inkonsekvent eftersom begreppen inte matchar.
"Konsistent" betyder inte "samma tecken överallt". Det betyder:
När du behandlar text som produktdata, inte dekoration, slutar språktillägg vara en stress och blir en rutin i byggandet.
Internationalization (i18n) är arbetet för att en app ska stödja många språk utan omskrivningar. Localization (l10n) är det faktiska innehållet för ett specifikt språk och region, som franska (Kanada) med rätt ordval, datumformat och ton.
Ett enkelt mål: varje bit användartext väljs av en stabil nyckel, inte skrivas direkt i UI-koden. Om du kan ändra en mening utan att öppna en React-komponent eller en Flutter-widget är du på rätt väg. Detta är kärnan i en internationaliseringsarkitektur för chattbyggda appar, där det är lätt att av misstag skicka med hårdkodad text som genererats under en chatt.
Användartext är bredare än de flesta team förväntar sig. Den inkluderar knappar, etiketter, valideringsfel, tomma tillstånd, onboardingtips, push-notiser, e-post, PDF-exporter och alla meddelanden en användare kan se eller höra. Vanligtvis ingår inte interna loggar, databaskolumnnamn, analytics-event-ID:n, feature flags eller admin-endast debug-utdata.
Var ska översättningar bo? I praktiken ofta både frontend och backend, med en tydlig gräns.
Misstaget att undvika är att blanda ansvar. Om backend returnerar fullt skrivna engelska meningar för UI-fel kan frontend inte lokalisera dem rent. Ett bättre mönster är: backend returnerar en felkod (och eventuellt säkra parametrar), och klienten mappar den koden till ett lokaliserat meddelande.
Copy-ägarskap är ett produktbeslut, inte en teknisk detalj. Bestäm tidigt vem som kan ändra ord och godkänna tonen.
Om produkt äger texterna, behandla översättningar som innehåll: versionera dem, granska dem och ge produkt ett säkert sätt att begära ändringar. Om engineering äger copy, sätt en regel att varje ny UI-sträng måste komma med en nyckel och en standardöversättning innan den kan släppas.
Exempel: om din registreringsflöde säger "Create account" på tre olika skärmar, gör det till en nyckel som används överallt. Det håller betydelsen konsekvent, gör översättare snabbare och hindrar små textändringar från att bli ett flerskärmsarbete senare.
Nycklar är kontraktet mellan ditt UI och dina översättningar. Om det kontraktet ändras hela tiden får du saknad text, stressiga fixar och inkonsekvent ordval över webb och mobil. En bra internationaliseringsarkitektur för chattbyggda appar börjar med en regel: nycklar ska beskriva betydelsen, inte den nuvarande engelska meningen.
Använd stabila ID:n som nycklar (som billing.invoice.payNow) istället för hela texten (som "Pay now"). Meningsnycklar går sönder så fort någon justerar ordalydelsen, lägger till skiljetecken eller ändrar versalisering.
Ett praktiskt och läsbart mönster är: skärm (eller domän) + komponent + intent. Håll det tråkigt och förutsägbart.
Exempel:
auth.login.titleauth.login.emailLabelbilling.checkout.payButtonnav.settingserrors.network.offlineBestäm när du ska återanvända en nyckel eller skapa en ny genom att fråga: "Är betydelsen identisk överallt?" Återanvänd nycklar för verkligt generiska handlingar, men dela upp när kontexten ändras. Till exempel kan "Spara" i en profilskärm vara enkel, medan "Spara" i en komplex redigerare kan behöva en mer specifik ton i vissa språk.
Håll delad UI-text i dedikerade namnrymder så att den inte dupliceras över skärmar. Vanliga fack som fungerar bra:
common.actions.* (spara, avbryt, ta bort)common.status.* (laddar, klar)common.fields.* (sök, lösenord)errors.* (validering, nätverk)nav.* (flikar, menyalternativ)När formuleringen ändras men betydelsen är densamma, behåll nyckeln och uppdatera bara översättningsvärdena. Det är hela poängen med stabila ID:n. Om betydelsen ändras (även subtilt), skapa en ny nyckel och låt den gamla ligga kvar tills du bekräftat att den inte används. Det undviker "tysta" mismatch där en gammal översättning tekniskt finns men blivit fel.
Ett litet exempel från ett Koder.ai-liknande flöde: din chatt genererar både en React-webbapp och en Flutter-mobilapp. Om båda använder common.actions.save får du konsekventa översättningar överallt. Men om webbappen använder profile.save och mobilen account.saveButton kommer ni glida isär över tid, även om engelskan ser likadan ut idag.
Behandla källspråket (ofta engelska) som den enda sanningskällan. Håll det på ett ställe, granska det som kod och undvik att låta strängar dyka upp i slumpmässiga komponenter "bara tillfälligt". Detta är det snabbaste sättet att undvika hårdkodad UI-text och senare omarbete.
En enkel regel hjälper: appen får bara visa text från i18n-systemet. Om någon behöver ny text, lägger de till en nyckel och ett standardmeddelande först, sedan använder den nyckeln i UI:t. Det håller din internationaliseringsarkitektur för chattbyggda appar stabil även när funktioner flyttas runt.
Om du släpper både webb och mobil vill du ha en gemensam katalog med nycklar, plus utrymme för feature-team att arbeta utan att trampa varandra på tårna. En praktisk layout:
Håll nycklar identiska över plattformar, även om implementationen skiljer sig (React på webben, Flutter på mobilen). Om du använder en plattform som Koder.ai för att generera båda apparna från chatt är det lättare att underhålla när båda projekten pekar på samma nyckelnamn och samma meddelandeformat.
Översättningar förändras över tid. Behandla ändringar som produktändringar: små, granskade och spårbara. En bra granskning fokuserar på betydelse och återanvändning, inte bara stavning.
För att stoppa nyckelglidning mellan team, gör nycklar ägda av features (billing., auth.), och döp aldrig om nycklar bara för att formuleringen ändras. Uppdatera meddelandet, behåll nyckeln. Nycklar är identifierare, inte copy.
Pluralregler skiljer sig mellan språk, så det enkla engelska mönstret (1 vs allt annat) faller snabbt. Vissa språk har separata former för 0, 1, 2–4 och många. Andra ändrar hela meningen, inte bara substantivet. Om du bakar plurallogik i UI:t med if-else kommer du duplicera text och missa kantfall.
Ett säkrare tillvägagångssätt är att hålla ett flexibelt meddelande per idé och låta i18n-lagret välja rätt form. ICU-liknande meddelanden är gjorda för detta. De håller grammatiken i översättningen, inte i dina komponenter.
Här är ett litet exempel som täcker fall folk glömmer:
itemsCount = "{count, plural, =0 {No items} one {# item} other {# items}}"
Denna enda nyckel täcker 0, 1 och allt annat. Översättare kan ersätta den med rätt pluralformer för sitt språk utan att du rör koden.
När du behöver genus- eller rollbaserat ordval, undvik att skapa separata nycklar som welcome_male och welcome_female om inte produkten verkligen kräver det. Använd select så meningen håller ihop:
welcomeUser = "{gender, select, female {Welcome, Ms. {name}} male {Welcome, Mr. {name}} other {Welcome, {name}}}"
För att undvika problem med grammatiska kasus, håll meningar så kompletta som möjligt. Sy ihop inte fragment som "{count} " + t('items') eftersom många språk inte kan byta ordningen så. Föredra ett meddelande som inkluderar siffran, substantivet och omgivande ord.
En enkel regel som fungerar bra i chattbyggda appar (inklusive Koder.ai-projekt): om en mening innehåller ett tal, en person eller en status, gör den till ICU från dag ett. Det kostar lite mer i början och sparar mycket översättningsskuld senare.
Om din React-webbapp och Flutter-mobilapp båda håller egna översättningsfiler kommer de glida isär. Samma knapp får olika ordalydelse, en nyckel betyder en sak på webb och något annat på mobil, och supportärenden börjar nämna "appen säger X men webbplatsen säger Y".
Den enklaste lösningen är också den viktigaste: välj ett format som källa till sanning och behandla det som kod. För de flesta team betyder det en delad uppsättning locale-filer (t.ex. JSON med ICU-meddelanden) som både webb och mobil konsumerar. När ni bygger via chatt och generatorer är detta ännu viktigare, eftersom det är lätt att av misstag skapa ny text på två ställen.
En praktisk uppsättning är ett litet "i18n-paket" eller en mapp som innehåller:
React och Flutter blir konsumenter. De ska inte uppfinna nya nycklar lokalt. I en Koder.ai-liknande arbetsflöde (React-webb, Flutter-mobil) kan du generera båda klienterna från samma nyckeluppsättning och hålla ändringar under granskning som vilken kodändring som helst.
Backend-justering är en del av samma berättelse. Fel, notiser och e-post bör inte vara handskrivna engelska strängar i Go. Returnera istället stabila felkoder (som auth.invalid_password) plus säkra parametrar. Sedan mappar klienterna koderna till översatt text. För server-sända e-post kan servern rendera mallar med samma nycklar och locale-filer.
Skapa ett litet regelverk och upprätthåll det i kodgranskning:
För att undvika dubblettnycklar med olika betydelser, lägg till ett "description"-fält (eller en kommentarsfil) för översättare och framtida du. Exempel: billing.trial_days_left bör förklara om den visas som en banner, i ett e-post eller båda. Den där meningen stoppar ofta "nästan-lagom"-återanvändning som skapar översättningsskuld.
Denna konsekvens är ryggraden i en internationaliseringsarkitektur för chattbyggda appar: ett delat vokabulär, många ytor och inga överraskningar när du släpper nästa språk.
En bra internationaliseringsarkitektur för chattbyggda appar börjar enkelt: en uppsättning meddelandenycklar, en sanningskälla för copy och samma regler för webb och mobil. Om du bygger snabbt (t.ex. med Koder.ai) håller denna struktur farten utan att skapa översättningsskuld.
Välj dina lokaler tidigt och bestäm vad som händer när en översättning saknas. Ett vanligt val är: visa användarens föredragna språk när det finns, annars fall tillbaka till engelska, och logga saknade nycklar så ni kan åtgärda dem före nästa release.
Sätt sedan detta på plats:
billing.plan_name.pro eller auth.error.invalid_password. Håll samma nycklar överallt.t("key") i komponenter. I Flutter, använd en lokalisering-wrapper och kalla samma nyckelbaserade uppslag i widgets. Målet är samma nycklar, inte samma bibliotek.{count, plural, one {# file} other {# files}} och "Hello, {name}". Detta undviker fusk som if (count === 1) utspritt i skärmar.Testa slutligen ett språk med längre ord (tyska är klassiskt) och ett med annorlunda skiljetecken. Det avslöjar snabbt knappar som flyter ut, rubriker som bryts illa och layouter som antar engelska längder.
Om ni håller översättningar i en delad mapp (eller genererat paket) och behandlar copy-ändringar som kodändringar, håller sig era webb- och mobilappar konsekventa även när funktioner byggs snabbt i chatt.
Översatt UI-text är bara halva problemet. De flesta appar visar också föränderliga värden som datum, priser, antal och namn. Om du behandlar dessa värden som vanlig text får du konstiga format, fel tidszoner och meningar som låter "fel" på många språk.
Börja med att formatera tal, valuta och datum med locale-regler, inte egen kod. En användare i Frankrike förväntar sig "1 234,50 €", medan en användare i USA förväntar sig "$1,234.50". Samma gäller datum: "03/04/2026" är tvetydigt, men locale-format gör det tydligt.
Tidszoner är nästa fälla. Servrar bör lagra tidsstämplar neutralt (vanligtvis UTC), men användare förväntar sig att se tider i sin egen zon. Till exempel kan en order skapad kl 23:30 UTC vara "imorgon" för någon i Tokyo. Bestäm en regel per skärm: visa användarlokal tid för personliga händelser, och visa en fast affärstidzon för saker som butikens upphämtning (och märk den tydligt).
Undvik att bygga meningar genom att konkatensera översatta fragment. Det bryter grammatiken eftersom ordningen skiljer sig mellan språk. Istället för:
"{count} " + t("items") + " " + t("in_cart")
använd ett meddelande med placeholders, till exempel: "{count} items in your cart". Översättaren kan då ordna om orden säkert.
RTL är inte bara text riktning. Layoutflödet vänds, vissa ikoner behöver speglas (som bakpilar) och blandat innehåll (arabiska + en engelsk produktkod) kan renderas i oväntad ordning. Testa riktiga skärmar, inte bara en etikett, och se till att UI-komponenter stödjer riktningsändringar.
Översätt aldrig vad användaren skrev (namn, adresser, supportärenden, chattmeddelanden). Du kan översätta etiketter runt det och formatera metadata (datum, tal), men innehållet självt måste förbli oförändrat. Om du lägger till automatisk översättning senare, gör det som en explicit funktion med en tydlig "original/översatt"-växling.
Ett praktiskt exempel: en Koder.ai-byggd app kan visa "{name} renewed on {date} for {amount}". Håll det som ett meddelande, formatera {date} och {amount} efter locale och visa i användarens tidszon. Detta mönster förhindrar mycket översättningsskuld.
Snabba regler som brukar förhindra buggar:
Översättningsskuld börjar ofta som "bara en snabb sträng" och blir veckors städning senare. I chattbyggda projekt kan det gå ännu snabbare eftersom UI-text genereras inne i komponenter, formulär och till och med backend-meddelanden.
De dyraste problemen är de som sprider sig över appen och blir svåra att hitta.
Föreställ dig en React-webbapp och en Flutter-mobilapp som båda visar en faktureringsbanner: "You have 1 free credit left". Någon ändrar webbtexten till "You have one credit remaining" och behåller nyckeln som hela meningen. Mobilen använder fortfarande den gamla nyckeln. Nu har du två nycklar för ett koncept och översättare ser båda.
Ett bättre mönster är stabila nycklar (som billing.creditsRemaining) och pluralisering med ICU-meddelanden så grammatiken blir korrekt i alla språk. Om du använder ett vibe-coding-verktyg som Koder.ai, lägg till en regel tidigt: all användartext som skapas i chatten ska landa i översättningsfiler, inte i komponenter eller serverfel. Den lilla vanan skyddar din internationaliseringsarkitektur för chattbyggda appar när projektet växer.
När internationalisering känns rörig är det oftast för att grunderna aldrig skrevs ner. En liten checklista och ett konkret exempel kan hålla ditt team (och framtida du) borta från översättningsskuld.
Här är en snabb checklista att köra för varje ny skärm:
billing.invoice.paidStatus, inte billing.greenLabel).Ett enkelt exempel: du lanserar en faktureringsskärm på engelska, spanska och japanska. UI:t har: "Invoice", "Paid", "Due in 3 days", "1 payment method" / "2 payment methods" och en totalsumma som "$1,234.50". Om du bygger detta med en internationaliseringsarkitektur för chattbyggda appar definierar du nycklar en gång (delade mellan webb och mobil) och varje språk fyller bara i värden. "Due in {days} days" blir ett ICU-meddelande och valutaformat kommer från en locale-medveten formatterare, inte hårdkodade kommatecken.
Rulla ut språkstöd funktion för funktion, inte som en stor omskrivning:
Dokumentera två saker så nya funktioner förblir konsekventa: dina regler för nyckelnamngivning (inklusive exempel) och en "definition of done" för strängar (ingen hårdkodad text, ICU för pluraler, formatering för datum/tal, tillagd i delade kataloger).
Nästa steg: om du bygger i Koder.ai, använd Planning Mode för att definiera skärmar och nycklar innan du genererar UI. Använd snapshots och rollback för att säkert iterera på copy och översättningar över webb och mobil utan att riskera en trasig release.