i18next / react-i18next

Internationalization for react done right. Using the i18next i18n ecosystem.
https://react.i18next.com
MIT License
9.22k stars 1.02k forks source link

False warning about accessing t function before calling init #977

Closed Robloche closed 4 years ago

Robloche commented 4 years ago

Describe the bug I'm having a warning that I think is a false positive. I get the thousands of the following warning: i18next.js:27 i18next::translator: key "xxx" for namespace "translation" won't get resolved as namespace was not yet loaded This means something IS WRONG in your application setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!

I think it's a false positive for 3 reasons:

  1. I do call init() before calling ReactDOM.render().
  2. I was working until I updated to v10.12.4 (or maybe 10.12.5, not sure...).
  3. All my localized strings are correctly displayed in my app.

Before all the warnings, the console prints this:

i18next: languageChanged fr-FR
i18next: initialized {debug: true, initImmediate: true, ns: Array(1), defaultNS: "translation", fallbackLng: Array(1), …}

Occurs in following versions npm 6.12.0 react-i18next 10.13.2

OS (please complete the following information):

jamuhl commented 4 years ago

1.) you call init before calling render -> does not mean init was done before you called render!!! (init is async)

https://github.com/i18next/i18next/blob/master/src/Translator.js#L345 calls https://github.com/i18next/i18next/blob/master/src/i18next.js#L296 ...your namespace not yet loaded

It's the same logic that tests for ready in react-i18next -> did you set useSuspense: false ?!?

Robloche commented 4 years ago

In fact, I tried to call render after the promise is fullfilled and got the same result...

I don't know useSuspense. I'll check it out...

jamuhl commented 4 years ago

If useSuspense is false and you got somewhere a withTranslation or useTranslation loading a namespace - you also run into this

jamuhl commented 4 years ago

Can you paste your i18next.init options and the component accessing the xxx key throwing that warning

jamuhl commented 4 years ago

wondering...tests are passing for that feature...might be I miss something: https://github.com/i18next/i18next/blob/master/test/i18next.hasLoadedNamespace.spec.js

Robloche commented 4 years ago

I'm in the middle of something else but plan to get back to this as soon as possible. I'll let you know what I find...

jamuhl commented 4 years ago

Might be I found some edgecase...might be the next update today will solve this false positive...

Will ping you again with new versions to test...

jamuhl commented 4 years ago

Can you retry with:

react-i18next@11.0.0 i18next@18.0.0

Robloche commented 4 years ago

I tried with:

react-i18next@11.0.0 i18next@18.0.0

and got the same warnings.

But I still haven't looked at useSuspense.

jamuhl commented 4 years ago

a codesandbox for reproduction might help...

Robloche commented 4 years ago

useSuspense set to true or false doesn't change the outcome.

jamuhl commented 4 years ago

Will need a sample to reproduce...as I don't get this on the example...

Robloche commented 4 years ago

The warning is displayed by i18next.js, in resolve(): image

With usedNS='translation'

Then, I delved a little bit and I think, the issue is that lang is fr-FR at this point although i18n was initialized with fr.

Robloche commented 4 years ago

In resolve, there's this: codes.forEach(function (code) {

With codes=['fr-FR', 'fr'].

So, this fails with fr-FR, hence the warning. And it succeeds with fr, hence my correctly localized strings.

Is it a bug on your side or am I using it the wrong way?

jamuhl commented 4 years ago

No, it's the behaviour you get based on: https://www.i18next.com/principles/fallback#language-fallback

If language is set to fr-FR it will try to fallback to fr in cases unable to resolve in fr-FR. If not possible it will finally fallback to the defined fallback language.

But still can't reproduce...

the check checks if loading is not pending: https://github.com/i18next/i18next/blob/master/src/i18next.js#L340

having no success loading fr-FR it still sets loading state to -1: https://github.com/i18next/i18next/blob/master/src/BackendConnector.js#L94

Robloche commented 4 years ago

I upgraded this morning to i18next@18.0.1 and it's fixed. The warnings are gone.

Thanks!

jamuhl commented 4 years ago

If you like this module don’t forget to star this repo. Make a tweet, share the word or have a look at our https://locize.com to support the devs of this project.

If you liked my support / work - I would enjoy a coffee sponsored using the “💜Sponsor Button”.

There are many ways to help this project :pray:

zmnv commented 4 years ago

i18next 19.0.1 react-i18next 11.2.5

same false warnings.

jamuhl commented 4 years ago

@zmnv are you sure they are false warnings...?

