Использование response-i18next с автономным компонентом React - ошибка 'missingKey'

Я получаю сообщения об ошибке «missingKey» от i18next, хотя кажется, что переводы загружаются (можно увидеть журнал консоли). Что я здесь делаю не так?

Вот мой файл i18n.js:

import i18n from 'i18next'
import i18nhttp from 'i18next-http-backend'
import Backend from 'i18next-chained-backend'
import LanguageDetector from 'i18next-browser-languagedetector'
import { initReactI18next } from 'react-i18next'

const options = {
  backends: [
    i18nhttp
  ],
    
  backendOptions: [
    { loadPath: '/api/constants/{{lng}}/{{ns}}.lang.json' }
  ]
}

i18n.use(Backend).use(LanguageDetector).use(initReactI18next).init({
  backend: options,
  ns: ['fin'],
  defaultNS: 'fin',
  fallbackNS: 'fin',
  fallbackLng: 'en',
  keySeparator: false,
  debug: true,
  detection: {
    order: ['queryString', 'cookie'],
    cache: ['cookie'],
    lookupCookie:'website#lang',
  },
  interpolation: {
    escapeValue: false
  },
  react: {
    useSuspense: true
  }
}, (err, t) => {
  if (err) return console.log('something went wrong loading', err);
  t('pinDescription') 
})

export default i18n

А вот и мой файл компонента React:

import React, { Suspense }  from 'react'
import ReactDOM from 'react-dom'
import '../../../scripts/i18n'
import { useTranslation } from 'react-i18next'

  const Translation = () => {
    const { t, i18n } = useTranslation()
  
    return (
      <div className="translation-sample">
        <h2>Translation Sample - from files</h2>
        <p>{t('accountNumberDescription')}</p>
      </div>
    )
  }

  const domElement = document.getElementById('translation-sample')

  if (domElement) {
    ReactDOM.render(
      <React.StrictMode>
        <Suspense fallback={<div>Loading ... </div>}>
          <Translation />
        </Suspense>
      </React.StrictMode>,
      domElement
    );
  }

Для перевода, который я пытаюсь отобразить в обратном вызове init (t ('pinDescription')), я получаю эту ошибку:

i18next::translator: key "pinDescription" for languages "en" won't get resolved as namespace "fin" was not yet loaded This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!

Что странно, поскольку в документации response-i81n указано, что этот обратный вызов выполняется после загрузки переводов.

Для этого и для ключа, который я пытаюсь отобразить в компоненте, я также получаю ошибку «отсутствует ключ»:

i18next::translator: missingKey en fin pinDescription pinDescription
i18next::translator: missingKey en fin accountDescription accountDescription

Я пробовал несколько вещей, в том числе:

  1. Оборачивание вызова init в обещание, экспорт этой функции и ожидание ее в компоненте
  2. Использование метода HOC
  3. Экспорт экземпляра i18n из файла i18n.js, а затем его импорт в компонент и вызов init (пробовал как ожидание, так и обещание / затем)

Кроме того, если я использую компонент оболочки Suspense, я вижу, что переводы загружены в консоль (однако я все еще получаю недостающие ключевые ошибки). Когда я удаляю "Suspense" и отказываюсь от него в конфигурации i81n.js, я никогда не вижу в консоли никаких указаний на то, что переводы загружены.

Я чувствую, что мне здесь не хватает чего-то фундаментального. Как лучше всего дождаться процесса загрузки инициализации / перевода перед использованием 't' в компоненте?

Основное различие между тем, что я делаю, и тем, что показывают большинство примеров в документации, заключается в том, что они показывают, что i18n.js загружается в файл index.js приложения React. У меня нет файла index.js или приложения React - я работаю с одним компонентом React, который позже будет внедрен в существующее приложение, отличное от React.

Кроме того, нет сетевых ошибок, я могу без проблем получить доступ к языковым json-файлам прямо в браузере, и я могу видеть, как переводы загружаются в консоли.

Вывод из консоли браузера (здесь я использую другое пространство имен, но код тот же):

