LocalSend多语言国际化方案
概述
LocalSend作为一款开源跨平台文件传输应用,支持53种语言,覆盖全球主要语言区域。其国际化方案基于Weblate协作平台、Slang代码生成工具和Flutter国际化框架,构建了一套完整的翻译协作、资源管理和动态切换体系。
Weblate平台翻译协作流程
平台集成架构
LocalSend采用Weblate作为官方翻译协作平台,通过自动化同步机制实现代码库与翻译平台的实时数据交换。
翻译工作流详解
1. 初始设置
- 项目地址:
https://hosted.weblate.org/projects/localsend/app - 支持语言:53种,包含中文简繁、日语、韩语等亚洲语言
- 翻译字符串:16,908个(平均每种语言319个)
2. 协作机制
// 翻译文件结构示例
app/assets/i18n/
├── en.json // 英语基准文件
├── zh-CN.json // 简体中文
├── zh-TW.json // 繁体中文
├── ja.json // 日语
├── _missing_translations_zh_CN.json // 缺失翻译
└── _unused_translations.json // 未使用翻译
3. 自动化同步
# GitHub Actions配置示例
name: Sync with Weblate
on:
push:
paths:
- 'app/assets/i18n/**'
jobs:
sync-translations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Update translations
run: |
# 从Weblate拉取最新翻译
# 生成Dart代码
dart run slang
多语言资源文件组织结构
文件层级设计
LocalSend采用JSON格式存储翻译资源,结构清晰且易于维护:
{
"locale": "English",
"appName": "LocalSend",
"general": {
"accept": "Accept",
"cancel": "Cancel",
"error": "Error"
},
"receiveTab": {
"title": "Receive",
"infoBox": {
"ip": "IP:",
"port": "Port:"
}
}
}
特殊标记说明
项目中使用了特殊的@标记来提供翻译上下文:
| 标记类型 | 用途 | 示例 |
|---|---|---|
@info | 提供翻译说明 | "@info": "Different locales may have different words" |
@combination | 组合规则说明 | "@combination": "In some languages, the adjective must be last." |
@: | 引用其他键 | "off": "@:general.off" |
复数处理机制
// 复数解析器配置
await LocaleSettings.setPluralResolver(
locale: locale,
cardinalResolver: (n, {zero, one, two, few, many, other}) {
if (n == 0) return zero ?? other ?? n.toString();
if (n == 1) return one ?? other ?? n.toString();
return other ?? n.toString();
}
);
动态语言切换实现机制
核心架构设计
LocalSend使用slang包实现国际化,支持运行时语言切换和延迟加载:
代码生成流程
1. 生成入口文件
// strings.g.dart - 自动生成的主文件
import 'strings_ar.g.dart' deferred as l_ar;
import 'strings_zh_CN.g.dart' deferred as l_zh_CN;
// ... 其他53种语言
enum AppLocale {
en(languageCode: 'en'),
zhCn(languageCode: 'zh', countryCode: 'CN'),
ja(languageCode: 'ja')
// ... 其他语言
}
2. 延迟加载机制
// 语言文件按需加载
await l_zh_CN.loadLibrary();
return l_zh_CN.TranslationsZhCn();
运行时切换实现
1. 语言设置存储
// 持久化存储语言设置
final persistedLocale = await _preferences.getString(_localeKey);
if (persistedLocale != null) {
await LocaleSettings.setLocaleRaw(persistedLocale);
} else {
await LocaleSettings.useDeviceLocale();
}
2. 界面更新机制
// 语言切换响应式更新
context.ref.watch(settingsProvider.select((s) => s.locale));
3. 动态字体适配
// 根据语言切换字体
fontFamily = switch (LocaleSettings.currentLocale) {
AppLocale.zhCn => 'NotoSansSC',
AppLocale.ja => 'NotoSansJP',
_ => null
};
社区翻译贡献指南
参与方式选择
方式一:Weblate平台(推荐)
- 访问
https://hosted.weblate.org/engage/localsend/ - 注册账号并选择目标语言
- 开始翻译,系统会自动保存进度
方式二:手动提交PR
- Fork项目仓库
- 编辑对应的翻译文件
- 提交Pull Request
翻译规范要求
1. 文件命名规范
语言代码规则:
- 简体中文: zh-CN.json
- 繁体中文: zh-TW.json
- 英语: en.json
- 日语: ja.json
2. 特殊字符处理
{
"fileNameInput": {
"original": "Original: {original}"
},
"progressPage": {
"speed": "Speed: {speed}/s"
}
}
3. 禁止翻译标记
- 所有以
@开头的字段(如@info,@combination)不翻译 - 技术术语和品牌名称保持原样
- 变量占位符(如
{n},{size})保持不变
质量保证措施
1. 翻译审查流程
2. 自动化验证
- JSON格式校验
- 变量占位符一致性检查
- 特殊标记完整性验证
3. 缺失翻译处理
# 生成缺失翻译报告
dart run slang --report-missing
常见问题解决
1. 翻译更新后不生效
# 重新生成翻译代码
dart run slang
flutter pub get
2. 新增语言支持
- 在Weblate平台申请新语言
- 或在代码库中创建对应的JSON文件
- 更新
AppLocale枚举和生成配置
3. 翻译上下文理解 对于复杂字符串,查看附近的@info标记获取上下文信息,确保翻译准确传达原意。
最佳实践总结
性能优化策略
- 延迟加载: 非当前语言资源不加载到内存
- 按需生成: 只在构建时生成必要的Dart代码
- 缓存机制: 已加载的语言资源进行缓存
维护性建议
- 定期同步: 保持Weblate与代码库的定期同步
- 版本控制: 翻译文件与代码版本协同更新
- 文档更新: 及时更新翻译指南和规范
扩展性考虑
当前架构支持轻松添加新语言,只需:
- 在Weblate平台配置新语言
- 或手动创建对应的JSON文件
- 运行生成命令即可集成
LocalSend的多语言国际化方案通过Weblate协作平台、自动化工具链和良好的架构设计,为全球用户提供了一致且高质量的多语言体验,同时降低了社区翻译贡献的门槛。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



