在 React 和 Redux 应用程序中自行添加 i18n

起初在React中让我感到惊讶的一件事是, everything是多么的组件,表面上听起来很简单,但对于功能性东西(例如表单管理,i18n(国际化),路由,状态...)它对我来说并不太自然,并且为非视觉功能性仅有的组件添加了组件层。

通常,其他 UI libs/frameworks 具有基于 API 的处理功能逻辑的方式:路由器 API、表单 API 等,它们为这些情况提供了扩展自己的 API 或实例的方式。

當我檢查 React 的 i18n 解決方案時,我發現大多數解決方案都使用翻譯部件,特別是當你需要更多的功能和功能時,它們很棒,但我的使用案例很簡單,所以我決定自己做。

如果您有兴趣尝试 React 的 i18n 库之一,请参阅 这篇文章涵盖 i18next 和 react-i18next

字母缩减

我将向你展示的解决方案使用 Redux,因为它已经是一个伟大的状态容器,但如果你愿意,你可以为字母构建一个容器,机械类似。

首先,让我们创建一个 store/literals.js 作为 Redux 状态,以存储字母:

 1[label store/literals.js]
 2const defaultState = {};
 3
 4const LOAD_LITERALS = "LOAD_LITERALS";
 5
 6export default (state = defaultState, { type, payload }) => {
 7  switch (type) {
 8    case LOAD_LITERALS:
 9      return payload;
10    default:
11      return state;
12  }
13};
14
15export const loadLiterals = literals => ({
16  type: LOAD_LITERALS,
17  payload: literals,
18});

如果你已经熟悉Redux,这里没有什么特别的,我们只有一种减速器来取代整个字母状态,以及一个loadLiterals动作创建器来设置它们。


在 React/Redux 应用中,安装通常从使用 React Redux 提供商组件的 index.js 文件开始:

 1[label index.js]
 2import React from "react";
 3import ReactDOM from "react-dom";
 4import { Provider } from "react-redux";
 5
 6import App from "./App";
 7import store from "./store";
 8
 9ReactDOM.render(
10  <Provider store={store}>
11    <App />
12  </Provider>,
13  document.getElementById("root")
14);

在这里,仓库来自一个您创建 Redux 仓库的文件,将根减速器传递到一个像combineReducers这样的函数:

 1[label store/index.js]
 2import { createStore, combineReducers } from "redux";
 3import literals from "./literals.js";
 4
 5const rootReducer = combineReducers({
 6  literals,
 7  // other reducers...
 8});
 9
10export createStore(rootReducer);

没有什么特别的,只是创建Redux商店的常规步骤。

加载文本

让我们创建一个具有以下结构的文件夹来组织您的 i18n 逻辑:

1+ i18n
2  - index.js
3  - en.json
4  - es.json
5  ....

JSON 文件只具有语言字母字母的关键值数据:

1[label i18n/en.json]
2{
3  "app_greet": "Hey Joe!"
4}

至于 index.js 文件,我们可以暴露一个函数,该函数返回给定语言的字母:

 1[label i18n/index.js]
 2import en from "./en.json";
 3import es from "./es.json";
 4
 5const langs = {
 6  en,
 7  es
 8};
 9
10export default function (lang = "en") {
11  return langs[lang];
12};

这个想法是早点在你的应用程序中加载字母字母,你可能需要同时初始化和配置其他东西,我有时会为此创建 init.js 文件,但只需按你想要的方式去做。

但是,你必须确保商店已经创建了,在创建商店后,让我们在 index.js 中做到这一点:

 1[label index.js]
 2import React from "react";
 3import ReactDOM from "react-dom";
 4import { Provider } from "react-redux";
 5
 6import App from "./App";
 7import { loadLiterals } from "store/literals";
 8import store from "./store";
 9import loadLang from "./i18n";
10
11const lang = loadLang();
12store.dispatch(loadLiterals(lang))
13
14ReactDOM.render(
15
16    <App />
17  ,
18  document.getElementById("root")
19);

正如你所看到的,我们通过调用loadLiterals函数来加载它们,我们可以通过使用store.dispatch实例方法调用组件外部的 Redux 操作。

这应该足以让你的字母加载。然后,在任何组件中,你可以使用连接函数来获得你的商店。

 1[label index.js]
 2import React from "react";
 3import { connect } from "react-redux";
 4
 5const App = ({ literals }) => (
 6  <div>
 7    {literals.app_greet}
 8  </div>
 9);
10
11const mapStateToProps = ({ literals }) => ({
12  literals
13});
14
15export default connect(mapStateToProps)(App);

虚假的装载文本

如果我们想更进一步,我们可以通过使用JavaScript 动态导入功能更改i18n/index.js中的默认导出到懒惰地加载字母:

1[label i18n/index.js]
2export default function (lang = "en") {
3  return import(`./${lang}.json`);
4};

不仅功能变得更简单,而且字母在需求上也会懒惰地加载,使包尺寸更小,这意味着一个加载更快的应用程序。

由于动态导入返回了一个承诺,现在我们需要更新我们如何在商店中加载字母如下:

 1[label index.js]
 2import React from "react";
 3import ReactDOM from "react-dom";
 4import { Provider } from "react-redux";
 5
 6import App from "./App";
 7import { loadLiterals } from "store/literals";
 8import store from "./store";
 9import loadLang from "./i18n";
10
11loadLang().then(lang => store.dispatch(loadLiterals(lang)));
12
13ReactDOM.render(
14
15    <App />
16  ,
17  document.getElementById("root")
18);

包装上

我们已经看到你如何从头开始将一些简单的i18n功能添加到你的React/Redux应用程序中,你不需要这样做,当然有不同的方法来完成同样的事情,但我希望你已经看到自己可以轻松和有趣地做到这一点,这对于简单的使用案例来说可能是足够的。

Published At
Categories with 技术
Tagged with
comments powered by Disqus