この記事はFlutter 3.24を前提にしています。
基本的なFlutterプロジェクトは作成済みとします。
アプリを作るとき、世界中のユーザーに向けて多言語対応が必要になる場合があります。今回はFlutterアプリの言語パックを作ります。
プロジェクトのルートで、次のコマンドを実行します。
flutter pub add easy_localization
すると pubspec.yaml に次のコードが追加されます。
dependencies :
easy_localization : version
プロジェクトのルートに、次のようにJSON形式の言語パックを作ります。筆者は英語と韓国語に対応するため、2つのファイルを用意しました。今回使う構成は次のとおりです。先に作っておくと便利です。
📦 assets
┣ 📂 translations
┃ ┣ 📜 en_US.json
┗ ┗ 📜 ko_KR.json
📦 lib
┣ 📜 home_page.dart
┗ 📜 main.dart
ファイル名には言語コードを使います。例えば英語は
en_US.json、韓国語は
ko_KR.json です。地域コードを使う場合は、ファイル名に含めます。例えば米国英語は
en_US.json です。
JSON、CSV、HTTP、XML、YAMLなどがサポートされています。詳細は
Easy Localization Loaderの公式ドキュメント↗ を参照してください。
pubspec.yaml に次のコードを追加します。
assets :
- assets/translations/
ios/Runner/Info.plistの <dict> 内に、次のコードを追加します。
...
< key >CFBundleLocalizations</ key >
< array >
< string >en_US</ string >
< string >ko_KR</ string >
</ array >
...
言語パックを使う前に、初期化と設定を行います。
/lib/main.dart import 'package:flutter/material.dart' ;
import 'package:easy_localization/easy_localization.dart' ;
import 'package:example_project/home_page.dart' ;
void main () async {
WidgetsFlutterBinding . ensureInitialized ();
await EasyLocalization . ensureInitialized (); // 언어 팩 초기화
runApp (
EasyLocalization (
// 언어 팩 설정
supportedLocales : const [ Locale ( 'en' , 'US' ), Locale ( 'ko' , 'KR' )],
path : 'assets/translations' ,
fallbackLocale : const Locale ( 'en' , 'US' ), // 휴대폰 설정이 없을 시 기본 언어
child : const MyApp ()),
);
}
class MyApp extends StatelessWidget {
const MyApp ({ super .key});
@override
Widget build ( BuildContext context) {
return MaterialApp (
localizationsDelegates : context.localizationDelegates,
supportedLocales : context.supportedLocales,
locale : context.locale,
home : const HomePage ());
}
}
キーと値を追加するだけです。次のように書きます。
assets/translations/en_US.json {
"hello" : "Hello, world!"
}
assets/translations/ko_KR.json
言語パックのデータを使うには、context.tr()を呼びます。ほかの方法も使えますが、ライブラリのドキュメントではcontext.tr()が推奨されています。
/lib/home_page.dart import 'package:easy_localization/easy_localization.dart' ;
import 'package:flutter/material.dart' ;
class HomePage extends StatelessWidget {
const HomePage ({ super .key});
@override
Widget build ( BuildContext context) {
return Scaffold (
appBar : AppBar (
title : const Text ( 'Home' ),
),
body : Center (
child : Column (
mainAxisAlignment : MainAxisAlignment .center,
children : [
Text (
context. tr ( 'hello' ), // 언어 팩 데이터 사용
style : const TextStyle (fontSize : 20 ),
),
ElevatedButton ( // 한국어 버튼
onPressed : () {
context. setLocale ( const Locale ( 'ko' , 'KR' ));
},
child : const Text ( '한국어' ),
),
ElevatedButton ( // 영어 버튼
onPressed : () {
context. setLocale ( const Locale ( 'en' , 'US' ));
},
child : const Text ( '영어' ),
),
],
),
),
);
}
}
言語パックの使用例
文字列に引数を埋め込みたい場合は、2つの方法が使えます。
assets/translations/en_US.json {
"hello" : "Hello, {}!" ,
"hello_friends" : "Hello, {}, {}!" ,
"hello_name" : "Hello, {name}!" ,
"hello_name_age" : "Hello, {name}! You are {age} years old." ,
"hello_friends_name" : "Hello, {}, {name}!" ,
}
/lib/home_page.dart // ...
context. tr ( 'hello' , args : [ 'John' ]);
context. tr ( 'hello_friends' , args : [ 'John' , 'Jane' ]);
context. tr ( 'hello_name' , namedArgs : { 'name' : 'John' });
context. tr ( 'hello_name_age' , namedArgs : { 'name' : 'John' , 'age' : 20 });
context. tr ( 'hello_friends_name' , args : [ 'John' ], namedArgs : { 'name' : 'Jane' });
// ...
このライブラリは、性別による切り替えにも対応しています。個人的には、あまり使う機会はなさそうです。
assets/translations/en_US.json {
"gender" :{
"male" : "Hi man ;) {}" ,
"female" : "Hello girl :) {}" ,
"other" : "Hello {}"
}
}
/lib/home_page.dart // ...
context. tr ( "gender" , gender : _gender ? "female" : "male" );
// ...
単数形と複数形にも対応しています。これは役に立ちそうです。
assets/translations/en_US.json {
"money" : {
"zero" : "You not have money" ,
"one" : "You have {} dollar" ,
"many" : "You have {} dollars" ,
"other" : "You have {} dollars"
},
"money_named_args" : { // 이름 지정
"zero" : "{name} has no money" ,
"one" : "{name} has {money} dollar" ,
"many" : "{name} has {money} dollars" ,
"other" : "{name} has {money} dollars"
}
}
/lib/home_page.dart // ...
context. plural ( 'money' , 0 );
context. plural ( 'money' , 1 );
context. plural ( 'money' , 2 );
context. plural ( 'money_named_args' , 10.23 , namedArgs : { 'name' : 'Jane' }, name : 'money' ) // 이름 지정
// ...
単数形と複数形の切り替え例
キーを階層に分けられます。筆者が最もよく使う機能です。
親のキーの後ろに
. を付け、子のキーを続けます。同じ階層のデータを参照するには、言語パック内で
@: を使います。
assets/translations/en_US.json {
"example" : {
"hello" : "Hello" ,
"world" : "World!" ,
"helloWorld" : "@:example.hello @:example.world" // 이렇게 사용합니다.
}
}
/lib/home_page.dart // ...
context. tr ( 'example.hello' ); // 결과: Hello
context. tr ( 'example.world' ); // 결과: World!
context. tr ( 'example.helloWorld' ); // 결과: Hello World!
// ...
端末の既定の言語に戻したい場合は、次のコードを使います。
/lib/home_page.dart // ...
context. resetLocale ();
// ...
言語設定を確認するには、次のコードを使います。
/lib/home_page.dart // ...
context.deviceLocale. toString () // 결과: en_US
// ...
上のコードにも出てきましたが、言語を変更するときは次のコードを使います。
/lib/home_page.dart // ...
context. setLocale ( Locale ( 'ko' , 'KR' )); // 한국어로 설정
// ...
インストール時にintlのバージョンで問題が起きる 🔗
Note: intl is pinned to version 0.19.0 by flutter_localizations from the flutter SDK.
See https://dart.dev/go/sdk-version-pinning for details.
The current Dart SDK version is 3.5.4.
Because easy_localization > =2.3.4-nullsafety < 3.0.0-dev.0 depends on flutter_localizations from sdk and easy_localization > =3.0.0-dev.0 < 3.0.0-nullsafety doesn't support null safety,
easy_localization >=2.3.4-nullsafety <3.0.0-nullsafety requires flutter_localizations from sdk.
And because easy_localization <2.3.4-nullsafety doesn't support null safety, easy_localization < 3.0.0-nullsafety requires flutter_localizations from sdk.
And because easy_localization > =3.0.0-nullsafety depends on flutter_localizations from sdk which depends on intl 0.19.0, every version of easy_localization requires intl 0.19.0.
So, because nftcam_flutter depends on both intl ^0.20.1 and easy_localization any, version solving failed.
The lower bound of "sdk: '>=2.0.0-dev.68.0 <3.0.0'" must be 2.12.0 or higher to enable null safety.
For details, see https://dart.dev/null-safety
The lower bound of "sdk: '>=2.7.0 <3.0.0'" must be 2.12.0 or higher to enable null safety.
For details, see https://dart.dev/null-safety
Flutterのチャンネルをmasterに切り替え、アップグレードします。
flutter channel master
flutter upgrade
次のように同期処理に変更すると解決できます。
/lib/home_page.dart // ...
const newLocale = Locale ( 'ko' , 'KR' );
await context. setLocale (newLocale);
Get . updateLocale (newLocale);
// ...
アプリを世界向けに公開する機会があったので、このライブラリを使ってみました。機能が豊富で、使い方も簡単でした。また、調べる途中で見つけた
flutter_localizations_generator↗ を使うと、Googleスプレッドシートで言語パックを管理できるそうです。
企画の時点で海外展開を予定していなくても、言語パックを先に導入しておくと、開発途中で文言を直す際にも便利そうです。今回は規模の大きいプロジェクトの終盤で導入し、苦労しました……😂
Googleスプレッドシートで言語パックを管理するには、どうすればよいでしょうか。
端末の設定と無関係に、アプリの既定の言語を設定できるでしょうか。
main.dartで直接setLocaleを呼べばよいのでしょうか。