Search code examples
i18nextreact-i18next

withTranslation HOC looks for translation in first namespace only


I'm upgrading my project from i18next^11.0.0 to i18next^15.0.0 and react-i18next^7.0.0 to react-i18next^10.0.0. I was using translate HOC previously but seems that it's replaced by withTranslation now. So my simple React component after these changes looks like:

import React from 'react';
import { withTranslation } from 'react-i18next';

const AboutControl = props => {
  const { t } = props;

  return (
    <div className="about-control">
      <p className="about-control-application-name">
        {t('name')} {VERSION}
      </p>

      <p>
        {t('supported-browsers')}:
      </p>

      <ul>
        <li>Google Chrome >= 55</li>
        <li>Mozilla Firefox >= 53</li>
      </ul>
    </div>
  );
};

export default withTranslation(['about', 'application'])(AboutControl);

Translation for supported-browsers key is defined in about namespace while translation for name key is in application namespace. However new version of the library doesn't translate name key in the example above:

If I change an order of about and application in withTranslation call

export default withTranslation(['application', 'about'])(AboutControl);

everything becomes vice versa (supported-browsers is not translated):

In older version of react-i18next nsMode option was available that solved the issue but it doesn't work anymore:

await i18next.init({
  whitelist: this.languages,
  lng: this.language || this.languages[0],
  fallbackLng: this.languages[0],
  lowerCaseLng: true,
  debug: false,
  resources: {},
  interpolation: {
    escapeValue: false // not needed for React
  },
  react: {
    wait: true,
    nsMode: true
  }
});

I didn't find anything related to this in documentation. Here is an example from there:

// load multiple namespaces
// the t function will be set to first namespace as default
withTranslation(['ns1', 'ns2', 'ns3'])(MyComponent);

Looks like that no any additional options are required otherwise I wonder what namespaces should be passed for if not to translate texts of a component. Is it a bug? Or does any workaround exist?

Migration guide from 9 to 10 doesn't highlight any changes on this behavior.


Solution

  • react-i18next didn't have nsMode since version 10.0.0. But this pull request adds it back (published in 10.7.0).

    One could translate texts (even without passing namespaces to withTranslation or useTranslation) just by prefixing keys by namespace (ns:key):

    import React from 'react';
    import { withTranslation } from 'react-i18next';
    
    const AboutControl = props => {
      const { t } = props;
    
      return (
        <div className="about-control">
          <p className="about-control-application-name">
            {t('application:name')} {VERSION}
          </p>
    
          <p>
            {t('about:supported-browsers')}:
          </p>
    
          <ul>
            <li>Google Chrome >= 55</li>
            <li>Mozilla Firefox >= 53</li>
          </ul>
        </div>
      );
    };
    
    export default withTranslation()(AboutControl);
    

    Passing namespaces to withTranslation is required when you load translation resources asynchronously to ensure that they are available before rendering.