Flutter配置国际化,多语言步骤优化
请先参考国际化 · 《Flutter实战》中的intl章节完成国际化配置至能够使用
其中intl.sh
文件的部分注释
# lib/i10n/localization_intl.dart 要进行翻译的(其中包含有Intl相关方法)文件
# i10n-arb/intl_*.arb 转换后的.arb文件 2
# i10n-arb 存放1转换后的相应.arb文件的目录 3
# lib/i10n 存放2再转换成相应dart文件的目录 4
# 转换成arb。传入3和1
flutter pub pub run intl_translation:extract_to_arb --output-dir=i10n-arb lib/i10n/localization_intl.dart
# 将arb转化成相关dart文件。传入4,1和2
flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/i10n --no-use-deferred-loading lib/i10n/localization_intl.dart i10n-arb/intl_*.arb
1. 抽离要翻译字段
- 删除掉
lib/i10n/localization_intl.dart
中以下部分
String get title {
return Intl.message(
'Flutter APP',
name: 'title',
desc: 'Title for the Demo application',
);
}
新建
lib/i10n/mixins
文件夹mixins
文件夹中新建commom.dart
文件并写入
// ignore_for_file: non_constant_identifier_names
import 'package:intl/intl.dart';
mixin Commom {
// 加上前缀方便在.arb文件中区分
String get commom_title => Intl.message(
'Flutter APP',
name: 'commom_title', // 在.arb文件中显示的字段名
desc: 'Title for the Demo application');
}
- 在
lib/i10n/localization_intl.dart
引用
// ...
import './mixins/commom.dart';
// ...
class DemoLocalizations with Common {
// ...
- 修改
intl.sh
文件- 只修改了1相应的路径
# lib/i10n/mixins/** 要进行翻译的(其中包含有Intl相关方法)文件 1
# i10n-arb/intl_*.arb 转换后的.arb文件 2
# i10n-arb 存放1转换后的相应.arb文件的目录 3
# lib/i10n 存放2再转换成相应dart文件的目录 4
# 转换成arb。传入3和1
flutter pub pub run intl_translation:extract_to_arb --output-dir=i10n-arb lib/i10n/mixins/**
# 将arb转化成相关dart文件。传入4,1和2
flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/i10n --no-use-deferred-loading lib/i10n/mixins/** i10n-arb/intl_*.arb
- 完成
2. 简化翻译步骤(需要安装Node.js)
参考使用Intl包 · 《Flutter实战》当前的翻译步骤为
-
lib/i10n/mixins/
下相关文件添加要翻译的字段 - 执行
./intl.sh
-
i10n-arb/
下相关文件进行相应的翻译 - 执行
./intl.sh
缺点
- 需要在多处相关文件进行相关改动
- 翻译时的.arb文件需要和
i10n-arb/intl_messages.arb
进行对比,并进行手动更改 - 若是修改之前的翻译字段,可能需要对部分.arb文件进行相关的手动修改
- 需要多次执行
./intl.sh
优化思路
- 原步骤中第一次执行
./intl.sh
是为了执行其中第一条命令。 - 第二次执行
./intl.sh
是为了执行其中第二条命令。 - 因此只要将对.arb文件进行相关翻译通过命令行执行即可
优化后的步骤
-
lib/i10n/mixins/
下相关文件添加要翻译的字段 - 执行
./intl.sh
如何优化
- 根目录下添加
node_intl.js
文件
const fs = require("fs");
const path = require("path");
// 要转换的语言(默认语言不填)
const localeList = ["en", "ja"];
// 获取命令行参数
const params = process.argv.splice(2);
// 判断是否为Object-JSON格式
function canParse(str) {
try {
return (
str !== "" &&
typeof str == "string" &&
Object.prototype.toString.call(JSON.parse(str)) === "[object Object]"
);
} catch (error) {
return false;
}
}
// 对文件 根据locale 进行修改
// locale = "en";
// 原来:
// "commom_tab_home": "首页",
// "@commom_tab_home": {
// "description": "{\"desc\":\"底部tab中的首页\",\"en\":\"Home\"}",
// "type": "text",
// "placeholders": {}
// },
// 修改后:
// "commom_tab_home": "Home",
// "@commom_tab_home": {
// "description": "{\"desc\":\"底部tab中的首页\",\"en\":\"Home\"}",
// "type": "text",
// "placeholders": {}
// },
function translateAccordingToLocale(fileContent) {
const newFileContentObj = {};
// 复制原文件内容,仅修改locale
localeList.forEach((locale) => {
let data = JSON.parse(fileContent);
data["@@locale"] = locale;
newFileContentObj[locale] = data;
});
// 遍历原文件内容,根据description进行相应转换
const data = JSON.parse(fileContent);
for (const key in data) {
if (data.hasOwnProperty(key) && /^@[^@]/.test(key)) {
const element = data[key]["description"];
if (canParse(element)) {
const desc = JSON.parse(element);
// 根据description进行相应转换
localeList.forEach((locale) => {
const translateToLocale = desc[locale];
translateToLocale &&
(newFileContentObj[locale][
key.replace(/^@/, "")
] = translateToLocale);
});
}
}
}
return Promise.resolve(newFileContentObj);
}
// 写入arb文件
function writeArb(fileContentObj) {
return new Promise((resolve, reject) => {
for (const locale in fileContentObj) {
if (fileContentObj.hasOwnProperty(locale)) {
fs.writeFile(
path.join(__dirname, `${params[0]}/intl_${locale}.arb`),
// 写入格式化后的文件内容
JSON.stringify(fileContentObj[locale], null, 2),
(err) => err && reject(err)
);
}
}
});
}
// 读取源arb文件
function readArb() {
return new Promise((resolve, reject) => {
if (params.length == 0) return reject("请传入相关.arb文件所在目录");
fs.readFile(
path.join(__dirname, `${params[0]}/intl_messages.arb`),
(err, data) => (err ? reject(err) : resolve(data))
);
});
}
readArb()
.then(translateAccordingToLocale)
.then(writeArb)
.catch((e) => {
console.error(`Node_Intl Error: ${e}`);
});
- 修改
./intl.sh
文件- 原来两条命令中新增一条命令
# lib/i10n/mixins/** 要进行翻译的(其中包含有Intl相关方法)文件 1
# i10n-arb/intl_*.arb 转换后的.arb文件 2
# i10n-arb 存放1转换后的相应.arb文件的目录 3
# lib/i10n 存放2再转换成相应dart文件的目录 4
# 转换成arb。传入3和1
flutter pub pub run intl_translation:extract_to_arb --output-dir=i10n-arb lib/i10n/mixins/**
# 优化翻译步骤 传入3
node node_intl.js i10n-arb
# 将arb转化成相关dart文件。传入4,1和2
flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/i10n --no-use-deferred-loading lib/i10n/mixins/** i10n-arb/intl_*.arb
- 翻译格式
-
lib/i10n/mixins/commom.dart
中 -
desc
格式需要为Object-JSON格式
-
// ignore_for_file: non_constant_identifier_names
import 'package:intl/intl.dart';
mixin Commom {
// 加上前缀方便在.arb文件中区分
String get commom_title => Intl.message(
'Flutter APP',
name: 'commom_title', // 在.arb文件中显示的字段名
desc: '{"desc":"Title for the Demo application","en":"英文翻译在这","ja":"日语翻译在这"}');
}
- 完成