Multi-language docs & content
How Restora 360 handles translations across the docs, the storefront, and the admin UI.
Principles
Restora 360's i18n is built on three rules:
- Slugs are locale-neutral. The URL
/docs/getting-started/what-is-restorais the same in every language. Translations override the content of the article, not the URL. This keeps share links, backlinks, and SEO canonical URLs stable. - Translations are additive, never destructive. A missing translation falls back to the default-locale (English) string. You can ship a partial translation without breaking anything.
- Currency is per-tenant, not per-locale. A French restaurant selling in Paris keeps EUR even if the customer browses in English. Locale controls language; currency is set in Settings → General Info.
How a doc article carries translations
Every DocArticle accepts an optional i18n field — a map from locale code ('fr', 'es', 'ar', …) to the subset of fields you want to override:
{
slug: 'what-is-restora',
categoryId: 'getting-started',
title: 'What is Restora 360?',
metaDescription: 'A one-line, English meta description.',
summary: 'English summary.',
sections: [/* English sections */],
i18n: {
fr: {
title: 'Qu\'est-ce que Restora 360 ?',
metaDescription: 'Une meta description française.',
summary: 'Résumé français.',
sections: [/* French sections */],
},
es: {
title: '¿Qué es Restora 360?',
// metaDescription + sections fall back to English.
},
},
}The renderer chooses the locale from the request (cookie locale, then Accept-Language, then English). Anything missing falls back field-by-field, not article-by-article — so a Spanish article with only a translated title still benefits from the English body.
Storefront translations (tenant-facing)
Tenant-facing pages (menu, cart, checkout, blog) use the existing Translations admin panel:
- Owner adds a locale in Admin → Translations → Locales.
- The platform pre-translates UI chrome (buttons, errors, emails) using the bundled translation memory.
- For free-text fields (menu item names, descriptions, blog posts) the AI translator (Anthropic) generates a draft the owner can refine.
- The locale selector on the storefront persists the choice in a
localecookie scoped to the tenant.
The storefront URLs stay path-clean — /menu, /cart — and the locale is invisible to crawlers in the URL but advertised via the Content-Language response header and <link rel="alternate" hreflang="…"> tags.
RTL languages
Arabic, Hebrew, Persian, and Urdu are right-to-left. When the active locale is RTL, the platform:
- Adds
dir="rtl"to<html>. - Mirrors layout (sidebars switch sides, padding/margin flip via
dir-aware Tailwind utilities). - Keeps numerals in the locale-native script (Arabic-Indic for
ar-SA, Latin forar-EG, configurable).
Currency symbols and dates use Intl.NumberFormat / Intl.DateTimeFormat with the active locale.
Fallback chain
When deciding which string to show, the system walks this chain top-to-bottom and stops at the first match:
- The exact requested locale (e.g.
fr-CA). - The language-only locale (e.g.
fr). - The tenant's default locale (set in Settings → General Info).
- English (
en) as the platform-wide fallback.
This means a tenant whose default is it will see an Italian fallback before English, but a customer asking for pt on the same tenant gets the English fallback if no Italian → Portuguese path is configured.
Adding a new docs language
Until the docs CMS lands (P2 in the roadmap), translations are added in code:
- Open the article in
src/lib/docs-center/articles.ts. - Add a key to the
i18nmap keyed by the ISO 639-1 code. - Ship only the fields you have. Missing fields fall back to English automatically.
- The search index is built from the active-locale text at render time — you don't need to maintain a separate index per language.
When the CMS adapter lands, this same shape becomes the JSON contract between the CMS and the renderer, so any work you do now ports directly.
Frequently asked
- No. The slug is locale-neutral. The active locale is selected from the user's cookie / Accept-Language, and search engines see the same canonical URL with hreflang tags pointing at the same path. This avoids duplicate-content penalties.
- You get a translated title and English body. The fallback works field-by-field, so a partial translation is always better than no translation.
- Yes. In Settings → General Info, set the default locale. Customers without an explicit preference (no cookie, no matching Accept-Language) will see that locale.