From b04c2a9693faee04083f6bdc83b2ea1700fd75ce Mon Sep 17 00:00:00 2001 From: lollipopkit Date: Sat, 27 May 2023 17:47:48 +0800 Subject: [PATCH] #51 new: custom `language` --- .dart_tool/flutter_gen/gen_l10n/l10n.dart | 12 +++++++ .dart_tool/flutter_gen/gen_l10n/l10n_de.dart | 6 ++++ .dart_tool/flutter_gen/gen_l10n/l10n_en.dart | 6 ++++ .dart_tool/flutter_gen/gen_l10n/l10n_zh.dart | 12 +++++++ lib/app.dart | 4 +++ lib/core/extension/locale.dart | 20 +++++++++++ lib/data/store/setting.dart | 3 ++ lib/l10n/app_de.arb | 2 ++ lib/l10n/app_en.arb | 2 ++ lib/l10n/app_zh.arb | 2 ++ lib/l10n/app_zh_tw.arb | 4 ++- lib/view/page/setting.dart | 38 ++++++++++++++++++++ 12 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 lib/core/extension/locale.dart diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n.dart b/.dart_tool/flutter_gen/gen_l10n/l10n.dart index a052fcce..52eb6f4c 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n.dart @@ -570,6 +570,18 @@ abstract class S { /// **'Key Auth'** String get keyAuth; + /// No description provided for @language. + /// + /// In en, this message translates to: + /// **'Language'** + String get language; + + /// No description provided for @languageName. + /// + /// In en, this message translates to: + /// **'English'** + String get languageName; + /// No description provided for @lastTry. /// /// In en, this message translates to: diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart index eba3c58d..7282c17b 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_de.dart @@ -261,6 +261,12 @@ class SDe extends S { @override String get keyAuth => 'Schlüsselauthentifzierung'; + @override + String get language => 'Sprache'; + + @override + String get languageName => 'Deutsch'; + @override String get lastTry => 'Letzter Versuch'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart index 8d4fd0fd..c789f063 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_en.dart @@ -261,6 +261,12 @@ class SEn extends S { @override String get keyAuth => 'Key Auth'; + @override + String get language => 'Language'; + + @override + String get languageName => 'English'; + @override String get lastTry => 'Last try'; diff --git a/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart b/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart index 6e461781..d089c9b2 100644 --- a/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart +++ b/.dart_tool/flutter_gen/gen_l10n/l10n_zh.dart @@ -261,6 +261,12 @@ class SZh extends S { @override String get keyAuth => '密钥认证'; + @override + String get language => '语言'; + + @override + String get languageName => '简体中文'; + @override String get lastTry => '最后尝试'; @@ -841,6 +847,12 @@ class SZhTw extends SZh { @override String get keyAuth => '密鑰認證'; + @override + String get language => '語言'; + + @override + String get languageName => '繁體中文'; + @override String get lastTry => '最後嘗試'; diff --git a/lib/app.dart b/lib/app.dart index ce7503ab..b75f8b6b 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:toolbox/core/extension/locale.dart'; import 'core/utils/ui.dart'; import 'data/res/build_data.dart'; @@ -23,9 +24,12 @@ class MyApp extends StatelessWidget { builder: (_, tMode, __) { final ok = tMode >= 0 && tMode <= ThemeMode.values.length - 1; final themeMode = ok ? ThemeMode.values[tMode] : ThemeMode.system; + final localeStr = _setting.locale.fetch(); + final locale = localeStr?.toLocale; return MaterialApp( debugShowCheckedModeBanner: false, + locale: locale, localizationsDelegates: S.localizationsDelegates, supportedLocales: S.supportedLocales, title: BuildData.name, diff --git a/lib/core/extension/locale.dart b/lib/core/extension/locale.dart new file mode 100644 index 00000000..ac2b1db5 --- /dev/null +++ b/lib/core/extension/locale.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; + +extension LocaleX on Locale { + String get name { + if (countryCode == null) { + return languageCode; + } + return '${languageCode}_$countryCode'; + } +} + +extension String2Locale on String { + Locale get toLocale { + final parts = split('_'); + if (parts.length == 1) { + return Locale(parts[0]); + } + return Locale(parts[0], parts[1]); + } +} diff --git a/lib/data/store/setting.dart b/lib/data/store/setting.dart index 3ae8900c..74c61d40 100644 --- a/lib/data/store/setting.dart +++ b/lib/data/store/setting.dart @@ -65,4 +65,7 @@ class SettingStore extends PersistentStore { 'run', 'none', ]); + + /// Locale + StoreProperty get locale => property('locale', defaultValue: null); } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index d533febe..00f9332a 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -79,6 +79,8 @@ "isBusy": "Is busy now", "keepForeground": "Stelle sicher, dass die App geöffnet bleibt.", "keyAuth": "Schlüsselauthentifzierung", + "language": "Sprache", + "languageName": "Deutsch", "lastTry": "Letzter Versuch", "launchPage": "Startseite", "license": "Lizenzen", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f16d8dad..38f4cad9 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -79,6 +79,8 @@ "isBusy": "Is busy now", "keepForeground": "Keep app foreground!", "keyAuth": "Key Auth", + "language": "Language", + "languageName": "English", "lastTry": "Last try", "launchPage": "Launch page", "license": "License", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index f1b9df44..002dea88 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -79,6 +79,8 @@ "isBusy": "当前正忙", "keepForeground": "请保持应用处于前台!", "keyAuth": "密钥认证", + "language": "语言", + "languageName": "简体中文", "lastTry": "最后尝试", "launchPage": "启动页", "license": "开源证书", diff --git a/lib/l10n/app_zh_tw.arb b/lib/l10n/app_zh_tw.arb index 220ba921..9e912c8c 100644 --- a/lib/l10n/app_zh_tw.arb +++ b/lib/l10n/app_zh_tw.arb @@ -79,6 +79,8 @@ "isBusy": "當前正忙", "keepForeground": "請保持應用處於前台!", "keyAuth": "密鑰認證", + "language": "語言", + "languageName": "繁體中文", "lastTry": "最後嘗試", "launchPage": "啓動頁", "license": "開源證書", @@ -177,4 +179,4 @@ "viewErr": "查看錯誤", "waitConnection": "請等待連接建立", "willTakEeffectImmediately": "更改將會立即生效" -} +} \ No newline at end of file diff --git a/lib/view/page/setting.dart b/lib/view/page/setting.dart index 4fc7ecb1..bdf9cacf 100644 --- a/lib/view/page/setting.dart +++ b/lib/view/page/setting.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_material_color_picker/flutter_material_color_picker.dart'; import 'package:provider/provider.dart'; +import 'package:toolbox/core/extension/locale.dart'; import 'package:toolbox/core/extension/navigator.dart'; import 'package:toolbox/data/model/app/tab.dart'; import 'package:toolbox/view/widget/input_field.dart'; @@ -39,6 +40,7 @@ class _SettingPageState extends State { final termThemeKey = GlobalKey>(); final maxRetryKey = GlobalKey>(); final fontSizeKey = GlobalKey>(); + final localeKey = GlobalKey>(); late final SettingStore _setting; late final ServerProvider _serverProvider; @@ -52,6 +54,7 @@ class _SettingPageState extends State { late int _maxRetryCount; late int _updateInterval; late double _fontSize; + late String _localeCode; String? _pushToken; @@ -60,6 +63,7 @@ class _SettingPageState extends State { super.didChangeDependencies(); _media = MediaQuery.of(context); _s = S.of(context)!; + _localeCode = _setting.locale.fetch() ?? _s.localeName; } @override @@ -114,6 +118,7 @@ class _SettingPageState extends State { Widget _buildApp() { final children = [ + _buildLocale(), _buildThemeMode(), _buildAppColorPreview(), _buildLaunchPage(), @@ -598,4 +603,37 @@ class _SettingPageState extends State { }, ); } + + Widget _buildLocale() { + final items = S.supportedLocales + .map( + (e) => PopupMenuItem( + value: e.name, + child: Text(e.name), + ), + ) + .toList(); + return ListTile( + title: Text(_s.language), + onTap: () { + localeKey.currentState?.showButtonMenu(); + }, + trailing: PopupMenuButton( + key: localeKey, + itemBuilder: (BuildContext context) => items, + initialValue: _localeCode, + onSelected: (String idx) { + setState(() { + _localeCode = idx; + }); + _setting.locale.put(idx); + _showRestartSnackbar(); + }, + child: Text( + _s.languageName, + style: textSize15, + ), + ), + ); + } }