Flutter语言国际化,英文、中文简体和中文繁体

官方文档:docs.flutter.dev/ui/accessib...

第一步:引入库

  • 设置generate: true,项目启动时会自动生成对应的语言库,需要开启generate

pubspec.yaml

yml 复制代码
dependencies:
  # 本地化
  flutter_localizations:
    sdk: flutter
  # 国际化
  intl: ^0.18.1
# ...
flutter:
  generate: true

第二步:编辑配置文件

  • 项目根目录下创建语言配置文件,固定命名为:l10n.yaml

l10n.yaml

yaml 复制代码
# 其他配置参考官网:https://docs.flutter.dev/ui/accessibility-and-internationalization/internationalization
# arb-dir: lib/l10n # arb文件文件路径,默认 lib/l10n
template-arb-file: intl_en.arb # arb文件名的格式,默认是app_en.arb
nullable-getter: false # Localizations.of(context)的返回值不可以为空
output-localization-file: planx_localizations.dart  # 生成的文件名,默认是app_localizations.dart.
output-class: PlanxLocalizations # 类名,默认是AppLocalizations.

第三步:新建对应的arb文件

  • 在lib/l10n文件中新建需要翻译的对应的arb文件
  • 英文,葡萄牙语,中文
  • arb内容文件格式(也是json格式)
  • 如果需要接收参数使用大括号,然后在@相同字段名 内设置格式等信息,只用en里面配置就可以了

intl_en.arb

json 复制代码
{
  "home": "Home",
  "dayFormat": "{date}",
	// 注释请删掉,@dayFormat设置接收参数的类型,DateTime可以设置模版格式
  "@dayFormat": {
    "placeholders": {
      "date": {
        "type": "DateTime",
        "format": "yMd"
      }
    }
  }
}

intl_zh.arb

json 复制代码
{
  "home": "首页",
  "dayFormat": "{date}"
}

第四步:执行flutter run

  • 运行项目后,此时我们可以看到,根目录下自动生成了对应的语言类

第五步:在MaterialApp中配置语言

main.dart

dart 复制代码
// 引入生成的国际化文件
import 'package:flutter_gen/gen_l10n/planx_localizations.dart';

// ....
MaterialApp(
  // ...
  // 配置语言,可以直接使用生成的PlanxLocalizations类支持的语言
  localizationsDelegates: PlanxLocalizations.localizationsDelegates,
  supportedLocales: PlanxLocalizations.supportedLocales,
  home: const IndexPage(),
);

使用

dart 复制代码
// 引入国际化文件
import 'package:flutter_gen/gen_l10n/planx_localizations.dart';
// .....
// 获取locale
PlanxLocalizations locale = PlanxLocalizations.of(context);
// 获取对应的翻译文案
print(locale.home);
print(locale.dayFormat(DateTime.now()));

如何设置同一语种的不同区域,以中文简体和繁体为例

  • 由于中文简体和繁体同属于中文,因此需要自定设置中文简体和繁体
  • MaterialApp中设置支持的语言
dart 复制代码
// 引入国际化文件
import 'package:flutter_gen/gen_l10n/planx_localizations.dart';

// ....
MaterialApp(
  // ...
  // 配置语言
  localizationsDelegates: PlanxLocalizations.localizationsDelegates,
  // 自行配置支持的语言
  supportedLocales: const <Locale>[
    Locale('en'),
    Locale('pt'),
    Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans'),
    Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),
  ],
  home: const IndexPage(),
);
  • 新建中文繁体的arb文件,注意文件名按照intl_zh_Hant.arb的格式

intl_zh_Hant.arb

json 复制代码
{
  "home": "首頁",
  "dayFormat": "{date}"
}
  • 重新运行项目,切换系统语言进行测试即可

修改语言

  • 我们通过以上的配置,可以通过手机的系统语言,自动适配app的语言
  • 如果我们需要手动设置app的语言,需要给MaterialApp中的locale参数传入需要设定的语言,null就表示取系统语言
dart 复制代码
MaterialApp(
  // ...
  // 这里配置app的语言,默认为null也就是系统语言
  locale: Locale('zh', 'CN'),
  localizationsDelegates: PlanxLocalizations.localizationsDelegates,
  supportedLocales: const <Locale>[
    Locale('en'),
    Locale('pt'),
    Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans'),
    Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),
  ],
  home: const IndexPage(),
);

配合provide状态管理和本地存储,设置语言

效果:

  • 安装相应的依赖:

pubspec.yaml

yml 复制代码
dependencies:
  # 状态管理
  provider: ^6.0.5
  # 本地存储
  shared_preferences: ^2.2.2
  • 简单封装本地存储,本地存储,用户下次进入时还是之前选择的语言

lib/utils/storage_util.dart

dart 复制代码
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';

class StorageUtil {
  static late SharedPreferences _preferences;

  static init() async {
    _preferences = await SharedPreferences.getInstance();
  }

