Languages and RTL
Orbix ships in English, Spanish, Portuguese, French and Arabic. Arabic switches the whole layout to
right-to-left. Numbers, currencies and dates are formatted for the active language with the browser Intl API.

How it works
- Translations live in
src/locales/<locale>/<area>.json(common.json,nav.json,dashboards.json...). A key is the file name plus the path inside it:common.actions.save. Eachsrc/locales/<locale>/index.tsbundles the files of its language into one chunk. - The dictionaries are loaded by Transloco (
@jsverse/transloco: only English and the active language, through the loader ofsrc/core/i18n.ts), and templates read them witht().t()reads the current language, a signal, so the language menu re-renders every template instantly, without a reload:
import { t, lang } from '@/core/i18n';
import { formatValue } from '@/core/format';
export class ReportsSalesPage {
protected readonly t = t;
protected readonly fmt = formatValue;
protected readonly lang = lang; // the active language: lang() is 'en', 'es', 'pt', 'fr' or 'ar'
}<button type="button" class="fd-btn fd-btn--primary">
<span class="fd-btn__label" data-i18n="common.actions.save">{{ t('common.actions.save') }}</span>
</button>
<input class="fd-input" type="search" [attr.placeholder]="t('common.actions.search')" data-i18n-attr="placeholder:common.actions.search">
<span>{{ fmt('currency', 48290.5) }}</span> <!-- $48,290.50 · 48.290,50 US$ · ٤٨٬٢٩٠٫٥٠ US$ -->- The
TranslocoServiceis available for dependency injection as usual (inject(TranslocoService)), for example forselectTranslate()streams in your services; the active language is the same. - The
data-i18nanddata-i18n-attrattributes are optional in your own components; the template keeps them so that markup created at runtime (data grids, page scripts, foundry-ui behaviors) is translated too. - The choice is saved in the browser (
fd:lang), and demo links accept?lang=es. Without a saved choice the template starts in English.<html lang>anddirfollow the language.
Placeholders and plurals
The dictionaries keep one format in every Orbix edition (the Transloco transpiler of src/core/i18n.ts).
Placeholders use double braces: "greeting": "Welcome back, {{name}}" and
t('greeting', { name: user.name }).
Plurals use _one / _other keys (Arabic also _zero, _two, _few, _many, the plural categories of the
language) and a count:
{ "count_one": "{{count}} task", "count_other": "{{count}} tasks" }{{ t('tasks.count', { count: tasks().length }) }}Formats: fmt(type, value, options) with the types number, decimal, compact, currency,
currency-compact, percent, date, date-long, date-short, datetime, time, month, weekday,
relative and duration-min; options { digits, currency }.
Add a language
- Copy
src/locales/entosrc/locales/deand translate the values (keep the keys andindex.ts). - In
src/core/i18n.ts, add it toLANGUAGES(['en', 'es', 'pt', 'fr', 'ar', 'de']) and to the dictionaries map (de: () => import('../locales/de')). - Add it to the language menus in
src/components/shell/topbar.htmlandsrc/components/auth/controls.html(copy one of the existing entries and changedata-fd-lang,lang, thearia-checkedbinding and the label). - Add the code to the language pattern of
src/boot/orbix-boot.js(/^(en|es|pt|fr|ar|de)$/). - Run
npm test– the translation tests check that every language has every key with the same placeholders.
For a right-to-left language (Hebrew, Persian, Urdu) nothing else is needed: the direction is derived from the language code.
Remove a language
Remove it from LANGUAGES and the dictionaries map, the two language menus and the boot pattern, then delete
src/locales/<locale>/.
Translating your own texts
Never write visible text directly in a template: always use a key, so every language stays complete. The test
tests/hardcoded-text.spec.ts renders every page and fails when a visible text or label is not translated (demo
content inside data-demo elements is allowed). Keep your keys in their own file per area (reports.json) to
find them easily.