Add translation keys
Add Arabic and English strings to your theme and use them in components.
Use this whenever your theme shows text of its own, so it reads correctly in Arabic and English.
Goal: pages.faq.title shows the right words in each language.
Strings live in locales/ar.json and locales/en.json as flat, dot-separated keys. The localesDir option of twilightReact() bundles every *.json file in that folder, and the root route hands the result to TwilightProvider. At runtime the store's own translations are looked up first and your theme keys are the fallback. See Languages and RTL and useTranslation.
Add the key to both files
The dots are part of the key; do not nest objects.
{
"pages.faq.title": "Frequently asked questions",
"pages.faq.items_count": "{{count}} questions"
}{
"pages.faq.title": "الأسئلة الشائعة",
"pages.faq.items_count": "{{count}} أسئلة"
}Use it with a fallback
The second argument is the fallback text, shown if the key is missing.
import { useTranslation } from '@salla.sa/twilight-theme-engine/i18n';
export function FaqHeader({ count }: { count: number }) {
const { t } = useTranslation();
return (
<header>
<h1>{t('pages.faq.title', 'Frequently asked questions')}</h1>
<p>{t('pages.faq.items_count', '{{count}} questions', { count })}</p>
</header>
);
}Confirm the wiring
A new theme already has it, so only check it is still there.
twilightReact({ localesDir: './locales' })import themeTranslations from 'virtual:twilight/theme-translations';
<TwilightProvider translations={themeTranslations} layout={ThemeLayout}>Check it worked
Open the page at /en/faq and /ar/faq: the heading changes language. If you see the fallback in both, a JSON file is invalid (first trap).
Traps
- A JSON syntax error empties every translation. The plugin catches the parse error and returns an empty module, so all
t()calls silently show their fallback. Validate the files. - A key in one language only shows the fallback (or the raw key) after a language switch.
- Store translations win. If the same key exists upstream, your theme value is ignored. Rename yours, following the
pages.<page>.<thing>andcommon.<group>.<thing>pattern. - Always pass a fallback. Without it a missing key renders as the raw key.
- Without
translations={themeTranslations}onTwilightProvider, none of your files load. - The file name is the locale code. Add
fr.jsonfor French. - Interpolation is
{{name}}and values are not HTML-escaped. Never pass untrusted markup.
Next
- Languages and RTL: direction and language switching.
- Add a page: where most new strings come from.