If so please provide a codesandbox for reproduction 🙏

zmnv commented 4 years ago

@jamuhl

Web CRA

  1. Initialization in index.js https://gitlab.com/zmnv/localization-example/blob/master/src/index.js

  2. i18next initialization https://gitlab.com/zmnv/localization-example/blob/master/src/i18n/index.js

  3. i18next configuration https://gitlab.com/zmnv/localization-example/blob/master/src/i18n/i18nextOptions.js

  4. Add Resources example https://gitlab.com/zmnv/localization-example/blob/master/src/Calibration/locales/index.js

  5. Using inside component https://gitlab.com/zmnv/localization-example/blob/master/src/Calibration/index.js


React Native

https://gist.github.com/zmnv/53729aace40af35e429e10691ee9e218

Actually I need to use i18next with React Native. I tried some different configurations of i18next and react-i18next.

All time I get warnings, BUT I see translated strings in render(); It works but gives me warnings.

Open App: image

Open Screen with HOC withTranslation('calibration')(Screen) image

also used with useSuspense: false the same result.

What am I doing wrong?


PS: I try to copy your examples from https://github.com/i18next/react-i18next/blob/master/example/react-native/App.js. Please update packages. Also I see that warnings...

jamuhl commented 4 years ago

@zmnv there is a) no language set and b) useSuspense: false -> doing check the ready flag you get: https://react.i18next.com/latest/usetranslation-hook#not-using-suspense and as long that is false - do not access t

the react-native sample is very basic working on passed in resources on init...

zmnv commented 4 years ago

@jamuhl ooohhhhh, I thought fallbackLng was enough. I just used i18next without language detector.

When I added languageDetector like in: https://github.com/i18next/react-i18next/blob/master/example/react-native/App.js#L15

it's worked without false warnings.

thank you!

andresilveirah commented 4 years ago

@jamuhl not sure if this is documented somewhere, I ran into the same scenario. Using i18next without a language detector and without setting the lng option thinking the fallbackLng would be enough. Thank you @zmnv for posting your answer, I've set the lng option attribute instead of using a languageDetector and it all worked.

jamuhl commented 4 years ago

@andresilveirah honestly I'm not sure where to add this in the docs - for people running into this...thought it's rather logical you got to set lng if not using a detector (fallbackLng is only fallback to current lng detected or set - as it says)

andresilveirah commented 4 years ago

@jamuhl you might be right, maybe it should be straight forward but maybe not 🤷‍♂ I guess it'll be up to you to keep track if this question come up over and over again and update the doc to be over explicative, or just ignore if it's only two people :)

tonix-tuft commented 4 years ago

I have a use case where this false warning might still be present, my i18next initialization is:

i18n
.use(initReactI18next)
.use(i18nextXHRBackend)
.use(intervalPlural)
.init(
    {
        lng,
        fallbackLng: [defaultLng],
        debug: isDebug,
        ns: ["common"],
        defaultNS: "common",
        saveMissing: true,
        saveMissingTo: "current",
        backend: {
            loadPath:
                loadPathBaseUrl + "/i18n/res/{{lng}}/{{ns}}.json",
            crossDomain: true
        },
    },
    () => {
        // init callback, I can't put the code in `i18n.on("languageChanged", ...)` here because
        // when this init callback is executed it's too late and the React components have already rendered...
        // I need to execute some code which depends on the "i18n.t" function before rendering the first time and each time the language changes...
    }
);

// Can't put this code in the "init" callback,
// as the "init" callback seems to be executed only after the React components render,
// but in my case I need to do some setup before rendering the suspended components, 
// therefore I put all my code in this event handler...
i18n.on("languageChanged", lng => {
    ref.lng = lng;

    // I need to execute some initialization functions which depend on the i18next "i18n" object 
    // each time the language changes and THE VERY FIRST time
    // when the first language is loaded  from the backend BUT BEFORE rendering the suspended components.
    // The namespace is loaded at this point,
    // and both "thousandSeparator" and "decimalSeparator" are translated correctly,
    // but i18next complains about them not being loaded (though, they are)
    // and outputs the warning in the console:
    // 
    //     i18next::translator: key "format.thousandSeparator" for namespace "common"
    //     for languages "en" won't get resolved as namespace was not yet loaded...
    // 
    const thousandSeparator = i18n.t('format.thousandSeparator')
    const decimalSeparator = i18n.t('format.decimalSeparator')

    Both `thousandSeparator, decimalSeparator` 
    initNumberFormatting(thousandSeparator, decimalSeparator)
});

