IOS本地化应用
BK項目已完成7788,在項目的后期需要被翻譯成多國語言版。為了適應全球多個國家使用多個存儲。
應用本地化是分別對字符串、圖片和 xib 或 storyboard 文件本地化,而傳統的做法是對 xib 上的字符串(包含UILabel和UIButton、UITextField等)關聯一個變量,通過NSLocalizedString這個函數去查找 Localizeable?.strings 文件里的key值進行本地化操作,或者是生成同一個xib文件的不同語言版本號。如 MainVC.xib(German) 和 MainVC.xib(English)。但這樣做未免過于繁雜,像人們常說的 tedious and useless.
還是先介紹一下本地化的一般流程:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
(1)偽本地化偽本地化是將字符串本地化為無意義語言的過程。
即將須要翻譯的字符串替換成其它如果已經是翻譯過的“譯文”,能夠用谷歌翻譯替換一下或者是將全部元音字母替換成x。比如:“Press here to continue” 會變成 “Prxss hxrx tx cxntxnxx”。這樣做的目的是為了盡早發現問題。
(2)凍結UI? 在應用開發的周期中必需要有一個明白的時間點來凍結UI。在此之后要堅決杜絕會影響本地化的資源變更。nib 文件能夠在XCode中鎖定。以防止改動可本地化的屬性、不可本地化的屬性或者是全部屬性,如圖所看到的。然后將需要翻譯的文本發給翻譯人員或者是本地化服務提供商去翻譯即可了。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
(3)本地化將資源發給本地化服務提供商之后,他們會發回翻譯完畢的文件。依據翻譯的文本進行本地化工作。
(4)版本號控制用版本號控制系統記錄下你的每一次變更。
(5)測試不用怎么說,必需要的步驟。
(6a)合并邏輯變更邏輯變更一般不會影響到nib文件和本地化的工作。多人協作的項目還是須要合并一些變更的邏輯的。
(6b)本地化變更假設你做了一些本地化變更,比方改變了已本地化的文本,那么就須要從頭開始這個過程。并將這些變更發給本地化人員。能夠重用之前的字符串翻譯,這么做會大大提高效率,但仍然非常麻煩。所以,應盡量避免在開發后期引入這類變更。
應用本地化的文章之前已經就有非常多大牛寫過了。這里就不在贅述了,直接貼出本人讀過的認為還不錯的文章:
1、MJ 的應用程序本地化,2013年寫的,對于XCode5,有些操作界面已經不一樣了,但思想是不變的。
2、IOS應用國際化教程(2014版),這個比較新,并且是使用 storyboard 的。
3、RAYWENDERLICH 上的 Internationalization Tutorial for iOS [2014 Edition]?這上面的文章都非常不錯,非常值得一讀,強烈推薦。
另外。重點是要講我在 github 上找到的一個類,很棒,優雅的代碼一直感動到我眼淚嘩嘩直流~~
這是github上的項目地址:HERE?,假設有找到很多其它更好的優秀代碼,請知會一聲。
就像作者所說的那樣:
? ? ? ?
? ? ? ?
下面是OHAutoNIBi18n.m類。做了一下小改動,在不改變 frame 的情況下。對 UILabel、UIButton、UITextField 的字體大小做了一下自適應。
// // OHAutoNIBi18n.m // // Created by Olivier on 03/11/10. // Copyright 2010 FoodReporter. All rights reserved. //#import <objc/runtime.h> #import <UIKit/UIKit.h>static inline NSString* localizedString(NSString* aString);static inline void localizeUIBarButtonItem(UIBarButtonItem* bbi); static inline void localizeUIBarItem(UIBarItem* bi); static inline void localizeUIButton(UIButton* btn); static inline void localizeUILabel(UILabel* lbl); static inline void localizeUINavigationItem(UINavigationItem* ni); static inline void localizeUISearchBar(UISearchBar* sb); static inline void localizeUISegmentedControl(UISegmentedControl* sc); static inline void localizeUITextField(UITextField* tf); static inline void localizeUITextView(UITextView* tv); static inline void localizeUIViewController(UIViewController* vc);// ------------------------------------------------------------------------------------------------@interface NSObject(OHAutoNIBi18n) -(void)localizeNibObject; @end@implementation NSObject(OHAutoNIBi18n)#define LocalizeIfClass(Cls) if ([self isKindOfClass:[Cls class]]) localize##Cls((Cls*)self) -(void)localizeNibObject {LocalizeIfClass(UIBarButtonItem);else LocalizeIfClass(UIBarItem);else LocalizeIfClass(UIButton);else LocalizeIfClass(UILabel);else LocalizeIfClass(UINavigationItem);else LocalizeIfClass(UISearchBar);else LocalizeIfClass(UISegmentedControl);else LocalizeIfClass(UITextField);else LocalizeIfClass(UITextView);else LocalizeIfClass(UIViewController);if (self.isAccessibilityElement == YES){self.accessibilityLabel = localizedString(self.accessibilityLabel);self.accessibilityHint = localizedString(self.accessibilityHint);}// Call the original awakeFromNib method[self localizeNibObject]; // this actually calls the original awakeFromNib (and not localizeNibObject) because we did some method swizzling }+(void)load {// Autoload : swizzle -awakeFromNib with -localizeNibObject as soon as the app (and thus this class) is loadedMethod localizeNibObject = class_getInstanceMethod([NSObject class], @selector(localizeNibObject));Method awakeFromNib = class_getInstanceMethod([NSObject class], @selector(awakeFromNib));method_exchangeImplementations(awakeFromNib, localizeNibObject); }@end/static inline NSString* localizedString(NSString* aString) {if (aString == nil || [aString length] == 0)return aString;// Don't translate strings starting with a digitif ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:[aString characterAtIndex:0]])return aString;#if OHAutoNIBi18n_DEBUG #warning Debug mode for i18n is activestatic NSString* const kNoTranslation = @"$!";NSString* tr = [[NSBundle mainBundle] localizedStringForKey:aString value:kNoTranslation table:nil];if ([tr isEqualToString:kNoTranslation]){if ([aString hasPrefix:@"."]){// strings in XIB starting with '.' are typically used as temporary placeholder for design// and will be replaced by code later, so don't warn about themreturn aString;}NSLog(@"No translation for string '%@'",aString);tr = [NSString stringWithFormat:@"$%@$",aString];}return tr; #elsereturn [[NSBundle mainBundle] localizedStringForKey:aString value:nil table:nil]; #endif }// ------------------------------------------------------------------------------------------------static inline void localizeUIBarButtonItem(UIBarButtonItem* bbi) {localizeUIBarItem(bbi); /* inheritence */NSMutableSet* locTitles = [[NSMutableSet alloc] initWithCapacity:[bbi.possibleTitles count]];for(NSString* str in bbi.possibleTitles) {[locTitles addObject:localizedString(str)];}bbi.possibleTitles = [NSSet setWithSet:locTitles]; #if ! __has_feature(objc_arc)[locTitles release]; #endif }static inline void localizeUIBarItem(UIBarItem* bi) {bi.title = localizedString(bi.title); }static inline void localizeUIButton(UIButton* btn) {NSString* title[4] = {[btn titleForState:UIControlStateNormal],[btn titleForState:UIControlStateHighlighted],[btn titleForState:UIControlStateDisabled],[btn titleForState:UIControlStateSelected]};[btn.titleLabel setAdjustsFontSizeToFitWidth:YES];[btn setTitle:localizedString(title[0]) forState:UIControlStateNormal];if (title[1] == [btn titleForState:UIControlStateHighlighted])[btn setTitle:localizedString(title[1]) forState:UIControlStateHighlighted];if (title[2] == [btn titleForState:UIControlStateDisabled])[btn setTitle:localizedString(title[2]) forState:UIControlStateDisabled];if (title[3] == [btn titleForState:UIControlStateSelected])[btn setTitle:localizedString(title[3]) forState:UIControlStateSelected]; }static inline void localizeUILabel(UILabel* lbl) {lbl.adjustsFontSizeToFitWidth = YES; // lbl.minimumScaleFactor = 6.0f;lbl.text = localizedString(lbl.text); }static inline void localizeUINavigationItem(UINavigationItem* ni) {ni.title = localizedString(ni.title);ni.prompt = localizedString(ni.prompt); }static inline void localizeUISearchBar(UISearchBar* sb) {sb.placeholder = localizedString(sb.placeholder);sb.prompt = localizedString(sb.prompt);sb.text = localizedString(sb.text);NSMutableArray* locScopesTitles = [[NSMutableArray alloc] initWithCapacity:[sb.scopeButtonTitles count]];for(NSString* str in sb.scopeButtonTitles) {[locScopesTitles addObject:localizedString(str)];}sb.scopeButtonTitles = [NSArray arrayWithArray:locScopesTitles]; #if ! __has_feature(objc_arc)[locScopesTitles release]; #endif }static inline void localizeUISegmentedControl(UISegmentedControl* sc) {NSUInteger n = sc.numberOfSegments;for(NSUInteger idx = 0; idx<n; ++idx) {[sc setTitle:localizedString([sc titleForSegmentAtIndex:idx]) forSegmentAtIndex:idx];} }static inline void localizeUITextField(UITextField* tf) {tf.adjustsFontSizeToFitWidth = YES;tf.text = localizedString(tf.text);tf.placeholder = localizedString(tf.placeholder); }static inline void localizeUITextView(UITextView* tv) {tv.text = localizedString(tv.text); }static inline void localizeUIViewController(UIViewController* vc) {vc.title = localizedString(vc.title); }tips:本地化的時候還須要注意:
1、別忘了從右向左讀的語言。
2、不要隨便如果逗號就是千位分隔符以及句點就是小數點。在不同的語言中可能會有不同。
3、注意數字和日期的格式化(輸入和輸出都須要進行格式化)。
至此,,應用本地化的事兒就簡單多了,剩下的事情就交給翻譯人員去吧~
參考文章:
Apple官方文檔:Localizing your APP
Apple官方文檔:Internationalize Your App
Apple官方文檔:?Data Formatting Guide
Apple官方文檔:?Internationalization Programming Topics
Apple官方文檔:?Internationalization and Localization
本地化協作工具:https://www.transifex.com/product/
? ? ? ? ? ? ? ? ? ? ? ? ? ??https://crowdin.com/
版權聲明:本文博客原創文章,博客,未經同意,不得轉載。
轉載于:https://www.cnblogs.com/yxwkf/p/4615096.html
總結
- 上一篇: 第4章 分治策略 monge阵列
- 下一篇: cut命令详解(转)