久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

objc系列譯文(9.3):字符串本地化

 UchihaItachiF 2015-12-25
原文出處: Florian Kugler   譯文出處:楊超   歡迎分享原創(chuàng)到伯樂頭條

一個應(yīng)用在進行多語言本地化的時候涉及到大量的工作。因為這一期的主題是字符串,,所以本文主要探討字符串的本地化,。字符串本地化有兩種方法:修改代碼或修改 nib 文件和 storyboard。本文將專注于通過代碼實現(xiàn)字符串的本地化,。

NSLocalizedString

NSLocalizedString 這個宏是字符串本地化的核心工具,。它還有三個鮮為人知的變體:NSLocalizedStringFromTableNSLocalizedStringFromTableInBundle 和 NSLocalizedStringWithDefaultValue,。這些宏最終都調(diào)用 NSBundle 的 localizedStringForKey:value:table: 方法來完成任務(wù),。

使用這些宏有兩個好處:一方面相比直接調(diào)用 localizedStringForKey:value:table: 方法,使用宏讓代碼簡單易懂,;另一方面,,類似 genstrings 這樣的工具能夠監(jiān)測到這些宏,從而生成供你翻譯使用的字符串文件,。這些工具會解析 .c 和 .m 后綴的文件,,然后為其中每一個需要進行本地化的字符串都生成對應(yīng)條目,并寫入到生成的 .strings 文件中,。

如果想讓 genstrings 檢測自己項目中所有的 .m 后綴文件,,可以執(zhí)行如下命令:

1
find . -name *.m | xargs genstrings -o en.lproj

-o 選項指定了生成字符串文件的存放目錄,默認(rèn)情況下文件名是 Localizable.strings,。需要注意的是,,genstrings 默認(rèn)會覆蓋已存在的同名字符串文件。-a 選項可以讓 genstrings 將生成的條目追加到已存在同名文件的末尾,,而不會覆蓋原文件,。

不過一般情況下你也許想將生成文件放到另一個目錄中,然后使用你喜歡的合并工具將它們與已有文件合并以保留已翻譯好的條目,。

字符串文件的格式非常簡單,,都是鍵值對的形式:

1
2
3
4
/* Insert new contact button */
"contact-editor.insert-new-contact-button" = "Insert contact";
/* Delete contact button */
"contact-editor.delete-contact-button" = "Delete contact";

更復(fù)雜的操作比如在需要本地化的字符串中插入格式化占位符等,我們將在稍后談到,。

另外,,字符串文件現(xiàn)在可以保存成 UTF-8 格式了,,因為 Xcode 在構(gòu)建過程中能夠?qū)⑺鼈冝D(zhuǎn)換成所需的 UTF-16 格式。

應(yīng)用中哪些字符串需要本地化,?

一般而言,,所有你想以某種形式展現(xiàn)在用戶眼前的字符串都需要本地化,包括標(biāo)簽和按鈕上的文本,,或者在運行時通過格式化字符串和數(shù)據(jù)動態(tài)生成的字符串,。

在本地化字符串時,根據(jù)語法規(guī)則為每一種類型的語句定義一個可本地化的字符串是非常重要的,。假設(shè)你在應(yīng)用中需要顯示「Paul invited you」和「You invited Paul」,,那么只本地化格式化字符串「%@ invited %@」看起來是個不錯的選擇,這樣在合適的時候把「you」本地化之后插入進去就可以完成任務(wù),。

在英語中這種做法沒什么問題,,但是請謹(jǐn)記,當(dāng)把這種小伎倆應(yīng)用到其他語言中時基本都會以失敗而告終,。以德語為例,,「Paul invited you」譯為「Paul hat dich eingeladen」,而「You invited Paul」則譯為「Du hast Paul eingeladen」,。

正確的做法是定義兩個可本地化字符串「%@ invited you」和「You invited %@」,,只有這樣翻譯器才能正確處理其他語言的特殊語法規(guī)則。

永遠(yuǎn)不要將句子分解為幾個部分,,而要將它們作為一個完整的可本地化字符串,。如果一個句子與另一個句子的語法規(guī)則并不完全一致,那么即使它們在你的母語中看起來極為相像,,也要創(chuàng)建兩個可本地化字符串,。

