🌊

Flutterアプリを多言語化する方法(作業時間:10分)

2023/08/17に公開
2

多言語化とは

アプリのユーザーが、そのアプリ内で使用する言語を選択できる機能を追加すること。
以下のアプリの海外展開(主に韓国)を考え、初めてFlutterで多言語化対応をしてみました。
初心者がやると少々ハマることがあると思うので忘備録として本記事を作成。

https://apps.apple.com/jp/app/where-is-ガチャ/id6454934831
https://play.google.com/store/apps/details?id=com.ta.googlemap

本記事通りに手順を進めると、以下2点の機能をご自身のアプリに導入することが出来ます。
①多言語化の設定方法について
②設定した言語の保存

上記の機能は上で紹介したアプリに導入済みなので、
ダウンロードして動きを見ていただければ幸いです。

多言語化対応①「必要パッケージの追加」

以下3つのパッケージを追加するのですが、pubspec.yaml内の指定箇所に配置しないといけません。
よって、今回はpubspec.yaml内に直接書き込み→「flutter pub get」の流れで追加したほうが良いです。

https://docs.flutter.dev/ui/accessibility-and-internationalization/internationalization
https://pub.dev/packages/intl
https://pub.dev/packages/shared_preferences

以下のコードを参考に「これを追記」の箇所を追加して「flutter pub get」をしてください。

pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  flutter_localizations: //これを追記
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  shared_preferences: ^2.1.2 //これを追記
  intl: ^0.18.0 //これを追記
  

dev_dependencies:
  flutter_test:
    sdk: flutter

  # The "flutter_lints" package below contains a set of recommended lints to
  # encourage good coding practices. The lint set provided by the package is
  # activated in the `analysis_options.yaml` file located at the root of your
  # package. See that file for information about deactivating specific lint
  # rules and activating additional ones.
  flutter_lints: ^2.0.0

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

# The following section is specific to Flutter packages.
flutter:
  generate: true //これを追記

多言語化対応②「多言語対応の設定」

以下の手順を実施します。

①libディレクトリ配下に、l10nディレクトリを作成(下図を参照ください)

②「l10nディレクトリ」中に「app_[言語].arbファイル」を用意する言語分作成する
※英語なら、ファイル名を「app_en.arb」とします
※上図では、英語・日本語・韓国語の3ヶ国語分のファイルを作成しています

下記の文字コード表を参考にファイル名を決定していく。

以下を参考にarbファイルの中身を作成してください。

英語ファイル

app_en.arb
{
  "@@locale":"en",
  "title":"Capsule Toy × Map",
  "ratethisapp": "Rate this app",
  "privacypolicy": "Privacy Policy"
}

日本語ファイル

app_ja.arb
{
  "@@locale":"ja",
  "title":"ガチャ × Map",
  "ratethisapp": "このアプリをレビューする",
  "privacypolicy": "プライバシーポリシー"
}

韓国語ファイル

app_ko.arb
{
  "@@locale":"ko",
  "title":"캡슐 토이 × 지도",
  "ratethisapp": "이 앱 리뷰",
  "privacypolicy": "개인 정보 보호 정책"
}

多言語化対応③「.dart_tool/flutter_gen/gen_l10nへファイル自動生成」

以下のコマンドをターミナルで実行してください。

flutter gen-l10n

実行後に「.dart_tool/flutter_gen/gen_l10n」配下に下の3つのファイルが作成されていればOKです。(下図を参照ください)
1.app_localizations_en.dart
2.app_localizations_ja.dart
3.app_localizations_ko.dart
4.app_localizations.dart

作成されていたら、「flutter pub get」してください。

flutter pub get

ここまで完了していれば、多言語か対応はほぼ完了したも同然です。
最後は用意した言語ファイルをアプリ内で利用していく方法を紹介します。

多言語化対応④「アプリへの実装」

まず、MaterialApp中のコードを以下のように変更してください。
※main.dartで、import 'package:flutter_gen/gen_l10n/app_localizations.dart';が使えるか確認してください(私が初めて実装した時はできなかったのでこちらのサイトを参考にしてみました)

