【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 パッケージの導入
pubspec.yaml
に記述追加
1-1. 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コードの自動生成時に
flutter pub get
を叩く
1-2. Flutterプロジェクトのrootで、flutter pub get
を叩き、パッケージをプロジェクトに取り込む。
Step2 Localization用のyaml作成
l10n.yaml
を作成
2-1. Flutterプロジェクトのrootにl10n.yaml
を作成する。
(引数付きでflutter gen-l10n
を叩けばコマンドでも生成可能)
l10n.yaml
に記述
2-2. 以下の記述は、自分用に変更等を加えているので、後述の説明とともに適宜書き換えて保存。
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用のフォルダと定義を作成
l10n
フォルダを作成
3-1. Step2のl10n.yaml
でarb-dir
の指定したlib/l10n
の通りの場所、名前でフォルダを作成
app_en.arb
ファイルを作成
3-2. 作成したフォルダにl10n.yaml
でtemplate-arb-file
に指定したapp_en.arb
の名前のファイルを作成
app_en.arb
に記述
3-3. 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.delegate
GlobalMaterialLocalizations.delegate
GlobalCupertinoLocalizations.delegate
GlobalWidgetsLocalizations.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
.gitignore
に記載
5-1. 自動生成されるコードは差分がでやすく、コミット対象に不向きなため、.gitignore
に記述してコミットから除外する。
**/l10n/*.dart
analysis_options.yaml
から除外(lintを使っている人のみ対象)
5-2. 自動生成されるコードを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
を選択し、Localizations
KeyにJapanese
を追加する。
(Localizations
Keyがない時は、+
を押してKey自体を追加する。)
6-3. 端末の言語設定変更と確認
端末言語を日本語にしてアプリを起動してみると、Localizeされた画面が表示されることを確認!
Step7 英語以外をデフォルト言語に設定
l10n.yaml
に追記
7-1. アプリで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
ちょうど知りたかったことが知れました。
ありがとうございます☺️