flutter-Intl国际化、格式化日期、数字

3,020 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
Intl 是官方出品的,包含用于处理国际化/本地化消息,日期和数字格式和解析,双向文本以及其他国际话问题。

pub地址:pub.dev/packages/in…

Github地址:github.com/dart-lang/i…

Intl插件最主要的是就是Intl类,他为我们提供了国际化的大量方法,同时该插件还封装了DateFormat、NumberFormat和BidiFormatter几个常用的格式化的工具类。

我经常使用到的就是国际化以及日期格式化功能。使用起来也非常的简单,我们先看看如何实现国际化。

安装Intl插件

Flutter为我们提供了Intl的插件,同时支持as和vs,使用插件可以快速的创建国际化需要的文件,比手动写要舒服多了。

VS code

插件地址:marketplace.visualstudio.com/items?itemN…

插件市场搜索能够更快的找到并安装它。

安装好以后,在命令窗口输入 Flutter Intl能够看到方法就表示已经安装成功了。

Android Studio

插件地址:plugins.jetbrains.com/plugin/1366…

当然,也可以在插件市场搜搜安装。

安装后在Tool里如果能看到Flutter Intl菜单就表示安装好了。

后边我我只用vs来演示了,as的方法大概相同,在tool中选择flutter intl菜单选中响应的功能就行了。

配置项目

创建一个测试的项目

flutter create intl_test

启动国际化支持

编辑pubspec.yaml文件,启动国际化的支持,引入Intl插件。

dependencies:
  # 国际化
  flutter_localizations:
    sdk: flutter
  intl: ^0.17.0

初始化Intl

执行命令Flutter Intl initialize

这个时候插件会帮我们创建一个基本的国际化结构,包括pubspec.yaml的调整

# 文件结尾会增加
flutter_intl:
  enabled: true

在lib目录下会生成以下文件,在I10n文件夹下边有一个默认的intl_en.arb语言包,arb文件全称Application Resource Bundle(abbr. ARB)是一种本地化资源格式,使用arb文件作为资源配置文件(类似xml)可以提供给翻译人员翻译,他的编辑也是很简单,就像一个json文件,使用key-value格式来录入我们的语言内容。而intl文件夹内的文件,还有I10n.dart都不需要手动编辑,而且不建议大家手动编辑,他们是会根据我们配置的语言包内容自动更新。

新增语言

在命令行输入Flutter intl: Add locale,来新增我们需要的语言。比如ko,ja,如果有地区的需要使用下划线来连接地区,比如简体中文zh_CN,繁体中文有zh_HK、zh_TW,英语美国en_US,英语英国en_GB等,这里根据应用的目标地区自行调整。

在输入语言后,插件会帮我们自动的创建message_,intl_.arb两个文件。同时在I10n中注册我们的语言。

我们可以直接编辑intl_**.arb的文件,来设置我们的语言包,比如我们新建的这个简体中文,然后来设置一些简单的测试数据。编辑语言包很简单,就是一个json格式的文件,要注意的arb文件不支持嵌套,只能有一层。

{
  "name": "姓名",
  "age": "年龄",
}
{
  "name": "Name",
  "age": "Age"
}

设置应用

在MaterialApp中增加

// 国际化配置
localizationsDelegates: const [
  GlobalMaterialLocalizations.delegate,
  GlobalWidgetsLocalizations.delegate,
  GlobalCupertinoLocalizations.delegate,
  S.delegate
],
// 将en设置为第一项,没有适配语言时,英语为首选项
supportedLocales: [
  const Locale('en', ''),
  ...S.delegate.supportedLocales
],

使用就很简单了,在需要国际化的地址,使用S.of(context)来获取一个国际化的实例,属性就是我们在arb中配置的key。

Text(S.of(context).name),
Text(S.of(context).age),

我们还可以增加两个按钮来切换语言。

\

分析一下实现

当我们配置arb文件后,Intl会在generated/I10n.dart文件中使用message方法生成get方法。比如刚才的姓名和年龄代码:

/// `Name`
String get name {
  return Intl.message(
    'Name',
    name: 'name',
    desc: '',
    args: [],
  );
}

