起初在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应用程序中,你不需要这样做,当然有不同的方法来完成同样的事情,但我希望你已经看到自己可以轻松和有趣地做到这一点,这对于简单的使用案例来说可能是足够的。