Tous les articles et vidéos

Arabe, français et MAD : i18n et RTL dans les frontends d'entreprise

et des frontends d'entreprise au Maroc et dans le Golfe : traduction au ou à l'exécution, dir et logique, , format du MAD.

Adil Ben Moussa
08 novembre 2026· 6 min
Arabe, français et MAD : i18n et RTL dans les frontends d'entreprise

Le même montant, 12450.5 dirhams, sort sous trois formes différentes de la même API Intl, selon une seule chaîne de locale. Puis la version arabe de l'écran arrive, chaque flèche pointe dans le mauvais sens, et un au milieu d'une phrase arabe peut afficher ses groupes de chiffres dans un ordre que personne n'a tapé. Au Maroc et dans le Golfe, ce n'est pas un cas limite. C'est le public principal.

Dans un frontend d'entreprise, les langues sont une décision de system design, parce qu'elles touchent tout à la fois : le build, la mise en page, les composants, les données et le . Décidé tard, le RTL touche chaque écran.

Les quelques concepts qui comptent

Traduction au build ou à l'exécution. L'i18n intégrée d' construit « une copie distribuable distincte de l'application pour chaque locale », avec les traductions fusionnées au moment du build. La CLI écrit chaque locale dans son propre répertoire, en général servi depuis son propre sous-répertoire. Une bibliothèque d'exécution, elle, charge les traductions pendant que l'app tourne. React n'a pas d'i18n intégrée, donc côté React, le choix porte sur la bibliothèque.

dir sur la racine, du CSS logique partout. La réponse de MDN est courte : « définissez explicitement dir sur l'élément racine », ce qui « est particulièrement important pour les écritures de droite à gauche », et utilisez l'attribut « plutôt que les propriétés CSS correspondantes quand c'est possible ». Les sont des « équivalents relatifs à la direction » des propriétés physiques, donc margin-inline-start suit la langue et margin-left, non. Les icônes demandent aussi une décision : une flèche de retour s'inverse, un bouton de lecture ou un logo, non. Sur tt-tech.io, les flèches portent une classe rtl:-scale-x-100 exactement pour cela.

Image : tt-tech.io, adapté de web.dev, Internationalization, CC BY 4.0.

Les trois cadres utilisent le même CSS : border-inline-start, border-inline-end, border-block-start et border-block-end. Seule la langue change, et le navigateur déplace les bordures.

Le bidi dans les données. La direction de la page est la partie facile. La partie difficile, c'est une valeur au milieu d'une phrase : un RIB, un numéro de téléphone, un nom de produit anglais dans un texte arabe. Dans l'algorithme bidirectionnel d'Unicode, les nombres « agissent comme s'ils étaient R » pour les caractères neutres qui les entourent, donc l'espace entre deux groupes de chiffres prend la direction de droite à gauche. Dans un texte arabe, les groupes d'un RIB écrit avec des espaces peuvent sortir dans l'ordre inverse. MDN indique que dir="auto" « doit être utilisé pour les données dont la direction est inconnue, comme les saisies des utilisateurs ou les données externes ». Il décrit <bdi> comme une façon de dire à l'algorithme bidirectionnel de traiter son texte « isolément du texte qui l'entoure ».

Nombres, devises et dates. Intl.NumberFormat « permet un formatage des nombres adapté à la langue ». Adapté à la langue veut aussi dire dépendant des données. J'ai lancé ceci dans 24 ( 78) :

const mad = (locale: string) =>
  new Intl.NumberFormat(locale, { style: 'currency', currency: 'MAD' }).format(12450.5);
 
mad('fr-FR'); // '12 450,50 MAD' (espace insécable étroite)
mad('fr-MA'); // '12.450,50 MAD' (groupes séparés par un point)
mad('ar-MA'); // '12.450,50 د.م.' (plus deux marques invisibles de droite à gauche)

Trois sorties, et elles dépendent des données de locale que votre navigateur ou votre version de Node embarque. Cela convient pour l'affichage, pas pour un test qui vérifie une chaîne exacte, ni pour une banque qui a décidé de l'apparence de ses relevés.

Choisissez le format monétaire exprès, sinon ce sont les données de locale qui le choisissent pour vous.

Le design system dans les deux sens. Les tokens, les composants et les tests visuels doivent aussi tourner en RTL, sinon chaque équipe produit trouve les mêmes bugs de son côté.

Polices et longueur des textes. L'arabe a besoin d'une police qui le rend bien, pas la police de repli de la police latine. Le texte traduit s'allonge, et le guide Fluent de Mozilla le note : « Beaucoup de langues utilisent des chaînes plus longues que l'anglais ».

