React - i18next


full locale
aka locale - <LANGUAGE>-<REGION>

configuration

  1. https://i18next.github.io/i18next/pages/doc_init.html
  2. http://www.uxshaper.com/how-we-do-internationalization-in-reactjs/

import i18next instance

  1. https://react.i18next.com/latest/using-with-hooks#configure-i-18-next

it’s necessary to import initialized i18next instance in top-level component because the former needs to be bundled (even though it’s not used directly):

// app/App.js

import './i18n';

add translations

  1. https://www.i18next.com/how-to/add-or-load-translations

add on init

  1. https://www.i18next.com/how-to/add-or-load-translations#add-on-init
  2. https://www.codeandweb.com/babeledit/tutorials/how-to-translate-your-react-app-with-react-i18next

the simplest way to add translations is via resources configuration option on init - all top-level keys (after language keys) become namespaces then.

// app/i18n/index.js

import en from './locales/en';
import ru from './locales/ru';

i18n.use(initReactI18next).init({
  resources: {en, ru},
  // ...
});

export default i18n;
// app/i18n/locales/en.js

// prettier-ignore
export default {
  welcome_page: { // namespace
    foo: 'bar', // key
  },
};

[NOT TESTED] load using a backend plugin

  1. https://www.i18next.com/how-to/add-or-load-translations#load-using-a-backend-plugin
  2. https://react.i18next.com/legacy-v9/step-by-step-guide#b-loading-multiple-translation-files

https://react.i18next.com/guides/multiple-translation-files

One of the advantages of react-i18next is based on i18next it supports the separation of translations into multiple files - which are called namespaces in i18next context

when using custom backend, i18next inspects ns configuration option to decide which files to load (file name == namespace).

ns configuration option has default value translation so translation.json file is looked up by default.

AFAIU if translations are added on init (via resources configuration option), specifying ns configuration option has no effect.

notes

using locale in lng option and language in resources option

https://www.i18next.com/principles/fallback#locals-resolving

Per default locals containing region or script will take a translation from the pure language file if not found.

it’s possible to specify a full locale in lng configuration option and use resources with language-only top-level keys (resources configuration option) - i18next will detect the language from locale automatically:

// app/i18n/index.js

i18n.use(initReactI18next).init({
  resources: {
    en: {foo: 'foo'},
    ru: {foo: 'фу'},
  },
  lng: 'en-US',
  // ...
});

tips

Trans component namespace

even if your component is wrapped into withTranslation HOC, Trans still doesn’t use its namespace by default => specify it explicitly:

insert NBSP

  1. https://stackoverflow.com/questions/25857902/i18next-html-escaped-server-side-generated-emails-needing-nbsp

i18next allows to escape/unescape interpolation values but not HTML entities inlined inside translations, say:

// app/i18n/locales/en.js

export default {
  login_welcome_page: {
    welcome: `Welcome to&nbsp;«MyApp»`,
  },
};

=> use Unicode character instead of HTML entity - directly or via constant:

// app/i18n/locales/en.js

export default {
  login_welcome_page: {
    welcome: 'Welcome to\u00A0«MyApp»',
  },
};

// OR

const NBSP = '\u00A0';

export default {
  login_welcome_page: {
    welcome: `Welcome to${NBSP}«MyApp»`,
  },
};

style guide

semantic keys vs. text

  1. https://react.i18next.com/#what-does-my-code-look-like

prefer semantic keys to text (welcomeMessage vs. Welcome to MyApp).

troubleshooting

Function components cannot be given refs

emulator window:

Warning: Function components cannot be given refs. Attempts to access this ref
will fail. Did you mean to use React.forwardRef()?

Check the render method of `ProfilePage`.
    in withI18nextTranslation(Connect(Form)) (at ProfilePage.js:47)
    ...

solution

  1. https://react.i18next.com/latest/withtranslation-hoc#use-ref-greater-than-v-10-6-0
  // app/components/_new/profile/Form.js

- export default withTranslation('profileForm')(Form);
+ export default withTranslation('profileForm', {withRef: true})(Form);

[flow] all branches are incompatible

ESlint error in MacVim:

[flow] all branches are incompatible: Either property `t` is missing in
`OwnProps` [1]. Or property `t` is missing in `StateProps` [2]. Or property `t`
is missing in `DispatchProps` [3].

solution

  1. https://github.com/facebook/flow/issues/2953#issuecomment-265137464
  // app/components/_new/profile/Form.js

  type OwnProps = {
+   t: (text: string, value?: {}) => string,
    // ...
  };