是否可以将 NSLocalizedString 基础结构(基于 localizable.strings)与自定义的“本地化”一起使用?
问题是,有些语言对男性和女性有不同的措辞。我想在首次启动时询问用户的性别,然后使用适当的短语。当然,两者都基于相同的语言。我可以用我自己的代码来做,但如果可能的话,我宁愿用简单的方法来做。
是否可以将 NSLocalizedString 基础结构(基于 localizable.strings)与自定义的“本地化”一起使用?
问题是,有些语言对男性和女性有不同的措辞。我想在首次启动时询问用户的性别,然后使用适当的短语。当然,两者都基于相同的语言。我可以用我自己的代码来做,但如果可能的话,我宁愿用简单的方法来做。
这是我使用 NSLocalizedString 的自定义实现,它使用注释作为默认值:
(NSLocalizedStringWithDefaultValue 不能与 genstring 一起正常工作,这就是我提出这个解决方案的原因)
1. 在您的预编译头文件(.pch 文件)中,重新定义“NSLocalizedString”宏:
// cutom NSLocalizedString that use macro comment as default value
#import "LocalizationHandlerUtil.h"
#undef NSLocalizedString
#define NSLocalizedString(key,_comment) [[LocalizationHandlerUtil singleton] localizedString:key comment:_comment]
2.创建一个类来实现本地化处理程序
#import "LocalizationHandlerUtil.h"
@implementation LocalizationHandlerUtil
static LocalizationHandlerUtil * singleton = nil;
+ (LocalizationHandlerUtil *)singleton
{
return singleton;
}
__attribute__((constructor))
static void staticInit_singleton()
{
singleton = [[LocalizationHandlerUtil alloc] init];
}
- (NSString *)localizedString:(NSString *)key comment:(NSString *)comment
{
// default localized string loading
NSString * localizedString = [[NSBundle mainBundle] localizedStringForKey:key value:key table:nil];
// if (value == key) and comment is not nil -> returns comment
if([localizedString isEqualToString:key] && comment !=nil)
return comment;
return localizedString;
}
@end
3.使用它!
确保在您的 App Build Phases 添加一个 Run 脚本,这样您的 Localizable.strings 文件将在每次构建时更新,即,新的本地化字符串将添加到您的 Localized.strings 文件中:
我的构建阶段脚本是一个 shell 脚本:
Shell: /bin/sh
Shell script content: find . -name \*.m | xargs genstrings -o MyProjectFolder
因此,当您在代码中添加此新行时:
self.title = NSLocalizedString(@"view_settings_title", @"Settings");
然后执行构建,您的 ./Localizable.scripts 文件将包含以下新行:
/* Settings */
"view_settings_title" = "view_settings_title";
并且由于'view_settings_title'的key == value,自定义LocalizedStringHandler将返回注释,即'Settings'
瞧 :-)
NSLocalizedString 只是在 NSBundle.h 中定义的一个宏
重新定义它或创建一个新的,例如 NSGenderAwareLocalizedString 以满足您的需求。
使用新的宏,您可以随意做任何事情:每种语言有两个字符串文件,一个用于男性,一个用于女性。或者,您可以定义一个约定,从男性本地化字符串的键中派生女性本地化字符串的键。
为此有一个特殊的机制。来自 Apple 参考:使用 genstrings 搜索自定义函数
该
genstrings
工具默认搜索 Core Foundation 和 Foundation 字符串宏。它使用这些宏中的信息在项目的字符串文件中创建字符串条目。除了标准宏之外,您还可以指示 genstrings 在代码中查找自定义字符串加载函数并使用这些函数。您可以使用自定义函数来包装内置的字符串加载例程并执行一些额外的处理,或者您可以用您自己的自定义模型替换默认的字符串处理行为。如果您想将 genstrings 与您自己的自定义函数一起使用,您的函数必须使用 Foundation 宏使用的命名和格式约定。您的函数的参数必须与相应宏的参数完全匹配。当您调用 时
genstrings
,您指定-s
选项后跟对应于 NSLocalizedString 宏的函数的名称。然后,您的其他函数名称应从此基本名称构建。例如,如果您指定了函数名MyStringFunction
,那么您的其他函数名应该是MyStringFunctionFromTable
、MyStringFunctionFromTableInBundle
和MyStringFunctionWithDefaultValue
。该genstrings
工具会查找这些函数并使用它们来构建相应的字符串文件。
实现自己的行为使用NSBundle
方法localizedStringForKey:value:table:
这是我使用 NSLocalizedString 的自定义实现,它使用注释作为默认值:
--> 在这里我转换成 2 种语言(英语和意大利语)
--> 将此方法放在 appdelegate 类中
- (NSString*)languageSelectedStringForKey:(NSString*) key {
NSString *path = nil;
NSString *language = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppLanguage"];
if ([language isEqualToString:@"English"])
path = [[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"];
else if ([language isEqualToString:@"Italian"])
path = [[NSBundle mainBundle] pathForResource:@"it" ofType:@"lproj"];
NSBundle* languageBundle = [NSBundle bundleWithPath:path];
NSString* str=[languageBundle localizedStringForKey:key value:@"" table:nil];
return str;
}
--> 调用这个方法
self.title = [appDelgate languageSelectedStringForKey:@"Back"];
以所选语言转换回。
@Guillaume 提供了最好的解决方案,但没有实际展示实现。由于问题的作者无法弄清楚,我决定将其包含在未来的人中。我发现该线程很有帮助,现在它不仅有用。:)
正如@Guillaume 所提到的,最好的解决方案是创建一个自定义宏,并在 table 上进行查找。“表”只是包含变体的另一个文件的名称。在这种情况下,我假设您将文件命名为“Female.strings”
这确保了最大的灵活性,并为您提供了一个不需要您为两种情况定义条目的解决方案。这实际上对您的情况非常有用,因为并非所有短语都可能具有女性形式。
因此,以下解决方案不需要重复条目,这非常酷!
首先定义你的宏:
#define SXLocalizedString(key, comment) [Utility SXLocalizedString:key with:comment]
然后像这样定义扩展函数:
+ (NSString*)SXLocalizedString:(NSString*)str with:(NSString*)comment {
NSString* feminine = NSLocalizedStringFromTable(str, @"Female", comment);
NSString* value = NSLocalizedString(str, comment);
if ([self userIsFemale] &&
feminine) {
// choose the feminine version of the string
value = feminine;
}
return value;
}
几年来 Xcode 有LOCALIZED_STRING_MACRO_NAMES
,所以如果它们遵循相同的参数结构,您可以放置自定义的NSLocalizedString
替代宏名称,并且 Xcode 将正确导出/导入它们,类似于genstrings 答案