字符串鍵值最佳實踐

使用 NSLocalizedString 宏的時候,第一個參數(shù)就是為每個特殊字符串指定的鍵值(key),。程序員經(jīng)常使用母語中的單詞作為鍵值,,這樣乍一看是個便利的方案,但是實際上相當(dāng)糟糕,,會引發(fā)非常嚴(yán)重的錯誤,。

在一個字符串文件中,鍵值需要具有唯一性,,因此任何母語中字面上具有唯一性的單詞在翻譯為其他語言的時候也必須具有唯一性。這一點是無法滿足的,,因為一個單詞翻譯為其他語言時經(jīng)常會有多種意思,,需要對應(yīng)到多種文字表示。

以英文單詞「run」為例,,作為名詞表示「跑步」,,作為動詞表示「奔跑」,,在翻譯的時候要加以區(qū)別。而且根據(jù)上下文的不同,,每種具體的譯法在文字上可能還會有細(xì)微變化,。

一個健身應(yīng)用在不同的地方用到這個單詞的不同意思是很正常的,但是如果你使用下面的方法來進行本地化:

1
NSLocalizedString(@"Run", nil)

無論第二個參數(shù)指定了注釋內(nèi)容還是留空,,你在字符串文件中都只有一個「run」的條目,。而在德語中,「run」作名詞時應(yīng)該譯為「Lauf」,,作動詞時則應(yīng)該譯為「laufen」,,或者在特定情況下譯為完全不同的形式比如「loslaufen」和「Los geht’s」。

好的鍵值應(yīng)該滿足兩個條件:首先鍵值必須在每個具體的上下文中保持唯一性,,其次如果我們沒有翻譯特定的那個上下文,,那么它們不會被其他情況覆蓋到而被翻譯。

本文推薦使用如下的命名空間方法:

1
2
NSLocalizedString(@"activity-profile.title.the-run", nil)
NSLocalizedString(@"home.button.start-run", nil)

這樣的鍵值可以區(qū)分應(yīng)用中不同地方出現(xiàn)的單詞,,同時提供具體的上下文,,比如是標(biāo)題中的或者按鈕中的。上面的例子里我們?yōu)榱撕啽愫雎粤说诙€參數(shù),,實際使用中如果鍵值本身沒有提供清晰的上下文說明,,你可以將進一步的說明作為第二個參數(shù)傳入。同時請確保鍵值中只含有 ASCII 字符,。

分割字符串文件

正如我們一開始提到的,,NSLocalizedString 有一些變體能夠提供更多字符串本地化的操作方式。NSLocalizedStringFromTable接收 key,、table 和 comment 這三個參數(shù),,其中 table 參數(shù)表示該字符串對應(yīng)的一個表格,genstrings 會為表中的每一個條目生成一個以條目名稱(假設(shè)為 table-item)命名的獨立字符串文件 table-item.strings,。

這樣你就可以把字符串文件分割成幾個小一些的文件,。在一個龐大的項目或者團隊中工作時,這一點顯得尤為重要,。同時這也讓合并原有的和重新生成的字符串文件變得容易一些,。

相比在每個地方調(diào)用下面的語句:

1
NSLocalizedStringFromTable(@"home.button.start-run", @"ActivityTracker", @"some comment..")

你可以自定義一個用于字符串本地化的函數(shù)來讓工作變得輕松一些

1
2
3
static NSString * LocalizedActivityTrackerString(NSString *key, NSString *comment) {
return [[NSBundle mainBundle] localizedStringForKey:key value:key table:@"ActivityTracker"];
}

為了給所有調(diào)用此函數(shù)的地方生成字符串文件,你可以在執(zhí)行 genstrings 的時候加上 -s 選項:

1
find . -name *.m | xargs genstrings -o en.lproj -s LocalizedActivityTrackerString

-s 這個選項指定了本地化函數(shù)的共同前綴名稱,,如果你還定義了LocalizedActivityTrackerStringFromTable,,LocalizedActivityTrackerStringFromTableInBundle,LocalizedActivityTrackerStringWithDefaultValue等函數(shù),,以上命令也會調(diào)用它們,。

