Я хочу отслеживать текущую локаль в моем магазине 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
Заранее благодарен за помощь ...