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