Skip to content
Orbix Next.js · Tailwind CSS v1.0.3

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.

Language menu

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.
  • The dictionaries are loaded with i18next and components read them with the useI18n() hook (built on react-i18next), so the language menu re-renders the page instantly, without a reload. English is bundled (src/locales/index.ts): Next.js prerenders every page in English and the browser hydrates the same text; the saved language is loaded on demand right after, under the preloader. <html lang> and dir follow the language:
const { t, fmt, lang } = useI18n();

<button type="button" className="fd-btn fd-btn--primary">
  <span className="fd-btn__label" data-i18n="common.actions.save">{t('common.actions.save')}</span>
</button>
<input className="fd-input" type="search" 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 data-i18n and data-i18n-attr attributes 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. This works with the static export (no server needed).

Placeholders and plurals

Placeholders use the i18next syntax: "greeting": "Welcome back, {{name}}" and t('greeting', { name: user.name }).

Plurals use _one / _other keys (Arabic also _zero, _two, _few, _many) 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

  1. Copy src/locales/en to src/locales/de and translate the values (keep the keys).
  2. Add its loader to LOADERS in src/locales/index.ts (copy the es entry and change the folder) and add it to LANGUAGES in src/core/i18n.ts: ['en', 'es', 'pt', 'fr', 'ar', 'de'].
  3. Add it to the language menus in src/components/shell/Topbar.tsx and src/components/auth/AuthControls.tsx (copy one of the existing entries and change data-fd-lang, lang, the aria-checked test and the label).
  4. Add the code to the language pattern of src/boot/orbix-boot.js (/^(en|es|pt|fr|ar|de)$/).
  5. 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, LOADERS, the two language menus and the boot pattern, then delete src/locales/<locale>/.

Translating your own texts

Never write visible text directly in a component: always use a key, so every language stays complete. The test tests/hardcoded-text.test.tsx 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.

Language in the URL (optional)

Orbix keeps one URL per page and switches the language in the browser, which works on every static host. If you prefer localized URLs (/es/apps/kanban), Next.js routing can carry the language:

  1. Move the route groups under a dynamic segment: src/app/[lang]/(app)/..., src/app/[lang]/(auth)/..., src/app/[lang]/(blank)/..., and give the [lang] folder a layout that exports generateStaticParams() { return LANGUAGES.map((lang) => ({ lang })); } (the static export then writes every page once per language).
  2. In that layout, read params.lang and call changeLanguage(lang) in the client root (src/core/i18n.ts), and render the prefix in your links (/${lang}/apps/kanban) and in src/config/menu.ts.
  3. With the server build (npm run build:server), add a middleware.ts that redirects / to the visitor's language (the Accept-Language header). A static export cannot redirect on the server: link to /en/ instead.

See "Internationalization" in the Next.js documentation for the routing part; the dictionaries, useI18n() and the RTL support of Orbix stay the same.