当前位置: 首页 > news >正文

Flutter 国际化与本地化实战指南

Flutter 国际化与本地化实战指南

一、国际化概述

国际化(Internationalization,简称i18n)是指应用程序能够支持多种语言和地区的能力。本地化(Localization,简称l10n)则是为特定地区或语言调整应用程序的过程。

Flutter 提供了完整的国际化支持,主要通过以下包实现:

  • flutter_localizations- 官方本地化支持
  • intl- 国际化工具库

二、配置国际化环境

2.1 添加依赖

dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter intl: ^0.18.1 dev_dependencies: flutter_test: sdk: flutter

2.2 配置 MaterialApp

import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:intl/intl.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter i18n Demo', localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [ Locale('en', 'US'), // 英语 Locale('zh', 'CN'), // 中文简体 Locale('ja', 'JP'), // 日语 Locale('ko', 'KR'), // 韩语 ], home: const HomePage(), ); } }

三、创建国际化资源文件

3.1 创建 arb 文件

创建lib/l10n目录,并添加以下文件:

app_en.arb- 英语资源

{ "@@locale": "en", "helloWorld": "Hello World", "welcome": "Welcome to our app", "greeting": "Hello {name}", "counter": "{count, plural, =0{No items} =1{One item} other{{count} items}}", "date": "{date, date, short}", "time": "{time, time, short}" }

app_zh.arb- 中文资源

{ "@@locale": "zh", "helloWorld": "你好世界", "welcome": "欢迎使用我们的应用", "greeting": "你好 {name}", "counter": "{count, plural, =0{没有项目} =1{一个项目} other{{count} 个项目}}", "date": "{date, date, short}", "time": "{time, time, short}" }

app_ja.arb- 日语资源

{ "@@locale": "ja", "helloWorld": "こんにちは世界", "welcome": "アプリへようこそ", "greeting": "こんにちは {name}", "counter": "{count, plural, =0{項目なし} =1{1つの項目} other{{count} 項目}}", "date": "{date, date, short}", "time": "{time, time, short}" }

3.2 配置 pubspec.yaml

flutter: generate: true assets: - lib/l10n/

3.3 生成代码

运行以下命令生成国际化代码:

flutter pub get flutter pub run intl_utils:generate

四、使用国际化字符串

4.1 基础用法

import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; return Scaffold( appBar: AppBar(title: Text(l10n.helloWorld)), body: Center( child: Column( children: [ Text(l10n.welcome), Text(l10n.greeting(name: 'John')), ], ), ), ); } }

4.2 复数处理

Text(l10n.counter(count: 0)); // 没有项目 Text(l10n.counter(count: 1)); // 一个项目 Text(l10n.counter(count: 5)); // 5 个项目

4.3 日期和时间格式化

Text(l10n.date(date: DateTime.now())); Text(l10n.time(time: DateTime.now()));

五、动态切换语言

5.1 创建语言状态管理

class LocaleProvider extends ChangeNotifier { Locale _locale = const Locale('en'); Locale get locale => _locale; void setLocale(Locale locale) { _locale = locale; notifyListeners(); } }

5.2 使用 Provider

void main() { runApp( ChangeNotifierProvider( create: (context) => LocaleProvider(), child: const MyApp(), ), ); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return Consumer<LocaleProvider>( builder: (context, provider, child) { return MaterialApp( locale: provider.locale, localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [ Locale('en', 'US'), Locale('zh', 'CN'), Locale('ja', 'JP'), ], home: const HomePage(), ); }, ); } }

5.3 创建语言选择器

class LanguageSelector extends StatelessWidget { const LanguageSelector({super.key}); @override Widget build(BuildContext context) { final provider = Provider.of<LocaleProvider>(context); return DropdownButton<Locale>( value: provider.locale, items: const [ DropdownMenuItem(value: Locale('en', 'US'), child: Text('English')), DropdownMenuItem(value: Locale('zh', 'CN'), child: Text('中文')), DropdownMenuItem(value: Locale('ja', 'JP'), child: Text('日本語')), ], onChanged: (locale) { if (locale != null) { provider.setLocale(locale); } }, ); } }

六、处理 RTL 语言

6.1 配置 RTL 支持

