master #81
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"
|
@ -46,7 +46,11 @@ class App extends StatelessWidget {
|
|||||||
const I18nRepository repository =
|
const I18nRepository repository =
|
||||||
I18RepositoryImpl(dataSource: dataSource);
|
I18RepositoryImpl(dataSource: dataSource);
|
||||||
|
|
||||||
print((await repository.load('fr')).err);
|
final test = (await repository.load('en')).ok;
|
||||||
|
|
||||||
|
print(test?.locale);
|
||||||
|
print(test?.data);
|
||||||
|
print(test?.data['btnAddFile']);
|
||||||
|
|
||||||
return 'test';
|
return 'test';
|
||||||
}),
|
}),
|
||||||
|
@ -16,3 +16,4 @@
|
|||||||
|
|
||||||
export 'enums/format.dart';
|
export 'enums/format.dart';
|
||||||
export 'exceptions/exceptions.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
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// 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 {
|
enum Format {
|
||||||
/// JSON i18 file format.
|
/// JSON i18 file format.
|
||||||
json(['json']),
|
json,
|
||||||
|
|
||||||
/// YAML i18 file format.
|
/// YAML i18 file format.
|
||||||
yaml(['yaml', 'yml']),
|
yaml,
|
||||||
|
yml,
|
||||||
|
|
||||||
/// ARB i18 file format.
|
/// ARB i18 file format.
|
||||||
arb(['arb']);
|
arb;
|
||||||
|
|
||||||
const Format(this.extensions);
|
|
||||||
|
|
||||||
final List<String> extensions;
|
|
||||||
|
|
||||||
/// Returns the [Format] that matches the given [ext].
|
/// Returns the [Format] that matches the given [ext].
|
||||||
static Format? fromExtension(String ext) {
|
static Format? fromExtension(String ext) {
|
||||||
for (final format in Format.values) {
|
for (final format in Format.values) {
|
||||||
if (format.extensions.contains(ext)) {
|
if (format.name == ext) {
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,4 +48,16 @@ enum Format {
|
|||||||
/// Returns the [Format] that matches the given [path].
|
/// Returns the [Format] that matches the given [path].
|
||||||
static Format? extensionOf(String path) =>
|
static Format? extensionOf(String path) =>
|
||||||
fromExtension(path.split('.').last);
|
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.');
|
: 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.
|
/// Exception thrown when the key is not found in the i18n file.
|
||||||
class KeyNotFoundException extends ClientException {
|
class KeyNotFoundException extends ClientException {
|
||||||
KeyNotFoundException(String key, [Map<String, dynamic> arguments = const {}])
|
KeyNotFoundException(String key, [Map<String, dynamic> arguments = const {}])
|
||||||
@ -51,3 +57,8 @@ class MalformedValueException extends ClientException {
|
|||||||
MalformedValueException(String key, String value)
|
MalformedValueException(String key, String value)
|
||||||
: super('Key `$key` references a malformed value. ($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/core/exceptions/exceptions.dart';
|
||||||
import 'package:wyatt_i18n/src/domain/data_sources/i18n_data_source.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 {
|
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.
|
/// 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 {
|
Future<bool> assetExists(String assetPath) async {
|
||||||
final encoded = utf8.encoder.convert(
|
final encoded = utf8.encoder.convert(
|
||||||
Uri(path: Uri.encodeFull(assetPath)).path,
|
Uri(path: Uri.encodeFull(assetPath)).path,
|
||||||
@ -35,48 +59,65 @@ class AssetsFileDataSourceImpl extends I18nDataSource {
|
|||||||
return asset != null;
|
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;
|
String? content;
|
||||||
|
final ext = format.name;
|
||||||
|
final path = locale == null
|
||||||
|
? '$basePath/$baseName.$ext'
|
||||||
|
: '$basePath/$baseName.$locale.$ext';
|
||||||
try {
|
try {
|
||||||
for (final ext in super.format.extensions) {
|
if (await assetExists(path)) {
|
||||||
if (await assetExists('$basePath.$ext')) {
|
content = await rootBundle.loadString(path);
|
||||||
content = await rootBundle.loadString('$basePath.$ext');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (_) {
|
} 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) {
|
if (content == null) {
|
||||||
throw SourceNotFoundException(basePath, format: format);
|
throw SourceNotFoundException(path, format: format);
|
||||||
}
|
}
|
||||||
|
|
||||||
return content;
|
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;
|
String? content;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
content = await _tryLoad('assets/i18n.$locale');
|
content = await rootBundle.loadString(uri.toString());
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
content = await _tryLoad('assets/i18n');
|
throw SourceNotFoundException(uri.toString(), format: format);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Content can't be null at this point.
|
return content;
|
||||||
/// Because if it is, previous [_tryLoad] calls would have t
|
|
||||||
/// hrown an exception.
|
|
||||||
return content!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads the i18n file from Assets folder.
|
/// Loads the i18n file from Assets folder.
|
||||||
///
|
///
|
||||||
/// The i18n file must be named `i18n.<locale>.<extension>` and must
|
/// The i18n file must be in [basePath], named [baseName] +
|
||||||
/// be specified in the `pubspec.yaml` file.
|
/// `.<locale>.<extension>` and must be specified in the `pubspec.yaml` file.
|
||||||
@override
|
@override
|
||||||
Future<String> load(String locale) async {
|
Future<String> load({required String? locale}) async => _tryLoad(locale);
|
||||||
final content = await _load(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);
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,14 @@ class NetworkDataSourceImpl extends I18nDataSource {
|
|||||||
const NetworkDataSourceImpl({super.format = Format.arb}) : super();
|
const NetworkDataSourceImpl({super.format = Format.arb}) : super();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> load(String locale) {
|
Future<String> load({required String? locale}) {
|
||||||
// TODO(wyatt): implement load from network
|
// TODO(wyatt): implement load
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String> loadFrom(Uri uri) {
|
||||||
|
// TODO(wyatt): implement loadFrom
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,7 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||||
import 'package:wyatt_i18n/src/domain/data_sources/i18n_data_source.dart';
|
import 'package:wyatt_i18n/wyatt_i18n.dart';
|
||||||
import 'package:wyatt_i18n/src/domain/entities/i18n.dart';
|
|
||||||
import 'package:wyatt_i18n/src/domain/repositories/i18n_repository.dart';
|
|
||||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
||||||
|
|
||||||
class I18RepositoryImpl extends I18nRepository {
|
class I18RepositoryImpl extends I18nRepository {
|
||||||
@ -27,17 +25,98 @@ class I18RepositoryImpl extends I18nRepository {
|
|||||||
|
|
||||||
final I18nDataSource dataSource;
|
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
|
@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>(
|
await Result.tryCatchAsync<I18n, AppException, AppException>(
|
||||||
() async {
|
() async {
|
||||||
final content = await dataSource.load(locale);
|
final content = await dataSource.load(locale: locale);
|
||||||
// TODO: Parse the content into a Map<String, dynamic> and return it.
|
|
||||||
|
|
||||||
return I18n(locale: locale,
|
return _parse(
|
||||||
unparsedData: content,
|
content,
|
||||||
data: {},);
|
parser ?? dataSource.format.parser,
|
||||||
|
locale: locale,
|
||||||
|
strict: strict,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
(error) => error,
|
(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;
|
final Format format;
|
||||||
|
|
||||||
/// Loads the i18n file from the source.
|
/// 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/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
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_i18n/src/domain/entities/i18n.dart';
|
||||||
|
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
||||||
|
|
||||||
/// Base class for i18n repositories.
|
/// Base class for i18n repositories.
|
||||||
abstract class I18nRepository extends BaseRepository {
|
abstract class I18nRepository extends BaseRepository {
|
||||||
const I18nRepository() : super();
|
const I18nRepository() : super();
|
||||||
|
|
||||||
/// Loads the i18n file from the source.
|
/// 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:
|
dependencies:
|
||||||
flutter: {sdk: flutter}
|
flutter: {sdk: flutter}
|
||||||
path: ^1.8.0
|
path: ^1.8.0
|
||||||
|
petitparser: ^5.1.0
|
||||||
wyatt_architecture:
|
wyatt_architecture:
|
||||||
hosted:
|
hosted:
|
||||||
url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/
|
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/
|
url: https://git.wyatt-studio.fr/api/packages/Wyatt-FOSS/pub/
|
||||||
name: wyatt_type_utils
|
name: wyatt_type_utils
|
||||||
version: 0.0.4
|
version: 0.0.4
|
||||||
|
yaml: ^3.1.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test: {sdk: flutter}
|
flutter_test: {sdk: flutter}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user