chore(i18n): initialize new package

This commit is contained in:
2023-02-27 13:55:26 +01:00
parent 4a73a8a4c0
commit 0a55df8638
40 changed files with 1701 additions and 0 deletions
@@ -0,0 +1,18 @@
// 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';
@@ -0,0 +1,45 @@
// 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/>.
enum Format {
/// JSON i18 file format.
json(['json']),
/// YAML i18 file format.
yaml(['yaml', 'yml']),
/// ARB i18 file format.
arb(['arb']);
const Format(this.extensions);
final List<String> extensions;
/// Returns the [Format] that matches the given [ext].
static Format? fromExtension(String ext) {
for (final format in Format.values) {
if (format.extensions.contains(ext)) {
return format;
}
}
return null;
}
/// Returns the [Format] that matches the given [path].
static Format? extensionOf(String path) =>
fromExtension(path.split('.').last);
}
@@ -0,0 +1,53 @@
// 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_architecture/wyatt_architecture.dart';
import 'package:wyatt_i18n/src/core/enums/format.dart';
/// Exception thrown when the i18n file is not found.
///
/// Source can be a file path or a URL.
class SourceNotFoundException extends ClientException {
SourceNotFoundException(String source, {required Format format})
: super('Source `$source` (format: $format) not found.');
}
/// Exception thrown when the i18n file is not valid.
class NoLocaleException extends ClientException {
NoLocaleException()
: super('No `@@locale` key found in the source nor locale provided.');
}
/// Exception thrown when the key is not found in the i18n file.
class KeyNotFoundException extends ClientException {
KeyNotFoundException(String key, [Map<String, dynamic> arguments = const {}])
: super(
'Key `$key` not found. ${arguments.isNotEmpty ? '($arguments)' : ''}',
);
}
/// Exception thrown when the searched key requires arguments but none were
/// provided.
class ArgumentsRequiredException extends ClientException {
ArgumentsRequiredException(String key, String value)
: super('Key `$key` requires arguments. ($value)');
}
/// Exception thrown when the key references a malformed value.
class MalformedValueException extends ClientException {
MalformedValueException(String key, String value)
: super('Key `$key` references a malformed value. ($value)');
}
@@ -0,0 +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 'data_sources/assets_file_data_source_impl.dart';
export 'data_sources/network_data_source_impl.dart';
export 'repositories/i18_repository_impl.dart';
@@ -0,0 +1,82 @@
// 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:flutter/services.dart' show ServicesBinding, rootBundle;
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';
class AssetsFileDataSourceImpl extends I18nDataSource {
const AssetsFileDataSourceImpl({super.format = Format.arb}) : super();
/// Checks if the given [assetPath] is a local asset.
Future<bool> assetExists(String assetPath) async {
final encoded = utf8.encoder.convert(
Uri(path: Uri.encodeFull(assetPath)).path,
);
final asset = await ServicesBinding.instance.defaultBinaryMessenger
.send('flutter/assets', encoded.buffer.asByteData());
return asset != null;
}
Future<String?> _tryLoad(String basePath) async {
String? content;
try {
for (final ext in super.format.extensions) {
if (await assetExists('$basePath.$ext')) {
content = await rootBundle.loadString('$basePath.$ext');
}
}
} catch (_) {
throw SourceNotFoundException(basePath, format: format);
}
if (content == null) {
throw SourceNotFoundException(basePath, format: format);
}
return content;
}
Future<String> _load(String locale) async {
String? content;
try {
content = await _tryLoad('assets/i18n.$locale');
} catch (_) {
content = await _tryLoad('assets/i18n');
}
/// Content can't be null at this point.
/// Because if it is, previous [_tryLoad] calls would have t
/// hrown an exception.
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.
@override
Future<String> load(String locale) async {
final content = await _load(locale);
return content;
}
}
@@ -0,0 +1,28 @@
// 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/enums/format.dart';
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
throw UnimplementedError();
}
}
@@ -0,0 +1,43 @@
// 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_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_type_utils/wyatt_type_utils.dart';
class I18RepositoryImpl extends I18nRepository {
const I18RepositoryImpl({
required this.dataSource,
}) : super();
final I18nDataSource dataSource;
@override
FutureOrResult<I18n> load(String locale) 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.
return I18n(locale: locale,
unparsedData: content,
data: {},);
},
(error) => error,
);
}
@@ -0,0 +1,32 @@
// 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_architecture/wyatt_architecture.dart';
import 'package:wyatt_i18n/src/core/enums/format.dart';
/// Base class for i18n data sources.
///
/// This class is used to load i18n files from a source.
/// It returns a [Future] that resolves to a [String] containing the i18n file
/// contents.
abstract class I18nDataSource extends BaseDataSource {
const I18nDataSource({this.format = Format.arb});
final Format format;
/// Loads the i18n file from the source.
Future<String> load(String locale);
}
@@ -0,0 +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 'data_sources/i18n_data_source.dart';
export 'entities/i18n.dart';
export 'repositories/i18n_repository.dart';
@@ -0,0 +1,45 @@
// 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_architecture/wyatt_architecture.dart';
/// Data structure for i18n files.
class I18n extends Entity {
const I18n({
required this.locale,
required this.unparsedData,
required this.data,
}) : super();
/// The locale of the i18n file.
final String locale;
/// The unparsed data of the i18n file.
final String unparsedData;
/// The data of the i18n file.
final Map<String, dynamic> data;
String operator [](String key) {
final value = data[key];
if (value is String) {
return value;
} else {
throw Exception('Invalid i18n key: $key');
}
}
}
@@ -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_architecture/wyatt_architecture.dart';
import 'package:wyatt_i18n/src/domain/entities/i18n.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);
}
+19
View File
@@ -0,0 +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 'core/core.dart';
export 'data/data.dart';
export 'domain/domain.dart';
@@ -0,0 +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/>.
abstract class WyattI18n {
static String get testString => 'Package: Wyatt I18n';
}