Skip to content

Instantly share code, notes, and snippets.

@luo3house
Last active April 26, 2023 06:45
Show Gist options
  • Save luo3house/9d6784ceba1eefc17a60dbebe321d8be to your computer and use it in GitHub Desktop.
Save luo3house/9d6784ceba1eefc17a60dbebe321d8be to your computer and use it in GitHub Desktop.
Simple i18n strings mapper
class Translation {
// "zh-a-b-c" -> m"-c"
static final _localeSuffixRE = RegExp(r"-[^-]+$");
final bool localeCaseSensitive;
var _currentLocale = "en";
var _fallbackLocale = "en";
Map<String, Map<String, String>> dict = Map();
Translation({
this.localeCaseSensitive = false,
Map<String, Map<String, String>>? dict,
}) {
this.dict = dict ?? Map();
}
Translation clone() => Translation(dict: dict, localeCaseSensitive: localeCaseSensitive)
..setLocale(_currentLocale)
..setFallbackLocale(_fallbackLocale);
void setLocale(String hyphenLocale) => _currentLocale = hyphenLocale;
void setFallbackLocale(String hyphenLocale) => _fallbackLocale = hyphenLocale;
String getLocale() => _currentLocale;
String getFallbackLocale() => _fallbackLocale;
/// Install a localized dictionary
install(String hyphenLocale, Map<String, String> trs) {
if (!localeCaseSensitive) hyphenLocale = hyphenLocale.toLowerCase();
final existsTranslations = dict[hyphenLocale] ?? {};
dict[hyphenLocale] = Map.fromEntries([
...existsTranslations.entries,
...trs.entries,
]);
}
/// Translate nullable
String? tr(String key) => find(_currentLocale, key) ?? find(_fallbackLocale, key);
/// Translate or fallback or key
String tror(String key, [String? fallback]) => tr(key) ?? fallback ?? key;
/// | Translations | Key | Result | Reason |
/// | ----------------------- | ------------ | ------------ | ------------- |
/// | `{ zh-CN }` | `zh-CN` | `zh-CN` | Exact |
/// | `{ zh }` | `zh-CN` | `zh` | StartsWith |
/// | `{ zh-CN, zh-HK }` | `zh` | `zh-CN` | FirstKey |
/// | `{ zh-Hant, zh-HK }` | `zh-SG` | `zh-Hant` | FirstKey |
/// | `{ zh-Hant-HK, zh-CN }` | `zh-Hant` | `zh-Hant-HK` | StartsWith |
/// | `{ zh-Hant, zh-CN }` | `zh-Hant-HK` | `zh-Hant` | 2x StartsWith |
String? find(String hyphenLocale, String key) {
if (!localeCaseSensitive) hyphenLocale = hyphenLocale.toLowerCase();
if (dict[hyphenLocale]?[key] != null) {
return dict[hyphenLocale]![key];
} else if (_localeSuffixRE.hasMatch(hyphenLocale)) {
return find(hyphenLocale.replaceAll(_localeSuffixRE, ""), key);
} else {
final foundKeys = dict.keys.where((key) => key.startsWith(hyphenLocale));
return foundKeys.isNotEmpty ? (dict[foundKeys.first]?[key]) : null;
}
}
}
void main() {
test("install merge", () {
final trs = Translation()
..install("en-US", {"hello": "hello"})
..install("en-US", {"color": "colour"})
..install("en-US", {"color": "color"});
expect(
"${trs.tr("hello")},${trs.tr("color")}",
"hello,color",
);
});
test("partial fallback", () {
final trs = Translation()
..install("en-UK", {"color": "colour"})
..install("en", {"hello": "hello"})
..setLocale("en-UK");
expect(trs.tr("hello"), "hello");
});
test("fallback locale", () {
final trs = Translation()
..install("zh-CN", {"yanse": "颜色"})
..install("en-UK", {"yanse": "colour"})
..setLocale("rn-RU")
..setFallbackLocale("en");
expect(trs.tr("yanse"), "colour");
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment