Все за back-end та back-end, ще подумаєте що ми фронта не знаємо 😅

Останнім часом нас трохи занесло в оцей весь micro Front-End. Ми розробляємо окремі модулі powered by ReactJS, котрі вбудовуються в батьківську App (CRM, яка також на ReactJS).

CRM-ка росте і постало питання локалізації наших модулів. Як отримати в нашому модулі (котрий є скажімо так, “чужим” для даної CRM) мову, котру обрав користувач в налаштуваннях порталу?

В хід пішов всім відомий i18next + Реактівський Context.

*Так, якщо потрібен коректний переклад, то поки що в широких масах немає нормального автоматизованого інструменту 🤷🤷‍♀

i18n
  .use(initReactI18next)
  .use(
    resourcesToBackend((language: string, namespace: string, callback) => {
      import(`./locales/${language}/${namespace}.json`)
        .then((resources) => {
          callback(null, resources);
        })
        .catch((error) => {
          callback(error, null);
        });
    })
  )
  .init({
    fallbackLng: "uk",
  });

По коду вище видно, що весь текстовий контент (переклади) знаходяться в директорії locales. Вона вміщує в себе окремі піддиректорії із мовними версіями. Разом із тим, в директорії із конкретною мовою може знаходитися декілька файлів. Для чого? Тому що, різні компоненти модуля можуть вбудовуватися у різних місцях батьківської апки. Таким чином, конкретний компонент модуля використовує переклади необхідні саме для нього, а не тягне всі текстовки.

Основна ж магія відбувається тут 👇

const Providers: React.FC<{
  children: React.ReactNode,
  userSettings?: UserSettings,
}> = ({ children, userSettings }) => {
  return (
    <UserSettingsProvider userSettings={userSettings}>
      <LocalizationProvider>{children}</LocalizationProvider>
    </UserSettingsProvider>
  );
};

Два провайдери: UserSettings та Localization. У UserSettings ми якраз і отримуємо всі налаштування юзера на порталі.

export const UserSettingsContext = React.createContext<UserSettingsContextType>({});

// рядок нижче дає нам змогу із будь-якого компоненту, обгорнутого в провайдер діставати всі налаштування користувача
export const useUserSettingsContext = () =>
  useContext<UserSettingsContextType>(UserSettingsContext);

const Provider: React.FC<Props> = ({ children, userSettings }) => {
  return (
    <UserSettingsContext.Provider value={{ userSettings }}>
      {children}
    </UserSettingsContext.Provider>
  );
};

Localization бере в роботу i18n:

export const LocalizationContext = React.createContext<LocalizationContextType>({});

const Provider: React.FC<Props> = ({ children }) => {
  const { userSettings } = useUserSettingsContext();

  useEffect(() => {
    i18n.changeLanguage(userSettings?.lang);
  }, [userSettings?.lang]);

  return (
    <LocalizationContext.Provider value={{ userSettings }}>
      <I18nextProvider i18n={i18n}>{children}</I18nextProvider>
    </LocalizationContext.Provider>
  );
};

Ну і how to use? 👩‍💻

Жив собі компонент модуля, який мав такий експорт:

export default Component;

А тепер з локалізацією став таким:

const ComponentWrap: React.FC<Props> = ({ userSettings }) => (
  <Providers userSettings={userSettings}>
    <Component />
  </Providers>
);

export default ComponentWrap;

to be continued 😉