N
Nuxt3mo ago
konsav

Switching from vue-i18n to @nuxtjs/i18n — Folder Structure & Dynamic Imports Issue

Hey everyone! I was using vue-i18n ("vue-i18n": "^9.2.2") with this setup and now I tried switching to @nuxtjs/i18n (version 9.1.1). Previous setup with vue-i18n: plugins/i18n.js
import { createI18n } from "vue-i18n";
import { defineNuxtPlugin } from "#app";

export default defineNuxtPlugin(({ vueApp }) => {
const i18n = createI18n({
legacy: false,
globalInjection: true,
locale: "el",
fallbackLocale: "el",
});

vueApp.use(i18n);
});
import { createI18n } from "vue-i18n";
import { defineNuxtPlugin } from "#app";

export default defineNuxtPlugin(({ vueApp }) => {
const i18n = createI18n({
legacy: false,
globalInjection: true,
locale: "el",
fallbackLocale: "el",
});

vueApp.use(i18n);
});
The problem: I have a lot of language files organized by page and component:
lang\GR\Common\Footer.json
lang\EN\Common\Footer.json
lang\GR\HomePage\test.json
lang\EN\HomePage\test.json
lang\GR\Common\Footer.json
lang\EN\Common\Footer.json
lang\GR\HomePage\test.json
lang\EN\HomePage\test.json
On each page, I import the JSON files with require() based on the current locale. Now, with @nuxtjs/i18n, I’m struggling to find the best way to keep this folder structure and dynamically load the translations. Do you have any idea about that? Thank you
8 Replies
kapa.ai
kapa.ai3mo ago
Hi @konsav. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To answer your question about switching from vue-i18n to @nuxtjs/i18n while maintaining your folder structure and dynamic imports, I'll provide some guidance based on the available information in the knowledge sources. The @nuxtjs/i18n module for Nuxt 3 offers a different approach to handling translations compared to vue-i18n. Here's how you can adapt your setup: 1. First, make sure you have properly installed and configured @nuxtjs/i18n in your Nuxt 3 project. Add it to your nuxt.config.ts file:
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
vueI18n: './i18n.config.ts'
}
})
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
vueI18n: './i18n.config.ts'
}
})
2. Create an i18n.config.ts file in your project root to configure vue-i18n:
export default defineI18nConfig(() => ({
legacy: false,
locale: 'el',
fallbackLocale: 'el',
messages: {}
}))
export default defineI18nConfig(() => ({
legacy: false,
locale: 'el',
fallbackLocale: 'el',
messages: {}
}))
3. To maintain your folder structure and dynamically load translations, you can use the lazy option and specify a custom loader. Here's an example of how you might configure this in your nuxt.config.ts:
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
lazy: true,
langDir: 'lang',
defaultLocale: 'el',
locales: [
{ code: 'el', file: 'el.ts' },
{ code: 'en', file: 'en.ts' }
],
vueI18n: './i18n.config.ts'
}
})
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
lazy: true,
langDir: 'lang',
defaultLocale: 'el',
locales: [
{ code: 'el', file: 'el.ts' },
{ code: 'en', file: 'en.ts' }
],
vueI18n: './i18n.config.ts'
}
})
4. In your language files (e.g., lang/el.ts and lang/en.ts), you can dynamically import the JSON files:
export default async () => {
const messages = {}

// Common translations
messages['Common'] = {
Footer: await import('./GR/Common/Footer.json')
}

// HomePage translations
messages['HomePage'] = {
test: await import('./GR/HomePage/test.json')
}

return messages
}
export default async () => {
const messages = {}

// Common translations
messages['Common'] = {
Footer: await import('./GR/Common/Footer.json')
}

// HomePage translations
messages['HomePage'] = {
test: await import('./GR/HomePage/test.json')
}

return messages
}
This approach allows you to maintain your folder structure while dynamically loading translations. However, it's important to note that this setup might not be as performant as loading all translations upfront, especially for larger applications. You may want to consider the trade-offs between maintaining your current structure and optimizing for performance. For more detailed information and advanced configuration options, I recommend checking out the official @nuxtjs/i18n documentation: Nuxt i18n Documentation If you need further assistance or have more specific questions about implementing this setup, please let me know. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@900420997872767070> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Omnislash
Omnislash3mo ago
I did it that way, got the inspiration on stackoverflow nuxt.config
import i18nConfig from './i18n.config'

export default defineNuxtConfig({
// blablabla
i18n: i18nConfig,
// blablabla
)}
import i18nConfig from './i18n.config'

export default defineNuxtConfig({
// blablabla
i18n: i18nConfig,
// blablabla
)}
i18n.config
import { languagesAvailable } from './utils/languages'

const translations = ['footer', 'home', 'article'] as const

const locales = languagesAvailable.map(lang => ({
code: lang,
files: translations.map(tra => `${lang}/${tra}.json`, )
}))

export default {
// experimental: {
// localeDetector: 'localDetector.ts'
// },
legacy: false,
locales,
langDir: 'translations',
fallbackLocale: 'fr' satisfies LanguageCode,
strategy: 'prefix',
datetimeFormats: {
en: {
short: {
year: 'numeric',
month: 'short',
day: 'numeric',
}
},
fr: {
short: {
year: 'numeric',
month: 'short',
day: '2-digit',
}
}
},
} as const
import { languagesAvailable } from './utils/languages'

