Built-in i18n with URL-prefix-based locale routing, SSR support, and automatic locale detection.
Add the i18n block to your lumenjs.config.ts:
export default { title: 'My App', i18n: { locales: ['en', 'fr'], defaultLocale: 'en', prefixDefault: false, // / instead of /en/ }, };
Create flat JSON files in locales/ at your project root:
Use flat dot-notation keys:
// locales/en.json { "home.title": "Welcome", "home.subtitle": "Build with Lit", "nav.docs": "Docs" } // locales/fr.json { "home.title": "Bienvenue", "home.subtitle": "Construisez avec Lit", "nav.docs": "Documentation" }
Import t() from @lumenjs/i18n and use it in your templates:
import { t } from '@lumenjs/i18n'; export class PageIndex extends LitElement { render() { return html`<h1>${t('home.title')}</h1>`; } }
| Function | Description |
|---|---|
t(key) | Returns the translated string, or the key if not found |
getLocale() | Returns the current locale string |
setLocale(locale) | Switches locale — sets cookie and navigates to the localized URL |
The locale is resolved using this priority chain:
1. URL prefix: /fr/about → locale fr
2. Cookie nk-locale (set on explicit switch)
3. Accept-Language header (auto-detected from browser)
4. Config defaultLocale
prefixDefault: false, the default locale uses clean URLs (/about instead of /en/about). Non-default locales always use a prefix (/fr/about).
Use setLocale() to build a language switcher:
import { getLocale, setLocale } from '@lumenjs/i18n'; render() { return html` <button class=${getLocale() === 'en' ? 'active' : ''} @click=${() => setLocale('en')}>EN</button> <button class=${getLocale() === 'fr' ? 'active' : ''} @click=${() => setLocale('fr')}>FR</button> `; }
The current locale is passed to loaders, so you can return locale-specific data:
export async function loader({ locale }) { const posts = await fetchPosts({ lang: locale }); return { posts }; }
Translations are fully server-rendered. The response includes:
1. Pre-rendered HTML with translated content (no flash of untranslated text)
2. <html lang="fr"> attribute set dynamically
3. Inlined translations for client hydration