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,用于监听状态的变化,如果发生变化就会执行Consumer的builder。
  • 在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("英语"),
),
相关推荐
Eiceblue8 分钟前
使用 Python 实现 Excel 行列转置(保留单元格样式)
前端·python·excel
西西学代码23 分钟前
像素和颜色之间的转换(Flutter)
前端·javascript·flutter
茶底世界之下36 分钟前
羽毛颜色已经很鲜艳,还要继续加色吗?用 Awaking 试一次减饱和
前端·ios·运营
风早爽太44 分钟前
Mac 搭建 Vue 开发环境
前端·vue.js
曹小强wxx1 小时前
Flutter 局域网设备发现:UDP 广播 + mDNS 双路合并,以及靠谱的在线判定与断线重连
物联网·网络协议·flutter
Lank_M1 小时前
Word图片裁剪转HTML失效,转换器各漏读了哪一层
前端
青烟小生1 小时前
前端架构设计实战:从组件思维到系统思维
前端
Amos_Web1 小时前
Rspack 源码解析(二十):Typed Hook 系统如何靠宏生成
前端·rust·前端框架
程序员大阳1 小时前
副队长CSS教程(29)–CSS Grid 实战:实现通用图文混排布局
前端·css·grid·图文混排
对空六课1 小时前
无头浏览器访问对跳出率的过滤规则
服务器·前端·算法·数据分析