Languages & Locales
Introduction
ReeWeb has first-class support for multi-language sites. Every page renders in every configured language, the default language is served at the root of your site, and other languages get a language-prefixed URL path. The configuration lives in a single file.
Configuration
Languages are declared in config/supported_languages.ts:
// All languages with translation files
export const languages = ["en", "sl"] as const;
// Languages shown in the language switcher
export const active_languages = ["sl", "en"] as const;
// First in list - served at root (no /{lang} prefix)
export const default_language = "sl";
// Human-readable names for the language switcher
export const language_names: Record<string, string> = {
en: "English",
sl: "Slovenian",
};
// BCP-47 locale strings for date/time formatting
export const language_locales: Record<string, string> = {
en: "en-US",
sl: "sl-SI",
};
The distinction between languages and active_languages matters:
languages- all languages that have translation files. The SSG script loads translations for these.active_languages- languages that appear in the UI language switcher. A subset oflanguages.
Both are typed as readonly string[] (using as const), which gives you full TypeScript type safety when referencing them elsewhere.
How Languages Affect URLs
The default language is served at the root of your site - no URL prefix. All other languages are served under /{lang}/:
/ → Slovenian (default)
/about/ → Slovenian
/english-only/ → Slovenian (English-only page renders at root)
/en/ → English index page
/en/about/ → English about page
This is handled automatically by both the SSG script (scripts/ssg.ts) and the dev server (scripts/dev.ts). The URL structure is:
/{lang}/{localized-path}/
Where {localized-path} may differ per language if you use route_name in translations (see Localized Routes).
Adding a New Language
To add a language, say German (de):
- Add
"de"tolanguages,active_languages,language_names, andlanguage_localesinconfig/supported_languages.ts - Create a
de.jsontranslation file in each directory that has anen.jsonorsl.json
That's it. The scripts automatically discover the new translation files and render every page in German. No other configuration is needed.
See the Adding a Language recipe for a step-by-step walkthrough.
Language-Variant Templates
Most pages share the same template across languages - only the translation strings differ. For pages that need different markup per language (a landing page with language-specific hero content, for example), you can create language-specific template variants:
about/index.en.ree- English versionabout/index.sl.ree- Slovenian version
The resolution chain is:
{name}.{requested_lang}.ree- exact match for the current language{name}.{default_language}.ree- fallback to the default language{name}.ree- generic fallback
This applies to every template load - pages, layouts, includes, and components.
Locale Strings for Date Formatting
The language_locales map feeds into template helpers like js_date_to_locale_string(), which use Intl.DateTimeFormat under the hood. Each entry should be a valid BCP-47 locale tag:
| Code | Locale | Example Date |
|---|---|---|
en | en-US | 06/15/26 |
sl | sl-SI | 15. 06. 26 |
de | de-DE | 15.06.26 |
fr | fr-FR | 15/06/26 |
Using the right locale means dates, times, currencies, and percentages are automatically formatted according to regional conventions.