Internationalization

Multi-language support with @nuxtjs/i18n — add new locales, use translations, and switch languages at runtime.

How i18n Works

Haze Dashboard uses the @nuxtjs/i18n module with the no_prefix strategy. This means URLs do not change based on the locale — there is no /en/ or /de/ prefix. The language is determined by the user's selection and stored in a cookie.

The module is registered in nuxt.config.ts and locale files live in the top-level i18n/ directory.

Locale Files

Three locales ship by default. Each JSON file contains approximately 100 translation keys organized by feature area:

FileLanguageCode
i18n/en.jsonEnglishen
i18n/de.jsonDeutsch (German)de
i18n/fr.jsonFrançais (French)fr

Keys are organized in nested groups for easy navigation:

json
{
  "app": {
    "title": "Haze Dashboard",
    "tagline": "Modern admin dashboard"
  },
  "nav": {
    "dashboard": "Dashboard",
    "analytics": "Analytics",
    "orders": "Orders"
  },
  "common": {
    "save": "Save",
    "cancel": "Cancel",
    "delete": "Delete",
    "search": "Search...",
    "loading": "Loading..."
  },
  "status": {
    "active": "Active",
    "pending": "Pending",
    "completed": "Completed"
  },
  "auth": {
    "login": "Sign in",
    "register": "Create account",
    "forgot_password": "Forgot password?"
  }
}

Using Translations in Templates

Use the $t() function directly in templates to output translated text:

vue

Using Translations in Script

In <script setup>, use the useI18n() composable to access the t function:

vue

Interpolation

Pass dynamic values to translations using curly braces in the JSON key and an object as the second argument:

json
{
  "dashboard": {
    "welcome": "Welcome back, {name}!",
    "showing": "Showing {count} of {total} results"
  }
}
vue

Adding a New Locale

To add Spanish support, follow these two steps:

1. Create the locale file — Copy i18n/en.json to i18n/es.json and translate all values:

json
// i18n/es.json
{
  "app": {
    "title": "Haze Dashboard",
    "tagline": "Panel de administracion moderno"
  },
  "nav": {
    "dashboard": "Panel",
    "analytics": "Analiticas",
    "orders": "Pedidos"
  },
  "common": {
    "save": "Guardar",
    "cancel": "Cancelar",
    "delete": "Eliminar"
  }
}

2. Register it in nuxt.config.ts — Add the new locale to the locales array:

typescript
// nuxt.config.ts
export default defineNuxtConfig({
  i18n: {
    locales: [
      { code: 'en', name: 'English', file: 'en.json' },
      { code: 'de', name: 'Deutsch', file: 'de.json' },
      { code: 'fr', name: 'Francais', file: 'fr.json' },
      { code: 'es', name: 'Espanol', file: 'es.json' },  // Add this
    ],
    defaultLocale: 'en',
    langDir: '../i18n',
    strategy: 'no_prefix',
  },
})

The locale switcher in the header will automatically include the new language. No other configuration is needed.

Adding New Translation Keys

When adding new pages or features, add translation keys to all locale files. Follow the existing naming convention:

PrefixUsageExample
app.*App-level labels (title, tagline)app.title
nav.*Navigation itemsnav.dashboard
common.*Shared action labelscommon.save
status.*Status labels for badgesstatus.pending
auth.*Authentication formsauth.login

Locale Switcher

The header includes a dropdown that lets users switch languages at runtime. It calls setLocale() from the i18n composable:

vue


The selected locale is persisted to a cookie by @nuxtjs/i18n, so it survives page refreshes and navigation.

Tip

Keys are organized by feature area: app.*, nav.*, common.*, status.*, auth.*. This makes it easy to find and update translations when adding new features.

Next Steps

Explore the Components reference to see all available shared UI primitives.