  // 设置本地缓存
  static Future<bool> set<T>(String key, T value) {
    String type = value.runtimeType.toString();
    switch (type) {
      case "String":
        return _preferences.setString(key, value as String);
      case "int":
        return _preferences.setInt(key, value as int);
      case "bool":
        return _preferences.setBool(key, value as bool);
      case "double":
        return _preferences.setDouble(key, value as double);
      case "List<String>":
        return _preferences.setStringList(key, value as List<String>);
      case "_InternalLinkedHashMap<String, String>":
        return _preferences.setString(key, json.encode(value));
      default:
        return Future.value(false);
    }
  }

  // 取出缓存
  static Object? get(String key) {
    Object? value = _preferences.get(key);
    if (value.runtimeType.toString() == "String") {
      try {
        return json.decode(value as String);
      } catch (err) {
        return value;
      }
    }
    return value;
  }

  // 删除缓存
  static Future<bool> remove(String key) {
    return _preferences.remove(key);
  }
}
  • 新增一个ChangeNotifier,用于存储语言,后续在ChangeNotifierProvider中可以监听

lib/provider/locale_provider.dart

dart 复制代码
import 'package:flutter/material.dart';
import 'package:planx_app/utils/storage_util.dart';

/// 定义一个 ChangeNotifier,用于存储当前的语言。后续在ChangeNotifierProvider中可以监听
class LocaleProvider extends ChangeNotifier {
  String? _locale;
  Locale? get locale {
    // 获取本地缓存
    _locale = (StorageUtil.get('locale') as String?) ?? "system";
    switch (_locale) {
      case 'zh':
        return const Locale('zh');
      case 'zh_Hant':
        return const Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant');
      case 'en':
        return const Locale('en');
      case 'pt':
        return const Locale('pt');
      default: // 选择系统设置语言
        return null;
    }
  }

  // 修改语言
  changeLanguage(String val) async {
    // 如果当前语言与新语言一致,则不做任何操作
    if (val == _locale) return;
    _locale = val;
    // 本地保存语言
    await StorageUtil.set('locale', val);
    // 通知所有监听器
    notifyListeners();
  }
}
  • 最外层使用ChangeNotifierProvider,用于监听状态的变化,如果发生变化就会执行Consumerbuilder
  • MaterialApp外面包一层Consumer获取值。并且给locale赋值,确定当前app的语言
  • provider的更多使用,请参考:Flutter状态管理之 Provider 使用详解 - 掘金
  • 注意:在main中初始化本地缓存实例

lib/main.dart

dart 复制代码
import 'package:provider/provider.dart';
import 'package:planx_app/utils/storage_util.dart';
void main() async {
  // main函数中有await时,需要先调用此方法
  WidgetsFlutterBinding.ensureInitialized();
  // 初始化本地缓存实例
  await StorageUtil.init();
  runApp(const MyApp());
}
  	//...
	///...
    ChangeNotifierProvider(
       // 监听LocaleProvider的变化
      create: (_) => LocaleProvider(),
      child: Consumer(
        // LocaleProvider变化就会执行Consumer的builder,并接收最新的LocaleProvider
        builder: (context,LocaleProvider localeProvider,Widget? child) {
          // 包裹MaterialApp
          return MaterialApp(
            // ...
            // 使用语言
            locale: localeProvider.locale,
            // ...
            home: const IndexPage(),
          );
        }
      ),
    );
  • 使用context.read<LocaleProvider>()获取LocaleProvider实例,通过实例更改语言
dart 复制代码
import 'package:provider/provider.dart';
import 'package:planx_app/provider/locale_provider.dart';
// ....
ElevatedButton(
  onPressed: () {
    context.read<LocaleProvider>().changeLanguage('en');
  },
  child: const Text("英语"),
),
相关推荐
fishmemory7sec4 分钟前
Electron 主进程与渲染进程、预加载preload.js
前端·javascript·electron
fishmemory7sec7 分钟前
Electron 使⽤ electron-builder 打包应用
前端·javascript·electron
豆豆1 小时前
为什么用PageAdmin CMS建设网站?
服务器·开发语言·前端·php·软件构建
twins35202 小时前
解决Vue应用中遇到路由刷新后出现 404 错误
前端·javascript·vue.js
qiyi.sky2 小时前
JavaWeb——Vue组件库Element(3/6):常见组件:Dialog对话框、Form表单(介绍、使用、实际效果)
前端·javascript·vue.js
煸橙干儿~~2 小时前
分析JS Crash(进程崩溃)
java·前端·javascript
安冬的码畜日常2 小时前
【D3.js in Action 3 精译_027】3.4 让 D3 数据适应屏幕(下)—— D3 分段比例尺的用法
前端·javascript·信息可视化·数据可视化·d3.js·d3比例尺·分段比例尺
l1x1n03 小时前
No.3 笔记 | Web安全基础:Web1.0 - 3.0 发展史
前端·http·html
昨天;明天。今天。3 小时前
案例-任务清单
前端·javascript·css
zqx_74 小时前
随记 前端框架React的初步认识
前端·react.js·前端框架