引言
使用Flutter时,如需要开发Google Play市场的安卓应用时,国际化是一个很常见的需求。笔者最近开发的一款应用同样有这个需求。
参考官方文档基本也跑通了单文件的多语言实现。只是官方文档提供的文档目前仅支持单文件的多语言需求,如果需要拆分多个文件,如用户相关的多语言拆分到user_zh.arb中,公共文本放在common_zh.arb中,就显得捉襟见肘了。
基于以上需求,通过互联网检索,发现没有特别好的方案,因此就诞生了这篇文章。
基本实现
官方文档已经描述的比较详细了,以下就不赘述,仅提供一些关键内容,及我自己使用的配置参数。
依赖
在flutter主目录的pubspec.yaml文件中添加如下配置
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: any
#...省略一些其他配置信息
flutter:
generate: true # Add this line
l10n.yaml 配置
将l10n.yaml添加到项目根目录下。
以下为笔者使用的配置,带详细注释
arb-dir: lib/l10n #arb检索路径
template-arb-file: app_zh.arb
output-dir: lib/l10n/generated #指定生成多语言文件目录
output-localization-file: app_localizations.dart #指定生成多语言文件名
prefer-matched-file: true # 优先匹配区域设置
prevent-collisions: true # 开启键名冲突检查
synthetic-package: false # 禁用自动合成(如果需要指定output-dir,这个参数必须为false)
nullable-getter: false #false即代表AppLocalizations.of(context)获取的对象不为空
多语言文件
在./lib/l10n下新增app_zh.arb和app_en.arb文件,配置文件以json的形式呈现
{
"helloWorld": "你好 世界!"
}
{
"helloWorld": "Hello World!"
}
生成多语言localization文件
- 最简单的方式是直接run应用,生成的文件在上述配置的目录/lib/l10n/generated目录下
- 其次可以使用
flutter gen-l10n
手动生成
在应用中使用
// 导入(tasks是我应用的,你可以根据自己应用修改)
import 'package:tasks/l10n/generated/app_localizations.dart';
// ...忽略部分代码
AppLocalizations get l10n => AppLocalizations.of(context);
// ...忽略部分代码
// 在组件具体调用
// 前置配置请参考官方文档
Text(l10n.helloWorld);
进阶使用
在小型项目中,所有多语言配置可以全部放在同一个文件中完全没问题,但是如果是中大型项目,多人开发下,如果所有配置放在同一个文件,单文件冲突合并就显得有点不优雅了。
一般来说,项目会按照业务拆分出不同的模块,那么我们也可以参考这点,优化一下,实现形如
lib/
l10n/
common_en.arb # 公共词汇
common_zh.arb
home/ # 首页模块
home_en.arb
home_zh.arb
的目录结构。
以下提供两多方式供你挑选
使用命令生成不同的多语言文件
具体细节参考 这里
省流版看以下命令
flutter gen-l10n --arb-dir ./lib/l10n/home --template-arb-file home_en.arb --output-localization-file home_localizations.dart --output-class HomeLocalizations &&
flutter gen-l10n --arb-dir ./lib/l10n/settings --template-arb-file settings_en.arb --output-localization-file settings_localizations.dart --output-class SettingsLocalizations
以上实现可以解决无法生成多arb文件的问题,但是又引入新的问题,如:1、使用命令行直接生成,需要删除项目的中l10n.yaml文件,无法使用配置文件控制多语言文件
2、通过命令生成的会生成多个文件(这个不一定是缺点,看自己需求)
基于以上问题,提供以下新思路:
能不能在不修改官方实现的基础上,同时实现多模块arb?
答案是可以的!
命令行合并json文件
既然官方不支持多arb文件,那么我们直接通过命令行手动合并所有模块下的 arb 到主arb下不就行了么?
这样既可以使用官方的原配置,同时也可以支持多文件,一举两得!
下面直接放出sh代码
#!/bin/bash
# 配置参数
BASE_DIR="lib/l10n"
MODULES=("common" "home" "setting") # 需要合并的模块目录
LANGUAGES=("en" "zh") # 支持的语言
# 清理旧文件
rm -f $BASE_DIR/app_*.arb
# 按语言合并
for lang in "${LANGUAGES[@]}"; do
OUTPUT_FILE="$BASE_DIR/app_${lang}.arb"
TEMP_FILE="${OUTPUT_FILE}.tmp"
# 初始化合并文件
echo "{}" > $TEMP_FILE
# 合并模块文件
for module in "${MODULES[@]}"; do
MODULE_FILE="$BASE_DIR/$module/${module}_${lang}.arb"
if [ -f "$MODULE_FILE" ]; then
jq -s '.[0] * .[1]' $TEMP_FILE $MODULE_FILE > $TEMP_FILE.tmp
mv $TEMP_FILE.tmp $TEMP_FILE
fi
done
# 格式化输出
jq --sort-keys . $TEMP_FILE > $OUTPUT_FILE
rm $TEMP_FILE
done
echo "ARB files merged successfully!"
使用
./merge_arb.sh && flutter gen-l10n
扩展
以上虽然实现了合并json文件,并生成dart类,但是每次使用还是得执行命令,比较繁琐。
基于以上,我们可以考虑
1、基于git hook
在项目根目录下的.git/hooks目录下新增pre-commit文件,然后在文件中添加内容:
./merge_arb.sh && flutter gen-l10n
2、基于flutter的编译(这个可以自己调研下)
扩展2
多文件下可能存在多个相同的字段名,可以考虑在copy对应目录下的json内容时,对应添加上文件名的前缀,如helloWorld在home.arb文件下复制到app.arb文件中时,对应key修改为home_helloWorld。
以上为本文的全部内容,关注我了解更多关于flutter的相关内容。
作者:独立开发者‘一一’,应用出海实践者,专注独立应用开发,目前开发了一款资产管理应用“归物(ReCollect)”,正在Google Play封测中,今年独立应用完成1/3。