Architecture d'internationalisation pour les applications construites via chat : définissez des clés stables, des règles de pluriel et un flux de traduction unique cohérent sur web et mobile.

La première chose qui casse, ce ne sont pas le code. Ce sont les mots.
Les applications construites via chat démarrent souvent comme un prototype rapide : vous tapez « Ajouter un bouton qui dit Enregistrer », l'interface apparaît, et vous passez à autre chose. Quelques semaines plus tard, vous voulez l'espagnol et l'allemand, et vous découvrez que ces libellés « temporaires » sont dispersés sur les écrans, composants, e‑mails et messages d'erreur.
Les changements de texte surviennent aussi plus fréquemment que les changements de code. Les noms de produit sont renommés, les textes légaux évoluent, l'onboarding est réécrit, et le support demande des messages d'erreur plus clairs. Si le texte vit directement dans le code UI, chaque petit changement de formulation devient une sortie risquée, et vous manquerez des endroits où la même idée est formulée différemment.
Voici les symptômes précoces qui indiquent que vous accumulez une dette de traduction :
Un exemple réaliste : vous construisez un CRM dans Koder.ai. L'app web indique « Deal stage », l'app mobile « Pipeline step », et un toast d'erreur « Invalid status ». Même si les trois sont traduits, les utilisateurs ressentiront une incohérence parce que les concepts ne correspondent pas.
« Cohérent » ne signifie pas « mêmes caractères partout ». Cela veut dire :
Une fois que vous traitez le texte comme des données produit, pas de la décoration, ajouter des langues cesse d'être une course et devient une routine de développement.
L'internationalisation (i18n) est le travail qui permet à une application de supporter plusieurs langues sans réécritures. La localisation (l10n) est le contenu effectif pour une langue et une région spécifiques, par exemple le français (Canada) avec les bons mots, formats de date et ton.
Un objectif simple : chaque texte adressé à l'utilisateur doit être sélectionné par une clé stable, pas tapé directement dans le code UI. Si vous pouvez changer une phrase sans ouvrir un composant React ou un widget Flutter, vous êtes sur la bonne voie. C'est le cœur d'une architecture d'internationalisation pour applications construites par chat, où il est facile d'envoyer par inadvertance du texte codé en dur généré pendant une session de chat.
Le texte destiné à l'utilisateur est plus large que ce que la plupart des équipes pensent. Il inclut boutons, libellés, erreurs de validation, états vides, conseils d'onboarding, notifications push, e‑mails, export PDF et tout message qu'un utilisateur peut voir ou entendre. Il n'inclut généralement pas les logs internes, les noms de colonnes de base de données, les identifiants d'événements analytics, les feature flags ou les sorties de debug réservées aux admins.
Où doivent vivre les traductions ? En pratique, souvent à la fois frontend et backend, avec une séparation claire :
L'erreur à éviter est de mélanger les responsabilités. Si le backend renvoie des phrases anglaises complètes pour les erreurs UI, le frontend ne peut pas les localiser proprement. Un meilleur modèle : le backend renvoie un code d'erreur (et éventuellement des paramètres sûrs), et le client mappe ce code sur un message localisé.
La propriété du contenu (« copy ownership ») est une décision produit, pas un détail technique. Décidez tôt qui peut changer les mots et approuver le ton.
Si le produit possède le copy, traitez les traductions comme du contenu : versionnez‑les, relisez‑les et donnez aux équipes produit un moyen sûr de demander des modifications. Si l'ingénierie possède le copy, définissez la règle qu'une nouvelle chaîne UI doit venir avec une clé et une traduction par défaut avant d'être livrée.
Exemple : si votre flow d'inscription dit « Create account » sur trois écrans différents, faites‑en une seule clé utilisée partout. Cela maintient la cohérence de sens, accélère les traducteurs et empêche qu'un petit changement de formulation devienne un nettoyage multi‑écrans.
Les clés sont le contrat entre votre UI et vos traductions. Si ce contrat change sans cesse, vous aurez du texte manquant, des correctifs en urgence et des formulations inconsistantes entre web et mobile. Une bonne architecture d'internationalisation pour applications construites par chat commence par une règle : les clés doivent décrire le sens, pas la phrase anglaise actuelle.
Utilisez des identifiants stables comme clés (par ex. billing.invoice.payNow) au lieu de la copie complète (par ex. « Pay now »). Les clés basées sur des phrases se cassent dès que quelqu'un ajuste une formulation, ajoute une ponctuation ou change la casse.
Un pattern lisible et pragmatique : écran (ou domaine) + composant + intention. Restez ennuyeux et prévisible.
Exemples :
auth.login.titleauth.login.emailLabelbilling.checkout.payButtonnav.settingserrors.network.offlineDécidez de réutiliser une clé ou d'en créer une nouvelle en vous demandant : « Le sens est‑il identique partout ? » Réutilisez pour des actions vraiment génériques, mais séparez les clés quand le contexte change. Par exemple, « Save » dans un écran de profil peut être une action simple, tandis que « Save » dans un éditeur complexe peut nécessiter un ton différent dans certaines langues.
Gardez le texte UI partagé dans des namespaces dédiés pour éviter les duplications. Paniers communs utiles :
common.actions.* (save, cancel, delete)common.status.* (loading, success)common.fields.* (search, password)errors.* (validation, network)nav.* (tabs, menu items)Quand le libellé change mais que le sens reste le même, conservez la clé et mettez à jour uniquement les valeurs traduites. C'est tout l'intérêt des IDs stables. Si le sens change (même légèrement), créez une nouvelle clé et laissez l'ancienne en place jusqu'à confirmer qu'elle n'est plus utilisée. Cela évite les discordances silencieuses où une ancienne traduction existe techniquement mais devient incorrecte.
Un petit exemple style Koder.ai : votre chat génère à la fois une app React web et une app Flutter mobile. Si les deux utilisent common.actions.save, vous obtenez des traductions cohérentes partout. Mais si le web utilise profile.save et le mobile account.saveButton, vous dériverez avec le temps, même si l'anglais semble identique aujourd'hui.
Traitez votre langue source (souvent l'anglais) comme la source de vérité unique. Gardez‑la en un seul endroit, relisez‑la comme du code, et évitez que des chaînes apparaissent dans des composants « juste pour l'instant ». C'est la façon la plus rapide d'éviter le texte UI codé en dur et les révisions ultérieures.
Une règle simple : l'application ne doit afficher que du texte provenant du système i18n. Si quelqu'un a besoin d'un nouveau texte, il ajoute une clé et un message par défaut d'abord, puis utilise cette clé dans l'UI. Cela garde votre architecture d'internationalisation stable même quand les fonctionnalités bougent.
Si vous livrez web et mobile, vous voulez un catalogue partagé de clés, plus de la place pour que les équipes fonctionnelles travaillent sans se marcher sur les pieds. Une mise en place pratique :
Gardez les clés identiques entre plateformes, même si l'implémentation diffère (React sur le web, Flutter sur mobile). Si vous utilisez une plateforme comme Koder.ai pour générer les deux apps depuis le chat, exporter le code source est plus simple à maintenir quand les deux projets pointent vers les mêmes noms de clés et le même format de message.
Les traductions évoluent. Traitez les changements comme des changements produit : petits, relus et traçables. Une bonne revue se concentre sur le sens et la réutilisation, pas seulement l'orthographe.
Pour éviter que les clés ne dérivent entre équipes, faites en sorte que les clés soient possédées par des features (billing.*, auth.*), et ne renommez jamais une clé juste parce que la formulation change. Mettez à jour le message, conservez la clé. Les clés sont des identifiants, pas du copy.
Les règles de pluriel varient selon la langue, donc le schéma anglais simple (1 vs tout le reste) casse vite. Certaines langues ont des formes séparées pour 0, 1, 2–4, et d'autres modifient la phrase entière, pas seulement le nom. Si vous intégrez la logique de pluriel dans l'UI avec des if‑else, vous finirez par dupliquer du copy et manquer des cas limites.
Une approche plus sûre : gardez un message flexible par idée et laissez la couche i18n choisir la forme appropriée. Les messages de type ICU sont conçus pour ça. Ils déplacent les décisions grammaticales dans la traduction, pas dans vos composants.
Voici un petit exemple qui couvre les cas qu'on oublie :
itemsCount = "{count, plural, =0 {No items} one {# item} other {# items}}"
Cette seule clé couvre 0, 1 et tout le reste. Les traducteurs peuvent la remplacer par les formes plurielles correctes pour leur langue sans que vous touchiez au code.
Quand vous avez besoin d'un mot selon le genre ou le rôle, évitez de créer des clés séparées comme welcome_male et welcome_female sauf si le produit l'exige vraiment. Utilisez select pour que la phrase reste une unité :
welcomeUser = "{gender, select, female {Welcome, Ms. {name}} male {Welcome, Mr. {name}} other {Welcome, {name}}}"
Pour éviter de vous enfermer avec des cas grammaticaux, conservez les phrases aussi complètes que possible. Ne collez pas des fragments comme "{count} " + t('items') parce que beaucoup de langues ne peuvent pas réordonner les mots ainsi. Préférez un seul message qui inclut le nombre, le nom et les mots autour.
Une règle simple qui marche bien dans les apps construites par chat (y compris les projets Koder.ai) : si une phrase contient un nombre, une personne ou un statut, faites‑la en ICU dès le départ. Cela coûte un peu plus au départ et évite beaucoup de dette de traduction plus tard.
Si votre app React web et votre app Flutter mobile gardent chacune leurs propres fichiers de traduction, elles divergeront. Le même bouton finit par avoir un libellé différent, une clé signifie une chose sur le web et une autre sur mobile, et les tickets de support commencent à dire « l'app dit X mais le site dit Y ».
La solution la plus simple et la plus importante : choisissez un format source de vérité et traitez‑le comme du code. Pour la plupart des équipes, cela signifie un ensemble partagé de fichiers de locale (par ex. JSON utilisant des messages ICU) que consomment le web et le mobile. Quand vous générez des apps via chat et des générateurs, cela compte encore plus, car il est facile de créer par inadvertance du nouveau texte à deux endroits.
Une configuration pratique est un petit « package i18n » ou dossier contenant :
React et Flutter deviennent des consommateurs. Ils ne doivent pas inventer de nouvelles clés localement. Dans un workflow type Koder.ai (React web, Flutter mobile), vous pouvez générer les deux clients à partir du même jeu de clés et garder les changements soumis à revue comme n'importe quel autre changement de code.
L'alignement backend fait partie de la même histoire. Erreurs, notifications et e‑mails ne devraient pas être des phrases anglaises écrites à la main en Go. Au lieu de cela, renvoyez des codes d'erreur stables (comme auth.invalid_password) plus d'éventuels paramètres sûrs. Ensuite, les clients mappent ces codes sur du texte traduit. Pour des e‑mails envoyés par le serveur, le serveur peut rendre des templates en utilisant les mêmes clés et fichiers de locale.
Créez un petit guide et appliquez‑le en revue de code :
Pour éviter les clés dupliquées aux sens différents, ajoutez un champ « description » (ou un fichier de commentaires) pour les traducteurs et le futur vous. Exemple : billing.trial_days_left doit préciser s'il est affiché en bannière, en e‑mail ou les deux. Cette phrase évite souvent la réutilisation « presque correcte » qui crée de la dette.
Cette cohérence est l'ossature d'une architecture d'internationalisation pour applications construites par chat : un vocabulaire partagé, de nombreuses surfaces et aucune surprise quand vous livrez une nouvelle langue.
Une bonne architecture d'internationalisation commence simple : un jeu de clés, une source de vérité pour le copy et les mêmes règles sur web et mobile. Si vous construisez vite (par ex. avec Koder.ai), cette structure permet de garder la rapidité sans créer de dette de traduction.
Choisissez vos locales tôt et décidez ce qui se passe quand une traduction manque. Un choix courant : afficher la langue préférée de l'utilisateur si disponible, sinon revenir à l'anglais, et journaliser les clés manquantes pour les corriger avant la sortie suivante.
Ensuite, mettez ceci en place :
billing.plan_name.pro ou auth.error.invalid_password. Gardez les mêmes clés partout.t("key") dans les composants. Dans Flutter, utilisez un wrapper de localisation et appelez la même recherche basée sur clé dans les widgets. L'objectif est d'avoir les mêmes clés, pas la même librairie.if (count === 1) dispersés dans les écrans.Enfin, testez une langue avec des mots plus longs (l'allemand est classique) et une autre avec une ponctuation différente. Cela révèle rapidement les boutons qui débordent, les titres qui se renvoient mal à la ligne, et les mises en page supposant la longueur anglaise.
Si vous gardez les traductions dans un dossier partagé (ou un package généré) et traitez les changements de copy comme des changements de code, vos apps web et mobile restent cohérentes même quand les fonctionnalités sont construites rapidement via chat.
Les chaînes traduites ne représentent qu'une moitié du problème. La plupart des apps affichent aussi des valeurs changeantes comme dates, prix, nombres et noms. Si vous traitez ces valeurs comme du texte brut, vous aurez des formats étranges, des fuseaux horaires erronés et des phrases qui sonnent faux dans beaucoup de langues.
Commencez par formater nombres, devises et dates selon les règles de la locale, pas avec du code personnalisé. Un utilisateur en France attend « 1 234,50 € », tandis qu'un utilisateur aux États‑Unis attend « $1,234.50 ». Idem pour les dates : « 03/04/2026 » est ambigu, alors que le format localisé clarifie.
Les fuseaux horaires sont un piège suivant. Les serveurs devraient stocker les timestamps dans une forme neutre (généralement UTC), mais les utilisateurs veulent voir les heures dans leur propre fuseau. Par exemple : une commande créée à 23:30 UTC peut être « demain » pour quelqu'un à Tokyo. Décidez d'une règle par écran : afficher l'heure locale de l'utilisateur pour des événements personnels, et afficher un fuseau horaire fixe (et bien étiqueté) pour des choses comme des créneaux de retrait en magasin.
Évitez de construire des phrases en concaténant des fragments traduits. Cela casse la grammaire car l'ordre des mots change selon les langues. Au lieu de :
"{count} " + t("items") + " " + t("in_cart")
utilisez un seul message avec placeholders, par ex. : « {count} items in your cart ». Le traducteur peut alors réordonner les mots en toute sécurité.
Le RTL n'est pas juste la direction du texte. Le flux de mise en page s'inverse, certaines icônes doivent être miroir (comme les flèches de retour), et le contenu mixte (arabe + un code produit en anglais) peut s'afficher dans un ordre surprenant. Testez des écrans réels, pas seulement une étiquette, et assurez‑vous que vos composants UI supportent le changement de direction.
Ne traduisez jamais ce que l'utilisateur a écrit (noms, adresses, tickets support, messages de chat). Vous pouvez traduire les libellés autour, et formater les métadonnées (dates, nombres), mais le contenu lui‑même doit rester tel quel. Si vous ajoutez une traduction automatique plus tard, faites‑en une fonctionnalité explicite avec un bascule « original/traduit » claire.
Un exemple pratique : une app construite avec Koder.ai peut afficher « {name} renewed on {date} for {amount} ». Gardez‑la comme un seul message, formatez {date} et {amount} selon la locale, et affichez la date dans le fuseau de l'utilisateur. Ce pattern unique évite beaucoup de dette de traduction.
Règles rapides qui évitent généralement les bugs :
La dette de traduction commence souvent par « juste une chaîne rapide » et se transforme en semaines de nettoyage. Dans les projets construits par chat, cela peut arriver encore plus vite parce que le texte UI est généré à l'intérieur de composants, formulaires et même messages backend.
Les problèmes les plus coûteux sont ceux qui se propagent dans l'application et deviennent difficiles à retrouver.
Imaginez une app React web et une app Flutter mobile affichant une bannière de facturation : « You have 1 free credit left ». Quelqu'un ajuste le texte web en « You have one credit remaining » et garde la clé basée sur la phrase entière. Le mobile utilise toujours l'ancienne clé. Vous avez maintenant deux clés pour un même concept, et les traducteurs voient les deux.
Un meilleur pattern : des clés stables (par ex. billing.creditsRemaining) et la pluralisation avec des messages ICU pour que la grammaire soit correcte dans toutes les langues. Si vous utilisez un outil de génération par chat comme Koder.ai, ajoutez une règle tôt : tout texte destiné à l'utilisateur produit dans le chat doit atterrir dans les fichiers de traduction, pas dans les composants ni les erreurs serveur. Cette petite habitude protège votre architecture d'i18n au fur et à mesure que le projet grandit.
Quand l'internationalisation devient brouillonne, c'est généralement parce que les bases n'ont pas été documentées. Une petite checklist et un exemple concret peuvent maintenir votre équipe (et votre futur vous) hors de la dette de traduction.
Voici une checklist rapide à exécuter pour chaque nouvel écran :
billing.invoice.paidStatus, pas billing.greenLabel).Un exemple simple : vous lancez un écran de facturation en anglais, espagnol et japonais. L'UI contient : « Invoice », « Paid », « Due in 3 days », « 1 payment method » / « 2 payment methods », et un total comme « $1,234.50 ». Avec une architecture d'i18n adaptée aux apps construites par chat, vous définissez les clés une fois (partagées entre web et mobile), et chaque langue ne remplit que les valeurs. « Due in {days} days » devient un message ICU, et le format monétaire vient d'un formateur sensible à la locale, pas de virgules codées en dur.
Déployez le support linguistique fonctionnalité par fonctionnalité, pas par un gros refactor :
Documentez deux choses pour que les nouvelles fonctionnalités restent cohérentes : vos règles de nommage de clés (avec exemples) et une « définition de prêt » pour les chaînes (pas de copy codé en dur, ICU pour les pluriels, formatage pour dates/nombres, ajout au catalogue partagé).
Étapes suivantes : si vous construisez dans Koder.ai, utilisez Planning Mode pour définir écrans et clés avant de générer l'UI. Ensuite, utilisez les snapshots et rollback pour itérer en sécurité sur le copy et les traductions entre web et mobile sans risquer une release cassée.