feat(i18n): add arb, json and yaml parsers
This commit is contained in:
		
							parent
							
								
									0a55df8638
								
							
						
					
					
						commit
						8a37aec127
					
				
							
								
								
									
										13
									
								
								packages/wyatt_i18n/example/assets/i18n.en.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								packages/wyatt_i18n/example/assets/i18n.en.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
{
 | 
			
		||||
    "@@locale": "en",
 | 
			
		||||
    "youHavePushed": "You have pushed {count} times the bouton !",
 | 
			
		||||
    "@youHavePushed": {
 | 
			
		||||
        "placeholders": {
 | 
			
		||||
            "count": {
 | 
			
		||||
                "type": "int"
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "btnAddFile": "Add file",
 | 
			
		||||
    "btnAddFileCaption": "Max size: 20MB"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								packages/wyatt_i18n/example/assets/i18n.en.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								packages/wyatt_i18n/example/assets/i18n.en.yaml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
"@@locale": en
 | 
			
		||||
youHavePushed: You have pushed {count} times the bouton !
 | 
			
		||||
"@youHavePushed":
 | 
			
		||||
    placeholders:
 | 
			
		||||
        count:
 | 
			
		||||
            type: int
 | 
			
		||||
btnAddFile: Add file
 | 
			
		||||
btnAddFileCaption: "Max size: 20MB"
 | 
			
		||||
@ -45,8 +45,12 @@ class App extends StatelessWidget {
 | 
			
		||||
 | 
			
		||||
                const I18nRepository repository =
 | 
			
		||||
                    I18RepositoryImpl(dataSource: dataSource);
 | 
			
		||||
                
 | 
			
		||||
                final test = (await repository.load('en')).ok;
 | 
			
		||||
 | 
			
		||||
                print((await repository.load('fr')).err);
 | 
			
		||||
                print(test?.locale);
 | 
			
		||||
                print(test?.data);
 | 
			
		||||
                print(test?.data['btnAddFile']);
 | 
			
		||||
 | 
			
		||||
                return 'test';
 | 
			
		||||
              }),
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,19 @@
 | 
			
		||||
// Copyright (C) 2023 WYATT GROUP
 | 
			
		||||
// Please see the AUTHORS file for details.
 | 
			
		||||
// 
 | 
			
		||||
//
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// any later version.
 | 
			
		||||
// 
 | 
			
		||||
//
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
// 
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
export 'enums/format.dart';
 | 
			
		||||
export 'exceptions/exceptions.dart';
 | 
			
		||||
export 'utils/utils.dart';
 | 
			
		||||
 | 
			
		||||
@ -14,24 +14,30 @@
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
import 'package:wyatt_i18n/src/core/utils/arb_parser.dart';
 | 
			
		||||
import 'package:wyatt_i18n/src/core/utils/json_parser.dart';
 | 
			
		||||
import 'package:wyatt_i18n/src/core/utils/parser.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:wyatt_i18n/src/core/utils/yaml_parser.dart';
 | 
			
		||||
 | 
			
		||||
/// Enum for i18n file formats and extensions.
 | 
			
		||||
///
 | 
			
		||||
/// This enum is used to determine the parser to use for a given i18n file.
 | 
			
		||||
enum Format {
 | 
			
		||||
  /// JSON i18 file format.
 | 
			
		||||
  json(['json']),
 | 
			
		||||
  json,
 | 
			
		||||
 | 
			
		||||
  /// YAML i18 file format.
 | 
			
		||||
  yaml(['yaml', 'yml']),
 | 
			
		||||
  yaml,
 | 
			
		||||
  yml,
 | 
			
		||||
 | 
			
		||||
  /// ARB i18 file format.
 | 
			
		||||
  arb(['arb']);
 | 
			
		||||
 | 
			
		||||
  const Format(this.extensions);
 | 
			
		||||
 | 
			
		||||
  final List<String> extensions;
 | 
			
		||||
  arb;
 | 
			
		||||
 | 
			
		||||
  /// Returns the [Format] that matches the given [ext].
 | 
			
		||||
  static Format? fromExtension(String ext) {
 | 
			
		||||
    for (final format in Format.values) {
 | 
			
		||||
      if (format.extensions.contains(ext)) {
 | 
			
		||||
      if (format.name == ext) {
 | 
			
		||||
        return format;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
@ -42,4 +48,16 @@ enum Format {
 | 
			
		||||
  /// Returns the [Format] that matches the given [path].
 | 
			
		||||
  static Format? extensionOf(String path) =>
 | 
			
		||||
      fromExtension(path.split('.').last);
 | 
			
		||||
 | 
			
		||||
  Parser<String, Map<String, dynamic>> get parser {
 | 
			
		||||
    switch (this) {
 | 
			
		||||
      case Format.json:
 | 
			
		||||
        return const JsonParser();
 | 
			
		||||
      case Format.yaml:
 | 
			
		||||
      case Format.yml:
 | 
			
		||||
        return const YamlParser();
 | 
			
		||||
      case Format.arb:
 | 
			
		||||
        return const ArbParser();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -31,6 +31,12 @@ class NoLocaleException extends ClientException {
 | 
			
		||||
      : super('No `@@locale` key found in the source nor locale provided.');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Exception thrown when the i18n locale is not valid.
 | 
			
		||||
class InvalidLocaleException extends ClientException {
 | 
			
		||||
  InvalidLocaleException(String locale, String expected)
 | 
			
		||||
      : super('Invalid locale `$locale`. Expected `$expected`.');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Exception thrown when the key is not found in the i18n file.
 | 
			
		||||
class KeyNotFoundException extends ClientException {
 | 
			
		||||
  KeyNotFoundException(String key, [Map<String, dynamic> arguments = const {}])
 | 
			
		||||
@ -51,3 +57,8 @@ class MalformedValueException extends ClientException {
 | 
			
		||||
  MalformedValueException(String key, String value)
 | 
			
		||||
      : super('Key `$key` references a malformed value. ($value)');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ParserException extends ClientException {
 | 
			
		||||
  ParserException(String message, StackTrace? stackTrace)
 | 
			
		||||
      : super('$message\n\n$stackTrace');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										26
									
								
								packages/wyatt_i18n/lib/src/core/utils/arb_parser.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								packages/wyatt_i18n/lib/src/core/utils/arb_parser.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
			
		||||
// Copyright (C) 2023 WYATT GROUP
 | 
			
		||||
// Please see the AUTHORS file for details.
 | 
			
		||||
//
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// any later version.
 | 
			
		||||
//
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
import 'package:wyatt_i18n/src/core/utils/json_parser.dart';
 | 
			
		||||
import 'package:wyatt_i18n/src/core/utils/parser.dart';
 | 
			
		||||
 | 
			
		||||
class ArbParser extends Parser<String, Map<String, dynamic>> {
 | 
			
		||||
  const ArbParser() : super();
 | 
			
		||||
 | 
			
		||||
  /// ARB files are JSON files, so we can use the JSON parser.
 | 
			
		||||
  @override
 | 
			
		||||
  Map<String, dynamic> parse(String input) => const JsonParser().parse(input);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								packages/wyatt_i18n/lib/src/core/utils/json_parser.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								packages/wyatt_i18n/lib/src/core/utils/json_parser.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
// Copyright (C) 2023 WYATT GROUP
 | 
			
		||||
// Please see the AUTHORS file for details.
 | 
			
		||||
//
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// any later version.
 | 
			
		||||
//
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
import 'dart:convert';
 | 
			
		||||
 | 
			
		||||
import 'package:wyatt_i18n/src/core/exceptions/exceptions.dart';
 | 
			
		||||
import 'package:wyatt_i18n/src/core/utils/parser.dart';
 | 
			
		||||
 | 
			
		||||
class JsonParser extends Parser<String, Map<String, dynamic>> {
 | 
			
		||||
  const JsonParser() : super();
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Map<String, dynamic> parse(String input) {
 | 
			
		||||
    try {
 | 
			
		||||
      return jsonDecode(input) as Map<String, dynamic>;
 | 
			
		||||
    } catch (e, s) {
 | 
			
		||||
      throw ParserException(e.toString(), s);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								packages/wyatt_i18n/lib/src/core/utils/parser.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								packages/wyatt_i18n/lib/src/core/utils/parser.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
// Copyright (C) 2023 WYATT GROUP
 | 
			
		||||
// Please see the AUTHORS file for details.
 | 
			
		||||
//
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// any later version.
 | 
			
		||||
//
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
abstract class Parser<I, O> {
 | 
			
		||||
  const Parser();
 | 
			
		||||
 | 
			
		||||
  O parse(I input);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								packages/wyatt_i18n/lib/src/core/utils/utils.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								packages/wyatt_i18n/lib/src/core/utils/utils.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
// Copyright (C) 2023 WYATT GROUP
 | 
			
		||||
// Please see the AUTHORS file for details.
 | 
			
		||||
// 
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// any later version.
 | 
			
		||||
// 
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
// 
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
export 'arb_parser.dart';
 | 
			
		||||
export 'json_parser.dart';
 | 
			
		||||
export 'parser.dart';
 | 
			
		||||
export 'yaml_parser.dart';
 | 
			
		||||
							
								
								
									
										34
									
								
								packages/wyatt_i18n/lib/src/core/utils/yaml_parser.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								packages/wyatt_i18n/lib/src/core/utils/yaml_parser.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
// Copyright (C) 2023 WYATT GROUP
 | 
			
		||||
// Please see the AUTHORS file for details.
 | 
			
		||||
//
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// any later version.
 | 
			
		||||
//
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
import 'package:wyatt_i18n/src/core/exceptions/exceptions.dart';
 | 
			
		||||
import 'package:wyatt_i18n/src/core/utils/parser.dart';
 | 
			
		||||
import 'package:yaml/yaml.dart';
 | 
			
		||||
 | 
			
		||||
class YamlParser extends Parser<String, Map<String, dynamic>> {
 | 
			
		||||
  const YamlParser() : super();
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Map<String, dynamic> parse(String input) {
 | 
			
		||||
    try {
 | 
			
		||||
      final yaml = loadYaml(input) as YamlMap;
 | 
			
		||||
 | 
			
		||||
      return yaml.map((key, value) => MapEntry(key.toString(), value));
 | 
			
		||||
    } catch (e, s) {
 | 
			
		||||
      throw ParserException(e.toString(), s);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -21,10 +21,34 @@ import 'package:wyatt_i18n/src/core/enums/format.dart';
 | 
			
		||||
import 'package:wyatt_i18n/src/core/exceptions/exceptions.dart';
 | 
			
		||||
import 'package:wyatt_i18n/src/domain/data_sources/i18n_data_source.dart';
 | 
			
		||||
 | 
			
		||||
/// {@template assets_file_data_source_impl}
 | 
			
		||||
/// Implementation of [I18nDataSource] that loads i18n files from the assets.
 | 
			
		||||
///
 | 
			
		||||
/// The [basePath] is the folder where the i18n files are located.
 | 
			
		||||
/// The [baseName] is the name of the i18n files without the extension.
 | 
			
		||||
/// The [format] is the format of the i18n files.
 | 
			
		||||
///
 | 
			
		||||
/// For example, if the i18n files are located in the `assets` and are named
 | 
			
		||||
/// `i18n.en.arb`, `i18n.fr.arb`, etc., then the [basePath] is `assets` and
 | 
			
		||||
/// the [baseName] is `i18n` and the [format] is [Format.arb].
 | 
			
		||||
/// {@endtemplate}
 | 
			
		||||
class AssetsFileDataSourceImpl extends I18nDataSource {
 | 
			
		||||
  const AssetsFileDataSourceImpl({super.format = Format.arb}) : super();
 | 
			
		||||
  /// {@macro assets_file_data_source_impl}
 | 
			
		||||
  const AssetsFileDataSourceImpl({
 | 
			
		||||
    this.basePath = 'assets',
 | 
			
		||||
    this.baseName = 'i18n',
 | 
			
		||||
    super.format = Format.arb,
 | 
			
		||||
  }) : super();
 | 
			
		||||
 | 
			
		||||
  /// The folder where the i18n files are located.
 | 
			
		||||
  final String basePath;
 | 
			
		||||
 | 
			
		||||
  /// The name of the i18n files without the extension.
 | 
			
		||||
  final String baseName;
 | 
			
		||||
 | 
			
		||||
  /// Checks if the given [assetPath] is a local asset.
 | 
			
		||||
  ///
 | 
			
		||||
  /// In fact, this method loads the asset and checks if it is null.
 | 
			
		||||
  Future<bool> assetExists(String assetPath) async {
 | 
			
		||||
    final encoded = utf8.encoder.convert(
 | 
			
		||||
      Uri(path: Uri.encodeFull(assetPath)).path,
 | 
			
		||||
@ -35,48 +59,65 @@ class AssetsFileDataSourceImpl extends I18nDataSource {
 | 
			
		||||
    return asset != null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<String?> _tryLoad(String basePath) async {
 | 
			
		||||
  /// Tries to load the i18n file from the given [locale].
 | 
			
		||||
  Future<String> _tryLoad(String? locale) async {
 | 
			
		||||
    String? content;
 | 
			
		||||
    final ext = format.name;
 | 
			
		||||
    final path = locale == null
 | 
			
		||||
        ? '$basePath/$baseName.$ext'
 | 
			
		||||
        : '$basePath/$baseName.$locale.$ext';
 | 
			
		||||
    try {
 | 
			
		||||
      for (final ext in super.format.extensions) {
 | 
			
		||||
        if (await assetExists('$basePath.$ext')) {
 | 
			
		||||
          content = await rootBundle.loadString('$basePath.$ext');
 | 
			
		||||
        }
 | 
			
		||||
      if (await assetExists(path)) {
 | 
			
		||||
        content = await rootBundle.loadString(path);
 | 
			
		||||
      }
 | 
			
		||||
    } catch (_) {
 | 
			
		||||
      throw SourceNotFoundException(basePath, format: format);
 | 
			
		||||
      content = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// If the i18n file is not found, then we try to load the
 | 
			
		||||
    /// default i18n file.
 | 
			
		||||
    if (content == null && locale != null) {
 | 
			
		||||
      try {
 | 
			
		||||
        content = await rootBundle.loadString('$basePath/$baseName.$ext');
 | 
			
		||||
      } catch (_) {
 | 
			
		||||
        throw SourceNotFoundException(path, format: format);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// If the default i18n file is not found, then we throw an exception.
 | 
			
		||||
    /// This case should happen only if the locale is null.
 | 
			
		||||
    if (content == null) {
 | 
			
		||||
      throw SourceNotFoundException(basePath, format: format);
 | 
			
		||||
      throw SourceNotFoundException(path, format: format);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return content;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<String> _load(String locale) async {
 | 
			
		||||
  /// Tries to load the i18n file from a given [uri].
 | 
			
		||||
  /// This method is used when the [uri] is not null.
 | 
			
		||||
  Future<String> _tryLoadUri(Uri uri) async {
 | 
			
		||||
    String? content;
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      content = await _tryLoad('assets/i18n.$locale');
 | 
			
		||||
      content = await rootBundle.loadString(uri.toString());
 | 
			
		||||
    } catch (_) {
 | 
			
		||||
      content = await _tryLoad('assets/i18n');
 | 
			
		||||
      throw SourceNotFoundException(uri.toString(), format: format);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Content can't be null at this point.
 | 
			
		||||
    /// Because if it is, previous [_tryLoad] calls would have t
 | 
			
		||||
    /// hrown an exception.
 | 
			
		||||
    return content!;
 | 
			
		||||
    return content;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Loads the i18n file from Assets folder.
 | 
			
		||||
  ///
 | 
			
		||||
  /// The i18n file must be named `i18n.<locale>.<extension>` and must
 | 
			
		||||
  /// be specified in the `pubspec.yaml` file.
 | 
			
		||||
  /// The i18n file must be in [basePath], named [baseName] +
 | 
			
		||||
  /// `.<locale>.<extension>` and must be specified in the `pubspec.yaml` file.
 | 
			
		||||
  @override
 | 
			
		||||
  Future<String> load(String locale) async {
 | 
			
		||||
    final content = await _load(locale);
 | 
			
		||||
  Future<String> load({required String? locale}) async => _tryLoad(locale);
 | 
			
		||||
 | 
			
		||||
    return content;
 | 
			
		||||
  }
 | 
			
		||||
  /// Loads the i18n file from Assets folder.
 | 
			
		||||
  ///
 | 
			
		||||
  /// If the [uri] is not null, then we try to load the i18n file
 | 
			
		||||
  /// from the given [uri]. In this case, the [basePath] and the
 | 
			
		||||
  /// [baseName] are ignored. And there is no fallback.
 | 
			
		||||
  @override
 | 
			
		||||
  Future<String> loadFrom(Uri uri) async => _tryLoadUri(uri);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -19,10 +19,16 @@ import 'package:wyatt_i18n/src/domain/data_sources/i18n_data_source.dart';
 | 
			
		||||
 | 
			
		||||
class NetworkDataSourceImpl extends I18nDataSource {
 | 
			
		||||
  const NetworkDataSourceImpl({super.format = Format.arb}) : super();
 | 
			
		||||
 | 
			
		||||
  
 | 
			
		||||
  @override
 | 
			
		||||
  Future<String> load(String locale) {
 | 
			
		||||
    // TODO(wyatt): implement load from network
 | 
			
		||||
  Future<String> load({required String? locale}) {
 | 
			
		||||
    // TODO(wyatt): implement load
 | 
			
		||||
    throw UnimplementedError();
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  @override
 | 
			
		||||
  Future<String> loadFrom(Uri uri) {
 | 
			
		||||
    // TODO(wyatt): implement loadFrom
 | 
			
		||||
    throw UnimplementedError();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -15,9 +15,7 @@
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
 | 
			
		||||
import 'package:wyatt_i18n/src/domain/data_sources/i18n_data_source.dart';
 | 
			
		||||
import 'package:wyatt_i18n/src/domain/entities/i18n.dart';
 | 
			
		||||
import 'package:wyatt_i18n/src/domain/repositories/i18n_repository.dart';
 | 
			
		||||
import 'package:wyatt_i18n/wyatt_i18n.dart';
 | 
			
		||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
 | 
			
		||||
 | 
			
		||||
class I18RepositoryImpl extends I18nRepository {
 | 
			
		||||
@ -27,17 +25,98 @@ class I18RepositoryImpl extends I18nRepository {
 | 
			
		||||
 | 
			
		||||
  final I18nDataSource dataSource;
 | 
			
		||||
 | 
			
		||||
  Future<I18n> _parse(
 | 
			
		||||
    String content,
 | 
			
		||||
    Parser<String, Map<String, dynamic>> parser, {
 | 
			
		||||
    String? locale,
 | 
			
		||||
    bool strict = false,
 | 
			
		||||
  }) async {
 | 
			
		||||
    final parsed = parser.parse(content);
 | 
			
		||||
 | 
			
		||||
    String parsedLocale;
 | 
			
		||||
 | 
			
		||||
    /// Checks if the locale is present in the parsed data.
 | 
			
		||||
    /// If not, throws an exception.
 | 
			
		||||
    /// If yes, sets the locale to the parsed locale.
 | 
			
		||||
    if (parsed.containsKey('@@locale')) {
 | 
			
		||||
      if (strict) {
 | 
			
		||||
        /// Checks if the parsed locale is a string.
 | 
			
		||||
        if (parsed['@@locale'] is! String) {
 | 
			
		||||
          throw NoLocaleException();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// Checks if the parsed locale is the same as the given locale.
 | 
			
		||||
        if (locale != null && parsed['@@locale'] as String != locale) {
 | 
			
		||||
          throw InvalidLocaleException(locale, parsed['@@locale'] as String);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      parsedLocale = parsed['@@locale'] as String;
 | 
			
		||||
    } else {
 | 
			
		||||
      if (strict) {
 | 
			
		||||
        /// Throws an exception if the locale is not present in the parsed data.
 | 
			
		||||
        throw NoLocaleException();
 | 
			
		||||
      } else {
 | 
			
		||||
        /// Sets the locale to the given locale.
 | 
			
		||||
        /// If the given locale is null, sets the locale to 'null'.
 | 
			
		||||
        /// This is done to prevent the locale from being null.
 | 
			
		||||
        /// It should never be null.
 | 
			
		||||
        parsedLocale = locale ?? 'null';
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return I18n(
 | 
			
		||||
      locale: parsedLocale,
 | 
			
		||||
      unparsedData: content,
 | 
			
		||||
      data: parsed,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  FutureOrResult<I18n> load(String locale) async =>
 | 
			
		||||
  FutureOrResult<I18n> load({
 | 
			
		||||
    required String? locale,
 | 
			
		||||
    bool strict = false,
 | 
			
		||||
    Parser<String, Map<String, dynamic>>? parser,
 | 
			
		||||
  }) async =>
 | 
			
		||||
      await Result.tryCatchAsync<I18n, AppException, AppException>(
 | 
			
		||||
        () async {
 | 
			
		||||
          final content = await dataSource.load(locale);
 | 
			
		||||
          // TODO: Parse the content into a Map<String, dynamic> and return it.
 | 
			
		||||
          final content = await dataSource.load(locale: locale);
 | 
			
		||||
 | 
			
		||||
          return I18n(locale: locale, 
 | 
			
		||||
          unparsedData: content,
 | 
			
		||||
          data: {},);
 | 
			
		||||
          return _parse(
 | 
			
		||||
            content,
 | 
			
		||||
            parser ?? dataSource.format.parser,
 | 
			
		||||
            locale: locale,
 | 
			
		||||
            strict: strict,
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        (error) => error,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  FutureOrResult<I18n> loadFrom(
 | 
			
		||||
    Uri uri, {
 | 
			
		||||
    Parser<String, Map<String, dynamic>>? parser,
 | 
			
		||||
  }) async =>
 | 
			
		||||
      await Result.tryCatchAsync<I18n, AppException, AppException>(
 | 
			
		||||
        () async {
 | 
			
		||||
          final content = await dataSource.loadFrom(uri);
 | 
			
		||||
 | 
			
		||||
          /// Strict is always true when loading from a uri. Because
 | 
			
		||||
          /// the locale is not given and can't be inferred.
 | 
			
		||||
          return _parse(
 | 
			
		||||
            content,
 | 
			
		||||
            parser ?? dataSource.format.parser,
 | 
			
		||||
            strict: true,
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        (error) => error,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Result<String, AppException> get(
 | 
			
		||||
    String key, [
 | 
			
		||||
    Map<String, dynamic> arguments = const {},
 | 
			
		||||
  ]) {
 | 
			
		||||
    // TODO: implement get
 | 
			
		||||
    throw UnimplementedError();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -28,5 +28,12 @@ abstract class I18nDataSource extends BaseDataSource {
 | 
			
		||||
  final Format format;
 | 
			
		||||
 | 
			
		||||
  /// Loads the i18n file from the source.
 | 
			
		||||
  Future<String> load(String locale);
 | 
			
		||||
  /// If [locale] is not `null`, it will load the file with the given [locale].
 | 
			
		||||
  /// Otherwise, it will load the file from the default location.
 | 
			
		||||
  Future<String> load({required String? locale});
 | 
			
		||||
 | 
			
		||||
  /// Loads the i18n file from the source.
 | 
			
		||||
  /// 
 | 
			
		||||
  /// This method is used to load the i18n file from the given [Uri].
 | 
			
		||||
  Future<String> loadFrom(Uri uri);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -15,12 +15,37 @@
 | 
			
		||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
 | 
			
		||||
import 'package:wyatt_i18n/src/core/utils/parser.dart';
 | 
			
		||||
import 'package:wyatt_i18n/src/domain/entities/i18n.dart';
 | 
			
		||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
 | 
			
		||||
 | 
			
		||||
/// Base class for i18n repositories.
 | 
			
		||||
abstract class I18nRepository extends BaseRepository {
 | 
			
		||||
  const I18nRepository() : super();
 | 
			
		||||
 | 
			
		||||
  /// Loads the i18n file from the source.
 | 
			
		||||
  FutureOrResult<I18n> load(String locale);
 | 
			
		||||
  /// If [strict] is `true`, it will throw an NoLocaleException if the
 | 
			
		||||
  /// `@@locale` key is not found in the i18n file, otherwise it will
 | 
			
		||||
  /// set the locale to the given [locale].
 | 
			
		||||
  /// If [parser] is not `null`, it will use the given parser to parse
 | 
			
		||||
  /// the i18n file. Otherwise, it will use the default parser for the format.
 | 
			
		||||
  FutureOrResult<I18n> load({
 | 
			
		||||
    required String? locale,
 | 
			
		||||
    bool strict = false,
 | 
			
		||||
    Parser<String, Map<String, dynamic>>? parser,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  /// Loads the i18n file from the given [uri].
 | 
			
		||||
  /// If [parser] is not `null`, it will use the given parser to parse
 | 
			
		||||
  /// the i18n file. Otherwise, it will use the default parser for the format.
 | 
			
		||||
  FutureOrResult<I18n> loadFrom(
 | 
			
		||||
    Uri uri, {
 | 
			
		||||
    Parser<String, Map<String, dynamic>>? parser,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  /// Gets the translation for the given [key].
 | 
			
		||||
  Result<String, AppException> get(
 | 
			
		||||
    String key, [
 | 
			
		||||
    Map<String, dynamic> arguments = const {},
 | 
			
		||||
  ]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ environment:
 | 
			
		||||
dependencies:
 | 
			
		||||
  flutter: {sdk: flutter}
 | 
			
		||||
  path: ^1.8.0
 | 
			
		||||
  petitparser: ^5.1.0
 | 
			
		||||
  wyatt_architecture:
 | 
			
		||||
    hosted:
 | 
			
		||||
      url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/
 | 
			
		||||
@ -24,6 +25,7 @@ dependencies:
 | 
			
		||||
      url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/
 | 
			
		||||
      name: wyatt_type_utils
 | 
			
		||||
    version: 0.0.4
 | 
			
		||||
  yaml: ^3.1.1
 | 
			
		||||
 | 
			
		||||
dev_dependencies:
 | 
			
		||||
  flutter_test: {sdk: flutter}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user