useTranslation
Gives a component the translate function t, the page language, its text direction and the language name.
import { useTranslation, I18nContextValue } from '@salla.sa/twilight-theme-engine/i18n';In plain words
A storefront speaks the shopper's language. Instead of writing "Cart" in a component, you write a key such as common.titles.cart, and t() (short for translate) returns the text for that key in the page's language: "سلة المشتريات" on /ar pages, "Shopping Cart" on /en pages.
useTranslation() is a hook: a function whose name starts with use, called at the top of a component. Besides t, it tells you the page's locale ('ar'), whether its text runs right-to-left (isRTL), and the language's name.
The texts come from two places: Salla's own messages, shared by every store, and your theme's locales/*.json files for the words only your theme uses.
Signature
function useTranslation(ns?: string | string[]): {
t: TFunction; // t(key) · t(key, 'Default text') · t(key, { name: 'Sara' })
i18n: i18n; // the i18next instance of the nearest I18nProvider
ready: boolean;
locale: string; // 'ar'
direction: 'ltr' | 'rtl';
isRTL: boolean;
isLTR: boolean;
languageName: string; // 'العربية', 'English', otherwise the code upper-cased
}
interface I18nContextValue {
locale: string;
direction: 'ltr' | 'rtl';
isRTL: boolean;
isLTR: boolean;
languageName: string;
}Try it live
t() from useTranslation(), reading Salla's messages and the playground's own locales/*.json for this page's language.Try this: pick common.titles.cart, then set the namespace to theme: only the theme files are searched and the key comes back. Then switch the ar / en pill (top bar, or the ☰ menu on a phone).مرحبًا من ترجمات القالب نفسه
- locale
- ar
- direction
- rtl (isRTL: true)
- languageName
- العربية
- ready
- true
import { useTranslation } from '@salla.sa/twilight-theme-engine/i18n';
export function Label() {
const { t } = useTranslation();
return <span>{t('playground.greeting')}</span>;
}
Example
import { useTranslation } from '@salla.sa/twilight-theme-engine/i18n';
export function CartHeading({ count }: { count: number }) {
const { t, locale, direction } = useTranslation();
return (
<h1 lang={locale} dir={direction} className="cart-heading">
{t('common.titles.cart', 'Cart')} <small>({count})</small>
</h1>
);
}
How it behaves
It returns react-i18next's own
useTranslation(ns)result (t,i18n,ready) spread together with the engine's language context,I18nContextValue.t(key)searches two i18next namespaces in order:app, Salla's shared messages for the page language (downloaded byrootBeforeLoad, see translations), thentheme, yourlocales/*.json(see Theme translations). When both have the key, Salla's text wins.Keys are split on
., and a dotted key is also looked up whole, so nested JSON ({ "common": { "titles": { "cart": "…" } } }) and flat keys ("common.titles.cart": "…") both resolve.A missing key returns the key itself, or the default you pass as the second argument. i18next's
{{name}}interpolation is on, withescapeValue: false; React still escapes the text when it renders it.readyis alwaystrue: every message is in memory before the page renders, and the instance is created withreact: { useSuspense: false }, so nothing suspends.locale,direction,isRTL,isLTRandlanguageNamecome from the instance'slanguagethroughgetLanguageInfo, so they describe the nearestI18nProvider: the page's, unless you nest one.A key that names a group rather than a text, such as
t('common.titles'), returns the sentence "key 'common.titles (ar)' returned an object instead of string."Outside
TwilightProviderit does not throw: the language fields are the context's Arabic defaults (ar,rtl,العربية), andtuses the last instance react-i18next registered, or returns keys when there is none.
Gotchas
t(key, { count })does not pick a plural form from a Salla-style translation such as{0} no items|{1} one item|[2,*] :count items: i18next looks forkey_one/key_othervariants, finds none, and returns the whole string. Fix:formatSallaPlural(t(key), count)from@salla.sa/twilight-theme-engine/utils(see formatSallaPlural).Salla's messages use Laravel placeholders, which i18next does not fill:
t('common.elements.search_about', { word })returns "Search for (:word)". Fix: replace the placeholder yourself,t('common.elements.search_about').replace(':word', word), as the engine'sCartSummarydoes with:amount.Choosing a namespace by prefix does not work: the instance has
nsSeparator: false, sot('theme:lookbook.title')treats the whole string as a key and returns it.useTranslation('theme')does select a namespace, but then searches only your files, and Salla keys such ascommon.titles.cartcome back as keys. Fix: calluseTranslation()with no argument, and pass{ ns: 'theme' }to onetcall when you need your own text for a key Salla also has.t(key, { lng: 'en' })on an Arabic page still returns Arabic: the instance holds only the page language's messages (createI18nInstanceloads<locale>.transalone) and falls back to that language. Fix: link to the other language, or render a subtree with a nested I18nProvider.t('some.key') || 'Default'never shows the default: a missing key returns the key, which is a non-empty string. Fix: pass the default as the second argument,t('some.key', 'Default').
Related
How a theme's locales/*.json files reach t(): the Vite plugin bundles them, TwilightProvider receives them, and Salla's messages are checked first.
formatSallaPluralPicks the right plural form out of a Salla translation such as '{1} one item|[2,*] :count items' and fills in the number.
getLanguageInfo & RTL_LOCALESReturns a language code's display name and text direction; RTL_LOCALES lists the four codes the engine treats as right-to-left.
translationsDownloads Salla's shared translations file, every storefront message in Arabic and English, which the engine's translate function reads.
useTwilightReads everything TwilightProvider knows: store, theme, settings, language, direction, current page, login token and the Salla SDK.