I have put my code using the t function within the "languageChanged" event callback, but I still see the warning, even though the translations are loaded and i18n is ready at that point and i18n.t('format.thousandSeparator') and i18n.t('format.decimalSeparator') work correctly and return me the translated text.

tonix-tuft commented 4 years ago

Right now, I can patch my code using:

... skipping i18n.init() code ...
...

i18n.on("languageChanged", lng => {
    // Manually setting `isInitialized` to true makes the warning disappear.
    i18n.isInitialized = true; // <----------
    ...
    initNumberFormatting(thousandSeparator, decimalSeparator)
});

This way the warning disappears, but I really think that this case is treated as a false positive by i18next, what do you think?

Thanks!

jamuhl commented 4 years ago

@tonix-tuft if that works - it just avoids the warning - not fixing the problem

do you use either Suspense or handle the ready state given by the withTranslation or useTranslation?

jamuhl commented 4 years ago

@andresilveirah just to come back to your isssue - a warning was added for the case no detector was used and no lng set...

andresilveirah commented 4 years ago

That's really cool @jamuhl , appreciate the effort.

tonix-tuft commented 4 years ago

@jamuhl I am using Suspense, yeah, that's a workaround, but I don't see the warning this way... Otherwise is there a way to execute some code using the ready i18next instance (as soon as the namespaces for the given language are fully loaded) that will run before the suspended React components will render for the very first time? init's callback is executed after and does not cover this use case...

Thank you very much!

jamuhl commented 4 years ago

@tonix-tuft do you use the backend as is - or add translations partial manually? Must be something special - normally I would expect the i18next.init call to return before the withTranslation/useTranslation get there state set to ready by loading needed namespaces and check for those translations available...

There is currently only a few ways I could think of this happening:

Would you be able to produce a codesandbox reproducing this behaviour in your app? That would help a lot...🙏

tonix-tuft commented 4 years ago

I am using the XHR backend plugin to load all the translations through AJAX.

Yes, I load several namespaces initially:

ns: ["common", "chat", "user", "input", "stats", "order"]

