Синхронизируйте магазин Redux с i18next LanguageDetector - PullRequest
0 голосов
/ 20 июня 2019

Я хочу отслеживать текущую локаль в моем магазине Redux (store.l10n.locale), но я не могу сделать это при инициализации из-за плагина, чтобы определить язык пользователя, который может изменить его, но не вызвать никаких действий...

Мне удалось синхронизировать хранилище Redux с текущей локалью, когда пользователь выбирает язык, и я даже слушал изменения параметров локали в активном URI (благодаря HOC, см. Ниже), чтобы вызвать действие.

Вот мой файл инициализации i18n:

import i18n from 'i18next'
import Backend from 'i18next-xhr-backend'
import LanguageDetector from 'i18next-browser-languagedetector'
import { initReactI18next } from 'react-i18next'
import moment from 'moment'

i18n
  // Load translation using xhr from /public/locales.
  .use(Backend)
  // Detect user language.
  .use(LanguageDetector)
  // Pass the i18n instance to react-i18next.
  .use(initReactI18next)
  // Init i18next.
  .init({
    fallbackLng: 'en',
    debug: true,

    interpolation: {
      // Not needed for React as it escapes by default.
      escapeValue: false,
      format: (value, format, lng) => {
        if (value instanceof Date) return moment(value).format(format)
        return value
      }
    }
  })

// Keep the language on moment.js in sync with i18next
// by listening to the change language event.
i18n.on('languageChanged', newlocale => {
  moment.locale(newlocale)
})

export default i18n

Вот мой срез l10n (тип действия, создатель действия, редуктор ...):

import { createSlice } from 'redux-starter-kit'
import { defaultLocale } from '../i18n/config'

const initialState = {
  locale: defaultLocale
}

const l10n = createSlice({
  slice: 'l10n',
  initialState: initialState,
  reducers: {
    changedLocale(state, action) {
      // 'Mutating' the state is possible
      // with the `createSlice()` function from `redux-starter-kit`
      // because it ships with the immer library.
      state.locale = action.payload
    }
  }
})

export default l10n
export const { reducer: l10nReducer, actions: l10nActions } = l10n
export const { changedLocale } = l10nActions

Вот этоHOC, чтобы установить текущую локаль на основе активного URI:

import React from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { withTranslation } from 'react-i18next'
import { withRouter } from 'react-router-dom'

import { getLocaleFromPath } from '../../../utils/l10n'
import { changedLocale } from '../../../ducks/l10n'

class L10nHOC extends React.Component {
  constructor(props) {
    super(props)

    this.setLocale(getLocaleFromPath(this.props.location.pathname), true)

    this.props.history.listen(location => {
      this.setLocale(getLocaleFromPath(location.pathname))
    })

    // this.props.i18n.on('languageChanged', lng => {
    //   this.props.changedLocale(lng)
    // })
  }

  setLocale = (newLocale, force = false) => {
    // if (force || newLocale !== this.props.locale) {
    if (force || newLocale !== this.props.i18n.language) {
      this.props.i18n.changeLanguage(newLocale)
      this.props.changedLocale(newLocale)
    }
  }

  render() {
    return this.props.children
  }
}

const mapStateToProps = state => ({
  // locale: state.l10n.locale
})

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      changedLocale
    },
    dispatch
  )

export default withRouter(
  withTranslation()(
    connect(
      mapStateToProps,
      mapDispatchToProps
    )(L10nHOC)
  )
)

Но с моим решением по интернационализации поверх реагирования (' react-i18next ') я использовал плагин для обнаруженияязык пользователя (' i18next-browser-languageDetector ').Этот плагин может изменить текущую локаль, но это изменение не отражено в моем магазине Redux.

Я полагаю, что мне следует «слушать» событие смены языка, и это то, что я пытался в моем HOC, следуя i18next API doc :

    this.props.i18n.on('languageChanged', lng => {
      this.props.changedLocale(lng)
    })

Но это не работает, поскольку, когда пользователь впервые заходит на мой веб-сайт, например, во Франции, отображаемый язык отображается на французском, но магазин все еще находится в егоinitialState («en» - язык по умолчанию).

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

i18next.js:27 i18next::backendConnector: loaded namespace translation for language en {public: "This content is public...", private: "This content is private!", …}
i18next.js:27 i18next::backendConnector: loaded namespace translation for language fr {public: "Ce contenu est public...", private: "Ce contenu est privé !", …}
i18next.js:27 i18next: languageChanged fr
i18next.js:27 i18next: initialized {debug: true, initImmediate: true, ns: Array(1), defaultNS: Array(1), fallbackLng: Array(1), …}
i18next.js:27 i18next: languageChanged fr

Заранее благодарен за помощь ...

...