# 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"`.