運用格式化字符串

我們經(jīng)常需要對一些在運行時才能最終確定下來的字符串進行本地化,格式化字符串可以完成這項工作,。Foundation 在這方面提供了一些非常強大的特性,。(可以參考Daniel 的文章獲得更多關(guān)于格式化字符串的細(xì)節(jié))

以字符串「Run 1 out of 3 completed.」為例,,我們可以這樣構(gòu)造格式化字符串:

1
NSString *localizedString = NSLocalizedString(@"activity-profile.label.run %lu out of %lu completed", nil); self.label.text = [NSString localizedStringWithFormat:localizedString, completedRuns, totalRuns];

在翻譯的時候經(jīng)常需要對其中的格式化占位符進行順序調(diào)整以符合語法,幸運的是我們可以在字符串文件中輕松地搞定:

1
"activity-profile.label.run %lu out of %lu completed" = "Von %2$lu L?ufen hast du %$1lu absolviert";

上面的德文翻譯得不是非常好,,只是單純用來說明調(diào)換占位符順序的功能而已,。

如果你需要對簡單的整數(shù)或者浮點數(shù)進行本地化,你可以使用 localizedStringWithFormat: 這個變體,。數(shù)字本地化的更高級用法涉及 NSNumberFormatter,,會在本文后面講到。

單復(fù)數(shù)與陰陽性

在 OS X 10.9 和 iOS 7 中,,本地化字符串的時候可以使用比替換格式化字符串中的占位符更酷的特性:蘋果官方想處理不同語言中對于名詞復(fù)數(shù)和不同性別采取的不同變化,。

讓我們再看一下之前的例子:@”%lu out of %lu runs completed.” 這個翻譯在「跑多次」的時候才是對的(譯者注:即第二個 %lu 代表的數(shù)字大于 1),所以我們不得不定義兩個不同的字符串來處理單次和多次的情況:

1
2
@"%lu out of one run completed"
@"%lu out of %lu runs completed"

這種做法在英語中是對的,,但是在其他很多語言中會出錯,。比如希伯來語中名詞有三種形式:第一種是單數(shù)和十的倍數(shù),第二種是 2,,第三種是其他的復(fù)數(shù),。克羅地亞語中,,個位數(shù)為 1 的數(shù)字有單獨的表示方法:「31 od 32 staze zavr?ene」,,與之相對的是「5 od 8 staza zavr?ene」(注意其中「staze」和「staza」的差別)。很多語言針對非整型數(shù)也有不同的表達(dá)方式,。

想全面了解這個問題可以參見基于 Unicode 的語言復(fù)數(shù)規(guī)則,。其中涵蓋的變化之博大精深令人嘆為觀止。

為了在 10.9 和 iOS 7 平臺上正確處理這個問題,,我們需要如下構(gòu)造可本地化字符串:

1
NSString localizedStringWithFormat:NSLocalizedString(@"activity-profile.label.%lu out of %lu runs completed"), completedRuns, totalRuns;

然后我們在 .strings 后綴文件所處目錄中創(chuàng)建一個同名的 .stringsdict 后綴的文件,,如果前者名為 Localizable.strings,則后者為 Localizable.stringsdict,。保留 .strings 后綴的字符串文件是必須的,,即使它里面什么內(nèi)容也沒有。這個.stringsdict 后綴的字符串字典文件是一個屬性列表(plist)文件,,比字符串文件復(fù)雜得多,,換來的是正確處理所有語言的名詞復(fù)數(shù)問題,而不需要將處理邏輯寫在代碼中,。

下面是一個該文件的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 
<plist version="1.0"
<dict
    <key>activity-profile.label.%lu out of %lu runs completed</key>
    <dict>
        <key>NSStringLocalizedFormatKey</key>
        <string>%lu out of %#@lu_total_runs@ completed</string>
        <key>lu_total_runs</key>
        <dict>
            <key>NSStringFormatSpecTypeKey</key>
            <string>NSStringPluralRuleType</string>
            <key>NSStringFormatValueTypeKey</key>
            <string>lu</string>
            <key>one</key>
            <string>%lu run</string>
            <key>other</key>
            <string>%lu runs</string>
        </dict>
    </dict>
</dict
</plist>

調(diào)用 localizedStringForKey:value:table: 會返回根據(jù)字符串字典文件中的鍵值對進行初始化的字符串集合,,這些字符串都是包含字符串字典文件中信息的的代理對象(proxy objects)。這些信息在調(diào)用 copy 和 mutableCopy 進行字符串拷貝的時候會被保留,,但是一旦你修改了該字符串,,這些額外信息就會丟失。更多細(xì)節(jié)請參見 OS X 10.9 的 Foundation 發(fā)行說明

字母大小寫

如果你要修改一個用戶可見字符串的大小寫,,請一定使用包含本地化功能的 NSString 方法變體:lowercaseStringWithLocale:和 uppercaseStringWithLocale:

調(diào)用這些方法的時候你需要傳入?yún)^(qū)域設(shè)置參數(shù) locale ,,這樣就可以將大小寫的改變應(yīng)用到本地化之后的其他語言版本中,。當(dāng)你使用NSLocalizedString 及其變體的那些宏時無須擔(dān)心本地化后的大小寫問題,因為在方法內(nèi)部已經(jīng)自動做了處理,,而且在用戶選擇的語言不可用時會使用默認(rèn)語言來代替,。

為了用戶界面的一致性,使用區(qū)域設(shè)置(locale)來本地化界面的其他部分是一個很好的方法,,可以參見后面的小節(jié)「選擇正確的區(qū)域設(shè)置」,。

文件路徑的本地化

一般而言你應(yīng)該始終用 NSURL 來表現(xiàn)文件路徑,因為這會讓文件名的本地化變得容易:

ompleted runs Total Runs Output

——————————————————————

0 0+ No runs completed yet

1 1 One run completed

1 2+ One of x runs completed

2+ 2+ x of y runs completed

 

以上輸出在英語系統(tǒng)中是正確的,,但是假設(shè)我們換到了阿拉伯語系統(tǒng)中,,系統(tǒng)設(shè)置被稱為「??????? ??????.app」。

構(gòu)造這樣一個其他語言的文件名是否包含后綴需要參照用戶 Finder 中的相關(guān)選項,。如果你需要獲取文件的類型,,也可以這樣調(diào)用NSURLLocalizedTypeDescriptionKey 來從中獲得。

本地化之后的文件名僅供顯示使用,,不能用來訪問實際的文件資源,,可以參考 Daniel 關(guān)于常見字符串模式的文章 以獲取更多關(guān)于路徑的細(xì)節(jié)。

格式器

在不同的語言中,,數(shù)字和日期被表現(xiàn)為各種形式,。幸好蘋果官方已經(jīng)提供了處理這些問題的方法,所以我們只需要使用NSNumberFormatter or NSDateFormatter 類來顯示用戶界面中的數(shù)字和日期即可,。

請記住數(shù)字和日期的格式器是可變對象,,因此并不線程安全。

格式化數(shù)字

數(shù)字格式器對象有很多配置選項,,但大多數(shù)情況下你只要使用一種定義好的數(shù)字格式就好,。畢竟使用數(shù)字格式器的原因就是不必再擔(dān)心其他語言中特定的數(shù)字格式。

對于數(shù)字 2.5,,在本文作者的機器上使用不同的格式器會得到不同的輸出:

數(shù)字類型                              德語結(jié)果                      阿拉伯語結(jié)果
------------------------------------------------------------------------------------------------------
NSNumberFormatterNoStyle             2                             ?  
NSNumberFormatterDecimalStyle        2,5                           ???  
NSNumberFormatterCurrencyStyle       2,50 €                        ????? ?.?.  
NSNumberFormatterScientificStyle     2,5E0                         ??????  
NSNumberFormatterPercentStyle        250 %                         ????  
NSNumberFormatterSpellOutStyle       zwei Komma fünf               ????? ???? ????

