React-i18next: Translation outside React Component

Created on 24 Jul 2019  路  24Comments  路  Source: i18next/react-i18next

I tried to translate strings exported outside React Components.
But any methods in docs doesn't work, and I guess its normal, because its typically React methods.

I've found similar topic, and there it is solution about importing instance.
But, when I do it I've had an error:

 Invariant Violation: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.

Probably it because of this line in the instance:

    .use(initReactI18next) 

When I delete this line, the error is gone, but the translations are not included.
How can I plug this simple .js file to React translations?

Most helpful comment

Outside of react components just use the i18next instance:

import i18n from `./i18n`

i18n.t(...);

Just be aware of the normal catch you's:

All 24 comments

Outside of react components just use the i18next instance:

import i18n from `./i18n`

i18n.t(...);

Just be aware of the normal catch you's:

Yep, I did and I described an error above.
I just import this instance, and the error appeared.
Dont have to even use it.

This is my istance:

import i18n from "i18next";
import { initReactI18next } from "react-i18next";

const resources = {
    en: {
        translation: {
           ...
}
};

i18n
    .use(initReactI18next) 
    .init({
        resources,
        lng: "en",

        keySeparator: false, 

        interpolation: {
            escapeValue: false 
        }
    });

export default i18n;

I don't know whats going on. I use a provider in index to encapsulate i18n in DOM tree.

Somewhere you're using a hook inside a class component...that's what the warning says...

Correct, I missed single useTranslation in another pure js file. When I removed that now everything is working as well, including translations.

Thank you so much.

I've got the issue, what you mentioned. The language doesn't want to change. Of course I checked docs and link sent by you.

But, nothing works, I try to fire this on a change language event, a then add additional namespace.
Nothing happened.
Should I wrap this t function in something?

I noticed that, when I set defaultNs to correct value, everything is change (class and functional React components) to a proper state, but only the outside React files don't respond.
Have you met with this case?

outside react files...what should trigger there a retranslation? once translated static content it's done...there is nothing like the render tree which gets rerendered and doing a fresh translation ---> use the events for that...https://www.i18next.com/overview/api#onlanguagechanged

I use it, but should I wrap this translations in a function?
I mean... This t translations can detect, that default namespace has been changed, and get the new data?

Code below:

i18n.on('languageChanged', language => {
    i18n.setDefaultNamespace('de')
})

Still nothing.

sorry guess i don't get what you like to do...why you need to change the namespace? makes no sense to me...what is the use case? do you have same keys on different namespaces and different values?

and why set namespace to de

i think you do something very wrong...above in code you have in resources the namespace translation now you like to access "de" namespace...!??!??

for change language just call i18n.changeLanguage(lng)

I try to force this t elements, imported from an instance to change itself.
You wrote that reload the namespace should work, and it doesn't, so I tried to change reloaded default namespaces, still with any effects.
It seems like this t elements dont affect on any changes.
I just want to force them to get new data, when the language is change. Just like of the rest code in React components.

make a codesandbox sample of what you like to do / have error with...i can't understand what you like to do, what is wrong by your text

or at least paste relevant code here

The structure is too complicated to put it on code sandbox, so I try to reproduce that issue.

fileOutsideReact.js :

import i18n from '/../i18n'
i18n.on('languageChanged', language => {
  this code trigger on language change
})
export default {
string1: i18n.t('text1', 'exampleValueForString1'),  <----- GET NEW VALUE ON LANGUAGE CHANGE
string2:  i18n.t('text2', 'exampleValueForString2')  <----- GET NEW VALUE ON LANGUAGE CHANGE
};

This example is simplified. In this case I can overrride this values in the function. But in real project this file exports a tons of values, and redundant would be painfully.
i18n.changeLanguage(lng)
Is inside React component

When I change the language strings 1 and 2, still are in prev language.
They dont change itself. So how I can force to change again, when the user pick new language?

PS: Dont care about namespaces, I just tried anything to force translations to update.

you have to call t function again... exported values will not change magically... i would suggest to redesign it... simply use i18next.t() where you need it...

i18n.t returns a string --- right?

export default { foo: 'bar' } --- exports an object with a string foo --- right?
export default { foo: i18n.t('foo') } --- still exports an object with a string foo --- right?

how does a string magically changes? - it does not --- right?

So this might work?

import { i18n }聽from './i18n';

const myExport = {};

function fill() {
  myExport.foo = i18n.t('foo');
}

// run it initial
fill();

// bind some events and fill values again (doing the magic you expect to happen magically)
i18n.on('languageChanged init',() => {
  fill(); // fills myExport with new value for foo based on current i18n lng
});

// export the const
export default myExport;

Problem is solved. For others if they are looking for solution in similar case.

I loop through object, and override a value, where is i18n translation function.
I thought that, export default would be work dynamically, but it wouldn't.

Thanks for advice.

@Creaa so what @jamuhl proposed works? Did you end implementing that?

@jamuhl Your implementation in not working on my end, but I don't have any errors.

Maybe it's because of loading times. Could you explain the bit about namespaces and how would that help me?

Can you create a sample and/or enable debug: true ?

Oh my god. I'm an idiot. It works perfectly. debug: true helped me realize there was a missing key.

Thanks!

@jamuhl Thanks a lot for the solution.

import i18n from `./i18n`

i18n.t(...);

This is working, but I have a problem with i18next-scanner because it's not getting my key automatically. Do you have an idea of how to configure it?

Thanks!

If you're calling the t function from outside a react component, you should call the t function from i18next instead. Also if the default namespace is different than translation, you can either change the default namespace, or pass the namespace as a prefix to the t function, like this:

import i18next from 'i18next;

const someFunction = () => {
   return i18next.t('namespace: title')
}

I18n.t() function is working only inside in functions. There is a way to use them in variables.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ok2ju picture ok2ju  路  3Comments

Flo-Slv picture Flo-Slv  路  4Comments

aniket-dalvi picture aniket-dalvi  路  4Comments

nicholasmaddren picture nicholasmaddren  路  4Comments

tankpower1 picture tankpower1  路  3Comments