Open27

Flutterの日本語のみ対応アプリに英語対応を追加してみる

ころむにーころむにー

pubspec.yaml に以下が記載されていることを確認。

pubspec.yaml
# ...

dependencies:
  # ...
  flutter_localizations:
    sdk: flutter
  # ...
  intl: 0.18.1
  # ...
ころむにーころむにー

大元のMaterialAppを修正。

lib/root_app.dart
    return MaterialApp(
      // ...
      localizationsDelegates: const [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: const [
+        Locale('en'),
        Locale('ja', 'JP'),
      ],
      // ...
    );
ころむにーころむにー

pubspec.yamlgenerate を追加。

pubspec.yaml
// ...

flutter:
  uses-material-design: true
+  generate: true
  // ...
ころむにーころむにー

lib/l10n/app_en.arblib/l10n/app_ja.arb を作成し、以下のように作成。

lib/l10n/app_en.arb
{
  "appTitle": "App title"
}
lib/l10n/app_ja.arb
{
  "appTitle": "アプリタイトル"
}
ころむにーころむにー

この状態で一旦アプリをデバッグ実行し、${FLUTTER_PROJECT}/.dart_tool/flutter_gen/gen_l10n が生成された状態にする。

ころむにーころむにー

ローカライゼーションのデリゲートを追加する。自動生成されているものを指定する。

lib/root_app.dart
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';

// ...
    return MaterialApp(
      // ...
-      localizationsDelegates: const [
-        GlobalMaterialLocalizations.delegate,
-        GlobalWidgetsLocalizations.delegate,
-        GlobalCupertinoLocalizations.delegate,
-      ],
+      localizationsDelegates: AppLocalizations.localizationsDelegates,
-      supportedLocales: const [
-        Locale('en'),
-        Locale('ja', 'JP'),
-      ],
+      supportedLocales: AppLocalizations.supportedLocales,
      // ...
    );
ころむにーころむにー

あとは、元々直書きしてあった日本語のテキストにラベルのキー名を定義しつつ lib/l10n/app_ja.arb に転記し、lib/l10n/app_en.arb に英語版を定義していく。

ころむにーころむにー

日本語で 保存期限: 2024/3/1 のようになっているところは、英語で Accessible until 1/3/2024 のようにしてみた。
日付の部分 1/3/2024 は、Intlのパッケージが自動で変換している。

ころむにーころむにー

1.03秒 みたいな、小数点第n位まで表示する+多言語化する文字列という構造は以下のように整理するのが良さそう。

  • 「小数点第n位まで表示する」部分はDartで実現
  • 「小数点第n位まで表示された文字列」を前提に「多言語化する文字列」をarbファイルで表現
app_ja.arb
{
  "@@locale": "ja",
  "nSeconds": "{seconds}秒",
  "@nSeconds": {
    "placeholders": {
      "seconds": {
        "type": "String"
      }
    }
  }
}
screen.dart
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

// ...

const durationSeconds = 1.03;
final durationSecondsString = durationSeconds.toStringAsFixed(3);
final durationText = Text(
  AppLocalizations.of(context)!.nSeconds(durationSecondsString),
  style: Theme.of(context).textTheme.bodySmall,
);
ころむにーころむにー

文字列の途中に太字を使うようなリッチテキストはarbファイルで表現できないので、多言語化する場合はリッチテキストはやめるのが一番簡単そう。つまり、1パラグラフ中の一部分を太字とするような仕様をやめ、1パラグラフ中の全ての文字は均一のスタイルにする。

ころむにーころむにー

あとは以下を対応する必要がある。

  • サーバーから取得できるデータ
  • 利用規約とプライバシーポリシー
  • ストアのメタデータとスクリーンショット
  • ストアに登録している課金アイテム
ころむにーころむにー

iOSのApp Storeのデータを多言語化する。

まず、ストアに設定済みの日本語のスクリーンショットとメタデータを、ローカルにダウンロードする。

https://docs.fastlane.tools/actions/upload_to_app_store/

bundle exec fastlane deliver download_screenshots --use_live_version true

App Store上でバージョンを新規作成し、編集中のバージョンが存在する状態にしてから、以下コマンドを実行する。

bundle exec fastlane deliver download_metadata

(記載途中)

ころむにーころむにー

iOSアプリのネイティブに持っているローカライズできる要素を多言語化する。

  • アプリの表示名
  • ビルド時のIPAファイル名
  • 権限取得時のユーザーに表示するメッセージ

以下を元に実施することで問題なくできた。

https://qiita.com/Se1getsu/items/71931162f88e7d9a769b

この際、xcstringsのファイル名は大文字・小文字も厳密に InfoPlist.xcstrings と一致する必要がある。一致していない場合、多言語化が発動しない。

ころむにーころむにー

Androidアプリのネイティブに持っているローカライズできる要素を多言語化する。

  • アプリの表示名

app/src/main/res/values-ja/strings.xml を追加して日本語を定義し、 app/src/main/res/values/strings.xml に英語を定義しておく。

ころむにーころむにー

端末の言語設定に応じた言語コードを取得し、サーバーから取得しているデータの言語データを選択したい。

以下を元にすると、 ja_JP における言語コード ja 部分は取得できるが、国コード JP 部分が null
になって取得できない。

final locale = Localizations.localeOf(context);
debugPrint(
  'Locale ${locale.toLanguageTag()} '
  'Language code: ${locale.languageCode}, '
  'Country code: ${locale.countryCode}',
);
I/flutter (10831): Language tag: ja Language code: ja, Country code: null

https://blog.okaryo.io/20221002-get-language-setting-in-device-with-flutter

ころむにーころむにー

以下のようにすると取得できた。

-final locale = Localizations.localeOf(context);
+final locale = WidgetsBinding.instance.platformDispatcher.locale;
debugPrint(
  'Language tag: ${locale.toLanguageTag()} '
  'Language code: ${locale.languageCode}, '
  'Country code: ${locale.countryCode}',
);
I/flutter (10831): Language tag: ja-JP Language code: ja, Country code: JP
ころむにーころむにー

デバイスロケールの変化をリアルタイムに取得するためには、 MaterialApp の中のウィジェットで、didChangeDependencies のイベントを利用する。
MaterialApp と同列の didChangeDependencies では変化がキャッチできない。

ころむにーころむにー

言語設定だけでなく、世界中で利用できるようにする場合は、以下のような地域によって変化する概念に関しても整理が必要。

  • 時刻
  • 曜日
  • ものの単位(温度、重さとか)
ころむにーころむにー

ストアのメタデータに関しては、以下がローカライズデータの必須情報

iOS

項目 fastlane のファイル名
アプリ情報 > 名前 fastlane/metadata/en-US/name.txt
アプリ情報 > サブタイトル fastlane/metadata/en-US/subtitle.txt
バージョン > 概要 fastlane/metadata/en-US/description.txt
バージョン > このバージョンの最新情報 fastlane/metadata/en-US/release_notes.txt
バージョン > キーワード fastlane/metadata/en-US/keywords.txt
バージョン > サポート URL fastlane/metadata/en-US/support_url.txt
ころむにーころむにー

Android

項目 fastlane のファイル名
メインのストアの掲載情報 > アプリ名 fastlane/metadata/en-US/title.txt
メインのストアの掲載情報 > 簡単な説明 fastlane/metadata/en-US/short_description.txt
メインのストアの掲載情報 > 詳しい説明 fastlane/metadata/en-US/full_description.txt
製品版 > リリースノート fastlane/metadata/en-US/changelogs/default.txt
ころむにーころむにー

iOSでは、一旦英語版のスクリーンショットを提出して審査通す必要がありそう。