i18n

Alixan UI uses the official Nuxt i18n module. The project keeps message keys typed, while locale switching and persistence are handled by the module.

For more detailed information, visit the Nuxt i18n documentation.

Installation

Install the Nuxt i18n module, then register it in nuxt.config.ts.

npx nuxt module add i18n

Configuration

Use strategy: 'prefix_except_default' to keep the default language without a prefix and prefix all other locales.

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxtjs/i18n'],
  i18n: {
    vueI18n: './configs/i18n.config.ts',
    defaultLocale: 'en',
    strategy: 'prefix_except_default',
    detectBrowserLanguage: false,
    locales: [
      { code: 'en', name: 'English', file: 'en.json' },
      { code: 'ru', name: 'Русский', file: 'ru.json' },
      { code: 'kk', name: 'Қазақша', file: 'kk.json' },
    ],
  },
})

Point vueI18n to the external config file and disable i18n warnings in i18n/configs/i18n.config.ts.

i18n/configs/i18n.config.ts
export default {
  // Disable warnings because some UI props intentionally pass plain strings through $t.
  missingWarn: false,
  fallbackWarn: false,
}

Translations

Keep locale JSON files in i18n/locales. The file option maps each locale to its translation file.

i18n/locales/en.json
{
  "app": {
    "settings": "Open settings"
  },
  "settings": {
    "language": "Language"
  },
  "component": {
    "button": "Button"
  }
}
i18n/locales/ru.json
{
  "app": {
    "settings": "Открыть настройки"
  },
  "settings": {
    "language": "Язык"
  },
  "component": {
    "button": "Кнопка"
  }
}
i18n/locales/kk.json
{
  "app": {
    "settings": "Баптауларды ашу"
  },
  "settings": {
    "language": "Тіл"
  },
  "component": {
    "button": "Батырма"
  }
}

Usage

Language

<script setup lang="ts">
type Locale = 'en' | 'ru' | 'kk'

const { locale, setLocale } = useI18n()

const languageOptions: Array<{ label: string; value: Locale }> = [
  { label: 'English', value: 'en' },
  { label: 'Русский', value: 'ru' },
  { label: 'Қазақша', value: 'kk' },
]

const changeLocale = async (value: Locale): Promise<void> => {
  useHead({
    htmlAttrs: { lang: value },
  })
  await setLocale(value)
}
</script>

<template>
  <div class="space-y-2">
    <p class="px-1 text-sm font-medium text-muted-foreground">
      {{ $t('settings.language') }}
    </p>
    <Select
      :model-value="locale"
      :options="languageOptions"
      @change="changeLocale($event.value as Locale)"
    />
  </div>
</template>

Page Meta

Pass page-level SEO translation keys to usePageMeta . The composable resolves them with useI18n().t internally.

pages/button.vue
<script setup lang="ts">
usePageMeta({
  title: 'seo.metaTitle',
  description: 'seo.metaDescription',
})
</script>