From ff55e8b203a0bc4e793851eb1e3c0e504f2e99d8 Mon Sep 17 00:00:00 2001 From: Matteo Pietro Dazzi Date: Wed, 10 Jul 2024 21:34:36 +0200 Subject: [PATCH 1/7] feat: extract defineLocale function --- lib/loaders/file_translation_loader.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/loaders/file_translation_loader.dart b/lib/loaders/file_translation_loader.dart index ea0d4bc..9905357 100644 --- a/lib/loaders/file_translation_loader.dart +++ b/lib/loaders/file_translation_loader.dart @@ -48,6 +48,7 @@ class FileTranslationLoader extends TranslationLoader implements IFileContent { /// Return the translation Map Future load() async { _decodedMap = Map(); + await this._defineLocale(); await _loadCurrentTranslation(); await _loadFallback(); return _decodedMap; @@ -62,14 +63,17 @@ class FileTranslationLoader extends TranslationLoader implements IFileContent { Future _loadCurrentTranslation() async { try { - this.locale = locale ?? await findDeviceLocale(); - MessagePrinter.info("The current locale is ${this.locale}"); _decodedMap.addAll(await loadFile(composeFileName())); } catch (e) { MessagePrinter.debug('Error loading translation $e'); } } + Future _defineLocale() async { + this.locale = locale ?? await findDeviceLocale(); + MessagePrinter.info("The current locale is ${this.locale}"); + } + Future _loadFallback() async { try { final Map fallbackMap = await loadFile(fallbackFile); From 1d391d54e8ebd2199adc5a8a7fd0ad32bda1d900 Mon Sep 17 00:00:00 2001 From: Matteo Pietro Dazzi Date: Wed, 10 Jul 2024 21:41:50 +0200 Subject: [PATCH 2/7] fix: avoid double call --- lib/loaders/file_translation_loader.dart | 26 ++++++++++-------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/lib/loaders/file_translation_loader.dart b/lib/loaders/file_translation_loader.dart index 9905357..e267b81 100644 --- a/lib/loaders/file_translation_loader.dart +++ b/lib/loaders/file_translation_loader.dart @@ -48,9 +48,14 @@ class FileTranslationLoader extends TranslationLoader implements IFileContent { /// Return the translation Map Future load() async { _decodedMap = Map(); + final fileName = composeFileName(); await this._defineLocale(); - await _loadCurrentTranslation(); - await _loadFallback(); + _decodedMap.addAll(await _loadTranslation(fileName, false)); + if (fileName != fallbackFile) { + final Map fallbackMap = await _loadTranslation(fallbackFile, true); + _decodedMap = _deepMergeMaps(fallbackMap, _decodedMap); + MessagePrinter.debug('Fallback maps have been merged'); + } return _decodedMap; } @@ -61,11 +66,12 @@ class FileTranslationLoader extends TranslationLoader implements IFileContent { cache: false); } - Future _loadCurrentTranslation() async { + Future _loadTranslation(String fileName, bool isFallback) async { try { - _decodedMap.addAll(await loadFile(composeFileName())); + return await loadFile(fileName); } catch (e) { - MessagePrinter.debug('Error loading translation $e'); + MessagePrinter.debug( + 'Error loading translation${isFallback ? " fallback " : " "}$e'); } } @@ -74,16 +80,6 @@ class FileTranslationLoader extends TranslationLoader implements IFileContent { MessagePrinter.info("The current locale is ${this.locale}"); } - Future _loadFallback() async { - try { - final Map fallbackMap = await loadFile(fallbackFile); - _decodedMap = _deepMergeMaps(fallbackMap, _decodedMap); - MessagePrinter.debug('Fallback maps have been merged'); - } catch (e) { - MessagePrinter.debug('Error loading translation fallback $e'); - } - } - Map _deepMergeMaps( Map map1, Map map2, From 0cc58e9f5ea8845845ff723471199689d77183c8 Mon Sep 17 00:00:00 2001 From: Matteo Pietro Dazzi Date: Wed, 10 Jul 2024 21:48:22 +0200 Subject: [PATCH 3/7] fix: make fallbackfile nullable --- example/lib/network_example.dart | 4 ++-- lib/loaders/file_translation_loader.dart | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/lib/network_example.dart b/example/lib/network_example.dart index 74037b0..68f4cb9 100644 --- a/example/lib/network_example.dart +++ b/example/lib/network_example.dart @@ -6,7 +6,7 @@ import 'package:flutter_i18n/loaders/decoders/json_decode_strategy.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; class CustomNetworkFileTranslationLoader extends NetworkFileTranslationLoader { - CustomNetworkFileTranslationLoader({required baseUri}) + CustomNetworkFileTranslationLoader(Uri baseUri) : super(baseUri: baseUri, decodeStrategies: [JsonDecodeStrategy()]); @override @@ -19,7 +19,7 @@ Future main() async { WidgetsFlutterBinding.ensureInitialized(); final FlutterI18nDelegate flutterI18nDelegate = FlutterI18nDelegate( translationLoader: CustomNetworkFileTranslationLoader( - baseUri: Uri.https("postman-echo.com", "get", + Uri.https("postman-echo.com", "get", {"title": "Basic network example", "content": "Translated content"}), ), ); diff --git a/lib/loaders/file_translation_loader.dart b/lib/loaders/file_translation_loader.dart index e267b81..7122130 100644 --- a/lib/loaders/file_translation_loader.dart +++ b/lib/loaders/file_translation_loader.dart @@ -14,7 +14,7 @@ import '../utils/message_printer.dart'; /// Loads translation files from JSON, YAML or XML format class FileTranslationLoader extends TranslationLoader implements IFileContent { - final String fallbackFile; + final String? fallbackFile; final String basePath; final String separator; final bool useCountryCode; @@ -51,8 +51,8 @@ class FileTranslationLoader extends TranslationLoader implements IFileContent { final fileName = composeFileName(); await this._defineLocale(); _decodedMap.addAll(await _loadTranslation(fileName, false)); - if (fileName != fallbackFile) { - final Map fallbackMap = await _loadTranslation(fallbackFile, true); + if (fallbackFile != null && fileName != fallbackFile) { + final Map fallbackMap = await _loadTranslation(fallbackFile!, true); _decodedMap = _deepMergeMaps(fallbackMap, _decodedMap); MessagePrinter.debug('Fallback maps have been merged'); } From c664c5779519ba99b78c4264e3f6decde562e50e Mon Sep 17 00:00:00 2001 From: Matteo Pietro Dazzi Date: Wed, 10 Jul 2024 21:56:51 +0200 Subject: [PATCH 4/7] feat: strict types --- lib/loaders/e2e_file_translation_loader.dart | 14 ++++---- lib/loaders/file_translation_loader.dart | 14 ++++---- lib/loaders/local_translation_loader.dart | 12 ++++--- .../namespace_file_translation_loader.dart | 18 +++++----- .../network_file_translation_loader.dart | 16 +++++---- test/test_loader.dart | 35 ++++++++++--------- 6 files changed, 59 insertions(+), 50 deletions(-) diff --git a/lib/loaders/e2e_file_translation_loader.dart b/lib/loaders/e2e_file_translation_loader.dart index 2d514d9..8b95b07 100644 --- a/lib/loaders/e2e_file_translation_loader.dart +++ b/lib/loaders/e2e_file_translation_loader.dart @@ -2,6 +2,8 @@ import 'dart:async'; import 'dart:convert'; import 'package:flutter/services.dart'; +import 'package:flutter_i18n/loaders/decoders/base_decode_strategy.dart'; +import 'package:flutter/widgets.dart'; import 'file_translation_loader.dart'; @@ -19,12 +21,12 @@ class E2EFileTranslationLoader extends FileTranslationLoader { AssetBundle customAssetBundle = _CustomAssetBundle(); E2EFileTranslationLoader( - {forcedLocale, - fallbackFile = "en", - basePath = "assets/flutter_i18n", - useCountryCode = false, - this.useE2E = true, - decodeStrategies}) + {Locale? forcedLocale, + String? fallbackFile = "en", + String basePath = "assets/flutter_i18n", + bool useCountryCode = false, + bool this.useE2E = true, + List? decodeStrategies}) : super( fallbackFile: fallbackFile, basePath: basePath, diff --git a/lib/loaders/file_translation_loader.dart b/lib/loaders/file_translation_loader.dart index 7122130..f9c7082 100644 --- a/lib/loaders/file_translation_loader.dart +++ b/lib/loaders/file_translation_loader.dart @@ -34,13 +34,13 @@ class FileTranslationLoader extends TranslationLoader implements IFileContent { ]; FileTranslationLoader( - {this.fallbackFile = "en", - this.basePath = "assets/flutter_i18n", - this.separator = "_", - this.useCountryCode = false, - this.useScriptCode = false, - forcedLocale, - decodeStrategies}) { + {String? this.fallbackFile = "en", + String this.basePath = "assets/flutter_i18n", + String this.separator = "_", + bool this.useCountryCode = false, + bool this.useScriptCode = false, + Locale? forcedLocale, + List? decodeStrategies}) { this.forcedLocale = forcedLocale; this.decodeStrategies = decodeStrategies; } diff --git a/lib/loaders/local_translation_loader.dart b/lib/loaders/local_translation_loader.dart index ff9ab80..408f6c0 100644 --- a/lib/loaders/local_translation_loader.dart +++ b/lib/loaders/local_translation_loader.dart @@ -1,14 +1,16 @@ import 'dart:io'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_i18n/loaders/decoders/base_decode_strategy.dart'; import 'package:flutter_i18n/loaders/file_translation_loader.dart'; class LocalTranslationLoader extends FileTranslationLoader { LocalTranslationLoader( - {basePath = "assets/flutter_i18n", - useCountryCode = false, - useScriptCode = false, - forcedLocale, - decodeStrategies}) + {String basePath = "assets/flutter_i18n", + bool useCountryCode = false, + bool useScriptCode = false, + Locale? forcedLocale, + List? decodeStrategies}) : super( basePath: basePath, useCountryCode: useCountryCode, diff --git a/lib/loaders/namespace_file_translation_loader.dart b/lib/loaders/namespace_file_translation_loader.dart index f9f7b36..447ba53 100644 --- a/lib/loaders/namespace_file_translation_loader.dart +++ b/lib/loaders/namespace_file_translation_loader.dart @@ -1,4 +1,6 @@ import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_i18n/loaders/decoders/base_decode_strategy.dart'; import 'package:flutter_i18n/loaders/file_translation_loader.dart'; import 'package:flutter_i18n/utils/message_printer.dart'; @@ -11,14 +13,14 @@ class NamespaceFileTranslationLoader extends FileTranslationLoader { Map _decodedMap = {}; NamespaceFileTranslationLoader( - {required this.namespaces, - this.fallbackDir = "en", - basePath = "assets/flutter_i18n", - separator = "_", - useCountryCode = false, - useScriptCode = false, - forcedLocale, - decodeStrategies}) + {required List? this.namespaces, + String this.fallbackDir = "en", + String basePath = "assets/flutter_i18n", + String separator = "_", + bool useCountryCode = false, + bool useScriptCode = false, + Locale? forcedLocale, + List? decodeStrategies}) : super( basePath: basePath, separator: separator, diff --git a/lib/loaders/network_file_translation_loader.dart b/lib/loaders/network_file_translation_loader.dart index a547ec6..f50bc9f 100644 --- a/lib/loaders/network_file_translation_loader.dart +++ b/lib/loaders/network_file_translation_loader.dart @@ -1,5 +1,7 @@ import 'dart:async'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_i18n/loaders/decoders/base_decode_strategy.dart'; import 'package:http/http.dart' as http; import 'file_translation_loader.dart'; @@ -9,13 +11,13 @@ class NetworkFileTranslationLoader extends FileTranslationLoader { final Uri baseUri; NetworkFileTranslationLoader( - {required this.baseUri, - forcedLocale, - fallbackFile = "en", - separator = "_", - useCountryCode = false, - useScriptCode = false, - decodeStrategies}) + {required Uri this.baseUri, + Locale? forcedLocale, + String fallbackFile = "en", + String separator = "_", + bool useCountryCode = false, + bool useScriptCode = false, + List? decodeStrategies}) : super( fallbackFile: fallbackFile, separator: separator, diff --git a/test/test_loader.dart b/test/test_loader.dart index d70161e..efee47a 100644 --- a/test/test_loader.dart +++ b/test/test_loader.dart @@ -1,7 +1,8 @@ +import 'package:flutter/widgets.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; +import 'package:flutter_i18n/loaders/decoders/toml_decode_strategy.dart'; import 'package:flutter_i18n/loaders/decoders/xml_decode_strategy.dart'; import 'package:flutter_i18n/loaders/decoders/yaml_decode_strategy.dart'; -import 'package:flutter_i18n/loaders/decoders/toml_decode_strategy.dart'; Future _loadString(String fileName, String extension) async { if (fileName.contains('_en')) { @@ -31,10 +32,10 @@ Future _loadString(String fileName, String extension) async { class TestJsonLoader extends FileTranslationLoader { TestJsonLoader({ - forcedLocale, - fallbackFile = "en", - basePath = "assets/flutter_i18n", - useCountryCode = false, + Locale? forcedLocale, + String fallbackFile = "en", + String basePath = "assets/flutter_i18n", + bool useCountryCode = false, }) : super( fallbackFile: fallbackFile, basePath: basePath, @@ -49,10 +50,10 @@ class TestJsonLoader extends FileTranslationLoader { class TestYamlLoader extends FileTranslationLoader { TestYamlLoader({ - forcedLocale, - fallbackFile = "en", - basePath = "assets/flutter_i18n", - useCountryCode = false, + Locale? forcedLocale, + String fallbackFile = "en", + String basePath = "assets/flutter_i18n", + bool useCountryCode = false, }) : super( fallbackFile: fallbackFile, basePath: basePath, @@ -77,10 +78,10 @@ class TestYamlLoader extends FileTranslationLoader { class TestTomlLoader extends FileTranslationLoader { TestTomlLoader({ - forcedLocale, - fallbackFile = "en", - basePath = "assets/flutter_i18n", - useCountryCode = false, + Locale? forcedLocale, + String fallbackFile = "en", + String basePath = "assets/flutter_i18n", + bool useCountryCode = false, }) : super( fallbackFile: fallbackFile, basePath: basePath, @@ -105,10 +106,10 @@ class TestTomlLoader extends FileTranslationLoader { class TestXmlLoader extends FileTranslationLoader { TestXmlLoader({ - forcedLocale, - fallbackFile = "en", - basePath = "assets/flutter_i18n", - useCountryCode = false, + Locale? forcedLocale, + String fallbackFile = "en", + String basePath = "assets/flutter_i18n", + bool useCountryCode = false, }) : super( fallbackFile: fallbackFile, basePath: basePath, From c288d44ce165b41f0a6fa2e16adc2f1d368b7707 Mon Sep 17 00:00:00 2001 From: Matteo Pietro Dazzi Date: Wed, 10 Jul 2024 22:04:02 +0200 Subject: [PATCH 5/7] fix: define locale --- lib/loaders/file_translation_loader.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/loaders/file_translation_loader.dart b/lib/loaders/file_translation_loader.dart index f9c7082..d201198 100644 --- a/lib/loaders/file_translation_loader.dart +++ b/lib/loaders/file_translation_loader.dart @@ -48,8 +48,8 @@ class FileTranslationLoader extends TranslationLoader implements IFileContent { /// Return the translation Map Future load() async { _decodedMap = Map(); - final fileName = composeFileName(); await this._defineLocale(); + final fileName = composeFileName(); _decodedMap.addAll(await _loadTranslation(fileName, false)); if (fallbackFile != null && fileName != fallbackFile) { final Map fallbackMap = await _loadTranslation(fallbackFile!, true); From d0bd0623450294a362b6116286b2c344bc75e24c Mon Sep 17 00:00:00 2001 From: Matteo Pietro Dazzi Date: Wed, 10 Jul 2024 22:10:00 +0200 Subject: [PATCH 6/7] fix: _loadTranslation --- lib/loaders/file_translation_loader.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/loaders/file_translation_loader.dart b/lib/loaders/file_translation_loader.dart index d201198..72c6612 100644 --- a/lib/loaders/file_translation_loader.dart +++ b/lib/loaders/file_translation_loader.dart @@ -66,13 +66,14 @@ class FileTranslationLoader extends TranslationLoader implements IFileContent { cache: false); } - Future _loadTranslation(String fileName, bool isFallback) async { + Future> _loadTranslation(String fileName, bool isFallback) async { try { return await loadFile(fileName); } catch (e) { MessagePrinter.debug( 'Error loading translation${isFallback ? " fallback " : " "}$e'); } + return Map(); } Future _defineLocale() async { From 312c950c380cbb889a4208c9cfd9a63e1d193a5b Mon Sep 17 00:00:00 2001 From: Matteo Pietro Dazzi Date: Wed, 10 Jul 2024 22:14:14 +0200 Subject: [PATCH 7/7] chore: test for fallback skip --- .../loaders/file_translation_loader_test.dart | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/test/loaders/file_translation_loader_test.dart b/test/loaders/file_translation_loader_test.dart index 3333cac..e6b823a 100644 --- a/test/loaders/file_translation_loader_test.dart +++ b/test/loaders/file_translation_loader_test.dart @@ -26,9 +26,8 @@ void main() { test('should deep merge fallback map', () async { var instance = FileTranslationLoader( - forcedLocale: Locale.fromSubtags(languageCode: "fr"), - fallbackFile: "en" - ); + forcedLocale: Locale.fromSubtags(languageCode: "fr"), + fallbackFile: "en"); instance.assetBundle = TestAssetBundleFallbackFrToEn(); var result = await instance.load(); @@ -44,6 +43,25 @@ void main() { expect(block["label2"], equals("Bonjour")); }); + test('should skip merge fallback map', () async { + var instance = FileTranslationLoader( + forcedLocale: Locale.fromSubtags(languageCode: "fr"), + fallbackFile: null); + instance.assetBundle = TestAssetBundleFallbackFrToEn(); + + var result = await instance.load(); + + expect(result, isMap); + expect(result, isNotEmpty); + expect(result["title"], equals("flutter_18n_fr")); + expect(result["sub_title"], equals(null)); + var block = result["block"]; + expect(block, isMap); + expect(block, isNotEmpty); + expect(block["label1"], equals(null)); + expect(block["label2"], equals("Bonjour")); + }); + test('`loadString` should load correct string', () async { final instance = TestJsonLoader(); final result = await instance.loadString("_fileName", "_extension"); @@ -51,21 +69,24 @@ void main() { expect(result, contains("_extension")); }); - test('`load` should load correct map from JSON with initial values', () async { + test('`load` should load correct map from JSON with initial values', + () async { final instance = TestJsonLoader(); final result = await instance.load(); expect(result["fileName"], "en"); expect(result["extension"], "json"); }); - test('`load` should load correct map from YAML with initial values', () async { + test('`load` should load correct map from YAML with initial values', + () async { final instance = TestYamlLoader(); final result = await instance.load(); expect(result["fileName"], "en"); expect(result["extension"], "yaml"); }); - test('`load` should load correct map from TOML with initial values', () async { + test('`load` should load correct map from TOML with initial values', + () async { final instance = TestTomlLoader(); final result = await instance.load(); expect(result["fileName"], "en");