在上表中數(shù)字格式器的一個很好的特性無法直觀地表現(xiàn)出來:在貨幣和百分?jǐn)?shù)形式中,,貨幣單位和百分號前面插入的不是一個普通空格,而是一個不換行空格,,因此實際顯示的時候數(shù)字和后面的符號不會被顯示在兩行中,。(而且這種加空格的顯示不是很酷嗎?)

默認(rèn)情況下格式器會使用系統(tǒng)設(shè)置中指定的區(qū)域設(shè)置,。在「字母大小寫」一節(jié)中我們已經(jīng)說過,,根據(jù)特定用戶界面的特定要求為格式器指定正確的區(qū)域設(shè)置是非常重要的,在后面的小節(jié)會進一步討論這一點。

格式化日期

與數(shù)字的格式化一樣,,日期的格式化也非常復(fù)雜,,因此我們有必要讓 NSDateFormatter 來負(fù)責(zé)這一點。使用日期格式器的時候你可以選擇蘋果官方提供的適用于所有區(qū)域設(shè)置的不同日期和時間格式,。再強調(diào)一遍,,選擇匹配界面其他元素的正確區(qū)域設(shè)置

有時你想用一種 NSDateFormatter 默認(rèn)不支持的格式來顯示日期,,這時不要使用簡單的格式化字符串(這樣做在應(yīng)用到其他語言中時幾乎肯定會出錯),,而要使用 NSDateFormatter 提供的 dateFormatFromTemplate:options:locale: 方法。

假設(shè)你想只顯示天和月份的縮寫,,系統(tǒng)并沒有提供這樣的默認(rèn)風(fēng)格的,。所以我們可以自定義格式器:

1
2
3
4
5
6
7
NSString *format = [NSDateFormatter dateFormatFromTemplate:@"dMMM" 
                                                   options:0
                                                    locale:locale];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 
[dateFormatter setDateFormat:format];
NSString *output = [dateFormatter stringFromDate:[NSDate date]]; 
NSLog(@"Today's day and month: %@", output);

相比使用格式化字符串,調(diào)用這個方法的一大好處就在于輸出結(jié)果在其他語言中也肯定是正確的,。舉例來說,,在美國英語中,我們期望輸出「Feb 2」,,而在德語中則應(yīng)該輸出「2. Feb」,。dateFormatFromTemplate:options:locale: 方法使用我們指定的模板和區(qū)域設(shè)置來構(gòu)造正確的輸出結(jié)果,在美國英語中將模板變?yōu)椤窶MM d」,,在德語中則變?yōu)椤竏. MMM」,。

想要深入了解模板字符串中可以使用的占位符,可以參考Unicode 格式的區(qū)域設(shè)置數(shù)據(jù)標(biāo)記語言文檔.

緩存格式器對象

因為創(chuàng)建格式器對象是一個非常消耗資源的操作,,所以最好將它緩存起來以供之后使用:

1
2
3
4
5
6
7
8
9
10
11
static NSDateFormatter *formatter;
- (NSString *)displayDate:(NSDate *)date
{
    if (!formatter) {
        formatter = [[NSDateFormatter alloc] init];
        formatter.dateStyle = NSDateFormatterShortStyle;
        formatter.timeStyle = NSDateFormatterNoStyle;
    }
    return [formatter stringFromDate:date];
}
1
這里有一個小的陷阱需要注意:如果用戶修改了區(qū)域設(shè)置,,我們就需要廢棄這個緩存。因此我們需要使用NSCurrentLocaleDidChangeNotification注冊一個通知事件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
static NSDateFormatter *formatter;
- (void)setup
{
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    [notificationCenter addObserver:self
                           selector:@selector(localeDidChange)
                               name:NSCurrentLocaleDidChangeNotification
                             object:nil];
}
- (NSString *)displayDate:(NSDate *)date
{
    if (!formatter) {
        formatter = [[NSDateFormatter alloc] init];
        formatter.dateStyle = NSDateFormatterShortStyle;
        formatter.timeStyle = NSDateFormatterNoStyle;
    }
    return [formatter stringFromDate:date];
}
- (void)localeDidChange
{
    formatter = nil;
}
- (void)dealloc
{
    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
    [notificationCenter removeObserver:self
                                  name:NSCurrentLocaleDidChangeNotification
                                object:nil];
}

