X Enterprises
Composables

useXafLocale

Reactive locale state composable. Reads from a parent XAFLocaleProvider via inject, falls back to a local singleton. Includes a small t() helper for tiny strings.

useXafLocale

Reactive locale state composable for the XAF layer. Designed to be used inside an <XAFLocaleProvider> so locale state is shared across the whole app; outside a provider, it returns a local singleton scoped to the call site (useful for tests and for components that need to render the locale code without depending on the provider tree).

The locale persists across visits via a cookie (default xaf_locale). Changing the locale dispatches a xaf:locale:changed window event so non-Vue code (price formatters, route middleware) can react.

Usage

const { locale, locales, resolved, setLocale, t } = useXafLocale()

// Read current locale (reactive):
console.log(locale.value) // "en"

// Switch:
setLocale("es")

// Simple key-value translator for tiny strings:
t({ en: "Buy now", es: "Comprar", fr: "Acheter" })
// → "Buy now" (when locale is "en")

// Resolved full option:
resolved.value // { code: "en", label: "English", flag: "🇺🇸", dir: "ltr" }

Options

OptionTypeDefaultDescription
defaultLocalestringFallback locale when used outside a provider. Has no effect inside a provider (the provider's locale wins).

Return value

FieldTypeDescription
localeReadonly<Ref<string>>Current locale code, reactive.
localesReadonly<Ref<XafLocaleOption[]>>Available locale options, reactive.
setLocale(code: string) => voidSwitch the locale. Silently ignores unknown codes.
resolvedComputedRef<XafLocaleOption>The full option for the current locale (label, flag, dir, hreflangUrl).
t<T>(map, fallback?) => TTiny translator — returns the value for the current locale, falling back to fallback, then defaultLocale, then the first defined key.
isReadyReadonly<Ref<boolean>>true once the cookie has been read on the client. Inside a provider, always true.

The t() translator

useXafLocale ships a tiny translator for the strings the layer renders itself (button labels in the locale switcher, "no results" copy, etc.). For real i18n with translation files, pluralization, and ICU message format, use vue-i18n on top.

const { t } = useXafLocale({ defaultLocale: "en" })

// Match by current locale:
t({ en: "Welcome", es: "Bienvenido" })
// → "Welcome"

// Fallback to the explicit second arg:
t({ de: "Willkommen" }, "Welcome")
// → "Welcome"

// Fallback to defaultLocale:
t({ en: "Buy", de: "Kaufen" })  // locale is "fr", defaultLocale "en"
// → "Buy"

// Fallback to first defined key:
t({ ja: "こんにちは" })  // locale "fr", defaultLocale "en"
// → "こんにちは"

// Works with non-string values:
t({
  en: { title: "Hi" },
  fr: { title: "Salut" },
})

Provider mode vs. singleton mode

Inside <XAFLocaleProvider> (provider mode)

useXafLocale() reads shared state from the provider via inject. Every component in the tree sees the same locale, and setLocale() triggers a single state update that re-renders all consumers + dispatches the window event.

Outside any provider (singleton mode)

useXafLocale() returns a local singleton scoped to the call site. Useful for:

  • Unit tests (you don't want to wrap every test in a provider)
  • Standalone components (e.g. a footer that just renders the current locale code without depending on the app tree)

In singleton mode, setLocale() updates the local ref but does not persist, dispatch the window event, or update <html lang>. Wrap your app in <XAFLocaleProvider> for the full feature set.

Listening to locale changes globally

window.addEventListener('xaf:locale:changed', (e) => {
  const { code } = (e as CustomEvent<{ code: string }>).detail
  // Refetch data, re-format prices, swap URL prefix, etc.
})

This event is only dispatched by <XAFLocaleProvider>, not by singleton-mode setLocale(). If you need to broadcast from a singleton, dispatch the event yourself.

Tips

  • For real i18n work (translations, pluralization), use vue-i18n on top. t() here is intentionally minimal.
  • When changing the locale, also update your route prefix (e.g. /en/about/es/about). The locale provider doesn't manage routes — pair with @nuxtjs/i18n if you need that.
  • Inside the provider, the <html lang> and <html dir> attributes are kept in sync automatically — useful for screen readers and CSS :lang() selectors.

AI Context

composable: useXafLocale
package: "@xenterprises/nuxt-x-affiliate"
use-when: Reactive locale state — read current locale, switch programmatically, render tiny strings via t()
Copyright © 2026