From 464ed005bbfd860ed9156171cc9d13a5de4a8d60 Mon Sep 17 00:00:00 2001 From: laiiihz Date: Tue, 1 Mar 2022 09:18:24 +0800 Subject: [PATCH] l10n update --- .vscode/launch.json | 19 +++ l10n.yaml | 3 + lib/home_page.dart | 8 +- lib/l10n/app_en.arb | 13 ++ lib/l10n/app_zh.arb | 10 ++ lib/l10n/fluent_localization.dart | 115 ++++++++++++++++++ lib/l10n/l10n.dart | 17 +++ lib/main.dart | 12 +- .../base_64_encoder_decoder.dart | 28 ++--- .../uri_encoder_decoder.dart | 11 +- .../abstract/formatter_base_view.dart | 10 +- .../json_formatter/json_formatter_view.dart | 1 + .../hash_generator/hash_generator_view.dart | 5 +- .../uuid_generator/uuid_generator.dart | 3 +- lib/tools/widgets/formatter_view.dart | 6 +- lib/widgets/titlebar_button.dart | 2 - lib/widgets/toolbar_view.dart | 6 +- pubspec.lock | 7 +- pubspec.yaml | 4 + 19 files changed, 242 insertions(+), 38 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 l10n.yaml create mode 100644 lib/l10n/app_en.arb create mode 100644 lib/l10n/app_zh.arb create mode 100644 lib/l10n/fluent_localization.dart create mode 100644 lib/l10n/l10n.dart diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..306ff73 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,19 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "devtoys", + "request": "launch", + "type": "dart" + }, + { + "name": "devtoys (profile mode)", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + } + ] +} \ No newline at end of file diff --git a/l10n.yaml b/l10n.yaml new file mode 100644 index 0000000..b56d12e --- /dev/null +++ b/l10n.yaml @@ -0,0 +1,3 @@ +arb-dir: lib/l10n +template-arb-file: app_en.arb +output-localization-file: s.dart diff --git a/lib/home_page.dart b/lib/home_page.dart index 61d981b..489baaa 100644 --- a/lib/home_page.dart +++ b/lib/home_page.dart @@ -1,4 +1,6 @@ +import 'package:devtoys/l10n/l10n.dart'; import 'package:devtoys/models/tool_items.dart'; +import 'package:devtoys/views/settings_view.dart'; import 'package:devtoys/widgets/window_tool_widget.dart'; import 'package:fluent_ui/fluent_ui.dart'; @@ -16,7 +18,7 @@ class _HomePageState extends State { Widget build(BuildContext context) { Widget child = NavigationView( appBar: NavigationAppBar( - title: const Text('DevToys'), + title: Text(S.of(context).appName), automaticallyImplyLeading: true, leading: Image.asset('assets/logo/256x256.webp'), ), @@ -43,7 +45,9 @@ class _HomePageState extends State { if (index < naviUtil.realItems.length) { return naviUtil.realItems[index].page; } - return const SizedBox.shrink(); + + // return const SizedBox.shrink(); + return const SettingsView(); }, ), ); diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb new file mode 100644 index 0000000..efe13c3 --- /dev/null +++ b/lib/l10n/app_en.arb @@ -0,0 +1,13 @@ +{ + "appName": "DevToys", + "@appName": { + "description": "name of app" + }, + "configuration": "configuration", + "conversion": "Conversion", + "selectConversion": "Select whitch conversion mode you want to use", + "encode": "Encode", + "decode": "Decode", + "input": "input", + "output": "output" +} diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb new file mode 100644 index 0000000..df0cd7f --- /dev/null +++ b/lib/l10n/app_zh.arb @@ -0,0 +1,10 @@ +{ + "appName": "DevToys", + "configuration": "配置", + "conversion": "转换", + "selectConversion": "选择您想使用的转换格式", + "encode": "编码", + "decode": "解码", + "input": "输入", + "output": "输出" +} diff --git a/lib/l10n/fluent_localization.dart b/lib/l10n/fluent_localization.dart new file mode 100644 index 0000000..53794ac --- /dev/null +++ b/lib/l10n/fluent_localization.dart @@ -0,0 +1,115 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:flutter/foundation.dart'; + +class ZhFluentLocalization implements FluentLocalizations { + const ZhFluentLocalization(); + + @override + String get backButtonTooltip => 'Back'; + + @override + String get closeButtonLabel => 'Close'; + + @override + String get searchLabel => 'Search'; + + @override + String get closeNavigationTooltip => 'Close Navigation'; + + @override + String get openNavigationTooltip => 'Open Navigation'; + + @override + String get clickToSearch => 'Click to search'; + + @override + String get modalBarrierDismissLabel => 'Dismiss'; + + @override + String get minimizeWindowTooltip => 'Minimze'; + + @override + String get restoreWindowTooltip => 'Restore'; + + @override + String get closeWindowTooltip => 'Close'; + + @override + String get dialogLabel => 'Dialog'; + + @override + String get cutButtonLabel => 'Cut'; + + @override + String get copyButtonLabel => 'Copy'; + + @override + String get pasteButtonLabel => 'Paste'; + + @override + String get selectAllButtonLabel => 'Select all'; + + @override + String get newTabLabel => 'Add new tab'; + + @override + String get closeTabLabel => 'Close tab (Ctrl+F4)'; + + @override + String get scrollTabBackwardLabel => 'Scroll tab list backward'; + + @override + String get scrollTabForwardLabel => 'Scroll tab list forward'; + + @override + String get noResultsFoundLabel => '找不到结果'; + + /// Creates an object that provides US English resource values for the material + /// library widgets. + /// + /// The [locale] parameter is ignored. + /// + /// This method is typically used to create a [LocalizationsDelegate]. + /// The [MaterialApp] does so by default. + static Future load(Locale locale) { + return SynchronousFuture(lookupAppLocalizations(locale)); + } + + static const LocalizationsDelegate delegate = + _CustomFluentLocalizationsDelegate(); + + static FluentLocalizations lookupAppLocalizations(Locale locale) { + // Lookup logic when only language code is specified. + switch (locale.languageCode) { + case 'en': + return const DefaultFluentLocalizations(); + case 'zh': + return const ZhFluentLocalization(); + } + + throw FlutterError( + 'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.'); + } +} + +class _CustomFluentLocalizationsDelegate + extends LocalizationsDelegate { + const _CustomFluentLocalizationsDelegate(); + + @override + bool isSupported(Locale locale) => + locale.languageCode == 'en' || locale.languageCode == 'zh'; + + @override + Future load(Locale locale) => + ZhFluentLocalization.load(locale); + + @override + bool shouldReload(_CustomFluentLocalizationsDelegate old) => false; + + @override + String toString() => 'DefaultFluentLocalizations.delegate(en_US)'; +} diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart new file mode 100644 index 0000000..f321e71 --- /dev/null +++ b/lib/l10n/l10n.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/s.dart'; + +class S { + static AppLocalizations of(BuildContext context) { + return AppLocalizations.of(context) ?? + lookupAppLocalizations(const Locale('zh')); + } + + static List get localizationsDelegates => + AppLocalizations.localizationsDelegates; + + static List get supportedLocales => AppLocalizations.supportedLocales; + + static LocalizationsDelegate get delegate => + AppLocalizations.delegate; +} diff --git a/lib/main.dart b/lib/main.dart index 82f33db..f2c54dd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,8 @@ import 'package:devtoys/home_page.dart'; +import 'package:devtoys/l10n/fluent_localization.dart'; +import 'package:devtoys/l10n/l10n.dart'; import 'package:fluent_ui/fluent_ui.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:window_manager/window_manager.dart'; void main() async { @@ -15,16 +18,21 @@ void main() async { class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); - // This widget is the root of your application. @override Widget build(BuildContext context) { return FluentApp( - title: 'DevToys', + onGenerateTitle: (context) => S.of(context).appName, theme: ThemeData.light(), darkTheme: ThemeData.dark(), themeMode: ThemeMode.system, home: const HomePage(), debugShowCheckedModeBanner: false, + localizationsDelegates: [ + S.delegate, + ZhFluentLocalization.delegate, + GlobalMaterialLocalizations.delegate, + ], + supportedLocales: S.supportedLocales, ); } } diff --git a/lib/tools/encoders_decoders/base_64_encoder_decoder/base_64_encoder_decoder.dart b/lib/tools/encoders_decoders/base_64_encoder_decoder/base_64_encoder_decoder.dart index 1085405..7b2e6d9 100644 --- a/lib/tools/encoders_decoders/base_64_encoder_decoder/base_64_encoder_decoder.dart +++ b/lib/tools/encoders_decoders/base_64_encoder_decoder/base_64_encoder_decoder.dart @@ -1,3 +1,4 @@ +import 'package:devtoys/l10n/l10n.dart'; import 'package:devtoys/tools/encoders_decoders/base_64_encoder_decoder/base_64_provider.dart'; import 'package:devtoys/widgets/app_title.dart'; import 'package:devtoys/widgets/tool_view.dart'; @@ -37,17 +38,16 @@ class _Base64EncoderDecoderViewState extends State { return ToolView.scrollVertical( title: const Text('Base 64 Encoder/Decoder'), children: [ - const AppTitle(title: 'Config'), + AppTitle(title: S.of(context).configuration), ToolViewConfig( leading: const Icon(FluentIcons.switch_widget), - title: const Text('Conversion'), - subtitle: - const Text('Select whitch conversion mode you want to use'), + title: Text(S.of(context).conversion), + subtitle: Text(S.of(context).selectConversion), trailing: Row( children: [ _provider.isEncode - ? const Text('Encode') - : const Text('Decode'), + ? Text(S.of(context).encode) + : Text(S.of(context).decode), ToggleSwitch( checked: _provider.isEncode, onChanged: (state) { @@ -57,7 +57,7 @@ class _Base64EncoderDecoderViewState extends State { ], )), AppTitleWrapper( - title: 'input', + title: S.of(context).input, actions: [ Button( child: const Icon(FluentIcons.paste), @@ -65,6 +65,12 @@ class _Base64EncoderDecoderViewState extends State { _provider.paste(); }, ), + Button( + child: const Icon(FluentIcons.clear), + onPressed: () { + _provider.clear(); + }, + ), ], child: TextBox( minLines: 10, @@ -76,7 +82,7 @@ class _Base64EncoderDecoderViewState extends State { ), ), AppTitleWrapper( - title: 'output', + title: S.of(context).output, actions: [ Button( child: const Icon(FluentIcons.copy), @@ -84,12 +90,6 @@ class _Base64EncoderDecoderViewState extends State { _provider.paste(); }, ), - Button( - child: const Icon(FluentIcons.clear), - onPressed: () { - _provider.clear(); - }, - ), ], child: TextBox( minLines: 10, diff --git a/lib/tools/encoders_decoders/uri_encoder_decoder/uri_encoder_decoder.dart b/lib/tools/encoders_decoders/uri_encoder_decoder/uri_encoder_decoder.dart index fad7310..db426c0 100644 --- a/lib/tools/encoders_decoders/uri_encoder_decoder/uri_encoder_decoder.dart +++ b/lib/tools/encoders_decoders/uri_encoder_decoder/uri_encoder_decoder.dart @@ -1,3 +1,4 @@ +import 'package:devtoys/l10n/l10n.dart'; import 'package:devtoys/tools/encoders_decoders/uri_encoder_decoder/uri_provider.dart'; import 'package:devtoys/widgets/app_title.dart'; import 'package:devtoys/widgets/tool_view.dart'; @@ -35,11 +36,11 @@ class _UriEncoderDecoderViewState extends State { return ToolView.scrollVertical( title: const Text('Uri Encoder/Decoder'), children: [ - const AppTitle(title: 'Config'), + AppTitle(title: S.of(context).configuration), ToolViewConfig( leading: const Icon(FluentIcons.switch_widget), - title: const Text('Conversion'), - subtitle: const Text('Select whitch conversion mode you want to use'), + title: Text(S.of(context).conversion), + subtitle: Text(S.of(context).selectConversion), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ @@ -54,7 +55,7 @@ class _UriEncoderDecoderViewState extends State { ), ), AppTitleWrapper( - title: 'input', + title: S.of(context).input, actions: [ Button( child: const Icon(FluentIcons.paste), @@ -75,7 +76,7 @@ class _UriEncoderDecoderViewState extends State { ), ), AppTitleWrapper( - title: 'output', + title: S.of(context).output, actions: [ Button( child: const Icon(FluentIcons.copy), diff --git a/lib/tools/formatters/abstract/formatter_base_view.dart b/lib/tools/formatters/abstract/formatter_base_view.dart index abdd410..d13f968 100644 --- a/lib/tools/formatters/abstract/formatter_base_view.dart +++ b/lib/tools/formatters/abstract/formatter_base_view.dart @@ -41,7 +41,9 @@ class _FormatterBaseViewState extends State { onChanged: (text) { try { widget.base.convertIt(); - } catch (e) {} + } catch (e) { + print(e); + } }, ), outputWidget: TextBox( @@ -51,14 +53,14 @@ class _FormatterBaseViewState extends State { ), inputActions: [ Button( - child: const Text('paste'), + child: const Icon(FluentIcons.paste), onPressed: () async { final rawText = await Clipboard.getData('text/plain'); widget.base.inputController.text = rawText?.text ?? ''; }, ), Button( - child: const Text('clear'), + child: const Icon(FluentIcons.clear), onPressed: () { widget.base.clearAll(); }, @@ -66,7 +68,7 @@ class _FormatterBaseViewState extends State { ], outputActions: [ Button( - child: const Text('copy'), + child: const Icon(FluentIcons.copy), onPressed: () async { await Clipboard.setData( ClipboardData(text: widget.base.outputController.text), diff --git a/lib/tools/formatters/json_formatter/json_formatter_view.dart b/lib/tools/formatters/json_formatter/json_formatter_view.dart index 5df4f4d..f70b958 100644 --- a/lib/tools/formatters/json_formatter/json_formatter_view.dart +++ b/lib/tools/formatters/json_formatter/json_formatter_view.dart @@ -25,6 +25,7 @@ class _JsonFormtterViewState extends State { @override void dispose() { provider.removeListener(update); + provider.dispose(); super.dispose(); } diff --git a/lib/tools/generators/hash_generator/hash_generator_view.dart b/lib/tools/generators/hash_generator/hash_generator_view.dart index 4c02a87..a97dd0a 100644 --- a/lib/tools/generators/hash_generator/hash_generator_view.dart +++ b/lib/tools/generators/hash_generator/hash_generator_view.dart @@ -1,3 +1,4 @@ +import 'package:devtoys/l10n/l10n.dart'; import 'package:devtoys/tools/generators/hash_generator/hash_provider.dart'; import 'package:devtoys/widgets/app_title.dart'; import 'package:devtoys/widgets/tool_view.dart'; @@ -37,7 +38,7 @@ class _HashGeneratorViewState extends State { return ToolView.scrollVertical( title: const Text('Hash Genergator'), children: [ - const AppTitle(title: 'Config'), + AppTitle(title: S.of(context).configuration), ToolViewConfig( title: const Text('UpperCase'), trailing: ToggleSwitch( @@ -48,7 +49,7 @@ class _HashGeneratorViewState extends State { ), ), AppTitle( - title: 'Input', + title: S.of(context).input, actions: [ Button( child: const Icon(FluentIcons.paste), diff --git a/lib/tools/generators/uuid_generator/uuid_generator.dart b/lib/tools/generators/uuid_generator/uuid_generator.dart index 91c2686..13745ea 100644 --- a/lib/tools/generators/uuid_generator/uuid_generator.dart +++ b/lib/tools/generators/uuid_generator/uuid_generator.dart @@ -1,3 +1,4 @@ +import 'package:devtoys/l10n/l10n.dart'; import 'package:devtoys/tools/generators/uuid_generator/uuid_provider.dart'; import 'package:devtoys/widgets/app_title.dart'; import 'package:devtoys/widgets/tool_view.dart'; @@ -36,7 +37,7 @@ class _UUIDGeneratorViewState extends State { return ToolView.scrollVertical( title: const Text('UUID Generator'), children: [ - const AppTitle(title: 'Config'), + AppTitle(title: S.of(context).configuration), ToolViewConfig( title: const Text('Hypens'), trailing: ToggleSwitch( diff --git a/lib/tools/widgets/formatter_view.dart b/lib/tools/widgets/formatter_view.dart index e209b11..33515c9 100644 --- a/lib/tools/widgets/formatter_view.dart +++ b/lib/tools/widgets/formatter_view.dart @@ -51,14 +51,14 @@ class FormatterViewState extends State { ), inputActions: [ Button( - child: const Text('paste'), + child: const Icon(FluentIcons.paste), onPressed: () async { final rawText = await Clipboard.getData('text/plain'); _inputController.text = rawText?.text ?? ''; }, ), Button( - child: const Text('clear'), + child: const Icon(FluentIcons.clear), onPressed: () { _inputController.clear(); _outputController.clear(); @@ -67,7 +67,7 @@ class FormatterViewState extends State { ], outputActions: [ Button( - child: const Text('copy'), + child: const Icon(FluentIcons.copy), onPressed: () async { await Clipboard.setData( ClipboardData(text: _outputController.text), diff --git a/lib/widgets/titlebar_button.dart b/lib/widgets/titlebar_button.dart index 62ca111..543852c 100644 --- a/lib/widgets/titlebar_button.dart +++ b/lib/widgets/titlebar_button.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:window_manager/window_manager.dart'; diff --git a/lib/widgets/toolbar_view.dart b/lib/widgets/toolbar_view.dart index fcf927a..5837112 100644 --- a/lib/widgets/toolbar_view.dart +++ b/lib/widgets/toolbar_view.dart @@ -2,6 +2,8 @@ import 'package:devtoys/extension/list_ext.dart'; import 'package:devtoys/widgets/app_title.dart'; import 'package:fluent_ui/fluent_ui.dart'; +import '../l10n/l10n.dart'; + class ToolbarView extends StatelessWidget { final List configs; final Widget inputWidget; @@ -27,7 +29,7 @@ class ToolbarView extends StatelessWidget { child: Column( children: [ AppTitle( - title: 'input', + title: S.of(context).input, actions: inputActions.sep(const SizedBox(width: 4)), ), const SizedBox(height: 8), @@ -39,7 +41,7 @@ class ToolbarView extends StatelessWidget { child: Column( children: [ AppTitle( - title: 'output', + title: S.of(context).output, actions: outputActions.sep(const SizedBox(width: 4)), ), const SizedBox(height: 8), diff --git a/pubspec.lock b/pubspec.lock index c72e89e..05ebb0d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -132,6 +132,11 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.0.4" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" flutter_svg: dependency: "direct main" description: @@ -152,7 +157,7 @@ packages: source: hosted version: "2.0.2" intl: - dependency: transitive + dependency: "direct main" description: name: intl url: "https://pub.flutter-io.cn" diff --git a/pubspec.yaml b/pubspec.yaml index e28d396..3f07696 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,6 +10,9 @@ environment: dependencies: flutter: sdk: flutter + flutter_localizations: + sdk: flutter + intl: ^0.17.0 cupertino_icons: ^1.0.2 fluent_ui: ^3.9.0 @@ -28,6 +31,7 @@ dev_dependencies: flutter: uses-material-design: true + generate: true assets: - assets/logo/1080x1080.webp