Quand choisir quoi

  • Build ou exécution : au build quand la locale est fixe pour chaque utilisateur et que les textes sont livrés avec le code ; à l'exécution quand les utilisateurs changent souvent de langue, ou que les textes viennent d'un .
  • Intl ou un formateur fixe : Intl pour de nombreuses locales et pour l'affichage seulement ; un formateur fixe et testé quand le format est une décision métier.
  • <bdi> ou dir="ltr" : <bdi> (ou dir="auto") pour du texte que vous ne contrôlez pas, comme des noms ; dir="ltr" pour des valeurs toujours écrites de gauche à droite, comme un RIB ou un .

Sur Atlas Bank

L'interface d'Atlas Bank n'existe qu'en anglais aujourd'hui (<html lang="en"> dans apps/atlas/src/index.html). Son formatage des montants est un choix délibéré. formatMad, dans libs/domain/src/lib/format.ts, se dit « délibérément pas Intl » : un format fixe, groupes séparés par une espace et décimales après la virgule, « rendu à l'identique dans tous les navigateurs et dans Node, pour que les tests puissent vérifier la chaîne exacte ». Les propres données ICU de fr-MA groupent avec un point, c'est donc un choix que le code fait exprès. format.spec.ts vérifie '12 450,50 MAD'.

Atlas montre aussi ce que coûterait le RTL. Ses styles utilisent encore par endroits des propriétés physiques : margin-left: auto dans account-detail.ts, text-align: right pour l'utilitaire .num. Chacun est une petite correction, trouvée tard.

Un sélecteur français et arabe avec dir="rtl" serait un bon ajout à Atlas pour cette partie. C'est une suggestion, ce n'est pas dans le dépôt aujourd'hui.

Ce que j'ai laissé de côté, et pourquoi

  • , systèmes de gestion des traductions, . De vrais outils et de vraies règles ; une ligne chacun. Pour les pluriels, utilisez des messages ICU et ne concaténez jamais de chaînes.
  • Détection de la locale. Une décision produit ; laissez l'utilisateur choisir, et retenez son choix.

Dès lundi

  • Mettez dir="rtl" sur l'élément html de votre app dans une branche et suivez le parcours principal de bout en bout. Notez chaque écran qui casse.
  • Cherchez margin-left, padding-right et text-align: left dans vos styles, et comptez-les. Ce nombre donne la taille de votre chantier RTL.
  • Trouvez chaque endroit qui formate des montants et vérifiez qu'il passe par une seule fonction.

Pour votre agent de code

Les règles de cet article, écrites pour un agent. Collez-les dans votre AGENTS.md, enregistrez-les comme , ou indiquez le fichier à votre agent.

Pour votre agent de code Télécharger le .md
# Internationalisation and RTL rules for enterprise apps

Source: https://tt-tech.io/blog/arabic-french-mad-i18n-rtl-enterprise
For Angular and React frontends. Add to AGENTS.md or save as a skill. Your project's own rules win where they differ.

## Rules

1. Choose build-time translation (Angular i18n, one build per locale) when the locale is fixed per user and the texts ship with the code. Choose a runtime library when users switch language often or texts come from a CMS.
2. Set `dir` explicitly on the root `html` element. Use the `dir` attribute instead of the CSS `direction` property where possible.
3. Use logical CSS properties: `margin-inline-start`, `padding-inline-end`, `border-inline-start`, `text-align: start`. Never add `margin-left`, `padding-right` or `text-align: left` in new code.
4. Mirror icons that show direction, such as back and forward arrows, in RTL. Do not mirror a play button or a logo.
5. Wrap text whose direction you do not control (names, user input, external data) in `<bdi>` or give it `dir="auto"`.
6. Mark values that are always left to right, such as a RIB or an IBAN, with `dir="ltr"`.
7. Format money through one function. Use `Intl.NumberFormat` for display across many locales; use a fixed, tested formatter when the format is a business decision.
8. Never assert an exact `Intl` output string in a test. It depends on the locale data the browser or Node version ships.
9. Build plurals and variable messages with ICU messages. Never concatenate translated strings.
10. Run design tokens, components and visual tests in RTL as well as LTR.
11. Use a font that renders Arabic well, not the Latin font's fallback. Leave room for translated text, which is often longer than English.
12. Let the user choose the language and remember the choice.

## Before you say done

- Search the diff for `margin-left`, `margin-right`, `padding-left`, `padding-right`, `text-align: left` and `text-align: right`. Replace each with a logical property or explain it.
- Search the diff for money formatting (`Intl.NumberFormat`, `toFixed`, currency codes) outside the shared formatter.
- Search the diff for string concatenation in translated text, and for names, user input or external values rendered without `<bdi>`, `dir="auto"` or `dir="ltr"`.

Sources

  1. Angular, Merge translations into the app
  2. Angular, Deploy multiple locales
  3. MDN, dir HTML global attribute
  4. MDN, CSS logical properties and values
  5. Unicode, UAX #9: Unicode Bidirectional Algorithm
  6. MDN, <bdi> HTML bidirectional isolate element
  7. MDN, Intl.NumberFormat
  8. Mozilla, Fluent for Firefox Developers
  9. web.dev, Internationalization
Partager cet article