/// `Age`
String get age {
  return Intl.message(
    'Age',
    name: 'age',
    desc: '',
    args: [],
  );
}
  • 第一个参数就是我们默认的国家化输出内容。
  • name:Intl函数的名称,对应arb文件中的key,这个参数必须是全局唯一的。
  • desc:文本的描述信息,方便我们了解这个词条的含义,方便翻译人员进行翻译。
  • args:插值

最后一个参数这里没用上,我们来看看如何使用插值这个参数。重新编辑一下我们的arb文件

{
  "name": "Name",
  "age": "Age",
  "input": "place input {label}",
  "todo": "Do what you {todo},{todo} what you do",
  "getMessageTips": "{howMany, plural, zero{You have no message} one{You have 1 message} other{You have {howMany} messages}}",
  "gender": "{gender, select, male{Mr {lastName}} female{Ms {lastName} } other{VIP {lastName}}}",
  "select": "{select, select, option1{{lastName},select} option2{{lastName},select} other{{lastName} default select}}"
}
{
  "name": "姓名",
  "age": "年龄",
  "input": "请输入 {label}",
  "todo": "做你{todo}到的,{todo}你做到的",
  "getMessageTips": "{howMany, plural, zero{没有消息} one{有1条消息} other{有{howMany}条消息}}",
  "gender": "{gender, select, male{{lastName}先生} female{{lastName}女士} other{{lastName} 贵宾}}",
  "select": "{select, select, option1{{lastName}被选择} option2{{lastName},被选择} other{{lastName} 默认选中}}"
}

在界面上增加一些输出

Text(S.of(context).getMessageTips(0)),
Text(S.of(context).getMessageTips(1)),
Text(S.of(context).getMessageTips(4)),
Text(S.of(context).input("country")),
Text(S.of(context).todo("say")),
Text(S.of(context).gender("male", "Jones")),
Text(S.of(context).gender("female", "Jones")),
Text(S.of(context).gender("other", "Jones")),
Text(S.of(context).select("option1", "Germany")),
Text(S.of(context).select("option2", "U.S.A")),
Text(S.of(context).select("", "china")),

\

使用占位符输出

/// `place input {label}`
String input(Object label) {
    return Intl.message(
      'place input $label',
      name: 'input',
      desc: '',
      args: [label],
    );
  }

和message不一样的地方是,这里不再是一个get方法了,是一个普通的方法,多了一个Object的输入参数,第一个参数中也多了占位符,在args的值就是我们传入给方法的值。

占位符可以多次使用

/// `Do what you {todo},{todo} what you do`
  String todo(Object todo) {
    return Intl.message(
      'Do what you $todo,$todo what you do',
      name: 'todo',
      desc: '',
      args: [todo],
    );
  }

和input方法一样,只是占位符可以多次使用。

数字国际化

/// `{howMany, plural, zero{You have no message} one{You have 1 message} other{You have {howMany} messages}}`
String getMessageTips(num howMany) {
  return Intl.plural(
  howMany,
  zero: 'You have no message',
  one: 'You have 1 message',
  other: 'You have $howMany messages',
  name: 'getMessageTips',
  desc: '',
  args: [howMany],
);
}

这里使用了Intl.plural方法,这是一个数字国际化的方法,根据不同的数量,进行不同内容的输出。

性别国际化

/// `{gender, select, male{Mr {lastName}} female{Ms {lastName} } other{VIP {lastName}}}`
  String gender(String gender, Object lastName) {
    return Intl.gender(
      gender,
      male: 'Mr $lastName',
      female: 'Ms $lastName ',
      other: 'VIP $lastName',
      name: 'gender',
      desc: '',
      args: [gender, lastName],
    );
  }

这个是性别国际化

多种选项

/// `{select, select, option1{{lastName},select} option2{{lastName},select} other{{lastName} default select}}`
  String select(Object select, Object lastName) {
    return Intl.select(
      select,
      {
        'option1': '$lastName,select',
        'option2': '$lastName,select',
        'other': '$lastName default select',
      },
      name: 'select',
      desc: '',
      args: [select, lastName],
    );
  }
}

明天再来说说日期和数字的格式化。

演示代码地址:gitee.com/radium/flut… 视频地址:查看视频