【Flutter】Localization(L10n)対応
動作確認環境
Flutter 2.2.3 • channel stable • https://github.com/flutter/flutter.git
Framework • revision f4abaa0735 (5 weeks ago) • 2021-07-01 12:46:11 -0700
Engine • revision 241c87ad80
Tools • Dart 2.13.4
経緯
FlutterでLocalizationする際、公式が出しているintlを導入することが多い思うが、自分が調べて行った際にサイト毎で微妙に手順が違っていて混乱したので、次から迷わないようにまとめておこうと思った次第。
Step1 パッケージの導入
1-1. pubspec.yamlに記述追加
Internationalizing Flutter appsのサイトを元に、Flutterプロジェクトのpubspec.yamlに追記する
dependencies:
flutter:
sdk: flutter
flutter_localizations: # Add this line
sdk: flutter # Add this line
intl: ^0.17.0 # Add this line
flutter:
generate: true # Add this line
要素の説明
-
flutter_localizations: 英語以外の言語のLocalizationに対応するためのパッケージ -
intl: 日時や数字等をLocalizationするためのパッケージ- 記事作成時点では
0.17.0が最新。必要に応じてversionは書き換え。
- 記事作成時点では
-
generate: generateフラグ- Localizationコードの自動生成時に
trueになっていないとerrorになる
- Localizationコードの自動生成時に
1-2. flutter pub getを叩く
Flutterプロジェクトのrootで、flutter pub getを叩き、パッケージをプロジェクトに取り込む。
Step2 Localization用のyaml作成
2-1. l10n.yamlを作成
Flutterプロジェクトのrootにl10n.yamlを作成する。
(引数付きでflutter gen-l10nを叩けばコマンドでも生成可能)

2-2. l10n.yamlに記述
以下の記述は、自分用に変更等を加えているので、後述の説明とともに適宜書き換えて保存。
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: l10n.dart
output-class: L10n
synthetic-package: false
要素の説明
-
arb-dir: Localizationで自動生成するフォルダの指定-
arbは、Application Resource Bundleの略 - default値は、
lib/l10n
-
-
template-arb-file: Localizationで自動生成するファイルの元となるresourceファイル- default値は、
app_en.arb
- default値は、
-
output-localization-file: Localization処理の定義をするファイル名- default値は、
app_localizations.dart - default値だと長い命名になるので、
l10n.dart等短めに指定しておく方が良い
- default値は、
-
output-class:output-localization-fileのファイル内で自動生成して定義されるclass名- default値は、
AppLocalizations - default値だと長い命名になるので、
L10n等短くなるよう指定しておく方が良い
- default値は、
-
output-dir: Localizationコードが自動生成されるフォルダ- default値は、
--arb-dirと同じフォルダになる -
--arb-dirと同じで良いため、yamlに記載はしていない
- default値は、
-
preferred-supported-locales: supportedLocalesで最初に来る言語を指定できる- 指定がない場合、生成された言語のアルファベット順になる
- アプリのLocalizeが端末言語に対応していない時、デフォルト言語として指定するために使う
- 指定した言語の
arbファイルにのみLocalization定義を書くと、自動生成された言語別ファイルでも同じ内容が記載される- 全言語で同一文字列を使う時に役立つ…かもしれない?
-
synthetic-package: コードを合成パッケージ(?)として生成するかプロジェクトの指定フォルダに生成するかどうか- default値は、
true -
trueの時、合成パッケージを生成するらしいが、使ったことないのでわからない。 -
falseの時、output-dirで指定したフォルダにLocalizationコードを生成する
- default値は、
Step3 Localization用のフォルダと定義を作成
3-1. l10nフォルダを作成
Step2のl10n.yamlでarb-dirの指定したlib/l10nの通りの場所、名前でフォルダを作成
3-2. app_en.arbファイルを作成
作成したフォルダにl10n.yamlでtemplate-arb-fileに指定したapp_en.arbの名前のファイルを作成

3-3. app_en.arbに記述
arbは、JSONとほぼ同じ記述形式になっている。
{
"@@locale": "en",
"helloWorld": "Hello World!",
"@helloWorld": {
"description": "The conventional newborn programmer greeting"
}
}
要素の説明
-
@@locale: ファイルが扱うlocale- localeのため、
enでなくen_USでも良い
- localeのため、
-
helloWorld: プロジェクトから呼び出すLocalizeKey- lowerCamelCaseで記述
- 値にあたる
Hello World!がLocalize時に読み出される
-
@helloWorld:helloWorldに対するアノテーションのようなもの- description、引数を取る時の型、フォーマット等の指定が行える
3-4. コード生成
flutter gen-l10nを叩いて、Localizationのコードを生成する。
ここまでで記述や作成位置に問題なければ、l10n.yamlの内容を元にLocalizationファイルが生成される。

