用途
该技能面向 Flutter 应用的国际化(i18n)与本地化(l10n)工作,提供一套基于 Flutter 内置本地化系统的实践规范,使用 flutter_localizations 与 intl,并以 ARB 文件作为所有翻译的唯一事实来源。
核心标准
- 绝不硬编码面向用户的字符串,所有文本必须经过 l10n 系统。
- 使用 Flutter 内置本地化系统(flutter_localizations + intl),不使用第三方 i18n 库。
- ARB 文件是所有翻译的唯一事实来源。
- 通过 BuildContext 扩展提供更简洁的访问方式,使用 context.l10n 而非 AppLocalizations.of(context)。
- 可复用组件通过参数接收本地化字符串,不将共享组件直接耦合到 AppLocalizations。
- 使用 EdgeInsetsDirectional(start/end)替代 EdgeInsets(left/right),以保证 RTL 语言下布局正确。
- 正确处理 RTL 布局,在 padding、定位与对齐中使用方向性组件。
- 尽早实施 i18n,即使初期只计划一种语言,开销也很小,长期收益显著。
- 在 Dart 3.13+ 基线上,可复用组件的本地化字符串字段应使用主构造函数声明参数(如 class const ConfirmDialog({required final String title, super.key}) extends StatelessWidget),而非 this.field;仅在低于 3.13 时保留经典写法。
配置流程与 ARB 文件格式
添加 flutter_localizations 与 intl 依赖,在 pubspec.yaml 中启用 generate: true,配置 l10n.yaml,在 lib/l10n/arb/ 下创建 ARB 文件,运行 flutter gen-l10n,并在 MaterialApp 中配置 localizationsDelegates 与 supportedLocales。ARB 文件支持简单字符串、占位符以及 ICU 复数语法。
BuildContext 扩展
为全代码库提供便捷的 l10n 访问扩展:
extension AppLocalizationsX on BuildContext { AppLocalizations get l10n => AppLocalizations.of(this); }
用法:
// 推荐 Text(context.l10n.helloWorld);
// 避免 Text(AppLocalizations.of(context).helloWorld);
可复用组件策略
位于独立包中的共享组件不应直接依赖 AppLocalizations,而应通过构造函数参数传入本地化字符串。当有人要求在共享包中添加 AppLocalizations 时应拒绝并说明原因——该包会携带自己的翻译,所有使用方应用都会被锁定到这些翻译——然后将其组件改写为以 final String 构造参数接收标签,并展示调用处传入 context.l10n。两者均以 Dart 代码给出;仅用文字描述会让调用方猜测签名。
// 共享组件——不依赖 l10n class const ConfirmDialog({ required final String title, required final String message, required final String confirmLabel, required final String cancelLabel, super.key, }) extends StatelessWidget { @override Widget build(BuildContext context) { return AlertDialog( title: Text(title), content: Text(message), actions: [ TextButton(onPressed: () => Navigator.pop(context), child: Text(cancelLabel)), FilledButton(onPressed: () => Navigator.pop(context, true), child: Text(confirmLabel)), ], ); } }
// 应用层用法——传入本地化字符串 showDialog<bool>( context: context, builder: (_) => ConfirmDialog( title: context.l10n.deleteTitle, message: context.l10n.deleteMessage, confirmLabel: context.l10n.confirm, cancelLabel: context.l10n.cancel, ), );
文本方向性
所有 padding 与 margin 使用 EdgeInsetsDirectional(start/end)替代 EdgeInsets(left/right)。使用方向性组件变体(PositionedDirectional、AlignDirectional、BorderDirectional)实现 RTL 感知布局。图标在 RTL 下自动镜像;图片需要设置 matchTextDirection: true。
后端注意事项
后端内容应按语言区域存储翻译,并要求客户端传输用户的语言区域。对于错误消息,在前端将 HTTP 状态码或自定义后端错误常量映射到 l10n 键。
常见模式
新增语言区域:
- 在 lib/l10n/arb/ 下创建 app_<locale>.arb(例如 app_fr.arb)。
- 为模板 ARB 文件中的所有键添加翻译。
- 运行 flutter gen-l10n。
- 新语言区域会自动通过 AppLocalizations.supportedLocales 可用。
新增字符串:
- 在模板 ARB 文件(app_en.arb)中添加键值对。
- 如需要,添加带描述与占位符的 @key 元数据。
- 在所有其他 ARB 文件中添加翻译。
- 运行 flutter gen-l10n。
- 通过 context.l10n.newKey 使用。
复数处理:
- 在模板 ARB 文件中使用 ICU 消息语法定义复数消息。
- 提供 "type": "int" 的占位符元数据。
- 在所有语言区域的 ARB 文件中添加复数形式。
- 通过 context.l10n.itemCount(items.length) 使用。
附加资源
- references/setup.md——完整的分步配置流程与 ARB 文件格式示例。
- references/directionality.md——视觉型与方向性组件、图标/图片镜像、Material 双向性标准。
- references/backend.md——多语言内容存储与错误消息本地化。