const translations = ['footer', 'home', 'article'] as const

const locales = languagesAvailable.map(lang => ({
code: lang,
files: translations.map(tra => `${lang}/${tra}.json`, )
}))

export default {
// experimental: {
// localeDetector: 'localDetector.ts'
// },
legacy: false,
locales,
langDir: 'translations',
fallbackLocale: 'fr' satisfies LanguageCode,
strategy: 'prefix',
datetimeFormats: {
en: {
short: {
year: 'numeric',
month: 'short',
day: 'numeric',
}
},
fr: {
short: {
year: 'numeric',
month: 'short',
day: '2-digit',
}
}
},
} as const
I have a languageAvailables file in /utils because I use it here and there
export const languagesAvailable = ['fr', 'en'] as const
export type LanguageCode = typeof languagesAvailable[number]
export const languagesAvailable = ['fr', 'en'] as const
export type LanguageCode = typeof languagesAvailable[number]
For some reason datetimeFormats doesn't work, but the rest is peachy
konsav
konsavOP3mo ago
@kapa.ai just to clarify, my setup isn’t as simple as having two files per language — I actually have multiple translation files for each page of the app, organized in a folder structure like this:
/lang

├── /GR
│ ├── /Common
│ │ └── Footer.json
│ ├── /HomePage
│ └── text.json
├── /EN
├── /Common
│ └── Footer.json
├── /HomePage
└── test.json
/lang

├── /GR
│ ├── /Common
│ │ └── Footer.json
│ ├── /HomePage
│ └── text.json
├── /EN
├── /Common
│ └── Footer.json
├── /HomePage
└── test.json
So instead of just el.ts and en.ts, I need to dynamically load all these files while keeping the folder structure intact.
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- I understand your need for a more complex folder structure with multiple translation files per language. Thank you for clarifying. Based on your specific setup, I can provide a more tailored solution using @nuxtjs/i18n while maintaining your folder structure. To achieve this, you can use a combination of dynamic imports and a custom loader. Here's how you can modify your setup: 1. First, ensure your nuxt.config.ts is configured correctly:
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
lazy: true,
langDir: 'lang',
defaultLocale: 'GR',
locales: [
{ code: 'GR', file: 'gr.ts' },
{ code: 'EN', file: 'en.ts' }
],
vueI18n: './i18n.config.ts'
}
})
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
lazy: true,
langDir: 'lang',
defaultLocale: 'GR',
locales: [
{ code: 'GR', file: 'gr.ts' },
{ code: 'EN', file: 'en.ts' }
],
vueI18n: './i18n.config.ts'
}
})
2. Create language loader files (gr.ts and en.ts) in your lang directory. These files will dynamically import all the JSON files for each language:
// lang/gr.ts
export default async () => {
const messages = {}

// Use webpack's require.context to get all JSON files
const files = import.meta.glob('./GR/**/*.json', { eager: true })

for (const path in files) {
const key = path.replace('./GR/', '').replace('.json', '')
const [section, file] = key.split('/')
if (!messages[section]) messages[section] = {}
messages[section][file] = files[path].default
}

return messages
}

// lang/en.ts (similar structure, but replace 'GR' with 'EN')
// lang/gr.ts
export default async () => {
const messages = {}

// Use webpack's require.context to get all JSON files
const files = import.meta.glob('./GR/**/*.json', { eager: true })

for (const path in files) {
const key = path.replace('./GR/', '').replace('.json', '')
const [section, file] = key.split('/')
if (!messages[section]) messages[section] = {}
messages[section][file] = files[path].default
}

return messages
}

// lang/en.ts (similar structure, but replace 'GR' with 'EN')
This approach uses Vite's import.meta.glob (or webpack's require.context if you're using webpack) to dynamically import all JSON files within the language directory. 3. In your i18n.config.ts, you can keep the basic configuration:
export default defineI18nConfig(() => ({
legacy: false,
locale: 'GR',
fallbackLocale: 'GR'
}))
export default defineI18nConfig(() => ({
legacy: false,
locale: 'GR',
fallbackLocale: 'GR'
}))
With this setup, @nuxtjs/i18n will lazy-load your translation files while maintaining your folder structure. You can then use the translations in your components like this:
<template>
<div>
{{ $t('Common.Footer.someKey') }}
{{ $t('HomePage.test.anotherKey') }}
</div>
</template>
<template>
<div>
{{ $t('Common.Footer.someKey') }}
{{ $t('HomePage.test.anotherKey') }}
</div>
</template>
This solution allows you to: 1. Keep your current folder structure intact 2. Dynamically load all translation files for each language 3. Use lazy-loading to improve initial load times However, please note that this approach might have performance implications for larger applications with many translation files. You may want to consider grouping some translations together if load times become an issue. For more advanced usage and configuration options, you can refer to the @nuxtjs/i18n documentation. If you need any further clarification or have more questions about implementing this setup, please don't hesitate to ask. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@900420997872767070> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
konsav
konsavOP3mo ago
@Omnislash Thank you for your response. Could you send me the post from stackoverflow?

Did you find this page helpful?