The i18n feature in Nuxt 3 retrieves language locales from an external API

While working on my Nuxt 3 app, I encountered an issue when trying to integrate i18n. Despite conducting extensive research, I couldn't find any helpful information, hence I have a question. I am utilizing i18n with Prismic CMS. The locales array is sourced from the Prismic API, fetched using my composable useLocales. Within this composable, I also store the data in global state using useState and return it. Upon successful retrieval, my goal is to populate the i18n instance with this data. However, I quickly realized that achieving this was not as straightforward as I had initially thought - none of my attempts have been successful so far.

Here are some approaches I have tried:

  1. I attempted to fetch data directly within the defineNuxtConfig function and set the payload as the value for the locales key - it became apparent that this method would not work, as asynchronous operations cannot be performed there.
// Inside defineNuxtConfig
i18n: {
    ...
    locales: await useLocales(),
    defaultLocale: "en-pl",
    ...
},
  1. I then tried fetching data in a custom plugin and setting the payload as the value for the locales key of the $i18n property. This appeared to update the locales, but did not affect the routing system:
export default defineNuxtPlugin(async ({ $i18n }) => {
    const locales = await useLocales();
    $i18n.locales = locales;
});
  1. Another attempt involved fetching data in a custom plugin in a similar manner, but instead of updating the existing i18n instance, I created a new one:
export default defineNuxtPlugin(async ({ vueApp }) => {
    const locales = await useLocales();
    const i18nInstance = createI18n({
        legacy: false,
        globalInjection: true,
        locale: "en-pl",
        locales: locales,
    });
    vueApp.use(i18nInstance);
});

In the documentation and community forums, most examples involve hardcoding locales data - I have struggled to find a solution that fits my specific use case online, which is surprising given its commonality.

If anyone has insight into how to correctly set these locales, I would greatly appreciate it.

Answer №1

When it comes to retrieving locales messages from an asynchronous method, you can follow this recommended approach suggested by the website:

Firstly, ensure to set 'lazy' to true:

i18n: {
  locales: [
    {
      code: 'en',
      file: 'en-US.js'
    },
    {
      code: 'es',
      file: 'es-ES.js'
    },
    {
      code: 'fr',
      file: 'fr-FR.js'
    }
  ],
  lazy: true,
  langDir: 'lang/',
  defaultLocale: 'en'
}

Then, resolve the fetched locales from the asynchronous method:

export default async (context, locale) => {
  return await Promise.resolve({
    welcome: 'Welcome'
  })
}

// or

export default {
  welcome: 'Welcome'
}

Refer to the documentation for more details: link

Answer №2

I'm unsure if it's too late to provide a response.

Suppose you already have API endpoints: 'api/locales=en-US' and 'api/locales=zh-TW'.

To begin, create a global function:

export const fetchAndApplyTranslations = async (lang: any, i18nSetLocaleMessage: any) => {
    try {
        const translations = await $fetch(`/api/locales?lang=${lang}`);
        if (translations) {
            i18nSetLocaleMessage(lang, translations);
            console.log(`Translations loaded for ${lang}`);
        }
    } catch (error) {
        console.error(`Failed to fetch translations for ${lang}:`, error);
    }
}

The 'lang' should be of string type, and 'i18nSetLocaleMessage' will be a function from 'i18n' itself. This function is used to set the newly fetched translations to your existing original translations (overwriting).

Next, create a plugin and execute this code:

import {fetchAndApplyTranslations} from "~/utils/tools";

export default defineNuxtPlugin(async nuxtApp => {
    const {$i18n} = useNuxtApp();
    await fetchAndApplyTranslations($i18n.locale.value, $i18n.setLocaleMessage);
});

This will run the fetchAndApplyTranslations function when a user FIRST visits the website. Essentially, all the original translations (JSON) will be overwritten by the APIs (database) upon a user's initial visit to the page.

Upon accessing the page, users will see the modified translations as plugins will asynchronously run with the page generation.

Additionally, for language switching, add this function again. When a user clicks to change the language, execute this function to overwrite the selected translation:

const {locales, locale, setLocale, setLocaleMessage} = useI18n()
const languageDropDownItems = ref([locales.value.map((getLocale: any) => ({
    label: getLocale.name,
    click: async () => {
        setLocale(getLocale.code);
        await fetchAndApplyTranslations(getLocale.code, setLocaleMessage);
    }
}))]);

In the nuxt.config.ts file, keep everything else the same. Changing the file to a js file to return JSON from APIs may not work.

    i18n: {
        lazy: true,
        langDir: 'locales',
        strategy: 'prefix_except_default',
        locales: [
            { code: 'en-US', iso: 'en-US', file: 'en-US.json', name: 'English' },
            { code: 'zh-TW', iso: 'zh-TW', file: 'zh-TW.json', name: '繁體中文' },
        ],
        defaultLocale: 'en-US',
        // detectBrowserLanguage: false,  // Remove it as true.
        vueI18n: './i18n.options.ts',
    },

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Updating a child component in React while applying a filter to the parent component

Although I've come across this question before, I'm struggling to comprehend it within my specific scenario. I'm currently using a search bar to filter the data, which is functioning properly. However, the image is not updating. The URL bei ...

