Initial flame_lua_runtime package
This commit is contained in:
162
lib/runtime/game/runtime_locale.dart
Normal file
162
lib/runtime/game/runtime_locale.dart
Normal file
@@ -0,0 +1,162 @@
|
||||
import 'dart:ui' show Locale;
|
||||
|
||||
class RuntimeLocaleInfo {
|
||||
const RuntimeLocaleInfo({
|
||||
required this.requested,
|
||||
required this.resolved,
|
||||
required this.defaultLocale,
|
||||
required this.supportedLocales,
|
||||
required this.languageCode,
|
||||
this.scriptCode,
|
||||
this.countryCode,
|
||||
});
|
||||
|
||||
final String requested;
|
||||
final String resolved;
|
||||
final String defaultLocale;
|
||||
final List<String> supportedLocales;
|
||||
final String languageCode;
|
||||
final String? scriptCode;
|
||||
final String? countryCode;
|
||||
|
||||
Map<String, Object?> toMap() {
|
||||
return {
|
||||
'requested': requested,
|
||||
'resolved': resolved,
|
||||
'default': defaultLocale,
|
||||
'supported': supportedLocales,
|
||||
'languageCode': languageCode,
|
||||
if (scriptCode != null) 'scriptCode': scriptCode,
|
||||
if (countryCode != null) 'countryCode': countryCode,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class RuntimeLocaleResolver {
|
||||
const RuntimeLocaleResolver._();
|
||||
|
||||
static RuntimeLocaleInfo resolve({
|
||||
required Locale requested,
|
||||
required String defaultLocale,
|
||||
required List<String> supportedLocales,
|
||||
}) {
|
||||
final requestedTag = normalizeTag(tagOf(requested));
|
||||
final fallback = normalizeTag(defaultLocale);
|
||||
final supported = supportedLocales.isEmpty
|
||||
? [fallback]
|
||||
: supportedLocales.map(normalizeTag).toList(growable: false);
|
||||
final resolved = _resolveTag(
|
||||
requestedTag: requestedTag,
|
||||
fallback: fallback,
|
||||
supported: supported,
|
||||
);
|
||||
|
||||
return RuntimeLocaleInfo(
|
||||
requested: requestedTag,
|
||||
resolved: resolved,
|
||||
defaultLocale: fallback,
|
||||
supportedLocales: supported,
|
||||
languageCode: requested.languageCode,
|
||||
scriptCode: requested.scriptCode,
|
||||
countryCode: requested.countryCode,
|
||||
);
|
||||
}
|
||||
|
||||
static Locale localeFromTag(String tag) {
|
||||
final parts = normalizeTag(tag).split('-');
|
||||
if (parts.isEmpty || parts.first.isEmpty) {
|
||||
throw const FormatException('Locale tag must not be empty');
|
||||
}
|
||||
|
||||
String? scriptCode;
|
||||
String? countryCode;
|
||||
for (final part in parts.skip(1)) {
|
||||
if (part.length == 4 && scriptCode == null) {
|
||||
scriptCode = part;
|
||||
} else {
|
||||
countryCode ??= part;
|
||||
}
|
||||
}
|
||||
|
||||
return Locale.fromSubtags(
|
||||
languageCode: parts.first,
|
||||
scriptCode: scriptCode,
|
||||
countryCode: countryCode,
|
||||
);
|
||||
}
|
||||
|
||||
static String tagOf(Locale locale) {
|
||||
final parts = [locale.languageCode];
|
||||
final scriptCode = locale.scriptCode;
|
||||
final countryCode = locale.countryCode;
|
||||
if (scriptCode != null && scriptCode.isNotEmpty) {
|
||||
parts.add(scriptCode);
|
||||
}
|
||||
if (countryCode != null && countryCode.isNotEmpty) {
|
||||
parts.add(countryCode);
|
||||
}
|
||||
return normalizeTag(parts.join('-'));
|
||||
}
|
||||
|
||||
static String normalizeTag(String tag) {
|
||||
final normalized = tag.trim().replaceAll('_', '-');
|
||||
if (normalized.isEmpty) {
|
||||
throw const FormatException('Locale tag must not be empty');
|
||||
}
|
||||
|
||||
final parts = normalized
|
||||
.split('-')
|
||||
.where((part) => part.isNotEmpty)
|
||||
.toList(growable: false);
|
||||
if (parts.isEmpty) {
|
||||
throw const FormatException('Locale tag must not be empty');
|
||||
}
|
||||
if (!_isLocalePart(parts.first)) {
|
||||
throw FormatException('Locale language code is invalid: ${parts.first}');
|
||||
}
|
||||
|
||||
final result = <String>[parts.first.toLowerCase()];
|
||||
for (final part in parts.skip(1)) {
|
||||
if (!_isLocalePart(part)) {
|
||||
throw FormatException('Locale tag part is invalid: $part');
|
||||
}
|
||||
if (part.length == 4) {
|
||||
result.add(
|
||||
'${part[0].toUpperCase()}${part.substring(1).toLowerCase()}',
|
||||
);
|
||||
} else if (part.length == 2 || part.length == 3) {
|
||||
result.add(part.toUpperCase());
|
||||
} else {
|
||||
result.add(part.toLowerCase());
|
||||
}
|
||||
}
|
||||
return result.join('-');
|
||||
}
|
||||
|
||||
static String _resolveTag({
|
||||
required String requestedTag,
|
||||
required String fallback,
|
||||
required List<String> supported,
|
||||
}) {
|
||||
final supportedSet = supported.toSet();
|
||||
if (supportedSet.contains(requestedTag)) {
|
||||
return requestedTag;
|
||||
}
|
||||
|
||||
final requestedLanguage = requestedTag.split('-').first;
|
||||
for (final candidate in supported) {
|
||||
if (candidate.split('-').first == requestedLanguage) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
if (supportedSet.contains(fallback)) {
|
||||
return fallback;
|
||||
}
|
||||
return supported.first;
|
||||
}
|
||||
|
||||
static bool _isLocalePart(String value) {
|
||||
return RegExp(r'^[A-Za-z0-9]{2,8}$').hasMatch(value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user