# Translations (i18n) **Every user-visible text is a key in `config/locales`, never a literal in code.** That includes the values of `placeholder`, `title`, `aria-label`, `alt` and `label`, and toasts. `aircloud check` refuses a literal (`i18n.inline_text`). ## Locales ```toml [i18n] default_locale = "pt-BR" available_locales = ["pt-BR", "en"] fallbacks = { "pt-BR" = ["en"] } ``` `[i18n]` in `aircloud.toml` declares the default locale, the locales the product offers, and the locales a missing key falls back to. Without the section, the product is English only (`default_locale` `en`). The keys live in `config/locales/.yml`, or `config/locales/**/..yml` to split them by area. ## Where a key is looked up - **A page** reads its texts with `useT()`. A key that starts with a dot is the page's own: in `src/pages//index.jsx`, `t(".title")` reads `.index.title`. - **Sub-routes, components and layouts** use explicit, full keys, such as `t("components.cart.save")`. A key starting with a dot outside a page has no scope and throws. - **Outside React**, import `t` from `@aircloudhq/web/helpers/translation`. - **Functions answer codes, never sentences.** The site maps each code it can receive to a key, with one literal `t("…")` per code. Never compute a key (`t("errors." + code)`): a computed key is invisible to `aircloud i18n missing`. Dates and times go through `l()`, never `Intl`. Money goes through the product's currency: see [Currency](currency.md). ## Finding missing and unused keys ```sh aircloud i18n missing aircloud i18n unused ``` `i18n missing` lists the keys a release would be refused for, and exits 1 when there are any. `i18n unused` lists the keys no code references. ## The bundle the tests read Your tests translate with the same compiled locale bundle a release carries. `aircloud i18n bundle` writes it with the platform's own builder: into the site's derived inputs, `app/site/.aircloud/`, when the product has a site, else to `.aircloud/locale-bundle.json`. Both are git-ignored and never uploaded. The generated test layer's `pretest` runs it, so `npm test` needs the `aircloud` CLI installed; run it yourself after you change a locale file or `[i18n]`: ```sh aircloud i18n bundle ``` --- Rendered from aircloud 0.1.12 at commit d84a0ce6dae53629277f656d96d81549df36807e.