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:
| File | Language | Code |
|---|---|---|
| i18n/en.json | English | en |
| i18n/de.json | Deutsch (German) | de |
| i18n/fr.json | Français (French) | fr |
Keys are organized in nested groups for easy navigation:
{
"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:
{{ $t('nav.dashboard') }}
{{ $t('common.loading') }}
{{ $t('status.active') }}
Using Translations in Script
In <script setup>, use the useI18n() composable to access the t function:
Interpolation
Pass dynamic values to translations using curly braces in the JSON key and an object as the second argument:
{
"dashboard": {
"welcome": "Welcome back, {name}!",
"showing": "Showing {count} of {total} results"
}
}{{ $t('dashboard.welcome', { name: 'Alex' }) }}
{{ $t('dashboard.showing', { count: 10, total: 248 }) }}
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:
// 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:
// 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:
| Prefix | Usage | Example |
|---|---|---|
| app.* | App-level labels (title, tagline) | app.title |
| nav.* | Navigation items | nav.dashboard |
| common.* | Shared action labels | common.save |
| status.* | Status labels for badges | status.pending |
| auth.* | Authentication forms | auth.login |
Locale Switcher
The header includes a dropdown that lets users switch languages at runtime. It calls setLocale() from the i18n composable:
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.