Ручное переключение интернационализации на основе react-intl

внешний интерфейс JavaScript React.js Redux

Знать столбец:zhuanlan.zhihu.com/c_215040065, личный блог:blog.caichengnan.com/

предисловие

Интернационализация — очень распространенное требование, раньше у меня не было соответствующего опыта в этой области, поэтому я решил попрактиковаться. Совсем недавно я писал React-скелет (скелет, который можно напрямую пересаживать в новые проекты), и я проверил его в Интернете.react-intlБиблиотека примерно эффективна.

Реализовать идеи

  • Во-первых, решить статическую интернационализацию, то есть автоматически загрузить соответствующий языковой шаблон в соответствии с языком браузера. Просто судить здесьnavigator.languageТипа достаточно, а затем предоставляется react-intlIntlProviderКомпоненты, загрузите локаль и сообщения свойств компонента и, наконец, импортируйте компоненты, которым необходимо использовать интернационализацию.FormattedMessageКомпоненты (встроенные в react-intl) сопоставляются со свойствами в соответствующих файлах интернационализации по идентификатору (например, hello в en_US.js ниже). Статическая интернационализация может быть достигнута.

  • Динамическая интернационализация, то есть пользователи могут переключать языки с помощью кнопок. Самое простое решение — поместить шаблон языка в хранилище избыточности, предоставить действие для переключения языка, изменить шаблон страны и языка в хранилище, а затем запустить соответствующийFormattedMessageРендеринг компонентов. Давай сделаем это!

Код

  • Создайте новый файл локали в папке src для хранения файлов интернационализированных языков Здесь мы создаем новые en_US.js и zh_CN.js.

en_US.js

const en_US = {
  hello: 'Hello, world!',
  name: 'my name is {name}'
}    
export default en_US;

zh_CN.js

const zh_CN = {
  hello: '你好,世界!',
  name: '我的名字是 {name}'
}
export default zh_CN; 

одна обычная переменнаяhello, один с переменной{name}полеname.

  • РеагироватьIntlProviderКомпоненты, похожие на ReduxProviderКомпоненты, которые необходимо импортировать глобально. Итак, давайте инкапсулируемIntl.jsxкомпоненты, которые сочетают в себе избыточность иIntlProviderОбъединить.

Intl.jsx

import React, { Component } from 'react';
import { addLocaleData, IntlProvider } from 'react-intl';
import { connect } from 'react-redux';
import zh_CN from './locale/lang/zh_CN';
import en_US from './locale/lang/en_US.js';
import zh from 'react-intl/locale-data/zh';
import en from 'react-intl/locale-data/en';

addLocaleData([...zh,...en]);

class Inter extends Component {
  render() {
    let { locale, localeMessage, children } = this.props;
    return (
      <IntlProvider key={locale} locale={locale} messages={localeMessage}>
        {children}
      </IntlProvider>
    )
  }
};

function chooseLocale(val) {
  let _val = val || navigator.language.split('_')[0];
  switch (_val) {
    case 'en':
      return en_US;
    case 'zh':
      return zh_CN;
    default:
      return en_US;
  }
}

const mapStateToProps = (state, ownProps) => ({
  locale: state.root.language,
  localeMessage: chooseLocale(state.root.language)
});

let Intl = connect(mapStateToProps)(Inter);

export default Intl;

Объясните этот компонент, компонент должен связать данные в редуксе сIntlProviderкомпонент,addLocaleDataФункция добавляет локализованный язык, который необходимо объявить. Два реквизита поставляются в REDUX,localeпредставляет текущий язык,localeMessageПредставляет содержимое языкового файла в локали.

Здесь есть очень важное место, ключевой атрибут. Изменения свойств в IntlProvider не вызываютFormattedMessageПеререндерил,сначала хотел принудительно обновить компонент с помощью forceUpdate.Позже нашел решение в интернете.Добавление ключа к компоненту может решить эту проблему.

  • Представлен в компонентах, которые фактически используют языкFormattedMessage, конечно же, react-intl также поддерживает другие типы компонентов преобразования, такие как типы времениFormattedDateи т.п.可从官网上查询API。github

App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import { FormattedMessage } from 'react-intl';
import actions from '../actions/index.js';
import { connect } from 'react-redux';

class App extends Component {
  changeLanguage() {
    let lang = this.props.locale;
    lang = lang === 'zh' ? 'en' : 'zh';
    this.props.changeLanguage(lang);
  }
  render() {
    const { locale } = this.props;
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">
            <FormattedMessage
              id="hello"
            />
          </h1>
        </header>
        <p className="App-intro">
          <FormattedMessage
            id="name"
            values={{ name: <b>{'carroll'}</b> }}
          />
        </p>
        <button onClick={() => this.changeLanguage()}>{locale === 'zh' ? '切换英文' : 'change chinese'}</button>

      </div>
    );
  }
}
const mapStateToProps = (state, ownProps) => ({
  locale: state.root.language,
});
const mapDispatchToProps = (dispatch, ownProps) => ({
  changeLanguage: (val) => dispatch(actions.changeLanguage(val))
});
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App);

App.js в основном реализует две функции: одну для динамического переключения, другую для динамического переключения.FormattedMessageПривязка id к данным.

  • Наконец, импортируйте в корневой файлIntl.jsxТолько что
// ... 省略前面的引入
ReactDOM.render(
  <Provider store={store}>
    <Intl>
      <App />
    </Intl>
  </Provider>,
  document.getElementById('root'));
  • Ниже исходный код на github

исходный код на гитхабе

Суммировать

Общая реализация, динамическое международное переключение не так уж сложно, но надо подумать. Пусто ли помещать интернационализированные данные в редукс, и можем ли мы не вводить его?FormattedMessageЭто также может решить переключение текста, вIntlProviderПриведет ли привязка к нему ключа повторный рендеринг других несвязанных компонентов. Это все вопросы, которые мы должны рассмотреть.

Если есть ошибка, укажите на нее, если она вам помогла, поставьте лайк