使用NSLocalizedString的最佳做法
我(像所有其他人)使用NSLocalizedString
本地化我的应用程序。
不幸的是,有几个“缺陷”(不一定是NSLocalizedString本身的错误),包括
- Xcode中的string没有自动完成。 这使得工作不仅容易出错,而且令人厌烦。
- 你可能最终会重新定义一个string,因为你不知道一个等价的string已经存在(即“请input密码”与“先input密码”)
- 与自动完成问题类似,您需要“记住”/ copypaste注释string,否则
genstring
最终会以一个string的多个注释 - 如果您想要在使用
genstring
之后已经对某些string进行了本地化,则必须小心谨慎,以免丢失旧的本地化版本。 - 相同的string分散在整个项目中。 例如,您在任何地方都使用了
NSLocalizedString(@"Abort", @"Cancel action")
,然后Code Review会要求您将该string重命名为NSLocalizedString(@"Cancel", @"Cancel action")
以使代码更一致。
我所做的(在做了一些search之后,我觉得很多人都这样做)是有一个单独的strings.h
文件,我定义了所有的本地化代码。 例如
// In strings.h #define NSLS_COMMON_CANCEL NSLocalizedString(@"Cancel", nil) // Somewhere else NSLog(@"%@", NSLS_COMMON_CANCEL);
这基本上提供了代码完成,一个地方改变variables名称(所以不再需要的genstring),和一个唯一的关键字自动重构。 然而,这是以一大堆没有内在结构的(即像LocString.Common.Cancel或类似的东西)结束的代价为代价的。
所以,虽然这工作得很好,但我想知道你们是如何在你的项目中做到的。 有没有其他的方法来简化使用NSLocalizedString? 有没有可能封装它的框架?
NSLocalizedString
有一些限制,但是对于Cocoa来说,这是非常重要的,编写自定义代码来处理本地化是不合理的,这意味着你将不得不使用它。 这就是说,一个小工具可以帮助,这里是我如何进行:
更新string文件
genstrings
覆盖您的string文件,丢弃您之前的所有翻译。 我写了update_strings.py来parsing旧的string文件,运行genstrings
并填写空白,以便您不必手动还原现有的翻译。 该脚本尽可能匹配现有的string文件,以避免更新时有太大差异。
命名你的string
如果您使用广告的NSLocalizedString
:
NSLocalizedString(@"Cancel or continue?", @"Cancel notice message when a download takes too long to proceed");
您可能会在代码的另一部分中定义相同的string,这可能会因相同的英语术语在不同的上下文中具有不同的含义而出现冲突( OK
和Cancel
会出现)。 这就是为什么我总是使用一个无意义的全部大写的string和一个特定于模块的前缀,以及一个非常精确的描述:
NSLocalizedString(@"DOWNLOAD_CANCEL_OR_CONTINUE", @"Cancel notice window title when a download takes too long to proceed");
在不同的地方使用相同的string
如果多次使用相同的string,则可以像使用一样使用macros,或者将其作为实例variablescaching在视图控制器或数据源中。 这样你就不必重复描述,在同一个本地化的实例中,这个描述可能会变得陈旧和不一致,这总是令人困惑。 由于实例variables是符号,因此您可以对这些最常见的翻译使用自动完成function,对特定的翻译使用“手动”string,而这些string只能出现一次。
我希望你能用Cocoa本地化这些提示更有效率!
至于Xcode中的string自动完成,你可以尝试http://questbe.at/lin/ 。
同意ndfred,但我想补充一点:
第二个参数可以用作…默认值!
(NSLocalizedStringWithDefaultValue无法与genstring正常工作,这就是为什么我提出这个解决scheme)
这里是我的自定义实现使用NSLocalizedString使用注释作为默认值:
1。 在预先编译的头文件(.pch文件)中,重新定义“NSLocalizedString”macros:
// 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.创build一个类来实现本地化处理程序
#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.使用它!
确保你在你的应用程序构build阶段添加一个运行脚本,这样你Localizable.strings文件将在每个版本更新,即新的本地化string将被添加到Localized.strings文件中:
我的构build阶段脚本是一个shell脚本:
Shell: /bin/sh Shell script content: find . -name \*.m | xargs genstrings -o MyClassesFolder
所以当你在你的代码中添加这个新行时:
self.title = NSLocalizedString(@"view_settings_title", @"Settings");
然后执行构build,你的./Localizable.scripts文件将包含这个新行:
/* Settings */ "view_settings_title" = "view_settings_title";
而且由于'view_settings_title'的key ==值,自定义LocalizedStringHandler将返回注释,即'设置'
Voilà:-)
我写了一个脚本来帮助维护多种语言的Localizable.strings。 虽然它不能帮助自动完成它有助于使用命令合并.strings文件:
merge_strings.rb ja.lproj/Localizable.strings en.lproj/Localizable.strings
欲了解更多信息,请参阅: https : //github.com/hiroshi/merge_strings
你们中有些人觉得我希望有用。
在Swift中,我使用下面的例子,例如在这种情况下,button“是”
NSLocalizedString("btn_yes", value: "Yes", comment: "Yes button")
注意使用该value:
用于默认文本值。 第一个参数作为翻译ID。 使用value:
参数的优点是可以稍后更改默认文本,但翻译ID保持不变。 Localizable.strings文件将包含"btn_yes" = "Yes";
如果未使用value:
参数,则第一个参数将用于:翻译ID和默认文本值。 Localizable.strings文件将包含"Yes" = "Yes";
。 这种pipe理本地化文件似乎很奇怪。 特别是如果翻译的文本很长,那么ID也很长。 每当缺省文本值的任何字符发生更改时,翻译ID也会发生变化。 当使用外部翻译系统时,这会导致问题。 翻译ID的改变被理解为添加新的翻译文本,这可能并不总是期望的。
#define PBLocalizedString(key, val) \ [[NSBundle mainBundle] localizedStringForKey:(key) value:(val) table:nil]
使用iOS 7&Xcode 5,您应该避免使用“Localization.strings”方法,并使用新的“基本本地化”方法。 有一些教程,如果你谷歌'基地本地化'
苹果文件: 基地本地化
我自己,我经常忘记编码,忘记把条目放到.strings文件中。 因此,我有帮助脚本来find我要把什么东西放回到.strings文件和翻译。
由于我使用我自己的macrosNSLocalizedString, 请检查和更新前使用脚本,因为我为简单假设nil用作NSLocalizedString的第二个参数。 你想改变的部分是
NSLocalizedString\(@(".*?")\s*,\s*nil\)
只要将它replace为符合你的macros和NSLocalizedString用法的东西。
这里是脚本,你只需要第3部分。 剩下的就是看哪里更容易一些:
// Part 1. Get keys from one of the Localizable.strings perl -ne 'print "$1\n" if /^\s*(".+")\s*=/' myapp/fr.lproj/Localizable.strings // Part 2. Get keys from the source code grep -n -h -Eo -r 'NSLocalizedString\(@(".*?")\s*,\s*nil\)' ./ | perl -ne 'print "$1\n" if /NSLocalizedString\(@(".+")\s*,\s*nil\)/' // Part 3. Get Part 1 and 2 together. comm -2 -3 <(grep -n -h -Eo -r 'NSLocalizedString\(@(".*?")\s*,\s*nil\)' ./ | perl -ne 'print "$1\n" if /NSLocalizedString\(@(".+")\s*,\s*nil\)/' | sort | uniq) <(perl -ne 'print "$1\n" if /^\s*(".+")\s*=/' myapp/fr.lproj/Localizable.strings | sort) | uniq >> fr-localization-delta.txt
输出文件包含在代码中find的键,但不在Localizable.strings文件中。 这是一个示例:
"MPH" "Map Direction" "Max duration of a detailed recording, hours" "Moving ..." "My Track" "New Trip"
当然可以磨光更多,但是我以为我会分享。
如果有人正在寻找一个Swift解决scheme。 你可能想看看我的解决scheme,我放在一起:SwiftyLocalization
只需几个步骤即可完成设置,您可以在Google Spreadsheet(评论,自定义颜色,突出显示,字体,多个工作表等)中进行非常灵活的本地化。
简而言之,步骤是:Google Spreadsheet – > CSV文件 – > Localizable.strings
此外,它还会生成Localizables.swift,这个结构的作用类似于为您提供密钥检索和解码的接口(您必须手动指定一种从关键字解码String的方法)。
为什么这很棒?
- 你不再需要在整个地方都有一个关键字。
- 在编译时检测到错误的键。
- Xcode可以做自动完成。
虽然有自动完成可本地化密钥的工具。 引用一个真正的variables将确保它总是一个有效的键,否则将不会编译。
// It's defined as computed static var, so it's up-to-date every time you call. // You can also have your custom retrieval method there. button.setTitle(Localizables.login.button_title_login, forState: .Normal)
该项目使用Google App Script将表格 – > CSV和Python脚本转换为CSV文件 – > Localizable.strings您可以快速浏览此示例表以了解可能的情况。