2021/1/8追記
現在はarbファイルからdartファイルを生成してくれるようになっていて結構楽になったようです。
以下は当時の手順
公式のチュートリアルを参考にして、Flutterアプリのテキストのローカライズ方法を説明します。
flutter_localizations, intl, intl_translation
を依存関係に追加します。
dependencies:
flutter:
sdk: flutter
# 追記ここから
flutter_localizations:
sdk: flutter
intl:
intl_translation:
# 追記ここまで
次のコマンドで依存関係を解決します。
cd <プロジェクトのルートディレクトリ>
flutter pub get
次のコマンドを実行して、intl_messages.arb
messages_all.dart
messages_messages.dart
を生成します。 intl_messages.arg
がjson形式の翻訳定義ファイルになりますが、今は翻訳対象のリソースが指定されていないので大した内容はありません。このコマンドを一度実行するのはdart
ファイルを生成したいためです。
mkdir -p lib/l10n
flutter pub pub run intl_translation:extract_to_arb --output-dir=lib/l10n lib/main.dart
プログラムで使用されているIntl.message
からリソースファイルを生成するため、先に翻訳リソースを使用する部分を記述しておきます。このシンプルな例では Hello World
を出力するtitle
という名前のリソースが生成されます。
そのためにlib/main.dart
に以下のクラスを追加します。
class DemoLocalizations {
static Future<DemoLocalizations> load(Locale locale) {
final String name = locale.countryCode.isEmpty
? locale.languageCode
: locale.toString();
final String localeName = Intl.canonicalizedLocale(name);
return initializeMessages(localeName).then((_) {
Intl.defaultLocale = localeName;
return new DemoLocalizations();
});
}
static DemoLocalizations of(BuildContext context) {
return Localizations.of<DemoLocalizations>(context, DemoLocalizations);
}
String get title {
return Intl.message(
'Hello World',
name: 'title',
desc: 'Title for the Demo application',
);
}
}
そしてもう一度arbファイルの生成コマンドを実行します。
flutter pub pub run intl_translation:extract_to_arb --output-dir=lib/l10n lib/main.dart
するとl10n/intl_messages.arb
は次のような内容になります。title
の定義が追加されました。
{
"@@last_modified": "2018-04-06T20:58:49.424203",
"title": "Hello World",
"@title": {
"description": "Title for the Demo application",
"type": "text",
"placeholders": {}
}
}
このl10n/intl_messages.arb
をコピーしてl10n/intl_en.arb
とl10n/intl_ja.arb
を作ります。
内容はそれぞれ次のようになります。単純に翻訳しているだけですね。
{
"title": "Hello World",
"@title": {
"description": "Title for the Demo application",
"type": "text",
"placeholders": {}
}
}
{
"title": "こんにちは世界",
"@title": {
"description": "Title for the Demo application",
"type": "text",
"placeholders": {}
}
}
ここまでファイルの準備ができたら以下のコマンドを実行します。
flutter pub pub run intl_translation:generate_from_arb --output-dir=lib/l10n --no-use-deferred-loading lib/main.dart lib/l10n/intl_*.arb
すると l10n/messages_en.dart
と l10n/messages_ja.dart
という2つのdartファイルが生成されます。
l10n/messages_ja.dart
の内容は次のようになっており、先ほど作成したリソースファイルがdartのクラスとして生成されたことがわかります。
// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
// This is a library that provides messages for a ja locale. All the
// messages from the main program should be duplicated here with the same
// function name.
import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';
final messages = new MessageLookup();
// ignore: unused_element
final _keepAnalysisHappy = Intl.defaultLocale;
// ignore: non_constant_identifier_names
typedef MessageIfAbsent(String message_str, List args);
class MessageLookup extends MessageLookupByLibrary {
get localeName => 'ja';
final messages = _notInlinedMessages(_notInlinedMessages);
static _notInlinedMessages(_) => <String, Function> {
"title" : MessageLookupByLibrary.simpleMessage("こんにちは世界")
};
}
次にMaterialApp
のインスタンス生成部分を次のように変更します。
return new MaterialApp(
title: "AppName",
home: new Invite(),
// ここから追記
localizationsDelegates: [
const DemoLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale("en", "US"),
const Locale("ja", "JP")
],
// ここまで追記
);
DemoLocalizationsDelegate
は今回のローカライズのためのDelegateです。
GlobalMaterialLocalizations.delegate
は多分組み込みのローカライズのもの?日付のフォーマットなどが管理されている。
GlobalWidgetsLocalizations
はウィジェットをローカライズするために必要?右から書く言語とかに対応するためにいるのか?
supportedLocaled
は対応言語のリストですかね。
このあたり必要性がよくわかっていないのですが、書かなかったら動かなかったので、必要なんでしょう。
main.dart
には先ほどのDelegateも追加しておきます。
class DemoLocalizationsDelegate
extends LocalizationsDelegate<DemoLocalizations> {
const DemoLocalizationsDelegate();
@override
bool isSupported(Locale locale) => ['en', 'ja'].contains(locale.languageCode);
@override
Future<DemoLocalizations> load(Locale locale) =>
DemoLocalizations.load(locale);
@override
bool shouldReload(DemoLocalizationsDelegate old) => false;
}
ここまでやってリビルドするとローカライズされたテキストを出力することができます。
英語 | 日本語 |
---|---|
感想
現時点では手順が少し面倒に感じますね。
ただintlを使用しないで直接マップをコードに書く方法もあったりして、選択するライブラリ次第では改善出来るのかもしれません。
そして使用する画面毎にクラスを分けたほうがいいのか。巨大な1つの言語リソース用のクラスを作っておくのか悩ましいところです。
クラス定義して関数まで作っておく必要があるのが、ちょっとしんどい。それをもとにarb作って、またdartのクラスが生成されてって感じなので。
まぁまずは使い続けてみることで自分なりの解決策が見つかるかもしれないので、気長に使ってみます。