使用NSLocalizedString的最佳实践

Jia*_*Yow 134 localization objective-c nslocalizedstring ios

我(和所有其他人一样)使用NSLocalizedString本地化我的应用程序.

不幸的是,有几个"缺点"(不一定是NSLocalizedString本身的错误),包括

  • Xcode中的字符串没有自动完成功能.这使得工作不仅容易出错而且令人厌烦.
  • 您可能最终只是因为您不知道已经存在的等效字符串而重新定义字符串(即"请输入密码"与"先输入密码")
  • 类似于自动完成问题,你需要"记住"/ copypaste注释字符串,否则genstring最终会有一个字符串的多个注释
  • 如果要genstring在已经对某些字符串进行本地化后使用,则必须小心不要丢失旧的本地化.
  • 在整个项目中,相同的字符串分散.例如,您NSLocalizedString(@"Abort", @"Cancel action")在任何地方都使用过,然后Code Review要求您重命名字符串NSLocalizedString(@"Cancel", @"Cancel action")以使代码更加一致.

我所做的(以及经过一些搜索后,我认为很多人这样做)是有一个单独的strings.h文件,我#define所有的本地化代码.例如

// In strings.h
#define NSLS_COMMON_CANCEL NSLocalizedString(@"Cancel", nil)
// Somewhere else
NSLog(@"%@", NSLS_COMMON_CANCEL);
Run Code Online (Sandbox Code Playgroud)

这基本上提供了代码完成,一个更改变量名称的位置(因此不再需要genstring),以及一个自动重构的唯一关键字.但是,这需要花费大量结果来解决一系列#define非固有结构的语句(例如LocString.Common.Cancel或类似的东西).

所以,虽然这有点好,但我想知道你们是如何在你的项目中做到的.是否有其他方法可以简化NSLocalizedString的使用?甚至可能有一个封装它的框架?

ndf*_*red 95

NSLocalizedString有一些限制,但它对Cocoa来说是如此重要,编写自定义代码来处理本地化是不合理的,这意味着你将不得不使用它.也就是说,一个小工具可以帮助,这是我如何进行:

更新字符串文件

genstrings覆盖您的字符串文件,丢弃所有以前的翻译.我编写了update_strings.py来解析旧的字符串文件,运行genstrings并填写空白,这样您就不必手动恢复现有的翻译.脚本尝试尽可能地匹配现有的字符串文件,以避免在更新它们时产生太大的差异.

命名你的字符串

如果您使用NSLocalizedString广告:

NSLocalizedString(@"Cancel or continue?", @"Cancel notice message when a download takes too long to proceed");
Run Code Online (Sandbox Code Playgroud)

您最终可能会在代码的另一部分中定义相同的字符串,这可能会发生冲突,因为相同的英语术语在不同的上下文中可能具有不同的含义(OK并且Cancel会浮现在脑海中).这就是为什么我总是使用带有模块特定前缀的无意义的全大写字符串,以及非常精确的描述:

NSLocalizedString(@"DOWNLOAD_CANCEL_OR_CONTINUE", @"Cancel notice window title when a download takes too long to proceed");
Run Code Online (Sandbox Code Playgroud)

在不同的地方使用相同的字符串

如果多次使用相同的字符串,则可以像使用宏一样使用宏,也可以将其作为实例变量缓存在视图控制器或数据源中.这样,您就不必重复可能变得陈旧的描述,并且在同一本地化的实例之间变得不一致,这总是令人困惑.由于实例变量是符号,因此您可以对这些最常见的翻译使用自动完成,并对特定的翻译使用"手动"字符串,这只会发生一次.

我希望通过这些提示,您可以更高效地使用Cocoa本地化!

  • 我永远不明白为什么gettext风格的本地化功能使用其中一个翻译作为关键.如果原始文本发生变化会怎样?您的密钥更改和所有本地化文件都使用旧文本作为密钥.它从来没有对我有意义.我总是使用像"home_button_text"这样的键,所以它们是独一无二的,永远不会改变.我还编写了一个bash脚本来解析我的所有Localizable.strings文件,并使用静态方法生成一个类文件,该文件将加载相应的字符串.这给了我代码完成.有一天,我可能会开源. (14认同)
  • 我认为你的意思是`genstrings`而不是`gestring`. (2认同)

hir*_*shi 30

至于Xcode中字符串的自动复制,你可以尝试http://questbe.at/lin/.

  • 这实际上是相当惊人的.无需创建宏. (3认同)

Pas*_*cal 24

同意ndfred,但我想补充一下:

第二个参数可以用作...默认值!!

(NSLocalizedStringWithDefaultValue与genstring无法正常工作,这就是我提出此解决方案的原因)

这是我的Custom实现,它使用NSLocalizedString,它使用comment作为默认值:

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]
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

3.使用它!

确保在App Build Phases中添加Run脚本,以便在每次构建时更新Localizable.strings文件,即在Localized.strings文件中添加新的本地化字符串:

我的构建阶段脚本是一个shell脚本:

Shell: /bin/sh
Shell script content: find . -name \*.m | xargs genstrings -o MyClassesFolder
Run Code Online (Sandbox Code Playgroud)

因此,当您在代码中添加此新行时:

self.title = NSLocalizedString(@"view_settings_title", @"Settings");
Run Code Online (Sandbox Code Playgroud)

然后执行构建,您的./Localizable.scripts文件将包含以下新行:

/* Settings */
"view_settings_title" = "view_settings_title";
Run Code Online (Sandbox Code Playgroud)

由于'view_settings_title'的key ==值,自定义LocalizedStringHandler将返回注释,即'Settings'

Voilà:-)