Because otherwise if I e.g. remove "user" and "input" from ns: [...] and then at some point during rendering one of my React components uses t("user: ...") or t("common: ..."), i18next won't load the missing namespaces... And also, if I change the language with i18n.changeLanguage(...), i18next won't load user and input namespaces and the keys using those namespaces with the t function with will not be translated (e.g. t("user:some key") will return "some key" instead of the translated string, because i18next didn't load the user namespace)...

But that's another story.

If you look at your fiddle here you should see the warning in the console (I attach a screenshot): https://jsfiddle.net/jamuhl/ferfywyf/

Screen Shot 2020-01-29 at 16 04 20

HTML code:

<script src="https://unpkg.com/i18next/i18next.js"></script>
<script src="https://unpkg.com/i18next-xhr-backend/i18nextXHRBackend.js"></script>
<script src="https://unpkg.com/i18next-browser-languagedetector/i18nextBrowserLanguageDetector.js"></script>
<div style="height: 150px">
  <button onclick="i18next.changeLanguage('en')">
  english
  </button>
  <button onclick="i18next.changeLanguage('de')">
  german
  </button>
  <hr />
  <div id="title"></div>
  <button id="saveBtn"></button>
  <hr />
  <div id="info"></div>
</div>

JS code:

// import i18next from 'i18next';

i18next
  .use(i18nextXHRBackend)
  .use(i18nextBrowserLanguageDetector)
  .init({
    fallbackLng: 'en',
    debug: true,
    ns: ['special', 'common'],
    defaultNS: 'special',
    backend: {
      // load from i18next-gitbook repo
      loadPath: 'https://raw.githubusercontent.com/i18next/i18next-gitbook/master/locales/{{lng}}/{{ns}}.json',
      crossDomain: true
    }
  }, function(err, t) {
    // init set content
    updateContent();
  });

// just set some content and react to language changes
// could be optimized using vue-i18next, jquery-i18next, react-i18next, ...
function updateContent() {
  document.getElementById('title').innerHTML = i18next.t('title', { what: 'i18next' });
  document.getElementById('saveBtn').innerHTML = i18next.t('common:button.save', { count: Math.floor(Math.random()*2+1)  });

  document.getElementById('info').innerHTML = `detected user language: "${i18next.language}"  --> loaded languages: "${i18next.languages.join(', ')}"`;
}

function changeLng(lng) {
  i18next.changeLanguage(lng);
}

i18next.on('languageChanged', () => {
  //i18next.isInitialized = true; // If you uncomment this line, the warning disappears...
  updateContent();
});

Try to uncomment //i18next.isInitialized = true; within i18next.on('languageChanged', () => { and you will see that the warning disappears.

jamuhl commented 4 years ago

When using multiple namespaces in one file like t("common: ...") you have to add that in withTranslation/useTranslation: https://react.i18next.com/latest/usetranslation-hook#loading-namespaces and all will work

The jsfiddle is old - and suffers an issue...renders initially twice - once on the init callback and once on the languageChanged event coming before init is done:

https://jsfiddle.net/jamuhl/ferfywyf/523/

i18next.on('languageChanged', () => {
  if (i18next.isInitialized) updateContent();
});

would correct that sample - might add a check for isInitialized to the react check - but not 100% that was once there and removed out of a reason...

jamuhl commented 4 years ago

Guess had todo with https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md#1012

Nope nothing todo with it...

jamuhl commented 4 years ago

https://github.com/i18next/react-i18next/blob/master/src/useTranslation.js#L42 why does it render and not throw the Suspense on your code? Are you sure you did not set useSuspense: false ?

tonix-tuft commented 4 years ago

Yes I am sure, useSuspense is not even set in my code, so it defaults to true I guess.

tonix-tuft commented 4 years ago

Anyway, shouldn't i18next.isInitialized be true when languageChanged's callback is executed for the very first time? When the callback is executed, I see the translations are loaded and i18n.t("any key") works, so it follows that i18next is initialized from the client code's point of view... What do you think?

jamuhl commented 4 years ago

languageChanged is an event - not a callback

and there you access t to early:

i18n.on("languageChanged", lng => {
    ref.lng = lng;

    // I need to execute some initialization functions which depend on the i18next "i18n" object 
    // each time the language changes and THE VERY FIRST time
    // when the first language is loaded  from the backend BUT BEFORE rendering the suspended components.
    // The namespace is loaded at this point,
    // and both "thousandSeparator" and "decimalSeparator" are translated correctly,
    // but i18next complains about them not being loaded (though, they are)
    // and outputs the warning in the console:
    // 
    //     i18next::translator: key "format.thousandSeparator" for namespace "common"
    //     for languages "en" won't get resolved as namespace was not yet loaded...
    // 
    const thousandSeparator = i18n.t('format.thousandSeparator')
    const decimalSeparator = i18n.t('format.decimalSeparator')

    Both `thousandSeparator, decimalSeparator` 
    initNumberFormatting(thousandSeparator, decimalSeparator)
});

change that to:

i18n.on("languageChanged initialized",() => {
    if (!i18n.isInitialized) return;
    ref.lng = i18n.language;

    // I need to execute some initialization functions which depend on the i18next "i18n" object 
    // each time the language changes and THE VERY FIRST time
    // when the first language is loaded  from the backend BUT BEFORE rendering the suspended components.
    // The namespace is loaded at this point,
    // and both "thousandSeparator" and "decimalSeparator" are translated correctly,
    // but i18next complains about them not being loaded (though, they are)
    // and outputs the warning in the console:
    // 
    //     i18next::translator: key "format.thousandSeparator" for namespace "common"
    //     for languages "en" won't get resolved as namespace was not yet loaded...
    // 
    const thousandSeparator = i18n.t('format.thousandSeparator')
    const decimalSeparator = i18n.t('format.decimalSeparator')

    Both `thousandSeparator, decimalSeparator` 
    initNumberFormatting(thousandSeparator, decimalSeparator)
});
tonix-tuft commented 4 years ago

I know that languageChanged is an event XD.

languageChanged's callback = The callback of languageChanged.

I cannot use if (!i18n.isInitialized) return; because that formatting will not be initialized when the page loads and I end up with unformatted content, only if I change the language with i18n.changeLanguage("another-LNG") then i18next executes the callback of languageChanged and this time formatting is set properly.

I need to set up formatting by executing this code:

    const thousandSeparator = i18n.t('format.thousandSeparator')
    const decimalSeparator = i18n.t('format.decimalSeparator')

    initNumberFormatting(thousandSeparator, decimalSeparator)

Before any component using the useTranslation() hook is rendered. The callback passed to i18n.init as a second parameter does not work because at the time it's executed, the React components using useTranslation()have already been rendered and if I set the formatting in the init callback, the formatting will be available only if change the language, but I need the formatting as soon as translations are loaded from the backend when the page loads.

The only way I found to do it seems to use the following code:

i18n.init(...); // Init i18next.

// Registrer "languageChanged" event handler/callback
i18n.on("languageChanged", lng => {
    //if (!i18n.isInitialized) return; // Can't use this line because otherwise formatting won't be set on initial rendering when the namespaces for the initial language are loaded.
    ref.lng = lng;

    //i18n.isInitialized = true; // With this line commented out, i18next outputs the warning, but `i18n.t('format.thousandSeparator')` returns the correct string for the user's language...
    const thousandSeparator = i18n.t('format.thousandSeparator')
    const decimalSeparator = i18n.t('format.decimalSeparator')

    initNumberFormatting(thousandSeparator, decimalSeparator)
});

I hope I was clear. Thank you again!

jamuhl commented 4 years ago

i18n.on("languageChanged initialized",() => { initialized event is bound too this way!!! But might be too late - not tested -> but as rendering is delayed until isInitialized the settings should be done

So guess - you can keep your "hacky" way to avoid the warning (knowing what you do - so it does not hurt). Not sure how to avoid this edge case - as there is no way to delay the languageChanged event to be called after init is done...

tonix-tuft commented 4 years ago

I cannot share you the source code, but I can attach a screenshot to make you understand better the issue I am facing.

This is the application I am building:

Screen Shot 2020-01-30 at 12 59 18

The React components that render the percentage values require i18n formatting and the formatting itself depends on the initialized i18next instance (because I need to call e.g. i18n.t("format.decimalSeparator") when I set up formatting).

On page load, i18next is initialized this way:

i18n
    .use(initReactI18next)
    .use(i18nextXHRBackend)
    .use(intervalPlural)
    .init({
           lng, // A global variable, generated server-side.
           fallbackLng: [defaultLng], // Same as "lng".
           ns: ["ns1", "ns2", "ns3", ... , "nsN"],
           defaultNS: "ns1",
           backend: ... // XHR backend configuration
    },
    () => {
         // init callback.
    }
);

i18n.on("languageChanged", lng => {
    // If I remove this patch, i18next displays the not initialized warning,
    // though I suppose that i18next is initialized at this point when it executes this code.
    //* Patch
    const isInitialized = i18n.isInitialized;
    i18n.isInitialized = true;
    //*/

    // Init i18n formatting. This code will run when the page loads and i18next
    // has loaded the translations for the initial language ("lng") downloading
    // the files from the backend, as well as when I programmatically call `i18n.changeLanguage("new-LNG")`.
    const thousandSeparator = i18n.t('format.thousandSeparator');
    const decimalSeparator = i18n.t('format.decimalSeparator');

    initNumberFormatting(thousandSeparator, decimalSeparator);

    // Resetting `i18n.isInitalized` to its previous value.
    //* Patch
    i18n.isInitialized = isInitialized;
    //*/
});

The above code works, and once the page loads and i18next has loaded the translations, the languageChanged's callback is executed and my formatting is initialized and only after the formatting initialization then the suspended React components render and the percentage values are formatted as they should:

Screen Shot 2020-01-30 at 13 27 01

Now, if I move this code:

    // Init i18n formatting.
    const thousandSeparator = i18n.t('format.thousandSeparator');
    const decimalSeparator = i18n.t('format.decimalSeparator');

    initNumberFormatting(thousandSeparator, decimalSeparator);

from the languageChanged event callback and put it within the init callback of i18next:

i18n
    .use(initReactI18next)
    .use(i18nextXHRBackend)
    .use(intervalPlural)
    .init({
           lng, // A global variable, generated server-side.
           fallbackLng: [defaultLng], // Same as "lng".
           ns: ["ns1", "ns2", "ns3", ... , "nsN"],
           defaultNS: "ns1",
           backend: ... // XHR backend configuration
    },
    () => {
         // i18next init callback.
         const thousandSeparator = i18n.t('format.thousandSeparator');
         const decimalSeparator = i18n.t('format.decimalSeparator');

         initNumberFormatting(thousandSeparator, decimalSeparator);
    }
);

i18n.on("languageChanged", lng => {
    // Execute only when the language changes through `i18n.changeLanguage()` while using the app,
    // and NOT when the page loads (when `i18n.isInitialized === false`).
    if (!i18n.isInitialized) return;

    // Init i18n formatting. This code will run ONLY when I programmatically call 
    // `i18n.changeLanguage("new-LNG")`, and not when the page loads for the first time
    // and i18next has loaded the translations.
    const thousandSeparator = i18n.t('format.thousandSeparator');
    const decimalSeparator = i18n.t('format.decimalSeparator');

    initNumberFormatting(thousandSeparator, decimalSeparator);
});

With the above code, when the page loads, the formatting is not initialized on time, it's rather initialized too late when the suspended React components have already been rendered, so you can see formatting is missing (in my case, if initNumberFormatting(thousandSeparator, decimalSeparator) isn't called before the components render, percentage values will not have the decimal part):

Screen Shot 2020-01-30 at 13 38 09

So the only way to achieve what I want is to use the first option and place all my initialization within the "languageChanged" event callback and setting i18n.isInitialized = false there to suppress the misleading warning (again, I assume that when the "languageChanged" callback is executed, it means that i18next is ready to be used and therefore is initialized).

I hope I was esplicative and clear. Let me know.

Thank you very much!

jamuhl commented 4 years ago

The implementation is suboptimal...taking separators from translations is not the best option...chicken egg problem

1) not all languages separate thousand 2) formatting should be done by Intl or a major lib doing this correctly 3) use: https://www.i18next.com/translation-function/formatting

