add i18n package #164
@ -14,21 +14,117 @@
 | 
			
		||||
// 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:flutter/services.dart';
 | 
			
		||||
import 'package:http/http.dart' as http;
 | 
			
		||||
import 'package:wyatt_i18n/src/core/enums/format.dart';
 | 
			
		||||
import 'package:wyatt_i18n/src/core/exceptions/exceptions.dart';
 | 
			
		||||
import 'package:wyatt_i18n/src/core/utils/assets_utils.dart';
 | 
			
		||||
import 'package:wyatt_i18n/src/domain/data_sources/i18n_data_source.dart';
 | 
			
		||||
 | 
			
		||||
/// {@template network_data_source_impl}
 | 
			
		||||
/// Implementation of [I18nDataSource] that loads i18n files from the network.
 | 
			
		||||
///
 | 
			
		||||
/// The [baseUri] is the base uri where the i18n files are located.
 | 
			
		||||
/// The [baseName] is the name of the i18n files without the extension.
 | 
			
		||||
/// The [fallbackAssetPath] is the path to the fallback i18n files.
 | 
			
		||||
/// The [format] is the format of the i18n files.
 | 
			
		||||
///
 | 
			
		||||
/// For example, if the i18n files are located at `https://example.com/i18n/`
 | 
			
		||||
/// and are named `i18n.en.arb`, `i18n.fr.arb`, etc., then the [baseUri] is
 | 
			
		||||
/// `https://example.com/i18n/` and the [baseName] is `i18n` and the
 | 
			
		||||
/// [format] is [Format.arb].
 | 
			
		||||
///
 | 
			
		||||
/// If the i18n file for the given locale is not found or if the fetch fails,
 | 
			
		||||
/// then the fallback i18n files are loaded from the [fallbackAssetPath] in
 | 
			
		||||
/// the root bundle.
 | 
			
		||||
///
 | 
			
		||||
/// For example, if the fallback i18n files are located in the `assets` and are
 | 
			
		||||
/// named `i18n.arb`, `i18n.en.arb`, `i18n.fr.arb`, etc., then the
 | 
			
		||||
/// [fallbackAssetPath] is `assets`.
 | 
			
		||||
/// {@endtemplate}
 | 
			
		||||
class NetworkDataSourceImpl extends I18nDataSource {
 | 
			
		||||
  const NetworkDataSourceImpl({super.format = Format.arb}) : super();
 | 
			
		||||
  /// {@macro network_data_source_impl}
 | 
			
		||||
  const NetworkDataSourceImpl({
 | 
			
		||||
    required this.baseUri,
 | 
			
		||||
    this.baseName = 'i18n',
 | 
			
		||||
    this.fallbackAssetPath = 'assets',
 | 
			
		||||
    super.format = Format.arb,
 | 
			
		||||
    super.defaultLocale = 'en',
 | 
			
		||||
  }) : super();
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Future<String> load({required String? locale}) {
 | 
			
		||||
    // TODO(wyatt): implement load
 | 
			
		||||
    throw UnimplementedError();
 | 
			
		||||
  /// The base uri where the i18n files are located.
 | 
			
		||||
  final Uri baseUri;
 | 
			
		||||
 | 
			
		||||
  /// The name of the i18n files without the extension.
 | 
			
		||||
  final String baseName;
 | 
			
		||||
 | 
			
		||||
  /// The path to the fallback i18n files.
 | 
			
		||||
  ///
 | 
			
		||||
  /// This is used when the i18n file for the given locale is not found or
 | 
			
		||||
  /// if the fetch fails.
 | 
			
		||||
  final String fallbackAssetPath;
 | 
			
		||||
 | 
			
		||||
  /// Tries to load the i18n file from the given [locale].
 | 
			
		||||
  Future<String> _tryLoad(String? locale, {Uri? overrideUri}) async {
 | 
			
		||||
    String? content;
 | 
			
		||||
    final ext = format.name;
 | 
			
		||||
 | 
			
		||||
    /// If the locale is null, then we try to load the default i18n file from
 | 
			
		||||
    /// the fallback asset path.
 | 
			
		||||
    /// Otherwise, we try to load the i18n file for the given locale from the
 | 
			
		||||
    /// base uri.
 | 
			
		||||
    final path = AssetsUtils.cleanPath(
 | 
			
		||||
      locale == null
 | 
			
		||||
          ? '$fallbackAssetPath/$baseName.$defaultLocale.$ext'
 | 
			
		||||
          : overrideUri?.toString() ?? '$baseUri/$baseName.$locale.$ext',
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (locale == null) {
 | 
			
		||||
      /// Load the default i18n file from the fallback asset path.
 | 
			
		||||
      try {
 | 
			
		||||
        if (await AssetsUtils.assetExists(path)) {
 | 
			
		||||
          content = await rootBundle.loadString(path);
 | 
			
		||||
        }
 | 
			
		||||
      } catch (_) {
 | 
			
		||||
        content = null;
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      /// Load the i18n file for the given locale from the base uri.
 | 
			
		||||
      try {
 | 
			
		||||
        final response = await http.get(Uri.parse(path));
 | 
			
		||||
        if (response.statusCode >= 200 && response.statusCode < 300) {
 | 
			
		||||
          content = response.body;
 | 
			
		||||
        }
 | 
			
		||||
      } catch (_) {
 | 
			
		||||
        content = null;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// If the i18n file is not found, then we try to load the
 | 
			
		||||
    /// default i18n file.
 | 
			
		||||
    if (content == null && locale != null) {
 | 
			
		||||
      try {
 | 
			
		||||
        final fallbackPath = AssetsUtils.cleanPath(
 | 
			
		||||
          '$fallbackAssetPath/$baseName.$defaultLocale.$ext',
 | 
			
		||||
        );
 | 
			
		||||
        content = await rootBundle.loadString(fallbackPath);
 | 
			
		||||
      } 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(path, format: format);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return content;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Future<String> loadFrom(Uri uri) {
 | 
			
		||||
    // TODO(wyatt): implement loadFrom
 | 
			
		||||
    throw UnimplementedError();
 | 
			
		||||
  }
 | 
			
		||||
  Future<String> load({required String? locale}) async => _tryLoad(locale);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Future<String> loadFrom(Uri uri) async => _tryLoad(null, overrideUri: uri);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ environment:
 | 
			
		||||
dependencies:
 | 
			
		||||
  collection: ^1.17.0
 | 
			
		||||
  flutter: {sdk: flutter}
 | 
			
		||||
  http: ^0.13.5
 | 
			
		||||
  intl: ^0.18.0
 | 
			
		||||
  path: ^1.8.0
 | 
			
		||||
  petitparser: ^5.1.0
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user