feat: add runtime i18n API with manifest translations

This commit is contained in:
gem
2026-06-12 10:19:14 +08:00
parent 79ee35db2f
commit 4ea3663853
8 changed files with 141 additions and 0 deletions

View File

@@ -186,6 +186,7 @@ class PackageActivationController {
_ensureContinue(shouldContinue);
return PackageActivationPlan(
package: candidate,
packages: allPackages,
initialDiff: diff,
resources: preparedResources,
scriptEngine: preparedScriptEngine,
@@ -219,6 +220,7 @@ class PackageActivationController {
class PackageActivationPlan {
const PackageActivationPlan({
required this.package,
required this.packages,
required this.initialDiff,
required this.resources,
required this.scriptEngine,
@@ -226,6 +228,7 @@ class PackageActivationPlan {
});
final GamePackage package;
final List<GamePackage> packages;
final GameDiff initialDiff;
final GameResourceManager resources;
final ScriptEngine scriptEngine;
@@ -235,6 +238,7 @@ class PackageActivationPlan {
class PackageActivationResult {
const PackageActivationResult({
required this.package,
required this.packages,
required this.initialDiff,
required this.resources,
required this.scriptEngine,
@@ -244,6 +248,7 @@ class PackageActivationResult {
factory PackageActivationResult.fromPlan(PackageActivationPlan plan) {
return PackageActivationResult(
package: plan.package,
packages: plan.packages,
initialDiff: plan.initialDiff,
resources: plan.resources,
scriptEngine: plan.scriptEngine,
@@ -252,6 +257,7 @@ class PackageActivationResult {
}
final GamePackage package;
final List<GamePackage> packages;
final GameDiff initialDiff;
final GameResourceManager resources;
final ScriptEngine scriptEngine;

View File

@@ -15,6 +15,7 @@ class GamePackageManifest {
this.display = const GameDisplayConfig(),
this.resources = const {},
this.modules = const {},
this.translations = const {},
this.base,
});
@@ -30,6 +31,10 @@ class GamePackageManifest {
final Map<String, GameResource> resources;
final Map<String, String> modules;
/// 翻译字典locale → { key → translatedText }。
/// Runtime 会按包加载顺序合并,游戏包覆盖框架包。
final Map<String, Map<String, String>> translations;
/// 依赖的框架包 gameId。加载时会先加载框架包再加载游戏包。
final String? base;
@@ -64,6 +69,26 @@ class GamePackageManifest {
final base = map['base'] as String?;
final translationsValue = map['translations'];
final translations = <String, Map<String, String>>{};
if (translationsValue is Map) {
for (final entry in translationsValue.entries) {
if (entry.key is! String || entry.value is! Map) {
throw const FormatException('manifest.translations must be a map');
}
final localeDict = <String, String>{};
for (final kv in (entry.value as Map).entries) {
if (kv.key is! String || kv.value is! String) {
throw const FormatException(
'manifest.translations values must be string maps',
);
}
localeDict[kv.key as String] = kv.value as String;
}
translations[entry.key as String] = localeDict;
}
}
final defaultLocale = (map['defaultLocale'] as String?) ?? 'en';
final supportedLocales = _stringList(
map,
@@ -95,6 +120,7 @@ class GamePackageManifest {
display: display,
resources: resources,
modules: modules,
translations: translations,
base: base,
);
}