Initial flame_lua_runtime package

This commit is contained in:
gem
2026-06-07 22:53:58 +08:00
commit 733b2fb798
262 changed files with 28439 additions and 0 deletions

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