У меня есть локализованная строка, которая должна принимать несколько переменных. Однако при локализации важно, чтобы порядок переменных мог меняться от языка к языку.
Так что это не очень хорошая идея:
NSString *text = NSLocalizedString(@"My birthday is at %@ %@ in %@", nil);
В некоторых языках одни слова стоят перед другими, в то время как в других это наоборот. У меня нет хорошего примера на данный момент.
Как бы я предоставил переменные NAMED в форматированной строке? Есть ли способ сделать это без каких-либо тяжелых самодельных замен строк? Даже некоторых пронумерованных переменных, таких как {% @ 1}, {% @ 2} и т. Д., Будет достаточно ... есть ли решение?
Вот почему NSLocalizedString
принимает два параметра. Используйте второй параметр, чтобы включить комментарий, описывающий значение переменных на родном языке. Затем переводчики могут переупорядочить их, используя конструкцию $
+ number. См. Примечания для локализаторов Apple .
Однако вы не можете пропустить параметры на одном языке. Например, если у вас есть 3 параметра на английском языке и 4 на французском языке, а третий вам не нужен на английском языке, вы не можете форматировать как % 1 $ @% 2 $ @ и% 4 $ @
. Вы можете пропустить только последнее.
Я решил эту проблему в своем проекте несколько недель назад, построив свою собственную простую систему шаблонов с NSScanner
. Метод использует систему шаблонов, которая находит переменные с синтаксисом $ {name}
. Переменные передаются в метод через NSDictionary
.
- (NSString *)localizedStringFromTemplateString:(NSString *)string variables:(NSDictionary *)variables {
NSMutableString *result = [NSMutableString string];
// Create scanner with the localized string
NSScanner *scanner = [[NSScanner alloc] initWithString:NSLocalizedString(string, nil)];
[scanner setCharactersToBeSkipped:nil];
NSString *output;
while (![scanner isAtEnd]) {
output = NULL;
// Find ${variable} templates
if ([scanner scanUpToString:@"${" intoString:&output]) {
[result appendString:output];
// Skip syntax
[scanner scanString:@"${" intoString:NULL];
output = NULL;
if ([scanner scanUpToString:@"}" intoString:&output]) {
id variable = nil;
// Check for the variable
if ((variable = [variables objectForKey:output])) {
if ([variable isKindOfClass:[NSString class]]) {
// NSString, append
[result appendString:variable];
} else if ([variable respondsToSelector:@selector(description)]) {
// Not a NSString, but can handle description, append
[result appendString:[variable description]];
}
} else {
// Not found, localize the template key and append
[result appendString:NSLocalizedString(output, nil)];
}
// Skip syntax
[scanner scanString:@"}" intoString:NULL];
}
}
}
[scanner release];
return result;
}
С файлом локализации, который выглядит так:
"born message" = "I was born in ${birthYear} on a ${birthWeekDay}. ${byebye}";
"byebye" = "Cheers!";
Мы можем достичь следующих результатов ...
NSDictionary *variables = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:1986], @"birthYear", @"monday", @"birthWeekDay", nil];
NSString *finalString [self localizedStringFromTemplateString:@"born message" variables:variables];
NSLog(@"%@", finalString); // "I was born in 1986 on a monday. Cheers!"
Как видите, я также добавил некоторые дополнительные функции. Во-первых, любые переменные, которые не найдены ( $ {byebye}
в моем примере), будут локализованы и добавлены к результатам. Я сделал это, потому что загружаю HTML-файлы из пакета приложения и запускаю их с помощью метода локализации (хотя при этом я не локализую строку ввода при создании сканера). Кроме того, для большей гибкости я добавил возможность отправлять другие вещи, кроме объектов NSString
.
Этот код, возможно, не самый эффективный или не самый красивый из написанных, но он выполняет свою работу без какого-либо заметного снижения производительности :)