こんにちは。広瀬マサルです。
みなさん多言語化ってどうしてますか?
僕もいろいろなフレームワークで様々な多言語化パッケージを使ってきましたがどうもイマイチな結果になることが多かったです。
なので、自分で新しいFlutterパッケージを作ってみました。
一言で簡単に言うと
Googleスプレッドシートから自動でコード生成し直感的に使える多言語化パッケージ
です。
翻訳を行うにあたって非常に便利なGoogleスプレッドシートからbuild_runnerを使ってコードジェネレーションを行いタイプセーフに翻訳済みのテキストを入力できます。
テキストの入力も非常に直感的に使えるようにしているので、もしかしたらこれまでの多言語化パッケージでは味わえなかった文字入力のスムーズさを出せるかもしれません。(あくまで可能性です)
使い方をまとめたので興味ある方はぜひ使ってみてください!
katana_localization
はじめに
多言語化パッケージは、基本的に下記のような特徴を備えているかと思います。
- 特定のキーとそれに対応した翻訳テキスト定義したファイルを作成
- 実装時に特定のキーを指定して現在のロケールにおける一致したテキストを抽出して表示
このとき、僕は下記の現象に悩まされてました。
-
実装時にどのキーが定義されているかが定義ファイルを毎回確認する必要がある
- どのキーが定義されているかがわからないので違うキーで重複して同じ翻訳テキストを定義することがあった
- キーをタイポして翻訳が正常に行われないことがある
- 翻訳をお願いするにあたってファイルを共有して構造を説明するのが面倒
- 翻訳を自動翻訳で済ませたい場合があるがそれを行うのも面倒
- BuildContextを使わないとアクセスできない場合がある
-
翻訳テキスト中に変数を入れたい場合に大抵の場合、後から値を注入する形になるので分かりづらい。
print( sprintf(localize("%s of the %s, by the %s, for the %s"), ["Government", "people", "people", "people"]) );
なので上記を解消するため下記の機能を有するパッケージを作成しました。
-
Googleスプレッドシートで翻訳データを作成する
- 翻訳をお願いするときにシートを共有するだけで良い
- キーと翻訳テキストが同一行にあるので、キーとテキストの対応がわかりやすい。そのため翻訳を依頼するときに説明が不要
-
GOOGLETRANSLATE
関数を用いることで簡単に自動翻訳が可能
-
build_runnerを使ってコードジェネレーションを行う
- IDEのサジェスト機能により用意されているキーを確認することができる
- タイプセーフで入力できるのでタイポしない
-
変数を利用する場合メソッドチェーンを利用することで文章の順番を崩さずに変数の入力をすることが可能
- 下記のように書けます。
print( l().$("Goverment").ofThe.$("People").byThe.$("People").forThe.$("People") );
- 言語を変更が容易。変更を検知しアプリ自体の描画を再更新できる。
- BuildContextを使わずともどこからでもアクセスが可能。
インストール
build_runnerを用いたコードジェネレーションを行うため下記のパッケージをインポートします。
flutter pub add katana_localization
flutter pub add --dev build_runner
flutter pub add --dev katana_localization_builder
事前準備
事前にGoogleスプレッドシートを利用可能にします。
-
こちらのテンプレートからスプレッドシートを自分のGoogleドライブにコピーします。
-
ファイル
->コピーの作成
からコピーが可能です。
-
-
コピーしたスプレッドシート内で
ファイル
->共有
->他のユーザーと共有
をクリックします。 -
(作成したスプレッドシート名)を共有
ウィンドウ内で、一般的なアクセス
をリンクを知っている全員
に変更します。
Googleスプレッドシートの記述方法
Googleスプレッドシートは一番左の列がキー
となり、各行のキーに対応する翻訳テキストを2行目にあるロケールに従い記載します。
キーのプレフィックスに#
をつけるとその行は読み込まれません。コメント等にお使いください。
変数を用いる場合
キーに{変数名}
を入力することでそこに変数を埋め込むことができます。
翻訳テキストにも同じ{変数名}
を記載することで同じ変数名に対応する値が埋め込まれて表示されます。
実装
定義ファイル作成
localization.dart
などのDartファイルを作成します。
part ‘元のファイル名.localize.dart’;
でPartファイルをインポートします。
そこにGoogleSpreadSheetLocalize
のアノテーションを付与したクラスを作成します。
クラス名は自由ですが必ず_$(定義したクラス名)
をextendsしてください。
GoogleSpreadSheetLocalize
のパラメーターには上で用意したGoogleスプレッドシートのURL(例:https://docs.google.com/spreadsheets/d/1bw7IXEr7BGkZ4U6on0OuF7HQkTMgDSm6u5ThpBkDPeo/edit#gid=551986808)をそのままコピーして貼り付けてください。
配列として複数のURLを貼り付けることができます。その場合すべてのスプレッドシートのデータが適用されます。(後に読み込まれたデータが優先)
基本的な翻訳をベースのスプレッドシートとして指定し、その上からアプリごとに異なる翻訳データを追加で指定することが可能です。
通常はダウンロードしたスプレッドシートの内容はキャッシュされますが、version
をインクリメントすることにより新しい内容に更新することができます。
さらにそのクラスを利用するためのトップレベルのフィールドを定義します。フィールド名は短いほうが後で利用しやすくなります。
// localization.dart
import 'package:katana_localization/katana_localization.dart';
part ‘localization.localize.dart’;
@GoogleSpreadSheetLocalize(
[
"https://docs.google.com/spreadsheets/d/1bw7IXEr7BGkZ4U6on0OuF7HQkTMgDSm6u5ThpBkDPeo/edit#gid=551986808",
],
verions: 1,
)
class AppLocalize extends _$AppLocalize { }
final l = AppLocalize();
MaterialAppへの翻訳データの登録
上記で作成したAppLocalize
クラスのオブジェクトを利用してLocalizeScope
とMaterialApp
を定義します。
LocalizeScopeのlocalize
に先程作成したAppLocalize
のオブジェクトを渡し、builder
にMaterialApp
を配置します。
MaterialAppのlocale
、localizationsDelegates
、supportedLocales
、localeResolutionCallback
にAppLocalize
のメソッドやフィールドを渡してください。
// main.dart
import 'package:flutter/material.dart';
import 'localization.dart';
void main() {
runApp(const MainPage());
}
class MainPage extends StatelessWidget {
const MainPage({super.key});
@override
Widget build(BuildContext context) {
return LocalizeScope(
localize: l,
builder: (context, localize)
return MaterialApp(
locale: localize.locale,
localizationsDelegates: localize.delegates(),
supportedLocales: localize.supportedLocales(),
localeResolutionCallback: localize.localeResolutionCallback(),
title: "Test App",
);
},
);
}
}
コードジェネレーション
下記のコマンドを入力することで自動でコード生成を行います。
flutter pub run build_runner build --delete-conflicting-outputs
連続でコマンドを実行する場合、キャッシュが残って翻訳が反映されないことがあるのでその際は事前に下記のコマンドを入力してください。
flutter pub run build_runner clean
利用方法
翻訳テキストの取得
AppLocalize
のオブジェクトをメソッドとして実行することで翻訳オブジェクトを取得することができます。
翻訳オブジェクトには、Googleスプレッドシートで定義されたキーがそのままフィールドやメソッドとして定義されているため下記のようにして翻訳テキストを取得することができます。
print( l().user ); // English: User、日本語: ユーザー
変数を利用する場合は$(入力値)
のメソッドが用意されているのでそこに値を入力します。
また、その入力値にも翻訳オブジェクトを指定することが可能です。
print( l().$( l().saving ).hasBeenCompleted );
// English: Saving has been completed.
// 日本語: 保存が完了しました。
print(
l().$(
l().$( l().saving ).of.$( l().data )
).hasBeenCompleted
);
// English: Saving of Data has been completed.
// 日本語: データの保存が完了しました。
現在の言語の取得と変更
現在の言語の取得はAppLocalizeのlocale
プロパティで可能です。
また、言語の変更はAppLocalizeのsetCurrentLocale
メソッドで可能です。
Googleスプレッドシートで定義したロケールで利用可能な言語のみに変更されます。
それ以外は変更されません。
setCurrentLocale
が実行されロケールの変更に成功した場合、LocalizeScope
が再ビルドされます。また、AppLocalize自体がChangeNotifierであるためaddListener
で変更を監視することでその他の場所でも変更を検知した処理を実装することが可能です。
おわりに
自分で使う用途で作ったものですが実装の思想的に合ってそうならぜひぜひ使ってみてください!
また、こちらにソースを公開しているのでissueやPullRequestをお待ちしてます!
また仕事の依頼等ございましたら、私のTwitterやWebサイトで直接ご連絡をお願いいたします!
GitHub Sponsors
スポンサーを随時募集してます。ご支援お待ちしております!