[Flutter2も対応]多言語対応についてのまとめ

2021/04/08 追記 ※flutter2対応しました。コード分けて書いてます。

Flutterで多言語対応を行う場合、大きく分けて2つの対応が必要です。
・アプリ全体を対応させる
・表示する文字列を言語設定によって切り替える

アプリ全体を対応させる

例えば、日付の表示形式は日本だと年月日ですが、アメリカは日月年です。
これを自分で対応させようとした場合、気が遠くなるような作業量が待ち構えています。
そこで、パッケージを導入することでお手軽に対応させることが出来ます。

パッケージの導入

まずはpubspec.yamlに以下の記述を追加してください。

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

vsCodeであれば、保存すると自動でgetしてくれます。

delegate、サポート情報の設定

ルートのMaterialAppに以下の記述を追加します。

localizationsDelegates: [
   GlobalMaterialLocalizations.delegate,
   GlobalWidgetsLocalizations.delegate,
   GlobalCupertinoLocalizations.delegate,
 ],
 supportedLocales: [
    const Locale('en', ''), // English, no country code
    const Locale('ja', ''), // Japanese, no country code
 ],

supportedLocalesについては注意点があります。
例えば、中国語には簡体字と繁体字という2種類の漢字が存在します。
更に、北京語・台湾華語・香港語に細分化することが出来るのです。
詳しくは以下の公式ページを確認してください。
https://flutter.dev/docs/development/accessibility-and-localization/internationalization

Locale()の第一引数は言語コード、第二引数は国コードみたいですね。

対応している言語コード一覧は以下です。
https://api.flutter.dev/flutter/flutter_localizations/GlobalMaterialLocalizations-class.html

対応している国コード一覧は見つけられませんでしたが、大文字2文字で指定するようです。
使いどころですが、例えば英語を使用している国はアメリカ、イギリス、オーストラリア、、と複数存在します。
そして先ほども紹介しましたが、国によって日付表示形式であったり、数字の桁の表し方が違ったりするのです。
そのため、言語とは別に国も指定する必要があるのです。

言語設定に対応した文字列の表示

次はスマホの言語設定に合わせて、表示するテキストを分岐させる処理についてです。
こちらも有名なパッケージはあるのですが、編集するたびに設定ファイルを再作成する必要があったりと、
まだ本番プロジェクトに使うには微妙なので自分でコードを書きました。
以下コードをLocaleMessage.dartというファイル名で保存してください。

※Flutter2とそれより古いバージョンでfuctory部分の実装方法が変わっています!対応する方を使ってください。

import 'package:flutter/widgets.dart';

class LocaleMessage
{
  // 内部処理開始 ----------------------------------------------
  
  // 旧flutter用 始まり######################
  //インスタンス保持用
  static LocaleMessage _instance;

  //factoryを使うことで、初期化処理をアプリ初期化時に書かなくて済む。
  factory LocaleMessage.of(BuildContext context)
  {
    if (_instance == null) {
      Locale myLocale = Localizations.localeOf(context);
      _instance = new LocaleMessage._(myLocale);
    }
    return _instance;
  }
  // 旧flutter用 終わり######################

 // flutter2用 始まり######################
  static LocaleMessage? _instance;

  static LocaleMessage _localeMessageInit(BuildContext context) {
    Locale myLocale = Localizations.localeOf(context);
    _instance = LocaleMessage._(myLocale);
    return _instance ??= throw Error();
  }

  factory LocaleMessage.of(BuildContext? context) => _instance ??= context != null ? _localeMessageInit(context) : throw Error();
 // flutter2用 終わり######################


  //内部処理 インスタンス生成用コンストラクタ
  LocaleMessage._(this.locale);

  //Locale情報保持
  Locale locale;
  // 内部処理終了 ----------------------------------------------

  // -- 以下を利用時に編集 --

  //定義済み言語コード
  // 対応言語を追加してください。
  final String ja = 'ja';
  final String en = 'en';

  //以下文字列定義。
  // 規定言語(en)は最後。
  // ifで対応言語毎のテキストをreturnしてください。
  String title()
  {
    if(locale.languageCode == ja)
      return 'タイトル';
    else
      return 'title';
  }
}

使う際には

LocaleMessage.of(context).title(); //初回
LocaleMessage.of(null).title(); //アプリ全体での呼び出しが2回目からはnullも可能。 


とすると、言語設定に応じたテキストが取得できます。

簡単にコードの解説をしますと、上半分の内部処理は変更不要です。
factryでシングルトンを実現し、簡単に呼び出せるようにしてます。

あなたのアプリに導入する際は下半分を修正する必要があります。
まず「定義済み言語コード」に対応言語を追加してください。
表示処理を記述する際のタイポミスを防ぐように、定数にします。

その後、表示したいテキストの数だけ、ここにメソッドを追加していきます。
今回はtitle()のみですが、hint()とか、idErorr()とかいろいろあるでしょう。
if文で、_locale.languageCode を見ていますが、これで端末の言語設定を取得できます。
定数と同じであればその文字列を出力、違ったら次へ、、、と処理を流していき、
一致するものがなければ、規定文字列(今回はen)が出力されるという内容です。

今回はコードベースなので、やろうと思えば設定ファイルだと実現できない細かな分岐処理も
わかりやすく記述することが可能です。ぜひ色々と試してみてください。

[iOSのみ]設定の追加

iOSはinfo.plistに設定を追加する必要があります。
ios/Runner内にあるので以下を追加してください。

	<key>CFBundleLocalizations</key>
  	<array>
    	<string>en</string>
    	<string>ja</string>
  	</array>

また、iPhoneシミュレーターで動作確認する際、規定が英語なので日本語に変わるかどうかみるかと思いますが、その場合は設定を開き以下の様に変更してください。

まとめ

Flutterでの多言語対応については、まだ王道があるようでないような、成熟していく最中なのかなという印象でした。
今回の実装方法でしばらくは困りそうにもないので、とりあえずこれでいいかな。