2023了,如何快速实现 Flutter 国际化

时间:2022-12-21 01:25:21

大家好,我是 17。

春节期间为大家精心准备了这篇实现国际化的文章,和大家一起,用最简单快速的方式实现 Flutter 国际化。

Flutter 国际化要解决的是两个问题

  1. flutter 框架本身的国际化,flutter 已经为我们实现,只要启用即可。
  2. 工程国际化,就是我们自己写的代码,需要自己做国际化。

flutter 框架的国际化

实现框架国际化只要 2 步

添加依赖

打开项目根目录下的 pubspec.yaml 文件,找到 dependencies,添加

flutter_localizations:
   sdk: flutter

添加后的配置

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter

添加好配置后,执行

flutter pub get

添加代码

MaterialApp(
 localizationsDelegates: [
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalCupertinoLocalizations.delegate,
 ],
 supportedLocales: [
    const Locale('en', 'US'), // 美国英语
    const Locale('zh', 'CN'), // 中文简体
    //其他Locales
  ],
  // ...
)

这样就大功告成了。

测试

代码加上了,但是怎么测试国际化有没有生效呢?很简单,加一个 TextField Widget,随便输入点内容,然后长按输入框,就会有提示文本 ”全选“ 出现。国际化成功后显示的是中文。把国际化的代码删除再看下,显示的是英文 ”Select all"。

const MaterialApp(
      supportedLocales: [
        Locale('en', 'US'), // 美国英语
        Locale('zh', 'CN'), // 中文简体
      ],
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate
      ],
      home: Scaffold(
          body: Center(
        child: TextField(),
      )),
    );

代码解释

supportedLocales 指定支持的语言和地区。Locale 的第一个参数是语言标签,第二个参数是地区标签。一般情况下,支持中文和英文就够了,如果要支持更多语言和地区,可以到 语言和地区的标签列表 中查阅。

GlobalMaterialLocalizations.delegate 为 Material 组件库提供本地化的字符串和其他值。 GlobalCupertinoLocalizations.delegate 为 Cupertino 组件库提供本地化的字符串和其他值。 GlobalWidgetsLocalizations.delegate 定义了默认的文本排列方向,由左到右或者由右到左。

到这里 Flutter 框架的国际化就完成了,下面看下如何为自己写的代码做国际化。

工程国际化

自己写的代码做国际化需要 IDE 和插件的配合,这样才能事半功倍。

初始化环境

  1. IDE 选择 vscode(visual studio code)
  2. IDE 插件用 Flutter Intl

2023了,如何快速实现 Flutter 国际化

  1. 打开 vscode,新建一个 application
  2. 配置 pubspec.yaml 文件,增加 flutter_localizations。这是必须的,必须得先支持 Flutter 框架的国际化。
flutter_localizations:
    sdk: flutter

执行 pub get

fluter pub get
  1. 同时按 cmd 键(windows 是 ctrl 键) + shift 键 + p 键,打开命令面板,单独按 F1,也能打开命令面板,选择 Flutter Intl:Initialize

2023了,如何快速实现 Flutter 国际化

执行完命令后在pubspec.yaml 中多了一个配置

flutter_intl:
  enabled: true

lib 文件夹中多了两个文件夹 generated 和 i10n。generated 我们不用管,vscode 的插件 Flutter Intl 负责维护。我们需要关注的是 l10n。l10n 是 localization 的缩写,10 代表中间省略了 10 个字母。

2023了,如何快速实现 Flutter 国际化

编辑内容

目录只有一个文件 intl_en.arb。

arb 文件扩展名为:Application Resource Bundle 缩写,意为应用程序资源包,并得到Google的支持,每个 .arb 文件都包含一个JSON表,该表从资源ID映射到本地化值。

arb 文件很简单,无关代码,交给翻译,翻译好了再放回来。

打开 intl_en.arb 发现只有一个 {} 我们增加一个 title。

{
  "title":"IAM17"
}

为了支持中文,我们通过命令面板执行 Flutter Intl:Add locale。

2023了,如何快速实现 Flutter 国际化

然后让我们输入语言和地区。我们输入 zh_CN,在 l10n 文件夹下面会多出一个文件 intl_zh_CN.arb。

2023了,如何快速实现 Flutter 国际化

打开 intl_zh_CN.arb,输入以下内容

{
  "title":"我是 17"
}

通过文件命名我们可以看出,默认的 intl_en.arb 不区分地区,只要语言是英语就行。

应用国际化

我们准备好了一个 title 现在把它展示出来 。

需要 4 步

  1. 引用 import generated/l10n.dart
  2. 添加 S.delegate
  3. 添加 supportedLocales: S.delegate.supportedLocales
  4. S.of(context).title 获得 title

