added flutter icons files and intl packages
This commit is contained in:
29
packages/sf_localizations/.gitignore
vendored
Executable file
29
packages/sf_localizations/.gitignore
vendored
Executable file
@@ -0,0 +1,29 @@
|
||||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
/pubspec.lock
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
build/
|
||||
10
packages/sf_localizations/.metadata
Executable file
10
packages/sf_localizations/.metadata
Executable file
@@ -0,0 +1,10 @@
|
||||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: "2663184aa79047d0a33a14a3b607954f8fdd8730"
|
||||
channel: "stable"
|
||||
|
||||
project_type: package
|
||||
3
packages/sf_localizations/CHANGELOG.md
Executable file
3
packages/sf_localizations/CHANGELOG.md
Executable file
@@ -0,0 +1,3 @@
|
||||
## 0.0.1
|
||||
|
||||
* TODO: Describe initial release.
|
||||
1
packages/sf_localizations/LICENSE
Executable file
1
packages/sf_localizations/LICENSE
Executable file
@@ -0,0 +1 @@
|
||||
TODO: Add your license here.
|
||||
39
packages/sf_localizations/README.md
Executable file
39
packages/sf_localizations/README.md
Executable file
@@ -0,0 +1,39 @@
|
||||
<!--
|
||||
This README describes the package. If you publish this package to pub.dev,
|
||||
this README's contents appear on the landing page for your package.
|
||||
|
||||
For information about how to write a good package README, see the guide for
|
||||
[writing package pages](https://dart.dev/tools/pub/writing-package-pages).
|
||||
|
||||
For general information about developing packages, see the Dart guide for
|
||||
[creating packages](https://dart.dev/guides/libraries/create-packages)
|
||||
and the Flutter guide for
|
||||
[developing packages and plugins](https://flutter.dev/to/develop-packages).
|
||||
-->
|
||||
|
||||
TODO: Put a short description of the package here that helps potential users
|
||||
know whether this package might be useful for them.
|
||||
|
||||
## Features
|
||||
|
||||
TODO: List what your package can do. Maybe include images, gifs, or videos.
|
||||
|
||||
## Getting started
|
||||
|
||||
TODO: List prerequisites and provide or point to information on how to
|
||||
start using the package.
|
||||
|
||||
## Usage
|
||||
|
||||
TODO: Include short and useful examples for package users. Add longer examples
|
||||
to `/example` folder.
|
||||
|
||||
```dart
|
||||
const like = 'sample';
|
||||
```
|
||||
|
||||
## Additional information
|
||||
|
||||
TODO: Tell users more about the package: where to find more information, how to
|
||||
contribute to the package, how to file issues, what response they can expect
|
||||
from the package authors, and more.
|
||||
6
packages/sf_localizations/analysis_options.yaml
Executable file
6
packages/sf_localizations/analysis_options.yaml
Executable file
@@ -0,0 +1,6 @@
|
||||
# include: package:utils/analysis_options.yaml
|
||||
|
||||
# # Additional information about this file can be found at
|
||||
# # https://dart.dev/guides/language/analysis-options
|
||||
|
||||
|
||||
3
packages/sf_localizations/assets/l10n/en.json
Executable file
3
packages/sf_localizations/assets/l10n/en.json
Executable file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"example": "example"
|
||||
}
|
||||
3
packages/sf_localizations/assets/l10n/es.json
Normal file
3
packages/sf_localizations/assets/l10n/es.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"example": "ejemplo"
|
||||
}
|
||||
5
packages/sf_localizations/lib/sf_localizations.dart
Executable file
5
packages/sf_localizations/lib/sf_localizations.dart
Executable file
@@ -0,0 +1,5 @@
|
||||
export 'src/sf_delegate.dart';
|
||||
export 'src/generated/i18n.dart';
|
||||
export 'src/utils/constants.dart';
|
||||
export 'src/utils/context_extension.dart';
|
||||
export 'src/utils/string_extension.dart';
|
||||
14
packages/sf_localizations/lib/src/asset_loaders/asset_loader.dart
Executable file
14
packages/sf_localizations/lib/src/asset_loaders/asset_loader.dart
Executable file
@@ -0,0 +1,14 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import '../utils/locale_extension.dart';
|
||||
|
||||
abstract class AssetLoader {
|
||||
const AssetLoader();
|
||||
|
||||
Future<Map<String, dynamic>> load(Locale locale);
|
||||
|
||||
@protected
|
||||
String getAssetPath(Locale locale) =>
|
||||
'packages/sf_localizations/assets/l10n/${locale.fileName}.json';
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'asset_loader.dart';
|
||||
|
||||
class RootBundleAssetLoader extends AssetLoader {
|
||||
const RootBundleAssetLoader();
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> load(Locale locale) async {
|
||||
final assetAsString = await rootBundle.loadString(getAssetPath(locale));
|
||||
|
||||
final translations = jsonDecode(assetAsString) as Map<String, dynamic>;
|
||||
|
||||
return translations;
|
||||
}
|
||||
}
|
||||
20
packages/sf_localizations/lib/src/asset_loaders/test_asset_loader.dart
Executable file
20
packages/sf_localizations/lib/src/asset_loaders/test_asset_loader.dart
Executable file
@@ -0,0 +1,20 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'asset_loader.dart';
|
||||
|
||||
class TestAssetLoader extends AssetLoader {
|
||||
const TestAssetLoader();
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> load(Locale locale) async {
|
||||
final data = await rootBundle.load(getAssetPath(locale));
|
||||
final bytes =
|
||||
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
|
||||
|
||||
final strings = utf8.decode(bytes);
|
||||
|
||||
return json.decode(strings) as Map<String, dynamic>;
|
||||
}
|
||||
}
|
||||
7
packages/sf_localizations/lib/src/generated/i18n.dart
Executable file
7
packages/sf_localizations/lib/src/generated/i18n.dart
Executable file
@@ -0,0 +1,7 @@
|
||||
// Generated code - do not modify by hand
|
||||
|
||||
class I18n {
|
||||
const I18n._();
|
||||
|
||||
static const String example = 'example';
|
||||
}
|
||||
166
packages/sf_localizations/lib/src/sf_delegate.dart
Executable file
166
packages/sf_localizations/lib/src/sf_delegate.dart
Executable file
@@ -0,0 +1,166 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:sf_localizations/sf_localizations.dart';
|
||||
import 'package:sf_localizations/src/asset_loaders/root_bundle_asset_loader.dart';
|
||||
import 'package:sf_localizations/src/asset_loaders/test_asset_loader.dart';
|
||||
import 'asset_loaders/asset_loader.dart';
|
||||
import 'package:utils/utils.dart';
|
||||
|
||||
class SFLocalizations {
|
||||
SFLocalizations._init(this._locale) {
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
SFLocalizations.testInit() : _locale = const Locale('es') {
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
static SFLocalizations? _instance;
|
||||
final _translationCache = <String, dynamic>{};
|
||||
final Locale _locale;
|
||||
|
||||
Locale get locale => _locale;
|
||||
|
||||
// Static getter for accessing translations without context
|
||||
static SFLocalizations get current {
|
||||
if (_instance == null) {
|
||||
throw Exception('$SFLocalizations not initialized yet');
|
||||
}
|
||||
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
Future<void> load(AssetLoader assetLoader) async {
|
||||
_translationCache.clear();
|
||||
try {
|
||||
final translations = await assetLoader.load(_locale);
|
||||
_translationCache.addAll(translations);
|
||||
} catch (e) {
|
||||
if (kDebugMode) print('Error loading locale $_locale: $e');
|
||||
}
|
||||
}
|
||||
|
||||
String tr(String key, [Map<String, dynamic>? args]) => _resolve(key, args);
|
||||
|
||||
String plural(String key, [Map<String, dynamic>? args, int? howMany]) =>
|
||||
_resolvePlural(key, args, howMany);
|
||||
|
||||
static SFLocalizations of(BuildContext context) {
|
||||
final translator = Localizations.of<SFLocalizations>(
|
||||
context,
|
||||
SFLocalizations,
|
||||
);
|
||||
|
||||
if (translator == null) {
|
||||
throw Exception('$SFLocalizations not in the context');
|
||||
}
|
||||
|
||||
return translator;
|
||||
}
|
||||
|
||||
// Add support for more languages by adding their respective message files
|
||||
static const LocalizationsDelegate<SFLocalizations> delegate =
|
||||
_SFLocalizationsDelegate();
|
||||
|
||||
String _resolve(String key, [Map<String, dynamic>? args]) {
|
||||
if (!_translationCache.containsKey(key)) {
|
||||
return key;
|
||||
}
|
||||
|
||||
final translationValue = _translationCache[key] as String;
|
||||
|
||||
return _format(translationValue, args);
|
||||
}
|
||||
|
||||
String _resolvePlural(
|
||||
String key, [
|
||||
Map<String, dynamic>? args,
|
||||
int? howMany,
|
||||
]) {
|
||||
if (!_translationCache.containsKey(key)) {
|
||||
return key;
|
||||
}
|
||||
|
||||
final translationValue = _translationCache[key]!;
|
||||
|
||||
if (translationValue is! Map) {
|
||||
return key;
|
||||
}
|
||||
|
||||
if (!translationValue.containsKey('other')) {
|
||||
return key;
|
||||
}
|
||||
|
||||
if (howMany == null) {
|
||||
return _format(translationValue['other'] as String, args);
|
||||
}
|
||||
|
||||
return _format(
|
||||
Intl.withLocale<String>(
|
||||
_locale.languageCode,
|
||||
() => Intl.plural(
|
||||
howMany,
|
||||
zero: _getPluralValue(translationValue, 'zero'),
|
||||
one: _getPluralValue(translationValue, 'one'),
|
||||
two: _getPluralValue(translationValue, 'two'),
|
||||
few: _getPluralValue(translationValue, 'few'),
|
||||
many: _getPluralValue(translationValue, 'many'),
|
||||
other: translationValue['other'] as String,
|
||||
),
|
||||
)
|
||||
as String,
|
||||
args,
|
||||
);
|
||||
}
|
||||
|
||||
String _getPluralValue(Map<dynamic, dynamic> translationValue, String key) {
|
||||
if (translationValue[key] != null &&
|
||||
(translationValue[key] as String).isEmpty) {
|
||||
return translationValue['other'] as String;
|
||||
}
|
||||
return translationValue[key] as String;
|
||||
}
|
||||
|
||||
String _format(String value, [Map<String, dynamic>? args]) {
|
||||
return (args?.isNotEmpty ?? false) ? _sprintf(value, args!) : value;
|
||||
}
|
||||
|
||||
String _sprintf(String format, Map<String, dynamic> values) {
|
||||
return format.replaceAllMapped(RegExp(r'\{(\w+)\}'), (match) {
|
||||
final key = match.group(1)!;
|
||||
if (!values.containsKey(key)) {
|
||||
throw ArgumentError('Missing value for placeholder {$key}');
|
||||
}
|
||||
return values[key].toString();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _SFLocalizationsDelegate extends LocalizationsDelegate<SFLocalizations> {
|
||||
const _SFLocalizationsDelegate();
|
||||
|
||||
static const _assetLoader = isTest
|
||||
? TestAssetLoader()
|
||||
: RootBundleAssetLoader();
|
||||
|
||||
@override
|
||||
bool isSupported(Locale locale) {
|
||||
return supportedLanguages.contains(locale.languageCode);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SFLocalizations> load(Locale locale) async {
|
||||
final localizations = SFLocalizations._init(locale);
|
||||
|
||||
await localizations.load(_assetLoader);
|
||||
|
||||
return localizations;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldReload(_SFLocalizationsDelegate old) => false;
|
||||
}
|
||||
1
packages/sf_localizations/lib/src/utils/constants.dart
Executable file
1
packages/sf_localizations/lib/src/utils/constants.dart
Executable file
@@ -0,0 +1 @@
|
||||
const supportedLanguages = ['en', 'es'];
|
||||
11
packages/sf_localizations/lib/src/utils/context_extension.dart
Executable file
11
packages/sf_localizations/lib/src/utils/context_extension.dart
Executable file
@@ -0,0 +1,11 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import '../sf_delegate.dart';
|
||||
|
||||
extension LocalizationContextExtension on BuildContext {
|
||||
Locale get locale => translator.locale;
|
||||
|
||||
String translate(String key, {Map<String, dynamic>? args}) =>
|
||||
translator.tr(key, args);
|
||||
|
||||
SFLocalizations get translator => SFLocalizations.of(this);
|
||||
}
|
||||
5
packages/sf_localizations/lib/src/utils/locale_extension.dart
Executable file
5
packages/sf_localizations/lib/src/utils/locale_extension.dart
Executable file
@@ -0,0 +1,5 @@
|
||||
import 'dart:ui' show Locale;
|
||||
|
||||
extension ExpandLocale on Locale {
|
||||
String get fileName => countryCode != null ? '$languageCode-$countryCode' : languageCode;
|
||||
}
|
||||
9
packages/sf_localizations/lib/src/utils/string_extension.dart
Executable file
9
packages/sf_localizations/lib/src/utils/string_extension.dart
Executable file
@@ -0,0 +1,9 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import '../sf_delegate.dart';
|
||||
|
||||
extension StringLocalizationExtension on String {
|
||||
String tr({BuildContext? context, Map<String, dynamic>? args}) =>
|
||||
context != null
|
||||
? SFLocalizations.of(context).tr(this, args)
|
||||
: SFLocalizations.current.tr(this, args);
|
||||
}
|
||||
28
packages/sf_localizations/pubspec.yaml
Executable file
28
packages/sf_localizations/pubspec.yaml
Executable file
@@ -0,0 +1,28 @@
|
||||
name: sf_localizations
|
||||
description: "A new Flutter package project."
|
||||
version: 0.0.1
|
||||
homepage: none
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: ^3.8.0
|
||||
flutter: ">=1.17.0"
|
||||
# resolution: workspace
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
intl: ^0.20.2
|
||||
utils:
|
||||
path: ../utils
|
||||
build_runner: ^2.7.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
|
||||
flutter:
|
||||
assets:
|
||||
- assets/l10n/
|
||||
|
||||
4
packages/sf_localizations/pubspec_overrides.yaml
Normal file
4
packages/sf_localizations/pubspec_overrides.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
# melos_managed_dependency_overrides: utils
|
||||
dependency_overrides:
|
||||
utils:
|
||||
path: ../utils
|
||||
58
packages/sf_localizations/scripts/i18n_generator.dart
Executable file
58
packages/sf_localizations/scripts/i18n_generator.dart
Executable file
@@ -0,0 +1,58 @@
|
||||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
const inputPath = 'assets/l10n/en.json';
|
||||
const outputPath = 'lib/src/generated/i18n.dart';
|
||||
|
||||
void main() {
|
||||
try {
|
||||
generateI18n();
|
||||
} catch (e) {
|
||||
print('Error generating I18n: $e');
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void generateI18n() {
|
||||
// Ensure input file exists
|
||||
final inputFile = File(inputPath);
|
||||
if (!inputFile.existsSync()) {
|
||||
throw 'Input file not found: $inputPath';
|
||||
}
|
||||
|
||||
// Create output directory if it doesn't exist
|
||||
final outputDir = Directory(outputPath.substring(0, outputPath.lastIndexOf('/')));
|
||||
if (!outputDir.existsSync()) {
|
||||
outputDir.createSync(recursive: true);
|
||||
}
|
||||
|
||||
// Read and parse JSON
|
||||
final jsonString = inputFile.readAsStringSync();
|
||||
final jsonMap = json.decode(jsonString) as Map<String, dynamic>;
|
||||
|
||||
// Generate Dart class
|
||||
final buffer = StringBuffer();
|
||||
buffer.writeln('// Generated code - do not modify by hand');
|
||||
buffer.writeln();
|
||||
buffer.writeln('class I18n {');
|
||||
buffer.writeln(' const I18n._();');
|
||||
buffer.writeln();
|
||||
|
||||
// Process JSON and write parent keys
|
||||
final parentKeys = jsonMap.keys.toList()..sort();
|
||||
for (final key in parentKeys) {
|
||||
final keyName = key[0].toLowerCase() + key.substring(1);
|
||||
|
||||
buffer.writeln(" static const String $keyName = '$key';");
|
||||
}
|
||||
|
||||
buffer.writeln('}');
|
||||
|
||||
// Write to output file
|
||||
final outputFile = File(outputPath);
|
||||
outputFile.writeAsStringSync(buffer.toString());
|
||||
|
||||
print('Successfully generated I18n class at: $outputPath');
|
||||
}
|
||||
Reference in New Issue
Block a user