diff --git a/packages/wyatt_i18n/example/assets/i18n.en.json b/packages/wyatt_i18n/example/assets/i18n.en.json
new file mode 100644
index 00000000..f59abc87
--- /dev/null
+++ b/packages/wyatt_i18n/example/assets/i18n.en.json
@@ -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"
+}
\ No newline at end of file
diff --git a/packages/wyatt_i18n/example/assets/i18n.en.yaml b/packages/wyatt_i18n/example/assets/i18n.en.yaml
new file mode 100644
index 00000000..e894e5d6
--- /dev/null
+++ b/packages/wyatt_i18n/example/assets/i18n.en.yaml
@@ -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"
diff --git a/packages/wyatt_i18n/example/lib/main.dart b/packages/wyatt_i18n/example/lib/main.dart
index dd147bd8..ed462ce9 100644
--- a/packages/wyatt_i18n/example/lib/main.dart
+++ b/packages/wyatt_i18n/example/lib/main.dart
@@ -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';
}),
diff --git a/packages/wyatt_i18n/lib/src/core/core.dart b/packages/wyatt_i18n/lib/src/core/core.dart
index cd89b9c1..575e445b 100644
--- a/packages/wyatt_i18n/lib/src/core/core.dart
+++ b/packages/wyatt_i18n/lib/src/core/core.dart
@@ -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 .
export 'enums/format.dart';
export 'exceptions/exceptions.dart';
+export 'utils/utils.dart';
diff --git a/packages/wyatt_i18n/lib/src/core/enums/format.dart b/packages/wyatt_i18n/lib/src/core/enums/format.dart
index adc5bb90..7ff768a8 100644
--- a/packages/wyatt_i18n/lib/src/core/enums/format.dart
+++ b/packages/wyatt_i18n/lib/src/core/enums/format.dart
@@ -14,24 +14,30 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+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 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> 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();
+ }
+ }
}
diff --git a/packages/wyatt_i18n/lib/src/core/exceptions/exceptions.dart b/packages/wyatt_i18n/lib/src/core/exceptions/exceptions.dart
index aa4ae2e3..b91aaf48 100644
--- a/packages/wyatt_i18n/lib/src/core/exceptions/exceptions.dart
+++ b/packages/wyatt_i18n/lib/src/core/exceptions/exceptions.dart
@@ -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 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');
+}
diff --git a/packages/wyatt_i18n/lib/src/core/utils/arb_parser.dart b/packages/wyatt_i18n/lib/src/core/utils/arb_parser.dart
new file mode 100644
index 00000000..e796b809
--- /dev/null
+++ b/packages/wyatt_i18n/lib/src/core/utils/arb_parser.dart
@@ -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 .
+
+import 'package:wyatt_i18n/src/core/utils/json_parser.dart';
+import 'package:wyatt_i18n/src/core/utils/parser.dart';
+
+class ArbParser extends Parser> {
+ const ArbParser() : super();
+
+ /// ARB files are JSON files, so we can use the JSON parser.
+ @override
+ Map parse(String input) => const JsonParser().parse(input);
+}
diff --git a/packages/wyatt_i18n/lib/src/core/utils/json_parser.dart b/packages/wyatt_i18n/lib/src/core/utils/json_parser.dart
new file mode 100644
index 00000000..66015bc7
--- /dev/null
+++ b/packages/wyatt_i18n/lib/src/core/utils/json_parser.dart
@@ -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 .
+
+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> {
+ const JsonParser() : super();
+
+ @override
+ Map parse(String input) {
+ try {
+ return jsonDecode(input) as Map;
+ } catch (e, s) {
+ throw ParserException(e.toString(), s);
+ }
+ }
+}
diff --git a/packages/wyatt_i18n/lib/src/core/utils/parser.dart b/packages/wyatt_i18n/lib/src/core/utils/parser.dart
new file mode 100644
index 00000000..9ef63217
--- /dev/null
+++ b/packages/wyatt_i18n/lib/src/core/utils/parser.dart
@@ -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 .
+
+abstract class Parser {
+ const Parser();
+
+ O parse(I input);
+}
diff --git a/packages/wyatt_i18n/lib/src/core/utils/utils.dart b/packages/wyatt_i18n/lib/src/core/utils/utils.dart
new file mode 100644
index 00000000..6dc64f48
--- /dev/null
+++ b/packages/wyatt_i18n/lib/src/core/utils/utils.dart
@@ -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 .
+
+export 'arb_parser.dart';
+export 'json_parser.dart';
+export 'parser.dart';
+export 'yaml_parser.dart';
diff --git a/packages/wyatt_i18n/lib/src/core/utils/yaml_parser.dart b/packages/wyatt_i18n/lib/src/core/utils/yaml_parser.dart
new file mode 100644
index 00000000..ab3414db
--- /dev/null
+++ b/packages/wyatt_i18n/lib/src/core/utils/yaml_parser.dart
@@ -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 .
+
+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> {
+ const YamlParser() : super();
+
+ @override
+ Map 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);
+ }
+ }
+}
diff --git a/packages/wyatt_i18n/lib/src/data/data_sources/assets_file_data_source_impl.dart b/packages/wyatt_i18n/lib/src/data/data_sources/assets_file_data_source_impl.dart
index ad2634e7..eb2a69f2 100644
--- a/packages/wyatt_i18n/lib/src/data/data_sources/assets_file_data_source_impl.dart
+++ b/packages/wyatt_i18n/lib/src/data/data_sources/assets_file_data_source_impl.dart
@@ -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 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 _tryLoad(String basePath) async {
+ /// Tries to load the i18n file from the given [locale].
+ Future _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 _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 _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..` and must
- /// be specified in the `pubspec.yaml` file.
+ /// The i18n file must be in [basePath], named [baseName] +
+ /// `..` and must be specified in the `pubspec.yaml` file.
@override
- Future load(String locale) async {
- final content = await _load(locale);
+ Future 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 loadFrom(Uri uri) async => _tryLoadUri(uri);
}
diff --git a/packages/wyatt_i18n/lib/src/data/data_sources/network_data_source_impl.dart b/packages/wyatt_i18n/lib/src/data/data_sources/network_data_source_impl.dart
index 44964fd1..64280681 100644
--- a/packages/wyatt_i18n/lib/src/data/data_sources/network_data_source_impl.dart
+++ b/packages/wyatt_i18n/lib/src/data/data_sources/network_data_source_impl.dart
@@ -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 load(String locale) {
- // TODO(wyatt): implement load from network
+ Future load({required String? locale}) {
+ // TODO(wyatt): implement load
+ throw UnimplementedError();
+ }
+
+ @override
+ Future loadFrom(Uri uri) {
+ // TODO(wyatt): implement loadFrom
throw UnimplementedError();
}
}
diff --git a/packages/wyatt_i18n/lib/src/data/repositories/i18_repository_impl.dart b/packages/wyatt_i18n/lib/src/data/repositories/i18_repository_impl.dart
index 4ae477da..3bd2a38d 100644
--- a/packages/wyatt_i18n/lib/src/data/repositories/i18_repository_impl.dart
+++ b/packages/wyatt_i18n/lib/src/data/repositories/i18_repository_impl.dart
@@ -15,9 +15,7 @@
// along with this program. If not, see .
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 _parse(
+ String content,
+ Parser> 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 load(String locale) async =>
+ FutureOrResult load({
+ required String? locale,
+ bool strict = false,
+ Parser>? parser,
+ }) async =>
await Result.tryCatchAsync(
() async {
- final content = await dataSource.load(locale);
- // TODO: Parse the content into a Map 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 loadFrom(
+ Uri uri, {
+ Parser>? parser,
+ }) async =>
+ await Result.tryCatchAsync(
+ () 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 get(
+ String key, [
+ Map arguments = const {},
+ ]) {
+ // TODO: implement get
+ throw UnimplementedError();
+ }
}
diff --git a/packages/wyatt_i18n/lib/src/domain/data_sources/i18n_data_source.dart b/packages/wyatt_i18n/lib/src/domain/data_sources/i18n_data_source.dart
index 7020ca8f..3421387b 100644
--- a/packages/wyatt_i18n/lib/src/domain/data_sources/i18n_data_source.dart
+++ b/packages/wyatt_i18n/lib/src/domain/data_sources/i18n_data_source.dart
@@ -28,5 +28,12 @@ abstract class I18nDataSource extends BaseDataSource {
final Format format;
/// Loads the i18n file from the source.
- Future 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 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 loadFrom(Uri uri);
}
diff --git a/packages/wyatt_i18n/lib/src/domain/repositories/i18n_repository.dart b/packages/wyatt_i18n/lib/src/domain/repositories/i18n_repository.dart
index aaf84b76..7716713a 100644
--- a/packages/wyatt_i18n/lib/src/domain/repositories/i18n_repository.dart
+++ b/packages/wyatt_i18n/lib/src/domain/repositories/i18n_repository.dart
@@ -15,12 +15,37 @@
// along with this program. If not, see .
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 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 load({
+ required String? locale,
+ bool strict = false,
+ Parser>? 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 loadFrom(
+ Uri uri, {
+ Parser>? parser,
+ });
+
+ /// Gets the translation for the given [key].
+ Result get(
+ String key, [
+ Map arguments = const {},
+ ]);
}
diff --git a/packages/wyatt_i18n/pubspec.yaml b/packages/wyatt_i18n/pubspec.yaml
index 5f04ca90..9124a7cd 100644
--- a/packages/wyatt_i18n/pubspec.yaml
+++ b/packages/wyatt_i18n/pubspec.yaml
@@ -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}