added flutter icons files and intl packages

This commit is contained in:
AlcalaJulian
2025-11-24 12:55:20 +01:00
parent 4225f7510b
commit d381908ff1
45 changed files with 1679 additions and 18 deletions

29
packages/sf_localizations/.gitignore vendored Executable file
View 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/

View 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

View File

@@ -0,0 +1,3 @@
## 0.0.1
* TODO: Describe initial release.

View File

@@ -0,0 +1 @@
TODO: Add your license here.

View 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.

View 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

View File

@@ -0,0 +1,3 @@
{
"example": "example"
}

View File

@@ -0,0 +1,3 @@
{
"example": "ejemplo"
}

View 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';

View 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';
}

View File

@@ -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;
}
}

View 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>;
}
}

View File

@@ -0,0 +1,7 @@
// Generated code - do not modify by hand
class I18n {
const I18n._();
static const String example = 'example';
}

View 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;
}

View File

@@ -0,0 +1 @@
const supportedLanguages = ['en', 'es'];

View 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);
}

View File

@@ -0,0 +1,5 @@
import 'dart:ui' show Locale;
extension ExpandLocale on Locale {
String get fileName => countryCode != null ? '$languageCode-$countryCode' : languageCode;
}

View 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);
}

View 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/

View File

@@ -0,0 +1,4 @@
# melos_managed_dependency_overrides: utils
dependency_overrides:
utils:
path: ../utils

View 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');
}