Locale Management
Switching Locales
Section titled “Switching Locales”<script setup>import { useI18n } from '@fluenti/vue'
const { locale, setLocale, getLocales, isLoading, preloadLocale } = useI18n()</script>
<template> <div class="locale-switcher"> <button v-for="l in getLocales()" :key="l" :class="{ active: locale === l }" @click="setLocale(l)" @mouseenter="preloadLocale(l)" > {{ l }} </button> <span v-if="isLoading">Loading...</span> </div></template>function LocaleSwitcher() { const { locale, setLocale, getLocales, isLoading, preloadLocale } = useI18n()
return ( <div> {getLocales().map(l => ( <button classList={{ active: locale() === l }} onClick={() => setLocale(l)} onMouseEnter={() => preloadLocale(l)} > {l} </button> ))} {isLoading() && <span>Loading...</span>} </div> )}Reactivity
Section titled “Reactivity”When you call setLocale():
- Vue: All
t()calls in templates re-evaluate (they readlocale.value). Allttagged templates (ComputedRefs) recompute. - Solid: All components reading
locale()re-render.createMemovalues recompute.
Every $d() and $n() call also updates automatically.
Lazy Loading
Section titled “Lazy Loading”Use msg for translations that need to be defined outside of components — in constants, stores, or route definitions.
The Problem
Section titled “The Problem”// This won't work — t`` needs a component contextconst ROLES = { admin: t`Administrator`, // Error: no component context}The Solution: msg“
Section titled “The Solution: msg“”import { msg } from '@fluenti/core'
const ROLES = { admin: msg`Administrator`, user: msg`Regular User`,}msg returns a MessageDescriptor — it records the message text without translating it. Resolve it at render time with t():
<template> <span>{{ t(ROLES.admin) }}</span></template>Use Cases
Section titled “Use Cases”- Route meta:
{ meta: { title: msgDashboard} } - Store constants: Error messages, role names, status labels
- Config objects: Menu items, navigation labels
- Enum-like maps: Any mapping where values need translation
Code Splitting
Section titled “Code Splitting”By default, all locale messages are bundled together. For apps with many locales or large catalogs, code splitting loads locale data on demand.
How It Works
Section titled “How It Works”- Run
fluenti compile --splitto generate per-locale ES modules with named exports - Each message becomes a
/* @__PURE__ */annotated export — unused messages are tree-shaken - Configure
chunkLoaderto dynamically import locale chunks - When
setLocale()is called, the chunk is loaded before switching
Compile with split mode:
npx fluenti compile --splitThis generates:
locales/compiled/en.js— named exports per messagelocales/compiled/zh-CN.js— same exports, translatedlocales/compiled/index.js— locale list and lazy loaders
Configure the plugin:
// Vueconst i18n = createFluentVue({ locale: 'en', messages: { en }, splitting: true, chunkLoader: (locale) => import(`./locales/compiled/${locale}.js`),})
// Solid<I18nProvider locale="en" messages={{ en }} splitting={true} chunkLoader={(locale) => import(`./locales/compiled/${locale}.js`)}> <App /></I18nProvider>Static vs Dynamic Splitting
Section titled “Static vs Dynamic Splitting”| Strategy | splitting: 'static' | splitting: 'dynamic' |
|---|---|---|
| Bundle | All locales in bundle, tree-shaken | Only default locale bundled |
| Loading | Sync — no loading states | Async — needs isLoading handling |
| Best for | Few locales, small catalogs | Many locales, large catalogs |
Configure in fluenti.config.ts:
export default { splitting: 'dynamic', defaultBuildLocale: 'en',}Build vs Dev Mode
Section titled “Build vs Dev Mode”| Mode | Behavior |
|---|---|
| Dev | All locales loaded eagerly for instant HMR |
| Build | Only defaultBuildLocale is bundled; others are lazy chunks |
Fallback Chain
Section titled “Fallback Chain”When a message is not found in the current locale, Fluenti tries:
- Current locale
- Fallback chain (if configured)
fallbackLocale(if set)- Returns the message ID
Configuration
Section titled “Configuration”const i18n = createFluentVue({ locale: 'zh-TW', fallbackLocale: 'en', messages: { en, 'zh-CN': zhCN, 'zh-TW': zhTW }, fallbackChain: { 'zh-TW': ['zh-CN', 'en'], 'pt-BR': ['pt', 'en'], '*': ['en'], },})With this config, when locale is zh-TW:
- Try
zh-TWcatalog - Try
zh-CNcatalog (from fallbackChain) - Try
encatalog (from fallbackChain) - Try
encatalog (from fallbackLocale)
Missing Handler
Section titled “Missing Handler”For custom behavior when a message is not found:
const i18n = createFluentVue({ locale: 'en', messages, missing: (locale, id) => { console.warn(`Missing translation: ${locale}/${id}`) return undefined // or return a fallback string },})