當前,React是web前端開發最流行的Javascript庫之一。隨着國家間的交流日益緊密,web前端需要有多語言版本,也就是國際化。通行的做法是根據用戶的瀏覽器來自動判斷用戶使用的語言,顯示對應的文本;但同時也提供一個語言切換按鈕。本教程從零開始,介紹了React下web前端實現多語言的過程。使用Vue的同學可以自己對照進行修改。
爲了簡化,本教程只實現了中/英雙語言。本教程需要提前安裝好node和React,參考地址爲:https://reactjs.org/。同時也需要一個編輯器或者IDE(推薦Atom或者Visual Studio Code)。
一、創建一個React項目
在工作目錄下執行以下命令並等待完成。該命令用來創建一個名爲multilanguage的React項目。
npx create-react-app multilanguage
下載完所有的文件後,會有下一步操作的提示:
cd multilanguage
npm start
執行上述命令後,會在本地打開一個瀏覽器窗口訪問http://localhost:3000/
。它顯示一個React頁面,只有一個大大的React Logo和學習React的超鏈接。恭喜你,你已經成功建立了一個React項目!
小提示:如果你的電腦3000端口被佔用了,它會提示你是否使用3001端口。
二、導入i18相關模塊
讓我們先按Ctrl + C鍵來關掉開發服務器的運行以便進行代碼編寫。
在Javascript中,我們通常使用i18next
庫來進行多語言的開發,想詳細研究的同學請點擊https://www.i18next.com/。我們這裏不做介紹直接使用就行。使用常用的編輯器打開剛纔創建的工程,在src/
下創建一個新文件叫i18n.js
,代碼如下:
import i18next from 'i18next'
import {initReactI18next} from 'react-i18next'
import XHR from 'i18next-xhr-backend'
import LanguageDetector from 'i18next-browser-languagedetector'
i18next.use(XHR).use(LanguageDetector).use(initReactI18next).init({
backend: {
loadPath:'./locales/{{lng}}.json'
},
react: {
useSuspense: true
},
fallbackLng: 'en',
preload: [
'en', 'zh','zh-cn'
],
keySeparator: false,
interpolation: {
escapeValue: false
}
})
export default i18next
簡要解釋一下,這個js文件主要是初始化i18next
庫。i18next
庫預先裝載一些預定的json文件,然後根據使用的語言將標記字符串替換成對應的語言文本。這段代碼定義了json路徑,預裝載語言等。
然後再編輯src/index.js
。首先,將第一行代碼改爲import React, {Suspense} from 'react';
。然後在導入語句裏增加這麼一行:import "./i18n";
。最後將輸出的元素用Suspense
包裝一下。修改完成的代碼如下:
import React, {Suspense} from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import './i18n';
ReactDOM.render(
<Suspense fallback = {"loading"} >
<App />
</Suspense>
, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
此時項目還不能運行,我們需要安裝i18n.js
中導入的庫,在項目根目錄下(記住不是源碼根目錄src
)使用命令行依次運行:
npm install i18next --save
npm install react-i18next --save
npm install i18next-xhr-backend --save
npm install i18next-browser-languagedetector --save
小提示:類似Atom或者Visual Studio Code這種IDE有終端插件,可以直接在編輯器裏打開命令行,並且默認就爲項目根目錄。
三、生成多語言文檔
從i18n.js
中我們可以看到,它需要裝載網頁主目錄下的locales
目錄下對應的json文件。這裏我們使用python
來轉換excel
表格以生成相應的json文件。在項目根目錄下的public目錄裏(也就是網頁根目錄)新建locales
文件夾,然後打開你的office或者wps office來新建一個multilanguage.xlsx
文檔(excel表格)。內容如下:
將該excel文件複製或者保存在locales
文件夾下,然後再在該文件夾下新建一個文件convert.py
。該.py
文件的作用是將excel表格裏的內容轉成json並保存,代碼爲:
import xlrd # 引入xlrd模塊
import json # 引入json模塊
def convert():
file = xlrd.open_workbook('multilanguage.xlsx') # 打開excel文件對象
table = file.sheets()[0] # 通過索引順序獲取表格
rows = table.nrows # 總的行數
en = {}
zh = {}
for r in range(1,rows): # 去除表頭所有從第一行開始
rowData = table.row_values(r) # 獲取每一列的數據
str = rowData[0]
en_str = rowData[1]
zh_str = rowData[2]
en[str] = en_str
zh[str] = zh_str
return en,zh
def main():
en,zh = convert()
# Writing JSON data
with open('en.json', 'w') as f:
json.dump(en, f)
with open('zh-cn.json', 'w', encoding='utf-8') as f2:
json.dump(zh, f2,ensure_ascii=False)
with open('zh.json', 'w', encoding='utf-8') as f3:
json.dump(zh, f3,ensure_ascii=False)
print("convert to json success")
main()
隨後在命令行裏切換到locales
目錄,運行python3 convert.py
。看到convert to json success
提示後,localse
目錄下會生成三個json文件。
這裏需要提前安裝python3和相應的python庫。Python3安裝鏈接:https://www.python.org/downloads/release/python-381/,庫安裝推薦使用pip
工具。
四、應用多語言
應用多語言就是進行對應的文本替換。打開src/App.js
,在導入語句裏增加一行import { useTranslation } from 'react-i18next';
,然後在函數組件App裏增加一行const {t} = useTranslation();
。接着進行文本替換,修改完成後的代碼如下:
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { useTranslation } from 'react-i18next';
function App() {
const {t} = useTranslation();
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
{t('edit')} <code>src/App.js</code> {t('save_load')}
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
{t('learn_react')}
</a>
</header>
</div>
);
}
export default App;
這時我們在項目根目錄下使用終端再次運行npm start
,頁面就變成中文啦。
五、編寫多語言按鈕
現在我們已經實現中英文雙界面了(如果你把你的語言設置改成英文,就會顯示英文)。但是光是這樣還不夠,還需要提供一個按鈕讓用戶可以自由切換語言並保存用戶的選擇。這裏,我們使用了React下的Material UI的多語言圖標。
首先,讓我們再次按下Ctrl + C鍵來關閉開發服務器的運行。接着,我們在/src
目錄下新建components\LanguageBtn\index.js
。
將下方的代碼直接複製到剛剛生成的js文件中。
import React, {useState} from 'react'
import TranslateIcon from "@material-ui/icons/Translate"
import DownIcon from '@material-ui/icons/KeyboardArrowDown';
import MenuItem from "@material-ui/core/MenuItem";
import Button from "@material-ui/core/Button";
import Menu from "@material-ui/core/Menu";
import PropTypes from "prop-types";
import {reactLocalStorage} from 'reactjs-localstorage'
import i18next from 'i18next'
const tokenId = "multilanguage_demo";
const options = ['English', "中文"];
const lngOptions = ['en', 'zh'];
function LanguageBtn({fontColor}) {
let userProfile = reactLocalStorage.getObject(tokenId) || {};
const language = userProfile['lng'] || i18next.language;
const indexInit = (language === 'zh' || language === 'zh-CN' || language === 'zh-cn') ? 1 : 0;
const [selectedIndex, setSelectedIndex] = useState(indexInit);
const [anchorEl, setAnchorEl] = React.useState(null);
const handleClick = event => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const handleCloseProfile = index => async event => {
if (index === selectedIndex) {
return;
}
setAnchorEl(null);
await i18next.changeLanguage(lngOptions[index])
userProfile['lng'] = lngOptions[index]
reactLocalStorage.setObject(tokenId, userProfile)
setSelectedIndex(index)
};
return (
<>
<Button
aria-haspopup="true"
onClick={handleClick}
>
<TranslateIcon style={{color: fontColor}} />
<p style={{color: fontColor}} >{options[selectedIndex].toUpperCase()}</p>
<DownIcon style={{color: fontColor}} />
</Button>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
{options.map((option,index) => (
<MenuItem
key = {option}
selected = {index === selectedIndex }
onClick={handleCloseProfile(index)}
value = {index}
>
{option}
</MenuItem>
))}
</Menu>
</>
)
}
LanguageBtn.propTypes = {
classes: PropTypes.object
};
export default LanguageBtn;
簡單解釋一下,這裏編寫了一個函數組件,它包含一個多語言按鈕和一個選擇菜單。點擊多語言按鈕後會顯示選擇菜單,點擊菜單後會根據用戶選擇的語言重新顯示文本並保存用戶的選擇。按鈕有一個屬性叫fontColor
,它用來設置按鈕文本的顏色,以對應不同背景色下文字的顯示問題。使用reactLocalStorage
將用戶的選項保存在本地存儲中。這裏同樣需要先安裝material ui庫,在項目根目錄下使用命令行依次運行:
npm install @material-ui/core --save
npm install @material-ui/icons --save
npm install reactjs-localstorage --save
我們的語言切換按鈕組件已經編寫好了,可以應用到本項目任何頁面的任何地方了。
六、應用切換按鈕
現在可以將我們的多語言切換按鈕顯示到我們的主頁面了。修改src/App.js
,導入我們剛纔編寫好的組件。
import LanguageBtn from './components/LanguageBtn';
然後在輸出中加入我們編寫好的組件:
<div style={{textAlign:"right",marginRight:"10px"}}>
<LanguageBtn fontColor='black'/>
</div>
這裏只進行了很簡單的頁面修改和css設置,主要是演示按鈕的功能。
修改後的App.js
最終代碼如下:
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { useTranslation } from 'react-i18next';
import LanguageBtn from './components/LanguageBtn';
function App() {
const {t} = useTranslation();
return (
<div className="App">
<div style={{textAlign:"right",marginRight:"10px"}}>
<LanguageBtn fontColor='black'/>
</div>
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
{t('edit')} <code>src/App.js</code> {t('save_load')}
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
{t('learn_react')}
</a>
</header>
</div>
);
}
export default App;
好了,所有工作都已經完成了,讓我們來再次運行npm start
進行測試。點擊頁面右上角的按鈕,可以自由切換語言喲。
七、打包發佈
打包發佈時也有幾點需要注意:
- 修改項目根目錄下的package.json,在依賴屬性
dependencies
上面增加一行"homepage":".",
,意思爲放在任意目錄下。 - 在項目根目錄下新建
.env
文件,裏面寫上這麼一行:GENERATE_SOURCEMAP=false
,該行指令的意思是打包後的工程不顯示源代碼。
最後運行npm run build
,它將在build
文件夾下生成打包好的發佈版本,把該目錄下所有文件複製到Apache網頁根目錄或者任意二級目錄下(比如multilanguagedemo
)。
在瀏覽器中訪問,顯示結果如下圖。
以上就是從零構建React下的多語言實現的所有流程。
由於自身水平有限,難免會出現錯誤或者有不完善的地方,懇請大家留言指正和改進。基於同樣的原因,這個完整的示例就不放在github上了,而是把它放在碼雲上。
示例碼雲地址:=> https://gitee.com/TianCaoJiangLin/multilanguage