Task: Add i18n translator and factory for translatable for text formatter and default factory

This commit is contained in:
Sambo Chea 2021-06-17 15:25:40 +07:00
parent 84c0e44b87
commit 5915aafb95
12 changed files with 154 additions and 16 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ build/
# Omit committing pubspec.lock for library packages; see # Omit committing pubspec.lock for library packages; see
# https://dart.dev/guides/libraries/private-files#pubspeclock. # https://dart.dev/guides/libraries/private-files#pubspeclock.
pubspec.lock pubspec.lock
.dccache

View File

@ -3,8 +3,8 @@ import 'package:cubetiq/text.dart';
void main(List<String> args) { void main(List<String> args) {
var text1 = 'Hello, {0}, then do this it by {1}!'; var text1 = 'Hello, {0}, then do this it by {1}!';
var text2 = 'Hello, {firstName}, then do this it by {lastName}!'; var text2 = 'Hello, {firstName}, then do this it by {lastName}!';
var result1 = TextFormatter(text1).format(['Sambo', 'Chea']); var result1 = TextFormatter(text1).format(args: ['Sambo', 'Chea']);
var result2 = TextFormatter(text2).decorate({ var result2 = TextFormatter(text2).decorate(params: {
'firstName': 'Sambo', 'firstName': 'Sambo',
'lastName': 'Chea', 'lastName': 'Chea',
}); });

View File

@ -0,0 +1,36 @@
import 'package:cubetiq/text.dart';
import 'package:cubetiq/i18n_translator.dart';
void main(List<String> args) {
var text = 'Your name is {name}!';
// Before set provider
var result = StringUtils.decorator(text, translate: true, params: {
'name': 'Sambo Chea',
});
print('Result Before => $result');
TranslatorFactory.setProvider(TranslatorProviderExample());
// After set provider
result = StringUtils.decorator(text, translate: true, params: {
'name': 'Sambo Chea',
});
print('Result After => $result');
}
class TranslatorProviderExample implements TranslatorProvider {
@override
bool hasKey(String key) {
return false;
}
@override
String translate(String key,
{Map<String, dynamic>? params, String? fallback}) {
if (key == 'Your name is {name}!') {
return 'ឈ្មោះរបស់អ្នកគឺ {name}!';
}
return key;
}
}

4
lib/i18n_translator.dart Normal file
View File

@ -0,0 +1,4 @@
library i18n_translator;
export 'src/i18n/translator_provider.dart';
export 'src/i18n/translator_factory.dart';

View File

@ -0,0 +1,34 @@
import 'translator_provider.dart';
/// Translate Factory
///
/// @author sombochea
/// @since 1.0.0
class TranslatorFactory {
static TranslatorProvider? _provider;
static void setProvider(TranslatorProvider provider) {
_provider = provider;
}
static bool hasProvider() => _provider != null;
static bool hasKey(String key) {
if (hasProvider()) {
return _provider!.hasKey(key);
}
return false;
}
static String translate(
String key, {
Map<String, dynamic>? params,
String? fallback,
}) {
if (hasProvider()) {
return _provider!.translate(key, params: params, fallback: fallback);
}
return fallback ?? key;
}
}

View File

@ -0,0 +1,9 @@
/// Translate Provider
///
/// @author sombochea
/// @since 1.0.0
abstract class TranslatorProvider {
bool hasKey(String key);
String translate(String key,
{Map<String, dynamic>? params, String? fallback});
}

View File

@ -7,10 +7,11 @@ extension StringExtensionOnNonull on String {
} }
extension StringExtensionOnNullable on String? { extension StringExtensionOnNullable on String? {
String? textFormat(List<dynamic> args) => StringUtils.textFormat(this, args); String? textFormat({List<dynamic>? args, bool translate = false}) =>
StringUtils.textFormat(this, args: args, translate: translate);
String? decorator(Map<String, dynamic> params) => String? decorator({Map<String, dynamic>? params, bool translate = false}) =>
StringUtils.decorator(this, params); StringUtils.decorator(this, params: params, translate: translate);
bool get isBlank { bool get isBlank {
if (this == null) return true; if (this == null) return true;

View File

@ -13,13 +13,19 @@ class StringUtils {
return n.toStringAsFixed(n.truncateToDouble() == n ? precision : precision); return n.toStringAsFixed(n.truncateToDouble() == n ? precision : precision);
} }
/// Text formatter with custom args
static TextFormatter textFormatter(String? text, {bool translate = false}) =>
TextFormatter(text).translate(translate: translate);
/// Text format with custom args /// Text format with custom args
static String? textFormat(String? text, List<dynamic> args) => static String? textFormat(String? text,
TextFormatter(text).format(args); {List<dynamic>? args, bool translate = false}) =>
textFormatter(text, translate: translate).format(args: args);
/// Text decorator with custom key/value params /// Text decorator with custom key/value params
static String? decorator(String? text, Map<String, dynamic> params) => static String? decorator(String? text,
TextFormatter(text).decorate(params); {Map<String, dynamic>? params, bool translate = false}) =>
textFormatter(text, translate: translate).decorate(params: params);
static String? asLowerCaseThenTrim(String? text) => static String? asLowerCaseThenTrim(String? text) =>
text?.toLowerCase().trim(); text?.toLowerCase().trim();

View File

@ -1,3 +1,5 @@
import 'package:cubetiq/i18n_translator.dart';
/// Text Formatter /// Text Formatter
/// ///
/// @author sombochea /// @author sombochea
@ -9,12 +11,20 @@ class TextFormatter {
this.text = text; this.text = text;
} }
String? format(List<dynamic> args) { TextFormatter translate({bool translate = true}) {
if (translate && text != null && text?.isNotEmpty == true) {
text = TranslatorFactory.translate(text!);
}
return this;
}
String? format({List<dynamic>? args}) {
if (text == null) { if (text == null) {
return null; return null;
} }
if (args.isEmpty) { if (args == null || args.isEmpty == true) {
return text; return text;
} }
@ -31,12 +41,12 @@ class TextFormatter {
return msg; return msg;
} }
String? decorate(Map<String, dynamic> params) { String? decorate({Map<String, dynamic>? params}) {
if (text == null) { if (text == null) {
return null; return null;
} }
if (params.isEmpty) { if (params == null || params.isEmpty == true) {
return text; return text;
} }

View File

@ -25,7 +25,7 @@ abstract class XLogProvider {
if (args == null || args.isEmpty) { if (args == null || args.isEmpty) {
content = data; content = data;
} else { } else {
content = StringUtils.textFormat(data, args) ?? 'null'; content = StringUtils.textFormat(data, args: args) ?? 'null';
} }
var text = '[$type] ${nowToString()}: $prefix => $content'.trim(); var text = '[$type] ${nowToString()}: $prefix => $content'.trim();

View File

@ -0,0 +1,37 @@
import 'package:cubetiq/i18n_translator.dart';
import 'package:cubetiq/src/xlog/xlog.dart';
import 'package:cubetiq/text.dart';
import 'package:test/test.dart';
void main() {
test('test translate function', () {
var text1 = 'Hello, my name is {0}!';
var result1 = TextFormatter(text1).translate().format(args: ['Sambo']);
XLog.success(result1);
expect('Hello, my name is Sambo!', result1);
TranslatorFactory.setProvider(TranslatorProviderExample());
result1 = TextFormatter(text1).translate().format(args: ['Sambo']);
XLog.success(result1);
expect('ឈ្មោះរបស់អ្នកគឺ Sambo!', result1);
});
}
class TranslatorProviderExample implements TranslatorProvider {
@override
bool hasKey(String key) {
return false;
}
@override
String translate(String key,
{Map<String, dynamic>? params, String? fallback}) {
if (key == 'Hello, my name is {0}!') {
return 'ឈ្មោះរបស់អ្នកគឺ {0}!';
}
return key;
}
}

View File

@ -4,10 +4,10 @@ import 'package:test/test.dart';
void main() { void main() {
test('text formatter function format', () { test('text formatter function format', () {
var text1 = 'Hello, {0}!'; var text1 = 'Hello, {0}!';
var result1 = TextFormatter(text1).format(['Sambo']); var result1 = TextFormatter(text1).format(args: ['Sambo']);
var text2 = 'Hello, {name}!'; var text2 = 'Hello, {name}!';
var result2 = TextFormatter(text2).decorate({'name': 'Chea'}); var result2 = TextFormatter(text2).decorate(params: {'name': 'Chea'});
expect('Hello, Sambo!', result1); expect('Hello, Sambo!', result1);
expect('Hello, Chea!', result2); expect('Hello, Chea!', result2);