簡介
國際化(internationalisation芒率,i18n):一個程序或軟件可給特定的人群使用而無須修改或重新編譯源代碼。對于 iOS 來說就是程梦,使App能夠適用于不同的語言鳄厌,地區(qū),文化的過程茫经。
本地化 (localisation,l10n):一個程序或軟件在支持國際化的基礎上萎津,給定程序特定區(qū)域的語言信息使其在信息的輸入輸出等處理上適應特定區(qū)域人群的使用科平。對于 iOS 來說就是,將App的內(nèi)容翻譯為多種語言的過程姜性。
總的來說,國際化是開發(fā)者的任務髓考,是一個一般化的過程部念;而本地化則是翻譯者所做的事情,是一個具體的過程氨菇。國際化的運作為本地化工作提供了可能儡炼。一個軟件的國際化實現(xiàn)需要本地化的支持。
用戶設置對于國際化的影響
在 iOS 設置應用中的通用->語言與地區(qū)
中可以分別設置語言查蓉,地區(qū)和日歷乌询。一個支持國際化的應用會根據(jù)語言的設置選擇相應的本地化包,語言的改變會導致系統(tǒng)重新啟動豌研,以便所有應用重新應用新的語言設置妹田。地區(qū)主要影響日期,時間鹃共,數(shù)字鬼佣,貨幣等數(shù)據(jù)的格式。用戶可以通過日歷選擇不同的歷法霜浴。地區(qū)和日歷的設置都是即時的晶衷,不需要重新啟動系統(tǒng)。另外阴孟,在語言與地區(qū)中還可以設置首選語言順序列表晌纫,應用會以此為依據(jù)選擇本地化語言包(按順序找第一個應用支持的本地化語言包)。
使應用支持國際化
使用Base Internationalization國際化界面文本
從Xcode5之后永丝,工程默認支持Base Internationalization锹漱。
Base Internationalization將界面文本與.storyboard和.xib文件分離,使得項目只需要一套.storyboard和.xib文件类溢。在.storyboard和.xib文件中使用你設置的開發(fā)語言填寫界面文本凌蔬,這套.storyboard和.xib文件就叫做Base Internationalization露懒。之后在本地化時,將以開發(fā)語言為資源翻譯成多種語言砂心,這些語言以.strings格式的文本文件對應相應的.storyboard和.xib文件懈词。
一般情況下,每種語言相對應的文件會放在相應的語言包下辩诞,比如en.lproj坎弯、zh.lproj等。但是所有的.storyboard和.xib文件會放在一個名為Base.lproj的文件夾內(nèi)译暂,這就是為了共用同一套.storyboard和.xib文件抠忘,這樣,在其他語言包內(nèi)就可以只存放相應的.strings格式的文本文件了外永。由于.storyboard和.xib文件中已經(jīng)使用開發(fā)語言填寫了界面文本崎脉,所以在開發(fā)語言的語言包內(nèi)就不需要再有相對應的.strings文件了。
關于開發(fā)語言的設置:
- 在項目的.xcodeproj文件中打開project.pbxproj
- 搜索developmentRegion伯顶,并將該key的值改為所要設置的開發(fā)語言對應的語言ID囚灼,比如en、zh等
-
保存祭衩,效果如下圖所示
使用Auto Layout輔助國際化界面文本
因為所支持的語言所占界面空間不同灶体,Auto Layout可以使一套界面適配布局不同的文字。使用時注意:
- 顯示文字的組件不使用固定寬度的約束掐暮,否則在某些語言下文字可能顯示不完全蝎抽,text fields和labels默認的行為都是自動適配到內(nèi)容的合適的尺寸,完全可以使用這種方式路克。
- 添加水平間距約束時化漆,使用leading和trailing核行,這樣針對左右順序不同的語言可互換左右間距值请琳。
- 因為語言不同視圖組件所占空間不同稠通,所以約束應與相鄰視圖組件建立,這樣當語言改變時殖妇,其他視圖組件也會自動適配刁笙。
國際化代碼中的文本
在項目中,一些在界面上顯示的文本是需要在代碼中提供的(比如錯誤信息提示)谦趣,而對這部分文本國際化的方式是將文本寫入.strings文件中疲吸,之后使用宏NSLocalizedString
去從文件中獲取。在.strings文件中鍵值對的格式為
"key1" = "value1";
"key2" = "value2";
使用NSLocalizedString
去取值的方式為
NSLocalizedString("key1", "comment");
NSLocalizedStringFromTable("key1", "tableName", "comment");
其中標準的NSLocalizedString
函數(shù)會從main bundle中的Localizable.strings文件中找到相應鍵的值前鹅,而comment是對該鍵值對的解釋摘悴。同理NSLocalizedStringFromTable
函數(shù)的第二個參數(shù)可以指定其他.strings文件的文件名。
國際化數(shù)據(jù)格式
不同的國家和地區(qū)有著不同的日期舰绘,時間蹂喻,貨幣葱椭,數(shù)值等的格式,所以要在代碼中根據(jù)用戶設置的地區(qū)來正確的格式化這些數(shù)據(jù)口四。
格式化時用到NSLocale類孵运,NSLocale類封裝了某一個地區(qū)的相應的格式化信息,如果要獲得用戶當前設置地區(qū)的NSLocale實例可以使用[NSLocale currentLocale]
或者[NSLocale autoupdatingCurrentLocale]
蔓彩,兩者的區(qū)別是治笨,后一個類方法返回的值會根據(jù)用戶設置的改變而改變,而前者不會赤嚼】趵担可以通過NSLocal查看很多這一地區(qū)的數(shù)據(jù)格式化信息,例如(其他key值請查閱相關文檔):
NSNumber *metricSystem = [[NSLocale currentLocale] objectForKey:NSLocaleUsesMetricSystem];
NSString *currencySymbol = [[NSLocale currentLocale] objectForKey:NSLocaleCurrencySymbol];
// 用當前地區(qū)的語言顯示語言ID
NSLocale *zhHansLocal = [NSLocale localeWithLocaleIdentifier:@"zh-Hans"];
NSString *currentLocalZH = [zhHansLocal displayNameForKey:NSLocaleIdentifier value:@"zh-Hant-TW"];
NSString *currentLocalEN = [zhHansLocal displayNameForKey:NSLocaleIdentifier value:@"en-US"];
// 獲取該地區(qū)所使用的引號
NSString *bQuote = [locale objectForKey:NSLocaleQuotationBeginDelimiterKey];
NSString *eQuote = [locale objectForKey:NSLocaleQuotationEndDelimiterKey];
// 國際化大小寫轉換
NSString *localizedUppercaseString = [string uppercaseStringWithLocale:[NSLocale currentLocale]];
NSString *localizedlowercaseString = [string lowercaseStringWithLocale:[NSLocale currentLocale]];
NSString *localizedCapitalizedString = [string capitalizedStringWithLocale:[NSLocale currentLocale]];
當使用[NSString stringWithFormat]
去拼裝字符串時更卒,如果傳入的參數(shù)帶有數(shù)值等孵,日期等需要格式化的內(nèi)容,最好使用以下方式(更好的方式是使用formatter進行轉換):
// 使[NSLocale systemLocale]
NSString *localizedString = [NSString localizedStringWithFormat:@"%3.2f", myNumber];
NSString *localizedString = [[NSString alloc] initWithFormat:@"%@" locale:[NSLocale localeWithLocaleIdentifier:@"zh"], [NSDate date]];
使用formatter格式化日期和時間時的國際化
// 使用預設的格式
NSString *localizedDateTime = [NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterShortStyle];
// 使用自定義的格式
NSDateFormatter *dateFormatter = [NSDateFormatter new];
NSString *localeFormatString = [NSDateFormatter dateFormatFromTemplate:@"dMMM" options:0 locale:dateFormatter.locale];
dateFormatter.dateFormat = localeFormatString;
NSString *localizedString = [dateFormatter stringFromDate:[NSDate date]];
對于數(shù)值型數(shù)據(jù)的格式化主要包括小數(shù)蹂空、千位分割流济、貨幣、百分比腌闯。同樣也需要支持國際化。
NSString *localizedString = [NSNumberFormatter localizedStringFromNumber:myNumber numberStyle:NSNumberFormatterDecimalStyle];
同理對于NSCalendar的使用也受NSLocale的影響雕憔。
地區(qū)和時區(qū)的設置發(fā)生變化的通知分別是NSCurrentLocaleDidChangeNotification
和NSSystemTimeZoneDidChangeNotification
國際化支持相反的語言方向
有一些語言姿骏,比如阿拉伯語等,方向是從右向左的斤彼。使用
Base Internationalization和Auto Layout在大部分情況下可以很好的支持這些語言分瘦,一些不支持的情況,可以在代碼中進行如下判斷:
if ([UIView userInterfaceLayoutDirectionForSemanticContentAttribute:view.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft) {
…
}
本地化應用
當我們使應用支持國際化后琉苇,就可以配合翻譯人員完成應用本地化的工作了嘲玫。大致的過程是,通過 Xcode 將開發(fā)語言的文本資源導出為 XLIFF (XML Localisation Interchange File Format) 文件并扇,翻譯人員在完成該文件內(nèi)的相應翻譯內(nèi)容后去团,再通過 Xcode 將文件導入,這時所翻譯的語言資源就會被加入到工程中了穷蛹。
導出 XLIFF
- 在 Xcode 中選中工程或 target土陪。
- 選擇 Editor > Export For Localization。
之后 Xcode 會將 .xliff 文件導出到你指定的目錄中肴熏。如果你在工程的 Localizations 設置項中還沒有添加過其他的語言鬼雀,而只有開發(fā)語言(如 English)一種,那么導出的文件為 en.xliff蛙吏。這時的 en.xliff 文件中并沒有指明要翻譯的目標語言源哩,而這會導致在翻譯完成后文件無法正常導入鞋吉,需要在文件源碼中添加target-language=""
字段。更好的做法是励烦,在創(chuàng)建工程時就把要從開發(fā)語言翻譯的其他語言(如 Chinese)添加到 Localizations 中谓着,這樣導出的文件就為 zh.xliff,且其中已標明目標語言崩侠,可以正常的導入漆魔。另一個要注意的地方是,.strings
文件支持國際化時却音,開始的開發(fā)語言版本不要放到Base.lproj文件夾中改抡,Base.lproj文件夾中存放的全部是界面文件,而是應直接放入對應的開發(fā)語言的.lproj文件中系瓢。
命令行方式:
xcodebuild -exportLocalizations -localizationPath <dirpath> -project <projectname> [[-exportLanguage <targetlanguage>]]
在等待翻譯資源的時候阿纤,你并不希望界面或者僅僅是界面中的文本再發(fā)生變化,這個時候可以使用 Xcode 的一項特性 Locking Views夷陋∏肥埃可以只針對某一 view 修改,在該 view 的 Identity inspector 中修改 Lock 項骗绕。也可設置整個 nib 文件的該屬性藐窄,選中對應 nib 文件后,修改 Editor > Localization Locking 菜單項酬土。
導入 XLIFF
- 在 Xcode 中選中工程或 target荆忍。
- 選擇 Editor > Import Localizations。
Xcode 會從 XLIFF 文件中解析出翻譯內(nèi)容的 .strings 文件撤缴,然后放到對應語言的 .lproj 目錄中刹枉,而在工程中,nib 文件和 .strings 文件都以組的形式管理屈呕。
命令行方式:
xcodebuild -importLocalizations -localizationPath <filepath> -project <projectname>
其他資源
除了文本資源外微宝,其他的資源文件,比如圖片虎眨、音視頻文件等可能也需要針對不同地區(qū)使用不同內(nèi)容蟋软。
在國際化資源文件后,就可以將本地化版本的文件加到對應的 .lproj 目錄中嗽桩。
最佳實踐
對于大部分的國內(nèi)開發(fā)者來說钟鸵,其應用主要針對使用中文的用戶,而鑒于翻譯資源的有限涤躲,可能針對其他地區(qū)用戶僅能支持國際通用的英文棺耍。在這種情況下,最合適的流程是种樱,在開發(fā)過程中蒙袍,開發(fā)者使用中文填寫界面文本俊卤,而之后由翻譯人員翻譯為英文,最后使應用在所有不匹配中文地區(qū)的設備上害幅,都能使用英文資源消恍。
要達到上述效果,首先要設置工程的開發(fā)語言為中文以现,如上文所述狠怨,修改工程文件中的字段 developmentRegion 為 zh,同時確保需要翻譯的英文已添加在列表中邑遏。在完成國際化的工作后佣赖,就可導出 en.xliff 文件交由翻譯人員翻譯,并最終導入记盒。最后一步憎蛤,是要確認 Info.plist 文件中的 CFBundleDevelopmentRegion 字段設置為 en,該字段決定在用戶當前地區(qū)未匹配到翻譯資源時纪吮,使用應用已有的哪一套翻譯資源作為界面文本顯示俩檬。
需要注意的一點是,盡管文檔中提到:
You can choose from more than 100 different languages and dialects designated by regions to localize your app. However, the more general you make your localized resources, the more regions you can support with a single set of resources. This can save a lot of space in your app bundle and help reduce localization costs. For example, if you don’t need to distinguish between different regions that use the English language, you can add English to support users in the United States, United Kingdom, and Australia. Even if you provide region-specific resources always provide a complete set of language-specific resources for all the languages you support.
但當用戶設備的語言設置為繁體中文時碾盟,并不會匹配到中文(zh)的語言資源棚辽,所以在上述配置后,最終在繁體中文的設備上冰肴,應用會使用英文資源屈藐。如果想要所有中文設備都顯示作為開發(fā)語言的簡體中文,最后需要多添加一種語言 zh-Hant嚼沿,但不需要進一步翻譯,直接以開發(fā)語言為模板生成即可瓷患。
測試
在 Xcode 中骡尽,可以使用預覽功能,在不運行應用的情況下擅编,檢測國際化和本地化的結果攀细。選擇一個 .storyboard 或 .xib 文件,打開輔助編輯器爱态,在相關文件中選擇 Preview谭贪,通過右下角語言選項,可以在國際化后選擇 Double-Length Pseudolocalizations 進行檢測锦担,本地化后選擇對應語言進行檢測俭识。
預覽過后,可以通過設置應用啟動時的參數(shù)洞渔,在設備上測試國際化和本地化的結果套媚,而不需要修改設備的設置缚态。編輯 Scheme,選擇 Run -> Options堤瘤,在 Application Language 一項中玫芦,可以選擇對應語言資源,Double-Length Pseudolocalizations 以及 Right to Left Pseudolocalizations本辐。勾選 Show non-localized strings 項桥帆,可以檢測未本地化的文本,其會以大寫形式顯示慎皱。