今日的程式碼 => GITHUB
這邊我想要介紹如何切換語言、設定 App 初始的語言,且下此開啟 App 時也會記住已經被切換過的語言。
這邊的教學,功能正常,但寫法不一定是最好的。這邊推薦另外的套件
flutter_localizations:
sdk: flutter
shared_preferences: ^2.0.7
- - - - - - - - - - - - - - - - - - - - -
assets:
- language/
建立一個 language 在專案目錄底下建立兩個 Json
{
"name": "flutter_localizations example",
"introduce": "Hello"
}
{
"name": "語言切換範例",
"introduce" : "你好呀"
}
會給予 sharedpreferences
一個預設的語言 data(zh)
,手機一打開時,會在 didChangeDependencies
裡面去讀取 sharedpreferences
,進而去設定 local
的地區是屬於什麼。
supportedLocales
= App 要支援的語言localizationsDelegates
= 委託確保加載正確語言的本地化數據localeResolutionCallback
= 檢查手機是否支援這個語言locale
= 現在手機的語言是什麼AppLocalizations
= 是我們自己建立管理語言的一個 class
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
/// 當地區更改時,重新設定地區,當使用者按下變換語言時,會觸發。
static void setLocale(BuildContext context, Locale newLocale) {
_MyAppState? state = context.findAncestorStateOfType<_MyAppState>();
state!.changeLocale(newLocale);
}
}
class _MyAppState extends State<MyApp> {
Locale _locale = new Locale.fromSubtags(languageCode: 'zh');
/// 更改地區
void changeLocale(Locale locale) {
setState(() {
this._locale = locale;
});
}
@override
void didChangeDependencies() async {
super.didChangeDependencies();
final languageApp = AppLocalizations();
final localeKey = await languageApp.readLocaleKey();
if (localeKey == "en") {
this._locale = new Locale("en", "EN");
} else {
this._locale = new Locale.fromSubtags(languageCode: 'zh');
}
setState(() {});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
supportedLocales: [
Locale('en', 'US'),
const Locale.fromSubtags(languageCode: 'zh'),
],
// These delegates make sure that the localization data for the proper language is loaded
// 委託確保加載正確語言的本地化數據
localizationsDelegates: [
// This class will be added later
// A class which loads the translations from JSON files
AppLocalizations.delegate,
// A class which loads the translations from JSON files
GlobalMaterialLocalizations.delegate,
// Built-in localization of basic text for Material widgets
GlobalWidgetsLocalizations.delegate,
],
locale: _locale,
// Returns a locale which will be used by the app
localeResolutionCallback: (locale, supportedLocales) {
// Check if the current device locale is supported
// 檢查手機是否支援這個語言
for (var supportedLocaleLanguage in supportedLocales) {
if (supportedLocaleLanguage.languageCode == locale?.languageCode &&
supportedLocaleLanguage.countryCode == locale?.countryCode) {
return supportedLocaleLanguage;
}
}
// If device not support with locale to get language code then default get first on from the list
return supportedLocales.first;
},
home: HomePage());
}
}
class AppLocalizations {
final Locale locale;
AppLocalizations({this.locale = const Locale.fromSubtags(languageCode: 'zh')});
/// Helper method to keep the code in the widgets concise
/// Localizations are accessed using an InheritedWidget "of" syntax
/// 訪問本地化
static AppLocalizations? of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
/// 儲存 SharedPreferences
void keepLocaleKey(String localeKey) async {
final _prefs = await SharedPreferences.getInstance();
await _prefs.remove("localeKey");
await _prefs.setString("localeKey", localeKey);
}
/// 讀取 SharedPreferences
Future<String> readLocaleKey() async {
final _prefs = await SharedPreferences.getInstance();
// 初始化最一剛開始的語言
return _prefs.getString("localeKey")??'zh';
}
/// 更改語言,重新設定語言
void setLocale(BuildContext context, Locale locale) async {
// keep value in shared pref
keepLocaleKey(locale.languageCode);
print("key language :${locale.languageCode}");
MyApp.setLocale(context, locale);
}
/// Static member to have a simple access to the delegate from the MaterialApp
/// 提供 Main Page 可以直接訪問。
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
late Map<String, String> _localizedStrings;
/// Load the language JSON file from the "lang" folder
/// 讀取 Json 格式
Future<bool> load() async {
String jsonString =
await rootBundle.loadString('language/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = json.decode(jsonString);
_localizedStrings = jsonMap.map((key, value) {
return MapEntry(key, value.toString());
});
return true;
}
/// This method will be called from every widget which needs a localized text
/// 提供每一個需要轉換語言的文字
String translate(String key) {
return _localizedStrings[key]!;
}
}
/// LocalizationsDelegate is a factory for a set of localized resources
/// In this case, the localized strings will be gotten in an AppLocalizations object
/// 本地化的字符串將在 AppLocalizations 對像中獲取
class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
// This delegate instance will never change (it doesn't even have fields!)
// It can provide a constant constructor.
const _AppLocalizationsDelegate();
/// 之泉的語言代碼
@override
bool isSupported(Locale locale) {
// Include all of your supported language codes here
return ['en', 'zh'].contains(locale.languageCode);
}
/// 讀取 Json
@override
Future<AppLocalizations> load(Locale locale) async {
// AppLocalizations class is where the JSON loading actually runs
AppLocalizations localizations = new AppLocalizations(locale: locale);
await localizations.load();
return localizations;
}
/// 使否重新 reload
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
Text(AppLocalizations.of(context)!.translate('introduce')),
AppLocalizations localeApp = AppLocalizations();
// 之後再按鈕的 onPressed 裡面
onPressed: () async {
if (await localeApp.readLocaleKey() == "zh") {
localeApp.setLocale(context, Locale("en", "EN"));
} else {
localeApp.setLocale(
context, Locale.fromSubtags(languageCode: 'zh'));
}
}