'How can I use a React context variable when initiating i18next interpolation?

The React app I'm working on is using react-18next. Inside the index.js file, there is a i18n.js file imported into it that configures and initiates i18n.

This includes interpolation configuration where we have some various formats for strings and numbers.

i18n.js

import i18n from 'i18next';

i18n.init({
  interpolation: {
    escapeValue: false,
    format: (value, format) => {

      if(format === 'currency') {
        return return new Intl.NumberFormat('en-Us', {
          maximumFractionDigits: decimals,
          style: 'currency',
          currency: 'USD',
        }).format(value);
      } 
    }
  }
});

I have a React context variable currency that I'd like to use in this interpolation function to replace "USD." How can I do that?

In order to access the context variable, I need to use the useContext() hook, which is unavailable inside this i18n.js file, as it needs to be called inside a React component.

The context variable changes, based on someone using a <select> input, so I would think the interpolation function would need to be re-instantiated each time the variable changes.

I tried moving i18n.init() into a custom hook and calling that hook from my App.js component.

useI18n.js

import React, { useContext, useEffect } from 'react';
import i18n from 'i18next';

import { ContextCurrency } from 'context';

const useI18n = () => {
  const { currency } = useContext(ContextCurrency);

  // init i18n when currency changes
  useEffect(() => {
    i18n.init(...);
  }, [currency]);

  return i18n;
}

export default useI18n;

This resulted in an error:

Warning: React has detected a change in the order of Hooks called by App. Uncaught TypeError: Cannot read properties of undefined (reading 'length')

The error is a check being made in React's areHookInputsEqual function. I'm not exactly sure why the error is being thrown but I know it has something to do with the hook I made. Besides, re-initiating 1i18n each time currency changes doesn't seem right.

Note: I am aware that I can instantiate the context variable in each component that makes use of the interpolation and pass it as an option to interpolation.format(), but that's what I'm trying to avoid. Ideally there would be a way to access this context variable in one single place rather than on a per-translation basis.



Solution 1:[1]

Like you already assumed, you normally need to pass the currency via t() function like here: https://www.i18next.com/translation-function/formatting#currency

But you could try to use the new formatting functionality i18next.services.formatter.add (done after init), but I did not test if this works with context…

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 adrai