When implementing Passport-jwt for fetching user data, req.user may sometimes be undefined

No matter how many answers I search for on Stackoverflow or read through the documentation, I still can't solve my problem. Signing in and signing up works perfectly fine - I have my token. But when I try to fetch my current_user using get('/isAu ...

Fullcalendar Bootstrap popover mysteriously disappears

I'm having issues with my Bootstrap popovers being hidden under the rows in FullCalendar. I've tried using container: 'body' and trigger: 'focus', but they don't seem to work. The function that's causing this proble ...

Customizing translations for various domains in Vue-i18n

Our app has a global reach and our company is undergoing a rebranding process in certain markets. For instance, we are currently known as "Acme Company" in the U.S. and Canada, but now we aim to be recognized as "Acme Company" in the U.S. and "Foo Company ...

Troubleshooting: Potential Reasons Why Registering Slash Commands with Options is Not Functioning Properly in Discord.js

While working on a Discord bot, I encountered an issue while trying to register a slash command with options for the ban command. The error message I received was: throw new DiscordAPIError(data, res.status, request); ^ DiscordAPIError: ...

Is it possible to change all text to lowercase except for URLs using .tolowercase()?

Currently, I am facing a challenge with my Greasemonkey script. The use of .tolowercase() is causing all uppercase letters to be converted to lowercase, which is disrupting URLs. I have explored alternatives like .startswith() and .endswith(), considering ...

Encountering issues with gulp-angular-templatecache while processing angular templates through pipelining

I've encountered an issue with gulp-angular-templatecache in my gulpfile. Here's the task causing trouble: gulp.task('templates', function() { return gulp.src(paths.angularTemplates) .pipe(templateCache()) ...

Is it possible to modify CSS properties using Ajax?

I am attempting to dynamically change the background color of a div using AJAX to fetch the user's specified color from the database. Below is the code snippet I am using: $.ajax({type: "POST", data: {id: id}, url: "actions/css.php", success: functio ...

Is it possible to determine the time format preference of the user's device in Angular? For example, whether they use a 24-hour system or a 12-hour system with AM

In Angular, is there a way to determine whether the user's time format is set to 24-hour or 12-hour system? Any help would be greatly appreciated. Thanks! ...

Rotating through elements in timed intervals

After exploring various examples of how to show/hide divs with a JavaScript timeout, I am still unable to resolve my specific issue. I currently have six divs that I want to cycle through sequentially every 10 seconds, starting with div #one. Although my ...

Saving compiled babel files to the corresponding directory level

Is there a way to output compiled babel files in the same directory as the source files? Currently, my script generates the compiled files in a separate folder while maintaining the folder structure. This is achieved through the following code snippet in m ...

Mastering the art of using either promises or callbacks properly

Attempting to retrieve the result of a variable after completing all asynchronous processes in a function. I've discovered that I need to use promises for this, so I spent today learning about them. I've implemented promises in my function and c ...

Shifting annotations on a Bar Graph featuring Negative Values on Google's Chart Maker

Incorporating google charts into my MVC project. Looking to create a bar chart that accommodates negative values. Desire annotations on the same side as the end of the bar for negative values (similar to positive values shown in the green box below). ht ...

How can we best organize a VueJS application to accommodate this specific logic?

I am currently working on an app that needs to display data fetched from multiple sources based on a condition. The issue I am facing is that the process of fetching, organizing, and returning the data varies depending on the source, sometimes even requiri ...

Steps for identifying if the line before in a textarea is blank

Is there a way to identify the structure of individual lines within a textarea? As an example, consider the following contents in my textarea: this is the first line in textarea 1234 this is the second line starting with 1234 this is the fourth line and ...

The box shadow feature does not function properly when the position is set to sticky

Applying position sticky to th and td in the example below seems to be causing issues with the box shadow not working. Can anyone provide insights on why this is happening? <div class="overflow-x-auto lg:overflow-visible"> <div> <t ...

What is the process for automatically disabling a checkbox based on the condition that the value in another field is 0?

Before we proceed, feel free to check out the jsFiddle example provided: https://jsfiddle.net/1wL1t21s/ In my scenario, there are multiple checkboxes for selecting toppings with a quantity adjustment feature using the plus (+) and minus (-) buttons. Curre ...

Problem Encountered with Modifying Active Link Color in Next.js Following Introduction of Multiple Root Layouts

Currently, I am in the process of developing an application with Next.js and incorporating multiple root layouts from the official documentation at https://nextjs.org/docs/app/building-your-application/routing/creating-multiple-root-layouts. This was neces ...

What could be causing the alteration of my JSON data when sent through a WEB.API Ajax request?

Before Ajax Call: "{ "UnitOfMeasureRelatedUnitDataInbound": [ { "Name": "test", "Active": true, "UnitOfMeasureTypeID": "dd89f0a0-59c3-49a1-a2ae-7e763da32065", "BaseUnitID": "4c835ebb-60f2-435f-a5f4-8dc311fbbca0", "BaseUnitName": null, ...

The object continues to be undefined despite its placement in a global scope

Currently, I am working on building a game of pong and encountering an issue with creating a paddle in the initialize method. Despite storing it as a global variable, the paddle remains undefined. I even tried making it a property of 'window', bu ...