i18next / react-i18next

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

Override current language with useTranslation #896

Closed Ericnr closed 5 years ago

Ericnr commented 5 years ago

I'm not sure if there's currently a way to do this but it would be interesting if there was a way to override the language set as a useTranslate option.

For an example, const [ translateToEnglish ] = useTranslate("reports", { lng: 'en'}).

It would load the reports namespace in english, and that t function would always translate to english, rather than the browser's language (in the case you are using a language detector).

jamuhl commented 5 years ago

you can i18n.getFixedT('en', 'reports') but that will not load or assert namespace was loaded.

Adding const [ translateToEnglish ] = useTranslate("reports", { lng: 'en'}) is possible just not sure I like the idea of adding complexity.

Ericnr commented 5 years ago

I think the complexity could be worth it.

In my case I have multi language accounting app (similar to quickbooks) and I'd want to let the person to use it in a different language even if they are signed up in the US. But that would mean that certain things like an invoice, and maybe some reports would still have to be in english.

I know there are ways around to do this right now, but I think what I proposed would be the cleanest, and I nice addition to the library over all.

...also, kudos to you, this is an amazing library.

Ericnr commented 5 years ago

There isn't a way to load a specific namespace from a language is there? That + getFixedT would also solve this problem I think.

jamuhl commented 5 years ago

No but https://www.i18next.com/overview/api#loadlanguages will load all already loaded namespaces in current language in the given language.

Also if you like to fallback eg. to en for invoices fallbackLng should be sufficient for this. You can even define a fallbackLng per language if needed to selective fallback: https://www.i18next.com/principles/fallback#fallback-language

bitttttten commented 4 years ago

I wanted to piggy back on this since I have a use case that I don't think I can solve with the above links. We have a language switcher, were we always want to display the users language rather than the site's language so we'd like to force a language with useTranslation to display the user's language.

For example, on the Asos website you can visit the German website for ASOS, and if you visit whilst being in The Netherlands you get presented with a message in Dutch:

Screenshot 2020-06-02 at 15 04 24

Right now I am just importing the raw language file and bypassing this library but it would be great to have it supported.

jamuhl commented 4 years ago

The problem lies in the way i18next load namespaces...there is no way to load languages/namespaces https://www.i18next.com/overview/api#loadnamespaces

also, the checks for has loaded https://github.com/i18next/react-i18next/blob/master/src/utils.js#L43 are based on current language...

so having something like useTranslate("reports", { lng: 'en'}) will be rather hairy to implement

stukennedy commented 3 years ago

You can achieve this by cloning the instance of i18next and feeding it to a provider that encapsulates the components you want to treat differently. I had a similar use-case; a site running in one language, and a component that the user can switch the language on independently of the site. This approach worked excellently for me, where i18n is a module that creates the instance of i18next.

import React, { useEffect, useState } from 'react';
import { I18nextProvider } from 'react-i18next';

import i18n from './i18n';
import TranslateMe from './TranslateMe';

const Wrapper = () => {
  const [i18next, seti18next] = useState(i18n.cloneInstance());

  useEffect(() => {
    const instance = i18n.cloneInstance();
    seti18next(instance);
  }, []);

  return (
    <I18nextProvider i18n={i18next}>
      <TranslateMe />
    </I18nextProvider>
  );
};
export default Wrapper;
import React from 'react';
import { useTranslation } from 'react-i18next';

const TranslateMe = () => {
  const { t, i18n } = useTranslation();

  const onChangeValue = (event) => {
    i18n.changeLanguage(event.target.value);
  }

  return (
    <>
      <h1>{t('my-translation-key')}</h1>
      <div onChange={onChangeValue}>
        <input type="radio" value="en-GB" name="languageType" /> English
        <input type="radio" value="fr-FR" name="languageType" /> French
        <input type="radio" value="nl-NL" name="languageType" /> Dutch
      </div>
    </>
  );
};
export default TranslateMe;
0x1eef commented 1 year ago

I came across this issue by chance, and I am a little disappointed to see it was closed.

const [t] = useTranslation("ns", {lng: 'pt'}) is a nice uniform interface that's one function call, and can avoid repetition that's otherwise required by providing the lng option to t every time you call it. In my case i18n.getFixedT('en', 'reports') should be fine but I don't see a point in continuing to use react-i18next because useTranslation has no purpose after making that switch. Passing around an initialized instance of i18n will work better, and something I would have to do even if I used i18n.changeLanguage instead.