flutter_demo github地址

    初始化一个项目 locale_demo

    VSCode 安装 flutter Intl 插件

    pubspec.yaml 添加如下依赖

    1. dependencies:
    2. flutter:
    3. sdk: flutter
    4. # 添加如下
    5. flutter_localizations:
    6. sdk: flutter
    7. # ...

    国际化初始化
    ⌘ + ⇧ + P

    > Flutter Intl: Initialize

    项目 lib 目录会自动生成 generatedl10n 目录
    默认语言文本 en 自动添加

    本文额外添加一个语言两种版本,简体中文和繁体中文
    > Flutter Intl: Add locale

    键入 zh_CN

    重复上述操作 键入 zh_TW

    l10n 目录生成 intl_zh_CN.arbintl_zh_TW.arb 文件

    |-lib |-generated |-intl -messages_all.dart -messages_en.dart -messages_zh_CN.dart -messages_zh_TW.dart -l10n.dart |-l10n -intl_en.arb -intl_zh_CN.arb -intl_zh_TW.arb

    main 文件中

    1. // 引入
    2. import 'package:flutter_localizations/flutter_localizations.dart';
    3. import 'generated/l10n.dart';
    4. // ...
    5. return MaterialApp(
    6. localizationsDelegates: [
    7. S.delegate,
    8. GlobalMaterialLocalizations.delegate,
    9. GlobalWidgetsLocalizations.delegate,
    10. GlobalCupertinoLocalizations.delegate,
    11. ],
    12. supportedLocales: S.delegate.supportedLocales,
    13. // ...
    14. );

    修改生成的 arb 文件
    intl_en.arb 文件中配置如下

    1. {
    2. "general_appbar_title": "General",
    3. "general_darkmode": "Dark Mode",
    4. "general_language": "Language",
    5. "general_textsize": "Text Size",
    6. "general_background": "Background",
    7. "general_sticker": "My Stickers",
    8. "general_sourcenet": "Photos, Videos, Files & Calls",
    9. "general_speaker": "Turn Off Speaker",
    10. "general_discover": "Manage Discover",
    11. "general_tool": "WeChat Tools",
    12. "general_backup": "Backup & Migrate Chats",
    13. "general_storage": "Storage",
    14. "general_clear": "Clear Chat History"
    15. }

    intl_zh_CN.arb

    1. {
    2. "general_appbar_title": "通用",
    3. "general_darkmode": "深色模式",
    4. "general_language": "多语言",
    5. "general_textsize": "字体大小",
    6. "general_background": "聊天背景",
    7. "general_sticker": "我的表情",
    8. "general_sourcenet": "照片、视频、文件和通话",
    9. "general_speaker": "听筒模式",
    10. "general_discover": "发现页管理",
    11. "general_tool": "辅助功能",
    12. "general_backup": "聊天记录备份与迁移",
    13. "general_storage": "存储空间",
    14. "general_clear": "清空聊天记录"
    15. }

    intl_zh_TW.arb

    1. {
    2. "general_appbar_title": "一般",
    3. "general_darkmode": "深色模式",
    4. "general_language": "語言",
    5. "general_textsize": "字型大小",
    6. "general_background": "聊天背景",
    7. "general_sticker": "我的貼圖",
    8. "general_sourcenet": "相片、影片和檔案",
    9. "general_speaker": "聽筒模式",
    10. "general_discover": "發現頁管理",
    11. "general_tool": "協助工具",
    12. "general_backup": "聊天巨鹿備份與轉移",
    13. "general_storage": "存儲空間",
    14. "general_clear": "刪除對話記錄"
    15. }

    lib目录下新建 pages 目录
    新建两个文件 general.dartlanguage.dart

    general.dart

    1. import 'package:flutter/material.dart';
    2. import 'package:locale_demo/generated/l10n.dart';
    3. class _ListTile extends StatelessWidget {
    4. final Widget title;
    5. final onTap;
    6. _ListTile({Key key, this.title, this.onTap}) : super(key: key);
    7. @override
    8. Widget build(BuildContext context) {
    9. return Container(
    10. color: Colors.white,
    11. child: ListTile(
    12. title: title,
    13. onTap: onTap,
    14. ),
    15. );
    16. }
    17. }
    18. class GeneralPage extends StatelessWidget {
    19. GeneralPage(BuildContext context);
    20. @override
    21. Widget build(BuildContext context) {
    22. return Scaffold(
    23. backgroundColor: Color(0xffedeced),
    24. appBar: AppBar(
    25. title: Text(S.of(context).general_appbar_title),
    26. ),
    27. body: SingleChildScrollView(
    28. child: Column(
    29. children: <Widget>[
    30. _ListTile(
    31. title: Text(S.of(context).general_darkmode),
    32. ),
    33. SizedBox(
    34. height: 10,
    35. ),
    36. _ListTile(
    37. title: Text(S.of(context).general_language),
    38. onTap: () {
    39. Navigator.pushNamed(context, '/language');
    40. },
    41. ),
    42. SizedBox(
    43. height: 10,
    44. ),
    45. _ListTile(
    46. title: Text(S.of(context).general_textsize),
    47. onTap: () {},
    48. ),
    49. _ListTile(
    50. title: Text(S.of(context).general_background),
    51. onTap: () {},
    52. ),
    53. _ListTile(
    54. title: Text(S.of(context).general_sticker),
    55. onTap: () {},
    56. ),
    57. _ListTile(
    58. title: Text(S.of(context).general_sourcenet),
    59. onTap: () {},
    60. ),
    61. SizedBox(
    62. height: 10,
    63. ),
    64. _ListTile(
    65. title: Text(S.of(context).general_speaker),
    66. onTap: () {},
    67. ),
    68. SizedBox(
    69. height: 10,
    70. ),
    71. _ListTile(
    72. title: Text(S.of(context).general_discover),
    73. onTap: () {},
    74. ),
    75. _ListTile(
    76. title: Text(S.of(context).general_tool),
    77. onTap: () {},
    78. ),
    79. SizedBox(
    80. height: 10,
    81. ),
    82. _ListTile(
    83. title: Text(S.of(context).general_backup),
    84. onTap: () {},
    85. ),
    86. _ListTile(
    87. title: Text(S.of(context).general_storage),
    88. onTap: () {},
    89. ),
    90. SizedBox(
    91. height: 10,
    92. ),
    93. _ListTile(
    94. title: Text(S.of(context).general_clear),
    95. onTap: () {},
    96. ),
    97. SizedBox(
    98. height: 40,
    99. ),
    100. ],
    101. ),
    102. ),
    103. );
    104. }
    105. }

    language.dart

    1. import 'package:flutter/material.dart';
    2. import 'package:locale_demo/generated/l10n.dart';
    3. class LanguageRadio extends StatefulWidget {
    4. @override
    5. _LanguageRadioState createState() => _LanguageRadioState();
    6. }
    7. class _LanguageRadioState extends State<LanguageRadio> {
    8. static const localeList = ['en', 'zh_CN', 'zh_TW'];
    9. int _localeIndex = 0;
    10. static String getLocaleName(index) {
    11. return ['English', '简体中文', '繁體中文'][index];
    12. }
    13. @override
    14. Widget build(BuildContext context) {
    15. return Container(
    16. child: Column(
    17. children: <Widget>[
    18. ListView.builder(
    19. itemCount: localeList.length,
    20. shrinkWrap: true,
    21. itemBuilder: (context, index) {
    22. return RadioListTile(
    23. value: index,
    24. groupValue: _localeIndex,
    25. title: Text(getLocaleName(index)),
    26. onChanged: (index) {
    27. print(index);
    28. setState(() {
    29. _localeIndex = index;
    30. });
    31. var value = localeList[index].split('_');
    32. S.load(Locale(value[0], value.length == 2 ? value[1] : ''));
    33. },
    34. );
    35. },
    36. ),
    37. SizedBox(
    38. height: 20,
    39. ),
    40. Text(S.of(context).general_language),
    41. ],
    42. ),
    43. );
    44. }
    45. }
    46. class LanguagePage extends StatelessWidget {
    47. LanguagePage(BuildContext context);
    48. @override
    49. Widget build(BuildContext context) {
    50. return Scaffold(
    51. appBar: AppBar(
    52. title: Text(S.of(context).general_language),
    53. ),
    54. body: LanguageRadio(),
    55. );
    56. }
    57. }

    至此,当我们点击了其他语言后,选项下的文字已经实时修改了,点击VSCode的 Restart ,会发现项目全局语言切换了,但是这种方式只能实时修改当前作用域下的Text,而无法实时修改全局的。

    接下来我们将使用 Provider 来管理国际化状态,做到实时修改

    pubspec.yaml 的依赖中添加如下

    1. dependencies:
    2. # ...
    3. provider: ^4.3.3

    provider

    ChangeNotifier
    ChangeNotifierProvider
    Provider

    lib 目录下,新建一个 model 目录
    model 目录下新建一个 locale.dart 文件,将 language.dart 中使用的变量放进 model 中,以共享全局

    1. import 'package:flutter/material.dart';
    2. class LocaleModel extends ChangeNotifier {
    3. int _localeIndex;
    4. int get localeIndex => _localeIndex;
    5. LocaleModel() {
    6. _localeIndex = 0;
    7. }
    8. static const localeList = ['en', 'zh_CN', 'zh_TW'];
    9. static String getLocaleName(index) {
    10. return ['English', '简体中文', '繁體中文'][index];
    11. }
    12. Locale get locale {
    13. var value = localeList[_localeIndex].split('_');
    14. return Locale(value[0], value.length == 2 ? value[1] : '');
    15. }
    16. void switchLocale(index) {
    17. _localeIndex = index;
    18. notifyListeners();
    19. }
    20. }

    main.dart

    1. class App extends StatelessWidget {
    2. @override
    3. Widget build(BuildContext context) {
    4. return ChangeNotifierProvider(
    5. create: (_) => LocaleModel(),
    6. child: Consumer<LocaleModel>(
    7. builder: (context, localeModel, child) {
    8. return MaterialApp(
    9. localizationsDelegates: [
    10. S.delegate,
    11. GlobalMaterialLocalizations.delegate,
    12. GlobalWidgetsLocalizations.delegate,
    13. GlobalCupertinoLocalizations.delegate,
    14. ],
    15. supportedLocales: S.delegate.supportedLocales,
    16. locale: localeModel.locale,
    17. // ...
    18. );
    19. }
    20. ),
    21. );
    22. }
    23. }

    language.dart
    不再需要 StateFulWidget ,直接通过 LocaleModel 获取

    1. class LanguageRadio extends StatelessWidget {
    2. @override
    3. Widget build(BuildContext context) {
    4. return Container(
    5. child: Column(
    6. children: <Widget>[
    7. ListView.builder(
    8. shrinkWrap: true,
    9. itemCount: LocaleModel.localeList.length,
    10. itemBuilder: (context, index) {
    11. var model = Provider.of<LocaleModel>(context);
    12. return RadioListTile(
    13. value: index,
    14. groupValue: model.localeIndex,
    15. title: Text(S.of(context).getLocaleName(index)),
    16. onChanged: (index) {
    17. model.switchLocale(index);
    18. },
    19. );
    20. },
    21. ),
    22. ],
    23. );
    24. );
    25. }
    26. }