i18n API (resuxjs/i18n)
resuxjs/i18n exports the Resux i18n module, configuration/runtime types, and locale composables. Enabling the module also activates compiler-level localization of page route records.
Route injection is part of the feature
localePath() is not what makes /ar/** work. The compiler transforms page records before the final route manifest is written, so localized URLs work for direct SSR requests and refreshes.
Imports
import i18nModule, {
useI18n,
useLocalePath,
useSwitchLocalePath,
defineI18nConfig,
createI18nHeadEntry,
type ResuxI18nLocaleInput,
type ResuxI18nMessageSource,
type ResuxI18nConfigInput,
type ResuxI18nModuleOptions,
type UseI18nResult
} from 'resuxjs/i18n'Configuration
interface ResuxI18nLocaleInput {
code: string
name?: string
dir?: 'ltr' | 'rtl'
}
type ResuxI18nMessageSource =
| Record<string, unknown>
| string
| (() => unknown | Promise<unknown>)
interface ResuxI18nConfigInput {
defaultLocale: string
fallbackLocale?: string
strategy?: 'prefix' | 'prefix_except_default' | 'no_prefix'
locales: ResuxI18nLocaleInput[]
messages?: Record<string, ResuxI18nMessageSource>
seo?: {
hreflang?: boolean
}
}Recommended configuration:
export default defineResuxConfig({
modules: ['resuxjs/i18n'],
i18n: {
defaultLocale: 'en',
fallbackLocale: 'en',
strategy: 'prefix_except_default',
locales: [
{ code: 'en', name: 'English', dir: 'ltr' },
{ code: 'ar', name: 'العربية', dir: 'rtl' }
],
messages: {
en: './locales/en.json',
ar: './locales/ar.json'
},
seo: { hreflang: true }
}
})The module default strategy is prefix_except_default. Under prefix, / redirects to the default locale root. Under prefix_except_default, default-prefixed page records are not generated. Under no_prefix, the pathname remains unchanged.
Generated route behavior
Given:
pages/about.vue
pages/products/[id].vue
pages/docs/[...slug].vuewith English and Arabic locales, prefix produces real records such as:
/en/about
/ar/about
/en/products/:id
/ar/products/:id
/en/docs/:slug*
/ar/docs/:slug*prefix_except_default produces:
/about
/ar/about
/products/:id
/ar/products/:id
/docs/:slug*
/ar/docs/:slug*Localized records keep unique route-record IDs while pointing to the same compiled page/component module. The page source is not compiled once per language.
defineI18nConfig()
function defineI18nConfig<T extends ResuxI18nConfigInput>(config: T): TTyped identity helper for reusable i18n configuration.
useI18n()
function useI18n(): UseI18nResultThe returned object includes:
interface UseI18nResult {
locale: Readonly<Ref<string>>
dir: Readonly<Ref<'ltr' | 'rtl'>>
locales: ResuxI18nLocale[]
defaultLocale: string
fallbackLocale: string
strategy: ResuxI18nStrategy
t(key: string, params?: ResuxI18nTranslationParams): string
tm(key: string): unknown
resolveLocalized(value: unknown): string | null
localePath(to: string, localeCode?: string): string
switchLocalePath(localeCode: string, to?: string): string
setLocale(localeCode: string, to?: string): Promise<void> | void
}Example:
const {
locale,
dir,
t,
tm,
resolveLocalized,
localePath,
switchLocalePath,
setLocale
} = useI18n()
const title = t('product.title')
const navigation = tm('navigation')
const localizedLabel = resolveLocalized({ en: 'More', ar: 'المزيد' })
const arabicProduct = localePath('/products/42?tab=reviews#top', 'ar')
await setLocale('ar')Locale resolution
For prefix and prefix_except_default, the active locale is resolved from the route pathname both during SSR and in the browser. Query strings and hashes are deliberately excluded from locale/route identity.
For no_prefix, SSR starts from the configured default locale because no locale exists in the pathname. The client uses per-app reactive locale state; setLocale() updates that state and the document lang/dir without changing the URL.
localePath()
localePath('/products/42?tab=reviews#top', 'ar')The helper first removes an existing configured locale prefix, applies the target strategy, then restores query/hash. Repeated calls therefore do not create duplicate prefixes.
switchLocalePath()
const switchLocalePath = useSwitchLocalePath()
switchLocalePath('ar')Uses the current logical route when to is omitted. Dynamic parameter values are already present in the current pathname and are preserved.
setLocale()
For prefixed strategies, setLocale() calculates the target localized URL and prefers the Resux client router. If no client router is available in a browser, it falls back to location.assign().
For no_prefix, it updates locale state directly and does not perform a fake pathname navigation.
Unknown locale codes are ignored rather than constructing an unsupported locale path.
useLocalePath()
function useLocalePath(): (
to: string,
localeCode?: string
) => stringReturns the route-building function from useI18n().
useSwitchLocalePath()
function useSwitchLocalePath(): (
localeCode: string,
to?: string
) => stringReturns the current-route switching function from useI18n().
createI18nHeadEntry()
function createI18nHeadEntry(
routePath: string,
routeOrigin?: string
): {
htmlAttrs: Record<string, string>
link: Array<Record<string, string>>
}Builds server/client i18n head information from public runtime config. The canonical pathname excludes query/hash. When seo.hreflang is enabled, alternate entries are emitted for configured locales plus x-default for the default locale.
Arabic configuration with dir: 'rtl' produces:
{
htmlAttrs: { lang: 'ar', dir: 'rtl' },
// canonical + alternate link records
}If runtime i18n config is unavailable, the helper returns English LTR attributes and no links.
Translation fallback and safety
t() checks the active locale, then the configured fallback locale, then returns the key. Nested lookup reads own properties only and rejects prototype-sensitive keys.
Message catalogs are public runtime data. Do not put credentials, API secrets, or server-only configuration in translations.
SSR and resumability
Localized route matching happens before page render. The SSR payload therefore starts with the same route-derived locale, lang, and dir that the client resumes. A localized route is not a post-hydration rewrite.