轉載請注明出處王亟亟的大牛之路
開篇啰嗦–階段感悟
最近2 -3個月基本都因為一些私事沒怎麼系統的工作和學習,途中看了幾天Kotlin的東西寫了些demo并且整了個小項目,但是整體狀态不是很好,這些天看到些95後碼農的強勢細思極恐。
現在大多數醒來就已經是中午,起得早去一下健身房,起的晚就家裡宅一天。公司有事或者有其他家事就去協調/溝通/處理下,整個人感覺都提前進入養老狀态(當然這個鍋有一半是沉迷王者榮耀不可自拔,不太好)
最近項目上基本沒啥事情了,然後讓手下的小夥伴們對之前做的一些内容進行二次封裝,然後他們引用了一個第三方國際化的庫我覺得不錯,然後看了看源碼就分享下,希望大家用得上(雖然現在産品的閱聽人群都是國内的,但是準備下好像沒毛病?)
廢話啰嗦完了,老規矩:https://github.com/ddwhan0123/Useful-Open-Source-Android (雖然我不怎麼工作了,但是git還是每天會花時間看看)
庫屬性介紹:
項目位址:https://github.com/AlexanderZaytsev/react-native-i18n
屬性 | 解釋 |
---|---|
支援RN版本 | 所有版本 |
支援平台 | iOS+Android |
是否需要NativeModule | 是 |
是否可移植 | 是 |
是否含有jni子產品 | 否 |
使用:
1.install (略,git裡都寫着了,就是npm那些事)
2.項目中使用
因為是一些靜态屬性引用,是以你用redux做儲存替換也可以,直接做飲用也可以(本文拿en,zh為例)。
首先是建英文版本的配置檔案,en/index.js
export default {
home: {
greeting: 'Greeting in en',
tab_home: 'Home',
tab_donate: 'Donate',
tab_demo: 'Demo',
language: 'language',
live_demo: 'Live Demo',
buy_me_coffee: 'Buy me a coffee',
gitee: 'Gitee',
star_me: 'Star me',
donate: 'donate',
exit: 'exit?',
},
donate: {
donate: 'donate us~~~',
donate_desc: '© 2017 Pactera Technology International Limited. All rights reserved.',
},
demo: {
dialog: 'dialog',
button: 'button',
switch: 'switch',
action_sheet: 'Action Sheet',
}
};
然後是中文的zh/index.js
export default {
home: {
greeting: 'Greeting in zh',
tab_home: '首頁',
tab_donate: '捐贈',
tab_demo: '例子',
language: '語言',
live_demo: '例子',
buy_me_coffee: '請我一杯coffee',
gitee: 'Gitee',
star_me: '關注我',
donate: '貢獻',
exit: '是否退出?',
},
donate: {
donate: '支援我們~~',
donate_desc: '© 2017 Pactera Technology International Limited. All rights reserved.',
},
demo: {
dialog: '提示框',
button: '按鈕',
switch: '開關',
action_sheet: '',
}
};
屬性名,結構是一緻的隻是屬性不同,當然這裡是靜态的2個檔案,如果場景需要可以服務端下發json,那就是完全動态的了,這部分看業務需求了。
2.1 預設的語言環境
我們在上面寫了2種語言配置,那麼哪種作為初始化的呢?在業務層調用前,我們可以先進行預設
i18n/index.js
import i18n from 'react-native-i18n';
import en from './en';
import zh from './zh';
i18n.defaultLocale = 'en';
i18n.fallbacks = true;
i18n.translations = {
en,
zh,
};
export {i18n};
這邊進行了一些預設,預設語境為en,允許fallbacks狀态(為true時,順序向下周遊翻譯),預設轉換的檔案就2個,一個en一個zh,這個你也可以自行後續添加根據需求而定。
2.2 業務層調用
先是倒包
import {i18n} from '你預設的index的目錄';
調用(拿一個Toast做個例子)
兩種輸出結果如下:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICdzFWRoRXdvN1LclHdpZXYyd2LcBzNvwVZ2x2bzNXak9CX90TQNNkRrFlQKBTSvwFbslmZvwFMwQzLcVmepNHdu9mZvwFVywUNMZTY18CX052bm9CX90zdNlXRE1UdGdUYzI1RaZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39TM2IDMxAjM3EjMwETM3EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
源碼分析
這個庫的實作分為2部分,一部分是Native的版本判斷等功能以及js部分的核心實作fnando/i18n-js
i18n-js是一個輕量級的js翻譯庫,他支援各種格式和内容的換算和語言内容的切換,位址如下:https://github.com/fnando/i18n-js
那麼翻譯轉換這塊是 I18n.js做的那麼Native做了些啥呢?我們來一探究竟(以安卓為例,蘋果看不懂,抱歉)
Native代碼就兩個類,是以我之前說你直接把Native代碼copy走然後項目依賴I18n.js也能達到這個效果
RNI18nPackage是一個普通的Package類,它的作用就是把我們的module加到主應用的getPackages()方法中的清單裡,然後一起打進包裡而已。
具體功能都在RNI18nModule裡
public class RNI18nModule extends ReactContextBaseJavaModule {
public RNI18nModule(ReactApplicationContext reactContext) {
super(reactContext);
}
//RN調用的控件名
@Override
public String getName() {
return "RNI18n";
}
//對取出的Locale清單進行格式化的方法
private String toLanguageTag(Locale locale) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return locale.toLanguageTag();
}
StringBuilder builder = new StringBuilder();
builder.append(locale.getLanguage());
if (locale.getCountry() != null) {
builder.append("-");
builder.append(locale.getCountry());
}
return builder.toString();
}
private WritableArray getLocaleList() {
WritableArray array = Arguments.createArray();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//擷取區域設定清單。這是擷取區域的首選方法。
LocaleList locales = getReactApplicationContext()
.getResources().getConfiguration().getLocales();
for (int i = ; i < locales.size(); i++) {
array.pushString(this.toLanguageTag(locales.get(i)));
}
} else {
array.pushString(this.toLanguageTag(getReactApplicationContext()
.getResources().getConfiguration().locale));
}
return array;
}
//js端可擷取屬性的清單
@Override
public Map<String, Object> getConstants() {
HashMap<String, Object> constants = new HashMap<String,Object>();
constants.put("languages", this.getLocaleList());
return constants;
}
//提供給js端調用的方法,用來擷取預設的語言環境,回調方式用的是promise
@ReactMethod
public void getLanguages(Promise promise) {
try {
promise.resolve(this.getLocaleList());
} catch (Exception e) {
promise.reject(e);
}
}
}
加一個toast看下locale會出現什麼
效果如下:
本想一探究竟内部的實作,結果是個不公開的類
總結:
首先Native那裡擷取本手機的LocaleList然後格式化取第一個元素交由I18n.js處理,然後I18n.js根據key選用一套有效的語言規則,再之後流程就和使用時候的順序一樣了。
整個庫內建難度較低,使用起來比較簡便,使用下來沒碰到大坑,配合redux更美味。
demo項目會在完成第一版功能後開源,是以暫時還沒有将該項目源碼放出,敬請期待
有問題可以微信聯系,當然得注明來意,不添加備注不會通過,謝謝(私人微信 非誠勿擾)
以後會同步微信釋出,掃麥麥的碼可以關注