Added support to named replacement; Some improvements.
Closed this issue · 1 comments
programadorthi commented
Estou colocando aqui em vez de abrir PR. Espero que ajude!
Como usar:
Strings.of(context).namedOf("key", {'name': value})
Strings.of(context).pluralNamedOf("named_plurals", 2, {'other': "OTHER NUMBER"})
library internationalization;
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
RegExp _namedValuesRegex = RegExp(r"\\?\{[a-zA-Z]+\\?\}");
List<Locale> supportedLocales = [];
class Strings {
static final Map<String, dynamic> _defaultLocaleStrings = new Map();
final Locale _locale;
final Locale _defaultLocale;
final String _path;
Map<String, dynamic> _locationStrings;
Strings._(this._defaultLocale, this._locale, this._path);
static Strings of(BuildContext context) {
return Localizations.of<Strings>(context, Strings);
}
// TODO: Is there a country code always?
Future<Map<String, dynamic>> _getFileData(Locale locale) async {
String path =
'${this._path}/${locale.languageCode}_${locale.countryCode}.json';
String data = await rootBundle.loadString(path);
return json.decode(data);
}
_load() async {
await _loadDefault();
if (_locale == _defaultLocale) {
return;
}
_locationStrings = await _getFileData(this._locale);
}
_loadDefault() async {
if (_defaultLocaleStrings.isNotEmpty) {
return;
}
Map<String, dynamic> _result = await _getFileData(this._defaultLocale);
_result.forEach((String key, dynamic value) {
_defaultLocaleStrings[key] = value;
});
}
bool _hasKey(String key) {
return (_locationStrings != null && _locationStrings.containsKey(key)) ||
_defaultLocaleStrings.containsKey(key);
}
dynamic _valueOf(String key) {
if (_locationStrings == null) {
return _defaultLocaleStrings[key];
}
return _locationStrings[key] ?? _defaultLocaleStrings[key];
}
String _applyNamedReplacement(String text, Map<String, dynamic> args) {
Iterable<RegExpMatch> matches = _namedValuesRegex.allMatches(text);
if (matches.isEmpty) {
throw Exception("No named replacement found in the text");
}
StringBuffer result = StringBuffer();
int currentTextIndex = 0;
for (Match match in matches) {
result.write(text.substring(currentTextIndex, match.start));
currentTextIndex = match.start;
String group = match.group(0);
// Escaped block keys are ignored. Ex: \{texto\}
if (group.startsWith("\\")) {
result.write(text.substring(currentTextIndex, match.end));
} else {
// Remove block keys
String key = group.substring(1, group.length - 1);
dynamic replacement = args[key];
if (replacement == null) {
throw Exception("No named replacement for key [$key] was found");
}
result.write(replacement.toString());
}
currentTextIndex = match.end;
}
if (currentTextIndex < text.length - 1) {
result.write(text.substring(currentTextIndex));
}
return result.toString();
}
String _getPluralKey(int pluralValue) {
if (pluralValue > 1) {
return "other";
}
if (pluralValue > 0) {
return "one";
}
return "zero";
}
String _getPluralText(String key, int pluralValue) {
if (!_hasKey(key)) {
return key;
}
Map<String, dynamic> plurals = _valueOf(key);
String pluralKey = _getPluralKey(pluralValue);
return plurals[pluralKey].toString();
}
String _interpolateValue(String value, List<String> args) {
if (args == null || args.isEmpty) {
return value;
}
for (int i = 0; i < args.length; i++) {
value = value.replaceAll("{$i}", args[i]);
}
return value;
}
String namedOf(String key, Map<String, dynamic> args) {
if (!_hasKey(key)) {
return key;
}
String value = _valueOf(key).toString();
if (value.isEmpty || args == null || args.isEmpty) {
return value;
}
return _applyNamedReplacement(value, args);
}
String valueOf(String key, {List<String> args}) {
if (!_hasKey(key)) {
return key;
}
String value = _valueOf(key).toString();
return _interpolateValue(value, args);
}
String pluralOf(String key, int pluralValue, {List<String> args}) {
String value = _getPluralText(key, pluralValue);
if (value == key) {
return key;
}
return _interpolateValue(value, args);
}
String pluralNamedOf(String key, int pluralValue, Map<String, dynamic> args) {
String value = _getPluralText(key, pluralValue);
if (value == key) {
return key;
}
return _applyNamedReplacement(value, args);
}
}
class InternationalizationDelegate extends LocalizationsDelegate<Strings> {
final Locale defaultLocale;
final String path;
InternationalizationDelegate({
this.defaultLocale,
this.path,
}) : assert(defaultLocale != null && path != null);
@override
bool isSupported(Locale locale) => supportedLocales
.any((value) => value.languageCode == locale.languageCode);
@override
Future<Strings> load(Locale locale) async {
Strings strings = Strings._(this.defaultLocale, locale, this.path);
await strings._load();
return strings;
}
@override
bool shouldReload(InternationalizationDelegate old) => false;
}
TercyoStorck commented
Now it's supported. Thank you!!