This commit is contained in:
2026-03-02 16:19:26 +08:00
parent 6e62394feb
commit d79a1d15bc
9 changed files with 1157 additions and 4 deletions

View File

@@ -39,6 +39,11 @@ typedef void (^KBSkinInstallConsumeCompletion)(BOOL success, NSError * _Nullable
/// 默认图标短文件名映射(从 KBSkinIconMap.strings 读取)。
+ (NSDictionary<NSString *, NSString *> *)defaultIconShortNames;
/// 根据语言代码加载对应的图标短文件名映射。
/// @param languageCode 语言代码(如 "en", "es", "pt", "id", "zh-Hant"
/// @return 按键ID -> 切图文件名的映射字典
+ (NSDictionary<NSString *, NSString *> *)iconShortNamesForLanguageCode:(NSString *)languageCode;
/// 主 App / 键盘扩展:通过远程 zip_url 下载并安装一套皮肤。
/// - skinJSON 结构与后端约定一致,至少包含:
/// * id: 皮肤唯一标识

View File

@@ -202,6 +202,62 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json";
return map;
}
+ (NSDictionary<NSString *, NSString *> *)iconShortNamesForLanguageCode:(NSString *)languageCode {
if (languageCode.length == 0) {
return [self defaultIconShortNames];
}
static NSMutableDictionary<NSString *, NSDictionary<NSString *, NSString *> *> *cachedMaps = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
cachedMaps = [NSMutableDictionary dictionary];
});
NSDictionary<NSString *, NSString *> *cached = cachedMaps[languageCode];
if (cached) {
return cached;
}
NSString *mapFileName = nil;
if ([languageCode isEqualToString:@"es"]) {
mapFileName = @"KBSkinIconMap_es";
} else if ([languageCode isEqualToString:@"pt"]) {
mapFileName = @"KBSkinIconMap_pt";
} else if ([languageCode isEqualToString:@"id"]) {
mapFileName = @"KBSkinIconMap_id";
} else if ([languageCode hasPrefix:@"zh-Hant"] || [languageCode isEqualToString:@"zh-TW"]) {
mapFileName = @"KBSkinIconMap_zh_hant";
} else if ([languageCode hasPrefix:@"zh-Hans"] || [languageCode isEqualToString:@"zh-CN"]) {
mapFileName = @"KBSkinIconMap";
} else {
mapFileName = @"KBSkinIconMap";
}
NSString *path = [[NSBundle mainBundle] pathForResource:mapFileName ofType:@"strings"];
NSDictionary<NSString *, NSString *> *map = nil;
if (path.length > 0) {
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
if ([dict isKindOfClass:NSDictionary.class]) {
map = dict;
}
}
if (!map || map.count == 0) {
map = [self defaultIconShortNames];
}
if (map) {
cachedMaps[languageCode] = map;
}
NSLog(@"[SkinBridge] Loaded icon map for language: %@, file: %@, count: %lu",
languageCode, mapFileName, (unsigned long)map.count);
return map ?: @{};
}
+ (NSUserDefaults *)sharedDefaults {
return [[NSUserDefaults alloc] initWithSuiteName:AppGroup];
}
@@ -240,7 +296,9 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json";
if ([skinJSON[@"key_icons"] isKindOfClass:NSDictionary.class]) {
iconShortNames = skinJSON[@"key_icons"];
} else {
iconShortNames = [self defaultIconShortNames];
NSString *currentLanguageCode = [[NSUserDefaults standardUserDefaults]
stringForKey:AppGroup_SelectedKeyboardLanguageCode];
iconShortNames = [self iconShortNamesForLanguageCode:currentLanguageCode];
}
NSLog(@"[SkinBridge] iconShortNames source=%@ count=%tu",
[skinJSON[@"key_icons"] isKindOfClass:NSDictionary.class] ? @"server" : @"default",
@@ -779,7 +837,9 @@ static NSString * const kKBSkinMetadataThemeKey = @"theme_json";
NSDictionary *shortNames = payload[kKBSkinPendingIconShortKey];
if (![shortNames isKindOfClass:NSDictionary.class] || shortNames.count == 0) {
shortNames = [self defaultIconShortNames];
NSString *currentLanguageCode = [[NSUserDefaults standardUserDefaults]
stringForKey:AppGroup_SelectedKeyboardLanguageCode];
shortNames = [self iconShortNamesForLanguageCode:currentLanguageCode];
}
NSString *iconsDirFinal = iconsDir;

View File

@@ -18,7 +18,7 @@
{
"code": "es",
"name": "Español (Latinoamérica)",
"defaultSkinZip": "",
"defaultSkinZip": "西班牙初始皮肤.zip",
"layouts": [
{
"variant": "qwerty",