i18n working fine in dev mode but not in production
I am using i18n latest beta version. In dev mode local everything is working as expected, translations in templates and in modules is working great. Once I push to production (vercel) none of the translations are working, only the translation property name is displayed in the templates/components/pages
30 Replies
Hi @rwcrabtree. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
When i18n works in development but not in production (e.g., on Vercel), and you see only the translation keys instead of the translated text, this is often due to a misconfiguration of the i18n module, especially regarding where the i18n options are defined.
From the knowledge sources, a common mistake is placing i18n configuration (such as
locales, defaultLocale, and detectBrowserLanguage) in the wrong file. For Nuxt 3 with @nuxtjs/i18n, these options should be in your nuxt.config.ts file, not in i18n.config.ts. If they're in the wrong place, the module may not load your translations correctly in production, even if it works in development. This has been confirmed as the root cause in a similar issue:
This block of config should be in the nuxt.config.ts file and not in the i18n.config.ts:Nuxt 3 i18n browser detection not working Additionally, ensure that your
nuxt.config.ts includes the correct i18n module configuration, and if you use a separate i18n.config.ts for advanced Vue I18n options, reference it via the vueI18n key:
Localization of numbers and dates is not working in Nuxt3 + VueI18n
Summary of steps to resolve:
1. Move all i18n options (locales, defaultLocale, detectBrowserLanguage, etc.) to nuxt.config.ts under the i18n key.
2. If you have advanced Vue I18n config, reference it with vueI18n: './i18n.config.ts'.
3. Redeploy your project.
If you follow these steps, your translations should work in production as they do in development. If the issue persists, double-check for typos in config keys and ensure your translation files are included in the build output.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@391697235995525121> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai this is what my config looks like: " i18n: {
langDir: 'locales',
defaultLocale: 'en',
strategy: 'no_prefix',
detectBrowserLanguage: false,
compilation: {
strictMessage: false,
escapeHtml: false
},
locales: [
{
code: 'en',
name: 'English',
file: 'en.json'
}
]
},"
@kapa.ai what are the default expectations in terms of where the language files are stored and how they are structured?
Let me check the knowledge base for you again. One moment! :books:
----------------------
The knowledge sources indicate that when using
- File Structure: Each locale is typically represented by a separate file (e.g.,
@nuxtjs/i18n with Nuxt 3, there are some expectations regarding where language files are stored and how they are structured:
- Default Location: If you use the lazy loading option, you should specify a langDir (e.g., "lang" or "locales"), and your language files (such as en.json, fr.json, etc.) should be placed in that directory.- File Structure: Each locale is typically represented by a separate file (e.g.,
en.json, fr.json). In your nuxt.config.ts, you define the locales array, where each locale object can specify a file property that matches the filename in your language directory.
Example from a knowledge source:
In this example, the language files en.json and nl-NL.json should be placed inside the locales directory at the root of your project. The structure inside each file is a standard JSON object with key-value pairs for translations.
If you do not use lazy loading, you can define your translations directly in the config or in a separate config file referenced by the vueI18n key. But for file-based (lazy) loading, the above structure is expected by default Nuxt i18n Calling useRoute within middleware may lead to misleading results.
If you need to customize further, you can refer to the official documentation, but the above is the default and most common expectation.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@391697235995525121> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai this is what my config looks like: " i18n: {
langDir: 'locales',
defaultLocale: 'en',
strategy: 'no_prefix',
detectBrowserLanguage: false,
compilation: {
strictMessage: false,
escapeHtml: false
},
locales: [
{
code: 'en',
name: 'English',
file: 'en.json'
}
]
},"
and my single language file is in i18n/locales/en.json , does this look correct?
Let me check the knowledge base for you again. One moment! :books:
----------------------
Based on the knowledge sources, your configuration is almost correct, but there is a potential mismatch in the directory path:
- You have set
- If your file is at
langDir: 'locales', which means Nuxt i18n expects your language files to be in the locales directory at the root of your project.
- You mentioned your file is in i18n/locales/en.json. If your locales directory is inside an i18n folder, you should set langDir: 'i18n/locales' in your config.
So, either:
- Move your en.json file to the root-level locales directory (i.e., locales/en.json), or
- Update your config to langDir: 'i18n/locales' if you want to keep the current structure.
The structure inside your en.json file should be a standard JSON object with key-value pairs for translations, which matches the default expectations Nuxt i18n Calling useRoute within middleware may lead to misleading results.
Summary:- If your file is at
i18n/locales/en.json, set langDir: 'i18n/locales'.
- If you want to use langDir: 'locales', move the file to locales/en.json.
This will ensure Nuxt i18n can find and load your language file as expected.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@391697235995525121> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai if I put langDir: 'i18n/locales' then I notice nuxt adds the i18n on it's own, so the path becomes i18n/i18n/locales which breaks it in development
Let me check the knowledge base for you again. One moment! :books:
----------------------
I'm sorry, but the knowledge sources do not explicitly mention whether Nuxt automatically prepends the
i18n directory to the langDir path or how it resolves nested paths for langDir. The sources only show examples where langDir is set to a single directory name like "locales" and the language files are placed directly in that directory at the project root Nuxt i18n Calling useRoute within middleware may lead to misleading results.
If you are experiencing that Nuxt adds i18n on its own and the path becomes i18n/i18n/locales, this behavior is not documented in the provided knowledge sources. For the most reliable results, it is recommended (based on the examples) to use a simple directory name for langDir (e.g., 'locales') and place your language files in that directory at the root of your project.
If you need to use a nested directory, you may need to experiment or consult the official documentation or community for clarification, as the knowledge sources do not provide a definitive answer on this behavior.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@391697235995525121> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
yeah I get this @kapa.ai [8:09:46 AM] WARN warning: Failed to resolve "../i18n/i18n/locales/en.json" from virtual:nuxt:%2Fhome%2Frwfresh%2FProjects%2Femoterai%2Fapps%2Fweb%2F.nuxt%2Fi18n.options.mjs. An id should be written. Did you pass a URL?
Plugin: vite:import-analysis
File: virtual:nuxt:%2Fhome%2Frwfresh%2FProjects%2Femoterai%2Fapps%2Fweb%2F.nuxt%2Fi18n.options.mjs:87:26
86 |
87 |
88 | import.meta.hot.accept("../i18n/i18n/locales/en.json", async mod => { | ^ 89 | localeLoaders["en"][0].load = () => Promise.resolve(mod.default) 90 | await useNuxtApp()._nuxtI18nDev.resetI18nProperties("en")
87 |
88 | import.meta.hot.accept("../i18n/i18n/locales/en.json", async mod => { | ^ 89 | localeLoaders["en"][0].load = () => Promise.resolve(mod.default) 90 | await useNuxtApp()._nuxtI18nDev.resetI18nProperties("en")
Let me check the knowledge base for you again. One moment! :books:
----------------------
Based on the knowledge sources, there is no explicit documentation about Nuxt automatically prepending the
- Set
i18n directory to the langDir path or about issues with double directory resolution. However, the sources do show that the expected and most reliable setup is to use a simple directory name for langDir (such as 'locales') and place your language files directly in that directory at the root of your project. For example:
With this configuration, your file should be at locales/en.json in your project root, not in a nested i18n/locales directory Nuxt i18n Calling useRoute within middleware may lead to misleading results.
The warning you are seeing about ../i18n/i18n/locales/en.json suggests that there is a path resolution issue, likely caused by setting langDir: 'i18n/locales' when your project is already in an i18n directory or similar. The knowledge sources do not provide a solution for nested directories, so the safest approach—according to the examples—is to use a flat structure.
Recommendation:- Set
langDir: 'locales' in your config.
- Place your language files in locales/en.json at the root of your project.
This matches the default expectations shown in the knowledge sources and should resolve the path issue you are experiencing. If you need a more complex directory structure, the knowledge sources do not provide enough information to confirm if or how this is supported.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@391697235995525121> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai following those instructions leads me to this error: [8:13:07 AM] WARN warning: Failed to resolve "../i18n/locales/en.json" from virtual:nuxt:%2Fhome%2Frwfresh%2FProjects%2Femoterai%2Fapps%2Fweb%2F.nuxt%2Fi18n.options.mjs. An id should be written. Did you pass a URL?
Plugin: vite:import-analysis
File: virtual:nuxt:%2Fhome%2Frwfresh%2FProjects%2Femoterai%2Fapps%2Fweb%2F.nuxt%2Fi18n.options.mjs:87:26
86 |
87 |
88 | import.meta.hot.accept("../i18n/locales/en.json", async mod => { | ^ 89 | localeLoaders["en"][0].load = () => Promise.resolve(mod.default) 90 | await useNuxtApp()._nuxtI18nDev.resetI18nProperties("en") ✔ Vite server built in 922ms 8:13:08 AM [nitro 8:13:10 AM] ERROR Error: Could not load /home/rwfresh/Projects/emoterai/apps/web/i18n/locales/en.json (imported by virtual:#internal/i18n/options.mjs): ENOENT: no such file or directory, open '/home/rwfresh/Projects/emoterai/apps/web/i18n/locales/en.json'
87 |
88 | import.meta.hot.accept("../i18n/locales/en.json", async mod => { | ^ 89 | localeLoaders["en"][0].load = () => Promise.resolve(mod.default) 90 | await useNuxtApp()._nuxtI18nDev.resetI18nProperties("en") ✔ Vite server built in 922ms 8:13:08 AM [nitro 8:13:10 AM] ERROR Error: Could not load /home/rwfresh/Projects/emoterai/apps/web/i18n/locales/en.json (imported by virtual:#internal/i18n/options.mjs): ENOENT: no such file or directory, open '/home/rwfresh/Projects/emoterai/apps/web/i18n/locales/en.json'
Let me check the knowledge base for you again. One moment! :books:
----------------------
Based on the knowledge sources, the expected setup for
@nuxtjs/i18n is to set langDir to a directory at the root of your project (e.g., langDir: 'locales') and place your language files directly in that directory, such as locales/en.json Nuxt i18n Calling useRoute within middleware may lead to misleading results.
However, your error message shows that Nuxt is looking for the file at /home/rwfresh/Projects/emoterai/apps/web/i18n/locales/en.json, which suggests that either:
- Your project root is /home/rwfresh/Projects/emoterai/apps/web/, and you have set langDir: 'i18n/locales', or
- There is some other configuration or project structure causing Nuxt to resolve the path with an extra i18n/ prefix.
The knowledge sources do not provide explicit details about how Nuxt resolves nested directories for langDir or how to handle monorepo or nested app structures. They only show examples with a flat structure, where langDir is a single directory at the root.
Summary from the knowledge sources:
- The default and supported approach is to use langDir: 'locales' and place your language files in locales/en.json at the root of your Nuxt project.
- If you use a nested path like i18n/locales, you may encounter path resolution issues, and the knowledge sources do not provide guidance on how to resolve this.
If you are still seeing errors after following this structure, the knowledge sources do not contain enough information to provide a definitive solution for your specific project layout or for advanced monorepo setups. You may need to consult the official documentation or Nuxt community for further troubleshooting if your project structure is non-standard.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@391697235995525121> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai my language file is in project root/locales/en.json. My nuxt config for i18n is "i18n: {
langDir: 'locales',
defaultLocale: 'en',
strategy: 'no_prefix',
detectBrowserLanguage: false,
compilation: {
strictMessage: false,
escapeHtml: false
},
locales: [
{
code: 'en',
name: 'English',
file: 'en.json'
}
]
}," and when I run I get this error [8:13:07 AM] WARN warning: Failed to resolve "../i18n/locales/en.json" from virtual:nuxt:%2Fhome%2Frwfresh%2FProjects%2Femoterai%2Fapps%2Fweb%2F.nuxt%2Fi18n.options.mjs. An id should be written. Did you pass a URL?
Plugin: vite:import-analysis
File: virtual:nuxt:%2Fhome%2Frwfresh%2FProjects%2Femoterai%2Fapps%2Fweb%2F.nuxt%2Fi18n.options.mjs:87:26
86 |
87 |
88 | import.meta.hot.accept("../i18n/locales/en.json", async mod => { | ^ 89 | localeLoaders["en"][0].load = () => Promise.resolve(mod.default) 90 | await useNuxtApp()._nuxtI18nDev.resetI18nProperties("en") ✔ Vite server built in 922ms 8:13:08 AM [nitro 8:13:10 AM] ERROR Error: Could not load /home/rwfresh/Projects/emoterai/apps/web/i18n/locales/en.json (imported by virtual:#internal/i18n/options.mjs): ENOENT: no such file or directory, open '/home/rwfresh/Projects/emoterai/apps/web/i18n/locales/en.json' So NUXT or i18n module is prepending i18n to the path. I don't know WHY or where
87 |
88 | import.meta.hot.accept("../i18n/locales/en.json", async mod => { | ^ 89 | localeLoaders["en"][0].load = () => Promise.resolve(mod.default) 90 | await useNuxtApp()._nuxtI18nDev.resetI18nProperties("en") ✔ Vite server built in 922ms 8:13:08 AM [nitro 8:13:10 AM] ERROR Error: Could not load /home/rwfresh/Projects/emoterai/apps/web/i18n/locales/en.json (imported by virtual:#internal/i18n/options.mjs): ENOENT: no such file or directory, open '/home/rwfresh/Projects/emoterai/apps/web/i18n/locales/en.json' So NUXT or i18n module is prepending i18n to the path. I don't know WHY or where
Let me check the knowledge base for you again. One moment! :books:
----------------------
Based on the knowledge sources, the expected and default setup for
- Your config and file placement are correct according to the knowledge sources. - The knowledge sources do not explain why
@nuxtjs/i18n is to set langDir to a directory at the root of your project (e.g., langDir: 'locales') and place your language files directly in that directory, such as locales/en.json. Your configuration matches this expectation Nuxt i18n Calling useRoute within middleware may lead to misleading results.
However, your error message shows that Nuxt is looking for the file at /home/rwfresh/Projects/emoterai/apps/web/i18n/locales/en.json, even though your config is langDir: 'locales' and your file is at locales/en.json. This suggests that something in your project structure or configuration is causing Nuxt or the i18n module to prepend i18n/ to the path.
The knowledge sources do not provide explicit information about why this would happen or how Nuxt resolves the langDir path in more complex project structures (such as monorepos or nested directories). All examples in the sources assume a flat project structure with langDir pointing to a root-level directory.
In summary:- Your config and file placement are correct according to the knowledge sources. - The knowledge sources do not explain why
i18n/ is being prepended to your path.
- There is not enough information in the knowledge sources to provide a definitive answer or solution for this specific path resolution issue.
If you continue to experience this problem, you may need to consult the official Nuxt i18n documentation or community for further troubleshooting, especially if your project uses a non-standard structure.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@391697235995525121> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai when I try and build locally I get this error: ERROR Nuxt Build Error: [vite:load-fallback] Could not load /home/rwfresh/Projects/emoterai/apps/web/i18n/locales/en.json (imported by virtual:nuxt:%2Fhome%2Frwfresh%2FProjects%2Femoterai%2Fapps%2Fweb%2F.nuxt%2Fi18n.options.mjs): ENOENT: no such file or directory, open '/home/rwfresh/Projects/emoterai/apps/web/i18n/locales/en.json' -> so where is this i18n.options.mjs file?
Let me check the knowledge base for you again. One moment! :books:
----------------------
The file
-
i18n.options.mjs referenced in your error message is an internal, auto-generated file created by Nuxt during the build process. It is located inside the .nuxt directory of your project (e.g., /home/rwfresh/Projects/emoterai/apps/web/.nuxt/i18n.options.mjs). This file is not meant to be edited directly; it is generated based on your Nuxt and i18n configuration.
The knowledge sources confirm that Nuxt generates internal files like this in the .nuxt directory as part of its build system, but they do not provide further details about the contents or structure of i18n.options.mjs specifically. The error you are seeing indicates that Nuxt (or Vite) is trying to import your language file from a path that does not exist, which is likely due to a misconfiguration or unexpected path resolution, but the sources do not provide more detail on this internal file or the exact cause of the path issue.
In summary:-
i18n.options.mjs is an internal file generated by Nuxt in the .nuxt directory.
- The knowledge sources do not provide more details about this file or how to debug its contents.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@391697235995525121> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai this file seems like the culprit with regards to the pah to the locales file being incorrect
Let me check the knowledge base for you again. One moment! :books:
----------------------
You are correct in suspecting that the generated
.nuxt/i18n.options.mjs file is responsible for resolving the path to your locales file. The error message you are seeing indicates that this file is attempting to import your language file from an unexpected path (/i18n/locales/en.json), which does not exist in your project structure.
However, the knowledge sources do not provide explicit details about the internal workings of .nuxt/i18n.options.mjs or how it constructs the import paths for locale files. They only confirm that this file is auto-generated by Nuxt during the build process and is not meant to be edited directly. The sources also do not explain why an incorrect path (with an extra i18n/ prefix) would be generated in your specific case.
In summary, while it is clear that .nuxt/i18n.options.mjs is involved in resolving the path to your locales file, the knowledge sources do not contain enough information to explain why the path is incorrect or how to fix it within that file. The issue likely stems from a configuration or project structure mismatch, but further details are not available in the provided sources.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@391697235995525121> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai is there some way I can be more explicit with the langDir option in nuxt.config?
Let me check the knowledge base for you again. One moment! :books:
----------------------
The knowledge sources do not provide explicit details about advanced usage or making the
There is no information in the knowledge sources about making the
langDir option more explicit in nuxt.config.ts. All examples in the sources use a simple directory name (like 'locales' or 'lang') at the project root and do not show usage of absolute paths or more complex path resolution for langDir Nuxt i18n Calling useRoute within middleware may lead to misleading results.
If you are experiencing issues with path resolution, the knowledge sources do not mention a supported way to make langDir more explicit (such as using absolute paths or special path helpers). The default and documented approach is to use a flat directory at the root of your project and reference it by name.
In summary:There is no information in the knowledge sources about making the
langDir option more explicit beyond specifying a directory name at the project root. If you need more advanced configuration, the knowledge sources do not provide guidance on this.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@391697235995525121> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Ok solution for anyone having this issue is to simply prepend your landDir value with ../ so in my case langDir: "../locales" . This is likely due to my project being in a monorepo although I'm not 100% sure.