完整代码,贴到 main.dart 就能运行。

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
// 1
import 'generated/l10n.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        localizationsDelegates: const [
          // 2
          S.delegate,
          GlobalMaterialLocalizations.delegate,
          GlobalCupertinoLocalizations.delegate,
          GlobalWidgetsLocalizations.delegate
        ],
        // 3
        supportedLocales: S.delegate.supportedLocales,
        home: Scaffold(body: Builder(
          builder: (context) {
            return Center(
              // 4
              child: Text(S.of(context).title),
            );
          },
        )));
  }
}

说英语的地区有很多,总不能每个地区都配置一套吧

一般情况下,只提供美国英语就够了,其它地区都使用美国英语。

MaterialApp(
      localeResolutionCallback: (locale, supportedLocales) {
        // 如果语言是英语
        if (locale?.languageCode == 'en') {
          //注意大小写,返回美国英语
          return const Locale('en', 'US');
        } else {
          return locale;
        }
      },
      // 省略...

参数 locale 是设备系统报告的设备支持的首选语言环境。当环境为英语时,不论是哪个地区,都返回美国英语。

localeResolutionCallback 负责在 App 启动和用户改变设备语言的时候确定语言环境。

实际上,设备系统报告的支持的语言环境可能不止一个,如果要对所有支持的语言环境做判断,可以用 LocaleListResolutionCallback 回调,并不常用,了解即可。

占位符

打开 intl_zh_CN.arb 和 intl_en.arb,把 17 用变量替换,变量用 {} 括起来就行。

{
  "title":"我是{name}"
}
{
  "title":"IAM{name}"
}

修改完后,保存文件,插件会为我自动生成代码,更新 generated 文件夹中的文件。用的时候这样用。

Text(S.of(context).title(17))

17 写成字符串也是可以的,因为参数的类型是 Object。

Text(S.of(context).title(”17“))

App 标题实现国际化

不能直接设置 title,需要在 onGenerateTitle 中设置。

MaterialApp(
  title:'不能在这里设置'
  onGenerateTitle: (context){
    return S.of(context).title;
  },
  // 省略...

如果直接设置在 title 处,S.of(context).title 是会报错的,原因是S.of会从当前的 context 沿着widget 树向顶部查找S,但是 MaterialApp 已经是顶层了,往上不可能找到 S,所以S.of(context)会返回 null,报错。

子树应用不同语言

可能某些特殊需求,我们需要对一部分子树应用不同语言,了解一下即可。

Scaffold(body: Builder(
     builder: (context) {
       return Column(
         children: [
           Text(S.of(context).title),
           Localizations.override(
               context: context,
               locale: const Locale('en'),
               child: Builder(
                 builder: (context) {
                   return Text(S.of(context).title);
                 },
               ))
         ],
       );
     },
   ))

显示两段文本,上面显示 ”我是 17“,下面显示 IAM17。

删除多余的语言

如果加多了,可以删除。直接删除对应的 arb 文件即可,插件会自动为我们重新生成 generated 中的代码。

获取当前 locale

var locale = Localizations.localeOf(context);

手动改变 Locale

比如当按一个按钮的时候需要切换为美国英语,执行下面的代码就行。

S.load(Locale('en', 'US'));

拿不到 context 怎么办

current 可以替代 S.of(context)

S.current.title

如果 App 只有中文如何设置

在一些非大陆行货渠道买的一些 Android 和 iOS 设备,会出现默认的 Locale 不是中文简体的情况。为了能让 App 确定显示中文,我们设置一下 locale 锁定中文。

MaterialApp(
        locale: Locale('zh', 'CN'),
        supportedLocales: [
          Locale('zh','CN')
        ],
         localizationsDelegates: const [
          GlobalMaterialLocalizations.delegate,
          GlobalCupertinoLocalizations.delegate,
          GlobalWidgetsLocalizations.delegate
        ],
        // 省略...

如果不设置 locale,flutter 会采用系统的首选语言。

最后赠送两个插件配置的小知识

在 pubspec.yaml 文件的最后有两行配置,除了 enabled,还有另外两个选项可以配置

  • class_name 前面我们用了很多的 S ,是类名,如果你不喜欢这个名字,可以修改。
  • main_locale 设置默认的 locale。
flutter_intl:
  enabled: true
  class_name: S # 可选。 Default: S
  main_locale: en # 可选。可以改成 zh_CN 中文简体,这关系到默认生成的arb文件的名字。Default: en

没骗你吧,说快速实现,就是快速实现。只要按步骤一步一步做下来,轻松就能实现国际化了。

本文到这就结束了,谢谢观看!