Also bind the https://www.i18next.com/overview/api#oninitialized beside language change -> https://github.com/i18next/react-i18next/blob/master/src/useTranslation.js#L42 might work

There is no need to explain over and over the https://github.com/i18next/react-i18next/issues/977#issuecomment-579922061 still is valid

tonix-tuft commented 4 years ago

Thank you @jamuhl, I got it. I was using accounting-js to format numbers: http://openexchangerates.github.io/accounting.js/

This library needs to know the thousand and decimal separator in advance:

accounting.settings = {
    currency: {
        symbol : "$",   // default currency symbol is '$'
        format: "%s%v", // controls output: %s = symbol, %v = value/number (can be object: see below)
        decimal : ".",  // decimal point separator
        thousand: ",",  // thousands separator
        precision : 2   // decimal places
    },
    number: {
        precision : 0,  // default precision on numbers is 0
        thousand: ",",
        decimal : "."
    }
}

I took a look at the https://www.i18next.com/translation-function/formatting link you provided and there's a lib called numeral.js which seems to be pretty interesting.

But even that library needs to know the separators to use in advance (http://numeraljs.com/#locales):

// load a locale
numeral.register('locale', 'fr', {
    delimiters: {
        thousands: ' ',
        decimal: ','
    },
    abbreviations: {
        thousand: 'k',
        million: 'm',
        billion: 'b',
        trillion: 't'
    },
    ordinal : function (number) {
        return number === 1 ? 'er' : 'ème';
    },
    currency: {
        symbol: '€'
    }
});

// switch between locales
numeral.locale('fr');

What do you advise in order to format numbers and currency in an i18n format to support all languages?

Thank you!

jamuhl commented 4 years ago

https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat

tonix-tuft commented 4 years ago

Thank you Jan! No more questions :)