MaterialApp( ... supportedLocales: const [ Locale('ar', 'SA'), // 阿拉伯语 Locale('he', 'IL'), // 希伯来语 ], );

6.2 使用 Directionality Widget

Directionality( textDirection: TextDirection.rtl, child: Text('مرحبا بالعالم'), // 阿拉伯语 );

6.3 自适应布局

Row( textDirection: Directionality.of(context), children: [ Text(l10n.name), Text(l10n.value), ], );

七、日期时间格式化

7.1 基础格式化

import 'package:intl/intl.dart'; final now = DateTime.now(); // 格式化日期 print(DateFormat.yMd().format(now)); // 12/31/2023 print(DateFormat('yyyy-MM-dd').format(now)); // 2023-12-31 // 格式化时间 print(DateFormat.jm().format(now)); // 11:59 PM print(DateFormat.Hms().format(now)); // 23:59:59 // 完整日期时间 print(DateFormat.yMMMd().format(now)); // Dec 31, 2023 print(DateFormat.yMMMEd().format(now)); // Sun, Dec 31, 2023

7.2 本地化日期时间

// 根据当前语言环境格式化 print(DateFormat.yMd(Localizations.localeOf(context).languageCode).format(now));

八、数字格式化

8.1 基础用法

import 'package:intl/intl.dart'; final number = 1234567.89; print(NumberFormat().format(number)); // 1,234,567.89 print(NumberFormat.currency().format(number)); // $1,234,567.89 print(NumberFormat.percent().format(0.75)); // 75%

8.2 本地化数字

final format = NumberFormat.decimalPattern(Localizations.localeOf(context).languageCode); print(format.format(number));

九、复数规则

9.1 基础复数

{ "items": "{count, plural, =0{no items} =1{one item} other{{count} items}}" }

9.2 复杂复数规则

{ "apples": "{count, plural, zero{no apples} one{one apple} two{two apples} few{few apples} many{many apples} other{{count} apples}}" }

十、处理地区差异

10.1 地区特定格式

// 美国格式 print(DateFormat.yMd('en_US').format(now)); // 12/31/2023 // 欧洲格式 print(DateFormat.yMd('de_DE').format(now)); // 31.12.2023 // 中国格式 print(DateFormat.yMd('zh_CN').format(now)); // 2023/12/31

10.2 货币格式

// 美元 print(NumberFormat.currency(locale: 'en_US').format(100)); // $100.00 // 欧元 print(NumberFormat.currency(locale: 'de_DE').format(100)); // 100,00 € // 人民币 print(NumberFormat.currency(locale: 'zh_CN', symbol: '¥').format(100)); // ¥100.00

十一、测试国际化

11.1 单元测试

test('English localization', () { final l10n = AppLocalizationsEn(); expect(l10n.helloWorld, 'Hello World'); expect(l10n.greeting(name: 'Test'), 'Hello Test'); }); test('Chinese localization', () { final l10n = AppLocalizationsZh(); expect(l10n.helloWorld, '你好世界'); expect(l10n.greeting(name: '测试'), '你好 测试'); });

11.2 Widget 测试

testWidgets('Localized text displays correctly', (tester) async { await tester.pumpWidget( MaterialApp( locale: const Locale('zh'), localizationsDelegates: const [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], home: const HomePage(), ), ); expect(find.text('你好世界'), findsOneWidget); });

十二、最佳实践

12.1 组织翻译文件

lib/ ├── l10n/ │ ├── app_en.arb │ ├── app_zh.arb │ ├── app_ja.arb │ └── app_ko.arb ├── main.dart └── ...

12.2 使用一致的命名规范

{ "homeTitle": "首页", "homeSubtitle": "欢迎回来", "btnSubmit": "提交", "btnCancel": "取消", "errorNetwork": "网络错误", "successSave": "保存成功" }

12.3 避免硬编码字符串

// 错误 Text('Hello World'); // 正确 Text(l10n.helloWorld);

12.4 使用翻译管理工具

  • Lokalise- 专业翻译管理平台
  • Transifex- 开源翻译管理
  • Crowdin- 企业级翻译管理

十三、实战案例:多语言应用

class InternationalizedApp extends StatelessWidget { const InternationalizedApp({super.key}); @override Widget build(BuildContext context) { return Consumer<LocaleProvider>( builder: (context, provider, child) { return MaterialApp( locale: provider.locale, localizationsDelegates: const [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], supportedLocales: const [ Locale('en', 'US'), Locale('zh', 'CN'), Locale('ja', 'JP'), Locale('ko', 'KR'), ], home: const HomePage(), ); }, ); } } class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; return Scaffold( appBar: AppBar( title: Text(l10n.homeTitle), actions: const [LanguageSelector()], ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(l10n.welcome), const SizedBox(height: 20), Text(l10n.greeting(name: '用户')), const SizedBox(height: 20), Text(l10n.counter(count: 5)), const SizedBox(height: 20), Text(l10n.date(date: DateTime.now())), ], ), ), ); } }

