add i18n package #164
@ -14,21 +14,117 @@
 | 
				
			|||||||
// 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: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/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';
 | 
					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 {
 | 
					class NetworkDataSourceImpl extends I18nDataSource {
 | 
				
			||||||
  const NetworkDataSourceImpl({super.format = Format.arb}) : super();
 | 
					  /// {@macro network_data_source_impl}
 | 
				
			||||||
  
 | 
					  const NetworkDataSourceImpl({
 | 
				
			||||||
  @override
 | 
					    required this.baseUri,
 | 
				
			||||||
  Future<String> load({required String? locale}) {
 | 
					    this.baseName = 'i18n',
 | 
				
			||||||
    // TODO(wyatt): implement load
 | 
					    this.fallbackAssetPath = 'assets',
 | 
				
			||||||
    throw UnimplementedError();
 | 
					    super.format = Format.arb,
 | 
				
			||||||
 | 
					    super.defaultLocale = 'en',
 | 
				
			||||||
 | 
					  }) : super();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// 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
 | 
					  @override
 | 
				
			||||||
  Future<String> loadFrom(Uri uri) {
 | 
					  Future<String> load({required String? locale}) async => _tryLoad(locale);
 | 
				
			||||||
    // TODO(wyatt): implement loadFrom
 | 
					
 | 
				
			||||||
    throw UnimplementedError();
 | 
					  @override
 | 
				
			||||||
  }
 | 
					  Future<String> loadFrom(Uri uri) async => _tryLoad(null, overrideUri: uri);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@ environment:
 | 
				
			|||||||
dependencies:
 | 
					dependencies:
 | 
				
			||||||
  collection: ^1.17.0
 | 
					  collection: ^1.17.0
 | 
				
			||||||
  flutter: {sdk: flutter}
 | 
					  flutter: {sdk: flutter}
 | 
				
			||||||
 | 
					  http: ^0.13.5
 | 
				
			||||||
  intl: ^0.18.0
 | 
					  intl: ^0.18.0
 | 
				
			||||||
  path: ^1.8.0
 | 
					  path: ^1.8.0
 | 
				
			||||||
  petitparser: ^5.1.0
 | 
					  petitparser: ^5.1.0
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user