UUUO Tech Blog

水産流通のDXや業務効率化を実現するアプリケーション「UUUO」「atohama」を開発・展開している株式会社ウーオのテックブログです。プロダクトにまつわる様々な情報発信を行います。

Flutter と多言語化対応

こんにちは、初めまして。
5月からウーオの中の人になったソフトウェア開発者の石田 (@geckour) です。

今回は Flutter での多言語化対応を地道に進めた話をしたいと思います。

日本語 英語
日本語の画面
日本語の画面
英語の画面
英語の画面

言語化対応された様子

目次

出発地点

UUUO では、このところ海外向けに展開するために多言語化対応を進めていました*1*2

最初は flutter_localizations を使っていたのですが、シンプルなテキストなら問題なく適用できるものの、複雑なテキストを扱おうとした際に問題が起きました。

flutter_localizations

flutter_localizations とは、Flutter が公式に出している多言語化対応のためのパッケージです。
小さな設定と簡単な記述でそこそこ色々な機能を使って多言語化対応ができます。

flutter_localizations でできること (抜粋)

flutter_localizations はなかなかに豊富な機能を備えていて、以下のようなことができます。

  • Locale による単純な文字列出し分け
  • 変数埋め込みへの対応
  • 複数形 (変数の数による表現の切り替え) への対応
  • Enum 変数による表現の切り替え

これだけでかなりのケースがカバーできると思います。

flutter_localizations だけでは難しいこともある

しかし、例えば RichText のように "文字列の部分部分で装飾する" 必要がある場合、英語と日本語のように文節で区切ったときに順番が入れ替わる可能性がある言語群に対応しようとすると、無理が生じてしまいます。
以下の例だと装飾の都合上文節レベルで区切って文字列定義を作る必要がありますが、日本語と英語で装飾対象の文節の位置が変わるので、そのままではうまく対応できません。

例1: 以下の日本語における 利用規約プライバシーポリシー を太字にしたい。英語における相当箇所 (Terms of ServicePrivacy Policy) も同様。

  • 日本語: 利用規約とプライバシーポリシーに同意する必要があります
  • 英語: You must agree to the Terms of Service and Privacy Policy

sample.dart

RichText(
  text: TextSpan(
    children: [
      // 英語の場合は後ろに持っていきたい
      TextSpan(
        text: t.terms_of_service,
        style: TextStyle(fontWeight: FontWeight.bold),
      ),
      TextSpan(
        text: t.and,
      ),
      TextSpan(
        text: t.privacy_policy,
        style: TextStyle(fontWeight: FontWeight.bold),
      ),
      // 英語の場合は前に持っていきたい
      TextSpan(
        text: t.must_agree,
      ),
    ],
  ),
)

sample_ja.arb

{
  "terms_of_service": "利用規約",
  "and": "",
  "privacy_policy": "プライバシーポリシー",
  "must_agree": "に同意する必要があります"
}

sample_en.arb

{
  "terms_of_service": "Terms of Service",
  "and": " and ",
  "privacy_policy": "Privacy Policy",
  "must_agree": "You must agree to the "
}

slang

flutter_localizations のみでは多言語化の実現が難しいパターンがあることを紹介しましたが、そんなときに強い味方となってくれるパッケージがあります。

以前は fast_i18n として提供されていて、今は slang として生まれ変わった多言語化対応のためのパッケージです。

slang でできること (抜粋)

基本的に flutter_localizations でできることは全て slang でもできます*3

加えて、

  • RichText への対応
  • 爆速コード生成
  • List/Map で定義した文字列への参照
  • 変数埋め込み記法の変更

などが利用できます。

以下に軽く説明していきますが、基本的に公式ドキュメントに全て書かれているので詳しく知りたい方はそちらをご参照ください。

RichText への対応

文字列定義のキー名末尾に (rich) と付けると、文字列定義の値に RichText 向けのマーカーを設定してコード内で利用することができるようになります。

先程の例を使うと、

例2: 以下の日本語における 利用規約プライバシーポリシー を太字にしたい。英語における相当箇所 (Terms of ServicePrivacy Policy) も同様。

  • 日本語: 利用規約とプライバシーポリシーに同意する必要があります
  • 英語: You must agree to the Terms of Service and Privacy Policy

sample_ja.i18n.json

{
  "caution(rich)": "${bold(利用規約)}と${bold(プライバシーポリシー)}に同意する必要があります"
}

sample_en.i18n.json

{
  "caution(rich)": "You must agree to the ${bold(Terms of Service)} and ${bold(Privacy Policy)}"
}

sample.dart

RichText(
  text: t.caution(
    bold: (text) => TextSpan(
      text: text,
      style: TextStyle(fontWeight: FontWeight.bold),
    ),
  ),
)

このように簡潔に記述することができます。

爆速コード生成

flutter_localizations での文字列定義ファイルからの Dart コード生成には flutter pub get を使うかと思いますが、slang の場合は (build_runner を利用している場合) flutter pub run build_runner build -d を使います。

ただ、このコマンドは往々にして実行に時間がかかるため、開発中は代替の flutter pub run slang が推奨されています (build_runner を利用している場合も使えます) 。
こちらは爆速です。

公式ドキュメントによると、CI などは (コード生成がいっぺんにできるからか) flutter pub run build_runner build -d がおすすめだそうです。

変数埋め込み記法の変更

slang のデフォルトの変数埋め込み識別子は $hoge または ${hoge} のような Dart の文字列への変数埋め込みと同じ記法です。

ただ、flutter_localizations からの移行の場合、なるべく変換の手間を減らすために {hoge} の形式にしたいという需要もあるかと思います。
slang は設定ファイルによる変数埋め込み記法の変更に対応しているのでこちらも実現可能です。

具体的には、(build_runner を利用している場合) build.yaml を用意して、

targets:
  $default:
    builders:
      slang_build_runner:
        options:
          string_interpolation: braces

このように記載するだけです。
build_runner を利用していない場合は slang.yaml が使えますが、そちらを使う場合は

string_interpolation: braces

このようにより簡単です。

まとめ

Flutter で多言語化対応したい場合、flutter_localizations でも十分色々なことができますが、slang を利用すればより柔軟な表現に対応できることを紹介しました。

個人的にはいずれ (割と近い未来に) RichText を使う必要が出てくるなどして乗り換えなければならないかもしれないリスクを抱えながら flutter_localizations を利用するよりは、最初から slang を利用することをおすすめします。

最後に

ウーオでは水産流通を革新するため、プロダクトを通じてあらゆるアプローチをしています。ウーオの事業やプロダクト開発にご興味がある方は、以下をぜひご覧ください 👇

uuuo.co.jp

◆カジュアル面談はこちらから◆ / 株式会社ウーオ

各ポジションの募集要項は以下をご覧ください 👇

ソフトウェアエンジニア(Mobile Application/Flutter) / 株式会社ウーオ

ソフトウェアエンジニア(Frontend/Flutter on the Web) / 株式会社ウーオ

ソフトウェアエンジニア(Backend/Ruby on Rails) / 株式会社ウーオ

それでは!