蘋果官方的數(shù)據(jù)格式化指南中對此做了注解:

理論上來說你應(yīng)該使用自動更新的區(qū)域設(shè)置(autoupdatingCurrentLocale),,這樣就可以在用戶做更改時生成對應(yīng)的區(qū)域設(shè)置文件,,但是這一招對日期格式器不適用。

所以我們不得不使用為區(qū)域設(shè)置的變更設(shè)置通知機制,。相比格式化日期的那一小段代碼,,這一段有點長,但是如果你頻繁使用日期格式器,,這樣做是值得的,。始終牢記在權(quán)衡利弊之后再進行改進。 再次強調(diào),,格式器不是線程安全的,。蘋果官方文檔中寫道,你可以在多線程環(huán)境下使用格式器,,但是不能有多個線程同時修改格式器,。如果你想將用到的所有格式器集中在一個對象中,,以便在區(qū)域設(shè)置更改時更方便地廢棄緩存,你必須保證只使用一個隊列存放它們從而依次創(chuàng)建和更新,。比如你可以使用并發(fā)隊列(concurrent queue)和 dispatch_sync 來獲取格式器,,在區(qū)域設(shè)置更改時使用 dispatch_barrier_async 來更新格式器。

解析用戶輸入數(shù)據(jù)

數(shù)字和日期格式器不止可以根據(jù)數(shù)字和日期對象生成可本地化字符串,,還能以其他方式工作,。每當(dāng)你需要處理用戶輸入中的數(shù)字或日期時,都應(yīng)該使用合適的格式器類來解析,。這是唯一能夠保證用戶輸入能夠按照當(dāng)前區(qū)域設(shè)置正確解析的方法。

解析機器生成數(shù)據(jù)

雖然格式器在處理用戶輸入時很好用,,在已知格式的情況下處理機器生成的數(shù)據(jù)有更好的方法,,因為為所有區(qū)域設(shè)置生成正確輸出的數(shù)字和日期格式器有性能上的損失。 舉例來說,,如果你從服務(wù)器接收到很多日期字符串,,在你將它們轉(zhuǎn)換成日期對象時,日期格式器并不是最好的選擇,。蘋果官方的日期格式化指南中提到對于這些固定格式且無需進行本地化的日期,,使用 UNIX 提供的 strptime_l(3) 函數(shù)更高效:

1
2
3
4
5
struct tm sometime; 
const char *formatString = "%Y-%m-%d %H:%M:%S %z"
(void) strptime_l("2014-02-07 12:00:00 -0700", formatString, &sometime, NULL);
NSLog(@"Issue #9 appeared on %@", [NSDate dateWithTimeIntervalSince1970: mktime(&sometime)]); 
// Output: Issue #9 appeared on 2014-02-07 12:00:00 -0700

因為 strptime_l 函數(shù)也可以感知用戶的區(qū)域設(shè)置,所以確保最后一個參數(shù)傳入 NULL 以使用標(biāo)準(zhǔn) POSIX 區(qū)域設(shè)置,。函數(shù)中可用的占位符請參考 strftime 用戶手冊,。

調(diào)試本地化字符串

應(yīng)用支持的語言版本越多,確保所有元素都正確顯示就越難,。但是這里有一些默認(rèn)的用戶選項和工具可以減輕你的負(fù)擔(dān),。