main.dart
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_localizations/flutter_localizations.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  static void setLocale(BuildContext context, Locale newLocale) {
    _MyAppState state = context.findAncestorStateOfType<_MyAppState>()!;
    state.setLocale(newLocale);
  }

  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
//多言語化対応コード
  Locale? locale;

  @override
  void initState() {
    super.initState();
    _loadSavedLanguage(); // 保存された言語を読み込む
  }

  void setLocale(Locale newLocale) {
    setState(() {
      locale = newLocale;
    });
  }

  void _loadSavedLanguage() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String? savedLanguageCode = prefs.getString('languageCode');
    if (savedLanguageCode != null) {
      setState(() {
        locale = Locale(savedLanguageCode);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      localizationsDelegates: AppLocalizations.localizationsDelegates, // 追加
      // supportedLocales: AppLocalizations.supportedLocales,
      supportedLocales: const [
        Locale('en'),
        Locale('ja'),
        Locale('ko'),
      ],
      locale: locale, // 現在の言語設定を反映
      home: MapPage(
        title: '',
      ),
    );
  }
}

あとは必要に応じて、言語選択をする画面を用意します。
この画面ではユーザーが使用したい言語を選択すると、選択した言語を「shared_preferences」で保存します。

以下のコードを参考にご自身のアプリにあった形で実装ください。
※下記コード中には「flutter_riverpod」を入れていますので、そのままコピペをしてもエラーになります

SettingsLanguage.dart
import 'package:flutter/material.dart';
import 'package:googlemap/main.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

class SettingsPage2 extends ConsumerStatefulWidget {
  @override
  _SettingsPage2State createState() => _SettingsPage2State();
}

class _SettingsPage2State extends ConsumerState<SettingsPage2> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        flexibleSpace: Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              colors: [Colors.blueAccent, Colors.deepPurple],
            ),
          ),
        ),
        title: Text(
          '言語設定',
          style: TextStyle(
            fontWeight: FontWeight.bold,
            fontSize: 22.0,
            color: Colors.white,
          ),
        ),
      ),
      body: ListView(
        children: [
          ListTile(
            title: Text('English'),
            onTap: () {
              _changeLanguage(context, 'en');
            },
          ),
          ListTile(
            title: Text('日本語'),
            onTap: () {
              _changeLanguage(context, 'ja');
            },
          ),
          ListTile(
            title: Text('한국어'),
            onTap: () {
              _changeLanguage(context, 'ko');
            },
          ),
        ],
      ),
    );
  }

  void _changeLanguage(BuildContext context, String languageCode) async {
    Locale newLocale = Locale(languageCode);

// 言語を保存する
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString('languageCode', languageCode);

    MyApp.setLocale(context, newLocale); // MyApp内のsetLocaleメソッドを呼び出し
    setState(() {
      // Now_location = placeMark.locality ?? "現在地データなし";
      ref.read(useLanguage.notifier).state = languageCode;
      print('現在のlanguageCodeは、$languageCode');
    });

    Navigator.pop(context); // メニューを閉じる
  }
}

最後に多言語化対応させたい文字の表記は下記のように実装します。

 title: Text(AppLocalizations.of(context)!.privacypolicy), //日本語選択なら「プライバシーポリシー」と表示される

まとめ

多言語化したいワードを増やす場合は上記手順の、

1.多言語化対応②「多言語対応の設定」→ 各言語ファイル内へ追加したいワードの追加
2.多言語化対応③「.dart_tool/flutter_gen/gen_l10nへファイル自動生成」→ コマンド実行・ファイル自動生成

を行なっていただくと適宜追加することが出来ます。

(最後にソッといいねボタンやバッジを贈るボタンを押して頂けたら幸いですm(_ _)m)

Discussion

minami0810stsminami0810sts

情報ありがとうございます。
アムロさんが実際に使用されている flutter_localizations と、リンク先の flutter_localization (末尾に s がつかない) は別物かと思いますが認識合いますでしょうか?
リンク先の flutter_localization は非公式ライブラリ、flutter_localizations は公式ライブラリの理解です

ライナー・ブラウンライナー・ブラウン

コメントいただきありがとうございます!
ご指摘のとおりflutter_localizationは誤りで、正しくはflutter_localizationsを利用しておりました。