jamuhl commented 4 years ago

@tonix-tuft hope I was able to help...

tonix-tuft commented 4 years ago

Today I modified the code again and here is what I ended up with:

i18n.on("initialized", () => {
    initFormatting();
});

i18n.on("languageChanged", lng => {
    if (!i18n.isInitialized) return;

   initFormatting();
});

function initFormatting() {
    // Init i18n formatting. This code will run ONLY when I programmatically call 
    // `i18n.changeLanguage("new-LNG")`, and not when the page loads for the first time
    // and i18next has loaded the translations.
    const thousandSeparator = i18n.t('format.thousandSeparator');
    const decimalSeparator = i18n.t('format.decimalSeparator');

    initNumberFormatting(thousandSeparator, decimalSeparator);
}

This way everything works, thanks again!

jamuhl commented 4 years ago

If you like this module don’t forget to star this repo. Make a tweet, share the word or have a look at our https://locize.com to support the devs of this project.

If you liked my support / work - I would enjoy a coffee sponsored using the “:purple_heart:Sponsor Button”.

There are many ways to help this project :pray:

mk6-dev commented 4 years ago

I'm having the same issue like render is getting loaded before i18n. and here is the init code for i18n,

.init( { fallbackLng: "en", debug: true, interpolation: { escapeValue: false // not needed for react as it escapes by default }, react: { useSuspense: false } }, () => { // init callback. }

I'm not really sure what to add in the callback funciton to supress the warnings, please help me out in resolving this issue

image