你可以使用 NSDoubleLocalizedStringsAppleTextDirection 和 NSForceRightToLeftWritingDirection 選項保證你的布局不會因為長字符串或者從右往左讀的語言而混亂,。NSShowNonLocalizedStrings 和 NSShowNonLocalizableStrings 則可以幫助你找到?jīng)]有翻譯的字符串和根本沒有制定字符串本地化宏的字符串,。(所有這些工具的選項都可以通過程序設(shè)置或者作為 Xcode 的 Scheme 編輯器啟動選項,如 -NSShowNonLocalizedStrings YES

還有兩個選項可以控制語言和區(qū)域設(shè)置:AppleLanguages 和 AppleLocale,。你可以配置這兩個選項讓應(yīng)用以不同于當(dāng)前系統(tǒng)的語言或者區(qū)域設(shè)置啟動,,讓你在測試時不用頻繁對系統(tǒng)設(shè)置進行切換。AppleLanguages 選項接收符合 ISO-639 標(biāo)準(zhǔn)的語言代碼列表作為參數(shù),,如下所示:

1
AppleLanguages (de, fr, en)

AppleLocale 則接收符合Unicode 國際組件標(biāo)準(zhǔn)(International Components for Unicode) 的區(qū)域設(shè)置標(biāo)識符作為參數(shù),,如下:

1
AppleLocale en_US

1
AppleLocale en_GR

如果你翻譯的字符串沒有正確顯示,你可以帶上 -lint 選項運行 plutil 命令來檢查一下字符串文件是否有語法錯誤,。例如你在行尾漏寫了分號,,plutil 會輸出如下警告:

1
2
3
$ plutil Localizable.strings
2014-02-04 15:22:40.395 plutil[92263:507] CFPropertyListCreateFromXMLData(): Old-style plist parser: missing semicolon in dictionary on line 6. Parsing will be abandoned. Break on _CFPropertyListMissingSemicolon to debug. 
Localizable.strings: Unexpected character / at line 1

當(dāng)我們修正了這個錯誤后,plutil 會告訴我們一切正常:

1
2
$ plutil Localizable.strings
Localizable.strings: OK

對于支持多種語言的應(yīng)用,,還有一個與調(diào)試無關(guān)的小技巧:你可以在 iOS 上自動生成應(yīng)用在多種語言下的屏幕截圖,。因為可以使用UIAutomation 來控制應(yīng)用,使用 AppleLanguages 在啟動時設(shè)置語言,所以整個測試過程可以自動化,。GitHub 上的這個項目中可以找到更多細(xì)節(jié),。

選擇正確的區(qū)域設(shè)置

在使用日期和數(shù)字格式器或者類似 [NSString lowercaseStringWithLocale:] 的方法調(diào)用時,確保你使用了正確的區(qū)域設(shè)置是很重要的,。如果你想使用系統(tǒng)當(dāng)前的區(qū)域設(shè)置,,你可以使用 [NSLocale currentLocale] 獲得,但是要注意這不一定與你的應(yīng)用實際運行時使用的相同,。

假設(shè)用戶的系統(tǒng)是中文的,,但是你的應(yīng)用只支持英語、德語,、西班牙語和法語,。這種情況下字符串本地化會使用默認(rèn)的英語來進行,如果你現(xiàn)在使用 [NSLocale currentLocale] 或者使用 [NSNumberFormatter localizedStringFromNumber:numberStyle:]這種未指定區(qū)域設(shè)置的格式器類,,那么這些數(shù)據(jù)會根據(jù)中文的區(qū)域設(shè)置來進行格式化,,而界面上的其他字符串則都是英語。

最終需要你來決定特定情況下什么最重要,,但是你會想要應(yīng)用的界面在一些情況下保持一致,。為了獲取應(yīng)用實際使用的而非當(dāng)前系統(tǒng)的區(qū)域設(shè)置,我們必須獲取 mainBundle 中的語言屬性來構(gòu)造區(qū)域設(shè)置:

1
2
NSString *localization = [NSBundle mainBundle].preferredLocalizations.firstObject; 
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:localization];

在這樣的區(qū)域設(shè)置下,,我們可以將日期格式化為與界面其他元素一致的形式:

1
2
3
4
5
NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 
formatter.locale = locale; 
formatter.dateStyle = NSDateFormatterShortStyle; 
formatter.timeStyle = NSDateFormatterNoStyle; 
NSString *localizedDate = [formatter stringFromDate:[NSDate date]];

結(jié)論

任何適用于自己母語的規(guī)律都不一定適用于其他語言,,在本地化字符串時要牢記這一點。眾多框架提供了很多強大的工具將不同語言的復(fù)雜性抽象出來,,我們只需要一以貫之地運用它們,。這會帶來一些額外的工作,但是會為你在制作自己應(yīng)用的其他語言版本時節(jié)約大量的時間

1 贊 1 收藏 1 評論

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多