введите описание изображения здесь

Заранее благодарим за любые советы или за указание, где я ошибаюсь!


person jspru    schedule 10.01.2021    source источник


Ответы (1)


Вы пропустили i18next provider

import React, { Suspense } from 'react';
import ReactDOM from 'react-dom';
import i18n from '../../../scripts/i18n';
import { useTranslation, I18nextProvider } from 'react-i18next';

const Translation = () => {
  const { t } = useTranslation();

  return (
    <div className="translation-sample">
      <h2>Translation Sample - from files</h2>
      <p>{t('accountNumberDescription')}</p>
    </div>
  );
};

const domElement = document.getElementById('translation-sample');

if (domElement) {
  ReactDOM.render(
    <React.StrictMode>
      <I18nextProvider i18n={i18n}> // <----
        <Suspense fallback={<div>Loading ... </div>}>
          <Translation />
        </Suspense>
      </I18nextProvider>
    </React.StrictMode>,
    domElement
  );
}
person felixmosh    schedule 10.01.2021
comment
Вы уверены, что провайдер нужен? Я не видел здесь упоминания об этом: react.i18next.com/latest/using -with-hooks react.i18next.com/guides/quick-start - person jspru; 10.01.2021
comment
Я уверен, что в исходном коде useTranslation видно, что он использует useContext github.com/i18next/react-i18next/blob/master/src/ - person felixmosh; 10.01.2021
comment
ах, хорошее наблюдение. однако похоже, что использование провайдера необязательно. я получал экземпляр i18n из хука useTranslation (), но пропустил его в моем коде, опубликованном выше (я удалил его во время экспериментов). добавил его обратно во фрагмент кода выше. - person jspru; 10.01.2021
comment
Вы пробовали добавить провайдера? посмотрите на код, он делает гораздо больше, чем использует контекст - person felixmosh; 10.01.2021
comment
Кроме того, почему вы используете i18next-chained-backend, в этом нет необходимости, просто используйте http - person felixmosh; 10.01.2021
comment
Я просто попробовал это с поставщиком и, к сожалению, все еще получаю те же ошибки. Да, похоже, что в «i18next-chained-backend» нет необходимости (я унаследовал этот код), поэтому я его тоже удалил. Для меня тот факт, что перевод в обратном вызове init не работает, является признаком того, что проблема кроется где-то в настройке i81n.js. Это еще до того, как компонент React вступит в игру. Я ожидал, что переводы будут загружены к моменту выполнения кода обратного вызова. Спасибо за предложения. - person jspru; 11.01.2021
comment
Есть сетевые ошибки? - person felixmosh; 11.01.2021
comment
Нет сетевых ошибок. На самом деле я вижу, как загружаются переводы, несмотря на ошибки. Я только что добавил снимок экрана консоли выше (нажмите, чтобы увидеть подробности). - person jspru; 11.01.2021
comment
Сможете ли вы создать небольшое репо, воссоздающее проблему? - person felixmosh; 11.01.2021
comment
Конечно, мне придется переработать его в более простую форму из реального полного приложения, над которым я работаю - я сделаю это, если не смогу решить эту проблему к концу дня сегодня - спасибо. - person jspru; 11.01.2021
comment
Проблема оказалась в том, что у меня был другой экземпляр i18n, запущенный из другого компонента, который конфликтовал с указанным выше. Как только я удалил это, все начало работать нормально. Единственное, поскольку это библиотека компонентов, а не приложение, у меня нет ни одного места, где я мог бы импортировать i18n.js - я должен импортировать его в каждый компонент индивидуально. Я думаю, что правильным решением было бы импортировать i18n.js один раз в клиентском приложении, однако в клиентском приложении нет React. Множество ограничений, характерных для моего проекта. Спасибо за помощь. - person jspru; 12.01.2021
comment
что касается документации для хуков, она должна работать так: react.i18next.com/latest/ using-with-hooks У меня также есть проблемы с использованием перевода для нескольких компонентов, и его, к сожалению, нигде не документировано :( - person Macilias; 13.05.2021