Реагируй i18следующий и правильный способ смены языка

Я разрабатываю мультиязычное приложение с использованием React, i18next а также i18next-browser-languagedetector,

Я инициализирую i18next следующим образом:

i18n
  .use(LanguageDetector)
  .init({
    lng: localStorage.getItem(I18N_LANGUAGE) || "pt",
    fallbackLng: "pt",
    resources: {
      en: stringsEn,
      pt: stringsPt
    },
    detection: {
      order: ["localStorage", "navigator"],
      lookupQuerystring: "lng",
      lookupLocalStorage: I18N_LANGUAGE,
      caches: ["localStorage"]
    }
  });

export default i18n;

И я реализовал селектор языка, который просто меняет значение в localStorage к тому, что выбрал пользователь.

Это правильный способ сделать это?

Я спрашиваю, потому что, хотя это работает, я чувствую, что я "обманываю", устанавливая localStorage.getItem(I18N_LANGUAGE) || "pt" и что я не использую определение языка, как я должен.

5 ответов

Решение

Согласно документации, вам не нужно указывать язык самостоятельно:

import i18next from 'i18next';
import LngDetector from 'i18next-browser-languagedetector';

i18next
  .use(LngDetector)
  .init({
    detection: options
  });

И согласно этому куску источника в i18next, он действительно использует возможности обнаружения плагина:

if (!lng && this.services.languageDetector) lng = this.services.languageDetector.detect();

Это правильный способ сделать это?

Так что нет, это не так. Позвольте плагину делать свою работу.:)

Надеюсь, это поможет кому-то в будущем. Документация точно не дает вам полной картины того, как настроить обнаружение, а затем я обнаружил закрытую проблему Github, в которой несколько человек задавали разумный вопрос, а сопровождающие были грубо в своих ответах, но также предоставили ссылка, которая должна была быть в документации, но не упоминается абсолютно нигде за пределами этого комментария Github. Этот пример прояснил мою проблему с несколькими небольшими поправками из того, что указано в текущей документации.

Затем я смог определить язык в своем URL-адресе с помощью https:www.domain.com?lng=es а также при использовании расширения браузера, которое позволяет мне изменять язык браузера.

Вот моя работа i18n.ts файл:

import i18n from 'i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
import { initReactI18next } from 'react-i18next'
import XHR from "i18next-http-backend" // <---- add this

import commonDe from './locales/de/common.json'
import commonEn from './locales/en/common.json'
import commonEs from './locales/es/common.json'
import commonFr from './locales/fr/common.json'

const resources = {
  de: { common: commonDe },
  en: { common: commonEn },
  es: { common: commonEs },
  fr: { common: commonFr }
}

const options = {
  order: ['querystring', 'navigator'],
  lookupQuerystring: 'lng'
}

i18n
  .use(XHR) // <---- add this
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    // lng: 'en' // <--- turn off for detection to work
    detection: options,
    resources,
    ns: ['common'],
    defaultNS: 'common',
    fallbackLng: 'en',
    supportedLngs: ['de', 'en', 'es', 'fr'],
    interpolation: {
      escapeValue: false,
    },
    debug: false,
  })

export default i18n

(бонусная помощь - если кто-то застрял в этой части)

Я работаю в проекте Next.js, и указанный выше файл был загружен в project-root/pages/_app.tsx файл вроде этого:

import React from 'react'
import { AppProps } from 'next/app'
import '../i18n/i18n'

import '../public/styles.css'

const TacoFridayApp = ({ Component, pageProps}: AppProps): JSX.Element => {
  
  return <Component {...pageProps} />
}

export default TacoFridayApp

Я думаю, что вы очень близки. Вы можете просто установить i18n с запасным языком изначально. А затем после загрузки сохраненной языковой информации для локального хранилища или локального хранилища или любого другого хранилища, позвоните i18nInstance.changeLanguage(lng),

@firstdoit:

Хороший ответ в отношении автоматического определения языка браузера. Однако вы не думаете, что это лучший подход, когда пользователю предоставляется автоматическая и ручная конфигурация.

Например, если у вас установлен браузер на английский, это подойдет для автоматического подхода, который вы предлагаете, основываясь на документации. Если пользователь меняет язык страницы с английского на французский, это не влияет на язык браузера, поэтому сайт остается только на английском, потому что настройки настроены на автоматическое определение языка браузера.

Я, в свою очередь, буду отдавать приоритет текущему языку страницы:

  • Либо передается через параметры (/george.php?lang=fr или /fr_FR/george.php)

Это будет передано как реквизиты для моего кода, как правило, как следует

  • var lang = this.props.lang || this.services.languageDetector.detect () || "Ан";

Что вы берете?

тратил на это много времени, но, к счастью, спас мне день своим taco_friday . Добавляем сюда мои два цента:

Я в основном пытался загрузить данные из моего локального хранилища в i18-next. Есть плагин под названием i18next-localstorage-backend, который должен облегчить это, но мне не удалось его запустить.

Но найдя вдохновение в том, чем поделились тако-пятница, я смог адаптировать свой i18n.ts соответственно:

      import i18n from 'i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
import { initReactI18next } from 'react-i18next'
import BrowserStorageManager from './services/browserStorageManager'
import loadTranslations from './services/loadTranslations'

const service = new BrowserStorageManager()
loadTranslations()

const resources = {
    'de-CH': service.getItem<any>('de-CH')?.value,
}

i18n.use(LanguageDetector)
    .use(initReactI18next)
    .init({
        debug: false,
        fallbackLng: 'deCH',
        resources,
        interpolation: {
            escapeValue: false, // not needed for react!!
        },
    }) 

Содержание browserStorageManager.ts является:

      import logSymbols from 'log-symbols'

class BrowserStorageManager {
    public setItem(key: string, value: any): void {
        localStorage.setItem(key, JSON.stringify({ value }))
    }

    public getItem<T>(key: string): T | null {
        const data: string | null = localStorage.getItem(key)
        if (data !== null) {
            return JSON.parse(data)
        }
        console.log(logSymbols.error, ` ${key}-key is empty - aborting ...`)
        return null
    }
}

export default BrowserStorageManager

И, наконец, структура resourceBundle в моем localStorage выглядит следующим образом:

      {
    value:{
        translation:{
            key: "value",
            ....
        }
    }
} 

translation является пространством имен по умолчанию, поэтому нет необходимости определять его в .init

Другие вопросы по тегам