Flutterアプリの多言語対応用のarbファイルをyaml形式で分割して管理する
はじめに
Flutterで個人開発しているサブスク管理アプリのsubskunでは多言語対応をしている。
多言語対応自体は以下のFlutter公式ドキュメントに沿っておこなったが、アプリの機能が増えてくると多言語設定用のファイルであるarbファイルが大きくなってきて見通しが悪くなってきてしまった。接頭辞をつけるなどの対策はしていたが、それでもやりにくくなってきてしまった。
そこで、多言語設定用のファイルを機能ごとに分割しようと思い立った。
使うパッケージについて
調べてみると、slang
というパッケージが使えそうだった。
かなり機能が豊富なパッケージで、ファイルの分割はもちろんだがファイルの形式としてjsonやyaml、csvでも多言語設定用のファイルを記述できるらしかった。
元々のarbファイルではコメントを書けなくて困っていたので、ファイル内にコメントを記述できるyamlファイルで作成することにした。ただ、後々考えてみると機能ごとにファイルを分割できるのであればコメント自体もあまり必要でなくなるのでシンプルなデータ形式であるjsonでも良かったと思っている。
設定方法
公式のREADMEがかなり充実しているのでそちらを見れば足りると思われる。この記事の中ではyamlファイルとして機能ごとにファイルを分割した自分の対応について書いておく。
パッケージをインストール
Flutterを使う場合はslang_flutter
パッケージも必要とのことなので一緒にインストール。現時点での最新版は3.7.0
。
dependencies:
slang: 3.7.0
slang_flutter: 3.7.0
機能ごとにyamlファイルを作成
ファイルの命名規則は以下。<namespace>
部分はキャメルケースである必要がある。
<namespace>_<locale?>.<extension>
自分は以下のような感じでファイルを作成したが、いろんなディレクトリの切り方ができるらしい。
lib/i18n/
└── feature1/
└── feature1_en.yaml
└── feature1_ja.yaml
└── feature2/
└── feature2_en.yaml
└── feature2_ja.yaml
# これもOK
lib/i18n/
└── feature1_en.yaml
└── feature1_ja.yaml
└── feature2_en.yaml
└── feature2_ja.yaml
# これもOK
lib/i18n/
└── en/
└── feature1.yaml
└── feature2.yaml
└── ja/
└── feature1.yaml
└── feature2.yaml
今回の例ではyamlファイルの中身は以下のようにする。${}
のようにDartでの文字列内変数と同じ形式を埋め込むことで、変数を扱うことができる。
# feature1_en.yamlの中身
header: Header
content: This is ${content}
# feature1_ja.yamlの中身
header: ヘッダー
content: これは${content}
ちなみに変数の埋め込み方法は設定を変えることで他の形式を利用することもできる。詳細は以下を参照。
slang用の設定ファイルを作成
ファイルの分割とyaml形式のファイルを使用するためには別途設定が必要になる。slang.yaml
またはbuild.yaml
をプロジェクトの直下に配置する。以下はslang.yaml
での設定例。
namespaces: true # これを設定することでファイルの分割ができる
input_directory: lib/i18n
input_file_pattern: .yaml # デフォルトはjsonなので、それ以外の形式を使うには設定する必要がある
output_directory: lib/i18n
output_file_name: translations.g.dart
コード内の設定
最後にslangを使うためにコード内に設定のための記述をする。
// エントリポイント
void main() {
WidgetsFlutterBinding.ensureInitialized(); // これ
LocaleSettings.useDeviceLocale(); // これも
runApp(TranslationProvider(child: MyApp())); // TranslationProviderで囲む
}
// MaterialAppを使用している箇所
MaterialApp(
locale: TranslationProvider.of(context).flutterLocale, // TranslationProviderを使用する
supportedLocales: LocaleSettings.supportedLocales,
localizationsDelegates: GlobalMaterialLocalizations.delegates,
child: FirstScreen(),
)
ビルド
準備ができたので以下のコマンドでビルドしてみる。
flutter pub run slang
するとlib/i18n/translations.g.dart
というファイルが生成された。出力先と出力ファイル名は設定で変更可能だ。
使ってみる
以下のように生成されたファイルをインポートして使用することができるようになった。機能ごとに切ったディレクトリ名を名前空間として持つこともできるようになっており、引数も渡すことができる。
import 'package:hoge/i18n/translations.g.dart';
final header = t.feature1.header;
final content = t.feature1.content(content: 'content');
context
を必要としないので元々のAppLocalizations
よりもかなり使いやすいように思われる。
ちなみにこのt
という変数も設定で変更できる。機能も設定も豊富にできるのでREADMEにぜひ読んでみてほしい。
わかっていないこと
これで当初やりたかったことは全てできたが、1つだけわからないことがある。
今まではアプリの起動中に端末の設定で言語を変更してアプリに戻った際に再描画が走って新しい言語が反映されていたが、slangを入れてからは再描画がされなくなってしまった。
設定の見落としかと思ってドキュメントを読んでみたが、それらしいものは見当たらなかった。詳しい方がいたら教えていただけると嬉しい。
おわり
以上で機能ごとのファイルの分割もyamlでの記述も可能になり、かなり開発がしやすくなったように思う。
アプリを多言語対応する予定があって、今後機能追加の予定があるのであれば最初からファイルの分割は対応しておいた方が後々が楽なように思った。多言語対応用のファイルの管理にお困りの方の助けになれば幸いだ。