translations
Downloads Salla's shared translations file, every storefront message in Arabic and English, which the engine's translate function reads.
import { translations } from '@salla.sa/twilight-theme-engine/api/translations';In plain words
Labels such as "Add to cart" are not written in your theme: Salla keeps them in one shared file, with every message in each language. translations.get() downloads that file.
The engine does this before every page and builds the translate function t from it, which is what components should use (useTranslation().t('pages.cart.total')). Read the file yourself only to inspect or search it.
Signature
translations.get(): Promise<TranslationMessages | null> // GET https://cdn.salla.network/js/translations.json
translations.queries.byLocale() // key ['translations']: takes no locale
type TranslationMessages = Record<string, Record<string, string>>;
// real shape: { 'ar.trans': { common: {…}, pages: {…}, … }, 'en.trans': {…} }Try it live
| data['ar.trans'] | إضافة للسلة |
|---|---|
| data['en.trans'] | Add to cart |
| t() on this en page | Add to cart |
import { useTranslation } from '@salla.sa/twilight-theme-engine/i18n';
// In a component, prefer t(): it reads this same file for the page's language.
export function AddToCartLabel() {
const { t } = useTranslation();
return <span>{t('pages.cart.add_to_cart')}</span>;
}
Example
import { useQuery } from '@tanstack/react-query';
import { translations } from '@salla.sa/twilight-theme-engine/api/translations';
import { useTranslation } from '@salla.sa/twilight-theme-engine/i18n';
/** Development helper: the cart messages Salla provides for this page's language. */
export function CartMessages() {
const { locale } = useTranslation();
const { data } = useQuery(translations.queries.byLocale());
// Typed as flat strings, but each file is nested: pages → cart → total.
const file = data?.[locale + '.trans'] as unknown as
| { pages?: { cart?: Record<string, string> } }
| undefined;
return (
<dl>
{Object.entries(file?.pages?.cart ?? {}).map(([key, text]) => (
<div key={key}>
<dt>pages.cart.{key}</dt>
<dd>{text}</dd>
</div>
))}
</dl>
);
}
How it behaves
Fetched through the
cdnclient, so no store or customer headers are sent: the file is the same for every store. Timeout 5 s. About 150 KB with onlyar.transanden.transin it (2026-09-16).It never throws: a failed download logs a warning and returns
null, andtis then built with no Salla messages, so a key renders as itself (or as the fallback you pass).rootBeforeLoadawaitsensureQueryData(translations.queries.byLocale())on every navigation and passes the file tocreateI18nInstance(locale, …), which takes<locale>.transas the default namespace and falls back to the theme's own bundled translations.Because the file sits in the query cache after the server render, it travels to the browser with the page HTML.
Gotchas
TranslationMessagespromises string values one level down, but the files are nested (pages→cart→total).data['ar.trans']['pages.cart.total']finds nothing: walk the dotted key, or uset().Despite its name,
byLocale()takes no locale and its key is only['translations']: one file holds every language.docs/11-internationalization.md shows
translationsQueries.byLocale(locale), a store-specific CDN address and akeysfactory. None of that exists: the export istranslations, and it reads one shared file.
Related
Source and docs
- Engine source:
packages/theme-engine/src/api/translations.ts