Skip to content

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 ​

ts
import i18nModule, {
  useI18n,
  useLocalePath,
  useSwitchLocalePath,
  defineI18nConfig,
  createI18nHeadEntry,
  type ResuxI18nLocaleInput,
  type ResuxI18nMessageSource,
  type ResuxI18nConfigInput,
  type ResuxI18nModuleOptions,
  type UseI18nResult
} from 'resuxjs/i18n'

Configuration ​

ts
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:

ts
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:

txt
pages/about.vue
pages/products/[id].vue
pages/docs/[...slug].vue

with English and Arabic locales, prefix produces real records such as:

txt
/en/about
/ar/about
/en/products/:id
/ar/products/:id
/en/docs/:slug*
/ar/docs/:slug*

prefix_except_default produces:

txt
/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() ​

ts
function defineI18nConfig<T extends ResuxI18nConfigInput>(config: T): T

Typed identity helper for reusable i18n configuration.

useI18n() ​

ts
function useI18n(): UseI18nResult

The returned object includes:

ts
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:

ts
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() ​

ts
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() ​

ts
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() ​

ts
function useLocalePath(): (
  to: string,
  localeCode?: string
) => string

Returns the route-building function from useI18n().

useSwitchLocalePath() ​

ts
function useSwitchLocalePath(): (
  localeCode: string,
  to?: string
) => string

Returns the current-route switching function from useI18n().

createI18nHeadEntry() ​

ts
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:

ts
{
  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.

Source-aligned documentation for the Resux resumable web framework.