添加西班牙词库

This commit is contained in:
2026-03-02 16:34:59 +08:00
parent d79a1d15bc
commit 04cfc35485
5 changed files with 170 additions and 4 deletions

View File

@@ -8,7 +8,8 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, KBSuggestionEngineType) { typedef NS_ENUM(NSInteger, KBSuggestionEngineType) {
KBSuggestionEngineTypeLatin = 0, // 拉丁字母(英语、西班牙语、葡萄牙语、印尼语) KBSuggestionEngineTypeLatin = 0, // 拉丁字母(英语、葡萄牙语、印尼语)
KBSuggestionEngineTypeSpanish, // 西班牙语
KBSuggestionEngineTypePinyinSimplified, // 简体拼音 KBSuggestionEngineTypePinyinSimplified, // 简体拼音
KBSuggestionEngineTypePinyinTraditional, // 繁体拼音 KBSuggestionEngineTypePinyinTraditional, // 繁体拼音
KBSuggestionEngineTypeBopomofo // 注音(繁体) KBSuggestionEngineTypeBopomofo // 注音(繁体)

View File

@@ -14,6 +14,7 @@
@property (nonatomic, copy) NSArray<NSString *> *simplifiedChineseWords; @property (nonatomic, copy) NSArray<NSString *> *simplifiedChineseWords;
@property (nonatomic, strong) NSDictionary<NSString *, NSArray<NSString *> *> *pinyinToTraditionalMap; @property (nonatomic, strong) NSDictionary<NSString *, NSArray<NSString *> *> *pinyinToTraditionalMap;
@property (nonatomic, strong) NSDictionary<NSString *, NSArray<NSString *> *> *bopomofoToChineseMap; @property (nonatomic, strong) NSDictionary<NSString *, NSArray<NSString *> *> *bopomofoToChineseMap;
@property (nonatomic, copy) NSArray<NSString *> *spanishWords;
@end @end
@implementation KBSuggestionEngine @implementation KBSuggestionEngine
@@ -38,6 +39,7 @@
_simplifiedChineseWords = [self kb_loadSimplifiedChineseWords]; _simplifiedChineseWords = [self kb_loadSimplifiedChineseWords];
_pinyinToTraditionalMap = [self kb_loadPinyinToTraditionalMap]; _pinyinToTraditionalMap = [self kb_loadPinyinToTraditionalMap];
_bopomofoToChineseMap = [self kb_loadBopomofoToChineseMap]; _bopomofoToChineseMap = [self kb_loadBopomofoToChineseMap];
_spanishWords = [self kb_loadSpanishWords];
} }
return self; return self;
} }
@@ -45,8 +47,9 @@
- (NSArray<NSString *> *)suggestionsForPrefix:(NSString *)prefix limit:(NSUInteger)limit { - (NSArray<NSString *> *)suggestionsForPrefix:(NSString *)prefix limit:(NSUInteger)limit {
if (prefix.length == 0 || limit == 0) { return @[]; } if (prefix.length == 0 || limit == 0) { return @[]; }
//
switch (self.engineType) { switch (self.engineType) {
case KBSuggestionEngineTypeSpanish:
return [self kb_spanishSuggestionsForPrefix:prefix limit:limit];
case KBSuggestionEngineTypePinyinTraditional: case KBSuggestionEngineTypePinyinTraditional:
return [self kb_traditionalPinyinSuggestionsForPrefix:prefix limit:limit]; return [self kb_traditionalPinyinSuggestionsForPrefix:prefix limit:limit];
case KBSuggestionEngineTypePinyinSimplified: case KBSuggestionEngineTypePinyinSimplified:
@@ -158,6 +161,8 @@
- (void)setEngineTypeFromString:(NSString *)engineTypeString { - (void)setEngineTypeFromString:(NSString *)engineTypeString {
if ([engineTypeString isEqualToString:@"latin"]) { if ([engineTypeString isEqualToString:@"latin"]) {
self.engineType = KBSuggestionEngineTypeLatin; self.engineType = KBSuggestionEngineTypeLatin;
} else if ([engineTypeString isEqualToString:@"spanish"]) {
self.engineType = KBSuggestionEngineTypeSpanish;
} else if ([engineTypeString isEqualToString:@"pinyin_traditional"]) { } else if ([engineTypeString isEqualToString:@"pinyin_traditional"]) {
self.engineType = KBSuggestionEngineTypePinyinTraditional; self.engineType = KBSuggestionEngineTypePinyinTraditional;
} else if ([engineTypeString isEqualToString:@"pinyin_simplified"]) { } else if ([engineTypeString isEqualToString:@"pinyin_simplified"]) {
@@ -531,4 +536,75 @@
return [result copy]; return [result copy];
} }
#pragma mark - Spanish Suggestions
- (NSArray<NSString *> *)kb_spanishSuggestionsForPrefix:(NSString *)prefix limit:(NSUInteger)limit {
NSString *lower = prefix.lowercaseString;
NSMutableArray<NSString *> *matches = [NSMutableArray array];
for (NSString *word in self.spanishWords) {
if ([word hasPrefix:lower]) {
[matches addObject:word];
if (matches.count >= limit * 2) {
break;
}
}
}
if (matches.count == 0) {
return [self kb_latinSuggestionsForPrefix:prefix limit:limit];
}
[matches sortUsingComparator:^NSComparisonResult(NSString *a, NSString *b) {
NSInteger ca = self.selectionCounts[a].integerValue;
NSInteger cb = self.selectionCounts[b].integerValue;
if (ca != cb) {
return (cb > ca) ? NSOrderedAscending : NSOrderedDescending;
}
return [a compare:b];
}];
if (matches.count > limit) {
return [matches subarrayWithRange:NSMakeRange(0, limit)];
}
return matches.copy;
}
- (NSArray<NSString *> *)kb_loadSpanishWords {
NSString *path = [[NSBundle mainBundle] pathForResource:@"spanish_words" ofType:@"json"];
if (!path) {
NSLog(@"[KBSuggestionEngine] spanish_words.json not found, using default words");
return [self.class kb_defaultWords];
}
NSData *data = [NSData dataWithContentsOfFile:path];
if (!data) {
NSLog(@"[KBSuggestionEngine] Failed to read spanish_words.json");
return [self.class kb_defaultWords];
}
NSError *error = nil;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (error || ![json isKindOfClass:NSDictionary.class]) {
NSLog(@"[KBSuggestionEngine] Failed to parse spanish_words.json: %@", error);
return [self.class kb_defaultWords];
}
NSArray *wordsArray = json[@"words"];
if (![wordsArray isKindOfClass:NSArray.class]) {
NSLog(@"[KBSuggestionEngine] Invalid words array in spanish_words.json");
return [self.class kb_defaultWords];
}
NSMutableArray<NSString *> *result = [NSMutableArray array];
for (id item in wordsArray) {
if ([item isKindOfClass:NSString.class]) {
[result addObject:item];
}
}
NSLog(@"[KBSuggestionEngine] Loaded %lu Spanish words", (unsigned long)result.count);
return result.count > 0 ? [result copy] : [self.class kb_defaultWords];
}
@end @end

View File

@@ -0,0 +1,85 @@
{
"__comment": "西班牙语(拉丁美洲)常用词库",
"words": [
"hola", "gracias", "por favor", "buenos días", "buenas tardes",
"buenas noches", "adiós", "hasta luego", "cómo estás", "muy bien",
"qué", "dónde", "cuándo", "por qué", "quién",
"cómo", "cuánto", "cuál", "cuáles", "dónde",
"aquí", "allí", "ahora", "después", "antes",
"hoy", "mañana", "ayer", "siempre", "nunca",
"también", "tampoco", "sí", "no", "tal vez",
"yo", "tú", "él", "ella", "nosotros",
"ellos", "ellas", "usted", "ustedes", "mí",
"ti", "sí", "conmigo", "contigo", "consigo",
"ser", "estar", "tener", "haber", "hacer",
"ir", "venir", "decir", "ver", "poder",
"dar", "saber", "querer", "pensar", "sentir",
"creer", "vivir", "morir", "nacer", "crecer",
"hablar", "escuchar", "mirar", "tocar", "oler",
"gustar", "amar", "odiar", "esperar", "temer",
"casa", "coche", "trabajo", "dinero", "tiempo",
"año", "mes", "semana", "día", "hora",
"minuto", "segundo", "momento", "vida", "muerte",
"amor", "odio", "paz", "guerra", "libertad",
"amigo", "amiga", "hermano", "hermana", "padre",
"madre", "hijo", "hija", "abuelo", "abuela",
"tío", "tía", "primo", "prima", "esposo",
"esposa", "novio", "novia", "familia", "pareja",
"agua", "comida", "ropa", "cama", "mesa",
"silla", "puerta", "ventana", "pared", "suelo",
"cielo", "sol", "luna", "estrella", "nube",
"lluvia", "nieve", "viento", "fuego", "tierra",
"árbol", "flor", "fruta", "verdura", "carne",
"pescado", "pan", "leche", "café", "cerveza",
"vino", "jugo", "azúcar", "sal", "aceite",
"grande", "pequeño", "alto", "bajo", "largo",
"corto", "ancho", "estrecho", "gordo", "delgado",
"bonito", "feo", "bueno", "malo", "nuevo",
"viejo", "joven", "antiguo", "moderno", "fácil",
"difícil", "rápido", "lento", "fuerte", "débil",
"caliente", "frío", "tibio", "seco", "mojado",
"limpio", "sucio", "ordenado", "desordenado", "lleno",
"vacío", "abierto", "cerrado", "encendido", "apagado",
"uno", "dos", "tres", "cuatro", "cinco",
"seis", "siete", "ocho", "nueve", "diez",
"once", "doce", "trece", "catorce", "quince",
"veinte", "treinta", "cuarenta", "cincuenta", "cien",
"mil", "millón", "primero", "segundo", "tercero",
"último", "siguiente", "anterior", "nuevo", "otro",
"mismo", "diferente", "igual", "similar", "opuesto",
"derecha", "izquierda", "arriba", "abajo", "delante",
"detrás", "dentro", "fuera", "cerca", "lejos",
"encima", "debajo", "entre", "alrededor", "a través",
"hacia", "desde", "hasta", "para", "por",
"con", "sin", "sobre", "bajo", "entre",
"contra", "según", "durante", "mediante", "excepto",
"salvo", "incluso", "aun", "aunque", "pero",
"sino", "porque", "pues", "como", "si",
"cuando", "mientras", "aunque", "a pesar de", "sin embargo",
"además", "también", "asimismo", "por lo tanto", "por consiguiente",
"así que", "de modo que", "ya que", "dado que", "visto que",
"es necesario", "es importante", "es posible", "es probable", "es evidente",
"me gusta", "me encanta", "me interesa", "me importa", "me parece",
"creo que", "pienso que", "digo que", "sé que", "veo que",
"quiero", "puedo", "debo", "tengo que", "hay que",
"vamos a", "vengo de", "voy a", "tengo que", "hay que",
"está bien", "está mal", "no importa", "no problem", "claro",
"claro que sí", "claro que no", "por supuesto", "exacto", "correcto",
"perfecto", "excelente", "genial", "increíble", "impresionante",
"maravilloso", "fantástico", "terrible", "horrible", "espantoso",
"increíble", "asombroso", "sorprendente", "extraño", "raro",
"normal", "común", "frecuente", "habitual", "usual",
"especial", "único", "particular", "específico", "concreto",
"general", "total", "completo", "absoluto", "relativo",
"verdadero", "falso", "real", "imaginario", "posible",
"imposible", "probable", "improbable", "seguro", "incierto",
"cierto", "dudoso", "claro", "oscuro", "confuso",
"simple", "complicado", "complejo", "sencillo", "fácil",
"dificil", "imposible", "posible", "probable", "improbable",
"mexico", "españa", "argentina", "colombia", "perú",
"chile", "venezuela", "ecuador", "guatemala", "cuba",
"bolivia", "honduras", "paraguay", "el salvador", "nicaragua",
"costa rica", "panamá", "uruguay", "puerto rico", "república dominicana",
"latinoamérica", "hispanoamérica", "américa latina", "el mundo", "el país"
]
}

View File

@@ -18,14 +18,14 @@
{ {
"code": "es", "code": "es",
"name": "Español (Latinoamérica)", "name": "Español (Latinoamérica)",
"defaultSkinZip": "西班牙初始皮肤.zip", "defaultSkinZip": "",
"layouts": [ "layouts": [
{ {
"variant": "qwerty", "variant": "qwerty",
"title": "QWERTY", "title": "QWERTY",
"profileId": "es_419_qwerty", "profileId": "es_419_qwerty",
"layoutJsonId": "letters_es", "layoutJsonId": "letters_es",
"suggestionEngine": "latin" "suggestionEngine": "spanish"
} }
] ]
}, },

View File

@@ -45,6 +45,7 @@
043213B12F556DF80065C888 /* KBSkinIconMap_es.strings in Resources */ = {isa = PBXBuildFile; fileRef = 043213AB2F556DF80065C888 /* KBSkinIconMap_es.strings */; }; 043213B12F556DF80065C888 /* KBSkinIconMap_es.strings in Resources */ = {isa = PBXBuildFile; fileRef = 043213AB2F556DF80065C888 /* KBSkinIconMap_es.strings */; };
043213B22F556DF80065C888 /* KBSkinIconMap_zh_hant.strings in Resources */ = {isa = PBXBuildFile; fileRef = 043213AE2F556DF80065C888 /* KBSkinIconMap_zh_hant.strings */; }; 043213B22F556DF80065C888 /* KBSkinIconMap_zh_hant.strings in Resources */ = {isa = PBXBuildFile; fileRef = 043213AE2F556DF80065C888 /* KBSkinIconMap_zh_hant.strings */; };
043213B42F557CC50065C888 /* 西班牙初始皮肤.zip in Resources */ = {isa = PBXBuildFile; fileRef = 043213B32F557CC50065C888 /* 西班牙初始皮肤.zip */; }; 043213B42F557CC50065C888 /* 西班牙初始皮肤.zip in Resources */ = {isa = PBXBuildFile; fileRef = 043213B32F557CC50065C888 /* 西班牙初始皮肤.zip */; };
043213B62F5582710065C888 /* spanish_words.json in Resources */ = {isa = PBXBuildFile; fileRef = 043213B52F5582710065C888 /* spanish_words.json */; };
043FBCD22EAF97630036AFE1 /* KBPermissionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C6EAE12EAF940F0089C901 /* KBPermissionViewController.m */; }; 043FBCD22EAF97630036AFE1 /* KBPermissionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 04C6EAE12EAF940F0089C901 /* KBPermissionViewController.m */; };
0450AA742EF013D000B6AF06 /* KBEmojiCollectionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 0450AA732EF013D000B6AF06 /* KBEmojiCollectionCell.m */; }; 0450AA742EF013D000B6AF06 /* KBEmojiCollectionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 0450AA732EF013D000B6AF06 /* KBEmojiCollectionCell.m */; };
0450AAE22EF03D5100B6AF06 /* KBPerson.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450AAE12EF03D5100B6AF06 /* KBPerson.swift */; }; 0450AAE22EF03D5100B6AF06 /* KBPerson.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450AAE12EF03D5100B6AF06 /* KBPerson.swift */; };
@@ -402,6 +403,7 @@
043213AD2F556DF80065C888 /* KBSkinIconMap_pt.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = KBSkinIconMap_pt.strings; sourceTree = "<group>"; }; 043213AD2F556DF80065C888 /* KBSkinIconMap_pt.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = KBSkinIconMap_pt.strings; sourceTree = "<group>"; };
043213AE2F556DF80065C888 /* KBSkinIconMap_zh_hant.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = KBSkinIconMap_zh_hant.strings; sourceTree = "<group>"; }; 043213AE2F556DF80065C888 /* KBSkinIconMap_zh_hant.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = KBSkinIconMap_zh_hant.strings; sourceTree = "<group>"; };
043213B32F557CC50065C888 /* 西班牙初始皮肤.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = "西班牙初始皮肤.zip"; sourceTree = "<group>"; }; 043213B32F557CC50065C888 /* 西班牙初始皮肤.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = "西班牙初始皮肤.zip"; sourceTree = "<group>"; };
043213B52F5582710065C888 /* spanish_words.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = spanish_words.json; sourceTree = "<group>"; };
0450AA722EF013D000B6AF06 /* KBEmojiCollectionCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBEmojiCollectionCell.h; sourceTree = "<group>"; }; 0450AA722EF013D000B6AF06 /* KBEmojiCollectionCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBEmojiCollectionCell.h; sourceTree = "<group>"; };
0450AA732EF013D000B6AF06 /* KBEmojiCollectionCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBEmojiCollectionCell.m; sourceTree = "<group>"; }; 0450AA732EF013D000B6AF06 /* KBEmojiCollectionCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBEmojiCollectionCell.m; sourceTree = "<group>"; };
0450AAE02EF03D5100B6AF06 /* keyBoard-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "keyBoard-Bridging-Header.h"; sourceTree = "<group>"; }; 0450AAE02EF03D5100B6AF06 /* keyBoard-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "keyBoard-Bridging-Header.h"; sourceTree = "<group>"; };
@@ -945,6 +947,7 @@
043213AC2F556DF80065C888 /* KBSkinIconMap_id.strings */, 043213AC2F556DF80065C888 /* KBSkinIconMap_id.strings */,
043213AD2F556DF80065C888 /* KBSkinIconMap_pt.strings */, 043213AD2F556DF80065C888 /* KBSkinIconMap_pt.strings */,
043213AE2F556DF80065C888 /* KBSkinIconMap_zh_hant.strings */, 043213AE2F556DF80065C888 /* KBSkinIconMap_zh_hant.strings */,
043213B52F5582710065C888 /* spanish_words.json */,
); );
path = Resource; path = Resource;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -2311,6 +2314,7 @@
043213A42F5528140065C888 /* pinyin_to_traditional.json in Resources */, 043213A42F5528140065C888 /* pinyin_to_traditional.json in Resources */,
043213AA2F5566EF0065C888 /* kb_input_profiles.json in Resources */, 043213AA2F5566EF0065C888 /* kb_input_profiles.json in Resources */,
04286A0B2ECD88B400CE730C /* KeyboardAssets.xcassets in Resources */, 04286A0B2ECD88B400CE730C /* KeyboardAssets.xcassets in Resources */,
043213B62F5582710065C888 /* spanish_words.json in Resources */,
043213A62F5561FD0065C888 /* kb_keyboard_layouts_i18n.json in Resources */, 043213A62F5561FD0065C888 /* kb_keyboard_layouts_i18n.json in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;