十四、总结

Flutter 国际化涉及多个方面:

  1. 配置环境- 添加依赖和配置 MaterialApp
  2. 创建资源文件- 使用 ARB 格式管理翻译
  3. 生成代码- 使用 intl 工具生成本地化类
  4. 使用翻译- 在 Widget 中引用本地化字符串
  5. 动态切换- 实现语言切换功能
  6. RTL 支持- 处理从右到左的语言
  7. 格式化- 日期、时间、数字的本地化格式化

通过合理的国际化设计,可以让应用程序更好地服务于全球用户。

http://www.jsqmd.com/news/894644/

相关文章:

  • 从修改器到Mod开发:如何利用dnSpy和Unity调试功能快速定位游戏核心逻辑
  • 构建FPI评级系统:多因子模型与自然语言生成在投资决策中的应用
  • 2026年热门的三亚中巴车出租/三亚会议车出租/三亚旅游车出租高评分公司推荐 - 行业平台推荐
  • 2026年4月大连味之母口碑好吗,大连味之母,大连味之母好不好 - 品牌推荐师
  • 基于AI的邮件HTML兼容性自动修复工具开发实践
  • ARM指令集解析:STC与STL指令深度剖析
  • AI智能体在电商中的角色探索:从“人找货”到“货找人”的交互新范式
  • AI生成代码中的CORS安全漏洞:从原理到修复的完整指南
  • 别再让SkinnedMeshRenderer拖垮你的游戏!Unity骨骼动画性能优化实战(BakeMesh + 动态合批)
  • 2026年知名的家具批发/酒店家具批发本地公司推荐 - 品牌宣传支持者
  • 构建会“说话”的智能体:从工具调用到记忆系统的工程实践
  • 从多仓库到pnpm workspace:前端Monorepo实战迁移与效率提升
  • CEO年度战略复盘:从数据叙事到战略聚焦的沟通艺术
  • 2026年热门的海口美兰机场租车/海口包年租车/海口租中巴租车/海口东站租车品牌公司推荐 - 行业平台推荐
  • STM32H743模拟SMBUS读取BQ40Z50电量,我踩过的三个坑(附完整代码与示波器波形)
  • AutoHotKey V2定时器(SetTimer)深度使用指南:从防抖连击到后台轮询,5个案例搞定
  • 大型语言模型压缩技术:SVD与DipSVD实践指南
  • Soul in Motion:用身体运动探索内在状态的身心实践框架
  • 别再手动调参了!用Python的sklearn一键找出最佳F1分数阈值(附完整代码)
  • Web应用API安全审计:从身份验证到输入验证的系统性加固实践
  • 从代码实现到系统设计:AI时代开发者的核心技能重构
  • taotoken的api密钥管理与审计日志如何满足企业安全合规需求
  • 告别重复登录!用Playwright连接已打开的Chrome浏览器,保留你的会话和Cookie
  • 别再让远处的模型糊成一片了!Unity/UE4中Mipmap的正确打开方式与性能调优
  • Unity UGUI ScrollRect 实现多级折叠菜单:一个ContentSizeFitter的奇葩刷新问题与解决方案
  • 非开发者如何排查Rust项目崩溃:从panic信息到问题定位
  • AI智能体在股票图表分析中的三种核心设计模式与实践
  • DipSVD:双层级重要性保护的LLM模型压缩技术
  • Claude Mythos事件:AI自动化漏洞挖掘如何重塑安全攻防格局
  • 终端AI编码助手深度对比:Claude Code与Codex CLI实战评测