Step4 プロジェクトに生成したコードを適用
4-1. MaterialAppに記述追加
MaterialAppのlocalizationsDelegates及びsupportedLocalesを記載する。
その際、生成したコードのimportも忘れずに行う。
import 'package:flutter/material.dart';
+import 'package:new_project/l10n/l10n.dart';
...
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
+ localizationsDelegates: L10n.localizationsDelegates,
+ supportedLocales: L10n.supportedLocales,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
MaterialApp側の要素の説明
-
localizationsDelegates: Localization Widgetのdelegate-
supportedLocalesを元に、Localizationの処理周りを担う -
localizationsDelegatesを記載する時、supportedLocalesも必須となる。
-
-
supportedLocales: Localizationをサポートしている言語
Localizationコードの要素の説明
-
L10n.localizationsDelegates: Localizationのdelegateを1つにまとめたもの- 以下のdelegateを含んでいるため、この1行だけ書けば良い
L10n.delegateGlobalMaterialLocalizations.delegateGlobalCupertinoLocalizations.delegateGlobalWidgetsLocalizations.delegate
- 以下のdelegateを含んでいるため、この1行だけ書けば良い
-
L10n.supportedLocales: Localizationのサポート言語- arbファイルで定義した言語を元にコード自動生成時に追加される
※自動生成コードのclass名をL10nにした場合で記載
4-2. Localizationで生成されたコードの適用
L10n.of(context)でinstanceを作ってLocalizeKeyを呼ぶことでLocalizationされたテキストが呼ばれる。
...
class MyHomePage extends StatelessWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
Widget build(BuildContext context) {
+ final l10n = L10n.of(context)!;
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
+ child: Text(l10n.helloWorld),
),
);
}
}
Step5
5-1. .gitignoreに記載
自動生成されるコードは差分がでやすく、コミット対象に不向きなため、.gitignoreに記述してコミットから除外する。
**/l10n/*.dart
5-2. analysis_options.yamlから除外(lintを使っている人のみ対象)
自動生成されるコードをlintに対象すると、修正できないwarningやerrorが出ることもあるためlintから除外する。
analyzer:
exclude:
- '**/l10n/*.dart'
Step6 他の言語追加
6-1. arbファイルの作成
追加したい言語のarbファイルをl10n.yamlのtemplate-arb-fileに記載と同じ命名で作成する
日本語のLocalizeを追加する場合を例に説明とapp_ja.arbを作成する

app_ja.arbファイルの中身は、app_en.arbをコピペし、各値を日本語向けに書き換える
{
"@@locale": "ja",
"helloWorld": "こんにちは世界!",
"@helloWorld": {
"description": "新米プログラマーの挨拶"
}
}
6-2. iOSプロジェクトで言語追加
XcodeでこのFlutterプロジェクトのiosフォルダにあるRunner.xcworkspaceを開く。
左のカラムでInfo.plistを選択し、LocalizationsKeyにJapaneseを追加する。
(LocalizationsKeyがない時は、+を押してKey自体を追加する。)

6-3. 端末の言語設定変更と確認
端末言語を日本語にしてアプリを起動してみると、Localizeされた画面が表示されることを確認!
Step7 英語以外をデフォルト言語に設定
7-1. l10n.yamlに追記
アプリでLocalizeに端末の言語が対応していない時、英語がLocalizeされていれば、英語がデフォルト言語となるようだ。
英語がLocalizeされていない時は、何が基準でデフォルト言語になっているか動作確認等してみたものの不明。
日本語をデフォルト言語にする場合、まずStep2-2のl10n.yamlにpreferred-supported-localesと言語コードを追記する
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: l10n.dart
output-class: L10n
synthetic-package: false
+preferred-supported-locales: ja
7-2. MaterialAppに記述追加
MaterialAppにlocaleResolutionCallbackを追加する。
callback処理内で、Localizeしている言語(supportedLocales)に端末言語(locale)が含まれているか確認する。
この時、localeには言語コード+国コードが含まれているので、言語コードだけのLocale instanceを生成して比較。
含まれていれば、そのlocaleをそのまま返す。
含まれていなければ、supportedLocalesの最初にあるlocaleを返す。
(この最初にくるlocaleを7-1の手順で設定している)
class MyApp extends StatelessWidget {
// This widget is the root of your application.
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
localizationsDelegates: L10n.localizationsDelegates,
supportedLocales: L10n.supportedLocales,
+ localeResolutionCallback: (locale, supportedLocales) {
+ if (locale != null) {
+ final _locale = Locale(locale.languageCode);
+ if (supportedLocales.contains(_locale)) {
+ return _locale;
+ }
+ }
+ return supportedLocales.first;
+ },
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
MaterialApp側の要素の説明
-
localeResolutionCallback:localeとsupportedLocalesが渡ってきて、callbackで返した言語がアプリに反映される-
locale: アプリ起動時の端末言語の優先度が1番高いものが来る。-
nullの時は、アプリ起動時に端末言語をまだ取得できていない状態
-
-
supportedLocales:MaterialAppのsupportedLocalesで渡している値
-
余談
同一言語他国家のLocalizeには本記事の方法では対応しきれないことが出てくると思われる。
en_USとen_UKをそれぞれLocalizeする方法は、また別途調査して書ければと思う。
Discussion
ちょうど知りたかったことが知れました。
ありがとうございます☺️