背景
部门开会让把国际化项目内支持的所有语种翻译整理成 Excel,于是我整理了这篇文章,通过脚本遍历工程目录,整合各模块内 arb文件,生成 Excel 表格。
引言
先简单介绍一下,flutter 框架本身支持国际化,添加依赖 flutter_localizations
和 flutter_intl
,运行命令行 flutter intl generate
,
lib 文件夹内会生成两个文件夹 generated 和 l10n,l10n 内存放各国的文本翻译资源即 .arb 文件,每个 .arb文件
都是一个JSON结构。
如上示例,小编项目内 l10n 内存放的三种文本翻译资源,英文、中文简体、中文繁体。以 intl_zh_CN.arb 为例,数据结构是这样的:
代码实现
好啦,回归正题,本篇主旨是分享如何通过脚本,指定项目,从各个模块中提取所有的翻译文本,按语种分类,一一匹配,然后整合导出Excel文件。
直接上代码:(copy可直接使用)
import 'dart:io';
import 'dart:convert';
import 'package:path/path.dart' as path;
import 'package:excel/excel.dart';
void main() {
const arbFileSuffix = 'arb'; // .arb 文件的后缀
const intlDirFiled = 'l10n'; // 需要命中的 intl 文件夹
final excel = Excel.createExcel();
// 待遍历的根目录
const rootDirPath = '/Users/rex/Downloads/project';
final rootDir = Directory(rootDirPath);
// 遍历目录,找到 intl 文件夹
FileSystemEntity? traverForIntl(
Directory directory,
) {
final childrenDirs = directory.listSync();
for (var childDir in childrenDirs) {
if (childDir is Directory) {
final dirName = path.basename(childDir.path);
if (dirName == intlDirFiled) {
return childDir;
} else {
final result = traverForIntl(childDir);
if (result == null) {
continue;
} else {
return result;
}
}
}
}
return null;
}
rootDir.listSync().forEach((moduleDirs) {
// 遍历模块目录,记录模块名称,用于 excel 的 sheet 名称
final moduleName = path.basename(moduleDirs.path);
if (moduleDirs is Directory) {
final intlDir = traverForIntl(moduleDirs);
if (intlDir != null && intlDir is Directory) {
final arbFiles = intlDir
.listSync()
.where((element) => element.path.endsWith(arbFileSuffix));
// 获取 arb 文件名称,例如 : intl_en_US、intl_zh_CN、用于 sheet 中 头部信息
Map<String, Map<String, dynamic>> arbContentMap = {};
for (var arbFile in arbFiles) {
final arbName = path.basename(arbFile.path).replaceAll('.arb', '');
final arbContent = (arbFile as File).readAsStringSync();
final arbMap = jsonDecode(arbContent) as Map<String, dynamic>;
arbContentMap.putIfAbsent(arbName, () => arbMap);
}
// 按 map 长度倒序排序
final abc = arbContentMap.entries.toList();
abc.sort((a, b) => b.value.length.compareTo(a.value.length));
Map<String, Map<String, dynamic>> resortArbMaps = Map.fromEntries(abc);
if (resortArbMaps.isNotEmpty) {
Sheet sheetObject = excel[moduleName];
// 每个头部信息 (标明语言类型)
final header = [TextCellValue('arb_key')];
header
.addAll(resortArbMaps.keys.map((e) => TextCellValue(e)).toList());
sheetObject.appendRow(header);
List mapKeys = resortArbMaps.values.first.keys.toList();
// 由于我们使用 appendRow 方法,所以遍历行数
for (var index = 0; index < mapKeys.length; index++) {
final itemKey = mapKeys[index];
final cellValues = [TextCellValue(itemKey)];
cellValues.addAll(
resortArbMaps.values
.map((e) => TextCellValue(e[itemKey] ?? ''))
.toList(),
);
sheetObject.appendRow(cellValues);
}
}
}
}
});
final fileBytes = excel.save();
File('/Users/rex/Downloads/arb翻译整理.xlsx')
..createSync(recursive: true)
..writeAsBytesSync(
fileBytes!,
mode: FileMode.write,
);
print('excel 文件生成成功');
}
PS:上述脚本需要添加三方库依赖
dependencies:
flutter:
sdk: flutter
excel: ^4.0.0
如上示例中指定的目录为 /Users/rex/Downloads/project
:
指定项目路径内有5个模块,每个模块中包含3个语言资源,点击运行脚本,导出 Excel 表格结构如下:
Excel表格导出成功,5个模块对应5个Sheet,以语种为列,arbKey为索引。