From d34795f549be3f492cf6d197ffd77a7b691f606d Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 10 Jan 2021 16:40:25 +0500 Subject: [PATCH 01/52] EasyLogger package --- .gitignore | 4 +- .../easy_logger/.idea/libraries/Dart_SDK.xml | 19 +++++ packages/easy_logger/.idea/modules.xml | 8 +++ packages/easy_logger/.idea/workspace.xml | 36 ++++++++++ packages/easy_logger/.metadata | 10 +++ packages/easy_logger/CHANGELOG.md | 3 + packages/easy_logger/LICENSE | 21 ++++++ packages/easy_logger/README.md | 2 + packages/easy_logger/analysis_options.yaml | 18 +++++ packages/easy_logger/lib/easy_logger.dart | 3 + packages/easy_logger/lib/src/enums.dart | 26 +++++++ packages/easy_logger/lib/src/logger.dart | 70 +++++++++++++++++++ .../easy_logger/lib/src/logger_printer.dart | 33 +++++++++ packages/easy_logger/pubspec.yaml | 17 +++++ .../easy_logger/test/easy_logger_test.dart | 1 + 15 files changed, 269 insertions(+), 2 deletions(-) create mode 100644 packages/easy_logger/.idea/libraries/Dart_SDK.xml create mode 100644 packages/easy_logger/.idea/modules.xml create mode 100644 packages/easy_logger/.idea/workspace.xml create mode 100644 packages/easy_logger/.metadata create mode 100644 packages/easy_logger/CHANGELOG.md create mode 100644 packages/easy_logger/LICENSE create mode 100644 packages/easy_logger/README.md create mode 100644 packages/easy_logger/analysis_options.yaml create mode 100644 packages/easy_logger/lib/easy_logger.dart create mode 100644 packages/easy_logger/lib/src/enums.dart create mode 100644 packages/easy_logger/lib/src/logger.dart create mode 100644 packages/easy_logger/lib/src/logger_printer.dart create mode 100644 packages/easy_logger/pubspec.yaml create mode 100644 packages/easy_logger/test/easy_logger_test.dart diff --git a/.gitignore b/.gitignore index d08d42e2..ca455ab4 100644 --- a/.gitignore +++ b/.gitignore @@ -456,9 +456,9 @@ PublishScripts/ # NuGet Symbol Packages *.snupkg # The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* +#**/[Pp]ackages/* # except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ +#!**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/[Pp]ackages/repositories.config # NuGet v3's project.json files produces more ignorable files diff --git a/packages/easy_logger/.idea/libraries/Dart_SDK.xml b/packages/easy_logger/.idea/libraries/Dart_SDK.xml new file mode 100644 index 00000000..de464dd7 --- /dev/null +++ b/packages/easy_logger/.idea/libraries/Dart_SDK.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/easy_logger/.idea/modules.xml b/packages/easy_logger/.idea/modules.xml new file mode 100644 index 00000000..4265dc6e --- /dev/null +++ b/packages/easy_logger/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/packages/easy_logger/.idea/workspace.xml b/packages/easy_logger/.idea/workspace.xml new file mode 100644 index 00000000..5b3388cc --- /dev/null +++ b/packages/easy_logger/.idea/workspace.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/easy_logger/.metadata b/packages/easy_logger/.metadata new file mode 100644 index 00000000..98e3efc9 --- /dev/null +++ b/packages/easy_logger/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: b0a22998593fc605c723dee8ff4d9315c32cfe2c + channel: beta + +project_type: package diff --git a/packages/easy_logger/CHANGELOG.md b/packages/easy_logger/CHANGELOG.md new file mode 100644 index 00000000..4eefbf04 --- /dev/null +++ b/packages/easy_logger/CHANGELOG.md @@ -0,0 +1,3 @@ +### [0.0.1] + +- initial release. diff --git a/packages/easy_logger/LICENSE b/packages/easy_logger/LICENSE new file mode 100644 index 00000000..7443ae69 --- /dev/null +++ b/packages/easy_logger/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/packages/easy_logger/README.md b/packages/easy_logger/README.md new file mode 100644 index 00000000..8403feb2 --- /dev/null +++ b/packages/easy_logger/README.md @@ -0,0 +1,2 @@ +# Easy Logger + diff --git a/packages/easy_logger/analysis_options.yaml b/packages/easy_logger/analysis_options.yaml new file mode 100644 index 00000000..dfab32b6 --- /dev/null +++ b/packages/easy_logger/analysis_options.yaml @@ -0,0 +1,18 @@ +#https://dart.dev/guides/language/analysis-options +include: package:pedantic/analysis_options.yaml + +analyzer: + strong-mode: + implicit-casts: false + errors: + missing_required_param: warning + missing_return: warning + todo: ignore + +linter: + rules: + avoid_classes_with_only_static_members: false + sort_constructors_first: true + prefer_single_quotes: true + public_member_api_docs: true + always_specify_types: true \ No newline at end of file diff --git a/packages/easy_logger/lib/easy_logger.dart b/packages/easy_logger/lib/easy_logger.dart new file mode 100644 index 00000000..3b8d5f3b --- /dev/null +++ b/packages/easy_logger/lib/easy_logger.dart @@ -0,0 +1,3 @@ +export 'src/logger.dart'; +export 'src/enums.dart'; +export 'src/logger_printer.dart'; diff --git a/packages/easy_logger/lib/src/enums.dart b/packages/easy_logger/lib/src/enums.dart new file mode 100644 index 00000000..c053425a --- /dev/null +++ b/packages/easy_logger/lib/src/enums.dart @@ -0,0 +1,26 @@ +/// Build mode enum for +enum BuildMode { + /// Release build mode + release, + + /// Profile build mode + profile, + + /// Debug build mode + debug +} + +/// Levels messages +enum EasyLoggerLevel { + ///Debug level message + debug, + + ///Information level message + info, + + ///Warning level message + warning, + + ///Error level message + error, +} diff --git a/packages/easy_logger/lib/src/logger.dart b/packages/easy_logger/lib/src/logger.dart new file mode 100644 index 00000000..7b450a6c --- /dev/null +++ b/packages/easy_logger/lib/src/logger.dart @@ -0,0 +1,70 @@ +import 'package:flutter/foundation.dart'; + +import 'enums.dart'; +import 'logger_printer.dart'; + +/// Easy Logger +class EasyLogger { + EasyLogger( + {this.name, + this.enableBuildModes = const [ + BuildMode.profile, + BuildMode.debug, + ], + this.enableLevels = const [ + EasyLoggerLevel.debug, + EasyLoggerLevel.info, + EasyLoggerLevel.error, + EasyLoggerLevel.warning, + ], + EasyLogPrinter printer}) { + _printer = printer ?? easyLogDefaultPrinter; + _currentBuildMode = _getCurrentBuildMode(); + } + + BuildMode _currentBuildMode; + String name; + List enableBuildModes; + List enableLevels; + + EasyLogPrinter _printer; + EasyLogPrinter get printer => _printer; + set printer(EasyLogPrinter newPrinter) => _printer = newPrinter; + + BuildMode _getCurrentBuildMode() { + if (kReleaseMode) { + return BuildMode.release; + } else if (kProfileMode) { + return BuildMode.profile; + } + return BuildMode.debug; + } + + bool isEnabled(EasyLoggerLevel level) { + if (!enableBuildModes.contains(_currentBuildMode)) { + return false; + } + if (!enableLevels.contains(level)) { + return false; + } + return true; + } + + void call(Object object, {StackTrace stackTrace, EasyLoggerLevel level = EasyLoggerLevel.info}) { + if (isEnabled(level)) { + _printer(object, stackTrace: stackTrace, level: level, name: name); + } + } + + void debug(Object object, {StackTrace stackTrace}) => + call(object, stackTrace: stackTrace, level: EasyLoggerLevel.debug); + + void info(Object object, {StackTrace stackTrace}) => + call(object, stackTrace: stackTrace, level: EasyLoggerLevel.info); + + void warning(Object object, {StackTrace stackTrace}) => + call(object, stackTrace: stackTrace, level: EasyLoggerLevel.warning); + + void error(Object object, {StackTrace stackTrace}) => + call(object, stackTrace: stackTrace, level: EasyLoggerLevel.error); +} diff --git a/packages/easy_logger/lib/src/logger_printer.dart b/packages/easy_logger/lib/src/logger_printer.dart new file mode 100644 index 00000000..75c13136 --- /dev/null +++ b/packages/easy_logger/lib/src/logger_printer.dart @@ -0,0 +1,33 @@ +import 'dart:developer'; + +import '../easy_logger.dart'; + +typedef EasyLogPrinter = Function(Object object, {String name, EasyLoggerLevel level, StackTrace stackTrace}); + +EasyLogPrinter easyLogDefaultPrinter = (Object object, {String name, StackTrace stackTrace, EasyLoggerLevel level}) { + String _prepareString() { + switch (level) { + case EasyLoggerLevel.debug: + // white + return '\u001b[37m[INFO] ${object.toString()}\u001b[0m'; + case EasyLoggerLevel.info: + // green + return '\u001b[32m[INFO] ${object.toString()}\u001b[0m'; + case EasyLoggerLevel.warning: + // blue + return '\u001B[34m[WARNING] ${object.toString()}\u001b[0m'; + case EasyLoggerLevel.error: + // red + return '\u001b[31m[ERROR] ${object.toString()}\u001b[0m'; + default: + // gray + return '\u001b[90m${object.toString()}\u001b[0m'; + } + } + + log( + _prepareString(), + name: name, + stackTrace: stackTrace, + ); +}; diff --git a/packages/easy_logger/pubspec.yaml b/packages/easy_logger/pubspec.yaml new file mode 100644 index 00000000..1e90ee6e --- /dev/null +++ b/packages/easy_logger/pubspec.yaml @@ -0,0 +1,17 @@ +name: easy_logger +description: Easy logger +version: 0.0.1 + +environment: + sdk: ">=2.7.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + pedantic: ^1.8.0+1 + +flutter: \ No newline at end of file diff --git a/packages/easy_logger/test/easy_logger_test.dart b/packages/easy_logger/test/easy_logger_test.dart new file mode 100644 index 00000000..ab73b3a2 --- /dev/null +++ b/packages/easy_logger/test/easy_logger_test.dart @@ -0,0 +1 @@ +void main() {} From d1859f13dd85577d9fb3257baaaeaa8d7c98ab73 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 10 Jan 2021 17:20:49 +0500 Subject: [PATCH 02/52] fix logger --- packages/easy_logger/lib/src/logger.dart | 32 +++++++++++++----------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/easy_logger/lib/src/logger.dart b/packages/easy_logger/lib/src/logger.dart index 7b450a6c..c4854832 100644 --- a/packages/easy_logger/lib/src/logger.dart +++ b/packages/easy_logger/lib/src/logger.dart @@ -5,19 +5,21 @@ import 'logger_printer.dart'; /// Easy Logger class EasyLogger { - EasyLogger( - {this.name, - this.enableBuildModes = const [ - BuildMode.profile, - BuildMode.debug, - ], - this.enableLevels = const [ - EasyLoggerLevel.debug, - EasyLoggerLevel.info, - EasyLoggerLevel.error, - EasyLoggerLevel.warning, - ], - EasyLogPrinter printer}) { + EasyLogger({ + this.name, + this.enableBuildModes = const [ + BuildMode.profile, + BuildMode.debug, + ], + this.enableLevels = const [ + EasyLoggerLevel.debug, + EasyLoggerLevel.info, + EasyLoggerLevel.error, + EasyLoggerLevel.warning, + ], + EasyLogPrinter printer, + this.defaultLevel = EasyLoggerLevel.info, + }) { _printer = printer ?? easyLogDefaultPrinter; _currentBuildMode = _getCurrentBuildMode(); } @@ -26,6 +28,7 @@ class EasyLogger { String name; List enableBuildModes; List enableLevels; + EasyLoggerLevel defaultLevel; EasyLogPrinter _printer; EasyLogPrinter get printer => _printer; @@ -50,7 +53,8 @@ class EasyLogger { return true; } - void call(Object object, {StackTrace stackTrace, EasyLoggerLevel level = EasyLoggerLevel.info}) { + void call(Object object, {StackTrace stackTrace, EasyLoggerLevel level}) { + level ??= defaultLevel; if (isEnabled(level)) { _printer(object, stackTrace: stackTrace, level: level, name: name); } From c05086750d0223889035213f4fc3697e00bbdfa8 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Mon, 11 Jan 2021 14:45:52 +0500 Subject: [PATCH 03/52] EasyLoger documentation --- packages/easy_logger/README.md | 96 ++++++++++++++++++- packages/easy_logger/lib/src/enums.dart | 6 +- packages/easy_logger/lib/src/logger.dart | 80 ++++++++++++---- .../easy_logger/lib/src/logger_printer.dart | 14 +-- 4 files changed, 169 insertions(+), 27 deletions(-) diff --git a/packages/easy_logger/README.md b/packages/easy_logger/README.md index 8403feb2..055f6a7b 100644 --- a/packages/easy_logger/README.md +++ b/packages/easy_logger/README.md @@ -1,2 +1,96 @@ -# Easy Logger +

+EasyLogger +

+## Getting Started + +### 🔩 Installation + +Add to your `pubspec.yaml`: + +```yaml +dependencies: + easy_logger: +``` + +### ⚙️ Configuration logger + +Create global logger value + +```dart +import 'package:easy_logger/easy_logger.dart'; + +final EasyLogger logger = EasyLogger( + name: 'NamePrefix', + defaultLevel: LevelMessages.debug, + enableBuildModes: [BuildMode.debug, BuildMode.profile, BuildMode.release], + enableLevels: [LevelMessages.debug, LevelMessages.info, LevelMessages.error, LevelMessages.warning], +); + +void main() async { +... +} +``` + +### 📜 EasyLogger properties + +| Properties | Required | Default | Description | +| ---------------- | -------- | ------------------------- | ----------- | +| name | false | '' | Name prefix in the logging line. | +| defaultLevel | false | LevelMessages.info | Default message level if no level is set when call [EasyLogger]. | +| enableBuildModes | false | [BuildMode.debug, BuildMode.profile] | List of available build modes in which logging is enabled. | +| enableLevels | false | [LevelMessages.debug, LevelMessages.info, LevelMessages.error, LevelMessages.warning] | List of available levels messages in which logging is enabled. | +| printer | false | easyLogDefaultPrinter() | Default function printing. | + +## Usage + +Simle usage: + +```dart +logger('Your log text'); +``` + +Or you can set the message level + +```dart +logger('Your log text', level: LevelMessages.info); +``` + + +### 🐛 StackTrace + +[EasyLogger] support [StackTrace] dump sending: + +```dart +try { + //same code +} on Exception catch (e, stackTrace) { + logger('same error', stackTrace: stackTrace); +} +``` + + +### 🖨️ Customise printer function + +[EasyLogger] have easiest way to change default printer function. +Create your custom printer and past like parameter in class. + +```dart +EasyLogPrinter customLogPrinter = ( + Object object, { + String name, + StackTrace stackTrace, + LevelMessages level, +}) { + print('$name: ${object.toString()}'); +}; + +final EasyLogger logger = EasyLogger( + printer: customLogPrinter, +); +``` +Or insert into class object + +```dart +logger.printer = customLogPrinter; +``` \ No newline at end of file diff --git a/packages/easy_logger/lib/src/enums.dart b/packages/easy_logger/lib/src/enums.dart index c053425a..e8936010 100644 --- a/packages/easy_logger/lib/src/enums.dart +++ b/packages/easy_logger/lib/src/enums.dart @@ -1,4 +1,4 @@ -/// Build mode enum for +/// Build mode enum used in [EasyLogger]. enum BuildMode { /// Release build mode release, @@ -10,8 +10,8 @@ enum BuildMode { debug } -/// Levels messages -enum EasyLoggerLevel { +/// Levels messages enum used in [EasyLogger]. +enum LevelMessages { ///Debug level message debug, diff --git a/packages/easy_logger/lib/src/logger.dart b/packages/easy_logger/lib/src/logger.dart index c4854832..c8f9f07d 100644 --- a/packages/easy_logger/lib/src/logger.dart +++ b/packages/easy_logger/lib/src/logger.dart @@ -3,35 +3,72 @@ import 'package:flutter/foundation.dart'; import 'enums.dart'; import 'logger_printer.dart'; -/// Easy Logger +/// Easy Logger callable class class EasyLogger { + /// Customized logger, part of [EasyLocalization](https://github.com/aissat/easy_localization) ecosystem. + /// Callable class, [more info](https://dart.dev/guides/language/language-tour#callable-classes) EasyLogger({ - this.name, + this.name = '', this.enableBuildModes = const [ BuildMode.profile, BuildMode.debug, ], - this.enableLevels = const [ - EasyLoggerLevel.debug, - EasyLoggerLevel.info, - EasyLoggerLevel.error, - EasyLoggerLevel.warning, + this.enableLevels = const [ + LevelMessages.debug, + LevelMessages.info, + LevelMessages.error, + LevelMessages.warning, ], EasyLogPrinter printer, - this.defaultLevel = EasyLoggerLevel.info, + this.defaultLevel = LevelMessages.info, }) { _printer = printer ?? easyLogDefaultPrinter; _currentBuildMode = _getCurrentBuildMode(); } BuildMode _currentBuildMode; + + /// Name prefix in the logging line. + /// @Default value `''` empty string. + /// Example: + /// ``` + /// [YourName] same log text + /// ``` String name; + + /// List of available build modes in which logging is enabled. + /// @Default value `const [BuildMode.profile, BuildMode.debug]` List enableBuildModes; - List enableLevels; - EasyLoggerLevel defaultLevel; + + /// List of available levels messages in which logging is enabled. + /// @Default value `const [LevelMessages.debug, LevelMessages.info, LevelMessages.error, LevelMessages.warning]` + List enableLevels; + + /// Default message level if no level is set when call [EasyLogger]. + /// @Default value `LevelMessages.info` + LevelMessages defaultLevel; EasyLogPrinter _printer; + + /// Print function that generates and printing log lines + /// @Default value `easyLogDefaultPrinter` EasyLogPrinter get printer => _printer; + + /// Printer function setter. + /// You can change the standard print function to a custom one. + /// Example: + /// ```dart + /// EasyLogPrinter customLogPrinter = ( + /// Object object, { + /// String name, + /// StackTrace stackTrace, + /// LevelMessages level, + /// }) { + /// print('$name: ${object.toString()}'); + /// }; + /// + /// logger.printer = customLogPrinter; + /// ``` set printer(EasyLogPrinter newPrinter) => _printer = newPrinter; BuildMode _getCurrentBuildMode() { @@ -43,7 +80,8 @@ class EasyLogger { return BuildMode.debug; } - bool isEnabled(EasyLoggerLevel level) { + /// Check [enableBuildModes] and [enableLevels] + bool isEnabled(LevelMessages level) { if (!enableBuildModes.contains(_currentBuildMode)) { return false; } @@ -53,22 +91,30 @@ class EasyLogger { return true; } - void call(Object object, {StackTrace stackTrace, EasyLoggerLevel level}) { + /// The main callable function for handling log messages. + void call(Object object, {StackTrace stackTrace, LevelMessages level}) { level ??= defaultLevel; if (isEnabled(level)) { _printer(object, stackTrace: stackTrace, level: level, name: name); } } + /// Helper for main callable function. + /// Call logger function with level [LevelMessages.debug] void debug(Object object, {StackTrace stackTrace}) => - call(object, stackTrace: stackTrace, level: EasyLoggerLevel.debug); + call(object, stackTrace: stackTrace, level: LevelMessages.debug); - void info(Object object, {StackTrace stackTrace}) => - call(object, stackTrace: stackTrace, level: EasyLoggerLevel.info); + /// Helper for main callable function. + /// Call logger function with level [LevelMessages.info] + void info(Object object, {StackTrace stackTrace}) => call(object, stackTrace: stackTrace, level: LevelMessages.info); + /// Helper for main callable function. + /// Call logger function with level [LevelMessages.warning] void warning(Object object, {StackTrace stackTrace}) => - call(object, stackTrace: stackTrace, level: EasyLoggerLevel.warning); + call(object, stackTrace: stackTrace, level: LevelMessages.warning); + /// Helper for main callable function. + /// Call logger function with level [LevelMessages.error] void error(Object object, {StackTrace stackTrace}) => - call(object, stackTrace: stackTrace, level: EasyLoggerLevel.error); + call(object, stackTrace: stackTrace, level: LevelMessages.error); } diff --git a/packages/easy_logger/lib/src/logger_printer.dart b/packages/easy_logger/lib/src/logger_printer.dart index 75c13136..311d43a0 100644 --- a/packages/easy_logger/lib/src/logger_printer.dart +++ b/packages/easy_logger/lib/src/logger_printer.dart @@ -2,21 +2,23 @@ import 'dart:developer'; import '../easy_logger.dart'; -typedef EasyLogPrinter = Function(Object object, {String name, EasyLoggerLevel level, StackTrace stackTrace}); +/// Type for function printing/logging in [EasyLogger]. +typedef EasyLogPrinter = Function(Object object, {String name, LevelMessages level, StackTrace stackTrace}); -EasyLogPrinter easyLogDefaultPrinter = (Object object, {String name, StackTrace stackTrace, EasyLoggerLevel level}) { +/// Default function printing. +EasyLogPrinter easyLogDefaultPrinter = (Object object, {String name, StackTrace stackTrace, LevelMessages level}) { String _prepareString() { switch (level) { - case EasyLoggerLevel.debug: + case LevelMessages.debug: // white return '\u001b[37m[INFO] ${object.toString()}\u001b[0m'; - case EasyLoggerLevel.info: + case LevelMessages.info: // green return '\u001b[32m[INFO] ${object.toString()}\u001b[0m'; - case EasyLoggerLevel.warning: + case LevelMessages.warning: // blue return '\u001B[34m[WARNING] ${object.toString()}\u001b[0m'; - case EasyLoggerLevel.error: + case LevelMessages.error: // red return '\u001b[31m[ERROR] ${object.toString()}\u001b[0m'; default: From c38e1676a2593cf641e924e79386f8da2bdc3ac1 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Mon, 11 Jan 2021 15:11:11 +0500 Subject: [PATCH 04/52] update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9d84a8c6..8549888f 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Easy and Fast internationalization for your Flutter Apps - ⁉️ Error widget for missing translations - ❤️ Extension methods on `Text` and `BuildContext` - 💻 Code generation for localization files and keys. +- 🖨️ Customizable logger. ## Getting Started From 838a868df68ce72de872355bebac39bba2ffcbc9 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Mon, 11 Jan 2021 15:22:51 +0500 Subject: [PATCH 05/52] update Ease logger readme --- packages/easy_logger/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/easy_logger/README.md b/packages/easy_logger/README.md index 055f6a7b..376edcc0 100644 --- a/packages/easy_logger/README.md +++ b/packages/easy_logger/README.md @@ -93,4 +93,15 @@ Or insert into class object ```dart logger.printer = customLogPrinter; +``` + +## 🖨️ Helpers + +For easest using logger you can send messages without `level` parameter. + +```dart + logger.debug('your log text'); + logger.info('your log text'); + logger.warning('your log text'); + logger.error('your log text'); ``` \ No newline at end of file From 0a5e6ddbfa1b96992fc4ac279543058775c5353f Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sat, 16 Jan 2021 20:25:26 +0500 Subject: [PATCH 06/52] update printer --- .../easy_logger/lib/src/logger_printer.dart | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/packages/easy_logger/lib/src/logger_printer.dart b/packages/easy_logger/lib/src/logger_printer.dart index 311d43a0..9db1a92b 100644 --- a/packages/easy_logger/lib/src/logger_printer.dart +++ b/packages/easy_logger/lib/src/logger_printer.dart @@ -1,5 +1,3 @@ -import 'dart:developer'; - import '../easy_logger.dart'; /// Type for function printing/logging in [EasyLogger]. @@ -7,29 +5,46 @@ typedef EasyLogPrinter = Function(Object object, {String name, LevelMessages lev /// Default function printing. EasyLogPrinter easyLogDefaultPrinter = (Object object, {String name, StackTrace stackTrace, LevelMessages level}) { - String _prepareString() { + String _coloredString(String string) { switch (level) { case LevelMessages.debug: // white - return '\u001b[37m[INFO] ${object.toString()}\u001b[0m'; + return '\u001b[37m$string\u001b[0m'; case LevelMessages.info: // green - return '\u001b[32m[INFO] ${object.toString()}\u001b[0m'; + return '\u001b[32m$string\u001b[0m'; case LevelMessages.warning: // blue - return '\u001B[34m[WARNING] ${object.toString()}\u001b[0m'; + return '\u001B[34m$string\u001b[0m'; case LevelMessages.error: // red - return '\u001b[31m[ERROR] ${object.toString()}\u001b[0m'; + return '\u001b[31m$string\u001b[0m'; default: // gray - return '\u001b[90m${object.toString()}\u001b[0m'; + return '\u001b[90m$string\u001b[0m'; + } + } + + String _prepareObject() { + switch (level) { + case LevelMessages.debug: + return _coloredString('[$name] [DEBUG] ${object.toString()}'); + case LevelMessages.info: + return _coloredString('[$name] [INFO] ${object.toString()}'); + case LevelMessages.warning: + return _coloredString('[$name] [WARNING] ${object.toString()}'); + case LevelMessages.error: + return _coloredString('[$name] [ERROR] ${object.toString()}'); + default: + return _coloredString('[$name] ${object.toString()}'); } } - log( - _prepareString(), - name: name, - stackTrace: stackTrace, - ); + print(_prepareObject()); + + if (stackTrace != null) { + String stackTraceString; + stackTraceString = '__________________________________\n${stackTrace.toString()}'; + print(_coloredString(stackTraceString)); + } }; From 559355301c0fd37f26a77b56c6a4f83c7ab9960a Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sat, 16 Jan 2021 22:18:29 +0500 Subject: [PATCH 07/52] fix printer --- packages/easy_logger/lib/src/logger_printer.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/easy_logger/lib/src/logger_printer.dart b/packages/easy_logger/lib/src/logger_printer.dart index 9db1a92b..0c6e6b6d 100644 --- a/packages/easy_logger/lib/src/logger_printer.dart +++ b/packages/easy_logger/lib/src/logger_printer.dart @@ -43,8 +43,7 @@ EasyLogPrinter easyLogDefaultPrinter = (Object object, {String name, StackTrace print(_prepareObject()); if (stackTrace != null) { - String stackTraceString; - stackTraceString = '__________________________________\n${stackTrace.toString()}'; - print(_coloredString(stackTraceString)); + print(_coloredString('__________________________________')); + print(_coloredString('${stackTrace.toString()}')); } }; From ddc4ae5a2728f68c7a23f3efd516dfdf106c27e3 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 17 Jan 2021 00:21:58 +0500 Subject: [PATCH 08/52] update tests --- lib/src/easy_localization_app.dart | 1 + test/easy_localization_logger_test.dart | 70 +++++++++++++++++++++++++ test/easy_localization_utils_test.dart | 33 ++---------- 3 files changed, 74 insertions(+), 30 deletions(-) create mode 100644 test/easy_localization_logger_test.dart diff --git a/lib/src/easy_localization_app.dart b/lib/src/easy_localization_app.dart index 8dbe49c0..2ddcead1 100644 --- a/lib/src/easy_localization_app.dart +++ b/lib/src/easy_localization_app.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:developer'; +import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/src/easy_localization_controller.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; diff --git a/test/easy_localization_logger_test.dart b/test/easy_localization_logger_test.dart new file mode 100644 index 00000000..a3bd8d7c --- /dev/null +++ b/test/easy_localization_logger_test.dart @@ -0,0 +1,70 @@ +import 'dart:async'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:easy_logger/easy_logger.dart'; +import 'package:flutter_test/flutter_test.dart'; + +List printLog = []; +dynamic overridePrint(Function() testFn) => () { + var spec = ZoneSpecification(print: (_, __, ___, String msg) { + // Add to log instead of printing to stdout + printLog.add(msg); + }); + return Zone.current.fork(specification: spec).run(testFn); + }; + +void main() async { + group('Logger testing', () { + test('Logger enable', () { + expect(EasyLocalization.logger, equals(EasyLocalization.logger)); + expect(EasyLocalization.logger, isNotNull); + }); + + test('Logger print', overridePrint(() { + printLog = []; + EasyLocalization.logger('Same print'); + expect(printLog.first, contains('Same print')); + expect(printLog.first, contains(EasyLocalization.logger.name)); + })); + + test('Logger print info', overridePrint(() { + printLog = []; + EasyLocalization.logger('print info', level: LevelMessages.info); + expect(printLog.first, contains('print info')); + expect(printLog.first, contains('[INFO]')); + })); + + test('Logger print debug', overridePrint(() { + printLog = []; + EasyLocalization.logger('print debug', level: LevelMessages.debug); + expect(printLog.first, contains('print debug')); + expect(printLog.first, contains('[DEBUG]')); + })); + + test('Logger print warning', overridePrint(() { + printLog = []; + EasyLocalization.logger('print warning', level: LevelMessages.warning); + expect(printLog.first, contains('print warning')); + expect(printLog.first, contains('[WARNING]')); + })); + + test('Logger print error', overridePrint(() { + printLog = []; + EasyLocalization.logger('print error', level: LevelMessages.error); + expect(printLog.first, contains('print error')); + expect(printLog.first, contains('[ERROR]')); + })); + + test('Logger print error with StackTrace', overridePrint(() { + printLog = []; + + StackTrace testStackTrace; + testStackTrace = StackTrace.fromString('test stack'); + + EasyLocalization.logger('print error', level: LevelMessages.error, stackTrace: testStackTrace); + expect(printLog.first, contains('print error')); + expect(printLog.first, contains('[ERROR]')); + expect(printLog.last, contains('test stack')); + })); + }); +} diff --git a/test/easy_localization_utils_test.dart b/test/easy_localization_utils_test.dart index 60b2313a..40dde5b7 100644 --- a/test/easy_localization_utils_test.dart +++ b/test/easy_localization_utils_test.dart @@ -28,47 +28,20 @@ void main() { test('localeFromString language, country, script code', () { var locale = localeFromString('zh_Hant_HK'); - expect( - locale, - Locale.fromSubtags( - languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK')); + expect(locale, Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK')); }); test('localeToString', () { - var locale = Locale.fromSubtags( - languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'); + var locale = Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'); var string = localeToString(locale); expect(string, 'zh_Hant_HK'); }); test('localeToString custom separator', () { - var locale = Locale.fromSubtags( - languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'); + var locale = Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'); var string = localeToString(locale, separator: '|'); expect(string, 'zh|Hant|HK'); }); }); - - group('Prints', () { - test('Info print', overridePrint(() { - printLog = []; - printInfo('Info'); - expect(printLog.first, '\u001b[32mEasy Localization: Info\u001b[0m'); - })); - - test('Warning print', overridePrint(() { - printLog = []; - printWarning('Warning'); - expect(printLog.first, - '\u001B[34m[WARNING] Easy Localization: Warning\u001b[0m'); - })); - - test('Error print', overridePrint(() { - printLog = []; - printError('Error'); - expect(printLog.first, - '\u001b[31m[ERROR] Easy Localization: Error\u001b[0m'); - })); - }); }); } From a5df3dd341468c931e7c8d5eb949703526286095 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 17 Jan 2021 00:26:22 +0500 Subject: [PATCH 09/52] update linter EasyLogger --- packages/easy_logger/analysis_options.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/easy_logger/analysis_options.yaml b/packages/easy_logger/analysis_options.yaml index dfab32b6..86bd4221 100644 --- a/packages/easy_logger/analysis_options.yaml +++ b/packages/easy_logger/analysis_options.yaml @@ -14,5 +14,5 @@ linter: avoid_classes_with_only_static_members: false sort_constructors_first: true prefer_single_quotes: true - public_member_api_docs: true + public_member_api_docs: true always_specify_types: true \ No newline at end of file From 4dbe8fd1b57fc9d2bb4edbca55df03653afed352 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 17 Jan 2021 00:48:01 +0500 Subject: [PATCH 10/52] fix tests --- test/easy_localization_context_test.dart | 28 +++----- test/easy_localization_logger_test.dart | 3 + test/easy_localization_test.dart | 80 +++++++-------------- test/easy_localization_widget_test.dart | 89 +++++++----------------- 4 files changed, 66 insertions(+), 134 deletions(-) diff --git a/test/easy_localization_context_test.dart b/test/easy_localization_context_test.dart index 58a19ca9..f6558fc7 100644 --- a/test/easy_localization_context_test.dart +++ b/test/easy_localization_context_test.dart @@ -1,5 +1,6 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/src/localization.dart'; +import 'package:easy_logger/easy_logger.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -36,6 +37,8 @@ class MyWidget extends StatelessWidget { void main() async { SharedPreferences.setMockInitialValues({}); + EasyLocalization.logger.enableLevels = [LevelMessages.error, LevelMessages.warning]; + await EasyLocalization.ensureInitialized(); group('BuildContext', () { testWidgets( @@ -94,8 +97,7 @@ void main() async { await tester.pumpAndSettle(); expect(Localization.of(_context), isInstanceOf()); - expect(_context.supportedLocales, - [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(_context.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(_context.locale, Locale('en', 'US')); var trFinder = find.text('test'); @@ -126,8 +128,7 @@ void main() async { expect(_context.locale, l); l = Locale('en', 'UK'); - expect( - () async => {await _context.setLocale(l)}, throwsAssertionError); + expect(() async => {await _context.setLocale(l)}, throwsAssertionError); l = Locale('ar', 'DZ'); await _context.setLocale(l); @@ -156,8 +157,7 @@ void main() async { await tester.pumpAndSettle(); - expect(_context.supportedLocales, - [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(_context.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(_context.locale, Locale('ar', 'DZ')); var trFinder = find.text('اختبار'); @@ -211,9 +211,7 @@ void main() async { saveLocale: false, useOnlyLangCode: true, // fallbackLocale:Locale('en') , - supportedLocales: [ - Locale('ar') - ], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [Locale('ar')], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump @@ -241,10 +239,7 @@ void main() async { child: MyApp(), path: 'i18n', // fallbackLocale:Locale('en') , - supportedLocales: [ - Locale('en', 'US'), - Locale('ar', 'DZ') - ], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump @@ -259,15 +254,12 @@ void main() async { testWidgets( '[EasyLocalization] after deleteSaveLocale test', (WidgetTester tester) async { - await tester.runAsync(() async { + await tester.runAsync(() async { await tester.pumpWidget(EasyLocalization( child: MyApp(), path: 'i18n', // fallbackLocale:Locale('en') , - supportedLocales: [ - Locale('en', 'US'), - Locale('ar', 'DZ') - ], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump diff --git a/test/easy_localization_logger_test.dart b/test/easy_localization_logger_test.dart index a3bd8d7c..d9aba07a 100644 --- a/test/easy_localization_logger_test.dart +++ b/test/easy_localization_logger_test.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:easy_localization/easy_localization.dart'; import 'package:easy_logger/easy_logger.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:shared_preferences/shared_preferences.dart'; List printLog = []; dynamic overridePrint(Function() testFn) => () { @@ -14,6 +15,8 @@ dynamic overridePrint(Function() testFn) => () { }; void main() async { + SharedPreferences.setMockInitialValues({}); + group('Logger testing', () { test('Logger enable', () { expect(EasyLocalization.logger, equals(EasyLocalization.logger)); diff --git a/test/easy_localization_test.dart b/test/easy_localization_test.dart index fc2a9aa8..026da6fa 100644 --- a/test/easy_localization_test.dart +++ b/test/easy_localization_test.dart @@ -5,6 +5,7 @@ import 'dart:ui'; import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/src/easy_localization_controller.dart'; import 'package:easy_localization/src/localization.dart'; +import 'package:easy_logger/easy_logger.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:intl/intl.dart'; @@ -43,6 +44,8 @@ void main() { saveLocale: false, assetLoader: JsonAssetLoader()); setUpAll(() async { + EasyLocalization.logger.enableLevels = [LevelMessages.error, LevelMessages.warning]; + await r1.loadTranslations(); await r2.loadTranslations(); Localization.load(Locale('en'), translations: r1.translations); @@ -59,16 +62,13 @@ void main() { }); test('load() succeeds', () async { - expect( - Localization.load(Locale('en'), translations: r1.translations), true); + expect(Localization.load(Locale('en'), translations: r1.translations), true); }); test('localeFromString() succeeds', () async { expect(Locale('ar'), localeFromString('ar')); expect(Locale('ar', 'DZ'), localeFromString('ar_DZ')); - expect( - Locale.fromSubtags( - languageCode: 'ar', scriptCode: 'Arab', countryCode: 'DZ'), + expect(Locale.fromSubtags(languageCode: 'ar', scriptCode: 'Arab', countryCode: 'DZ'), localeFromString('ar_Arab_DZ')); }); @@ -82,19 +82,15 @@ void main() { }); test('load() correctly sets locale path', () async { - expect( - Localization.load(Locale('en'), translations: r1.translations), true); + expect(Localization.load(Locale('en'), translations: r1.translations), true); expect(Localization.instance.tr('path'), 'path/en.json'); }); test('load() respects useOnlyLangCode', () async { - expect( - Localization.load(Locale('en'), translations: r1.translations), true); + expect(Localization.load(Locale('en'), translations: r1.translations), true); expect(Localization.instance.tr('path'), 'path/en.json'); - expect( - Localization.load(Locale('en', 'us'), translations: r2.translations), - true); + expect(Localization.load(Locale('en', 'us'), translations: r2.translations), true); expect(Localization.instance.tr('path'), 'path/en-us.json'); }); @@ -136,34 +132,25 @@ void main() { }); test('can resolve linked locale messages and apply modifiers', () { - expect(Localization.instance.tr('linkAndModify'), - 'this is linked and MODIFIED'); + expect(Localization.instance.tr('linkAndModify'), 'this is linked and MODIFIED'); }); - test('can resolve multiple linked locale messages and apply modifiers', - () { + test('can resolve multiple linked locale messages and apply modifiers', () { expect(Localization.instance.tr('linkMany'), 'many Locale messages'); }); test('can resolve linked locale messages with brackets', () { - expect(Localization.instance.tr('linkedWithBrackets'), - 'linked with brackets.'); + expect(Localization.instance.tr('linkedWithBrackets'), 'linked with brackets.'); }); test('can resolve any number of nested arguments', () { - expect( - Localization.instance - .tr('nestedArguments', args: ['a', 'argument', '!']), - 'this is a nested argument!'); + expect(Localization.instance.tr('nestedArguments', args: ['a', 'argument', '!']), 'this is a nested argument!'); }); test('can resolve nested named arguments', () { expect( - Localization.instance.tr('nestedNamedArguments', namedArgs: { - 'firstArg': 'this', - 'secondArg': 'named argument', - 'thirdArg': '!' - }), + Localization.instance.tr('nestedNamedArguments', + namedArgs: {'firstArg': 'this', 'secondArg': 'named argument', 'thirdArg': '!'}), 'this is a nested named argument!'); }); @@ -174,8 +161,7 @@ void main() { test('reports missing resource', overridePrint(() { printLog = []; expect(Localization.instance.tr('test_missing'), 'test_missing'); - expect(printLog.first, - '\u001B[34m[WARNING] Easy Localization: Localization key [test_missing] not found\u001b[0m'); + expect(printLog.first, contains('Localization key [test_missing] not found')); })); test('returns resource and replaces argument', () { @@ -186,8 +172,7 @@ void main() { }); test('returns resource and replaces argument in any nest level', () { expect( - Localization.instance - .tr('nested.super.duper.nested_with_arg', args: ['what a nest']), + Localization.instance.tr('nested.super.duper.nested_with_arg', args: ['what a nest']), 'nested.super.duper.nested_with_arg what a nest', ); }); @@ -199,25 +184,20 @@ void main() { ); }); - test( - 'should raise exception if provided arguments length is different from the count of {} in the resource', - () { + test('should raise exception if provided arguments length is different from the count of {} in the resource', () { // @TODO }); test('return resource and replaces named argument', () { expect( - Localization.instance.tr('test_replace_named', - namedArgs: {'arg1': 'one', 'arg2': 'two'}), + Localization.instance.tr('test_replace_named', namedArgs: {'arg1': 'one', 'arg2': 'two'}), 'test named replace one two', ); }); - test('returns resource and replaces named argument in any nest level', - () { + test('returns resource and replaces named argument in any nest level', () { expect( - Localization.instance.tr('nested.super.duper.nested_with_named_arg', - namedArgs: {'arg': 'what a nest'}), + Localization.instance.tr('nested.super.duper.nested_with_named_arg', namedArgs: {'arg': 'what a nest'}), 'nested.super.duper.nested_with_named_arg what a nest', ); }); @@ -235,13 +215,11 @@ void main() { test('gender returns the correct resource and replaces args', () { expect( - Localization.instance - .tr('gender_and_replace', gender: 'male', args: ['one']), + Localization.instance.tr('gender_and_replace', gender: 'male', args: ['one']), 'Hi one man ;)', ); expect( - Localization.instance - .tr('gender_and_replace', gender: 'female', args: ['one']), + Localization.instance.tr('gender_and_replace', gender: 'female', args: ['one']), 'Hello one girl :)', ); }); @@ -279,25 +257,19 @@ void main() { }); test('with number format', () { - expect( - Localization.instance - .plural('day', 3, format: NumberFormat.currency()), - 'USD3.00 other days'); + expect(Localization.instance.plural('day', 3, format: NumberFormat.currency()), 'USD3.00 other days'); }); test('zero with args', () { - expect(Localization.instance.plural('money', 0, args: ['John', '0']), - 'John has no money'); + expect(Localization.instance.plural('money', 0, args: ['John', '0']), 'John has no money'); }); test('one with args', () { - expect(Localization.instance.plural('money', 1, args: ['John', '1']), - 'John has 1 dollar'); + expect(Localization.instance.plural('money', 1, args: ['John', '1']), 'John has 1 dollar'); }); test('other with args', () { - expect(Localization.instance.plural('money', 3, args: ['John', '3']), - 'John has 3 dollars'); + expect(Localization.instance.plural('money', 3, args: ['John', '3']), 'John has 3 dollars'); }); }); diff --git a/test/easy_localization_widget_test.dart b/test/easy_localization_widget_test.dart index 42e658ba..5b25f030 100644 --- a/test/easy_localization_widget_test.dart +++ b/test/easy_localization_widget_test.dart @@ -1,5 +1,6 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/src/localization.dart'; +import 'package:easy_logger/easy_logger.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -37,7 +38,9 @@ class MyWidget extends StatelessWidget { void main() async { SharedPreferences.setMockInitialValues({}); + EasyLocalization.logger.enableLevels = [LevelMessages.error, LevelMessages.warning]; await EasyLocalization.ensureInitialized(); + testWidgets( '[EasyLocalization with JsonAssetLoader] test', (WidgetTester tester) async { @@ -56,8 +59,7 @@ void main() async { expect(Localization.of(_context), isInstanceOf()); expect(Localization.instance, isInstanceOf()); expect(Localization.instance, Localization.of(_context)); - expect(EasyLocalization.of(_context).supportedLocales, - [Locale('en', 'US')]); + expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US')]); expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); final trFinder = find.text('test'); @@ -108,8 +110,7 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, - [Locale('en', 'US')]); + expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US')]); expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); final trFinder = find.text('test'); @@ -137,8 +138,7 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, - [Locale('en', 'US')]); + expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US')]); expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); final trFinder = find.text('test'); @@ -184,8 +184,7 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, - [Locale('en', 'US')]); + expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US')]); expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); var l = Locale('en', 'US'); @@ -228,8 +227,7 @@ void main() async { await tester.pumpAndSettle(); expect(Localization.of(_context), isInstanceOf()); - expect(EasyLocalization.of(_context).supportedLocales, - [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); var trFinder = find.text('test'); @@ -260,8 +258,7 @@ void main() async { expect(EasyLocalization.of(_context).locale, l); l = Locale('en', 'UK'); - expect(() async => {await EasyLocalization.of(_context).setLocale(l)}, - throwsAssertionError); + expect(() async => {await EasyLocalization.of(_context).setLocale(l)}, throwsAssertionError); l = Locale('ar', 'DZ'); await EasyLocalization.of(_context).setLocale(l); @@ -290,8 +287,7 @@ void main() async { await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, - [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(EasyLocalization.of(_context).locale, Locale('ar', 'DZ')); var trFinder = find.text('اختبار'); @@ -321,17 +317,13 @@ void main() async { path: 'i18n', saveLocale: false, useOnlyLangCode: true, - supportedLocales: [ - Locale('en'), - Locale('ar') - ], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [Locale('en'), Locale('ar')], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, - [Locale('en'), Locale('ar')]); + expect(EasyLocalization.of(_context).supportedLocales, [Locale('en'), Locale('ar')]); expect(EasyLocalization.of(_context).locale, Locale('en')); var l = Locale('en'); @@ -350,17 +342,13 @@ void main() async { path: 'i18n', saveLocale: false, useOnlyLangCode: true, - supportedLocales: [ - Locale('en'), - Locale('ar') - ], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [Locale('en'), Locale('ar')], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, - [Locale('en'), Locale('ar')]); + expect(EasyLocalization.of(_context).supportedLocales, [Locale('en'), Locale('ar')]); expect(EasyLocalization.of(_context).locale, Locale('en')); var l = Locale('en'); @@ -403,9 +391,7 @@ void main() async { saveLocale: false, useOnlyLangCode: true, // fallbackLocale:Locale('en') , - supportedLocales: [ - Locale('ar') - ], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [Locale('ar')], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump @@ -440,8 +426,7 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, - [Locale('en'), Locale('ar')]); + expect(EasyLocalization.of(_context).supportedLocales, [Locale('en'), Locale('ar')]); expect(EasyLocalization.of(_context).locale, Locale('en')); expect(EasyLocalization.of(_context).fallbackLocale, null); }); @@ -462,8 +447,7 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, - [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); expect(EasyLocalization.of(_context).fallbackLocale, null); }); @@ -485,8 +469,7 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, - [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(EasyLocalization.of(_context).locale, Locale('ar', 'DZ')); expect(EasyLocalization.of(_context).fallbackLocale, null); }); @@ -495,7 +478,7 @@ void main() async { }); group('SharedPreferences saveLocale', () { - setUpAll(() async{ + setUpAll(() async { SharedPreferences.setMockInitialValues({ 'locale': 'ar', }); @@ -512,17 +495,13 @@ void main() async { saveLocale: true, // fallbackLocale:Locale('en') , useOnlyLangCode: true, - supportedLocales: [ - Locale('en'), - Locale('ar') - ], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [Locale('en'), Locale('ar')], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, - [Locale('en'), Locale('ar')]); + expect(EasyLocalization.of(_context).supportedLocales, [Locale('en'), Locale('ar')]); expect(EasyLocalization.of(_context).locale, Locale('ar')); expect(EasyLocalization.of(_context).fallbackLocale, null); }); @@ -547,17 +526,13 @@ void main() async { path: 'i18n', saveLocale: true, // fallbackLocale:Locale('en') , - supportedLocales: [ - Locale('en', 'US'), - Locale('ar', 'DZ') - ], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, - [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(EasyLocalization.of(_context).locale, Locale('ar', 'DZ')); expect(EasyLocalization.of(_context).fallbackLocale, null); }); @@ -573,17 +548,13 @@ void main() async { path: 'i18n', saveLocale: false, // fallbackLocale:Locale('en') , - supportedLocales: [ - Locale('en', 'US'), - Locale('ar', 'DZ') - ], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, - [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); await EasyLocalization.of(_context).setLocale(Locale('en', 'US')); @@ -606,10 +577,7 @@ void main() async { child: MyApp(), path: 'i18n', // fallbackLocale:Locale('en') , - supportedLocales: [ - Locale('en', 'US'), - Locale('ar', 'DZ') - ], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump @@ -629,10 +597,7 @@ void main() async { child: MyApp(), path: 'i18n', // fallbackLocale:Locale('en') , - supportedLocales: [ - Locale('en', 'US'), - Locale('ar', 'DZ') - ], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump From b40be38f3307a3f8a4f924820156e24e8e622bad Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sat, 6 Feb 2021 18:49:41 +0500 Subject: [PATCH 11/52] easy logger tests --- .../easy_logger/test/easy_logger_test.dart | 84 ++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/packages/easy_logger/test/easy_logger_test.dart b/packages/easy_logger/test/easy_logger_test.dart index ab73b3a2..c82d9ded 100644 --- a/packages/easy_logger/test/easy_logger_test.dart +++ b/packages/easy_logger/test/easy_logger_test.dart @@ -1 +1,83 @@ -void main() {} +import 'dart:async'; + +import 'package:easy_logger/easy_logger.dart'; +import 'package:flutter_test/flutter_test.dart'; + +List printLog = []; +ZoneSpecification spec; +dynamic Function() overridePrint(Function() testFn) => () { + spec = ZoneSpecification( + print: (_, __, ___, String msg) { + // Add to log instead of printing to stdout + printLog.add(msg); + }, + ); + return Zone.current.fork(specification: spec).run(testFn); + }; + +EasyLogger logger; +void main() { + group('Logger testing print', () { + logger = EasyLogger(name: 'test logger'); + + test('Logger print', overridePrint(() { + printLog = []; + logger('Same print'); + expect(printLog.first, contains('Same print')); + expect(printLog.first, contains(logger.name)); + })); + + test('Logger print info', overridePrint(() { + printLog = []; + logger('print info', level: LevelMessages.info); + expect(printLog.first, contains('print info')); + expect(printLog.first, contains('[INFO]')); + })); + + test('Logger print debug', overridePrint(() { + printLog = []; + logger('print debug', level: LevelMessages.debug); + expect(printLog.first, contains('print debug')); + expect(printLog.first, contains('[DEBUG]')); + })); + + test('Logger print warning', overridePrint(() { + printLog = []; + logger('print warning', level: LevelMessages.warning); + expect(printLog.first, contains('print warning')); + expect(printLog.first, contains('[WARNING]')); + })); + + test('Logger print error', overridePrint(() { + printLog = []; + logger('print error', level: LevelMessages.error); + expect(printLog.first, contains('print error')); + expect(printLog.first, contains('[ERROR]')); + })); + + test('Logger print error with StackTrace', overridePrint(() { + printLog = []; + + StackTrace testStackTrace; + testStackTrace = StackTrace.fromString('test stack'); + + logger('print error', level: LevelMessages.error, stackTrace: testStackTrace); + expect(printLog.first, contains('print error')); + expect(printLog.first, contains('[ERROR]')); + expect(printLog.last, contains('test stack')); + })); + }); + + group('Logger BuildModes', () { + logger = EasyLogger(name: 'test logger'); + + test('Logger BuildModes is not null', () { + expect(logger.enableBuildModes, isNotNull); + expect(logger.enableBuildModes, isNotEmpty); + }); + + test('Logger default enable', () { + expect(logger.isEnabled(LevelMessages.debug), true); + }); + }); +} From 223eb5695b176932a4ad621c173e141fecc4b21a Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 10 Jan 2021 17:33:01 +0500 Subject: [PATCH 12/52] integrating new logger system --- CHANGELOG.md | 1 + README.md | 13 ++++----- lib/src/asset_loader.dart | 3 +- lib/src/easy_localization_app.dart | 29 ++++++++++--------- lib/src/easy_localization_controller.dart | 19 ++++--------- lib/src/localization.dart | 34 ++++++++++------------- lib/src/utils.dart | 19 +------------ pubspec.yaml | 6 +++- 8 files changed, 47 insertions(+), 77 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f95cf69..c755e1ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Removed preloader widget ~~`preloaderWidget`~~ - Added `EasyLocalization.ensureInitialized()`, Needs to be called - fixed many issues. +- customizable logger [EasyLogger] ### [2.3.3] diff --git a/README.md b/README.md index 8549888f..050442be 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,6 @@ Easy and Fast internationalization for your Flutter Apps - ⁉️ Error widget for missing translations - ❤️ Extension methods on `Text` and `BuildContext` - 💻 Code generation for localization files and keys. -- 🖨️ Customizable logger. ## Getting Started @@ -286,7 +285,7 @@ var money = plural('money', 10.23) // output: You have 10.23 dollars var money = plural('money_args', 10.23, args: ['John', '10.23']) // output: John has 10.23 dollars ``` -### Linked translations: +### 🔥 Linked translations: If there's a translation key that will always have the same concrete text as another one you can just link to it. To link to another translation key, all you have to do is to prefix its contents with an `@:` sign followed by the full name of the translation key including the namespace you want to link to. @@ -323,7 +322,7 @@ Example: print('dateLogging'.tr(namedArguments: {'currentDate': DateTime.now().toIso8601String()})); //Output: INFO: the date today is 2020-11-27T16:40:42.657. ``` -### Formatting linked translations: +#### Formatting linked translations: Formatting linked locale messages If the language distinguishes cases of character, you may need to control the case of the linked locale messages. Linked messages can be formatted with modifier `@.modifier:key` @@ -443,11 +442,9 @@ print(LocaleKeys.title.tr()); //String Text(LocaleKeys.title).tr(); //Widget ``` -

- - - -

+### 🖨️ Logger + +///TODO: add info about configure ## Screenshots diff --git a/lib/src/asset_loader.dart b/lib/src/asset_loader.dart index b380f857..81bab17a 100644 --- a/lib/src/asset_loader.dart +++ b/lib/src/asset_loader.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'dart:developer'; import 'dart:ui'; import 'package:easy_localization/easy_localization.dart'; @@ -34,7 +33,7 @@ class RootBundleAssetLoader extends AssetLoader { @override Future> load(String path, Locale locale) async { var localePath = getLocalePath(path, locale); - log('Load asset from $path', name: 'Easy Localization'); + EasyLocalization.logger('Load asset from $path'); return json.decode(await rootBundle.loadString(localePath)); } } diff --git a/lib/src/easy_localization_app.dart b/lib/src/easy_localization_app.dart index 2ddcead1..31726497 100644 --- a/lib/src/easy_localization_app.dart +++ b/lib/src/easy_localization_app.dart @@ -1,8 +1,8 @@ import 'dart:async'; -import 'dart:developer'; import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/src/easy_localization_controller.dart'; +import 'package:easy_logger/easy_logger.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; @@ -82,20 +82,21 @@ class EasyLocalization extends StatefulWidget { assert(supportedLocales != null && supportedLocales.isNotEmpty), assert(path != null && path.isNotEmpty), super(key: key) { - log('Start', name: 'Easy Localization'); + EasyLocalization.logger('Start'); } @override _EasyLocalizationState createState() => _EasyLocalizationState(); - static _EasyLocalizationProvider of(BuildContext context) => - _EasyLocalizationProvider.of(context); + static _EasyLocalizationProvider of(BuildContext context) => _EasyLocalizationProvider.of(context); /// ensureInitialized needs to be called in main /// so that savedLocale is loaded and used from the /// start. - static Future ensureInitialized() async => - EasyLocalizationController.initEasyLocation(); + static Future ensureInitialized() async => EasyLocalizationController.initEasyLocation(); + + /// Customizable logger + static EasyLogger logger = EasyLogger(name: '🌎 Easy Localization'); } class _EasyLocalizationState extends State { @@ -105,7 +106,7 @@ class _EasyLocalizationState extends State { @override void initState() { - log('Init state', name: 'Easy Localization'); + EasyLocalization.logger('Init state'); localizationController = EasyLocalizationController( saveLocale: widget.saveLocale, fallbackLocale: widget.fallbackLocale, @@ -135,7 +136,7 @@ class _EasyLocalizationState extends State { @override Widget build(BuildContext context) { - log('Build', name: 'Easy Localization'); + EasyLocalization.logger('Build'); if (translationsLoadError != null) { return widget.errorWidget != null ? widget.errorWidget(translationsLoadError) @@ -180,11 +181,10 @@ class _EasyLocalizationProvider extends InheritedWidget { // _EasyLocalizationDelegate get delegate => parent.delegate; - _EasyLocalizationProvider(this.parent, this._localeState, - {Key key, this.delegate}) + _EasyLocalizationProvider(this.parent, this._localeState, {Key key, this.delegate}) : currentLocale = _localeState.locale, super(key: key, child: parent.child) { - log('Init provider', name: 'Easy Localization'); + EasyLocalization.logger('Init provider'); } /// Get current locale @@ -224,9 +224,8 @@ class _EasyLocalizationDelegate extends LocalizationsDelegate { /// * use only the lang code to generate i18n file path like en.json or ar.json // final bool useOnlyLangCode; - _EasyLocalizationDelegate( - {this.localizationController, this.supportedLocales}) { - log('Init Localization Delegate', name: 'Easy Localization'); + _EasyLocalizationDelegate({this.localizationController, this.supportedLocales}) { + EasyLocalization.logger('Init Localization Delegate'); } @override @@ -234,7 +233,7 @@ class _EasyLocalizationDelegate extends LocalizationsDelegate { @override Future load(Locale value) async { - log('Load Localization Delegate', name: 'Easy Localization'); + EasyLocalization.logger('Load Localization Delegate'); if (localizationController.translations == null) { await localizationController.loadTranslations(); } diff --git a/lib/src/easy_localization_controller.dart b/lib/src/easy_localization_controller.dart index de73c391..72bc7673 100644 --- a/lib/src/easy_localization_controller.dart +++ b/lib/src/easy_localization_controller.dart @@ -1,9 +1,6 @@ -import 'dart:developer'; - import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:intl/intl_standalone.dart' - if (dart.library.html) 'package:intl/intl_browser.dart'; +import 'package:intl/intl_standalone.dart' if (dart.library.html) 'package:intl/intl_browser.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'translations.dart'; @@ -37,25 +34,21 @@ class EasyLocalizationController extends ChangeNotifier { _locale = forceLocale; } else if (_savedLocale == null && startLocale != null) { _locale = _getFallbackLocale(supportedLocales, startLocale); - log('Start locale loaded ${_locale.toString()}', - name: 'Easy Localization'); + EasyLocalization.logger('Start locale loaded ${_locale.toString()}'); } // If saved locale then get else if (saveLocale && _savedLocale != null) { - log('Saved locale loaded ${_savedLocale.toString()}', - name: 'Easy Localization'); + EasyLocalization.logger('Saved locale loaded ${_savedLocale.toString()}'); _locale = _savedLocale; } else { // From Device Locale - _locale = supportedLocales.firstWhere( - (locale) => _checkInitLocale(locale, _osLocale), + _locale = supportedLocales.firstWhere((locale) => _checkInitLocale(locale, _osLocale), orElse: () => _getFallbackLocale(supportedLocales, fallbackLocale)); } } //Get fallback Locale - Locale _getFallbackLocale( - List supportedLocales, Locale fallbackLocale) { + Locale _getFallbackLocale(List supportedLocales, Locale fallbackLocale) { //If fallbackLocale not set then return first from supportedLocales if (fallbackLocale != null) { return fallbackLocale; @@ -113,6 +106,6 @@ class EasyLocalizationController extends ChangeNotifier { _savedLocale = null; final _preferences = await SharedPreferences.getInstance(); await _preferences.setString('locale', null); - log('Saved locale deleted', name: 'Easy Localization'); + EasyLocalization.logger('Saved locale deleted'); } } diff --git a/lib/src/localization.dart b/lib/src/localization.dart index 987a1c07..93fa441f 100644 --- a/lib/src/localization.dart +++ b/lib/src/localization.dart @@ -13,8 +13,7 @@ class Localization { String path; bool useOnlyLangCode; final RegExp _replaceArgRegex = RegExp(r'{}'); - final RegExp _linkKeyMatcher = - RegExp(r'(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))'); + final RegExp _linkKeyMatcher = RegExp(r'(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))'); final RegExp _linkKeyPrefixMatcher = RegExp(r'^@(?:\.([a-z]+))?:'); final RegExp _bracketsMatcher = RegExp(r'[()]'); final _modifiers = { @@ -27,8 +26,7 @@ class Localization { static Localization _instance; static Localization get instance => _instance ?? (_instance = Localization()); - static Localization of(BuildContext context) => - Localizations.of(context, Localization); + static Localization of(BuildContext context) => Localizations.of(context, Localization); static bool load(Locale locale, {Translations translations}) { instance._locale = locale; @@ -36,8 +34,7 @@ class Localization { return translations == null ? false : true; } - String tr(String key, - {List args, Map namedArgs, String gender}) { + String tr(String key, {List args, Map namedArgs, String gender}) { String res; if (gender != null) { @@ -65,8 +62,7 @@ class Localization { final formatterName = linkPrefixMatches.first[1]; // Remove the leading @:, @.case: and the brackets - final linkPlaceholder = - link.replaceAll(linkPrefix, '').replaceAll(_bracketsMatcher, ''); + final linkPlaceholder = link.replaceAll(linkPrefix, '').replaceAll(_bracketsMatcher, ''); var translated = _resolve(linkPlaceholder); @@ -75,14 +71,13 @@ class Localization { translated = _modifiers[formatterName](translated); } else { if (logging) { - printWarning( - 'Undefined modifier $formatterName, available modifiers: ${_modifiers.keys.toString()}'); + EasyLocalization.logger + .warning('Undefined modifier $formatterName, available modifiers: ${_modifiers.keys.toString()}'); } } } - result = - translated.isEmpty ? result : result.replaceAll(link, translated); + result = translated.isEmpty ? result : result.replaceAll(link, translated); } return result; @@ -96,13 +91,11 @@ class Localization { String _replaceNamedArgs(String res, Map args) { if (args == null || args.isEmpty) return res; - args.forEach((String key, String value) => - res = res.replaceAll(RegExp('{$key}'), value)); + args.forEach((String key, String value) => res = res.replaceAll(RegExp('{$key}'), value)); return res; } - String plural(String key, num value, - {List args, NumberFormat format}) { + String plural(String key, num value, {List args, NumberFormat format}) { final res = Intl.pluralLogic(value, zero: _resolvePlural(key, 'zero'), one: _resolvePlural(key, 'one'), @@ -111,8 +104,7 @@ class Localization { many: _resolvePlural(key, 'many'), other: _resolvePlural(key, 'other'), locale: _locale.languageCode); - return _replaceArgs( - res, args ?? [format == null ? '$value' : format.format(value)]); + return _replaceArgs(res, args ?? [format == null ? '$value' : format.format(value)]); } String _gender(String key, {String gender}) => Intl.genderLogic( @@ -127,7 +119,7 @@ class Localization { final resource = _translations.get('$key.$subKey'); if (resource == null && subKey == 'other') { - printError('Plural key [$key.$subKey] required'); + EasyLocalization.logger.error('Plural key [$key.$subKey] required'); return '$key.$subKey'; } else { return resource; @@ -137,7 +129,9 @@ class Localization { String _resolve(String key, {bool logging = true}) { final resource = _translations.get(key); if (resource == null) { - if (logging) printWarning('Localization key [$key] not found'); + if (logging) { + EasyLocalization.logger.warning('Localization key [$key] not found'); + } return key; } return resource; diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 07744788..ef49dc7e 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -8,9 +8,7 @@ Locale localeFromString(String localeString) { return Locale(localeList.first, localeList.last); case 3: return Locale.fromSubtags( - languageCode: localeList.first, - scriptCode: localeList[1], - countryCode: localeList.last); + languageCode: localeList.first, scriptCode: localeList[1], countryCode: localeList.last); default: return Locale(localeList.first); } @@ -20,18 +18,3 @@ Locale localeFromString(String localeString) { String localeToString(Locale locale, {String separator = '_'}) { return locale.toString().split('_').join(separator); } - -/// Emit a [info] log event -void printInfo(String info) { - print('\u001b[32mEasy Localization: $info\u001b[0m'); -} - -/// Emit a [warning] log event -void printWarning(String warning) { - print('\u001B[34m[WARNING] Easy Localization: $warning\u001b[0m'); -} - -/// Emit a [error] log event -void printError(String error) { - print('\u001b[31m[ERROR] Easy Localization: $error\u001b[0m'); -} diff --git a/pubspec.yaml b/pubspec.yaml index 9454ee11..64777c4b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ description: Easy and Fast internationalizing and localization your Flutter Apps homepage: https://github.com/aissat/easy_localization issue_tracker: https://github.com/aissat/easy_localization/issues -version: 3.0.0-dev.1 +version: 3.0.0-dev.2 environment: sdk: ">=2.7.0 <3.0.0" @@ -16,8 +16,12 @@ dependencies: shared_preferences: ^0.5.12+4 args: ^1.6.0 path: ^1.7.0 + easy_logger: + path: packages/easy_logger flutter_localizations: sdk: flutter + + dev_dependencies: flutter_test: sdk: flutter From d078e1deacaa4ad2591bf3b2015a47d93a17d526 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Mon, 11 Jan 2021 15:08:56 +0500 Subject: [PATCH 13/52] add info about Easy logger in readme file --- README.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 050442be..8a1837c9 100644 --- a/README.md +++ b/README.md @@ -444,7 +444,38 @@ Text(LocaleKeys.title).tr(); //Widget ### 🖨️ Logger -///TODO: add info about configure +[Easy Localization] logger based on [Easy logger] + +You can customize logger for you project + +Change enabled build modes: + +```dart +EasyLocalization.logger.enableBuildModes = [BuildMode.profile, BuildMode.debug, BuildMode.release]; +``` + +Change level messages: + +```dart +EasyLocalization.logger.enableLevels = [LevelMessages.debug, LevelMessages.info, LevelMessages.error, LevelMessages.warning]; +``` + +Customize default printer function: + +```dart +EasyLogPrinter customLogPrinter = ( + Object object, { + String name, + StackTrace stackTrace, + LevelMessages level, +}) { + print('$name: ${object.toString()}'); +}; + +EasyLocalization.logger.printer = customLogPrinter; +``` + +///TODO: add lint to [Easy Logger] git. ## Screenshots From 79fb542bbf4329849f66c4188f4c149082347e1d Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 17 Jan 2021 00:21:58 +0500 Subject: [PATCH 14/52] update tests --- test/easy_localization_logger_test.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/easy_localization_logger_test.dart b/test/easy_localization_logger_test.dart index d9aba07a..a3bd8d7c 100644 --- a/test/easy_localization_logger_test.dart +++ b/test/easy_localization_logger_test.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:easy_localization/easy_localization.dart'; import 'package:easy_logger/easy_logger.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:shared_preferences/shared_preferences.dart'; List printLog = []; dynamic overridePrint(Function() testFn) => () { @@ -15,8 +14,6 @@ dynamic overridePrint(Function() testFn) => () { }; void main() async { - SharedPreferences.setMockInitialValues({}); - group('Logger testing', () { test('Logger enable', () { expect(EasyLocalization.logger, equals(EasyLocalization.logger)); From 61d48a25bb64e8d32d1d0e2103c36268294a2ced Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 17 Jan 2021 00:53:23 +0500 Subject: [PATCH 15/52] format --- example/lib/generated/codegen_loader.g.dart | 605 +++++++++--------- example/lib/generated/locale_keys.g.dart | 3 +- example/lib/lang_view.dart | 2 +- example/lib/main.dart | 55 +- lib/src/easy_localization_app.dart | 12 +- lib/src/easy_localization_controller.dart | 9 +- lib/src/localization.dart | 28 +- lib/src/utils.dart | 5 +- packages/easy_logger/lib/src/logger.dart | 3 +- .../easy_logger/lib/src/logger_printer.dart | 6 +- test/easy_localization_context_test.dart | 5 +- test/easy_localization_logger_test.dart | 3 +- test/easy_localization_test.dart | 5 +- test/easy_localization_utils_test.dart | 11 +- test/easy_localization_widget_test.dart | 5 +- 15 files changed, 392 insertions(+), 365 deletions(-) diff --git a/example/lib/generated/codegen_loader.g.dart b/example/lib/generated/codegen_loader.g.dart index 7a08b700..29aa2a5d 100644 --- a/example/lib/generated/codegen_loader.g.dart +++ b/example/lib/generated/codegen_loader.g.dart @@ -6,317 +6,308 @@ import 'dart:ui'; import 'package:easy_localization/easy_localization.dart' show AssetLoader; -class CodegenLoader extends AssetLoader{ +class CodegenLoader extends AssetLoader { const CodegenLoader(); @override - Future> load(String fullPath, Locale locale ) { + Future> load(String fullPath, Locale locale) { return Future.value(mapLocales[locale.toString()]); } - static const Map ar_DZ = { - "title": "السلام", - "msg": "السلام عليكم يا {} في عالم {}", - "msg_named": "{} مكتوبة باللغة {lang}", - "clickMe": "إضغط هنا", - "profile": { - "reset_password": { - "label": "اعادة تعين كلمة السر", - "username": "المستخدم", - "password": "كلمة السر" - } - }, - "clicked": { - "zero": "لم تنقر بعد!", - "one": "لقد نقرت مرة واحدة!", - "two": "لقد قمت بالنقر مرتين!", - "few": " لقد قمت بالنقر {} مرات!", - "many": "لقد قمت بالنقر {} مرة!", - "other": "{} نقرة!" - }, - "amount": { - "zero": "المبلغ : {}", - "one": " المبلغ : {}", - "two": " المبلغ : {}", - "few": " المبلغ : {}", - "many": " المبلغ : {}", - "other": " المبلغ : {}" - }, - "gender": { - "male": " مرحبا يا رجل", - "female": " مرحبا بك يا فتاة", - "with_arg": { - "male": "{} مرحبا يا رجل", - "female": "{} مرحبا بك يا فتاة" - } - }, - "reset_locale": "إعادة تعيين اللغة المحفوظة" -}; -static const Map ar = { - "title": "السلام", - "msg": "السلام عليكم يا {} في عالم {}", - "msg_named": "{} مكتوبة باللغة {lang}", - "clickMe": "إضغط هنا", - "profile": { - "reset_password": { - "label": "اعادة تعين كلمة السر", - "username": "المستخدم", - "password": "كلمة السر" - } - }, - "clicked": { - "zero": "لم تنقر بعد!", - "one": "لقد نقرت مرة واحدة!", - "two": "لقد قمت بالنقر مرتين!", - "few": " لقد قمت بالنقر {} مرات!", - "many": "لقد قمت بالنقر {} مرة!", - "other": "{} نقرة!" - }, - "amount": { - "zero": "المبلغ : {}", - "one": " المبلغ : {}", - "two": " المبلغ : {}", - "few": " المبلغ : {}", - "many": " المبلغ : {}", - "other": " المبلغ : {}" - }, - "gender": { - "male": " مرحبا يا رجل", - "female": " مرحبا بك يا فتاة", - "with_arg": { - "male": "{} مرحبا يا رجل", - "female": "{} مرحبا بك يا فتاة" - } - }, - "reset_locale": "إعادة تعيين اللغة المحفوظة" -}; -static const Map de_DE = { - "title": "Hallo", - "msg": "Hallo {} in der {} welt ", - "msg_named": "{} ist in {lang} geschrieben", - "clickMe": "Click mich", - "profile": { - "reset_password": { - "label": "Password zurücksetzten", - "username": "Name", - "password": "Password" - } - }, - "clicked": { - "zero": "Du hast {} mal geklickt", - "one": "Du hast {} mal geklickt", - "two": "Du hast {} mal geklickt", - "few": "Du hast {} mal geklickt", - "many": "Du hast {} mal geklickt", - "other": "Du hast {} mal geklickt" - }, - "amount": { - "zero": "Deine Klicks: {}", - "one": "Deine Klicks: {}", - "two": "Deine Klicks: {}", - "few": "Deine Klicks: {}", - "many": "Deine Klicks: {}", - "other": "Deine Klicks: {}" - }, - "gender": { - "male": "Hi Mann ;) ", - "female": "Hallo Frau :)", - "with_arg": { - "male": "Hi Mann ;) {}", - "female": "Hallo Frau :) {}" - } - }, - "reset_locale": "Gespeicherte Sprache zurücksettzen" -}; -static const Map de = { - "title": "Hallo", - "msg": "Hallo {} in der {} welt ", - "msg_named": "{} ist in {lang} geschrieben", - "clickMe": "Click mich", - "profile": { - "reset_password": { - "label": "Password zurücksetzten", - "username": "Name", - "password": "Password" - } - }, - "clicked": { - "zero": "Du hast {} mal geklickt", - "one": "Du hast {} mal geklickt", - "two": "Du hast {} mal geklickt", - "few": "Du hast {} mal geklickt", - "many": "Du hast {} mal geklickt", - "other": "Du hast {} mal geklickt" - }, - "amount": { - "zero": "Deine Klicks: {}", - "one": "Deine Klicks: {}", - "two": "Deine Klicks: {}", - "few": "Deine Klicks: {}", - "many": "Deine Klicks: {}", - "other": "Deine Klicks: {}" - }, - "gender": { - "male": "Hi Mann ;) ", - "female": "Hallo Frau :)", - "with_arg": { - "male": "Hi Mann ;) {}", - "female": "Hallo Frau :) {}" - } - }, - "reset_locale": "Gespeicherte Sprache zurücksettzen" -}; -static const Map en_US = { - "title": "Hello", - "msg": "Hello {} in the {} world ", - "msg_named": "{} are written in the {lang} language", - "clickMe": "Click me", - "profile": { - "reset_password": { - "label": "Reset Password", - "username": "Username", - "password": "password" - } - }, - "clicked": { - "zero": "You clicked {} times!", - "one": "You clicked {} time!", - "two": "You clicked {} times!", - "few": "You clicked {} times!", - "many": "You clicked {} times!", - "other": "You clicked {} times!" - }, - "amount": { - "zero": "Your amount : {} ", - "one": "Your amount : {} ", - "two": "Your amount : {} ", - "few": "Your amount : {} ", - "many": "Your amount : {} ", - "other": "Your amount : {} " - }, - "gender": { - "male": "Hi man ;) ", - "female": "Hello girl :)", - "with_arg": { - "male": "Hi man ;) {}", - "female": "Hello girl :) {}" - } - }, - "reset_locale": "Reset Saved Language" -}; -static const Map en = { - "title": "Hello", - "msg": "Hello {} in the {} world ", - "msg_named": "{} are written in the {lang} language", - "clickMe": "Click me", - "profile": { - "reset_password": { - "label": "Reset Password", - "username": "Username", - "password": "password" - } - }, - "clicked": { - "zero": "You clicked {} times!", - "one": "You clicked {} time!", - "two": "You clicked {} times!", - "few": "You clicked {} times!", - "many": "You clicked {} times!", - "other": "You clicked {} times!" - }, - "amount": { - "zero": "Your amount : {} ", - "one": "Your amount : {} ", - "two": "Your amount : {} ", - "few": "Your amount : {} ", - "many": "Your amount : {} ", - "other": "Your amount : {} " - }, - "gender": { - "male": "Hi man ;) ", - "female": "Hello girl :)", - "with_arg": { - "male": "Hi man ;) {}", - "female": "Hello girl :) {}" - } - }, - "reset_locale": "Reset Saved Language" -}; -static const Map ru_RU = { - "title": "Привет!", - "msg": "Привет! {} добро пожаловать {} мир! ", - "msg_named": "{} написан на языке {lang}", - "clickMe": "Нажми на меня", - "profile": { - "reset_password": { - "label": "Сбросить пароль", - "username": "Логин", - "password": "Пароль" - } - }, - "clicked": { - "zero": "Ты кликнул {} раз!", - "one": "Ты кликнул {} раз!", - "two": "Ты кликнул {} раза!", - "few": "Ты кликнул {} раз!", - "many": "Ты кликнул {} раз!", - "other": "Ты кликнул {} раз!" - }, - "amount": { - "zero": "Твой счет : {} ", - "one": "Твой счет : {} ", - "two": "Твой счет : {} ", - "few": "Твой счет : {} ", - "many": "Твой счет : {} ", - "other": "Твой счет : {} " - }, - "gender": { - "male": "Привет мужык ;) ", - "female": "Привет девчуля :)", - "with_arg": { - "male": "Привет мужык ;) {}", - "female": "Привет девчуля :) {}" - } - }, - "reset_locale": "Сбросить сохраненный язык" -}; -static const Map ru = { - "title": "Привет!", - "msg": "Привет! {} добро пожаловать {} мир! ", - "msg_named": "{} написан на языке {lang}", - "clickMe": "Нажми на меня", - "profile": { - "reset_password": { - "label": "Сбросить пароль", - "username": "Логин", - "password": "Пароль" - } - }, - "clicked": { - "zero": "Ты кликнул {} раз!", - "one": "Ты кликнул {} раз!", - "two": "Ты кликнул {} раза!", - "few": "Ты кликнул {} раз!", - "many": "Ты кликнул {} раз!", - "other": "Ты кликнул {} раз!" - }, - "amount": { - "zero": "Твой счет : {} ", - "one": "Твой счет : {} ", - "two": "Твой счет : {} ", - "few": "Твой счет : {} ", - "many": "Твой счет : {} ", - "other": "Твой счет : {} " - }, - "gender": { - "male": "Привет мужык ;) ", - "female": "Привет девчуля :)", - "with_arg": { - "male": "Привет мужык ;) {}", - "female": "Привет девчуля :) {}" - } - }, - "reset_locale": "Сбросить сохраненный язык" -}; -static const Map> mapLocales = {"ar_DZ": ar_DZ, "ar": ar, "de_DE": de_DE, "de": de, "en_US": en_US, "en": en, "ru_RU": ru_RU, "ru": ru}; + static const Map ar_DZ = { + "title": "السلام", + "msg": "السلام عليكم يا {} في عالم {}", + "msg_named": "{} مكتوبة باللغة {lang}", + "clickMe": "إضغط هنا", + "profile": { + "reset_password": { + "label": "اعادة تعين كلمة السر", + "username": "المستخدم", + "password": "كلمة السر" + } + }, + "clicked": { + "zero": "لم تنقر بعد!", + "one": "لقد نقرت مرة واحدة!", + "two": "لقد قمت بالنقر مرتين!", + "few": " لقد قمت بالنقر {} مرات!", + "many": "لقد قمت بالنقر {} مرة!", + "other": "{} نقرة!" + }, + "amount": { + "zero": "المبلغ : {}", + "one": " المبلغ : {}", + "two": " المبلغ : {}", + "few": " المبلغ : {}", + "many": " المبلغ : {}", + "other": " المبلغ : {}" + }, + "gender": { + "male": " مرحبا يا رجل", + "female": " مرحبا بك يا فتاة", + "with_arg": {"male": "{} مرحبا يا رجل", "female": "{} مرحبا بك يا فتاة"} + }, + "reset_locale": "إعادة تعيين اللغة المحفوظة" + }; + static const Map ar = { + "title": "السلام", + "msg": "السلام عليكم يا {} في عالم {}", + "msg_named": "{} مكتوبة باللغة {lang}", + "clickMe": "إضغط هنا", + "profile": { + "reset_password": { + "label": "اعادة تعين كلمة السر", + "username": "المستخدم", + "password": "كلمة السر" + } + }, + "clicked": { + "zero": "لم تنقر بعد!", + "one": "لقد نقرت مرة واحدة!", + "two": "لقد قمت بالنقر مرتين!", + "few": " لقد قمت بالنقر {} مرات!", + "many": "لقد قمت بالنقر {} مرة!", + "other": "{} نقرة!" + }, + "amount": { + "zero": "المبلغ : {}", + "one": " المبلغ : {}", + "two": " المبلغ : {}", + "few": " المبلغ : {}", + "many": " المبلغ : {}", + "other": " المبلغ : {}" + }, + "gender": { + "male": " مرحبا يا رجل", + "female": " مرحبا بك يا فتاة", + "with_arg": {"male": "{} مرحبا يا رجل", "female": "{} مرحبا بك يا فتاة"} + }, + "reset_locale": "إعادة تعيين اللغة المحفوظة" + }; + static const Map de_DE = { + "title": "Hallo", + "msg": "Hallo {} in der {} welt ", + "msg_named": "{} ist in {lang} geschrieben", + "clickMe": "Click mich", + "profile": { + "reset_password": { + "label": "Password zurücksetzten", + "username": "Name", + "password": "Password" + } + }, + "clicked": { + "zero": "Du hast {} mal geklickt", + "one": "Du hast {} mal geklickt", + "two": "Du hast {} mal geklickt", + "few": "Du hast {} mal geklickt", + "many": "Du hast {} mal geklickt", + "other": "Du hast {} mal geklickt" + }, + "amount": { + "zero": "Deine Klicks: {}", + "one": "Deine Klicks: {}", + "two": "Deine Klicks: {}", + "few": "Deine Klicks: {}", + "many": "Deine Klicks: {}", + "other": "Deine Klicks: {}" + }, + "gender": { + "male": "Hi Mann ;) ", + "female": "Hallo Frau :)", + "with_arg": {"male": "Hi Mann ;) {}", "female": "Hallo Frau :) {}"} + }, + "reset_locale": "Gespeicherte Sprache zurücksettzen" + }; + static const Map de = { + "title": "Hallo", + "msg": "Hallo {} in der {} welt ", + "msg_named": "{} ist in {lang} geschrieben", + "clickMe": "Click mich", + "profile": { + "reset_password": { + "label": "Password zurücksetzten", + "username": "Name", + "password": "Password" + } + }, + "clicked": { + "zero": "Du hast {} mal geklickt", + "one": "Du hast {} mal geklickt", + "two": "Du hast {} mal geklickt", + "few": "Du hast {} mal geklickt", + "many": "Du hast {} mal geklickt", + "other": "Du hast {} mal geklickt" + }, + "amount": { + "zero": "Deine Klicks: {}", + "one": "Deine Klicks: {}", + "two": "Deine Klicks: {}", + "few": "Deine Klicks: {}", + "many": "Deine Klicks: {}", + "other": "Deine Klicks: {}" + }, + "gender": { + "male": "Hi Mann ;) ", + "female": "Hallo Frau :)", + "with_arg": {"male": "Hi Mann ;) {}", "female": "Hallo Frau :) {}"} + }, + "reset_locale": "Gespeicherte Sprache zurücksettzen" + }; + static const Map en_US = { + "title": "Hello", + "msg": "Hello {} in the {} world ", + "msg_named": "{} are written in the {lang} language", + "clickMe": "Click me", + "profile": { + "reset_password": { + "label": "Reset Password", + "username": "Username", + "password": "password" + } + }, + "clicked": { + "zero": "You clicked {} times!", + "one": "You clicked {} time!", + "two": "You clicked {} times!", + "few": "You clicked {} times!", + "many": "You clicked {} times!", + "other": "You clicked {} times!" + }, + "amount": { + "zero": "Your amount : {} ", + "one": "Your amount : {} ", + "two": "Your amount : {} ", + "few": "Your amount : {} ", + "many": "Your amount : {} ", + "other": "Your amount : {} " + }, + "gender": { + "male": "Hi man ;) ", + "female": "Hello girl :)", + "with_arg": {"male": "Hi man ;) {}", "female": "Hello girl :) {}"} + }, + "reset_locale": "Reset Saved Language" + }; + static const Map en = { + "title": "Hello", + "msg": "Hello {} in the {} world ", + "msg_named": "{} are written in the {lang} language", + "clickMe": "Click me", + "profile": { + "reset_password": { + "label": "Reset Password", + "username": "Username", + "password": "password" + } + }, + "clicked": { + "zero": "You clicked {} times!", + "one": "You clicked {} time!", + "two": "You clicked {} times!", + "few": "You clicked {} times!", + "many": "You clicked {} times!", + "other": "You clicked {} times!" + }, + "amount": { + "zero": "Your amount : {} ", + "one": "Your amount : {} ", + "two": "Your amount : {} ", + "few": "Your amount : {} ", + "many": "Your amount : {} ", + "other": "Your amount : {} " + }, + "gender": { + "male": "Hi man ;) ", + "female": "Hello girl :)", + "with_arg": {"male": "Hi man ;) {}", "female": "Hello girl :) {}"} + }, + "reset_locale": "Reset Saved Language" + }; + static const Map ru_RU = { + "title": "Привет!", + "msg": "Привет! {} добро пожаловать {} мир! ", + "msg_named": "{} написан на языке {lang}", + "clickMe": "Нажми на меня", + "profile": { + "reset_password": { + "label": "Сбросить пароль", + "username": "Логин", + "password": "Пароль" + } + }, + "clicked": { + "zero": "Ты кликнул {} раз!", + "one": "Ты кликнул {} раз!", + "two": "Ты кликнул {} раза!", + "few": "Ты кликнул {} раз!", + "many": "Ты кликнул {} раз!", + "other": "Ты кликнул {} раз!" + }, + "amount": { + "zero": "Твой счет : {} ", + "one": "Твой счет : {} ", + "two": "Твой счет : {} ", + "few": "Твой счет : {} ", + "many": "Твой счет : {} ", + "other": "Твой счет : {} " + }, + "gender": { + "male": "Привет мужык ;) ", + "female": "Привет девчуля :)", + "with_arg": { + "male": "Привет мужык ;) {}", + "female": "Привет девчуля :) {}" + } + }, + "reset_locale": "Сбросить сохраненный язык" + }; + static const Map ru = { + "title": "Привет!", + "msg": "Привет! {} добро пожаловать {} мир! ", + "msg_named": "{} написан на языке {lang}", + "clickMe": "Нажми на меня", + "profile": { + "reset_password": { + "label": "Сбросить пароль", + "username": "Логин", + "password": "Пароль" + } + }, + "clicked": { + "zero": "Ты кликнул {} раз!", + "one": "Ты кликнул {} раз!", + "two": "Ты кликнул {} раза!", + "few": "Ты кликнул {} раз!", + "many": "Ты кликнул {} раз!", + "other": "Ты кликнул {} раз!" + }, + "amount": { + "zero": "Твой счет : {} ", + "one": "Твой счет : {} ", + "two": "Твой счет : {} ", + "few": "Твой счет : {} ", + "many": "Твой счет : {} ", + "other": "Твой счет : {} " + }, + "gender": { + "male": "Привет мужык ;) ", + "female": "Привет девчуля :)", + "with_arg": { + "male": "Привет мужык ;) {}", + "female": "Привет девчуля :) {}" + } + }, + "reset_locale": "Сбросить сохраненный язык" + }; + static const Map> mapLocales = { + "ar_DZ": ar_DZ, + "ar": ar, + "de_DE": de_DE, + "de": de, + "en_US": en_US, + "en": en, + "ru_RU": ru_RU, + "ru": ru + }; } diff --git a/example/lib/generated/locale_keys.g.dart b/example/lib/generated/locale_keys.g.dart index a96b713a..fa46008f 100644 --- a/example/lib/generated/locale_keys.g.dart +++ b/example/lib/generated/locale_keys.g.dart @@ -1,6 +1,6 @@ // DO NOT EDIT. This is code generated via package:easy_localization/generate.dart -abstract class LocaleKeys { +abstract class LocaleKeys { static const title = 'title'; static const msg = 'msg'; static const msg_named = 'msg_named'; @@ -15,5 +15,4 @@ abstract class LocaleKeys { static const gender_with_arg = 'gender.with_arg'; static const gender = 'gender'; static const reset_locale = 'reset_locale'; - } diff --git a/example/lib/lang_view.dart b/example/lib/lang_view.dart index 89702f27..ca272a47 100644 --- a/example/lib/lang_view.dart +++ b/example/lib/lang_view.dart @@ -94,7 +94,7 @@ class LanguageView extends StatelessWidget { subtitle: Text( subtitle, ), - onTap: () async{ + onTap: () async { log(locale.toString(), name: toString()); await context.setLocale(locale); //BuildContext extension method //EasyLocalization.of(context).locale = locale; diff --git a/example/lib/main.dart b/example/lib/main.dart index f57e70bd..8a5a7504 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -8,36 +8,36 @@ import 'package:flutter_icons/flutter_icons.dart'; import 'generated/locale_keys.g.dart'; import 'lang_view.dart'; -void main() async{ +void main() async { WidgetsFlutterBinding.ensureInitialized(); await EasyLocalization.ensureInitialized(); runApp(EasyLocalization( - child: MyApp(), - supportedLocales: [ - Locale('en', 'US'), - Locale('ar', 'DZ'), - Locale('de', 'DE'), - Locale('ru', 'RU') - ], - path: 'resources/langs/langs.csv', //'resources/langs', - // fallbackLocale: Locale('en', 'US'), - // startLocale: Locale('de', 'DE'), - // saveLocale: false, - // useOnlyLangCode: true, + child: MyApp(), + supportedLocales: [ + Locale('en', 'US'), + Locale('ar', 'DZ'), + Locale('de', 'DE'), + Locale('ru', 'RU') + ], + path: 'resources/langs/langs.csv', //'resources/langs', + // fallbackLocale: Locale('en', 'US'), + // startLocale: Locale('de', 'DE'), + // saveLocale: false, + // useOnlyLangCode: true, - // optional assetLoader default used is RootBundleAssetLoader which uses flutter's assetloader - // install easy_localization_loader for enable custom loaders - // assetLoader: RootBundleAssetLoader() - // assetLoader: HttpAssetLoader() - // assetLoader: FileAssetLoader() - assetLoader: CsvAssetLoader() - // assetLoader: YamlAssetLoader() //multiple files - // assetLoader: YamlSingleAssetLoader() //single file - // assetLoader: XmlAssetLoader() //multiple files - // assetLoader: XmlSingleAssetLoader() //single file - // assetLoader: CodegenLoader() - )); + // optional assetLoader default used is RootBundleAssetLoader which uses flutter's assetloader + // install easy_localization_loader for enable custom loaders + // assetLoader: RootBundleAssetLoader() + // assetLoader: HttpAssetLoader() + // assetLoader: FileAssetLoader() + assetLoader: CsvAssetLoader() + // assetLoader: YamlAssetLoader() //multiple files + // assetLoader: YamlSingleAssetLoader() //single file + // assetLoader: XmlAssetLoader() //multiple files + // assetLoader: XmlSingleAssetLoader() //single file + // assetLoader: CodegenLoader() + )); } class MyApp extends StatelessWidget { @@ -132,7 +132,8 @@ class _MyHomePageState extends State { flex: 1, ), Text(LocaleKeys.msg).tr(args: ['aissat', 'Flutter']), - Text(LocaleKeys.msg_named).tr(namedArgs: {'lang': 'Dart'}, args: ['Easy localization']), + Text(LocaleKeys.msg_named) + .tr(namedArgs: {'lang': 'Dart'}, args: ['Easy localization']), Text(LocaleKeys.clicked).plural(counter), FlatButton( onPressed: () { @@ -172,4 +173,4 @@ class _MyHomePageState extends State { ), ); } -} \ No newline at end of file +} diff --git a/lib/src/easy_localization_app.dart b/lib/src/easy_localization_app.dart index 31726497..fa3923a4 100644 --- a/lib/src/easy_localization_app.dart +++ b/lib/src/easy_localization_app.dart @@ -88,12 +88,14 @@ class EasyLocalization extends StatefulWidget { @override _EasyLocalizationState createState() => _EasyLocalizationState(); - static _EasyLocalizationProvider of(BuildContext context) => _EasyLocalizationProvider.of(context); + static _EasyLocalizationProvider of(BuildContext context) => + _EasyLocalizationProvider.of(context); /// ensureInitialized needs to be called in main /// so that savedLocale is loaded and used from the /// start. - static Future ensureInitialized() async => EasyLocalizationController.initEasyLocation(); + static Future ensureInitialized() async => + EasyLocalizationController.initEasyLocation(); /// Customizable logger static EasyLogger logger = EasyLogger(name: '🌎 Easy Localization'); @@ -181,7 +183,8 @@ class _EasyLocalizationProvider extends InheritedWidget { // _EasyLocalizationDelegate get delegate => parent.delegate; - _EasyLocalizationProvider(this.parent, this._localeState, {Key key, this.delegate}) + _EasyLocalizationProvider(this.parent, this._localeState, + {Key key, this.delegate}) : currentLocale = _localeState.locale, super(key: key, child: parent.child) { EasyLocalization.logger('Init provider'); @@ -224,7 +227,8 @@ class _EasyLocalizationDelegate extends LocalizationsDelegate { /// * use only the lang code to generate i18n file path like en.json or ar.json // final bool useOnlyLangCode; - _EasyLocalizationDelegate({this.localizationController, this.supportedLocales}) { + _EasyLocalizationDelegate( + {this.localizationController, this.supportedLocales}) { EasyLocalization.logger('Init Localization Delegate'); } diff --git a/lib/src/easy_localization_controller.dart b/lib/src/easy_localization_controller.dart index 72bc7673..82961f1f 100644 --- a/lib/src/easy_localization_controller.dart +++ b/lib/src/easy_localization_controller.dart @@ -1,6 +1,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:intl/intl_standalone.dart' if (dart.library.html) 'package:intl/intl_browser.dart'; +import 'package:intl/intl_standalone.dart' + if (dart.library.html) 'package:intl/intl_browser.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'translations.dart'; @@ -42,13 +43,15 @@ class EasyLocalizationController extends ChangeNotifier { _locale = _savedLocale; } else { // From Device Locale - _locale = supportedLocales.firstWhere((locale) => _checkInitLocale(locale, _osLocale), + _locale = supportedLocales.firstWhere( + (locale) => _checkInitLocale(locale, _osLocale), orElse: () => _getFallbackLocale(supportedLocales, fallbackLocale)); } } //Get fallback Locale - Locale _getFallbackLocale(List supportedLocales, Locale fallbackLocale) { + Locale _getFallbackLocale( + List supportedLocales, Locale fallbackLocale) { //If fallbackLocale not set then return first from supportedLocales if (fallbackLocale != null) { return fallbackLocale; diff --git a/lib/src/localization.dart b/lib/src/localization.dart index 93fa441f..a0c3dc4c 100644 --- a/lib/src/localization.dart +++ b/lib/src/localization.dart @@ -13,7 +13,8 @@ class Localization { String path; bool useOnlyLangCode; final RegExp _replaceArgRegex = RegExp(r'{}'); - final RegExp _linkKeyMatcher = RegExp(r'(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))'); + final RegExp _linkKeyMatcher = + RegExp(r'(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))'); final RegExp _linkKeyPrefixMatcher = RegExp(r'^@(?:\.([a-z]+))?:'); final RegExp _bracketsMatcher = RegExp(r'[()]'); final _modifiers = { @@ -26,7 +27,8 @@ class Localization { static Localization _instance; static Localization get instance => _instance ?? (_instance = Localization()); - static Localization of(BuildContext context) => Localizations.of(context, Localization); + static Localization of(BuildContext context) => + Localizations.of(context, Localization); static bool load(Locale locale, {Translations translations}) { instance._locale = locale; @@ -34,7 +36,8 @@ class Localization { return translations == null ? false : true; } - String tr(String key, {List args, Map namedArgs, String gender}) { + String tr(String key, + {List args, Map namedArgs, String gender}) { String res; if (gender != null) { @@ -62,7 +65,8 @@ class Localization { final formatterName = linkPrefixMatches.first[1]; // Remove the leading @:, @.case: and the brackets - final linkPlaceholder = link.replaceAll(linkPrefix, '').replaceAll(_bracketsMatcher, ''); + final linkPlaceholder = + link.replaceAll(linkPrefix, '').replaceAll(_bracketsMatcher, ''); var translated = _resolve(linkPlaceholder); @@ -71,13 +75,14 @@ class Localization { translated = _modifiers[formatterName](translated); } else { if (logging) { - EasyLocalization.logger - .warning('Undefined modifier $formatterName, available modifiers: ${_modifiers.keys.toString()}'); + EasyLocalization.logger.warning( + 'Undefined modifier $formatterName, available modifiers: ${_modifiers.keys.toString()}'); } } } - result = translated.isEmpty ? result : result.replaceAll(link, translated); + result = + translated.isEmpty ? result : result.replaceAll(link, translated); } return result; @@ -91,11 +96,13 @@ class Localization { String _replaceNamedArgs(String res, Map args) { if (args == null || args.isEmpty) return res; - args.forEach((String key, String value) => res = res.replaceAll(RegExp('{$key}'), value)); + args.forEach((String key, String value) => + res = res.replaceAll(RegExp('{$key}'), value)); return res; } - String plural(String key, num value, {List args, NumberFormat format}) { + String plural(String key, num value, + {List args, NumberFormat format}) { final res = Intl.pluralLogic(value, zero: _resolvePlural(key, 'zero'), one: _resolvePlural(key, 'one'), @@ -104,7 +111,8 @@ class Localization { many: _resolvePlural(key, 'many'), other: _resolvePlural(key, 'other'), locale: _locale.languageCode); - return _replaceArgs(res, args ?? [format == null ? '$value' : format.format(value)]); + return _replaceArgs( + res, args ?? [format == null ? '$value' : format.format(value)]); } String _gender(String key, {String gender}) => Intl.genderLogic( diff --git a/lib/src/utils.dart b/lib/src/utils.dart index ef49dc7e..3961f95c 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -8,7 +8,10 @@ Locale localeFromString(String localeString) { return Locale(localeList.first, localeList.last); case 3: return Locale.fromSubtags( - languageCode: localeList.first, scriptCode: localeList[1], countryCode: localeList.last); + languageCode: localeList.first, + scriptCode: localeList[1], + countryCode: localeList.last, + ); default: return Locale(localeList.first); } diff --git a/packages/easy_logger/lib/src/logger.dart b/packages/easy_logger/lib/src/logger.dart index c8f9f07d..ca7bbc8b 100644 --- a/packages/easy_logger/lib/src/logger.dart +++ b/packages/easy_logger/lib/src/logger.dart @@ -106,7 +106,8 @@ class EasyLogger { /// Helper for main callable function. /// Call logger function with level [LevelMessages.info] - void info(Object object, {StackTrace stackTrace}) => call(object, stackTrace: stackTrace, level: LevelMessages.info); + void info(Object object, {StackTrace stackTrace}) => + call(object, stackTrace: stackTrace, level: LevelMessages.info); /// Helper for main callable function. /// Call logger function with level [LevelMessages.warning] diff --git a/packages/easy_logger/lib/src/logger_printer.dart b/packages/easy_logger/lib/src/logger_printer.dart index 0c6e6b6d..4757bae9 100644 --- a/packages/easy_logger/lib/src/logger_printer.dart +++ b/packages/easy_logger/lib/src/logger_printer.dart @@ -1,10 +1,12 @@ import '../easy_logger.dart'; /// Type for function printing/logging in [EasyLogger]. -typedef EasyLogPrinter = Function(Object object, {String name, LevelMessages level, StackTrace stackTrace}); +typedef EasyLogPrinter = Function(Object object, + {String name, LevelMessages level, StackTrace stackTrace}); /// Default function printing. -EasyLogPrinter easyLogDefaultPrinter = (Object object, {String name, StackTrace stackTrace, LevelMessages level}) { +EasyLogPrinter easyLogDefaultPrinter = + (Object object, {String name, StackTrace stackTrace, LevelMessages level}) { String _coloredString(String string) { switch (level) { case LevelMessages.debug: diff --git a/test/easy_localization_context_test.dart b/test/easy_localization_context_test.dart index f6558fc7..caddb4b1 100644 --- a/test/easy_localization_context_test.dart +++ b/test/easy_localization_context_test.dart @@ -37,7 +37,10 @@ class MyWidget extends StatelessWidget { void main() async { SharedPreferences.setMockInitialValues({}); - EasyLocalization.logger.enableLevels = [LevelMessages.error, LevelMessages.warning]; + EasyLocalization.logger.enableLevels = [ + LevelMessages.error, + LevelMessages.warning, + ]; await EasyLocalization.ensureInitialized(); group('BuildContext', () { diff --git a/test/easy_localization_logger_test.dart b/test/easy_localization_logger_test.dart index a3bd8d7c..b0483812 100644 --- a/test/easy_localization_logger_test.dart +++ b/test/easy_localization_logger_test.dart @@ -61,7 +61,8 @@ void main() async { StackTrace testStackTrace; testStackTrace = StackTrace.fromString('test stack'); - EasyLocalization.logger('print error', level: LevelMessages.error, stackTrace: testStackTrace); + EasyLocalization.logger('print error', + level: LevelMessages.error, stackTrace: testStackTrace); expect(printLog.first, contains('print error')); expect(printLog.first, contains('[ERROR]')); expect(printLog.last, contains('test stack')); diff --git a/test/easy_localization_test.dart b/test/easy_localization_test.dart index 026da6fa..40994854 100644 --- a/test/easy_localization_test.dart +++ b/test/easy_localization_test.dart @@ -44,7 +44,10 @@ void main() { saveLocale: false, assetLoader: JsonAssetLoader()); setUpAll(() async { - EasyLocalization.logger.enableLevels = [LevelMessages.error, LevelMessages.warning]; + EasyLocalization.logger.enableLevels = [ + LevelMessages.error, + LevelMessages.warning, + ]; await r1.loadTranslations(); await r2.loadTranslations(); diff --git a/test/easy_localization_utils_test.dart b/test/easy_localization_utils_test.dart index 40dde5b7..ec959c38 100644 --- a/test/easy_localization_utils_test.dart +++ b/test/easy_localization_utils_test.dart @@ -28,17 +28,22 @@ void main() { test('localeFromString language, country, script code', () { var locale = localeFromString('zh_Hant_HK'); - expect(locale, Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK')); + expect( + locale, + Locale.fromSubtags( + languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK')); }); test('localeToString', () { - var locale = Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'); + var locale = Locale.fromSubtags( + languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'); var string = localeToString(locale); expect(string, 'zh_Hant_HK'); }); test('localeToString custom separator', () { - var locale = Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'); + var locale = Locale.fromSubtags( + languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'); var string = localeToString(locale, separator: '|'); expect(string, 'zh|Hant|HK'); }); diff --git a/test/easy_localization_widget_test.dart b/test/easy_localization_widget_test.dart index 5b25f030..98a9d99c 100644 --- a/test/easy_localization_widget_test.dart +++ b/test/easy_localization_widget_test.dart @@ -38,7 +38,10 @@ class MyWidget extends StatelessWidget { void main() async { SharedPreferences.setMockInitialValues({}); - EasyLocalization.logger.enableLevels = [LevelMessages.error, LevelMessages.warning]; + EasyLocalization.logger.enableLevels = [ + LevelMessages.error, + LevelMessages.warning, + ]; await EasyLocalization.ensureInitialized(); testWidgets( From 36f1142fed79fd06906f589c814e3d55a8958861 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sat, 6 Feb 2021 19:05:42 +0500 Subject: [PATCH 16/52] update readme --- README.md | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 8a1837c9..f7b9e7ce 100644 --- a/README.md +++ b/README.md @@ -444,7 +444,7 @@ Text(LocaleKeys.title).tr(); //Widget ### 🖨️ Logger -[Easy Localization] logger based on [Easy logger] +[Easy Localization] logger based on [Easy Logger] You can customize logger for you project @@ -460,22 +460,7 @@ Change level messages: EasyLocalization.logger.enableLevels = [LevelMessages.debug, LevelMessages.info, LevelMessages.error, LevelMessages.warning]; ``` -Customize default printer function: - -```dart -EasyLogPrinter customLogPrinter = ( - Object object, { - String name, - StackTrace stackTrace, - LevelMessages level, -}) { - print('$name: ${object.toString()}'); -}; - -EasyLocalization.logger.printer = customLogPrinter; -``` - -///TODO: add lint to [Easy Logger] git. +Read more about [Easy Logger](https://github.com/aissat/easy_localization/blob/master/packages/easy_logger/README.md) ## Screenshots From 240f6ba659e9fec591a9a4ab084b631337a5635a Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sat, 6 Feb 2021 19:25:21 +0500 Subject: [PATCH 17/52] update readme --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index f7b9e7ce..20b5c109 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Easy and Fast internationalization for your Flutter Apps - ⁉️ Error widget for missing translations - ❤️ Extension methods on `Text` and `BuildContext` - 💻 Code generation for localization files and keys. +- 🖨️ Customizable logger. ## Getting Started @@ -462,6 +463,13 @@ EasyLocalization.logger.enableLevels = [LevelMessages.debug, LevelMessages.info, Read more about [Easy Logger](https://github.com/aissat/easy_localization/blob/master/packages/easy_logger/README.md) + +

+ + + +

+ ## Screenshots | Arabic RTL | English LTR | Error widget | From 8957898cbbff0221218cff2552538d2a6eea40b2 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 7 Feb 2021 13:47:02 +0500 Subject: [PATCH 18/52] update readme files --- README.md | 33 ++++++++++++++++++++++++++++----- packages/easy_logger/README.md | 19 +++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 20b5c109..ecdcb2fd 100644 --- a/README.md +++ b/README.md @@ -443,22 +443,45 @@ print(LocaleKeys.title.tr()); //String Text(LocaleKeys.title).tr(); //Widget ``` -### 🖨️ Logger +## 🖨️ Logger [Easy Localization] logger based on [Easy Logger] You can customize logger for you project -Change enabled build modes: +### Show only lost keys message + +Lost translations keys logged like warning messages. Change [Easy Logger] level for display only errors and warnings. ```dart -EasyLocalization.logger.enableBuildModes = [BuildMode.profile, BuildMode.debug, BuildMode.release]; +EasyLocalization.logger.enableLevels = [LevelMessages.error, LevelMessages.warning]; ``` -Change level messages: +### Logger off + +For disable logger, change Build Modes in [Easy Logger] to empty List; + +```dart +EasyLocalization.logger.enableBuildModes = []; +``` + +### Catching logger messages + +For catching logger messages you need override default printer function. ```dart -EasyLocalization.logger.enableLevels = [LevelMessages.debug, LevelMessages.info, LevelMessages.error, LevelMessages.warning]; +EasyLogPrinter customLogPrinter = ( + Object object, { + String name, + StackTrace stackTrace, + LevelMessages level, +}) { + ///Your function + print('$name: ${object.toString()}'); +}; + +/// override printer to custom +EasyLocalization.logger.printer = customLogPrinter; ``` Read more about [Easy Logger](https://github.com/aissat/easy_localization/blob/master/packages/easy_logger/README.md) diff --git a/packages/easy_logger/README.md b/packages/easy_logger/README.md index 376edcc0..8272a139 100644 --- a/packages/easy_logger/README.md +++ b/packages/easy_logger/README.md @@ -69,6 +69,25 @@ try { } ``` +### 🖨️ Customise message or build levels + +[EasyLogger] supported Flutter build modes. Read more about [Build modes](https://flutter.dev/docs/testing/build-modes) + +```dart +// only debug and profile modes +logger.enableBuildModes = [BuildMode.debug, BuildMode.profile] + +// logger off +logger.enableLevels = [] +``` + +You can customize what levels of messages you need + +```dart +// show only errors +logger.enableBuildModes = [LevelMessages.error] + +``` ### 🖨️ Customise printer function From 06296a2a24e80b50687b024cac0370358dd8d250 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 7 Feb 2021 15:00:12 +0500 Subject: [PATCH 19/52] deviceLocale and resetLocale functions --- lib/src/easy_localization_app.dart | 6 ++++++ lib/src/easy_localization_controller.dart | 19 ++++++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/src/easy_localization_app.dart b/lib/src/easy_localization_app.dart index fa3923a4..239a9a73 100644 --- a/lib/src/easy_localization_app.dart +++ b/lib/src/easy_localization_app.dart @@ -211,6 +211,12 @@ class _EasyLocalizationProvider extends InheritedWidget { await _localeState.deleteSaveLocale(); } + /// Getting device locale from platform + Locale get deviceLocale => _localeState.deviceLocale; + + /// Reset locale to platform locale + Future resetLocale() => _localeState.resetLocale(); + @override bool updateShouldNotify(_EasyLocalizationProvider oldWidget) { return oldWidget.currentLocale != locale; diff --git a/lib/src/easy_localization_controller.dart b/lib/src/easy_localization_controller.dart index 82961f1f..eacf91ac 100644 --- a/lib/src/easy_localization_controller.dart +++ b/lib/src/easy_localization_controller.dart @@ -8,7 +8,7 @@ import 'translations.dart'; class EasyLocalizationController extends ChangeNotifier { static Locale _savedLocale; - static Locale _osLocale; + static Locale _systemLocale; Locale _locale; @@ -17,6 +17,7 @@ class EasyLocalizationController extends ChangeNotifier { final String path; final bool saveLocale; final bool useOnlyLangCode; + Translations _translations; Translations get translations => _translations; @@ -44,7 +45,7 @@ class EasyLocalizationController extends ChangeNotifier { } else { // From Device Locale _locale = supportedLocales.firstWhere( - (locale) => _checkInitLocale(locale, _osLocale), + (locale) => _checkInitLocale(locale, _systemLocale), orElse: () => _getFallbackLocale(supportedLocales, fallbackLocale)); } } @@ -60,12 +61,12 @@ class EasyLocalizationController extends ChangeNotifier { } } - bool _checkInitLocale(Locale locale, Locale _osLocale) { - // If suported locale not contain countryCode then check only languageCode + bool _checkInitLocale(Locale locale, Locale _systemLocale) { + // If supported locale not contain countryCode then check only languageCode if (locale.countryCode == null) { - return (locale.languageCode == _osLocale.languageCode); + return (locale.languageCode == _systemLocale.languageCode); } else { - return (locale == _osLocale); + return (locale == _systemLocale); } } @@ -102,7 +103,7 @@ class EasyLocalizationController extends ChangeNotifier { final _strLocale = _preferences.getString('locale'); _savedLocale = _strLocale != null ? localeFromString(_strLocale) : null; final _deviceLocale = await findSystemLocale(); - _osLocale = localeFromString(_deviceLocale); + _systemLocale = localeFromString(_deviceLocale); } Future deleteSaveLocale() async { @@ -111,4 +112,8 @@ class EasyLocalizationController extends ChangeNotifier { await _preferences.setString('locale', null); EasyLocalization.logger('Saved locale deleted'); } + + Locale get deviceLocale => _systemLocale; + + Future resetLocale() => setLocale(_systemLocale); } From 5f029f5d7cb6dadcb5c9d4f2deaa0c46e8f2c193 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 7 Feb 2021 15:17:14 +0500 Subject: [PATCH 20/52] add more logger --- lib/src/easy_localization_controller.dart | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/src/easy_localization_controller.dart b/lib/src/easy_localization_controller.dart index eacf91ac..8480ea1d 100644 --- a/lib/src/easy_localization_controller.dart +++ b/lib/src/easy_localization_controller.dart @@ -89,6 +89,7 @@ class EasyLocalizationController extends ChangeNotifier { _locale = l; await loadTranslations(); notifyListeners(); + EasyLocalization.logger('Locale $locale changed'); await _saveLocale(_locale); } @@ -96,6 +97,7 @@ class EasyLocalizationController extends ChangeNotifier { if (!saveLocale) return; final _preferences = await SharedPreferences.getInstance(); await _preferences.setString('locale', locale.toString()); + EasyLocalization.logger('Locale $locale saved'); } static Future initEasyLocation() async { @@ -104,6 +106,7 @@ class EasyLocalizationController extends ChangeNotifier { _savedLocale = _strLocale != null ? localeFromString(_strLocale) : null; final _deviceLocale = await findSystemLocale(); _systemLocale = localeFromString(_deviceLocale); + EasyLocalization.logger('Localization initialized'); } Future deleteSaveLocale() async { @@ -115,5 +118,9 @@ class EasyLocalizationController extends ChangeNotifier { Locale get deviceLocale => _systemLocale; - Future resetLocale() => setLocale(_systemLocale); + Future resetLocale() async { + EasyLocalization.logger('Reset locale to platform locale $_systemLocale'); + + await setLocale(_systemLocale); + } } From a381a0d1ab6da5ddaf92bd2d7b184f7b81a356fa Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 7 Feb 2021 18:23:33 +0500 Subject: [PATCH 21/52] update example --- .../android/app/src/main/AndroidManifest.xml | 19 ++++- .../io/aissat/example/example/MainActivity.kt | 11 +-- .../app/src/main/res/values/styles.xml | 3 + example/lib/generated/codegen_loader.g.dart | 16 ++-- example/lib/lang_view.dart | 77 +++++++++++-------- example/lib/main.dart | 2 +- example/pubspec.yaml | 2 +- example/resources/langs/ar-DZ.json | 2 +- example/resources/langs/ar-DZ.xml | 2 +- example/resources/langs/ar-DZ.yaml | 2 +- example/resources/langs/ar.json | 2 +- example/resources/langs/de-DE.json | 2 +- example/resources/langs/de-DE.xml | 2 +- example/resources/langs/de-DE.yaml | 2 +- example/resources/langs/de.json | 2 +- example/resources/langs/en-US.json | 2 +- example/resources/langs/en-US.xml | 2 +- example/resources/langs/en-US.yaml | 2 +- example/resources/langs/en.json | 2 +- example/resources/langs/langs.csv | 2 +- example/resources/langs/langs.xml | 8 +- example/resources/langs/langs.yaml | 8 +- example/resources/langs/ru-RU.json | 2 +- example/resources/langs/ru-RU.xml | 2 +- example/resources/langs/ru-RU.yaml | 2 +- example/resources/langs/ru.json | 2 +- lib/src/public_ext.dart | 8 +- 27 files changed, 108 insertions(+), 80 deletions(-) diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index c0e99143..abf17029 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -6,9 +6,11 @@ additional functionality it is fine to subclass or reimplement FlutterApplication and put your custom class here. --> + - + + + + + + + diff --git a/example/android/app/src/main/kotlin/io/aissat/example/example/MainActivity.kt b/example/android/app/src/main/kotlin/io/aissat/example/example/MainActivity.kt index 5ff31616..3d315a25 100644 --- a/example/android/app/src/main/kotlin/io/aissat/example/example/MainActivity.kt +++ b/example/android/app/src/main/kotlin/io/aissat/example/example/MainActivity.kt @@ -1,12 +1,5 @@ package io.aissat.example.example -import android.os.Bundle -import io.flutter.app.FlutterActivity -import io.flutter.plugins.GeneratedPluginRegistrant +import io.flutter.embedding.android.FlutterActivity -class MainActivity: FlutterActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - GeneratedPluginRegistrant.registerWith(this) - } -} +class MainActivity: FlutterActivity() {} diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml index 00fa4417..c745a5ef 100644 --- a/example/android/app/src/main/res/values/styles.xml +++ b/example/android/app/src/main/res/values/styles.xml @@ -5,4 +5,7 @@ Flutter draws its first frame --> @drawable/launch_background + diff --git a/example/lib/generated/codegen_loader.g.dart b/example/lib/generated/codegen_loader.g.dart index 29aa2a5d..0a52c173 100644 --- a/example/lib/generated/codegen_loader.g.dart +++ b/example/lib/generated/codegen_loader.g.dart @@ -47,7 +47,7 @@ class CodegenLoader extends AssetLoader { "female": " مرحبا بك يا فتاة", "with_arg": {"male": "{} مرحبا يا رجل", "female": "{} مرحبا بك يا فتاة"} }, - "reset_locale": "إعادة تعيين اللغة المحفوظة" + "reset_locale": "إعادة ضبط اللغة" }; static const Map ar = { "title": "السلام", @@ -82,7 +82,7 @@ class CodegenLoader extends AssetLoader { "female": " مرحبا بك يا فتاة", "with_arg": {"male": "{} مرحبا يا رجل", "female": "{} مرحبا بك يا فتاة"} }, - "reset_locale": "إعادة تعيين اللغة المحفوظة" + "reset_locale": "إعادة ضبط اللغة" }; static const Map de_DE = { "title": "Hallo", @@ -117,7 +117,7 @@ class CodegenLoader extends AssetLoader { "female": "Hallo Frau :)", "with_arg": {"male": "Hi Mann ;) {}", "female": "Hallo Frau :) {}"} }, - "reset_locale": "Gespeicherte Sprache zurücksettzen" + "reset_locale": "Sprache zurücksetzen" }; static const Map de = { "title": "Hallo", @@ -152,7 +152,7 @@ class CodegenLoader extends AssetLoader { "female": "Hallo Frau :)", "with_arg": {"male": "Hi Mann ;) {}", "female": "Hallo Frau :) {}"} }, - "reset_locale": "Gespeicherte Sprache zurücksettzen" + "reset_locale": "Sprache zurücksetzen" }; static const Map en_US = { "title": "Hello", @@ -187,7 +187,7 @@ class CodegenLoader extends AssetLoader { "female": "Hello girl :)", "with_arg": {"male": "Hi man ;) {}", "female": "Hello girl :) {}"} }, - "reset_locale": "Reset Saved Language" + "reset_locale": "Reset Language" }; static const Map en = { "title": "Hello", @@ -222,7 +222,7 @@ class CodegenLoader extends AssetLoader { "female": "Hello girl :)", "with_arg": {"male": "Hi man ;) {}", "female": "Hello girl :) {}"} }, - "reset_locale": "Reset Saved Language" + "reset_locale": "Reset Language" }; static const Map ru_RU = { "title": "Привет!", @@ -260,7 +260,7 @@ class CodegenLoader extends AssetLoader { "female": "Привет девчуля :) {}" } }, - "reset_locale": "Сбросить сохраненный язык" + "reset_locale": "Сбросить язык" }; static const Map ru = { "title": "Привет!", @@ -298,7 +298,7 @@ class CodegenLoader extends AssetLoader { "female": "Привет девчуля :) {}" } }, - "reset_locale": "Сбросить сохраненный язык" + "reset_locale": "Сбросить язык" }; static const Map> mapLocales = { "ar_DZ": ar_DZ, diff --git a/example/lib/lang_view.dart b/example/lib/lang_view.dart index ca272a47..5ef750a7 100644 --- a/example/lib/lang_view.dart +++ b/example/lib/lang_view.dart @@ -36,54 +36,72 @@ class LanguageView extends StatelessWidget { ), ), ), - buildSwitchListTileMenuItem( - context: context, + _SwitchListTileMenuItem( title: 'عربي', subtitle: 'عربي', locale: context.supportedLocales[1] //BuildContext extension method ), - buildDivider(), - buildSwitchListTileMenuItem( - context: context, + _Divider(), + _SwitchListTileMenuItem( title: 'English', subtitle: 'English', - locale: EasyLocalization.of(context).supportedLocales[0]), - buildDivider(), - buildSwitchListTileMenuItem( - context: context, + locale: context.supportedLocales[0]), + _Divider(), + _SwitchListTileMenuItem( title: 'German', subtitle: 'German', - locale: EasyLocalization.of(context).supportedLocales[2]), - buildDivider(), - buildSwitchListTileMenuItem( - context: context, + locale: context.supportedLocales[2]), + _Divider(), + _SwitchListTileMenuItem( title: 'Русский', subtitle: 'Русский', - locale: EasyLocalization.of(context).supportedLocales[3]), - buildDivider(), + locale: context.supportedLocales[3]), + _Divider(), ], ), ), ); } +} - Container buildDivider() => Container( - margin: EdgeInsets.symmetric( - horizontal: 24, - ), - child: Divider( - color: Colors.grey, - ), - ); +class _Divider extends StatelessWidget { + const _Divider({Key key}) : super(key: key); - Container buildSwitchListTileMenuItem( - {BuildContext context, String title, String subtitle, Locale locale}) { + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.symmetric( + horizontal: 24, + ), + child: Divider( + color: Colors.grey, + ), + ); + } +} + +class _SwitchListTileMenuItem extends StatelessWidget { + const _SwitchListTileMenuItem({ + Key key, + this.title, + this.subtitle, + this.locale, + }) : super(key: key); + + final String title; + final String subtitle; + final Locale locale; + + bool isSelected(BuildContext context) => locale == context.locale; + + @override + Widget build(BuildContext context) { return Container( - margin: EdgeInsets.only( - left: 10, - right: 10, - top: 5, + margin: EdgeInsets.only(left: 10, right: 10, top: 5), + decoration: BoxDecoration( + border: + isSelected(context) ? Border.all(color: Colors.blueAccent) : null, ), child: ListTile( dense: true, @@ -97,7 +115,6 @@ class LanguageView extends StatelessWidget { onTap: () async { log(locale.toString(), name: toString()); await context.setLocale(locale); //BuildContext extension method - //EasyLocalization.of(context).locale = locale; Navigator.pop(context); }), ); diff --git a/example/lib/main.dart b/example/lib/main.dart index 8a5a7504..90f5cfd9 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -157,7 +157,7 @@ class _MyHomePageState extends State { ), RaisedButton( onPressed: () { - context.deleteSaveLocale(); + context.resetLocale(); }, child: Text(LocaleKeys.reset_locale).tr(), ), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index b1407b79..6d2e5006 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -14,7 +14,7 @@ description: A new Flutter project. version: 1.0.0+1 environment: - sdk: ">=2.6.0 <3.0.0" + sdk: ">=2.7.0 <3.0.0" dependencies: flutter: diff --git a/example/resources/langs/ar-DZ.json b/example/resources/langs/ar-DZ.json index ca6d048c..f1fefd16 100644 --- a/example/resources/langs/ar-DZ.json +++ b/example/resources/langs/ar-DZ.json @@ -34,5 +34,5 @@ "female": "{} مرحبا بك يا فتاة" } }, - "reset_locale": "إعادة تعيين اللغة المحفوظة" + "reset_locale": "إعادة ضبط اللغة" } \ No newline at end of file diff --git a/example/resources/langs/ar-DZ.xml b/example/resources/langs/ar-DZ.xml index 0ac54dc8..ca768498 100644 --- a/example/resources/langs/ar-DZ.xml +++ b/example/resources/langs/ar-DZ.xml @@ -34,6 +34,6 @@ المستخدم - إعادة تعيين اللغة المحفوظة + إعادة ضبط اللغة السلام \ No newline at end of file diff --git a/example/resources/langs/ar-DZ.yaml b/example/resources/langs/ar-DZ.yaml index 2391d5c4..d1d20d8d 100644 --- a/example/resources/langs/ar-DZ.yaml +++ b/example/resources/langs/ar-DZ.yaml @@ -27,4 +27,4 @@ gender: with_arg: male: "{} مرحبا يا رجل" female: "{} مرحبا بك يا فتاة" -reset_locale: إعادة تعيين اللغة المحفوظة +reset_locale: إعادة ضبط اللغة diff --git a/example/resources/langs/ar.json b/example/resources/langs/ar.json index ca6d048c..f1fefd16 100644 --- a/example/resources/langs/ar.json +++ b/example/resources/langs/ar.json @@ -34,5 +34,5 @@ "female": "{} مرحبا بك يا فتاة" } }, - "reset_locale": "إعادة تعيين اللغة المحفوظة" + "reset_locale": "إعادة ضبط اللغة" } \ No newline at end of file diff --git a/example/resources/langs/de-DE.json b/example/resources/langs/de-DE.json index 88dcc50d..c76410da 100644 --- a/example/resources/langs/de-DE.json +++ b/example/resources/langs/de-DE.json @@ -34,5 +34,5 @@ "female": "Hallo Frau :) {}" } }, - "reset_locale": "Gespeicherte Sprache zurücksettzen" + "reset_locale": "Sprache zurücksetzen" } \ No newline at end of file diff --git a/example/resources/langs/de-DE.xml b/example/resources/langs/de-DE.xml index 7a52ccdc..a324fb52 100644 --- a/example/resources/langs/de-DE.xml +++ b/example/resources/langs/de-DE.xml @@ -34,6 +34,6 @@ Name - Gespeicherte Sprache zurücksettzen + Sprache zurücksetzen Hallo \ No newline at end of file diff --git a/example/resources/langs/de-DE.yaml b/example/resources/langs/de-DE.yaml index db5303b5..bb4a6687 100644 --- a/example/resources/langs/de-DE.yaml +++ b/example/resources/langs/de-DE.yaml @@ -27,4 +27,4 @@ gender: with_arg: male: Hi Mann ;) {} female: Hallo Frau :) {} -reset_locale: Gespeicherte Sprache zurücksettzen +reset_locale: Sprache zurücksetzen diff --git a/example/resources/langs/de.json b/example/resources/langs/de.json index 88dcc50d..c76410da 100644 --- a/example/resources/langs/de.json +++ b/example/resources/langs/de.json @@ -34,5 +34,5 @@ "female": "Hallo Frau :) {}" } }, - "reset_locale": "Gespeicherte Sprache zurücksettzen" + "reset_locale": "Sprache zurücksetzen" } \ No newline at end of file diff --git a/example/resources/langs/en-US.json b/example/resources/langs/en-US.json index 9e121edd..7cee30b5 100644 --- a/example/resources/langs/en-US.json +++ b/example/resources/langs/en-US.json @@ -34,5 +34,5 @@ "female": "Hello girl :) {}" } }, - "reset_locale": "Reset Saved Language" + "reset_locale": "Reset Language" } \ No newline at end of file diff --git a/example/resources/langs/en-US.xml b/example/resources/langs/en-US.xml index c891b036..942fad01 100644 --- a/example/resources/langs/en-US.xml +++ b/example/resources/langs/en-US.xml @@ -34,6 +34,6 @@ Username - Reset Saved Language + Reset Language Hello \ No newline at end of file diff --git a/example/resources/langs/en-US.yaml b/example/resources/langs/en-US.yaml index f8f95ce5..3d49e160 100644 --- a/example/resources/langs/en-US.yaml +++ b/example/resources/langs/en-US.yaml @@ -27,4 +27,4 @@ gender: with_arg: male: Hi man ;) {} female: Hello girl :) {} -reset_locale: Reset Saved Language +reset_locale: Reset Language diff --git a/example/resources/langs/en.json b/example/resources/langs/en.json index 9e121edd..7cee30b5 100644 --- a/example/resources/langs/en.json +++ b/example/resources/langs/en.json @@ -34,5 +34,5 @@ "female": "Hello girl :) {}" } }, - "reset_locale": "Reset Saved Language" + "reset_locale": "Reset Language" } \ No newline at end of file diff --git a/example/resources/langs/langs.csv b/example/resources/langs/langs.csv index 3f582f83..72d07d0a 100644 --- a/example/resources/langs/langs.csv +++ b/example/resources/langs/langs.csv @@ -22,4 +22,4 @@ gender.male,Hi man ;) , مرحبا يا رجل,Hi Mann ;) ,Привет мужы gender.female,Hello girl :), مرحبا بك يا فتاة,Hallo Frau :),Привет девчуля :) gender.with_arg.male,Hi man ;) {},{} مرحبا يا رجل,Hi Mann ;) {},Привет мужык ;) {} gender.with_arg.female,Hello girl :) {},{} مرحبا بك يا فتاة,Hallo Frau :) {},Привет девчуля :) {} -reset_locale,Reset Saved Language,إعادة تعيين اللغة المحفوظة,Gespeicherte Sprache zurГјcksettzen,Сбросить сохраненный язык +reset_locale,Reset Language,إعادة ضبط اللغة,Gespeicherte Sprache zurГјcksettzen,Сбросить язык diff --git a/example/resources/langs/langs.xml b/example/resources/langs/langs.xml index 60bf7f16..1ffd1ad7 100644 --- a/example/resources/langs/langs.xml +++ b/example/resources/langs/langs.xml @@ -35,7 +35,7 @@ المستخدم - إعادة تعيين اللغة المحفوظة + إعادة ضبط اللغة السلام @@ -73,7 +73,7 @@ Name - Gespeicherte Sprache zurücksettzen + Sprache zurücksetzen Hallo @@ -111,7 +111,7 @@ Username - Reset Saved Language + Reset Language Hello @@ -149,7 +149,7 @@ Логин - Сбросить сохраненный язык + Сбросить язык Привет! \ No newline at end of file diff --git a/example/resources/langs/langs.yaml b/example/resources/langs/langs.yaml index fba120ec..5f5717d5 100644 --- a/example/resources/langs/langs.yaml +++ b/example/resources/langs/langs.yaml @@ -28,7 +28,7 @@ en_US: with_arg: male: Hi man ;) {} female: Hello girl :) {} - reset_locale: Reset Saved Language + reset_locale: Reset Language ar_DZ: title: السلام @@ -60,7 +60,7 @@ ar_DZ: with_arg: male: "{} مرحبا يا رجل" female: "{} مرحبا بك يا فتاة" - reset_locale: إعادة تعيين اللغة المحفوظة + reset_locale: إعادة ضبط اللغة de_DE: title: Hallo @@ -92,7 +92,7 @@ de_DE: with_arg: male: Hi Mann ;) {} female: Hallo Frau :) {} - reset_locale: Gespeicherte Sprache zurücksettzen + reset_locale: Sprache zurücksetzen ru_RU: title: Привет! @@ -124,4 +124,4 @@ ru_RU: with_arg: male: Привет мужык ;) {} female: Привет девчуля :) {} - reset_locale: Сбросить сохраненный язык \ No newline at end of file + reset_locale: Сбросить язык \ No newline at end of file diff --git a/example/resources/langs/ru-RU.json b/example/resources/langs/ru-RU.json index 4a6c5200..042c210e 100644 --- a/example/resources/langs/ru-RU.json +++ b/example/resources/langs/ru-RU.json @@ -34,5 +34,5 @@ "female": "Привет девчуля :) {}" } }, - "reset_locale": "Сбросить сохраненный язык" + "reset_locale": "Сбросить язык" } \ No newline at end of file diff --git a/example/resources/langs/ru-RU.xml b/example/resources/langs/ru-RU.xml index 58912d4c..9899607b 100644 --- a/example/resources/langs/ru-RU.xml +++ b/example/resources/langs/ru-RU.xml @@ -34,6 +34,6 @@ Логин - Сбросить сохраненный язык + Сбросить язык Привет! \ No newline at end of file diff --git a/example/resources/langs/ru-RU.yaml b/example/resources/langs/ru-RU.yaml index 0b66cf21..318c097f 100644 --- a/example/resources/langs/ru-RU.yaml +++ b/example/resources/langs/ru-RU.yaml @@ -27,4 +27,4 @@ gender: with_arg: male: Привет мужык ;) {} female: Привет девчуля :) {} -reset_locale: Сбросить сохраненный язык +reset_locale: Сбросить язык diff --git a/example/resources/langs/ru.json b/example/resources/langs/ru.json index 4a6c5200..042c210e 100644 --- a/example/resources/langs/ru.json +++ b/example/resources/langs/ru.json @@ -34,5 +34,5 @@ "female": "Привет девчуля :) {}" } }, - "reset_locale": "Сбросить сохраненный язык" + "reset_locale": "Сбросить язык" } \ No newline at end of file diff --git a/lib/src/public_ext.dart b/lib/src/public_ext.dart index 3ad032c8..6ce2d506 100644 --- a/lib/src/public_ext.dart +++ b/lib/src/public_ext.dart @@ -104,8 +104,6 @@ extension BuildContextEasyLocalizationExtension on BuildContext { /// Get fallback locale Locale get fallbackLocale => EasyLocalization.of(this).fallbackLocale; - // Locale get startLocale => EasyLocalization.of(this).startLocale; - /// {@macro flutter.widgets.widgetsApp.localizationsDelegates} /// retrun /// ```dart @@ -121,4 +119,10 @@ extension BuildContextEasyLocalizationExtension on BuildContext { /// Clears a saved locale from device storage void deleteSaveLocale() => EasyLocalization.of(this).deleteSaveLocale(); + + /// Getting device locale from platform + void deviceLocale() => EasyLocalization.of(this).deviceLocale; + + /// Reset locale to platform locale + Future resetLocale() => EasyLocalization.of(this).resetLocale(); } From ee493c7f5e99f4d61e666d334ff69f6ff1f4065f Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 7 Feb 2021 18:47:19 +0500 Subject: [PATCH 22/52] fix extensions, add tests --- lib/src/public_ext.dart | 5 +- test/easy_localization_context_test.dart | 74 ++++++++++-- test/easy_localization_widget_test.dart | 137 +++++++++++++++++++---- 3 files changed, 183 insertions(+), 33 deletions(-) diff --git a/lib/src/public_ext.dart b/lib/src/public_ext.dart index 6ce2d506..36b32117 100644 --- a/lib/src/public_ext.dart +++ b/lib/src/public_ext.dart @@ -118,10 +118,11 @@ extension BuildContextEasyLocalizationExtension on BuildContext { EasyLocalization.of(this).delegates; /// Clears a saved locale from device storage - void deleteSaveLocale() => EasyLocalization.of(this).deleteSaveLocale(); + Future deleteSaveLocale() => + EasyLocalization.of(this).deleteSaveLocale(); /// Getting device locale from platform - void deviceLocale() => EasyLocalization.of(this).deviceLocale; + Locale get deviceLocale => EasyLocalization.of(this).deviceLocale; /// Reset locale to platform locale Future resetLocale() => EasyLocalization.of(this).resetLocale(); diff --git a/test/easy_localization_context_test.dart b/test/easy_localization_context_test.dart index caddb4b1..7dfe09da 100644 --- a/test/easy_localization_context_test.dart +++ b/test/easy_localization_context_test.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/src/localization.dart'; import 'package:easy_logger/easy_logger.dart'; @@ -100,7 +102,8 @@ void main() async { await tester.pumpAndSettle(); expect(Localization.of(_context), isInstanceOf()); - expect(_context.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(_context.supportedLocales, + [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(_context.locale, Locale('en', 'US')); var trFinder = find.text('test'); @@ -131,7 +134,8 @@ void main() async { expect(_context.locale, l); l = Locale('en', 'UK'); - expect(() async => {await _context.setLocale(l)}, throwsAssertionError); + expect( + () async => {await _context.setLocale(l)}, throwsAssertionError); l = Locale('ar', 'DZ'); await _context.setLocale(l); @@ -160,7 +164,8 @@ void main() async { await tester.pumpAndSettle(); - expect(_context.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(_context.supportedLocales, + [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(_context.locale, Locale('ar', 'DZ')); var trFinder = find.text('اختبار'); @@ -214,7 +219,9 @@ void main() async { saveLocale: false, useOnlyLangCode: true, // fallbackLocale:Locale('en') , - supportedLocales: [Locale('ar')], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [ + Locale('ar') + ], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump @@ -242,14 +249,17 @@ void main() async { child: MyApp(), path: 'i18n', // fallbackLocale:Locale('en') , - supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [ + Locale('en', 'US'), + Locale('ar', 'DZ') + ], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); expect(_context.locale, Locale('ar', 'DZ')); - _context.deleteSaveLocale(); + await _context.deleteSaveLocale(); }); }, ); @@ -262,12 +272,62 @@ void main() async { child: MyApp(), path: 'i18n', // fallbackLocale:Locale('en') , - supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [ + Locale('en', 'US'), + Locale('ar', 'DZ') + ], // Locale('en', 'US'), Locale('ar','DZ') + )); + await tester.idle(); + // The async delegator load will require build on the next frame. Thus, pump + await tester.pumpAndSettle(); + + expect(_context.locale, Locale('en', 'US')); + }); + }, + ); + + testWidgets( + '[EasyLocalization] device locale test', + (WidgetTester tester) async { + await tester.runAsync(() async { + await tester.pumpWidget(EasyLocalization( + child: MyApp(), + path: 'i18n', + supportedLocales: [ + Locale('en', 'US'), + Locale('ar', 'DZ') + ], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); + expect(_context.deviceLocale.toString(), Platform.localeName); + }); + }, + ); + + testWidgets( + '[EasyLocalization] reset device locale test', + (WidgetTester tester) async { + await tester.runAsync(() async { + await tester.pumpWidget(EasyLocalization( + child: MyApp(), + path: 'i18n', + supportedLocales: [ + Locale('en', 'US'), + Locale('ar', 'DZ') + ], // Locale('en', 'US'), Locale('ar','DZ') + startLocale: Locale('ar', 'DZ'), + )); + await tester.idle(); + // The async delegator load will require build on the next frame. Thus, pump + await tester.pumpAndSettle(); + + expect(_context.locale, Locale('ar', 'DZ')); + // reset to device locale + await _context.resetLocale(); + await tester.pumpAndSettle(); expect(_context.locale, Locale('en', 'US')); }); }, diff --git a/test/easy_localization_widget_test.dart b/test/easy_localization_widget_test.dart index 98a9d99c..b018c9b1 100644 --- a/test/easy_localization_widget_test.dart +++ b/test/easy_localization_widget_test.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/src/localization.dart'; import 'package:easy_logger/easy_logger.dart'; @@ -62,7 +64,8 @@ void main() async { expect(Localization.of(_context), isInstanceOf()); expect(Localization.instance, isInstanceOf()); expect(Localization.instance, Localization.of(_context)); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US')]); + expect(EasyLocalization.of(_context).supportedLocales, + [Locale('en', 'US')]); expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); final trFinder = find.text('test'); @@ -113,7 +116,8 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US')]); + expect(EasyLocalization.of(_context).supportedLocales, + [Locale('en', 'US')]); expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); final trFinder = find.text('test'); @@ -141,7 +145,8 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US')]); + expect(EasyLocalization.of(_context).supportedLocales, + [Locale('en', 'US')]); expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); final trFinder = find.text('test'); @@ -168,7 +173,8 @@ void main() async { await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - final trFinder = find.byWidgetPredicate((widget) => widget is ErrorWidget); + final trFinder = + find.byWidgetPredicate((widget) => widget is ErrorWidget); expect(trFinder, findsOneWidget); await tester.pump(); }); @@ -187,7 +193,8 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US')]); + expect(EasyLocalization.of(_context).supportedLocales, + [Locale('en', 'US')]); expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); var l = Locale('en', 'US'); @@ -230,7 +237,8 @@ void main() async { await tester.pumpAndSettle(); expect(Localization.of(_context), isInstanceOf()); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(EasyLocalization.of(_context).supportedLocales, + [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); var trFinder = find.text('test'); @@ -261,7 +269,8 @@ void main() async { expect(EasyLocalization.of(_context).locale, l); l = Locale('en', 'UK'); - expect(() async => {await EasyLocalization.of(_context).setLocale(l)}, throwsAssertionError); + expect(() async => {await EasyLocalization.of(_context).setLocale(l)}, + throwsAssertionError); l = Locale('ar', 'DZ'); await EasyLocalization.of(_context).setLocale(l); @@ -290,7 +299,8 @@ void main() async { await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(EasyLocalization.of(_context).supportedLocales, + [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(EasyLocalization.of(_context).locale, Locale('ar', 'DZ')); var trFinder = find.text('اختبار'); @@ -320,13 +330,17 @@ void main() async { path: 'i18n', saveLocale: false, useOnlyLangCode: true, - supportedLocales: [Locale('en'), Locale('ar')], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [ + Locale('en'), + Locale('ar') + ], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('en'), Locale('ar')]); + expect(EasyLocalization.of(_context).supportedLocales, + [Locale('en'), Locale('ar')]); expect(EasyLocalization.of(_context).locale, Locale('en')); var l = Locale('en'); @@ -345,13 +359,17 @@ void main() async { path: 'i18n', saveLocale: false, useOnlyLangCode: true, - supportedLocales: [Locale('en'), Locale('ar')], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [ + Locale('en'), + Locale('ar') + ], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('en'), Locale('ar')]); + expect(EasyLocalization.of(_context).supportedLocales, + [Locale('en'), Locale('ar')]); expect(EasyLocalization.of(_context).locale, Locale('en')); var l = Locale('en'); @@ -394,7 +412,9 @@ void main() async { saveLocale: false, useOnlyLangCode: true, // fallbackLocale:Locale('en') , - supportedLocales: [Locale('ar')], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [ + Locale('ar') + ], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump @@ -429,7 +449,8 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('en'), Locale('ar')]); + expect(EasyLocalization.of(_context).supportedLocales, + [Locale('en'), Locale('ar')]); expect(EasyLocalization.of(_context).locale, Locale('en')); expect(EasyLocalization.of(_context).fallbackLocale, null); }); @@ -450,7 +471,8 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(EasyLocalization.of(_context).supportedLocales, + [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); expect(EasyLocalization.of(_context).fallbackLocale, null); }); @@ -472,7 +494,8 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(EasyLocalization.of(_context).supportedLocales, + [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(EasyLocalization.of(_context).locale, Locale('ar', 'DZ')); expect(EasyLocalization.of(_context).fallbackLocale, null); }); @@ -498,13 +521,17 @@ void main() async { saveLocale: true, // fallbackLocale:Locale('en') , useOnlyLangCode: true, - supportedLocales: [Locale('en'), Locale('ar')], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [ + Locale('en'), + Locale('ar') + ], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('en'), Locale('ar')]); + expect(EasyLocalization.of(_context).supportedLocales, + [Locale('en'), Locale('ar')]); expect(EasyLocalization.of(_context).locale, Locale('ar')); expect(EasyLocalization.of(_context).fallbackLocale, null); }); @@ -529,13 +556,17 @@ void main() async { path: 'i18n', saveLocale: true, // fallbackLocale:Locale('en') , - supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [ + Locale('en', 'US'), + Locale('ar', 'DZ') + ], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(EasyLocalization.of(_context).supportedLocales, + [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(EasyLocalization.of(_context).locale, Locale('ar', 'DZ')); expect(EasyLocalization.of(_context).fallbackLocale, null); }); @@ -551,13 +582,17 @@ void main() async { path: 'i18n', saveLocale: false, // fallbackLocale:Locale('en') , - supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [ + Locale('en', 'US'), + Locale('ar', 'DZ') + ], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); + expect(EasyLocalization.of(_context).supportedLocales, + [Locale('en', 'US'), Locale('ar', 'DZ')]); expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); await EasyLocalization.of(_context).setLocale(Locale('en', 'US')); @@ -580,7 +615,10 @@ void main() async { child: MyApp(), path: 'i18n', // fallbackLocale:Locale('en') , - supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [ + Locale('en', 'US'), + Locale('ar', 'DZ') + ], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump @@ -600,12 +638,63 @@ void main() async { child: MyApp(), path: 'i18n', // fallbackLocale:Locale('en') , - supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ') + supportedLocales: [ + Locale('en', 'US'), + Locale('ar', 'DZ') + ], // Locale('en', 'US'), Locale('ar','DZ') + )); + await tester.idle(); + // The async delegator load will require build on the next frame. Thus, pump + await tester.pumpAndSettle(); + + expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); + }); + }, + ); + + testWidgets( + '[EasyLocalization] device locale test', + (WidgetTester tester) async { + await tester.runAsync(() async { + await tester.pumpWidget(EasyLocalization( + child: MyApp(), + path: 'i18n', + supportedLocales: [ + Locale('en', 'US'), + Locale('ar', 'DZ') + ], // Locale('en', 'US'), Locale('ar','DZ') )); await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); + expect(EasyLocalization.of(_context).deviceLocale.toString(), + Platform.localeName); + }); + }, + ); + + testWidgets( + '[EasyLocalization] reset device locale test', + (WidgetTester tester) async { + await tester.runAsync(() async { + await tester.pumpWidget(EasyLocalization( + child: MyApp(), + path: 'i18n', + supportedLocales: [ + Locale('en', 'US'), + Locale('ar', 'DZ') + ], // Locale('en', 'US'), Locale('ar','DZ') + startLocale: Locale('ar', 'DZ'), + )); + await tester.idle(); + // The async delegator load will require build on the next frame. Thus, pump + await tester.pumpAndSettle(); + + expect(EasyLocalization.of(_context).locale, Locale('ar', 'DZ')); + // reset to device locale + await _context.resetLocale(); + await tester.pumpAndSettle(); expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); }); }, From 93f09a8c1df9e7cfd3a9b21560ad90cb7e6b65ab Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 7 Feb 2021 18:59:46 +0500 Subject: [PATCH 23/52] update readme --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index ecdcb2fd..0bea67fa 100644 --- a/README.md +++ b/README.md @@ -353,6 +353,31 @@ Output: print('example.emptyNameError'.tr()); //Output: Please fill in your full name ``` +### 🔥 Reset locale `resetLocale()` + +Reset locale to device locale + +Example: + +```dart +RaisedButton( + onPressed: (){ + context.resetLocale(); + }, + child: Text(LocaleKeys.reset_locale).tr(), +) +``` + +### 🔥 Get device locale `deviceLocale` + +Get device locale + +Example: + +```dart +print(${context.deviceLocale.toString()}) // OUTPUT: en_US +``` + ### 🔥 Delete save locale `deleteSaveLocale()` Clears a saved locale from device storage From 5a40847bf059ef1760a8968bb8fdcf7724df4ebb Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 7 Feb 2021 19:02:18 +0500 Subject: [PATCH 24/52] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c755e1ce..5aec976e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Added `EasyLocalization.ensureInitialized()`, Needs to be called - fixed many issues. - customizable logger [EasyLogger] +- device locale and reset device locale ### [2.3.3] From e43cd64c002f327a3382282639dfe32f0fd53380 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 7 Feb 2021 19:05:48 +0500 Subject: [PATCH 25/52] rename vars --- lib/src/easy_localization_controller.dart | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/src/easy_localization_controller.dart b/lib/src/easy_localization_controller.dart index 8480ea1d..46a8b27d 100644 --- a/lib/src/easy_localization_controller.dart +++ b/lib/src/easy_localization_controller.dart @@ -8,7 +8,7 @@ import 'translations.dart'; class EasyLocalizationController extends ChangeNotifier { static Locale _savedLocale; - static Locale _systemLocale; + static Locale _deviceLocale; Locale _locale; @@ -45,7 +45,7 @@ class EasyLocalizationController extends ChangeNotifier { } else { // From Device Locale _locale = supportedLocales.firstWhere( - (locale) => _checkInitLocale(locale, _systemLocale), + (locale) => _checkInitLocale(locale, _deviceLocale), orElse: () => _getFallbackLocale(supportedLocales, fallbackLocale)); } } @@ -61,12 +61,12 @@ class EasyLocalizationController extends ChangeNotifier { } } - bool _checkInitLocale(Locale locale, Locale _systemLocale) { + bool _checkInitLocale(Locale locale, Locale _deviceLocale) { // If supported locale not contain countryCode then check only languageCode if (locale.countryCode == null) { - return (locale.languageCode == _systemLocale.languageCode); + return (locale.languageCode == _deviceLocale.languageCode); } else { - return (locale == _systemLocale); + return (locale == _deviceLocale); } } @@ -104,8 +104,8 @@ class EasyLocalizationController extends ChangeNotifier { final _preferences = await SharedPreferences.getInstance(); final _strLocale = _preferences.getString('locale'); _savedLocale = _strLocale != null ? localeFromString(_strLocale) : null; - final _deviceLocale = await findSystemLocale(); - _systemLocale = localeFromString(_deviceLocale); + final _foundPlatformLocale = await findSystemLocale(); + _deviceLocale = localeFromString(_foundPlatformLocale); EasyLocalization.logger('Localization initialized'); } @@ -116,11 +116,11 @@ class EasyLocalizationController extends ChangeNotifier { EasyLocalization.logger('Saved locale deleted'); } - Locale get deviceLocale => _systemLocale; + Locale get deviceLocale => _deviceLocale; Future resetLocale() async { - EasyLocalization.logger('Reset locale to platform locale $_systemLocale'); + EasyLocalization.logger('Reset locale to platform locale $_deviceLocale'); - await setLocale(_systemLocale); + await setLocale(_deviceLocale); } } From 010fd5431b69c867daacd3f49515d3357f50a110 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 7 Feb 2021 19:54:13 +0500 Subject: [PATCH 26/52] extensions helpers --- CHANGELOG.md | 1 + README.md | 17 +++++ lib/src/asset_loader.dart | 2 +- lib/src/easy_localization_controller.dart | 4 +- lib/src/utils.dart | 30 ++++++++ test/easy_localization_test.dart | 83 ++++++++++++++++------- test/easy_localization_utils_test.dart | 10 +-- 7 files changed, 113 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aec976e..1817a17f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - fixed many issues. - customizable logger [EasyLogger] - device locale and reset device locale +- extensions helpers ### [2.3.3] diff --git a/README.md b/README.md index 0bea67fa..7b15e47f 100644 --- a/README.md +++ b/README.md @@ -511,6 +511,22 @@ EasyLocalization.logger.printer = customLogPrinter; Read more about [Easy Logger](https://github.com/aissat/easy_localization/blob/master/packages/easy_logger/README.md) +## ➕ Extensions helpers + +### String to locale + +```dart +'en_US'.toLocale(); // Locale('en', 'US') + +//with custom separator +'en|US'.toLocale(separator: '|') // Locale('en', 'US') +``` +### Locale to String with separator + +```dart +Locale('en', 'US').toStringWithSeparator(separator: '|') // en|US +``` +

@@ -518,6 +534,7 @@ Read more about [Easy Logger](https://github.com/aissat/easy_localization/blob/m

+ ## Screenshots | Arabic RTL | English LTR | Error widget | diff --git a/lib/src/asset_loader.dart b/lib/src/asset_loader.dart index 81bab17a..ada78bbf 100644 --- a/lib/src/asset_loader.dart +++ b/lib/src/asset_loader.dart @@ -27,7 +27,7 @@ class RootBundleAssetLoader extends AssetLoader { const RootBundleAssetLoader(); String getLocalePath(String basePath, Locale locale) { - return '$basePath/${localeToString(locale, separator: "-")}.json'; + return '$basePath/${locale.toStringWithSeparator(separator: "-")}.json'; } @override diff --git a/lib/src/easy_localization_controller.dart b/lib/src/easy_localization_controller.dart index 46a8b27d..714239fe 100644 --- a/lib/src/easy_localization_controller.dart +++ b/lib/src/easy_localization_controller.dart @@ -103,9 +103,9 @@ class EasyLocalizationController extends ChangeNotifier { static Future initEasyLocation() async { final _preferences = await SharedPreferences.getInstance(); final _strLocale = _preferences.getString('locale'); - _savedLocale = _strLocale != null ? localeFromString(_strLocale) : null; + _savedLocale = _strLocale != null ? _strLocale.toLocale() : null; final _foundPlatformLocale = await findSystemLocale(); - _deviceLocale = localeFromString(_foundPlatformLocale); + _deviceLocale = _foundPlatformLocale.toLocale(); EasyLocalization.logger('Localization initialized'); } diff --git a/lib/src/utils.dart b/lib/src/utils.dart index 3961f95c..b5c67ac0 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -1,6 +1,7 @@ part of 'easy_localization_app.dart'; /// Convert string locale [localeString] to [Locale] +@Deprecated('Deprecated on Easy Localization 3.0') Locale localeFromString(String localeString) { final localeList = localeString.split('_'); switch (localeList.length) { @@ -18,6 +19,35 @@ Locale localeFromString(String localeString) { } /// Convert [locale] to Srting with custom [separator] +@Deprecated('Deprecated on Easy Localization 3.0') String localeToString(Locale locale, {String separator = '_'}) { return locale.toString().split('_').join(separator); } + +/// [Easy Localization] locale helper +extension LocaleToStringHelper on Locale { + /// Convert [locale] to String with custom separator + String toStringWithSeparator({String separator = '_'}) { + return toString().split('_').join(separator); + } +} + +/// [Easy Localization] string locale helper +extension StringToLocaleHelper on String { + /// Convert string to [Locale] object + Locale toLocale({String separator = '_'}) { + final localeList = split(separator); + switch (localeList.length) { + case 2: + return Locale(localeList.first, localeList.last); + case 3: + return Locale.fromSubtags( + languageCode: localeList.first, + scriptCode: localeList[1], + countryCode: localeList.last, + ); + default: + return Locale(localeList.first); + } + } +} diff --git a/test/easy_localization_test.dart b/test/easy_localization_test.dart index 40994854..7fd8d4ba 100644 --- a/test/easy_localization_test.dart +++ b/test/easy_localization_test.dart @@ -65,14 +65,17 @@ void main() { }); test('load() succeeds', () async { - expect(Localization.load(Locale('en'), translations: r1.translations), true); + expect( + Localization.load(Locale('en'), translations: r1.translations), true); }); test('localeFromString() succeeds', () async { - expect(Locale('ar'), localeFromString('ar')); - expect(Locale('ar', 'DZ'), localeFromString('ar_DZ')); - expect(Locale.fromSubtags(languageCode: 'ar', scriptCode: 'Arab', countryCode: 'DZ'), - localeFromString('ar_Arab_DZ')); + expect(Locale('ar'), 'ar'.toLocale()); + expect(Locale('ar', 'DZ'), 'ar_DZ'.toLocale()); + expect( + Locale.fromSubtags( + languageCode: 'ar', scriptCode: 'Arab', countryCode: 'DZ'), + 'ar_Arab_DZ'.toLocale()); }); test('load() Failed assertion', () async { @@ -85,15 +88,19 @@ void main() { }); test('load() correctly sets locale path', () async { - expect(Localization.load(Locale('en'), translations: r1.translations), true); + expect( + Localization.load(Locale('en'), translations: r1.translations), true); expect(Localization.instance.tr('path'), 'path/en.json'); }); test('load() respects useOnlyLangCode', () async { - expect(Localization.load(Locale('en'), translations: r1.translations), true); + expect( + Localization.load(Locale('en'), translations: r1.translations), true); expect(Localization.instance.tr('path'), 'path/en.json'); - expect(Localization.load(Locale('en', 'us'), translations: r2.translations), true); + expect( + Localization.load(Locale('en', 'us'), translations: r2.translations), + true); expect(Localization.instance.tr('path'), 'path/en-us.json'); }); @@ -135,25 +142,34 @@ void main() { }); test('can resolve linked locale messages and apply modifiers', () { - expect(Localization.instance.tr('linkAndModify'), 'this is linked and MODIFIED'); + expect(Localization.instance.tr('linkAndModify'), + 'this is linked and MODIFIED'); }); - test('can resolve multiple linked locale messages and apply modifiers', () { + test('can resolve multiple linked locale messages and apply modifiers', + () { expect(Localization.instance.tr('linkMany'), 'many Locale messages'); }); test('can resolve linked locale messages with brackets', () { - expect(Localization.instance.tr('linkedWithBrackets'), 'linked with brackets.'); + expect(Localization.instance.tr('linkedWithBrackets'), + 'linked with brackets.'); }); test('can resolve any number of nested arguments', () { - expect(Localization.instance.tr('nestedArguments', args: ['a', 'argument', '!']), 'this is a nested argument!'); + expect( + Localization.instance + .tr('nestedArguments', args: ['a', 'argument', '!']), + 'this is a nested argument!'); }); test('can resolve nested named arguments', () { expect( - Localization.instance.tr('nestedNamedArguments', - namedArgs: {'firstArg': 'this', 'secondArg': 'named argument', 'thirdArg': '!'}), + Localization.instance.tr('nestedNamedArguments', namedArgs: { + 'firstArg': 'this', + 'secondArg': 'named argument', + 'thirdArg': '!' + }), 'this is a nested named argument!'); }); @@ -164,7 +180,8 @@ void main() { test('reports missing resource', overridePrint(() { printLog = []; expect(Localization.instance.tr('test_missing'), 'test_missing'); - expect(printLog.first, contains('Localization key [test_missing] not found')); + expect(printLog.first, + contains('Localization key [test_missing] not found')); })); test('returns resource and replaces argument', () { @@ -175,7 +192,8 @@ void main() { }); test('returns resource and replaces argument in any nest level', () { expect( - Localization.instance.tr('nested.super.duper.nested_with_arg', args: ['what a nest']), + Localization.instance + .tr('nested.super.duper.nested_with_arg', args: ['what a nest']), 'nested.super.duper.nested_with_arg what a nest', ); }); @@ -187,20 +205,25 @@ void main() { ); }); - test('should raise exception if provided arguments length is different from the count of {} in the resource', () { + test( + 'should raise exception if provided arguments length is different from the count of {} in the resource', + () { // @TODO }); test('return resource and replaces named argument', () { expect( - Localization.instance.tr('test_replace_named', namedArgs: {'arg1': 'one', 'arg2': 'two'}), + Localization.instance.tr('test_replace_named', + namedArgs: {'arg1': 'one', 'arg2': 'two'}), 'test named replace one two', ); }); - test('returns resource and replaces named argument in any nest level', () { + test('returns resource and replaces named argument in any nest level', + () { expect( - Localization.instance.tr('nested.super.duper.nested_with_named_arg', namedArgs: {'arg': 'what a nest'}), + Localization.instance.tr('nested.super.duper.nested_with_named_arg', + namedArgs: {'arg': 'what a nest'}), 'nested.super.duper.nested_with_named_arg what a nest', ); }); @@ -218,11 +241,13 @@ void main() { test('gender returns the correct resource and replaces args', () { expect( - Localization.instance.tr('gender_and_replace', gender: 'male', args: ['one']), + Localization.instance + .tr('gender_and_replace', gender: 'male', args: ['one']), 'Hi one man ;)', ); expect( - Localization.instance.tr('gender_and_replace', gender: 'female', args: ['one']), + Localization.instance + .tr('gender_and_replace', gender: 'female', args: ['one']), 'Hello one girl :)', ); }); @@ -260,19 +285,25 @@ void main() { }); test('with number format', () { - expect(Localization.instance.plural('day', 3, format: NumberFormat.currency()), 'USD3.00 other days'); + expect( + Localization.instance + .plural('day', 3, format: NumberFormat.currency()), + 'USD3.00 other days'); }); test('zero with args', () { - expect(Localization.instance.plural('money', 0, args: ['John', '0']), 'John has no money'); + expect(Localization.instance.plural('money', 0, args: ['John', '0']), + 'John has no money'); }); test('one with args', () { - expect(Localization.instance.plural('money', 1, args: ['John', '1']), 'John has 1 dollar'); + expect(Localization.instance.plural('money', 1, args: ['John', '1']), + 'John has 1 dollar'); }); test('other with args', () { - expect(Localization.instance.plural('money', 3, args: ['John', '3']), 'John has 3 dollars'); + expect(Localization.instance.plural('money', 3, args: ['John', '3']), + 'John has 3 dollars'); }); }); diff --git a/test/easy_localization_utils_test.dart b/test/easy_localization_utils_test.dart index ec959c38..28db5fe3 100644 --- a/test/easy_localization_utils_test.dart +++ b/test/easy_localization_utils_test.dart @@ -17,17 +17,17 @@ void main() { group('Utils', () { group('Locales', () { test('localeFromString only language code', () { - var locale = localeFromString('en'); + var locale = 'en'.toLocale(); expect(locale, Locale('en')); }); test('localeFromString language code and country code', () { - var locale = localeFromString('en_US'); + var locale = 'en_US'.toLocale(); expect(locale, Locale('en', 'US')); }); test('localeFromString language, country, script code', () { - var locale = localeFromString('zh_Hant_HK'); + var locale = 'zh_Hant_HK'.toLocale(); expect( locale, Locale.fromSubtags( @@ -37,14 +37,14 @@ void main() { test('localeToString', () { var locale = Locale.fromSubtags( languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'); - var string = localeToString(locale); + var string = locale.toStringWithSeparator(); expect(string, 'zh_Hant_HK'); }); test('localeToString custom separator', () { var locale = Locale.fromSubtags( languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'); - var string = localeToString(locale, separator: '|'); + var string = locale.toStringWithSeparator(separator: '|'); expect(string, 'zh|Hant|HK'); }); }); From 6f283e48d9d4ed75f7dceee342a606be5a79279e Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 7 Feb 2021 20:10:29 +0500 Subject: [PATCH 27/52] update example --- .../android/app/src/main/AndroidManifest.xml | 50 +++++++++---------- .../io/aissat/example/example/MainActivity.kt | 3 +- .../res/drawable-v21/launch_background.xml | 12 +++++ .../app/src/main/res/values-night/styles.xml | 18 +++++++ .../app/src/main/res/values/styles.xml | 13 +++-- 5 files changed, 66 insertions(+), 30 deletions(-) create mode 100644 example/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 example/android/app/src/main/res/values-night/styles.xml diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index abf17029..f8891d42 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,16 +1,8 @@ - - - - + + + + - - - - - - - + + diff --git a/example/android/app/src/main/kotlin/io/aissat/example/example/MainActivity.kt b/example/android/app/src/main/kotlin/io/aissat/example/example/MainActivity.kt index 3d315a25..c9820620 100644 --- a/example/android/app/src/main/kotlin/io/aissat/example/example/MainActivity.kt +++ b/example/android/app/src/main/kotlin/io/aissat/example/example/MainActivity.kt @@ -2,4 +2,5 @@ package io.aissat.example.example import io.flutter.embedding.android.FlutterActivity -class MainActivity: FlutterActivity() {} +class MainActivity: FlutterActivity() { +} \ No newline at end of file diff --git a/example/android/app/src/main/res/drawable-v21/launch_background.xml b/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..449a9f93 --- /dev/null +++ b/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml index c745a5ef..d74aa35c 100644 --- a/example/android/app/src/main/res/values/styles.xml +++ b/example/android/app/src/main/res/values/styles.xml @@ -1,11 +1,18 @@ - - From 38ba44ce3306165af8ea7889759764ccbe8256b2 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 7 Feb 2021 20:14:23 +0500 Subject: [PATCH 28/52] update logs --- lib/src/asset_loader.dart | 2 +- lib/src/easy_localization_app.dart | 12 ++++++------ lib/src/easy_localization_controller.dart | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/src/asset_loader.dart b/lib/src/asset_loader.dart index ada78bbf..99ccdb21 100644 --- a/lib/src/asset_loader.dart +++ b/lib/src/asset_loader.dart @@ -33,7 +33,7 @@ class RootBundleAssetLoader extends AssetLoader { @override Future> load(String path, Locale locale) async { var localePath = getLocalePath(path, locale); - EasyLocalization.logger('Load asset from $path'); + EasyLocalization.logger.debug('Load asset from $path'); return json.decode(await rootBundle.loadString(localePath)); } } diff --git a/lib/src/easy_localization_app.dart b/lib/src/easy_localization_app.dart index 239a9a73..f2015750 100644 --- a/lib/src/easy_localization_app.dart +++ b/lib/src/easy_localization_app.dart @@ -82,7 +82,7 @@ class EasyLocalization extends StatefulWidget { assert(supportedLocales != null && supportedLocales.isNotEmpty), assert(path != null && path.isNotEmpty), super(key: key) { - EasyLocalization.logger('Start'); + EasyLocalization.logger.debug('Start'); } @override @@ -108,7 +108,7 @@ class _EasyLocalizationState extends State { @override void initState() { - EasyLocalization.logger('Init state'); + EasyLocalization.logger.debug('Init state'); localizationController = EasyLocalizationController( saveLocale: widget.saveLocale, fallbackLocale: widget.fallbackLocale, @@ -138,7 +138,7 @@ class _EasyLocalizationState extends State { @override Widget build(BuildContext context) { - EasyLocalization.logger('Build'); + EasyLocalization.logger.debug('Build'); if (translationsLoadError != null) { return widget.errorWidget != null ? widget.errorWidget(translationsLoadError) @@ -187,7 +187,7 @@ class _EasyLocalizationProvider extends InheritedWidget { {Key key, this.delegate}) : currentLocale = _localeState.locale, super(key: key, child: parent.child) { - EasyLocalization.logger('Init provider'); + EasyLocalization.logger.debug('Init provider'); } /// Get current locale @@ -235,7 +235,7 @@ class _EasyLocalizationDelegate extends LocalizationsDelegate { _EasyLocalizationDelegate( {this.localizationController, this.supportedLocales}) { - EasyLocalization.logger('Init Localization Delegate'); + EasyLocalization.logger.debug('Init Localization Delegate'); } @override @@ -243,7 +243,7 @@ class _EasyLocalizationDelegate extends LocalizationsDelegate { @override Future load(Locale value) async { - EasyLocalization.logger('Load Localization Delegate'); + EasyLocalization.logger.debug('Load Localization Delegate'); if (localizationController.translations == null) { await localizationController.loadTranslations(); } diff --git a/lib/src/easy_localization_controller.dart b/lib/src/easy_localization_controller.dart index 714239fe..2f4d8e47 100644 --- a/lib/src/easy_localization_controller.dart +++ b/lib/src/easy_localization_controller.dart @@ -106,7 +106,7 @@ class EasyLocalizationController extends ChangeNotifier { _savedLocale = _strLocale != null ? _strLocale.toLocale() : null; final _foundPlatformLocale = await findSystemLocale(); _deviceLocale = _foundPlatformLocale.toLocale(); - EasyLocalization.logger('Localization initialized'); + EasyLocalization.logger.debug('Localization initialized'); } Future deleteSaveLocale() async { From db3ad0eac500d4fdc849da49cc12ff9b4244dddb Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sun, 7 Feb 2021 20:16:10 +0500 Subject: [PATCH 29/52] change debug color on logger --- packages/easy_logger/lib/src/logger_printer.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/easy_logger/lib/src/logger_printer.dart b/packages/easy_logger/lib/src/logger_printer.dart index 4757bae9..cc2d03c8 100644 --- a/packages/easy_logger/lib/src/logger_printer.dart +++ b/packages/easy_logger/lib/src/logger_printer.dart @@ -10,8 +10,8 @@ EasyLogPrinter easyLogDefaultPrinter = String _coloredString(String string) { switch (level) { case LevelMessages.debug: - // white - return '\u001b[37m$string\u001b[0m'; + // gray + return '\u001b[90m$string\u001b[0m'; case LevelMessages.info: // green return '\u001b[32m$string\u001b[0m'; From b1a82a284d7ad60d41cedf14fec43d72c32964f5 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Wed, 10 Feb 2021 00:58:12 +0500 Subject: [PATCH 30/52] update readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7b15e47f..05bdb7f7 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,9 @@ import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:easy_localization/easy_localization.dart'; void main() async { + WidgetsFlutterBinding.ensureInitialized(); await EasyLocalization.ensureInitialized(); + runApp( EasyLocalization( supportedLocales: [Locale('en', 'US'), Locale('de', 'DE')], From 3e932d1ffa8506a31fc098405120d658bfacb3e1 Mon Sep 17 00:00:00 2001 From: aissat Date: Mon, 15 Feb 2021 22:47:31 +0100 Subject: [PATCH 31/52] migrate easy_logger to null safety --- packages/easy_logger/lib/src/logger.dart | 22 +++++++++---------- .../easy_logger/lib/src/logger_printer.dart | 4 ++-- packages/easy_logger/pubspec.yaml | 6 ++--- .../easy_logger/test/easy_logger_test.dart | 4 ++-- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/easy_logger/lib/src/logger.dart b/packages/easy_logger/lib/src/logger.dart index ca7bbc8b..776f8f68 100644 --- a/packages/easy_logger/lib/src/logger.dart +++ b/packages/easy_logger/lib/src/logger.dart @@ -19,14 +19,14 @@ class EasyLogger { LevelMessages.error, LevelMessages.warning, ], - EasyLogPrinter printer, + EasyLogPrinter? printer, this.defaultLevel = LevelMessages.info, }) { _printer = printer ?? easyLogDefaultPrinter; _currentBuildMode = _getCurrentBuildMode(); } - BuildMode _currentBuildMode; + BuildMode? _currentBuildMode; /// Name prefix in the logging line. /// @Default value `''` empty string. @@ -48,11 +48,11 @@ class EasyLogger { /// @Default value `LevelMessages.info` LevelMessages defaultLevel; - EasyLogPrinter _printer; + EasyLogPrinter? _printer; /// Print function that generates and printing log lines /// @Default value `easyLogDefaultPrinter` - EasyLogPrinter get printer => _printer; + EasyLogPrinter? get printer => _printer; /// Printer function setter. /// You can change the standard print function to a custom one. @@ -69,7 +69,7 @@ class EasyLogger { /// /// logger.printer = customLogPrinter; /// ``` - set printer(EasyLogPrinter newPrinter) => _printer = newPrinter; + set printer(EasyLogPrinter? newPrinter) => _printer = newPrinter; BuildMode _getCurrentBuildMode() { if (kReleaseMode) { @@ -92,30 +92,30 @@ class EasyLogger { } /// The main callable function for handling log messages. - void call(Object object, {StackTrace stackTrace, LevelMessages level}) { + void call(Object object, {StackTrace? stackTrace, LevelMessages? level}) { level ??= defaultLevel; if (isEnabled(level)) { - _printer(object, stackTrace: stackTrace, level: level, name: name); + _printer!(object, stackTrace: stackTrace, level: level, name: name); } } /// Helper for main callable function. /// Call logger function with level [LevelMessages.debug] - void debug(Object object, {StackTrace stackTrace}) => + void debug(Object object, {StackTrace? stackTrace}) => call(object, stackTrace: stackTrace, level: LevelMessages.debug); /// Helper for main callable function. /// Call logger function with level [LevelMessages.info] - void info(Object object, {StackTrace stackTrace}) => + void info(Object object, {StackTrace? stackTrace}) => call(object, stackTrace: stackTrace, level: LevelMessages.info); /// Helper for main callable function. /// Call logger function with level [LevelMessages.warning] - void warning(Object object, {StackTrace stackTrace}) => + void warning(Object object, {StackTrace? stackTrace}) => call(object, stackTrace: stackTrace, level: LevelMessages.warning); /// Helper for main callable function. /// Call logger function with level [LevelMessages.error] - void error(Object object, {StackTrace stackTrace}) => + void error(Object object, {StackTrace? stackTrace}) => call(object, stackTrace: stackTrace, level: LevelMessages.error); } diff --git a/packages/easy_logger/lib/src/logger_printer.dart b/packages/easy_logger/lib/src/logger_printer.dart index cc2d03c8..5afc45b9 100644 --- a/packages/easy_logger/lib/src/logger_printer.dart +++ b/packages/easy_logger/lib/src/logger_printer.dart @@ -2,11 +2,11 @@ import '../easy_logger.dart'; /// Type for function printing/logging in [EasyLogger]. typedef EasyLogPrinter = Function(Object object, - {String name, LevelMessages level, StackTrace stackTrace}); + {String? name, LevelMessages? level, StackTrace? stackTrace}); /// Default function printing. EasyLogPrinter easyLogDefaultPrinter = - (Object object, {String name, StackTrace stackTrace, LevelMessages level}) { + (Object object, {String? name, StackTrace? stackTrace, LevelMessages? level}) { String _coloredString(String string) { switch (level) { case LevelMessages.debug: diff --git a/packages/easy_logger/pubspec.yaml b/packages/easy_logger/pubspec.yaml index 1e90ee6e..13079249 100644 --- a/packages/easy_logger/pubspec.yaml +++ b/packages/easy_logger/pubspec.yaml @@ -1,9 +1,9 @@ name: easy_logger description: Easy logger -version: 0.0.1 +version: 0.0.1-nullsafety environment: - sdk: ">=2.7.0 <3.0.0" + sdk: '>=2.12.0-259.8.beta <3.0.0' dependencies: flutter: @@ -12,6 +12,6 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.8.0+1 + pedantic: ^1.10.0-nullsafety.3 flutter: \ No newline at end of file diff --git a/packages/easy_logger/test/easy_logger_test.dart b/packages/easy_logger/test/easy_logger_test.dart index c82d9ded..085cbd76 100644 --- a/packages/easy_logger/test/easy_logger_test.dart +++ b/packages/easy_logger/test/easy_logger_test.dart @@ -4,7 +4,7 @@ import 'package:easy_logger/easy_logger.dart'; import 'package:flutter_test/flutter_test.dart'; List printLog = []; -ZoneSpecification spec; +ZoneSpecification? spec; dynamic Function() overridePrint(Function() testFn) => () { spec = ZoneSpecification( print: (_, __, ___, String msg) { @@ -15,7 +15,7 @@ dynamic Function() overridePrint(Function() testFn) => () { return Zone.current.fork(specification: spec).run(testFn); }; -EasyLogger logger; +late EasyLogger logger; void main() { group('Logger testing print', () { logger = EasyLogger(name: 'test logger'); From 842853d61a5aa101860795100f9a8fa6c1e51c61 Mon Sep 17 00:00:00 2001 From: aissat Date: Mon, 15 Feb 2021 22:49:24 +0100 Subject: [PATCH 32/52] [pub] migrating to null safety --- .github/workflows/main.yml | 2 +- README.md | 1 + bin/generate.dart | 34 ++-- example/lib/main.dart | 6 +- example/pubspec.yaml | 2 +- lib/src/asset_loader.dart | 4 +- lib/src/easy_localization_app.dart | 60 +++---- lib/src/easy_localization_controller.dart | 44 ++--- lib/src/localization.dart | 60 +++---- lib/src/public.dart | 18 +-- lib/src/public_ext.dart | 42 ++--- lib/src/translations.dart | 18 +-- packages/easy_logger/pubspec.yaml | 4 +- pubspec.yaml | 17 +- test/easy_localization_context_test.dart | 74 ++++----- test/easy_localization_widget_test.dart | 186 +++++++++++----------- 16 files changed, 290 insertions(+), 282 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 36aae74f..1679137c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,7 +20,7 @@ jobs: java-version: '12.x' - uses: subosito/flutter-action@v1 with: - channel: 'stable' # or: 'dev' or 'beta' + channel: 'dev' # or: 'dev' or 'beta' - name: Install packages dependencies run: flutter pub get diff --git a/README.md b/README.md index 05bdb7f7..58f42dbb 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Easy and Fast internationalization for your Flutter Apps - ⁉️ Error widget for missing translations - ❤️ Extension methods on `Text` and `BuildContext` - 💻 Code generation for localization files and keys. +- 🛡️ Null safety - 🖨️ Customizable logger. ## Getting Started diff --git a/bin/generate.dart b/bin/generate.dart index 8a6469e4..13fcc207 100644 --- a/bin/generate.dart +++ b/bin/generate.dart @@ -40,36 +40,36 @@ GenerateOptions _generateOption(List args) { return generateOptions; } -ArgParser _generateArgParser(GenerateOptions generateOptions) { +ArgParser _generateArgParser(GenerateOptions? generateOptions) { var parser = ArgParser(); parser.addOption('source-dir', abbr: 'S', defaultsTo: 'resources/langs', - callback: (String x) => generateOptions.sourceDir = x, + callback: (String? x) => generateOptions!.sourceDir = x, help: 'Folder containing localization files'); parser.addOption('source-file', abbr: 's', - callback: (String x) => generateOptions.sourceFile = x, + callback: (String? x) => generateOptions!.sourceFile = x, help: 'File to use for localization'); parser.addOption('output-dir', abbr: 'O', defaultsTo: 'lib/generated', - callback: (String x) => generateOptions.outputDir = x, + callback: (String? x) => generateOptions!.outputDir = x, help: 'Output folder stores for the generated file'); parser.addOption('output-file', abbr: 'o', defaultsTo: 'codegen_loader.g.dart', - callback: (String x) => generateOptions.outputFile = x, + callback: (String? x) => generateOptions!.outputFile = x, help: 'Output file name'); parser.addOption('format', abbr: 'f', defaultsTo: 'json', - callback: (String x) => generateOptions.format = x, + callback: (String? x) => generateOptions!.format = x, help: 'Support json or keys formats', allowed: ['json', 'keys']); @@ -77,12 +77,12 @@ ArgParser _generateArgParser(GenerateOptions generateOptions) { } class GenerateOptions { - String sourceDir; - String sourceFile; - String templateLocale; - String outputDir; - String outputFile; - String format; + String? sourceDir; + String? sourceFile; + String? templateLocale; + String? outputDir; + String? outputFile; + String? format; @override String toString() { @@ -92,8 +92,8 @@ class GenerateOptions { void handleLangFiles(GenerateOptions options) async { final current = Directory.current; - final source = Directory.fromUri(Uri.parse(options.sourceDir)); - final output = Directory.fromUri(Uri.parse(options.outputDir)); + final source = Directory.fromUri(Uri.parse(options.sourceDir!)); + final output = Directory.fromUri(Uri.parse(options.outputDir!)); final sourcePath = Directory(path.join(current.path, source.path)); final outputPath = Directory(path.join(current.path, output.path, options.outputFile)); @@ -133,7 +133,7 @@ Future> dirContents(Directory dir) { } void generateFile( - List files, Directory outputPath, String format) async { + List files, Directory outputPath, String? format) async { var generatedFile = File(outputPath.path); if (!generatedFile.existsSync()) { generatedFile.createSync(recursive: true); @@ -179,7 +179,7 @@ abstract class LocaleKeys { classBuilder.writeln(file); } -String _resolve(Map translations, [String accKey]) { +String _resolve(Map translations, [String? accKey]) { var fileContent = ''; final sortedKeys = translations.keys.toList(); @@ -234,7 +234,7 @@ class CodegenLoader extends AssetLoader{ listLocales.add('"$localeName": $localeName'); final fileData = File(file.path); - Map data = json.decode(await fileData.readAsString()); + Map? data = json.decode(await fileData.readAsString()); final mapString = JsonEncoder.withIndent(' ').convert(data); gFile += 'static const Map $localeName = $mapString;\n'; diff --git a/example/lib/main.dart b/example/lib/main.dart index 90f5cfd9..d68eed5b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -87,7 +87,7 @@ class _MyHomePageState extends State { title: Text(LocaleKeys.title).tr(context: context), //Text(AppLocalizations.of(context).tr('title')), actions: [ - FlatButton( + TextButton( child: Icon(Icons.language), onPressed: () { Navigator.push( @@ -135,7 +135,7 @@ class _MyHomePageState extends State { Text(LocaleKeys.msg_named) .tr(namedArgs: {'lang': 'Dart'}, args: ['Easy localization']), Text(LocaleKeys.clicked).plural(counter), - FlatButton( + TextButton( onPressed: () { incrementCounter(); }, @@ -155,7 +155,7 @@ class _MyHomePageState extends State { SizedBox( height: 20, ), - RaisedButton( + ElevatedButton( onPressed: () { context.resetLocale(); }, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 6d2e5006..8395c51d 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. - +publish_to: none # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 # followed by an optional build number separated by a +. diff --git a/lib/src/asset_loader.dart b/lib/src/asset_loader.dart index 99ccdb21..03cef967 100644 --- a/lib/src/asset_loader.dart +++ b/lib/src/asset_loader.dart @@ -17,7 +17,7 @@ import 'package:flutter/services.dart'; /// ``` abstract class AssetLoader { const AssetLoader(); - Future> load(String path, Locale locale); + Future?> load(String path, Locale locale); } /// @@ -31,7 +31,7 @@ class RootBundleAssetLoader extends AssetLoader { } @override - Future> load(String path, Locale locale) async { + Future?> load(String path, Locale locale) async { var localePath = getLocalePath(path, locale); EasyLocalization.logger.debug('Load asset from $path'); return json.decode(await rootBundle.loadString(localePath)); diff --git a/lib/src/easy_localization_app.dart b/lib/src/easy_localization_app.dart index f2015750..1a6edb0a 100644 --- a/lib/src/easy_localization_app.dart +++ b/lib/src/easy_localization_app.dart @@ -32,10 +32,10 @@ class EasyLocalization extends StatefulWidget { final List supportedLocales; /// Locale when the locale is not in the list - final Locale fallbackLocale; + final Locale? fallbackLocale; /// Overrides device locale. - final Locale startLocale; + final Locale? startLocale; /// Trigger for using only language code for reading localization files. /// @Default value false @@ -65,22 +65,21 @@ class EasyLocalization extends StatefulWidget { /// Shows a custom error widget when an error is encountered instead of the default error widget. /// @Default value `errorWidget = ErrorWidget()` - final Widget Function(FlutterError message) errorWidget; + final Widget Function(FlutterError? message)? errorWidget; EasyLocalization({ - Key key, - @required this.child, - @required this.supportedLocales, - @required this.path, + Key? key, + required this.child, + required this.supportedLocales, + required this.path, this.fallbackLocale, this.startLocale, this.useOnlyLangCode = false, this.assetLoader = const RootBundleAssetLoader(), this.saveLocale = true, this.errorWidget, - }) : assert(child != null), - assert(supportedLocales != null && supportedLocales.isNotEmpty), - assert(path != null && path.isNotEmpty), + }) : assert(supportedLocales.isNotEmpty), + assert(path.isNotEmpty), super(key: key) { EasyLocalization.logger.debug('Start'); } @@ -88,7 +87,7 @@ class EasyLocalization extends StatefulWidget { @override _EasyLocalizationState createState() => _EasyLocalizationState(); - static _EasyLocalizationProvider of(BuildContext context) => + static _EasyLocalizationProvider? of(BuildContext context) => _EasyLocalizationProvider.of(context); /// ensureInitialized needs to be called in main @@ -102,9 +101,9 @@ class EasyLocalization extends StatefulWidget { } class _EasyLocalizationState extends State { - _EasyLocalizationDelegate delegate; - EasyLocalizationController localizationController; - FlutterError translationsLoadError; + _EasyLocalizationDelegate? delegate; + EasyLocalizationController? localizationController; + FlutterError? translationsLoadError; @override void initState() { @@ -124,7 +123,7 @@ class _EasyLocalizationState extends State { }, ); // causes localization to rebuild with new language - localizationController.addListener(() { + localizationController!.addListener(() { if (mounted) setState(() {}); }); super.initState(); @@ -132,7 +131,7 @@ class _EasyLocalizationState extends State { @override void dispose() { - localizationController.dispose(); + localizationController!.dispose(); super.dispose(); } @@ -141,12 +140,12 @@ class _EasyLocalizationState extends State { EasyLocalization.logger.debug('Build'); if (translationsLoadError != null) { return widget.errorWidget != null - ? widget.errorWidget(translationsLoadError) - : ErrorWidget(translationsLoadError); + ? widget.errorWidget!(translationsLoadError) + : ErrorWidget(translationsLoadError!); } return _EasyLocalizationProvider( widget, - localizationController, + localizationController!, delegate: _EasyLocalizationDelegate( localizationController: localizationController, supportedLocales: widget.supportedLocales, @@ -158,7 +157,7 @@ class _EasyLocalizationState extends State { class _EasyLocalizationProvider extends InheritedWidget { final EasyLocalization parent; final EasyLocalizationController _localeState; - final Locale currentLocale; + final Locale? currentLocale; final _EasyLocalizationDelegate delegate; /// {@macro flutter.widgets.widgetsApp.localizationsDelegates} @@ -184,7 +183,7 @@ class _EasyLocalizationProvider extends InheritedWidget { // _EasyLocalizationDelegate get delegate => parent.delegate; _EasyLocalizationProvider(this.parent, this._localeState, - {Key key, this.delegate}) + {Key? key, required this.delegate}) : currentLocale = _localeState.locale, super(key: key, child: parent.child) { EasyLocalization.logger.debug('Init provider'); @@ -194,7 +193,7 @@ class _EasyLocalizationProvider extends InheritedWidget { Locale get locale => _localeState.locale; /// Get fallback locale - Locale get fallbackLocale => parent.fallbackLocale; + Locale? get fallbackLocale => parent.fallbackLocale; // Locale get startLocale => parent.startLocale; /// Change app locale @@ -212,7 +211,7 @@ class _EasyLocalizationProvider extends InheritedWidget { } /// Getting device locale from platform - Locale get deviceLocale => _localeState.deviceLocale; + Locale? get deviceLocale => _localeState.deviceLocale; /// Reset locale to platform locale Future resetLocale() => _localeState.resetLocale(); @@ -222,13 +221,13 @@ class _EasyLocalizationProvider extends InheritedWidget { return oldWidget.currentLocale != locale; } - static _EasyLocalizationProvider of(BuildContext context) => + static _EasyLocalizationProvider? of(BuildContext context) => context.dependOnInheritedWidgetOfExactType<_EasyLocalizationProvider>(); } class _EasyLocalizationDelegate extends LocalizationsDelegate { - final List supportedLocales; - final EasyLocalizationController localizationController; + final List? supportedLocales; + final EasyLocalizationController? localizationController; /// * use only the lang code to generate i18n file path like en.json or ar.json // final bool useOnlyLangCode; @@ -239,16 +238,17 @@ class _EasyLocalizationDelegate extends LocalizationsDelegate { } @override - bool isSupported(Locale locale) => supportedLocales.contains(locale); + bool isSupported(Locale locale) => supportedLocales!.contains(locale); @override Future load(Locale value) async { EasyLocalization.logger.debug('Load Localization Delegate'); - if (localizationController.translations == null) { - await localizationController.loadTranslations(); + if (localizationController!.translations == null) { + await localizationController!.loadTranslations(); } - Localization.load(value, translations: localizationController.translations); + Localization.load(value, + translations: localizationController!.translations); return Future.value(Localization.instance); } diff --git a/lib/src/easy_localization_controller.dart b/lib/src/easy_localization_controller.dart index 2f4d8e47..425fb9fd 100644 --- a/lib/src/easy_localization_controller.dart +++ b/lib/src/easy_localization_controller.dart @@ -7,10 +7,10 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'translations.dart'; class EasyLocalizationController extends ChangeNotifier { - static Locale _savedLocale; - static Locale _deviceLocale; + static Locale? _savedLocale; + static Locale? _deviceLocale; - Locale _locale; + late Locale _locale; final Function(FlutterError e) onLoadError; final assetLoader; @@ -18,19 +18,19 @@ class EasyLocalizationController extends ChangeNotifier { final bool saveLocale; final bool useOnlyLangCode; - Translations _translations; - Translations get translations => _translations; + Translations? _translations; + Translations? get translations => _translations; EasyLocalizationController({ - @required List supportedLocales, - @required this.saveLocale, - @required this.assetLoader, - @required this.path, - @required this.useOnlyLangCode, - @required this.onLoadError, - Locale startLocale, - Locale fallbackLocale, - Locale forceLocale, // used for testing + required List supportedLocales, + required this.saveLocale, + required this.assetLoader, + required this.path, + required this.useOnlyLangCode, + required this.onLoadError, + Locale? startLocale, + Locale? fallbackLocale, + Locale? forceLocale, // used for testing }) { if (forceLocale != null) { _locale = forceLocale; @@ -41,7 +41,7 @@ class EasyLocalizationController extends ChangeNotifier { // If saved locale then get else if (saveLocale && _savedLocale != null) { EasyLocalization.logger('Saved locale loaded ${_savedLocale.toString()}'); - _locale = _savedLocale; + _locale = _savedLocale!; } else { // From Device Locale _locale = supportedLocales.firstWhere( @@ -52,7 +52,7 @@ class EasyLocalizationController extends ChangeNotifier { //Get fallback Locale Locale _getFallbackLocale( - List supportedLocales, Locale fallbackLocale) { + List supportedLocales, Locale? fallbackLocale) { //If fallbackLocale not set then return first from supportedLocales if (fallbackLocale != null) { return fallbackLocale; @@ -61,10 +61,10 @@ class EasyLocalizationController extends ChangeNotifier { } } - bool _checkInitLocale(Locale locale, Locale _deviceLocale) { + bool _checkInitLocale(Locale locale, Locale? _deviceLocale) { // If supported locale not contain countryCode then check only languageCode if (locale.countryCode == null) { - return (locale.languageCode == _deviceLocale.languageCode); + return (locale.languageCode == _deviceLocale!.languageCode); } else { return (locale == _deviceLocale); } @@ -93,7 +93,7 @@ class EasyLocalizationController extends ChangeNotifier { await _saveLocale(_locale); } - Future _saveLocale(Locale locale) async { + Future _saveLocale(Locale? locale) async { if (!saveLocale) return; final _preferences = await SharedPreferences.getInstance(); await _preferences.setString('locale', locale.toString()); @@ -112,15 +112,15 @@ class EasyLocalizationController extends ChangeNotifier { Future deleteSaveLocale() async { _savedLocale = null; final _preferences = await SharedPreferences.getInstance(); - await _preferences.setString('locale', null); + await _preferences.remove('locale'); EasyLocalization.logger('Saved locale deleted'); } - Locale get deviceLocale => _deviceLocale; + Locale? get deviceLocale => _deviceLocale; Future resetLocale() async { EasyLocalization.logger('Reset locale to platform locale $_deviceLocale'); - await setLocale(_deviceLocale); + await setLocale(_deviceLocale!); } } diff --git a/lib/src/localization.dart b/lib/src/localization.dart index a0c3dc4c..b68c45fa 100644 --- a/lib/src/localization.dart +++ b/lib/src/localization.dart @@ -6,47 +6,47 @@ import 'package:intl/intl.dart'; import 'translations.dart'; class Localization { - Translations _translations; - Locale _locale; + Translations? _translations; + late Locale _locale; set translations(val) => _translations = val; - String path; - bool useOnlyLangCode; + String? path; + bool? useOnlyLangCode; final RegExp _replaceArgRegex = RegExp(r'{}'); final RegExp _linkKeyMatcher = RegExp(r'(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))'); final RegExp _linkKeyPrefixMatcher = RegExp(r'^@(?:\.([a-z]+))?:'); final RegExp _bracketsMatcher = RegExp(r'[()]'); - final _modifiers = { - 'upper': (String val) => val.toUpperCase(), - 'lower': (String val) => val.toLowerCase(), - 'capitalize': (String val) => '${val[0].toUpperCase()}${val.substring(1)}' + final _modifiers = { + 'upper': (String? val) => val!.toUpperCase(), + 'lower': (String? val) => val!.toLowerCase(), + 'capitalize': (String? val) => '${val![0].toUpperCase()}${val.substring(1)}' }; Localization(); - static Localization _instance; + static Localization? _instance; static Localization get instance => _instance ?? (_instance = Localization()); - static Localization of(BuildContext context) => + static Localization? of(BuildContext context) => Localizations.of(context, Localization); - static bool load(Locale locale, {Translations translations}) { + static bool load(Locale locale, {Translations? translations}) { instance._locale = locale; instance._translations = translations; return translations == null ? false : true; } - String tr(String key, - {List args, Map namedArgs, String gender}) { - String res; + String? tr(String? key, + {List? args, Map? namedArgs, String? gender}) { + String? res; if (gender != null) { - res = _gender(key, gender: gender); + res = _gender(key!, gender: gender); } else { res = _resolve(key); } - res = _replaceLinks(res); + res = _replaceLinks(res!); res = _replaceNamedArgs(res, namedArgs); @@ -59,9 +59,9 @@ class Localization { var result = res; for (final match in matches) { - final link = match[0]; + final link = match[0]!; final linkPrefixMatches = _linkKeyPrefixMatcher.allMatches(link); - final linkPrefix = linkPrefixMatches.first[0]; + final linkPrefix = linkPrefixMatches.first[0]!; final formatterName = linkPrefixMatches.first[1]; // Remove the leading @:, @.case: and the brackets @@ -72,7 +72,7 @@ class Localization { if (formatterName != null) { if (_modifiers.containsKey(formatterName)) { - translated = _modifiers[formatterName](translated); + translated = _modifiers[formatterName]!(translated); } else { if (logging) { EasyLocalization.logger.warning( @@ -82,27 +82,27 @@ class Localization { } result = - translated.isEmpty ? result : result.replaceAll(link, translated); + translated!.isEmpty ? result : result.replaceAll(link, translated); } return result; } - String _replaceArgs(String res, List args) { + String? _replaceArgs(String? res, List? args) { if (args == null || args.isEmpty) return res; - args.forEach((String str) => res = res.replaceFirst(_replaceArgRegex, str)); + args.forEach((String str) => res = res!.replaceFirst(_replaceArgRegex, str)); return res; } - String _replaceNamedArgs(String res, Map args) { + String _replaceNamedArgs(String res, Map? args) { if (args == null || args.isEmpty) return res; args.forEach((String key, String value) => res = res.replaceAll(RegExp('{$key}'), value)); return res; } - String plural(String key, num value, - {List args, NumberFormat format}) { + String? plural(String? key, num value, + {List? args, NumberFormat? format}) { final res = Intl.pluralLogic(value, zero: _resolvePlural(key, 'zero'), one: _resolvePlural(key, 'one'), @@ -115,7 +115,7 @@ class Localization { res, args ?? [format == null ? '$value' : format.format(value)]); } - String _gender(String key, {String gender}) => Intl.genderLogic( + String? _gender(String key, {required String gender}) => Intl.genderLogic( gender, female: _resolve(key + '.female'), male: _resolve(key + '.male'), @@ -123,8 +123,8 @@ class Localization { locale: _locale.languageCode, ); - String _resolvePlural(String key, String subKey) { - final resource = _translations.get('$key.$subKey'); + String? _resolvePlural(String? key, String subKey) { + final resource = _translations!.get('$key.$subKey'); if (resource == null && subKey == 'other') { EasyLocalization.logger.error('Plural key [$key.$subKey] required'); @@ -134,8 +134,8 @@ class Localization { } } - String _resolve(String key, {bool logging = true}) { - final resource = _translations.get(key); + String? _resolve(String? key, {bool logging = true}) { + final resource = _translations!.get(key); if (resource == null) { if (logging) { EasyLocalization.logger.warning('Localization key [$key] not found'); diff --git a/lib/src/public.dart b/lib/src/public.dart index 51c81d1b..1d30282c 100644 --- a/lib/src/public.dart +++ b/lib/src/public.dart @@ -31,15 +31,15 @@ import 'localization.dart'; /// Text('gender').tr(gender: _gender ? "female" : "male"), // gender /// ``` /// {@endtemplate} -String tr(String key, - {BuildContext context, - List args, - Map namedArgs, - String gender}) { +String? tr(String? key, + {BuildContext? context, + List? args, + Map? namedArgs, + String? gender}) { return context == null ? Localization.instance .tr(key, args: args, namedArgs: namedArgs, gender: gender) - : Localization.of(context) + : Localization.of(context)! .tr(key, args: args, namedArgs: namedArgs, gender: gender); } @@ -83,9 +83,9 @@ String tr(String key, /// var money = plural('money_args', 10.23, args: ['John', '10.23']) // output: John has 10.23 dollars /// ``` /// {@endtemplate} -String plural(String key, num value, - {BuildContext context, List args, NumberFormat format}) { +String? plural(String? key, num value, + {BuildContext? context, List? args, NumberFormat? format}) { return context == null ? Localization.instance.plural(key, value, args: args, format: format) - : Localization.of(context).plural(key, value, args: args, format: format); + : Localization.of(context)!.plural(key, value, args: args, format: format); } diff --git a/lib/src/public_ext.dart b/lib/src/public_ext.dart index 36b32117..e9ecf6fc 100644 --- a/lib/src/public_ext.dart +++ b/lib/src/public_ext.dart @@ -13,16 +13,16 @@ import 'public.dart' as ez; extension TextTranslateExtension on Text { /// {@macro tr} Text tr( - {BuildContext context, - List args, - Map namedArgs, - String gender}) => + {BuildContext? context, + List? args, + Map? namedArgs, + String? gender}) => Text( ez.tr(data, context: context, args: args, namedArgs: namedArgs, - gender: gender), + gender: gender)!, key: key, style: style, strutStyle: strutStyle, @@ -38,8 +38,9 @@ extension TextTranslateExtension on Text { /// {@macro plural} Text plural(num value, - {BuildContext context, List args, NumberFormat format}) => - Text(ez.plural(data, value, context: context, args: args, format: format), + {BuildContext? context, List? args, NumberFormat? format}) => + Text( + ez.plural(data, value, context: context, args: args, format: format)!, key: key, style: style, strutStyle: strutStyle, @@ -62,12 +63,14 @@ extension TextTranslateExtension on Text { /// ``` extension StringTranslateExtension on String { /// {@macro tr} - String tr( - {List args, Map namedArgs, String gender}) => + String? tr( + {List? args, + Map? namedArgs, + String? gender}) => ez.tr(this, args: args, namedArgs: namedArgs, gender: gender); /// {@macro plural} - String plural(num value, {List args, NumberFormat format}) => + String? plural(num value, {List? args, NumberFormat? format}) => ez.plural(this, value, args: args, format: format); } @@ -86,23 +89,24 @@ extension StringTranslateExtension on String { /// ``` extension BuildContextEasyLocalizationExtension on BuildContext { /// Get current locale - Locale get locale => EasyLocalization.of(this).locale; + Locale get locale => EasyLocalization.of(this)!.locale; /// Change app locale - void setLocale(Locale val) async => EasyLocalization.of(this).setLocale(val); + Future setLocale(Locale val) async => + EasyLocalization.of(this)!.setLocale(val); /// Old Change app locale @Deprecated( 'This is the func used in the old version of EasyLocalization. The modern func is `setLocale(val)` . ' 'This feature was deprecated after v3.0.0') - set locale(Locale val) => EasyLocalization.of(this).setLocale(val); + set locale(Locale val) => EasyLocalization.of(this)!.setLocale(val); /// Get List of supported locales. List get supportedLocales => - EasyLocalization.of(this).supportedLocales; + EasyLocalization.of(this)!.supportedLocales; /// Get fallback locale - Locale get fallbackLocale => EasyLocalization.of(this).fallbackLocale; + Locale? get fallbackLocale => EasyLocalization.of(this)!.fallbackLocale; /// {@macro flutter.widgets.widgetsApp.localizationsDelegates} /// retrun @@ -115,15 +119,15 @@ extension BuildContextEasyLocalizationExtension on BuildContext { /// ], /// ``` List get localizationDelegates => - EasyLocalization.of(this).delegates; + EasyLocalization.of(this)!.delegates; /// Clears a saved locale from device storage Future deleteSaveLocale() => - EasyLocalization.of(this).deleteSaveLocale(); + EasyLocalization.of(this)!.deleteSaveLocale(); /// Getting device locale from platform - Locale get deviceLocale => EasyLocalization.of(this).deviceLocale; + Locale? get deviceLocale => EasyLocalization.of(this)!.deviceLocale; /// Reset locale to platform locale - Future resetLocale() => EasyLocalization.of(this).resetLocale(); + Future resetLocale() => EasyLocalization.of(this)!.resetLocale(); } diff --git a/lib/src/translations.dart b/lib/src/translations.dart index fd1627cd..d2c5882d 100644 --- a/lib/src/translations.dart +++ b/lib/src/translations.dart @@ -1,15 +1,15 @@ class Translations { final Map _translations; - final Map _nestedKeysCache; + final Map _nestedKeysCache; Translations(this._translations) : _nestedKeysCache = {}; - String get(String key) => - (isNestedKey(key) ? getNested(key) : _translations[key]); + String? get(String? key) => + (isNestedKey(key) ? getNested(key) : _translations[key!]); - String getNested(String key) { + String? getNested(String? key) { if (isNestedCached(key)) return _nestedKeysCache[key]; - final keys = key.split('.'); + final keys = key!.split('.'); final kHead = keys.first; var value = _translations[kHead]; @@ -26,9 +26,9 @@ class Translations { // ? getNested(key) != null // : _translations.containsKey(key); - bool isNestedCached(String key) => _nestedKeysCache.containsKey(key); + bool isNestedCached(String? key) => _nestedKeysCache.containsKey(key); - void cacheNestedKey(String key, String value) { + void cacheNestedKey(String? key, String? value) { if (!isNestedKey(key)) { throw Exception('Cannot cache a key that is not nested.'); } @@ -36,6 +36,6 @@ class Translations { _nestedKeysCache[key] = value; } - bool isNestedKey(String key) => - !_translations.containsKey(key) && key.contains('.'); + bool isNestedKey(String? key) => + !_translations.containsKey(key) && key!.contains('.'); } diff --git a/packages/easy_logger/pubspec.yaml b/packages/easy_logger/pubspec.yaml index 13079249..e19e2970 100644 --- a/packages/easy_logger/pubspec.yaml +++ b/packages/easy_logger/pubspec.yaml @@ -1,9 +1,9 @@ name: easy_logger description: Easy logger -version: 0.0.1-nullsafety +version: 0.0.2-nullsafety environment: - sdk: '>=2.12.0-259.8.beta <3.0.0' + sdk: '>=2.12.0-0 <3.0.0' dependencies: flutter: diff --git a/pubspec.yaml b/pubspec.yaml index 64777c4b..258405c0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,20 +3,21 @@ description: Easy and Fast internationalizing and localization your Flutter Apps # author: AISSAT abdelwahab homepage: https://github.com/aissat/easy_localization issue_tracker: https://github.com/aissat/easy_localization/issues +publish_to: none -version: 3.0.0-dev.2 +version: 3.0.0-nullsafety environment: - sdk: ">=2.7.0 <3.0.0" + sdk: '>=2.12.0-0 <3.0.0' dependencies: flutter: sdk: flutter - intl: ">=0.16.0 <0.17.0" - shared_preferences: ^0.5.12+4 - args: ^1.6.0 - path: ^1.7.0 - easy_logger: + shared_preferences: ^2.0.0-nullsafety + intl: ^0.17.0 + args: ^2.0.0 + path: ^1.8.0 + easy_logger: path: packages/easy_logger flutter_localizations: sdk: flutter @@ -25,7 +26,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - pedantic: ^1.9.2 + pedantic: ^1.10.0 flutter: assets: diff --git a/test/easy_localization_context_test.dart b/test/easy_localization_context_test.dart index 7dfe09da..052166df 100644 --- a/test/easy_localization_context_test.dart +++ b/test/easy_localization_context_test.dart @@ -8,7 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; -BuildContext _context; +BuildContext? _context; class MyApp extends StatelessWidget { @override @@ -59,13 +59,13 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(_context.supportedLocales, [Locale('en', 'US')]); - expect(_context.locale, Locale('en', 'US')); + expect(_context!.supportedLocales, [Locale('en', 'US')]); + expect(_context!.locale, Locale('en', 'US')); var l = Locale('en', 'US'); - await _context.setLocale(l); + await _context!.setLocale(l); await tester.pumpAndSettle(); - expect(_context.locale, Locale('en', 'US')); + expect(_context!.locale, Locale('en', 'US')); final trFinder = find.text('test'); expect(trFinder, findsOneWidget); @@ -76,14 +76,14 @@ void main() async { expect(plural('day', 1, context: _context), '1 day'); expect(plural('day', 2, context: _context), '2 days'); expect(plural('day', 3, context: _context), '3 other days'); - expect(_context.locale, Locale('en', 'US')); + expect(_context!.locale, Locale('en', 'US')); l = Locale('ar', 'DZ'); expect(() async { - await _context.setLocale(l); + await _context!.setLocale(l); }, throwsAssertionError); await tester.pumpAndSettle(); - expect(_context.locale, Locale('en', 'US')); + expect(_context!.locale, Locale('en', 'US')); }); }, ); @@ -101,10 +101,10 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(Localization.of(_context), isInstanceOf()); - expect(_context.supportedLocales, + expect(Localization.of(_context!), isInstanceOf()); + expect(_context!.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(_context.locale, Locale('en', 'US')); + expect(_context!.locale, Locale('en', 'US')); var trFinder = find.text('test'); expect(trFinder, findsOneWidget); @@ -117,31 +117,31 @@ void main() async { expect(plural('day', 3, context: _context), '3 other days'); var l = Locale('en', 'US'); - await _context.setLocale(l); + await _context!.setLocale(l); await tester.pumpAndSettle(); - expect(_context.locale, l); + expect(_context!.locale, l); l = Locale('ar', 'DZ'); - await _context.setLocale(l); + await _context!.setLocale(l); await tester.idle(); await tester.pumpAndSettle(); - expect(_context.locale, l); + expect(_context!.locale, l); l = Locale('en', 'US'); - await _context.setLocale(l); + await _context!.setLocale(l); await tester.idle(); await tester.pumpAndSettle(); - expect(_context.locale, l); + expect(_context!.locale, l); l = Locale('en', 'UK'); expect( - () async => {await _context.setLocale(l)}, throwsAssertionError); + () async => {await _context!.setLocale(l)}, throwsAssertionError); l = Locale('ar', 'DZ'); - await _context.setLocale(l); + await _context!.setLocale(l); await tester.idle(); await tester.pumpAndSettle(); - expect(_context.locale, l); + expect(_context!.locale, l); }); }, ); @@ -160,20 +160,20 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - await _context.setLocale(Locale('ar', 'DZ')); + await _context!.setLocale(Locale('ar', 'DZ')); await tester.pumpAndSettle(); - expect(_context.supportedLocales, + expect(_context!.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(_context.locale, Locale('ar', 'DZ')); + expect(_context!.locale, Locale('ar', 'DZ')); var trFinder = find.text('اختبار'); expect(trFinder, findsOneWidget); var pluralFinder = find.text('1 يوم'); expect(pluralFinder, findsOneWidget); - expect(Localization.of(_context), isInstanceOf()); + expect(Localization.of(_context!), isInstanceOf()); expect(tr('test', context: _context), 'اختبار'); expect(plural('day', 1, context: _context), '1 يوم'); expect(plural('day', 2, context: _context), '2 أيام'); @@ -202,9 +202,9 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(_context.supportedLocales, [Locale('ar')]); - expect(_context.locale, Locale('ar')); - expect(_context.fallbackLocale, Locale('ar')); + expect(_context!.supportedLocales, [Locale('ar')]); + expect(_context!.locale, Locale('ar')); + expect(_context!.fallbackLocale, Locale('ar')); }); }, ); @@ -227,9 +227,9 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(_context.supportedLocales, [Locale('ar')]); - expect(_context.locale, Locale('ar')); - expect(_context.fallbackLocale, null); + expect(_context!.supportedLocales, [Locale('ar')]); + expect(_context!.locale, Locale('ar')); + expect(_context!.fallbackLocale, null); }); }, ); @@ -258,8 +258,8 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(_context.locale, Locale('ar', 'DZ')); - await _context.deleteSaveLocale(); + expect(_context!.locale, Locale('ar', 'DZ')); + await _context!.deleteSaveLocale(); }); }, ); @@ -281,7 +281,7 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(_context.locale, Locale('en', 'US')); + expect(_context!.locale, Locale('en', 'US')); }); }, ); @@ -302,7 +302,7 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(_context.deviceLocale.toString(), Platform.localeName); + expect(_context!.deviceLocale.toString(), Platform.localeName); }); }, ); @@ -324,11 +324,11 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(_context.locale, Locale('ar', 'DZ')); + expect(_context!.locale, Locale('ar', 'DZ')); // reset to device locale - await _context.resetLocale(); + await _context!.resetLocale(); await tester.pumpAndSettle(); - expect(_context.locale, Locale('en', 'US')); + expect(_context!.locale, Locale('en', 'US')); }); }, ); diff --git a/test/easy_localization_widget_test.dart b/test/easy_localization_widget_test.dart index b018c9b1..92cbe2d8 100644 --- a/test/easy_localization_widget_test.dart +++ b/test/easy_localization_widget_test.dart @@ -9,15 +9,15 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'utils/test_asset_loaders.dart'; -BuildContext _context; +BuildContext? _context; class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - locale: EasyLocalization.of(context).locale, - supportedLocales: EasyLocalization.of(context).supportedLocales, - localizationsDelegates: EasyLocalization.of(context).delegates, + locale: EasyLocalization.of(context)!.locale, + supportedLocales: EasyLocalization.of(context)!.supportedLocales, + localizationsDelegates: EasyLocalization.of(context)!.delegates, home: MyWidget(), ); } @@ -61,12 +61,12 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(Localization.of(_context), isInstanceOf()); + expect(Localization.of(_context!), isInstanceOf()); expect(Localization.instance, isInstanceOf()); - expect(Localization.instance, Localization.of(_context)); - expect(EasyLocalization.of(_context).supportedLocales, + expect(Localization.instance, Localization.of(_context!)); + expect(EasyLocalization.of(_context!)!.supportedLocales, [Locale('en', 'US')]); - expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); final trFinder = find.text('test'); expect(trFinder, findsOneWidget); @@ -84,23 +84,23 @@ void main() async { }, ); - testWidgets( - '[EasyLocalization with child==null AssertionError] test', - (WidgetTester tester) async { - await tester.runAsync(() async { - try { - await tester.pumpWidget(EasyLocalization( - child: null, - path: 'i18n', - supportedLocales: [Locale('en', 'US')], - )); - } on AssertionError catch (e) { - // throw AssertionError('Expected ArgumentError'); - expect(e, isAssertionError); - } - }); - }, - ); + // testWidgets( + // '[EasyLocalization with child==null AssertionError] test', + // (WidgetTester tester) async { + // await tester.runAsync(() async { + // try { + // await tester.pumpWidget(EasyLocalization( + // child: null, + // path: 'i18n', + // supportedLocales: [Locale('en', 'US')], + // )); + // } on AssertionError catch (e) { + // // throw AssertionError('Expected ArgumentError'); + // expect(e, isAssertionError); + // } + // }); + // }, + // ); testWidgets( '[EasyLocalization with RootBundleAssetLoader] test', @@ -116,9 +116,9 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, + expect(EasyLocalization.of(_context!)!.supportedLocales, [Locale('en', 'US')]); - expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); final trFinder = find.text('test'); expect(trFinder, findsOneWidget); @@ -145,9 +145,9 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, + expect(EasyLocalization.of(_context!)!.supportedLocales, [Locale('en', 'US')]); - expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); final trFinder = find.text('test'); expect(trFinder, findsOneWidget); @@ -193,14 +193,14 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, + expect(EasyLocalization.of(_context!)!.supportedLocales, [Locale('en', 'US')]); - expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); var l = Locale('en', 'US'); - await EasyLocalization.of(_context).setLocale(l); + await EasyLocalization.of(_context!)!.setLocale(l); await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); final trFinder = find.text('test'); expect(trFinder, findsOneWidget); @@ -211,14 +211,14 @@ void main() async { expect(plural('day', 1, context: _context), '1 day'); expect(plural('day', 2, context: _context), '2 days'); expect(plural('day', 3, context: _context), '3 other days'); - expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); l = Locale('ar', 'DZ'); expect(() async { - await EasyLocalization.of(_context).setLocale(l); + await EasyLocalization.of(_context!)!.setLocale(l); }, throwsAssertionError); await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); }); }, ); @@ -236,10 +236,10 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(Localization.of(_context), isInstanceOf()); - expect(EasyLocalization.of(_context).supportedLocales, + expect(Localization.of(_context!), isInstanceOf()); + expect(EasyLocalization.of(_context!)!.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); var trFinder = find.text('test'); expect(trFinder, findsOneWidget); @@ -252,31 +252,31 @@ void main() async { expect(plural('day', 3, context: _context), '3 other days'); var l = Locale('en', 'US'); - await EasyLocalization.of(_context).setLocale(l); + await EasyLocalization.of(_context!)!.setLocale(l); await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).locale, l); + expect(EasyLocalization.of(_context!)!.locale, l); l = Locale('ar', 'DZ'); - await EasyLocalization.of(_context).setLocale(l); + await EasyLocalization.of(_context!)!.setLocale(l); await tester.idle(); await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).locale, l); + expect(EasyLocalization.of(_context!)!.locale, l); l = Locale('en', 'US'); - await EasyLocalization.of(_context).setLocale(l); + await EasyLocalization.of(_context!)!.setLocale(l); await tester.idle(); await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).locale, l); + expect(EasyLocalization.of(_context!)!.locale, l); l = Locale('en', 'UK'); - expect(() async => {await EasyLocalization.of(_context).setLocale(l)}, + expect(() async => {await EasyLocalization.of(_context!)!.setLocale(l)}, throwsAssertionError); l = Locale('ar', 'DZ'); - await EasyLocalization.of(_context).setLocale(l); + await EasyLocalization.of(_context!)!.setLocale(l); await tester.idle(); await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).locale, l); + expect(EasyLocalization.of(_context!)!.locale, l); }); }, ); @@ -295,20 +295,20 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - await EasyLocalization.of(_context).setLocale(Locale('ar', 'DZ')); + await EasyLocalization.of(_context!)!.setLocale(Locale('ar', 'DZ')); await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, + expect(EasyLocalization.of(_context!)!.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(EasyLocalization.of(_context).locale, Locale('ar', 'DZ')); + expect(EasyLocalization.of(_context!)!.locale, Locale('ar', 'DZ')); var trFinder = find.text('اختبار'); expect(trFinder, findsOneWidget); var pluralFinder = find.text('1 يوم'); expect(pluralFinder, findsOneWidget); - expect(Localization.of(_context), isInstanceOf()); + expect(Localization.of(_context!), isInstanceOf()); expect(tr('test', context: _context), 'اختبار'); expect(plural('day', 1, context: _context), '1 يوم'); expect(plural('day', 2, context: _context), '2 أيام'); @@ -339,13 +339,13 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, + expect(EasyLocalization.of(_context!)!.supportedLocales, [Locale('en'), Locale('ar')]); - expect(EasyLocalization.of(_context).locale, Locale('en')); + expect(EasyLocalization.of(_context!)!.locale, Locale('en')); var l = Locale('en'); - await EasyLocalization.of(_context).setLocale(l); - expect(EasyLocalization.of(_context).locale, l); + await EasyLocalization.of(_context!)!.setLocale(l); + expect(EasyLocalization.of(_context!)!.locale, l); }); }, ); @@ -368,13 +368,13 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, + expect(EasyLocalization.of(_context!)!.supportedLocales, [Locale('en'), Locale('ar')]); - expect(EasyLocalization.of(_context).locale, Locale('en')); + expect(EasyLocalization.of(_context!)!.locale, Locale('en')); var l = Locale('en'); - await EasyLocalization.of(_context).setLocale(l); - expect(EasyLocalization.of(_context).locale, l); + await EasyLocalization.of(_context!)!.setLocale(l); + expect(EasyLocalization.of(_context!)!.locale, l); }); }, ); @@ -395,9 +395,10 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('ar')]); - expect(EasyLocalization.of(_context).locale, Locale('ar')); - expect(EasyLocalization.of(_context).fallbackLocale, Locale('ar')); + expect( + EasyLocalization.of(_context!)!.supportedLocales, [Locale('ar')]); + expect(EasyLocalization.of(_context!)!.locale, Locale('ar')); + expect(EasyLocalization.of(_context!)!.fallbackLocale, Locale('ar')); }); }, ); @@ -420,9 +421,10 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, [Locale('ar')]); - expect(EasyLocalization.of(_context).locale, Locale('ar')); - expect(EasyLocalization.of(_context).fallbackLocale, null); + expect( + EasyLocalization.of(_context!)!.supportedLocales, [Locale('ar')]); + expect(EasyLocalization.of(_context!)!.locale, Locale('ar')); + expect(EasyLocalization.of(_context!)!.fallbackLocale, null); }); }, ); @@ -430,7 +432,7 @@ void main() async { group('SharedPreferences SavedLocale NULL', () { setUp(() { SharedPreferences.setMockInitialValues({ - 'locale': null, + 'locale': '', }); }); @@ -449,10 +451,10 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, + expect(EasyLocalization.of(_context!)!.supportedLocales, [Locale('en'), Locale('ar')]); - expect(EasyLocalization.of(_context).locale, Locale('en')); - expect(EasyLocalization.of(_context).fallbackLocale, null); + expect(EasyLocalization.of(_context!)!.locale, Locale('en')); + expect(EasyLocalization.of(_context!)!.fallbackLocale, null); }); }, ); @@ -471,10 +473,10 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, + expect(EasyLocalization.of(_context!)!.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); - expect(EasyLocalization.of(_context).fallbackLocale, null); + expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context!)!.fallbackLocale, null); }); }, ); @@ -494,10 +496,10 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, + expect(EasyLocalization.of(_context!)!.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(EasyLocalization.of(_context).locale, Locale('ar', 'DZ')); - expect(EasyLocalization.of(_context).fallbackLocale, null); + expect(EasyLocalization.of(_context!)!.locale, Locale('ar', 'DZ')); + expect(EasyLocalization.of(_context!)!.fallbackLocale, null); }); }, ); @@ -530,10 +532,10 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, + expect(EasyLocalization.of(_context!)!.supportedLocales, [Locale('en'), Locale('ar')]); - expect(EasyLocalization.of(_context).locale, Locale('ar')); - expect(EasyLocalization.of(_context).fallbackLocale, null); + expect(EasyLocalization.of(_context!)!.locale, Locale('ar')); + expect(EasyLocalization.of(_context!)!.fallbackLocale, null); }); }, ); @@ -565,10 +567,10 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, + expect(EasyLocalization.of(_context!)!.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(EasyLocalization.of(_context).locale, Locale('ar', 'DZ')); - expect(EasyLocalization.of(_context).fallbackLocale, null); + expect(EasyLocalization.of(_context!)!.locale, Locale('ar', 'DZ')); + expect(EasyLocalization.of(_context!)!.fallbackLocale, null); }); }, ); @@ -591,11 +593,11 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).supportedLocales, + expect(EasyLocalization.of(_context!)!.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); - await EasyLocalization.of(_context).setLocale(Locale('en', 'US')); + await EasyLocalization.of(_context!)!.setLocale(Locale('en', 'US')); }); }, ); @@ -624,8 +626,8 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).locale, Locale('ar', 'DZ')); - await EasyLocalization.of(_context).deleteSaveLocale(); + expect(EasyLocalization.of(_context!)!.locale, Locale('ar', 'DZ')); + await EasyLocalization.of(_context!)!.deleteSaveLocale(); }); }, ); @@ -647,7 +649,7 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); }); }, ); @@ -668,7 +670,7 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).deviceLocale.toString(), + expect(EasyLocalization.of(_context!)!.deviceLocale.toString(), Platform.localeName); }); }, @@ -691,11 +693,11 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).locale, Locale('ar', 'DZ')); + expect(EasyLocalization.of(_context!)!.locale, Locale('ar', 'DZ')); // reset to device locale - await _context.resetLocale(); + await _context!.resetLocale(); await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context).locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); }); }, ); From 243f8cfeb541b6c798c8bc599847a39199bd1ae7 Mon Sep 17 00:00:00 2001 From: xurei Date: Tue, 16 Feb 2021 15:01:24 +0100 Subject: [PATCH 33/52] [Null-Safety] Fallback translations support (#333) --- README.md | 25 +++++++------ lib/src/easy_localization_app.dart | 13 ++++++- lib/src/easy_localization_controller.dart | 45 +++++++++++++++-------- lib/src/localization.dart | 24 +++++++----- test/easy_localization_test.dart | 32 ++++++++++++++-- test/utils/test_asset_loaders.dart | 3 +- 6 files changed, 99 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 58f42dbb..9336624c 100644 --- a/README.md +++ b/README.md @@ -130,18 +130,19 @@ class MyApp extends StatelessWidget { ### 📜 Easy localization widget properties -| Properties | Required | Default | Description | -| ---------------- | -------- | ------------------------- | ----------- | -| key | false | | Widget key. | -| child | true | | Place for your main page widget. | -| supportedLocales | true | | List of supported locales. | -| path | true | | Path to your folder with localization files. | -| assetLoader | false | `RootBundleAssetLoader()` | Class loader for localization files. You can use custom loaders from [Easy Localization Loader](https://github.com/aissat/easy_localization_loader) or create your own class. | -| fallbackLocale | false | | Returns the locale when the locale is not in the list `supportedLocales`.| -| startLocale | false | | Overrides device locale. | -| saveLocale | false | `true` | Save locale in device storage. | -| useOnlyLangCode | false | `false` | Trigger for using only language code for reading localization files.

Example:
`en.json //useOnlyLangCode: true`
`en-US.json //useOnlyLangCode: false` | -| errorWidget | false | `FutureErrorWidget()` | Shows a custom error widget when an error occurs. | +| Properties | Required | Default | Description | +| ----------------------- | -------- | ------------------------- | ----------- | +| key | false | | Widget key. | +| child | true | | Place for your main page widget. | +| supportedLocales | true | | List of supported locales. | +| path | true | | Path to your folder with localization files. | +| assetLoader | false | `RootBundleAssetLoader()` | Class loader for localization files. You can use custom loaders from [Easy Localization Loader](https://github.com/aissat/easy_localization_loader) or create your own class. | +| fallbackLocale | false | | Returns the locale when the locale is not in the list `supportedLocales`.| +| startLocale | false | | Overrides device locale. | +| saveLocale | false | `true` | Save locale in device storage. | +| useFallbackTranslations | false | `false` | If a localization key is not found in the locale file, try to use the fallbackLocale file. | +| useOnlyLangCode | false | `false` | Trigger for using only language code for reading localization files.

Example:
`en.json //useOnlyLangCode: true`
`en-US.json //useOnlyLangCode: false` | +| errorWidget | false | `FutureErrorWidget()` | Shows a custom error widget when an error occurs. | ## Usage diff --git a/lib/src/easy_localization_app.dart b/lib/src/easy_localization_app.dart index 1a6edb0a..ec5a9710 100644 --- a/lib/src/easy_localization_app.dart +++ b/lib/src/easy_localization_app.dart @@ -46,6 +46,14 @@ class EasyLocalization extends StatefulWidget { /// ``` final bool useOnlyLangCode; + /// If a localization key is not found in the locale file, try to use the fallbackLocale file. + /// @Default value false + /// Example: + /// ``` + /// useFallbackTranslations: true + /// ``` + final bool useFallbackTranslations; + /// Path to your folder with localization files. /// Example: /// ```dart @@ -75,6 +83,7 @@ class EasyLocalization extends StatefulWidget { this.fallbackLocale, this.startLocale, this.useOnlyLangCode = false, + this.useFallbackTranslations = false, this.assetLoader = const RootBundleAssetLoader(), this.saveLocale = true, this.errorWidget, @@ -115,6 +124,7 @@ class _EasyLocalizationState extends State { startLocale: widget.startLocale, assetLoader: widget.assetLoader, useOnlyLangCode: widget.useOnlyLangCode, + useFallbackTranslations: widget.useFallbackTranslations, path: widget.path, onLoadError: (FlutterError e) { setState(() { @@ -247,8 +257,7 @@ class _EasyLocalizationDelegate extends LocalizationsDelegate { await localizationController!.loadTranslations(); } - Localization.load(value, - translations: localizationController!.translations); + Localization.load(value, translations: localizationController.translations, fallbackTranslations: localizationController.fallbackTranslations); return Future.value(Localization.instance); } diff --git a/lib/src/easy_localization_controller.dart b/lib/src/easy_localization_controller.dart index 425fb9fd..35026724 100644 --- a/lib/src/easy_localization_controller.dart +++ b/lib/src/easy_localization_controller.dart @@ -10,28 +10,31 @@ class EasyLocalizationController extends ChangeNotifier { static Locale? _savedLocale; static Locale? _deviceLocale; - late Locale _locale; + Locale _locale, _fallbackLocale; final Function(FlutterError e) onLoadError; final assetLoader; final String path; + final bool useFallbackTranslations; final bool saveLocale; final bool useOnlyLangCode; - - Translations? _translations; - Translations? get translations => _translations; + Translations _translations, _fallbackTranslations; + Translations get translations => _translations; + Translations get fallbackTranslations => _fallbackTranslations; EasyLocalizationController({ - required List supportedLocales, - required this.saveLocale, - required this.assetLoader, - required this.path, - required this.useOnlyLangCode, - required this.onLoadError, - Locale? startLocale, - Locale? fallbackLocale, - Locale? forceLocale, // used for testing + @required List supportedLocales, + @required this.useFallbackTranslations, + @required this.saveLocale, + @required this.assetLoader, + @required this.path, + @required this.useOnlyLangCode, + @required this.onLoadError, + Locale startLocale, + Locale fallbackLocale, + Locale forceLocale, // used for testing }) { + _fallbackLocale = fallbackLocale; if (forceLocale != null) { _locale = forceLocale; } else if (_savedLocale == null && startLocale != null) { @@ -73,10 +76,12 @@ class EasyLocalizationController extends ChangeNotifier { Future loadTranslations() async { Map data; try { - useOnlyLangCode - ? data = await assetLoader.load(path, Locale(_locale.languageCode)) - : data = await assetLoader.load(path, _locale); + data = await loadTranslationData(_locale); _translations = Translations(data); + if (useFallbackTranslations && _fallbackLocale != null) { + data = await loadTranslationData(_fallbackLocale); + _fallbackTranslations = Translations(data); + } } on FlutterError catch (e) { onLoadError(e); } catch (e) { @@ -84,6 +89,14 @@ class EasyLocalizationController extends ChangeNotifier { } } + Future loadTranslationData(Locale locale) async { + if (useOnlyLangCode) { + return assetLoader.load(path, Locale(locale.languageCode)); + } else { + return assetLoader.load(path, locale); + } + } + Locale get locale => _locale; Future setLocale(Locale l) async { _locale = l; diff --git a/lib/src/localization.dart b/lib/src/localization.dart index b68c45fa..546d226c 100644 --- a/lib/src/localization.dart +++ b/lib/src/localization.dart @@ -6,9 +6,8 @@ import 'package:intl/intl.dart'; import 'translations.dart'; class Localization { - Translations? _translations; - late Locale _locale; - set translations(val) => _translations = val; + Translations _translations, _fallbackTranslations; + Locale _locale; String? path; bool? useOnlyLangCode; @@ -30,9 +29,10 @@ class Localization { static Localization? of(BuildContext context) => Localizations.of(context, Localization); - static bool load(Locale locale, {Translations? translations}) { + static bool load(Locale locale, {Translations translations, Translations fallbackTranslations}) { instance._locale = locale; instance._translations = translations; + instance._fallbackTranslations = fallbackTranslations; return translations == null ? false : true; } @@ -134,13 +134,19 @@ class Localization { } } - String? _resolve(String? key, {bool logging = true}) { - final resource = _translations!.get(key); + String _resolve(String key, {bool logging = true}) { + var resource = _translations.get(key); if (resource == null) { - if (logging) { - EasyLocalization.logger.warning('Localization key [$key] not found'); + if (logging) EasyLocalization.logger.warning('Localization key [$key] not found'); + if (_fallbackTranslations == null) { + return key; + } else { + resource = _fallbackTranslations.get(key); + if (resource == null) { + if (logging) EasyLocalization.logger.warning('Fallback localization key [$key] not found'); + return key; + } } - return key; } return resource; } diff --git a/test/easy_localization_test.dart b/test/easy_localization_test.dart index 7fd8d4ba..b67878c8 100644 --- a/test/easy_localization_test.dart +++ b/test/easy_localization_test.dart @@ -28,6 +28,7 @@ void main() { path: 'path/en.json', supportedLocales: [Locale('en')], useOnlyLangCode: true, + useFallbackTranslations: false, saveLocale: false, onLoadError: (FlutterError e) { log(e.toString()); @@ -38,6 +39,7 @@ void main() { supportedLocales: [Locale('en', 'us')], path: 'path/en-us.json', useOnlyLangCode: false, + useFallbackTranslations: false, onLoadError: (FlutterError e) { log(e.toString()); }, @@ -69,6 +71,11 @@ void main() { Localization.load(Locale('en'), translations: r1.translations), true); }); + test('load() with fallback succeeds', () async { + expect( + Localization.load(Locale('en'), translations: r1.translations, fallbackTranslations: r2.translations), true); + }); + test('localeFromString() succeeds', () async { expect(Locale('ar'), 'ar'.toLocale()); expect(Locale('ar', 'DZ'), 'ar_DZ'.toLocale()); @@ -107,9 +114,11 @@ void main() { group('tr', () { var r = EasyLocalizationController( forceLocale: Locale('en'), - supportedLocales: [Locale('en')], + supportedLocales: [Locale('en'), Locale('fb')], + fallbackLocale: Locale('fb'), path: 'path', useOnlyLangCode: true, + useFallbackTranslations: true, onLoadError: (FlutterError e) { log(e.toString()); }, @@ -118,7 +127,7 @@ void main() { setUpAll(() async { await r.loadTranslations(); - Localization.load(Locale('en'), translations: r.translations); + Localization.load(Locale('en'), translations: r.translations, fallbackTranslations: r.fallbackTranslations); }); test('finds and returns resource', () { expect(Localization.instance.tr('test'), 'test'); @@ -180,8 +189,25 @@ void main() { test('reports missing resource', overridePrint(() { printLog = []; expect(Localization.instance.tr('test_missing'), 'test_missing'); - expect(printLog.first, + final logIterator = printLog.iterator; + logIterator.moveNext(); + expect(logIterator.current, contains('Localization key [test_missing] not found')); + logIterator.moveNext(); + expect(logIterator.current, + contains('Fallback localization key [test_missing] not found')); + })); + + test('uses fallback translations', overridePrint(() { + printLog = []; + expect(Localization.instance.tr('test_missing_fallback'), 'fallback!'); + })); + + test('reports missing resource with fallback', overridePrint(() { + printLog = []; + expect(Localization.instance.tr('test_missing_fallback'), 'fallback!'); + expect(printLog.first, + contains('Localization key [test_missing_fallback] not found')); })); test('returns resource and replaces argument', () { diff --git a/test/utils/test_asset_loaders.dart b/test/utils/test_asset_loaders.dart index 9afdbdcb..804e4117 100644 --- a/test/utils/test_asset_loaders.dart +++ b/test/utils/test_asset_loaders.dart @@ -55,7 +55,8 @@ class JsonAssetLoader extends AssetLoader { } } }, - 'path': '$fullPath' + 'path': '$fullPath', + 'test_missing_fallback': (locale.languageCode == 'fb' ? 'fallback!' : null), }); } } From 788b9ffececa2ed7a21513ccd0fee902c61ae45c Mon Sep 17 00:00:00 2001 From: aissat Date: Wed, 17 Feb 2021 00:17:31 +0100 Subject: [PATCH 34/52] addded plural_rules and clean code --- lib/src/easy_localization_app.dart | 2 +- lib/src/easy_localization_controller.dart | 31 +- lib/src/localization.dart | 101 ++-- lib/src/plural_rules.dart | 560 ++++++++++++++++++++++ lib/src/public.dart | 4 +- lib/src/public_ext.dart | 4 +- lib/src/translations.dart | 24 +- 7 files changed, 660 insertions(+), 66 deletions(-) create mode 100644 lib/src/plural_rules.dart diff --git a/lib/src/easy_localization_app.dart b/lib/src/easy_localization_app.dart index ec5a9710..1a369f26 100644 --- a/lib/src/easy_localization_app.dart +++ b/lib/src/easy_localization_app.dart @@ -257,7 +257,7 @@ class _EasyLocalizationDelegate extends LocalizationsDelegate { await localizationController!.loadTranslations(); } - Localization.load(value, translations: localizationController.translations, fallbackTranslations: localizationController.fallbackTranslations); + Localization.load(value, translations: localizationController!.translations, fallbackTranslations: localizationController!.fallbackTranslations); return Future.value(Localization.instance); } diff --git a/lib/src/easy_localization_controller.dart b/lib/src/easy_localization_controller.dart index 35026724..c26dc87f 100644 --- a/lib/src/easy_localization_controller.dart +++ b/lib/src/easy_localization_controller.dart @@ -10,7 +10,8 @@ class EasyLocalizationController extends ChangeNotifier { static Locale? _savedLocale; static Locale? _deviceLocale; - Locale _locale, _fallbackLocale; + late Locale _locale; + Locale? _fallbackLocale; final Function(FlutterError e) onLoadError; final assetLoader; @@ -18,21 +19,21 @@ class EasyLocalizationController extends ChangeNotifier { final bool useFallbackTranslations; final bool saveLocale; final bool useOnlyLangCode; - Translations _translations, _fallbackTranslations; - Translations get translations => _translations; - Translations get fallbackTranslations => _fallbackTranslations; + Translations? _translations, _fallbackTranslations; + Translations? get translations => _translations; + Translations? get fallbackTranslations => _fallbackTranslations; EasyLocalizationController({ - @required List supportedLocales, - @required this.useFallbackTranslations, - @required this.saveLocale, - @required this.assetLoader, - @required this.path, - @required this.useOnlyLangCode, - @required this.onLoadError, - Locale startLocale, - Locale fallbackLocale, - Locale forceLocale, // used for testing + required List supportedLocales, + required this.useFallbackTranslations, + required this.saveLocale, + required this.assetLoader, + required this.path, + required this.useOnlyLangCode, + required this.onLoadError, + Locale? startLocale, + Locale? fallbackLocale, + Locale? forceLocale, // used for testing }) { _fallbackLocale = fallbackLocale; if (forceLocale != null) { @@ -79,7 +80,7 @@ class EasyLocalizationController extends ChangeNotifier { data = await loadTranslationData(_locale); _translations = Translations(data); if (useFallbackTranslations && _fallbackLocale != null) { - data = await loadTranslationData(_fallbackLocale); + data = await loadTranslationData(_fallbackLocale!); _fallbackTranslations = Translations(data); } } on FlutterError catch (e) { diff --git a/lib/src/localization.dart b/lib/src/localization.dart index 546d226c..7cd90ade 100644 --- a/lib/src/localization.dart +++ b/lib/src/localization.dart @@ -3,11 +3,12 @@ import 'dart:ui'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/widgets.dart'; import 'package:intl/intl.dart'; +import 'plural_rules.dart'; import 'translations.dart'; class Localization { - Translations _translations, _fallbackTranslations; - Locale _locale; + Translations? _translations, _fallbackTranslations; + late Locale _locale; String? path; bool? useOnlyLangCode; @@ -29,24 +30,24 @@ class Localization { static Localization? of(BuildContext context) => Localizations.of(context, Localization); - static bool load(Locale locale, {Translations translations, Translations fallbackTranslations}) { + static bool load(Locale locale, {Translations? translations, Translations? fallbackTranslations}) { instance._locale = locale; instance._translations = translations; instance._fallbackTranslations = fallbackTranslations; return translations == null ? false : true; } - String? tr(String? key, + String tr(String key, {List? args, Map? namedArgs, String? gender}) { String? res; if (gender != null) { - res = _gender(key!, gender: gender); + res = _gender(key, gender: gender); } else { res = _resolve(key); } - res = _replaceLinks(res!); + res = _replaceLinks(res); res = _replaceNamedArgs(res, namedArgs); @@ -82,15 +83,15 @@ class Localization { } result = - translated!.isEmpty ? result : result.replaceAll(link, translated); + translated.isEmpty ? result : result.replaceAll(link, translated); } return result; } - String? _replaceArgs(String? res, List? args) { + String _replaceArgs(String res, List? args) { if (args == null || args.isEmpty) return res; - args.forEach((String str) => res = res!.replaceFirst(_replaceArgRegex, str)); + args.forEach((String str) => res = res.replaceFirst(_replaceArgRegex, str)); return res; } @@ -101,47 +102,74 @@ class Localization { return res; } - String? plural(String? key, num value, + static PluralRule? _pluralRule(String? locale, num howMany){ + startRuleEvaluation(howMany); + return pluralRules[locale] ; + } + + String? plural(String key, num value, {List? args, NumberFormat? format}) { - final res = Intl.pluralLogic(value, - zero: _resolvePlural(key, 'zero'), - one: _resolvePlural(key, 'one'), - two: _resolvePlural(key, 'two'), - few: _resolvePlural(key, 'few'), - many: _resolvePlural(key, 'many'), - other: _resolvePlural(key, 'other'), - locale: _locale.languageCode); + late var pluralCase; + late var res; + var pluralRule = _pluralRule(_locale.languageCode,value); + switch (value) { + case 0: + pluralCase = PluralCase.ZERO ; + break; + case 1: + pluralCase = PluralCase.ONE ; + break; + case 2: + pluralCase = PluralCase.TWO; + break; + default: + pluralCase = pluralRule!(); + } + switch (pluralCase) { + case PluralCase.ZERO: + res= _resolvePlural(key, 'zero'); + break; + case PluralCase.ONE: + res= _resolvePlural(key, 'one'); + break; + case PluralCase.TWO: + res= _resolvePlural(key, 'two'); + break; + case PluralCase.FEW: + res= _resolvePlural(key, 'few'); + break; + case PluralCase.MANY: + res= _resolvePlural(key, 'many'); + break; + case PluralCase.OTHER: + res= _resolvePlural(key, 'other'); + break; + default: + throw ArgumentError.value( + value, 'howMany', 'Invalid plural argument'); + } + return _replaceArgs( res, args ?? [format == null ? '$value' : format.format(value)]); } - String? _gender(String key, {required String gender}) => Intl.genderLogic( - gender, - female: _resolve(key + '.female'), - male: _resolve(key + '.male'), - other: _resolve(key + '.other', logging: false), - locale: _locale.languageCode, - ); - - String? _resolvePlural(String? key, String subKey) { - final resource = _translations!.get('$key.$subKey'); + String _gender(String key, {required String gender}) { + return _resolve(key + '.$gender'); + } - if (resource == null && subKey == 'other') { - EasyLocalization.logger.error('Plural key [$key.$subKey] required'); - return '$key.$subKey'; - } else { - return resource; - } + String _resolvePlural(String key, String subKey) { + var resource = _resolve('$key.$subKey'); + return resource; } String _resolve(String key, {bool logging = true}) { - var resource = _translations.get(key); + var resource = _translations!.get(key); if (resource == null) { if (logging) EasyLocalization.logger.warning('Localization key [$key] not found'); if (_fallbackTranslations == null) { return key; } else { - resource = _fallbackTranslations.get(key); + resource = _fallbackTranslations!.get(key); if (resource == null) { if (logging) EasyLocalization.logger.warning('Fallback localization key [$key] not found'); return key; @@ -150,4 +178,5 @@ class Localization { } return resource; } + } diff --git a/lib/src/plural_rules.dart b/lib/src/plural_rules.dart new file mode 100644 index 00000000..b838d097 --- /dev/null +++ b/lib/src/plural_rules.dart @@ -0,0 +1,560 @@ +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +/// Provides locale-specific plural rules. Based on pluralrules.js from Closure. +/// +/// Each function does the calculation for one or more locales. These are done in terms of +/// various values used by the CLDR syntax and defined by UTS #35 +/// http://unicode.org/reports/tr35/tr35-numbers.html#Plural_rules_syntax +/// +/// * n - absolute value of the source number (integer and decimals). +/// * i - integer digits of n. +/// * v - number of visible fraction digits in n, with trailing zeros. +/// * w - number of visible fraction digits in n, without trailing zeros. +/// * f - visible fractional digits in n, with trailing zeros. +/// * t - visible fractional digits in n, without trailing zeros. + +// Suppress naming issues as changing them might be breaking. +// ignore_for_file: constant_identifier_names, non_constant_identifier_names + +import 'dart:math' as math; + +typedef PluralRule = PluralCase Function(); + +/// The possible cases used in a plural rule. +enum PluralCase { ZERO, ONE, TWO, FEW, MANY, OTHER } + +/// The default rule in case we don't have anything more specific for a locale. +PluralCase _default_rule() => OTHER; + +/// This must be called before evaluating a new rule, because we're using +/// library-global state to both keep the rules terse and minimize space. +void startRuleEvaluation(num howMany, [int? precision = 0]) { + _n = howMany; + _precision = precision; + _i = _n.round(); + _updateVF(_n); + _updateWT(_f, _v); +} + +/// The number whose [PluralCase] we are trying to find. +/// +// This is library-global state, along with the other variables. This allows us +// to avoid calculating parameters that the functions don't need and also +// not introduce a subclass per locale or have instance tear-offs which +// we can't cache. This is fine as long as these methods aren't async, which +// they should never be. +num _n = 0; + +/// The integer part of [_n] +int _i = 0; +int? _precision; + +/// Returns the number of digits in the fractional part of a number +/// (3.1416 => 4) +/// +/// Takes the item count [n] and uses [_precision]. +/// That's because a just looking at the value of a number is not enough to +/// decide the plural form. For example "1 dollar" vs "1.00 dollars", the +/// value is 1, but how it is formatted also matters. +int _decimals(num n) { + var str = _precision == null ? '$n' : n.toStringAsFixed(_precision!); + var result = str.indexOf('.'); + return (result == -1) ? 0 : str.length - result - 1; +} + +/// Calculates and sets the _v and _f as per CLDR plural rules. +/// +/// The short names for parameters / return match the CLDR syntax and UTS #35 +/// (https://unicode.org/reports/tr35/tr35-numbers.html#Plural_rules_syntax) +/// Takes the item count [n] and a [precision]. +void _updateVF(num n) { + var defaultDigits = 3; + + _v = _precision ?? math.min(_decimals(n), defaultDigits); + + var base = math.pow(10, _v) as int; + _f = (n * base).floor() % base; +} + +/// Calculates and sets _w and _t as per CLDR plural rules. +/// +/// The short names for parameters / return match the CLDR syntax and UTS #35 +/// (https://unicode.org/reports/tr35/tr35-numbers.html#Plural_rules_syntax) +/// @param v Calculated previously. +/// @param f Calculated previously. +void _updateWT(int v, int f) { + if (f == 0) { + // Unused, for now _w = 0; + _t = 0; + return; + } + + while ((f % 10) == 0) { + f = (f / 10).floor(); + v--; + } + + // Unused, for now _w = v; + _t = f; +} + +/// Number of visible fraction digits. +int _v = 0; + +/// Number of visible fraction digits without trailing zeros. +// Unused, for now int _w = 0; + +/// The visible fraction digits in n, with trailing zeros. +int _f = 0; + +/// The visible fraction digits in n, without trailing zeros. +int _t = 0; + +// An example, for precision n = 3.1415 and precision = 7) +// n : 3.1415 +// str n: 3.1415000 (the "formatted" n, 7 fractional digits) +// i : 3 (the integer part of n) +// f : 1415000 (the fractional part of n) +// v : 7 (how many digits in f) +// t : 1415 (f, without trailing 0s) +// w : 4 (how many digits in t) + +PluralCase get ZERO => PluralCase.ZERO; +PluralCase get ONE => PluralCase.ONE; +PluralCase get TWO => PluralCase.TWO; +PluralCase get FEW => PluralCase.FEW; +PluralCase get MANY => PluralCase.MANY; +PluralCase get OTHER => PluralCase.OTHER; + +PluralCase _fil_rule() { + if (_v == 0 && (_i == 1 || _i == 2 || _i == 3) || + _v == 0 && _i % 10 != 4 && _i % 10 != 6 && _i % 10 != 9 || + _v != 0 && _f % 10 != 4 && _f % 10 != 6 && _f % 10 != 9) { + return ONE; + } + return OTHER; +} + +PluralCase _pt_PT_rule() { + if (_n == 1 && _v == 0) { + return ONE; + } + return OTHER; +} + +PluralCase _br_rule() { + if (_n % 10 == 1 && _n % 100 != 11 && _n % 100 != 71 && _n % 100 != 91) { + return ONE; + } + if (_n % 10 == 2 && _n % 100 != 12 && _n % 100 != 72 && _n % 100 != 92) { + return TWO; + } + if ((_n % 10 >= 3 && _n % 10 <= 4 || _n % 10 == 9) && + (_n % 100 < 10 || _n % 100 > 19) && + (_n % 100 < 70 || _n % 100 > 79) && + (_n % 100 < 90 || _n % 100 > 99)) { + return FEW; + } + if (_n != 0 && _n % 1000000 == 0) { + return MANY; + } + return OTHER; +} + +PluralCase _sr_rule() { + if (_v == 0 && _i % 10 == 1 && _i % 100 != 11 || + _f % 10 == 1 && _f % 100 != 11) { + return ONE; + } + if (_v == 0 && + _i % 10 >= 2 && + _i % 10 <= 4 && + (_i % 100 < 12 || _i % 100 > 14) || + _f % 10 >= 2 && _f % 10 <= 4 && (_f % 100 < 12 || _f % 100 > 14)) { + return FEW; + } + return OTHER; +} + +PluralCase _ro_rule() { + if (_i == 1 && _v == 0) { + return ONE; + } + if (_v != 0 || _n == 0 || _n != 1 && _n % 100 >= 1 && _n % 100 <= 19) { + return FEW; + } + return OTHER; +} + +PluralCase _hi_rule() { + if (_i == 0 || _n == 1) { + return ONE; + } + return OTHER; +} + +PluralCase _fr_rule() { + if (_i == 0 || _i == 1) { + return ONE; + } + return OTHER; +} + +PluralCase _cs_rule() { + if (_i == 1 && _v == 0) { + return ONE; + } + if (_i >= 2 && _i <= 4 && _v == 0) { + return FEW; + } + if (_v != 0) { + return MANY; + } + return OTHER; +} + +PluralCase _pl_rule() { + if (_i == 1 && _v == 0) { + return ONE; + } + if (_v == 0 && + _i % 10 >= 2 && + _i % 10 <= 4 && + (_i % 100 < 12 || _i % 100 > 14)) { + return FEW; + } + if (_v == 0 && _i != 1 && _i % 10 >= 0 && _i % 10 <= 1 || + _v == 0 && _i % 10 >= 5 && _i % 10 <= 9 || + _v == 0 && _i % 100 >= 12 && _i % 100 <= 14) { + return MANY; + } + return OTHER; +} + +PluralCase _lv_rule() { + if (_n % 10 == 0 || + _n % 100 >= 11 && _n % 100 <= 19 || + _v == 2 && _f % 100 >= 11 && _f % 100 <= 19) { + return ZERO; + } + if (_n % 10 == 1 && _n % 100 != 11 || + _v == 2 && _f % 10 == 1 && _f % 100 != 11 || + _v != 2 && _f % 10 == 1) { + return ONE; + } + return OTHER; +} + +PluralCase _he_rule() { + if (_i == 1 && _v == 0) { + return ONE; + } + if (_i == 2 && _v == 0) { + return TWO; + } + if (_v == 0 && (_n < 0 || _n > 10) && _n % 10 == 0) { + return MANY; + } + return OTHER; +} + +PluralCase _mt_rule() { + if (_n == 1) { + return ONE; + } + if (_n == 0 || _n % 100 >= 2 && _n % 100 <= 10) { + return FEW; + } + if (_n % 100 >= 11 && _n % 100 <= 19) { + return MANY; + } + return OTHER; +} + +PluralCase _si_rule() { + if ((_n == 0 || _n == 1) || _i == 0 && _f == 1) { + return ONE; + } + return OTHER; +} + +PluralCase _cy_rule() { + if (_n == 0) { + return ZERO; + } + if (_n == 1) { + return ONE; + } + if (_n == 2) { + return TWO; + } + if (_n == 3) { + return FEW; + } + if (_n == 6) { + return MANY; + } + return OTHER; +} + +PluralCase _da_rule() { + if (_n == 1 || _t != 0 && (_i == 0 || _i == 1)) { + return ONE; + } + return OTHER; +} + +PluralCase _ru_rule() { + if (_v == 0 && _i % 10 == 1 && _i % 100 != 11) { + return ONE; + } + if (_v == 0 && + _i % 10 >= 2 && + _i % 10 <= 4 && + (_i % 100 < 12 || _i % 100 > 14)) { + return FEW; + } + if (_v == 0 && _i % 10 == 0 || + _v == 0 && _i % 10 >= 5 && _i % 10 <= 9 || + _v == 0 && _i % 100 >= 11 && _i % 100 <= 14) { + return MANY; + } + return OTHER; +} + +PluralCase _be_rule() { + if (_n % 10 == 1 && _n % 100 != 11) { + return ONE; + } + if (_n % 10 >= 2 && _n % 10 <= 4 && (_n % 100 < 12 || _n % 100 > 14)) { + return FEW; + } + if (_n % 10 == 0 || + _n % 10 >= 5 && _n % 10 <= 9 || + _n % 100 >= 11 && _n % 100 <= 14) { + return MANY; + } + return OTHER; +} + +PluralCase _mk_rule() { + if (_v == 0 && _i % 10 == 1 || _f % 10 == 1) { + return ONE; + } + return OTHER; +} + +PluralCase _ga_rule() { + if (_n == 1) { + return ONE; + } + if (_n == 2) { + return TWO; + } + if (_n >= 3 && _n <= 6) { + return FEW; + } + if (_n >= 7 && _n <= 10) { + return MANY; + } + return OTHER; +} + +PluralCase _pt_rule() { + if (_n >= 0 && _n <= 2 && _n != 2) { + return ONE; + } + return OTHER; +} + +PluralCase _es_rule() { + if (_n == 1) { + return ONE; + } + return OTHER; +} + +PluralCase _is_rule() { + if (_t == 0 && _i % 10 == 1 && _i % 100 != 11 || _t != 0) { + return ONE; + } + return OTHER; +} + +PluralCase _ar_rule() { + if (_n == 0) { + return ZERO; + } + if (_n == 1) { + return ONE; + } + if (_n == 2) { + return TWO; + } + if (_n % 100 >= 3 && _n % 100 <= 10) { + return FEW; + } + if (_n % 100 >= 11 && _n % 100 <= 99) { + return MANY; + } + return OTHER; +} + +PluralCase _sl_rule() { + if (_v == 0 && _i % 100 == 1) { + return ONE; + } + if (_v == 0 && _i % 100 == 2) { + return TWO; + } + if (_v == 0 && _i % 100 >= 3 && _i % 100 <= 4 || _v != 0) { + return FEW; + } + return OTHER; +} + +PluralCase _lt_rule() { + if (_n % 10 == 1 && (_n % 100 < 11 || _n % 100 > 19)) { + return ONE; + } + if (_n % 10 >= 2 && _n % 10 <= 9 && (_n % 100 < 11 || _n % 100 > 19)) { + return FEW; + } + if (_f != 0) { + return MANY; + } + return OTHER; +} + +PluralCase _en_rule() { + if (_i == 1 && _v == 0) { + return ONE; + } + return OTHER; +} + +PluralCase _ak_rule() { + if (_n >= 0 && _n <= 1) { + return ONE; + } + return OTHER; +} + +/// Selected Plural rules by locale. +final pluralRules = { + 'af': _es_rule, + 'am': _hi_rule, + 'ar': _ar_rule, + 'az': _es_rule, + 'be': _be_rule, + 'bg': _es_rule, + 'bn': _hi_rule, + 'br': _br_rule, + 'bs': _sr_rule, + 'ca': _en_rule, + 'chr': _es_rule, + 'cs': _cs_rule, + 'cy': _cy_rule, + 'da': _da_rule, + 'de': _en_rule, + 'de_AT': _en_rule, + 'de_CH': _en_rule, + 'el': _es_rule, + 'en': _en_rule, + 'en_AU': _en_rule, + 'en_CA': _en_rule, + 'en_GB': _en_rule, + 'en_IE': _en_rule, + 'en_IN': _en_rule, + 'en_SG': _en_rule, + 'en_US': _en_rule, + 'en_ZA': _en_rule, + 'es': _es_rule, + 'es_419': _es_rule, + 'es_ES': _es_rule, + 'es_MX': _es_rule, + 'es_US': _es_rule, + 'et': _en_rule, + 'eu': _es_rule, + 'fa': _hi_rule, + 'fi': _en_rule, + 'fil': _fil_rule, + 'fr': _fr_rule, + 'fr_CA': _fr_rule, + 'ga': _ga_rule, + 'gl': _en_rule, + 'gsw': _es_rule, + 'gu': _hi_rule, + 'haw': _es_rule, + 'he': _he_rule, + 'hi': _hi_rule, + 'hr': _sr_rule, + 'hu': _es_rule, + 'hy': _fr_rule, + 'id': _default_rule, + 'in': _default_rule, + 'is': _is_rule, + 'it': _en_rule, + 'iw': _he_rule, + 'ja': _default_rule, + 'ka': _es_rule, + 'kk': _es_rule, + 'km': _default_rule, + 'kn': _hi_rule, + 'ko': _default_rule, + 'ky': _es_rule, + 'ln': _ak_rule, + 'lo': _default_rule, + 'lt': _lt_rule, + 'lv': _lv_rule, + 'mk': _mk_rule, + 'ml': _es_rule, + 'mn': _es_rule, + 'mo': _ro_rule, + 'mr': _hi_rule, + 'ms': _default_rule, + 'mt': _mt_rule, + 'my': _default_rule, + 'nb': _es_rule, + 'ne': _es_rule, + 'nl': _en_rule, + 'no': _es_rule, + 'no_NO': _es_rule, + 'or': _es_rule, + 'pa': _ak_rule, + 'pl': _pl_rule, + 'pt': _pt_rule, + 'pt_BR': _pt_rule, + 'pt_PT': _pt_PT_rule, + 'ro': _ro_rule, + 'ru': _ru_rule, + 'sh': _sr_rule, + 'si': _si_rule, + 'sk': _cs_rule, + 'sl': _sl_rule, + 'sq': _es_rule, + 'sr': _sr_rule, + 'sr_Latn': _sr_rule, + 'sv': _en_rule, + 'sw': _en_rule, + 'ta': _es_rule, + 'te': _es_rule, + 'th': _default_rule, + 'tl': _fil_rule, + 'tr': _es_rule, + 'uk': _ru_rule, + 'ur': _en_rule, + 'uz': _es_rule, + 'vi': _default_rule, + 'zh': _default_rule, + 'zh_CN': _default_rule, + 'zh_HK': _default_rule, + 'zh_TW': _default_rule, + 'zu': _hi_rule, + 'default': _default_rule +}; + +/// Do we have plural rules specific to [locale] +bool localeHasPluralRules(String locale) => pluralRules.containsKey(locale); diff --git a/lib/src/public.dart b/lib/src/public.dart index 1d30282c..159f1df3 100644 --- a/lib/src/public.dart +++ b/lib/src/public.dart @@ -31,7 +31,7 @@ import 'localization.dart'; /// Text('gender').tr(gender: _gender ? "female" : "male"), // gender /// ``` /// {@endtemplate} -String? tr(String? key, +String? tr(String key, {BuildContext? context, List? args, Map? namedArgs, @@ -83,7 +83,7 @@ String? tr(String? key, /// var money = plural('money_args', 10.23, args: ['John', '10.23']) // output: John has 10.23 dollars /// ``` /// {@endtemplate} -String? plural(String? key, num value, +String? plural(String key, num value, {BuildContext? context, List? args, NumberFormat? format}) { return context == null ? Localization.instance.plural(key, value, args: args, format: format) diff --git a/lib/src/public_ext.dart b/lib/src/public_ext.dart index e9ecf6fc..e60fd6c6 100644 --- a/lib/src/public_ext.dart +++ b/lib/src/public_ext.dart @@ -18,7 +18,7 @@ extension TextTranslateExtension on Text { Map? namedArgs, String? gender}) => Text( - ez.tr(data, + ez.tr(data!, context: context, args: args, namedArgs: namedArgs, @@ -40,7 +40,7 @@ extension TextTranslateExtension on Text { Text plural(num value, {BuildContext? context, List? args, NumberFormat? format}) => Text( - ez.plural(data, value, context: context, args: args, format: format)!, + ez.plural(data!, value, context: context, args: args, format: format)!, key: key, style: style, strutStyle: strutStyle, diff --git a/lib/src/translations.dart b/lib/src/translations.dart index d2c5882d..5afe9dee 100644 --- a/lib/src/translations.dart +++ b/lib/src/translations.dart @@ -1,23 +1,27 @@ class Translations { - final Map _translations; + final Map? _translations; final Map _nestedKeysCache; Translations(this._translations) : _nestedKeysCache = {}; - String? get(String? key) => - (isNestedKey(key) ? getNested(key) : _translations[key!]); + String? get(String key) => + (isNestedKey(key) ? getNested(key) : _translations![key]); - String? getNested(String? key) { + String? getNested(String key) { if (isNestedCached(key)) return _nestedKeysCache[key]; - final keys = key!.split('.'); + final keys = key.split('.'); final kHead = keys.first; - var value = _translations[kHead]; + var value = _translations![kHead]; + + // print(value); for (var i = 1; i < keys.length; i++) { if (value is Map) value = value[keys[i]]; } + if(value == null) throw Exception('Cannot cache a key that is not nested.'); + cacheNestedKey(key, value); return value; } @@ -26,9 +30,9 @@ class Translations { // ? getNested(key) != null // : _translations.containsKey(key); - bool isNestedCached(String? key) => _nestedKeysCache.containsKey(key); + bool isNestedCached(String key) => _nestedKeysCache.containsKey(key); - void cacheNestedKey(String? key, String? value) { + void cacheNestedKey(String key, String value) { if (!isNestedKey(key)) { throw Exception('Cannot cache a key that is not nested.'); } @@ -36,6 +40,6 @@ class Translations { _nestedKeysCache[key] = value; } - bool isNestedKey(String? key) => - !_translations.containsKey(key) && key!.contains('.'); + bool isNestedKey(String key) => + !_translations!.containsKey(key) && key.contains('.'); } From dc094073f1eeb2fd442b2fb05c86d1df2282694c Mon Sep 17 00:00:00 2001 From: aissat Date: Wed, 17 Feb 2021 00:20:27 +0100 Subject: [PATCH 35/52] [TESTES] update testes context and widget --- test/easy_localization_context_test.dart | 152 +++++++------ test/easy_localization_widget_test.dart | 266 +++++++++++------------ 2 files changed, 205 insertions(+), 213 deletions(-) diff --git a/test/easy_localization_context_test.dart b/test/easy_localization_context_test.dart index 052166df..4a2101aa 100644 --- a/test/easy_localization_context_test.dart +++ b/test/easy_localization_context_test.dart @@ -8,7 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; -BuildContext? _context; +late BuildContext _context; class MyApp extends StatelessWidget { @override @@ -38,34 +38,35 @@ class MyWidget extends StatelessWidget { } void main() async { + await EasyLocalization.ensureInitialized(); SharedPreferences.setMockInitialValues({}); EasyLocalization.logger.enableLevels = [ LevelMessages.error, LevelMessages.warning, ]; - await EasyLocalization.ensureInitialized(); group('BuildContext', () { testWidgets( '[EasyLocalization] locale test', (WidgetTester tester) async { await tester.runAsync(() async { - await tester.pumpWidget(EasyLocalization( + await tester.pumpWidget(EasyLocalization( child: MyApp(), path: 'i18n', supportedLocales: [Locale('en', 'US')], )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + // await tester.pump(); + await tester.pump(); - expect(_context!.supportedLocales, [Locale('en', 'US')]); - expect(_context!.locale, Locale('en', 'US')); + expect(_context.supportedLocales, [Locale('en', 'US')]); + expect(_context.locale, Locale('en', 'US')); var l = Locale('en', 'US'); - await _context!.setLocale(l); - await tester.pumpAndSettle(); - expect(_context!.locale, Locale('en', 'US')); + await _context.setLocale(l); + await tester.pump(); + expect(_context.locale, Locale('en', 'US')); final trFinder = find.text('test'); expect(trFinder, findsOneWidget); @@ -76,14 +77,17 @@ void main() async { expect(plural('day', 1, context: _context), '1 day'); expect(plural('day', 2, context: _context), '2 days'); expect(plural('day', 3, context: _context), '3 other days'); - expect(_context!.locale, Locale('en', 'US')); + expect(_context.locale, Locale('en', 'US')); l = Locale('ar', 'DZ'); expect(() async { - await _context!.setLocale(l); + await _context.setLocale(l); }, throwsAssertionError); - await tester.pumpAndSettle(); - expect(_context!.locale, Locale('en', 'US')); + await tester.pump(); + expect(_context.locale, Locale('en', 'US')); + + + }); }, ); @@ -97,14 +101,14 @@ void main() async { path: 'i18n', supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(Localization.of(_context!), isInstanceOf()); - expect(_context!.supportedLocales, + expect(Localization.of(_context), isInstanceOf()); + expect(_context.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(_context!.locale, Locale('en', 'US')); + expect(_context.locale, Locale('en', 'US')); var trFinder = find.text('test'); expect(trFinder, findsOneWidget); @@ -117,31 +121,32 @@ void main() async { expect(plural('day', 3, context: _context), '3 other days'); var l = Locale('en', 'US'); - await _context!.setLocale(l); - await tester.pumpAndSettle(); - expect(_context!.locale, l); + await _context.setLocale(l); + await tester.pump(); + expect(_context.locale, l); l = Locale('ar', 'DZ'); - await _context!.setLocale(l); - await tester.idle(); - await tester.pumpAndSettle(); - expect(_context!.locale, l); + await _context.setLocale(l); + // await tester.idle(); + await tester.pump(); + expect(_context.locale, l); l = Locale('en', 'US'); - await _context!.setLocale(l); - await tester.idle(); - await tester.pumpAndSettle(); - expect(_context!.locale, l); + await _context.setLocale(l); + // await tester.idle(); + await tester.pump(); + expect(_context.locale, l); l = Locale('en', 'UK'); expect( - () async => {await _context!.setLocale(l)}, throwsAssertionError); + () async => {await _context.setLocale(l)}, throwsAssertionError); l = Locale('ar', 'DZ'); - await _context!.setLocale(l); - await tester.idle(); - await tester.pumpAndSettle(); - expect(_context!.locale, l); + await _context.setLocale(l); + // await tester.idle(); + await tester.pump(); + expect(_context.locale, l); + }); }, ); @@ -156,32 +161,37 @@ void main() async { supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - await _context!.setLocale(Locale('ar', 'DZ')); + await _context.setLocale(Locale('ar', 'DZ')); - await tester.pumpAndSettle(); + await tester.pump(); - expect(_context!.supportedLocales, + expect(_context.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(_context!.locale, Locale('ar', 'DZ')); + expect(_context.locale, Locale('ar', 'DZ')); var trFinder = find.text('اختبار'); expect(trFinder, findsOneWidget); var pluralFinder = find.text('1 يوم'); expect(pluralFinder, findsOneWidget); - expect(Localization.of(_context!), isInstanceOf()); + expect(Localization.of(_context), isInstanceOf()); expect(tr('test', context: _context), 'اختبار'); expect(plural('day', 1, context: _context), '1 يوم'); expect(plural('day', 2, context: _context), '2 أيام'); expect(plural('day', 3, context: _context), '3 أيام'); - // var l = Locale('en', 'US'); - // _context.locale = l; - // expect(_context.locale, l); + var l = Locale('en', 'US'); + _context.locale = l; + expect(_context.locale, l); + + l = Locale('ar', 'DZ'); + await _context.setLocale(l); + expect(_context.locale, l); + }); }, ); @@ -198,13 +208,13 @@ void main() async { supportedLocales: [Locale('ar')], fallbackLocale: Locale('ar'), )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(_context!.supportedLocales, [Locale('ar')]); - expect(_context!.locale, Locale('ar')); - expect(_context!.fallbackLocale, Locale('ar')); + expect(_context.supportedLocales, [Locale('ar')]); + expect(_context.locale, Locale('ar')); + expect(_context.fallbackLocale, Locale('ar')); }); }, ); @@ -223,13 +233,13 @@ void main() async { Locale('ar') ], // Locale('en', 'US'), Locale('ar','DZ') )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(_context!.supportedLocales, [Locale('ar')]); - expect(_context!.locale, Locale('ar')); - expect(_context!.fallbackLocale, null); + expect(_context.supportedLocales, [Locale('ar')]); + expect(_context.locale, Locale('ar')); + expect(_context.fallbackLocale, null); }); }, ); @@ -254,12 +264,12 @@ void main() async { Locale('ar', 'DZ') ], // Locale('en', 'US'), Locale('ar','DZ') )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(_context!.locale, Locale('ar', 'DZ')); - await _context!.deleteSaveLocale(); + expect(_context.locale, Locale('ar', 'DZ')); + await _context.deleteSaveLocale(); }); }, ); @@ -277,11 +287,11 @@ void main() async { Locale('ar', 'DZ') ], // Locale('en', 'US'), Locale('ar','DZ') )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(_context!.locale, Locale('en', 'US')); + expect(_context.locale, Locale('en', 'US')); }); }, ); @@ -298,11 +308,11 @@ void main() async { Locale('ar', 'DZ') ], // Locale('en', 'US'), Locale('ar','DZ') )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(_context!.deviceLocale.toString(), Platform.localeName); + expect(_context.deviceLocale.toString(), Platform.localeName); }); }, ); @@ -320,15 +330,15 @@ void main() async { ], // Locale('en', 'US'), Locale('ar','DZ') startLocale: Locale('ar', 'DZ'), )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(_context!.locale, Locale('ar', 'DZ')); + expect(_context.locale, Locale('ar', 'DZ')); // reset to device locale - await _context!.resetLocale(); - await tester.pumpAndSettle(); - expect(_context!.locale, Locale('en', 'US')); + await _context.resetLocale(); + await tester.pump(); + expect(_context.locale, Locale('en', 'US')); }); }, ); diff --git a/test/easy_localization_widget_test.dart b/test/easy_localization_widget_test.dart index 92cbe2d8..2ea70482 100644 --- a/test/easy_localization_widget_test.dart +++ b/test/easy_localization_widget_test.dart @@ -9,7 +9,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'utils/test_asset_loaders.dart'; -BuildContext? _context; +late BuildContext _context; class MyApp extends StatelessWidget { @override @@ -56,17 +56,16 @@ void main() async { supportedLocales: [Locale('en', 'US')], assetLoader: JsonAssetLoader(), )); - await tester.idle(); -// await tester.pump(Duration(milliseconds: 400)); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(Localization.of(_context!), isInstanceOf()); + expect(Localization.of(_context), isInstanceOf()); expect(Localization.instance, isInstanceOf()); - expect(Localization.instance, Localization.of(_context!)); - expect(EasyLocalization.of(_context!)!.supportedLocales, + expect(Localization.instance, Localization.of(_context)); + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('en', 'US')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context)!.locale, Locale('en', 'US')); final trFinder = find.text('test'); expect(trFinder, findsOneWidget); @@ -84,23 +83,6 @@ void main() async { }, ); - // testWidgets( - // '[EasyLocalization with child==null AssertionError] test', - // (WidgetTester tester) async { - // await tester.runAsync(() async { - // try { - // await tester.pumpWidget(EasyLocalization( - // child: null, - // path: 'i18n', - // supportedLocales: [Locale('en', 'US')], - // )); - // } on AssertionError catch (e) { - // // throw AssertionError('Expected ArgumentError'); - // expect(e, isAssertionError); - // } - // }); - // }, - // ); testWidgets( '[EasyLocalization with RootBundleAssetLoader] test', @@ -112,13 +94,13 @@ void main() async { assetLoader: RootBundleAssetLoader(), supportedLocales: [Locale('en', 'US')], )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.supportedLocales, + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('en', 'US')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context)!.locale, Locale('en', 'US')); final trFinder = find.text('test'); expect(trFinder, findsOneWidget); @@ -141,13 +123,13 @@ void main() async { path: 'i18n', supportedLocales: [Locale('en', 'US')], )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.supportedLocales, + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('en', 'US')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context)!.locale, Locale('en', 'US')); final trFinder = find.text('test'); expect(trFinder, findsOneWidget); @@ -170,9 +152,9 @@ void main() async { path: 'i18', supportedLocales: [Locale('en', 'US')], )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); final trFinder = find.byWidgetPredicate((widget) => widget is ErrorWidget); expect(trFinder, findsOneWidget); @@ -189,18 +171,18 @@ void main() async { path: 'i18n', supportedLocales: [Locale('en', 'US')], )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.supportedLocales, + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('en', 'US')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context)!.locale, Locale('en', 'US')); var l = Locale('en', 'US'); - await EasyLocalization.of(_context!)!.setLocale(l); - await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); + await EasyLocalization.of(_context)!.setLocale(l); + await tester.pump(); + expect(EasyLocalization.of(_context)!.locale, Locale('en', 'US')); final trFinder = find.text('test'); expect(trFinder, findsOneWidget); @@ -211,14 +193,14 @@ void main() async { expect(plural('day', 1, context: _context), '1 day'); expect(plural('day', 2, context: _context), '2 days'); expect(plural('day', 3, context: _context), '3 other days'); - expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context)!.locale, Locale('en', 'US')); l = Locale('ar', 'DZ'); expect(() async { - await EasyLocalization.of(_context!)!.setLocale(l); + await EasyLocalization.of(_context)!.setLocale(l); }, throwsAssertionError); - await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); + await tester.pump(); + expect(EasyLocalization.of(_context)!.locale, Locale('en', 'US')); }); }, ); @@ -232,14 +214,14 @@ void main() async { path: 'i18n', supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(Localization.of(_context!), isInstanceOf()); - expect(EasyLocalization.of(_context!)!.supportedLocales, + expect(Localization.of(_context), isInstanceOf()); + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context)!.locale, Locale('en', 'US')); var trFinder = find.text('test'); expect(trFinder, findsOneWidget); @@ -252,31 +234,31 @@ void main() async { expect(plural('day', 3, context: _context), '3 other days'); var l = Locale('en', 'US'); - await EasyLocalization.of(_context!)!.setLocale(l); - await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context!)!.locale, l); + await EasyLocalization.of(_context)!.setLocale(l); + await tester.pump(); + expect(EasyLocalization.of(_context)!.locale, l); l = Locale('ar', 'DZ'); - await EasyLocalization.of(_context!)!.setLocale(l); - await tester.idle(); - await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context!)!.locale, l); + await EasyLocalization.of(_context)!.setLocale(l); + // await tester.idle(); + await tester.pump(); + expect(EasyLocalization.of(_context)!.locale, l); l = Locale('en', 'US'); - await EasyLocalization.of(_context!)!.setLocale(l); - await tester.idle(); - await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context!)!.locale, l); + await EasyLocalization.of(_context)!.setLocale(l); + // await tester.idle(); + await tester.pump(); + expect(EasyLocalization.of(_context)!.locale, l); l = Locale('en', 'UK'); - expect(() async => {await EasyLocalization.of(_context!)!.setLocale(l)}, + expect(() async => {await EasyLocalization.of(_context)!.setLocale(l)}, throwsAssertionError); l = Locale('ar', 'DZ'); - await EasyLocalization.of(_context!)!.setLocale(l); - await tester.idle(); - await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context!)!.locale, l); + await EasyLocalization.of(_context)!.setLocale(l); + // await tester.idle(); + await tester.pump(); + expect(EasyLocalization.of(_context)!.locale, l); }); }, ); @@ -291,24 +273,24 @@ void main() async { supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - await EasyLocalization.of(_context!)!.setLocale(Locale('ar', 'DZ')); + await EasyLocalization.of(_context)!.setLocale(Locale('ar', 'DZ')); - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.supportedLocales, + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('ar', 'DZ')); + expect(EasyLocalization.of(_context)!.locale, Locale('ar', 'DZ')); var trFinder = find.text('اختبار'); expect(trFinder, findsOneWidget); var pluralFinder = find.text('1 يوم'); expect(pluralFinder, findsOneWidget); - expect(Localization.of(_context!), isInstanceOf()); + expect(Localization.of(_context), isInstanceOf()); expect(tr('test', context: _context), 'اختبار'); expect(plural('day', 1, context: _context), '1 يوم'); expect(plural('day', 2, context: _context), '2 أيام'); @@ -335,17 +317,17 @@ void main() async { Locale('ar') ], // Locale('en', 'US'), Locale('ar','DZ') )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.supportedLocales, + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('en'), Locale('ar')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('en')); + expect(EasyLocalization.of(_context)!.locale, Locale('en')); var l = Locale('en'); - await EasyLocalization.of(_context!)!.setLocale(l); - expect(EasyLocalization.of(_context!)!.locale, l); + await EasyLocalization.of(_context)!.setLocale(l); + expect(EasyLocalization.of(_context)!.locale, l); }); }, ); @@ -364,17 +346,17 @@ void main() async { Locale('ar') ], // Locale('en', 'US'), Locale('ar','DZ') )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.supportedLocales, + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('en'), Locale('ar')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('en')); + expect(EasyLocalization.of(_context)!.locale, Locale('en')); var l = Locale('en'); - await EasyLocalization.of(_context!)!.setLocale(l); - expect(EasyLocalization.of(_context!)!.locale, l); + await EasyLocalization.of(_context)!.setLocale(l); + expect(EasyLocalization.of(_context)!.locale, l); }); }, ); @@ -391,14 +373,14 @@ void main() async { supportedLocales: [Locale('ar')], fallbackLocale: Locale('ar'), )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); expect( - EasyLocalization.of(_context!)!.supportedLocales, [Locale('ar')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('ar')); - expect(EasyLocalization.of(_context!)!.fallbackLocale, Locale('ar')); + EasyLocalization.of(_context)!.supportedLocales, [Locale('ar')]); + expect(EasyLocalization.of(_context)!.locale, Locale('ar')); + expect(EasyLocalization.of(_context)!.fallbackLocale, Locale('ar')); }); }, ); @@ -417,14 +399,14 @@ void main() async { Locale('ar') ], // Locale('en', 'US'), Locale('ar','DZ') )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); expect( - EasyLocalization.of(_context!)!.supportedLocales, [Locale('ar')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('ar')); - expect(EasyLocalization.of(_context!)!.fallbackLocale, null); + EasyLocalization.of(_context)!.supportedLocales, [Locale('ar')]); + expect(EasyLocalization.of(_context)!.locale, Locale('ar')); + expect(EasyLocalization.of(_context)!.fallbackLocale, null); }); }, ); @@ -446,15 +428,15 @@ void main() async { // fallbackLocale:Locale('en') , supportedLocales: [Locale('en'), Locale('ar')], // )); - await tester.idle(); + // await tester.idle(); await tester.pump(Duration(seconds: 2)); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.supportedLocales, + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('en'), Locale('ar')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('en')); - expect(EasyLocalization.of(_context!)!.fallbackLocale, null); + expect(EasyLocalization.of(_context)!.locale, Locale('en')); + expect(EasyLocalization.of(_context)!.fallbackLocale, null); }); }, ); @@ -468,15 +450,15 @@ void main() async { // fallbackLocale:Locale('en') , supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], // )); - await tester.idle(); + // await tester.idle(); await tester.pump(Duration(seconds: 2)); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.supportedLocales, + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); - expect(EasyLocalization.of(_context!)!.fallbackLocale, null); + expect(EasyLocalization.of(_context)!.locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context)!.fallbackLocale, null); }); }, ); @@ -491,15 +473,15 @@ void main() async { // fallbackLocale:Locale('en') , supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], // )); - await tester.idle(); + // await tester.idle(); await tester.pump(Duration(seconds: 2)); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.supportedLocales, + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('ar', 'DZ')); - expect(EasyLocalization.of(_context!)!.fallbackLocale, null); + expect(EasyLocalization.of(_context)!.locale, Locale('ar', 'DZ')); + expect(EasyLocalization.of(_context)!.fallbackLocale, null); }); }, ); @@ -528,14 +510,14 @@ void main() async { Locale('ar') ], // Locale('en', 'US'), Locale('ar','DZ') )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.supportedLocales, + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('en'), Locale('ar')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('ar')); - expect(EasyLocalization.of(_context!)!.fallbackLocale, null); + expect(EasyLocalization.of(_context)!.locale, Locale('ar')); + expect(EasyLocalization.of(_context)!.fallbackLocale, null); }); }, ); @@ -563,14 +545,14 @@ void main() async { Locale('ar', 'DZ') ], // Locale('en', 'US'), Locale('ar','DZ') )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.supportedLocales, + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('ar', 'DZ')); - expect(EasyLocalization.of(_context!)!.fallbackLocale, null); + expect(EasyLocalization.of(_context)!.locale, Locale('ar', 'DZ')); + expect(EasyLocalization.of(_context)!.fallbackLocale, null); }); }, ); @@ -589,15 +571,15 @@ void main() async { Locale('ar', 'DZ') ], // Locale('en', 'US'), Locale('ar','DZ') )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.supportedLocales, + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context)!.locale, Locale('en', 'US')); - await EasyLocalization.of(_context!)!.setLocale(Locale('en', 'US')); + await EasyLocalization.of(_context)!.setLocale(Locale('en', 'US')); }); }, ); @@ -622,12 +604,12 @@ void main() async { Locale('ar', 'DZ') ], // Locale('en', 'US'), Locale('ar','DZ') )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.locale, Locale('ar', 'DZ')); - await EasyLocalization.of(_context!)!.deleteSaveLocale(); + expect(EasyLocalization.of(_context)!.locale, Locale('ar', 'DZ')); + await EasyLocalization.of(_context)!.deleteSaveLocale(); }); }, ); @@ -645,11 +627,11 @@ void main() async { Locale('ar', 'DZ') ], // Locale('en', 'US'), Locale('ar','DZ') )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); + expect(EasyLocalization.of(_context)!.locale, Locale('en', 'US')); }); }, ); @@ -666,11 +648,11 @@ void main() async { Locale('ar', 'DZ') ], // Locale('en', 'US'), Locale('ar','DZ') )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.deviceLocale.toString(), + expect(EasyLocalization.of(_context)!.deviceLocale.toString(), Platform.localeName); }); }, @@ -689,15 +671,15 @@ void main() async { ], // Locale('en', 'US'), Locale('ar','DZ') startLocale: Locale('ar', 'DZ'), )); - await tester.idle(); + // await tester.idle(); // The async delegator load will require build on the next frame. Thus, pump - await tester.pumpAndSettle(); + await tester.pump(); - expect(EasyLocalization.of(_context!)!.locale, Locale('ar', 'DZ')); + expect(EasyLocalization.of(_context)!.locale, Locale('ar', 'DZ')); // reset to device locale - await _context!.resetLocale(); - await tester.pumpAndSettle(); - expect(EasyLocalization.of(_context!)!.locale, Locale('en', 'US')); + await _context.resetLocale(); + await tester.pump(); + expect(EasyLocalization.of(_context)!.locale, Locale('en', 'US')); }); }, ); From 2eb4137da3215ef0da9ceac7b6978c3ca7adccd1 Mon Sep 17 00:00:00 2001 From: aissat Date: Wed, 17 Feb 2021 00:21:52 +0100 Subject: [PATCH 36/52] [example] add linux project --- example/linux/.gitignore | 1 + example/linux/CMakeLists.txt | 106 ++++++++++++++++++ example/linux/flutter/CMakeLists.txt | 91 +++++++++++++++ .../flutter/generated_plugin_registrant.cc | 9 ++ .../flutter/generated_plugin_registrant.h | 13 +++ example/linux/flutter/generated_plugins.cmake | 15 +++ example/linux/main.cc | 6 + example/linux/my_application.cc | 105 +++++++++++++++++ example/linux/my_application.h | 18 +++ 9 files changed, 364 insertions(+) create mode 100644 example/linux/.gitignore create mode 100644 example/linux/CMakeLists.txt create mode 100644 example/linux/flutter/CMakeLists.txt create mode 100644 example/linux/flutter/generated_plugin_registrant.cc create mode 100644 example/linux/flutter/generated_plugin_registrant.h create mode 100644 example/linux/flutter/generated_plugins.cmake create mode 100644 example/linux/main.cc create mode 100644 example/linux/my_application.cc create mode 100644 example/linux/my_application.h diff --git a/example/linux/.gitignore b/example/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/example/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/example/linux/CMakeLists.txt b/example/linux/CMakeLists.txt new file mode 100644 index 00000000..1f0ece39 --- /dev/null +++ b/example/linux/CMakeLists.txt @@ -0,0 +1,106 @@ +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +set(BINARY_NAME "example") +set(APPLICATION_ID "io.aissat.example.example") + +cmake_policy(SET CMP0063 NEW) + +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Configure build options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") + +# Flutter library and tool build rules. +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Application build +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) +apply_standard_settings(${BINARY_NAME}) +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) +add_dependencies(${BINARY_NAME} flutter_assemble) +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/example/linux/flutter/CMakeLists.txt b/example/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..a1da1b9e --- /dev/null +++ b/example/linux/flutter/CMakeLists.txt @@ -0,0 +1,91 @@ +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) +pkg_check_modules(BLKID REQUIRED IMPORTED_TARGET blkid) +pkg_check_modules(LZMA REQUIRED IMPORTED_TARGET liblzma) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO + PkgConfig::BLKID + PkgConfig::LZMA +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + linux-x64 ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/example/linux/flutter/generated_plugin_registrant.cc b/example/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..d38195aa --- /dev/null +++ b/example/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,9 @@ +// +// Generated file. Do not edit. +// + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/example/linux/flutter/generated_plugin_registrant.h b/example/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..9bf74789 --- /dev/null +++ b/example/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,13 @@ +// +// Generated file. Do not edit. +// + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/example/linux/flutter/generated_plugins.cmake b/example/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..51436ae8 --- /dev/null +++ b/example/linux/flutter/generated_plugins.cmake @@ -0,0 +1,15 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) diff --git a/example/linux/main.cc b/example/linux/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/example/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/example/linux/my_application.cc b/example/linux/my_application.cc new file mode 100644 index 00000000..634f4c51 --- /dev/null +++ b/example/linux/my_application.cc @@ -0,0 +1,105 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen *screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "example"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } + else { + gtk_window_set_title(window, "example"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar ***arguments, int *exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject *object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/example/linux/my_application.h b/example/linux/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/example/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ From 0a9ea0b0e6e90346930907fdd6a1d4eeaa67626f Mon Sep 17 00:00:00 2001 From: aissat Date: Wed, 17 Feb 2021 00:26:58 +0100 Subject: [PATCH 37/52] fixed deprecated_member_use issue --- test/easy_localization_context_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/easy_localization_context_test.dart b/test/easy_localization_context_test.dart index 4a2101aa..9ab20d8f 100644 --- a/test/easy_localization_context_test.dart +++ b/test/easy_localization_context_test.dart @@ -185,7 +185,7 @@ void main() async { expect(plural('day', 3, context: _context), '3 أيام'); var l = Locale('en', 'US'); - _context.locale = l; + await _context.setLocale(l); expect(_context.locale, l); l = Locale('ar', 'DZ'); From b60b34cabac4546b64d7340f7902342d6f23fd3a Mon Sep 17 00:00:00 2001 From: Miran Kamal <32594520+MiranKm@users.noreply.github.com> Date: Tue, 16 Feb 2021 17:03:12 +0300 Subject: [PATCH 38/52] fixes a typo in readme, makes it more clear (#320) * fixes a typo in readme, makes it more clear * fixes a mistake in the documentation Co-authored-by: Alexey Z <47769319+Overman775@users.noreply.github.com> --- README.md | 2 +- lib/src/easy_localization_app.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9336624c..69cf7559 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ void main() async { runApp( EasyLocalization( supportedLocales: [Locale('en', 'US'), Locale('de', 'DE')], - path: 'assets/translations', // <-- change patch to your + path: 'assets/translations', // <-- change the path of the translation files fallbackLocale: Locale('en', 'US'), child: MyApp() ), diff --git a/lib/src/easy_localization_app.dart b/lib/src/easy_localization_app.dart index 1a369f26..b3691360 100644 --- a/lib/src/easy_localization_app.dart +++ b/lib/src/easy_localization_app.dart @@ -68,7 +68,7 @@ class EasyLocalization extends StatefulWidget { final assetLoader; /// Save locale in device storage. - /// @Default value false + /// @Default value true final bool saveLocale; /// Shows a custom error widget when an error is encountered instead of the default error widget. From 26314e38dceb8b65efdf583b8ac95d623584f522 Mon Sep 17 00:00:00 2001 From: aissat Date: Wed, 17 Feb 2021 00:39:10 +0100 Subject: [PATCH 39/52] format files --- lib/src/easy_localization_app.dart | 4 ++- lib/src/localization.dart | 36 ++++++++++--------- lib/src/public.dart | 3 +- lib/src/public_ext.dart | 3 +- lib/src/translations.dart | 3 +- .../easy_logger/lib/src/logger_printer.dart | 4 +-- .../easy_logger/test/easy_logger_test.dart | 3 +- test/easy_localization_context_test.dart | 7 +--- test/easy_localization_test.dart | 9 +++-- test/easy_localization_widget_test.dart | 7 ++-- test/utils/test_asset_loaders.dart | 3 +- 11 files changed, 44 insertions(+), 38 deletions(-) diff --git a/lib/src/easy_localization_app.dart b/lib/src/easy_localization_app.dart index b3691360..134bd05a 100644 --- a/lib/src/easy_localization_app.dart +++ b/lib/src/easy_localization_app.dart @@ -257,7 +257,9 @@ class _EasyLocalizationDelegate extends LocalizationsDelegate { await localizationController!.loadTranslations(); } - Localization.load(value, translations: localizationController!.translations, fallbackTranslations: localizationController!.fallbackTranslations); + Localization.load(value, + translations: localizationController!.translations, + fallbackTranslations: localizationController!.fallbackTranslations); return Future.value(Localization.instance); } diff --git a/lib/src/localization.dart b/lib/src/localization.dart index 7cd90ade..71a66d79 100644 --- a/lib/src/localization.dart +++ b/lib/src/localization.dart @@ -30,7 +30,8 @@ class Localization { static Localization? of(BuildContext context) => Localizations.of(context, Localization); - static bool load(Locale locale, {Translations? translations, Translations? fallbackTranslations}) { + static bool load(Locale locale, + {Translations? translations, Translations? fallbackTranslations}) { instance._locale = locale; instance._translations = translations; instance._fallbackTranslations = fallbackTranslations; @@ -102,22 +103,22 @@ class Localization { return res; } - static PluralRule? _pluralRule(String? locale, num howMany){ + static PluralRule? _pluralRule(String? locale, num howMany) { startRuleEvaluation(howMany); - return pluralRules[locale] ; + return pluralRules[locale]; } String? plural(String key, num value, {List? args, NumberFormat? format}) { late var pluralCase; late var res; - var pluralRule = _pluralRule(_locale.languageCode,value); + var pluralRule = _pluralRule(_locale.languageCode, value); switch (value) { case 0: - pluralCase = PluralCase.ZERO ; + pluralCase = PluralCase.ZERO; break; case 1: - pluralCase = PluralCase.ONE ; + pluralCase = PluralCase.ONE; break; case 2: pluralCase = PluralCase.TWO; @@ -127,26 +128,25 @@ class Localization { } switch (pluralCase) { case PluralCase.ZERO: - res= _resolvePlural(key, 'zero'); + res = _resolvePlural(key, 'zero'); break; case PluralCase.ONE: - res= _resolvePlural(key, 'one'); + res = _resolvePlural(key, 'one'); break; case PluralCase.TWO: - res= _resolvePlural(key, 'two'); + res = _resolvePlural(key, 'two'); break; case PluralCase.FEW: - res= _resolvePlural(key, 'few'); + res = _resolvePlural(key, 'few'); break; case PluralCase.MANY: - res= _resolvePlural(key, 'many'); + res = _resolvePlural(key, 'many'); break; case PluralCase.OTHER: - res= _resolvePlural(key, 'other'); + res = _resolvePlural(key, 'other'); break; default: - throw ArgumentError.value( - value, 'howMany', 'Invalid plural argument'); + throw ArgumentError.value(value, 'howMany', 'Invalid plural argument'); } return _replaceArgs( @@ -165,18 +165,20 @@ class Localization { String _resolve(String key, {bool logging = true}) { var resource = _translations!.get(key); if (resource == null) { - if (logging) EasyLocalization.logger.warning('Localization key [$key] not found'); + if (logging) + EasyLocalization.logger.warning('Localization key [$key] not found'); if (_fallbackTranslations == null) { return key; } else { resource = _fallbackTranslations!.get(key); if (resource == null) { - if (logging) EasyLocalization.logger.warning('Fallback localization key [$key] not found'); + if (logging) + EasyLocalization.logger + .warning('Fallback localization key [$key] not found'); return key; } } } return resource; } - } diff --git a/lib/src/public.dart b/lib/src/public.dart index 159f1df3..9e487c68 100644 --- a/lib/src/public.dart +++ b/lib/src/public.dart @@ -87,5 +87,6 @@ String? plural(String key, num value, {BuildContext? context, List? args, NumberFormat? format}) { return context == null ? Localization.instance.plural(key, value, args: args, format: format) - : Localization.of(context)!.plural(key, value, args: args, format: format); + : Localization.of(context)! + .plural(key, value, args: args, format: format); } diff --git a/lib/src/public_ext.dart b/lib/src/public_ext.dart index e60fd6c6..a44647c2 100644 --- a/lib/src/public_ext.dart +++ b/lib/src/public_ext.dart @@ -40,7 +40,8 @@ extension TextTranslateExtension on Text { Text plural(num value, {BuildContext? context, List? args, NumberFormat? format}) => Text( - ez.plural(data!, value, context: context, args: args, format: format)!, + ez.plural(data!, value, + context: context, args: args, format: format)!, key: key, style: style, strutStyle: strutStyle, diff --git a/lib/src/translations.dart b/lib/src/translations.dart index 5afe9dee..f0a933c1 100644 --- a/lib/src/translations.dart +++ b/lib/src/translations.dart @@ -20,7 +20,8 @@ class Translations { if (value is Map) value = value[keys[i]]; } - if(value == null) throw Exception('Cannot cache a key that is not nested.'); + if (value == null) + throw Exception('Cannot cache a key that is not nested.'); cacheNestedKey(key, value); return value; diff --git a/packages/easy_logger/lib/src/logger_printer.dart b/packages/easy_logger/lib/src/logger_printer.dart index 5afc45b9..077882e4 100644 --- a/packages/easy_logger/lib/src/logger_printer.dart +++ b/packages/easy_logger/lib/src/logger_printer.dart @@ -5,8 +5,8 @@ typedef EasyLogPrinter = Function(Object object, {String? name, LevelMessages? level, StackTrace? stackTrace}); /// Default function printing. -EasyLogPrinter easyLogDefaultPrinter = - (Object object, {String? name, StackTrace? stackTrace, LevelMessages? level}) { +EasyLogPrinter easyLogDefaultPrinter = (Object object, + {String? name, StackTrace? stackTrace, LevelMessages? level}) { String _coloredString(String string) { switch (level) { case LevelMessages.debug: diff --git a/packages/easy_logger/test/easy_logger_test.dart b/packages/easy_logger/test/easy_logger_test.dart index 085cbd76..249f863c 100644 --- a/packages/easy_logger/test/easy_logger_test.dart +++ b/packages/easy_logger/test/easy_logger_test.dart @@ -61,7 +61,8 @@ void main() { StackTrace testStackTrace; testStackTrace = StackTrace.fromString('test stack'); - logger('print error', level: LevelMessages.error, stackTrace: testStackTrace); + logger('print error', + level: LevelMessages.error, stackTrace: testStackTrace); expect(printLog.first, contains('print error')); expect(printLog.first, contains('[ERROR]')); expect(printLog.last, contains('test stack')); diff --git a/test/easy_localization_context_test.dart b/test/easy_localization_context_test.dart index 9ab20d8f..70dbbf91 100644 --- a/test/easy_localization_context_test.dart +++ b/test/easy_localization_context_test.dart @@ -50,7 +50,7 @@ void main() async { '[EasyLocalization] locale test', (WidgetTester tester) async { await tester.runAsync(() async { - await tester.pumpWidget(EasyLocalization( + await tester.pumpWidget(EasyLocalization( child: MyApp(), path: 'i18n', supportedLocales: [Locale('en', 'US')], @@ -85,9 +85,6 @@ void main() async { }, throwsAssertionError); await tester.pump(); expect(_context.locale, Locale('en', 'US')); - - - }); }, ); @@ -146,7 +143,6 @@ void main() async { // await tester.idle(); await tester.pump(); expect(_context.locale, l); - }); }, ); @@ -191,7 +187,6 @@ void main() async { l = Locale('ar', 'DZ'); await _context.setLocale(l); expect(_context.locale, l); - }); }, ); diff --git a/test/easy_localization_test.dart b/test/easy_localization_test.dart index b67878c8..d1f42fbc 100644 --- a/test/easy_localization_test.dart +++ b/test/easy_localization_test.dart @@ -73,7 +73,10 @@ void main() { test('load() with fallback succeeds', () async { expect( - Localization.load(Locale('en'), translations: r1.translations, fallbackTranslations: r2.translations), true); + Localization.load(Locale('en'), + translations: r1.translations, + fallbackTranslations: r2.translations), + true); }); test('localeFromString() succeeds', () async { @@ -127,7 +130,9 @@ void main() { setUpAll(() async { await r.loadTranslations(); - Localization.load(Locale('en'), translations: r.translations, fallbackTranslations: r.fallbackTranslations); + Localization.load(Locale('en'), + translations: r.translations, + fallbackTranslations: r.fallbackTranslations); }); test('finds and returns resource', () { expect(Localization.instance.tr('test'), 'test'); diff --git a/test/easy_localization_widget_test.dart b/test/easy_localization_widget_test.dart index 2ea70482..f3fb8528 100644 --- a/test/easy_localization_widget_test.dart +++ b/test/easy_localization_widget_test.dart @@ -83,7 +83,6 @@ void main() async { }, ); - testWidgets( '[EasyLocalization with RootBundleAssetLoader] test', (WidgetTester tester) async { @@ -377,8 +376,7 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pump(); - expect( - EasyLocalization.of(_context)!.supportedLocales, [Locale('ar')]); + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('ar')]); expect(EasyLocalization.of(_context)!.locale, Locale('ar')); expect(EasyLocalization.of(_context)!.fallbackLocale, Locale('ar')); }); @@ -403,8 +401,7 @@ void main() async { // The async delegator load will require build on the next frame. Thus, pump await tester.pump(); - expect( - EasyLocalization.of(_context)!.supportedLocales, [Locale('ar')]); + expect(EasyLocalization.of(_context)!.supportedLocales, [Locale('ar')]); expect(EasyLocalization.of(_context)!.locale, Locale('ar')); expect(EasyLocalization.of(_context)!.fallbackLocale, null); }); diff --git a/test/utils/test_asset_loaders.dart b/test/utils/test_asset_loaders.dart index 804e4117..12b935e1 100644 --- a/test/utils/test_asset_loaders.dart +++ b/test/utils/test_asset_loaders.dart @@ -56,7 +56,8 @@ class JsonAssetLoader extends AssetLoader { } }, 'path': '$fullPath', - 'test_missing_fallback': (locale.languageCode == 'fb' ? 'fallback!' : null), + 'test_missing_fallback': + (locale.languageCode == 'fb' ? 'fallback!' : null), }); } } From e4293411a25efaea2c691c632124799f7204481b Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Wed, 17 Feb 2021 13:43:57 +0500 Subject: [PATCH 40/52] fixed null safety and grammar --- example/lib/lang_view.dart | 10 +++--- example/lib/main.dart | 8 +++-- example/pubspec.yaml | 6 ++-- lib/src/easy_localization_app.dart | 2 +- lib/src/easy_localization_controller.dart | 7 +++-- lib/src/localization.dart | 27 ++++++++++------ lib/src/public.dart | 21 ++++++++----- lib/src/public_ext.dart | 38 ++++++++++++++--------- lib/src/translations.dart | 3 +- pubspec.yaml | 4 +-- 10 files changed, 77 insertions(+), 49 deletions(-) diff --git a/example/lib/lang_view.dart b/example/lib/lang_view.dart index 5ef750a7..a81274aa 100644 --- a/example/lib/lang_view.dart +++ b/example/lib/lang_view.dart @@ -66,7 +66,7 @@ class LanguageView extends StatelessWidget { } class _Divider extends StatelessWidget { - const _Divider({Key key}) : super(key: key); + const _Divider({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -83,10 +83,10 @@ class _Divider extends StatelessWidget { class _SwitchListTileMenuItem extends StatelessWidget { const _SwitchListTileMenuItem({ - Key key, - this.title, - this.subtitle, - this.locale, + Key? key, + required this.title, + required this.subtitle, + required this.locale, }) : super(key: key); final String title; diff --git a/example/lib/main.dart b/example/lib/main.dart index d68eed5b..04333508 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -56,7 +56,7 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); + MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @@ -85,10 +85,12 @@ class _MyHomePageState extends State { return Scaffold( appBar: AppBar( title: Text(LocaleKeys.title).tr(context: context), - //Text(AppLocalizations.of(context).tr('title')), actions: [ TextButton( - child: Icon(Icons.language), + child: Icon( + Icons.language, + color: Colors.white, + ), onPressed: () { Navigator.push( context, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 8395c51d..44dbf078 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -14,7 +14,7 @@ publish_to: none version: 1.0.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0-0 <3.0.0" dependencies: flutter: @@ -22,10 +22,10 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 + cupertino_icons: ^1.0.2 easy_localization: path: ../ - flutter_icons: ^1.0.0+1 + flutter_icons: ^1.1.0 #custom loaders easy_localization_loader: diff --git a/lib/src/easy_localization_app.dart b/lib/src/easy_localization_app.dart index 134bd05a..23ca9782 100644 --- a/lib/src/easy_localization_app.dart +++ b/lib/src/easy_localization_app.dart @@ -221,7 +221,7 @@ class _EasyLocalizationProvider extends InheritedWidget { } /// Getting device locale from platform - Locale? get deviceLocale => _localeState.deviceLocale; + Locale get deviceLocale => _localeState.deviceLocale; /// Reset locale to platform locale Future resetLocale() => _localeState.resetLocale(); diff --git a/lib/src/easy_localization_controller.dart b/lib/src/easy_localization_controller.dart index c26dc87f..0b8a5a22 100644 --- a/lib/src/easy_localization_controller.dart +++ b/lib/src/easy_localization_controller.dart @@ -8,7 +8,7 @@ import 'translations.dart'; class EasyLocalizationController extends ChangeNotifier { static Locale? _savedLocale; - static Locale? _deviceLocale; + static late Locale _deviceLocale; late Locale _locale; Locale? _fallbackLocale; @@ -99,6 +99,7 @@ class EasyLocalizationController extends ChangeNotifier { } Locale get locale => _locale; + Future setLocale(Locale l) async { _locale = l; await loadTranslations(); @@ -130,11 +131,11 @@ class EasyLocalizationController extends ChangeNotifier { EasyLocalization.logger('Saved locale deleted'); } - Locale? get deviceLocale => _deviceLocale; + Locale get deviceLocale => _deviceLocale; Future resetLocale() async { EasyLocalization.logger('Reset locale to platform locale $_deviceLocale'); - await setLocale(_deviceLocale!); + await setLocale(_deviceLocale); } } diff --git a/lib/src/localization.dart b/lib/src/localization.dart index 71a66d79..d05b0e81 100644 --- a/lib/src/localization.dart +++ b/lib/src/localization.dart @@ -10,8 +10,6 @@ class Localization { Translations? _translations, _fallbackTranslations; late Locale _locale; - String? path; - bool? useOnlyLangCode; final RegExp _replaceArgRegex = RegExp(r'{}'); final RegExp _linkKeyMatcher = RegExp(r'(?:@(?:\.[a-z]+)?:(?:[\w\-_|.]+|\([\w\-_|.]+\)))'); @@ -30,17 +28,24 @@ class Localization { static Localization? of(BuildContext context) => Localizations.of(context, Localization); - static bool load(Locale locale, - {Translations? translations, Translations? fallbackTranslations}) { + static bool load( + Locale locale, { + Translations? translations, + Translations? fallbackTranslations, + }) { instance._locale = locale; instance._translations = translations; instance._fallbackTranslations = fallbackTranslations; return translations == null ? false : true; } - String tr(String key, - {List? args, Map? namedArgs, String? gender}) { - String? res; + String tr( + String key, { + List? args, + Map? namedArgs, + String? gender, + }) { + late String res; if (gender != null) { res = _gender(key, gender: gender); @@ -108,7 +113,7 @@ class Localization { return pluralRules[locale]; } - String? plural(String key, num value, + String plural(String key, num value, {List? args, NumberFormat? format}) { late var pluralCase; late var res; @@ -165,16 +170,18 @@ class Localization { String _resolve(String key, {bool logging = true}) { var resource = _translations!.get(key); if (resource == null) { - if (logging) + if (logging) { EasyLocalization.logger.warning('Localization key [$key] not found'); + } if (_fallbackTranslations == null) { return key; } else { resource = _fallbackTranslations!.get(key); if (resource == null) { - if (logging) + if (logging) { EasyLocalization.logger .warning('Fallback localization key [$key] not found'); + } return key; } } diff --git a/lib/src/public.dart b/lib/src/public.dart index 9e487c68..9a9e0a57 100644 --- a/lib/src/public.dart +++ b/lib/src/public.dart @@ -31,11 +31,13 @@ import 'localization.dart'; /// Text('gender').tr(gender: _gender ? "female" : "male"), // gender /// ``` /// {@endtemplate} -String? tr(String key, - {BuildContext? context, - List? args, - Map? namedArgs, - String? gender}) { +String tr( + String key, { + BuildContext? context, + List? args, + Map? namedArgs, + String? gender, +}) { return context == null ? Localization.instance .tr(key, args: args, namedArgs: namedArgs, gender: gender) @@ -83,8 +85,13 @@ String? tr(String key, /// var money = plural('money_args', 10.23, args: ['John', '10.23']) // output: John has 10.23 dollars /// ``` /// {@endtemplate} -String? plural(String key, num value, - {BuildContext? context, List? args, NumberFormat? format}) { +String plural( + String key, + num value, { + BuildContext? context, + List? args, + NumberFormat? format, +}) { return context == null ? Localization.instance.plural(key, value, args: args, format: format) : Localization.of(context)! diff --git a/lib/src/public_ext.dart b/lib/src/public_ext.dart index a44647c2..48b3551c 100644 --- a/lib/src/public_ext.dart +++ b/lib/src/public_ext.dart @@ -4,7 +4,7 @@ import 'package:intl/intl.dart'; import 'easy_localization_app.dart'; import 'public.dart' as ez; -/// Text widget extension method for acces to [tr()] and [plural()] +/// Text widget extension method for access to [tr()] and [plural()] /// Example : /// ```drat /// Text('title').tr() @@ -18,11 +18,11 @@ extension TextTranslateExtension on Text { Map? namedArgs, String? gender}) => Text( - ez.tr(data!, + ez.tr(data ?? '', context: context, args: args, namedArgs: namedArgs, - gender: gender)!, + gender: gender), key: key, style: style, strutStyle: strutStyle, @@ -40,8 +40,13 @@ extension TextTranslateExtension on Text { Text plural(num value, {BuildContext? context, List? args, NumberFormat? format}) => Text( - ez.plural(data!, value, - context: context, args: args, format: format)!, + ez.plural( + data ?? '', + value, + context: context, + args: args, + format: format, + ), key: key, style: style, strutStyle: strutStyle, @@ -56,7 +61,7 @@ extension TextTranslateExtension on Text { textWidthBasis: textWidthBasis); } -/// Strings extension method for acces to [tr()] and [plural()] +/// Strings extension method for access to [tr()] and [plural()] /// Example : /// ```drat /// 'title'.tr() @@ -64,18 +69,23 @@ extension TextTranslateExtension on Text { /// ``` extension StringTranslateExtension on String { /// {@macro tr} - String? tr( - {List? args, - Map? namedArgs, - String? gender}) => + String tr({ + List? args, + Map? namedArgs, + String? gender, + }) => ez.tr(this, args: args, namedArgs: namedArgs, gender: gender); /// {@macro plural} - String? plural(num value, {List? args, NumberFormat? format}) => + String plural( + num value, { + List? args, + NumberFormat? format, + }) => ez.plural(this, value, args: args, format: format); } -/// BuildContext extension method for acces to [locale], [supportedLocales], [fallbackLocale], [delegates] and [deleteSaveLocale()] +/// BuildContext extension method for access to [locale], [supportedLocales], [fallbackLocale], [delegates] and [deleteSaveLocale()] /// /// Example : /// @@ -110,7 +120,7 @@ extension BuildContextEasyLocalizationExtension on BuildContext { Locale? get fallbackLocale => EasyLocalization.of(this)!.fallbackLocale; /// {@macro flutter.widgets.widgetsApp.localizationsDelegates} - /// retrun + /// return /// ```dart /// delegates = [ /// delegate @@ -127,7 +137,7 @@ extension BuildContextEasyLocalizationExtension on BuildContext { EasyLocalization.of(this)!.deleteSaveLocale(); /// Getting device locale from platform - Locale? get deviceLocale => EasyLocalization.of(this)!.deviceLocale; + Locale get deviceLocale => EasyLocalization.of(this)!.deviceLocale; /// Reset locale to platform locale Future resetLocale() => EasyLocalization.of(this)!.resetLocale(); diff --git a/lib/src/translations.dart b/lib/src/translations.dart index f0a933c1..b1ae47d7 100644 --- a/lib/src/translations.dart +++ b/lib/src/translations.dart @@ -20,8 +20,9 @@ class Translations { if (value is Map) value = value[keys[i]]; } - if (value == null) + if (value == null) { throw Exception('Cannot cache a key that is not nested.'); + } cacheNestedKey(key, value); return value; diff --git a/pubspec.yaml b/pubspec.yaml index 258405c0..24a51d7a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,9 +14,9 @@ dependencies: flutter: sdk: flutter shared_preferences: ^2.0.0-nullsafety - intl: ^0.17.0 + intl: '>=0.17.0-0 <=0.17.0' args: ^2.0.0 - path: ^1.8.0 + path: '>=1.8.0-0 <=1.8.0' easy_logger: path: packages/easy_logger flutter_localizations: From e44dd4ea79e7e01e2751b3ac95bbbcca31b87599 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Wed, 17 Feb 2021 13:56:35 +0500 Subject: [PATCH 41/52] update icons and disable easy_localization_loader --- example/lib/main.dart | 56 +++++++++++++++++++++---------------------- example/pubspec.yaml | 2 +- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 04333508..16a85348 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,9 +1,9 @@ import 'dart:ui'; import 'package:easy_localization/easy_localization.dart'; -import 'package:easy_localization_loader/easy_localization_loader.dart'; +//import 'package:easy_localization_loader/easy_localization_loader.dart'; // import custom loaders import 'package:flutter/material.dart'; -import 'package:flutter_icons/flutter_icons.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'generated/locale_keys.g.dart'; import 'lang_view.dart'; @@ -13,31 +13,31 @@ void main() async { await EasyLocalization.ensureInitialized(); runApp(EasyLocalization( - child: MyApp(), - supportedLocales: [ - Locale('en', 'US'), - Locale('ar', 'DZ'), - Locale('de', 'DE'), - Locale('ru', 'RU') - ], - path: 'resources/langs/langs.csv', //'resources/langs', - // fallbackLocale: Locale('en', 'US'), - // startLocale: Locale('de', 'DE'), - // saveLocale: false, - // useOnlyLangCode: true, + child: MyApp(), + supportedLocales: [ + Locale('en', 'US'), + Locale('ar', 'DZ'), + Locale('de', 'DE'), + Locale('ru', 'RU') + ], + path: 'resources/langs', + // fallbackLocale: Locale('en', 'US'), + // startLocale: Locale('de', 'DE'), + // saveLocale: false, + // useOnlyLangCode: true, - // optional assetLoader default used is RootBundleAssetLoader which uses flutter's assetloader - // install easy_localization_loader for enable custom loaders - // assetLoader: RootBundleAssetLoader() - // assetLoader: HttpAssetLoader() - // assetLoader: FileAssetLoader() - assetLoader: CsvAssetLoader() - // assetLoader: YamlAssetLoader() //multiple files - // assetLoader: YamlSingleAssetLoader() //single file - // assetLoader: XmlAssetLoader() //multiple files - // assetLoader: XmlSingleAssetLoader() //single file - // assetLoader: CodegenLoader() - )); + // optional assetLoader default used is RootBundleAssetLoader which uses flutter's assetloader + // install easy_localization_loader for enable custom loaders + // assetLoader: RootBundleAssetLoader() + // assetLoader: HttpAssetLoader() + // assetLoader: FileAssetLoader() + // assetLoader: CsvAssetLoader() + // assetLoader: YamlAssetLoader() //multiple files + // assetLoader: YamlSingleAssetLoader() //single file + // assetLoader: XmlAssetLoader() //multiple files + // assetLoader: XmlSingleAssetLoader() //single file + // assetLoader: CodegenLoader() + )); } class MyApp extends StatelessWidget { @@ -125,9 +125,9 @@ class _MyHomePageState extends State { Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(FontAwesome.male), + FaIcon(FontAwesomeIcons.male), Switch(value: _gender, onChanged: switchGender), - Icon(FontAwesome.female), + FaIcon(FontAwesomeIcons.female), ], ), Spacer( diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 44dbf078..d5362f20 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -25,7 +25,7 @@ dependencies: cupertino_icons: ^1.0.2 easy_localization: path: ../ - flutter_icons: ^1.1.0 + font_awesome_flutter: 9.0.0-nullsafety #custom loaders easy_localization_loader: From 96a3707fdb0856dd38348e94cca0aac271ff6f8b Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Wed, 17 Feb 2021 15:47:38 +0500 Subject: [PATCH 42/52] fix bug empty _translations in null safety --- lib/src/localization.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/localization.dart b/lib/src/localization.dart index d05b0e81..2ed87bbf 100644 --- a/lib/src/localization.dart +++ b/lib/src/localization.dart @@ -168,7 +168,7 @@ class Localization { } String _resolve(String key, {bool logging = true}) { - var resource = _translations!.get(key); + var resource = _translations?.get(key); if (resource == null) { if (logging) { EasyLocalization.logger.warning('Localization key [$key] not found'); @@ -176,7 +176,7 @@ class Localization { if (_fallbackTranslations == null) { return key; } else { - resource = _fallbackTranslations!.get(key); + resource = _fallbackTranslations?.get(key); if (resource == null) { if (logging) { EasyLocalization.logger From ac76815b8e94e03dc91b364846aa9147c3ae6d0e Mon Sep 17 00:00:00 2001 From: Andrew Coutts Date: Fri, 19 Feb 2021 09:36:12 -0500 Subject: [PATCH 43/52] Fix crash when a key containing periods doesn't exist. Fixed shared preferences null exception during unit tests --- example/ios/Flutter/Debug.xcconfig | 1 + example/ios/Flutter/Release.xcconfig | 1 + lib/src/translations.dart | 23 ++++++++++++++++++----- test/easy_localization_context_test.dart | 2 +- test/easy_localization_test.dart | 14 ++++++++++++++ test/utils/test_asset_loaders.dart | 4 ++++ 6 files changed, 39 insertions(+), 6 deletions(-) diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig index e8efba11..b2f5fae9 100644 --- a/example/ios/Flutter/Debug.xcconfig +++ b/example/ios/Flutter/Debug.xcconfig @@ -1,2 +1,3 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig index 399e9340..88c29144 100644 --- a/example/ios/Flutter/Release.xcconfig +++ b/example/ios/Flutter/Release.xcconfig @@ -1,2 +1,3 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/lib/src/translations.dart b/lib/src/translations.dart index b1ae47d7..6dd89b59 100644 --- a/lib/src/translations.dart +++ b/lib/src/translations.dart @@ -3,8 +3,20 @@ class Translations { final Map _nestedKeysCache; Translations(this._translations) : _nestedKeysCache = {}; - String? get(String key) => - (isNestedKey(key) ? getNested(key) : _translations![key]); + String? get(String key) { + String? returnValue; + + /// Try to look it up as a nested key + if (isNestedKey(key)) { + returnValue = getNested(key); + } + + /// If we failed to find the key as a nested key, then fall back + /// to looking it up like normal. + returnValue ??= _translations?[key]; + + return returnValue; + } String? getNested(String key) { if (isNestedCached(key)) return _nestedKeysCache[key]; @@ -20,11 +32,12 @@ class Translations { if (value is Map) value = value[keys[i]]; } - if (value == null) { - throw Exception('Cannot cache a key that is not nested.'); + /// If we found the value, cache it. If the value is null then + /// we're not going to cache it, and returning null instead. + if (value != null) { + cacheNestedKey(key, value); } - cacheNestedKey(key, value); return value; } diff --git a/test/easy_localization_context_test.dart b/test/easy_localization_context_test.dart index 70dbbf91..c66a5d80 100644 --- a/test/easy_localization_context_test.dart +++ b/test/easy_localization_context_test.dart @@ -38,8 +38,8 @@ class MyWidget extends StatelessWidget { } void main() async { - await EasyLocalization.ensureInitialized(); SharedPreferences.setMockInitialValues({}); + await EasyLocalization.ensureInitialized(); EasyLocalization.logger.enableLevels = [ LevelMessages.error, LevelMessages.warning, diff --git a/test/easy_localization_test.dart b/test/easy_localization_test.dart index d1f42fbc..c72ca499 100644 --- a/test/easy_localization_test.dart +++ b/test/easy_localization_test.dart @@ -151,6 +151,20 @@ void main() { ); }); + test('won\'t fail for missing key (no periods)', () { + expect( + Localization.instance.tr('Processing'), + 'Processing', + ); + }); + + test('won\'t fail for missing key with periods', () { + expect( + Localization.instance.tr('Processing.'), + 'Processing.', + ); + }); + test('can resolve linked locale messages', () { expect(Localization.instance.tr('linked'), 'this is linked'); }); diff --git a/test/utils/test_asset_loaders.dart b/test/utils/test_asset_loaders.dart index 12b935e1..cb438f06 100644 --- a/test/utils/test_asset_loaders.dart +++ b/test/utils/test_asset_loaders.dart @@ -30,6 +30,10 @@ class JsonAssetLoader extends AssetLoader { 'one': '{} has {} dollar', 'other': '{} has {} dollars', }, + 'nested_periods': { + 'Processing': 'Processing', + 'Processing.': 'Processing.', + }, 'nested.but.not.nested': 'nested but not nested', 'linked': 'this @:isLinked', 'isLinked': 'is linked', From 5883c340b95b09ec1dbd0b39435501d7030ae7bd Mon Sep 17 00:00:00 2001 From: Andrew Coutts Date: Fri, 19 Feb 2021 09:42:43 -0500 Subject: [PATCH 44/52] easy_logger from pub so it's a valid import again --- pubspec.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index 24a51d7a..50171f2e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,8 +17,7 @@ dependencies: intl: '>=0.17.0-0 <=0.17.0' args: ^2.0.0 path: '>=1.8.0-0 <=1.8.0' - easy_logger: - path: packages/easy_logger + easy_logger: ^0.0.2-nullsafety flutter_localizations: sdk: flutter From 9fe03e916f3213c58edf12d3ba0b97766504b6ae Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sat, 20 Feb 2021 14:14:36 +0500 Subject: [PATCH 45/52] fix easy_logger depence --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 50171f2e..0b93b862 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/aissat/easy_localization issue_tracker: https://github.com/aissat/easy_localization/issues publish_to: none -version: 3.0.0-nullsafety +version: 3.0.0-nullsafety.1 environment: sdk: '>=2.12.0-0 <3.0.0' From c8501dbc2f1adcbdcaf61efdc8836601c9748456 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sat, 20 Feb 2021 14:29:11 +0500 Subject: [PATCH 46/52] added info about fallback locale keys redirection --- CHANGELOG.md | 3 ++- README.md | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1817a17f..d8014bb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,17 +2,18 @@ ### [3.0.0] +- **BREAKING**: Added `EasyLocalization.ensureInitialized()`, Needs to be called - Added Formatting linked translations [more](https://github.com/aissat/easy_localization#linked-translations) - Updated `plural()` function, with arguments [more](https://github.com/aissat/easy_localization#linked-translations) ```dart var money = plural('money_args', 10.23, args: ['John', '10.23']) // output: John has 10.23 dollars ``` - Removed preloader widget ~~`preloaderWidget`~~ -- Added `EasyLocalization.ensureInitialized()`, Needs to be called - fixed many issues. - customizable logger [EasyLogger] - device locale and reset device locale - extensions helpers +- support fallback locale keys redirection ### [2.3.3] diff --git a/README.md b/README.md index 69cf7559..6eb2fb3b 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ Easy and Fast internationalization for your Flutter Apps - 🔌 Load translations as JSON, CSV, Yaml, Xml using [Easy Localization Loader](https://github.com/aissat/easy_localization_loader) - 💾 React and persist to locale changes - ⚡ Supports plural, gender, nesting, RTL locales and more +- ↩️ Fallback locale keys redirection - ⁉️ Error widget for missing translations - ❤️ Extension methods on `Text` and `BuildContext` - 💻 Code generation for localization files and keys. From c09be0eb340b9c17a31ddeffe8145af2358a36a2 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sat, 20 Feb 2021 15:43:06 +0500 Subject: [PATCH 47/52] remove context from tr() and plural() --- lib/src/public.dart | 14 +-- lib/src/public_ext.dart | 12 +- test/easy_localization_context_test.dart | 145 ----------------------- test/easy_localization_widget_test.dart | 48 ++++---- 4 files changed, 33 insertions(+), 186 deletions(-) diff --git a/lib/src/public.dart b/lib/src/public.dart index 9a9e0a57..91f806d3 100644 --- a/lib/src/public.dart +++ b/lib/src/public.dart @@ -33,16 +33,12 @@ import 'localization.dart'; /// {@endtemplate} String tr( String key, { - BuildContext? context, List? args, Map? namedArgs, String? gender, }) { - return context == null - ? Localization.instance - .tr(key, args: args, namedArgs: namedArgs, gender: gender) - : Localization.of(context)! - .tr(key, args: args, namedArgs: namedArgs, gender: gender); + return Localization.instance + .tr(key, args: args, namedArgs: namedArgs, gender: gender); } /// {@template plural} @@ -88,12 +84,8 @@ String tr( String plural( String key, num value, { - BuildContext? context, List? args, NumberFormat? format, }) { - return context == null - ? Localization.instance.plural(key, value, args: args, format: format) - : Localization.of(context)! - .plural(key, value, args: args, format: format); + return Localization.instance.plural(key, value, args: args, format: format); } diff --git a/lib/src/public_ext.dart b/lib/src/public_ext.dart index 48b3551c..cdc8ec56 100644 --- a/lib/src/public_ext.dart +++ b/lib/src/public_ext.dart @@ -18,11 +18,12 @@ extension TextTranslateExtension on Text { Map? namedArgs, String? gender}) => Text( - ez.tr(data ?? '', - context: context, - args: args, - namedArgs: namedArgs, - gender: gender), + ez.tr( + data ?? '', + args: args, + namedArgs: namedArgs, + gender: gender, + ), key: key, style: style, strutStyle: strutStyle, @@ -43,7 +44,6 @@ extension TextTranslateExtension on Text { ez.plural( data ?? '', value, - context: context, args: args, format: format, ), diff --git a/test/easy_localization_context_test.dart b/test/easy_localization_context_test.dart index c66a5d80..12b05f38 100644 --- a/test/easy_localization_context_test.dart +++ b/test/easy_localization_context_test.dart @@ -46,151 +46,6 @@ void main() async { ]; group('BuildContext', () { - testWidgets( - '[EasyLocalization] locale test', - (WidgetTester tester) async { - await tester.runAsync(() async { - await tester.pumpWidget(EasyLocalization( - child: MyApp(), - path: 'i18n', - supportedLocales: [Locale('en', 'US')], - )); - // await tester.idle(); - // The async delegator load will require build on the next frame. Thus, pump - // await tester.pump(); - await tester.pump(); - - expect(_context.supportedLocales, [Locale('en', 'US')]); - expect(_context.locale, Locale('en', 'US')); - - var l = Locale('en', 'US'); - await _context.setLocale(l); - await tester.pump(); - expect(_context.locale, Locale('en', 'US')); - - final trFinder = find.text('test'); - expect(trFinder, findsOneWidget); - final pluralFinder = find.text('1 day'); - expect(pluralFinder, findsOneWidget); - - expect(tr('test', context: _context), 'test'); - expect(plural('day', 1, context: _context), '1 day'); - expect(plural('day', 2, context: _context), '2 days'); - expect(plural('day', 3, context: _context), '3 other days'); - expect(_context.locale, Locale('en', 'US')); - - l = Locale('ar', 'DZ'); - expect(() async { - await _context.setLocale(l); - }, throwsAssertionError); - await tester.pump(); - expect(_context.locale, Locale('en', 'US')); - }); - }, - ); - - testWidgets( - '[EasyLocalization] change loacle test', - (WidgetTester tester) async { - await tester.runAsync(() async { - await tester.pumpWidget(EasyLocalization( - child: MyApp(), - path: 'i18n', - supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], - )); - // await tester.idle(); - // The async delegator load will require build on the next frame. Thus, pump - await tester.pump(); - - expect(Localization.of(_context), isInstanceOf()); - expect(_context.supportedLocales, - [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(_context.locale, Locale('en', 'US')); - - var trFinder = find.text('test'); - expect(trFinder, findsOneWidget); - var pluralFinder = find.text('1 day'); - expect(pluralFinder, findsOneWidget); - - expect(tr('test', context: _context), 'test'); - expect(plural('day', 1, context: _context), '1 day'); - expect(plural('day', 2, context: _context), '2 days'); - expect(plural('day', 3, context: _context), '3 other days'); - - var l = Locale('en', 'US'); - await _context.setLocale(l); - await tester.pump(); - expect(_context.locale, l); - - l = Locale('ar', 'DZ'); - await _context.setLocale(l); - // await tester.idle(); - await tester.pump(); - expect(_context.locale, l); - - l = Locale('en', 'US'); - await _context.setLocale(l); - // await tester.idle(); - await tester.pump(); - expect(_context.locale, l); - - l = Locale('en', 'UK'); - expect( - () async => {await _context.setLocale(l)}, throwsAssertionError); - - l = Locale('ar', 'DZ'); - await _context.setLocale(l); - // await tester.idle(); - await tester.pump(); - expect(_context.locale, l); - }); - }, - ); - - testWidgets( - '[EasyLocalization] loacle ar_DZ test', - (WidgetTester tester) async { - await tester.runAsync(() async { - await tester.pumpWidget(EasyLocalization( - child: MyApp(), - path: 'i18n', - supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')], - )); - - // await tester.idle(); - // The async delegator load will require build on the next frame. Thus, pump - await tester.pump(); - - await _context.setLocale(Locale('ar', 'DZ')); - - await tester.pump(); - - expect(_context.supportedLocales, - [Locale('en', 'US'), Locale('ar', 'DZ')]); - expect(_context.locale, Locale('ar', 'DZ')); - - var trFinder = find.text('اختبار'); - expect(trFinder, findsOneWidget); - var pluralFinder = find.text('1 يوم'); - expect(pluralFinder, findsOneWidget); - - expect(Localization.of(_context), isInstanceOf()); - expect(tr('test', context: _context), 'اختبار'); - expect(plural('day', 1, context: _context), '1 يوم'); - expect(plural('day', 2, context: _context), '2 أيام'); - expect(plural('day', 3, context: _context), '3 أيام'); - - var l = Locale('en', 'US'); - await _context.setLocale(l); - expect(_context.locale, l); - - l = Locale('ar', 'DZ'); - await _context.setLocale(l); - expect(_context.locale, l); - }); - }, - ); - testWidgets( '[EasyLocalization] _getFallbackLocale() fallbackLocale!=null test', (WidgetTester tester) async { diff --git a/test/easy_localization_widget_test.dart b/test/easy_localization_widget_test.dart index f3fb8528..d6d760e6 100644 --- a/test/easy_localization_widget_test.dart +++ b/test/easy_localization_widget_test.dart @@ -72,10 +72,10 @@ void main() async { final pluralFinder = find.text('1 day'); expect(pluralFinder, findsOneWidget); - expect(tr('test', context: _context), 'test'); - expect(plural('day', 1, context: _context), '1 day'); - expect(plural('day', 2, context: _context), '2 days'); - expect(plural('day', 3, context: _context), '3 other days'); + expect(tr('test'), 'test'); + expect(plural('day', 1), '1 day'); + expect(plural('day', 2), '2 days'); + expect(plural('day', 3), '3 other days'); expect('test'.tr(), 'test'); expect('day'.plural(1), '1 day'); @@ -105,10 +105,10 @@ void main() async { expect(trFinder, findsOneWidget); final pluralFinder = find.text('1 day'); expect(pluralFinder, findsOneWidget); - expect(tr('test', context: _context), 'test'); - expect(plural('day', 1, context: _context), '1 day'); - expect(plural('day', 2, context: _context), '2 days'); - expect(plural('day', 3, context: _context), '3 other days'); + expect(tr('test'), 'test'); + expect(plural('day', 1), '1 day'); + expect(plural('day', 2), '2 days'); + expect(plural('day', 3), '3 other days'); }); }, ); @@ -135,10 +135,10 @@ void main() async { final pluralFinder = find.text('1 day'); expect(pluralFinder, findsOneWidget); - expect(tr('test', context: _context), 'test'); - expect(plural('day', 1, context: _context), '1 day'); - expect(plural('day', 2, context: _context), '2 days'); - expect(plural('day', 3, context: _context), '3 other days'); + expect(tr('test'), 'test'); + expect(plural('day', 1), '1 day'); + expect(plural('day', 2), '2 days'); + expect(plural('day', 3), '3 other days'); }); }, ); @@ -188,10 +188,10 @@ void main() async { final pluralFinder = find.text('1 day'); expect(pluralFinder, findsOneWidget); - expect(tr('test', context: _context), 'test'); - expect(plural('day', 1, context: _context), '1 day'); - expect(plural('day', 2, context: _context), '2 days'); - expect(plural('day', 3, context: _context), '3 other days'); + expect(tr('test'), 'test'); + expect(plural('day', 1), '1 day'); + expect(plural('day', 2), '2 days'); + expect(plural('day', 3), '3 other days'); expect(EasyLocalization.of(_context)!.locale, Locale('en', 'US')); l = Locale('ar', 'DZ'); @@ -227,10 +227,10 @@ void main() async { var pluralFinder = find.text('1 day'); expect(pluralFinder, findsOneWidget); - expect(tr('test', context: _context), 'test'); - expect(plural('day', 1, context: _context), '1 day'); - expect(plural('day', 2, context: _context), '2 days'); - expect(plural('day', 3, context: _context), '3 other days'); + expect(tr('test'), 'test'); + expect(plural('day', 1), '1 day'); + expect(plural('day', 2), '2 days'); + expect(plural('day', 3), '3 other days'); var l = Locale('en', 'US'); await EasyLocalization.of(_context)!.setLocale(l); @@ -290,10 +290,10 @@ void main() async { expect(pluralFinder, findsOneWidget); expect(Localization.of(_context), isInstanceOf()); - expect(tr('test', context: _context), 'اختبار'); - expect(plural('day', 1, context: _context), '1 يوم'); - expect(plural('day', 2, context: _context), '2 أيام'); - expect(plural('day', 3, context: _context), '3 أيام'); + expect(tr('test'), 'اختبار'); + expect(plural('day', 1), '1 يوم'); + expect(plural('day', 2), '2 أيام'); + expect(plural('day', 3), '3 أيام'); // var l = Locale('en', 'US'); // EasyLocalization.of(_context).locale = l; From 6da8badf951c274095c37f7f52548b9423f093ea Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sat, 20 Feb 2021 15:45:16 +0500 Subject: [PATCH 48/52] update readme --- CHANGELOG.md | 2 ++ README.md | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8014bb0..4cdf13ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ### [3.0.0] - **BREAKING**: Added `EasyLocalization.ensureInitialized()`, Needs to be called +- **BREAKING**: Added support null safety +- **BREAKING**: removed context parameter from `plural()` and `tr()` - Added Formatting linked translations [more](https://github.com/aissat/easy_localization#linked-translations) - Updated `plural()` function, with arguments [more](https://github.com/aissat/easy_localization#linked-translations) ```dart diff --git a/README.md b/README.md index 6eb2fb3b..50ba71ed 100644 --- a/README.md +++ b/README.md @@ -198,7 +198,6 @@ var title = tr('title') //Static function | Name | Type | Description | | -------- | -------- | -------- | -| context| `BuildContext` | The location in the tree where this widget builds | | args| `List` | List of localized strings. Replaces `{}` left to right | | namedArgs| `Map` | Map of localized strings. Replaces the name keys `{key_name}` according to its name | | gender | `String` | Gender switcher. Changes the localized string based on gender string | @@ -244,7 +243,6 @@ You can use extension methods of [String] or [Text] widget, you can also use `pl | Name | Type | Description | | -------- | -------- | -------- | -| context| `BuildContext` | The location in the tree where this widget builds| | value| `num` | Number value for pluralization | | args| `List` | List of localized strings. Replaces `{}` left to right | | format| `NumberFormat` | Formats a numeric value using a [NumberFormat](https://pub.dev/documentation/intl/latest/intl/NumberFormat-class.html) class | From 2ef586d5e4fa0be25de6e545dd0bb2066efe52f0 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sat, 20 Feb 2021 15:48:20 +0500 Subject: [PATCH 49/52] remove missed context from tr() and plural() --- lib/src/public_ext.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/src/public_ext.dart b/lib/src/public_ext.dart index cdc8ec56..e49585ee 100644 --- a/lib/src/public_ext.dart +++ b/lib/src/public_ext.dart @@ -13,8 +13,7 @@ import 'public.dart' as ez; extension TextTranslateExtension on Text { /// {@macro tr} Text tr( - {BuildContext? context, - List? args, + {List? args, Map? namedArgs, String? gender}) => Text( @@ -38,8 +37,11 @@ extension TextTranslateExtension on Text { textWidthBasis: textWidthBasis); /// {@macro plural} - Text plural(num value, - {BuildContext? context, List? args, NumberFormat? format}) => + Text plural( + num value, { + List? args, + NumberFormat? format, + }) => Text( ez.plural( data ?? '', From bfc7707992d3f9a89d44d22ca9b90c3dd0e42971 Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sat, 20 Feb 2021 15:48:58 +0500 Subject: [PATCH 50/52] update example --- example/lib/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 16a85348..4fd62a5b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -84,7 +84,7 @@ class _MyHomePageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(LocaleKeys.title).tr(context: context), + title: Text(LocaleKeys.title).tr(), actions: [ TextButton( child: Icon( From c5454cf4287ee806097ca15ebc594aa4f44a299f Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sat, 20 Feb 2021 15:53:51 +0500 Subject: [PATCH 51/52] remove missed context from tr() and plural() --- test/easy_localization_context_test.dart | 5 ++--- test/easy_localization_widget_test.dart | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/test/easy_localization_context_test.dart b/test/easy_localization_context_test.dart index 12b05f38..5e90eace 100644 --- a/test/easy_localization_context_test.dart +++ b/test/easy_localization_context_test.dart @@ -1,7 +1,6 @@ import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; -import 'package:easy_localization/src/localization.dart'; import 'package:easy_logger/easy_logger.dart'; import 'package:flutter/material.dart'; @@ -29,8 +28,8 @@ class MyWidget extends StatelessWidget { return Scaffold( body: Column( children: [ - Text('test').tr(context: context), - Text('day').plural(1, context: context), + Text('test').tr(), + Text('day').plural(1), ], ), ); diff --git a/test/easy_localization_widget_test.dart b/test/easy_localization_widget_test.dart index d6d760e6..547b7f84 100644 --- a/test/easy_localization_widget_test.dart +++ b/test/easy_localization_widget_test.dart @@ -30,8 +30,8 @@ class MyWidget extends StatelessWidget { return Scaffold( body: Column( children: [ - Text('test').tr(context: context), - Text('day').plural(1, context: context), + Text('test').tr(), + Text('day').plural(1), ], ), ); From 05b9e283e8421bf83985a6cc94d731e528d6223c Mon Sep 17 00:00:00 2001 From: Alexey Zdorovykh Date: Sat, 20 Feb 2021 15:54:50 +0500 Subject: [PATCH 52/52] upper easy logger setting in tests --- test/easy_localization_context_test.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/easy_localization_context_test.dart b/test/easy_localization_context_test.dart index 5e90eace..4209de7c 100644 --- a/test/easy_localization_context_test.dart +++ b/test/easy_localization_context_test.dart @@ -37,13 +37,14 @@ class MyWidget extends StatelessWidget { } void main() async { - SharedPreferences.setMockInitialValues({}); - await EasyLocalization.ensureInitialized(); EasyLocalization.logger.enableLevels = [ LevelMessages.error, LevelMessages.warning, ]; + SharedPreferences.setMockInitialValues({}); + await EasyLocalization.ensureInitialized(); + group('BuildContext', () { testWidgets( '[EasyLocalization] _getFallbackLocale() fallbackLocale!=null test',