Skip to content
Orbix Vue · Bootstrap 5 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 into vue-i18n (only English and the active language; src/core/i18n.ts) and components read them with the useI18n() composable, so the language menu re-renders the page instantly, without a reload:
<script setup lang="ts">
import { useI18n } from '@/composables/useI18n';

const { t, fmt, lang } = useI18n();
</script>

<template>
  <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" :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$ -->
</template>
  • lang is a computed ref with the active language (en, es, pt, fr or ar). The vue-i18n instance is also installed in the app (app.use(i18n) in src/main.ts), and i18n.global.locale holds the same value.
  • 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. <html lang> and dir follow the language.

Placeholders and plurals

The dictionaries keep one format in every Orbix edition, compiled by src/core/i18n.ts for vue-i18n. 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

  1. Copy src/locales/en to src/locales/de and translate the values (keep the keys).
  2. 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.vue and src/components/auth/AuthControls.vue (copy one of the existing entries and change data-fd-lang, lang, the aria-checked binding 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, 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.test.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.