iOS App 本地化終極指南

了解 iOS App 本地化的來龍去脈,以及如何逐步讓您的應用程序為全球用戶群做好準備,包括演示應用程序 App 示例。

iOS 操作系統每年都在不斷發展壯大。對於 app 開發人員而言,Apple 對國際化的日益關注意味著更容易製作適合全球市場的應用程序。

App Store在 175 個國家/地區可用,每周有超過 50 億的訪問者,使 app 在盡可能多的地區和語言中可用,也是應用程序成功的必經之路,而現在做到這一點的簡便性意味著幾乎沒有任何藉口跳過它。

本分步指南將向您展示向全世界開放您的app是多麼簡單。我們將在 UIKit 和 SwiftUI 中進行 app 本地化,這使其適用於所有類型的團隊。

目錄

安裝和設置

在本教程中,我們將研究“Sleepy”,這是一款銷售助眠專輯的 iOS App 應用程序。演示應用程序將使我們能夠展示 iOS App 本地化的所有關鍵步驟。Sleepy 的靈感來自Uladzislau Luchkouski關於Sleepy 聲音的案例研究。雖然 Sleepy 使用 Swift 5,但我們將在 iOS 15 上使用 Xcode 版本 13.3.1 和 SwiftUI 3。

現在我們的環境已經準備就緒,我們已經準備好構建我們夢想的App 應用程序。第一步是考慮您想要支持的語言。在這種情況下,Sleepy 將以英語作為基本語言,它還將支持西班牙語和希伯來語——希伯來語將有助於處理從右到左 (RTL) 的語言。您可以根據您的應用程序 App 的需要隨意添加盡可能多的語言,並且 每次都可以重複相同的過程。

創建項目

從 iOS App 本地化這個簡單的應用程序中學到的原則可以應用於任何類型的App,無論大小。您可以在此處獲取UIKitSwiftUI中的完整項目。當您成功運行該項目時,您應該能夠看到睡眠聲音列表。點擊任何相冊將顯示更多詳細信息。

如何將支持的語言添加到我的應用程序?

iOS App 可以本地化到 100 多個語言環境和地區。iOS 使用兩個字母的 ISO 639-1 標準來表示語言,例如en英語、fr法語等。

🗒️注意 »如果 ISO 639-1 代碼不適用於特定語言,請改用 ISO 639-2 代碼。例如,夏威夷語沒有 ISO 639-1 代碼,因此使用 ISO 639-2 代碼,haw.

Apple 在其文檔中提供了有關語言代碼的更多信息。這些標識符告訴 iOS 系統您的App 本地化為哪種語言,並向用戶顯示該語言。

現在我們的項目已經準備就緒,讓我們進入有趣的部分:iOS App 本地化。

Project Navigator中選擇項目名稱。如果未選中,則選中Use Base Internationalization 。

基本 App 國際化將面向用戶的字符串.storyboard.xib文件分開。它使本地化人員無需 在 Interface Builder 中修改文件.storyboard。 .xib當您選中Use Base Internationalization選項時,Xcode 會將Main.storyboard和傳輸LaunchScreen.storyboardBase.lproj默認語言的文件夾中。您會記得我們在 iOS App本地化教程中的基本語言是英語。

🗒️注意 »如果您不啟用Use Base Internationalization ,您將必須手動管理所有本地化文件和文件夾結構。如果您需要自己管理本地化文件,則可以輕鬆閱讀官方指南

添加本地化語言

接下來是添加您想要支持的語言。在我們的例子中,我們將添加西班牙語和希伯來語。從Project Navigator ➞選擇項目名稱。在Localizations下,單擊加號 (+) 以添加您要支持的語言和地區。將顯示一個語言列表供您選擇您選擇的語言,讓我們從西班牙語開始。

選擇語言(在我們的示例中為西班牙語)後,將顯示用於創建所需語言本地化表的選擇文件和參考語言。取消選中LaunchScreen.storyboard。Apple 僅允許在 中使用靜態資產LaunchScreen,不支持在LaunchScreen.

在上面的屏幕中,有兩件事需要您注意:

  1. 參考語言——我們設計應用程序所使用的基本語言,默認為 英語。建議使用英語(或您團隊的母語/流利的語言)。將其更改為另一種語言將使用該語言的鍵創建所有本地化文件。由於基本語言應該是本地化的指南,因此建議保持這種狀態。
  2. 文件類型——確保所有文件都設置為Localizable Strings
  3. 如上圖所示,點擊完成。

對應用程序應支持的任意數量的語言重複這些相同的步驟。

添加語言支持後項目的變化

添加所有支持的語言後,您會發現項目發生了一些變化。讓我們回顧一下這些變化,以及它對我們的本地化目標意味著什麼。

  • 語言文件夾:Xcode 將創建es.lproj並分別he.lproj包含Main.strings西班牙語和希伯來語。
  • 故事板:Main.storyboard現在應該是一個包含基本語言Main.storyboardMain.strings支持語言的文件夾。

如何使用翻譯文件?

在我們的iOS App 本地化之旅中,我們會遇到不同的文件,它們都可以幫助我們實現我們的目標。

  • 字符串文件:字符串文件包含一種語言的面向用戶的本地化字符串的翻譯,帶有可選註釋。字符串文件中每個字符串的語法是一個鍵值對,其中是用於查找包含翻譯的key標識符。value
  • lproj文件夾:是一個目錄,用於存儲特定於語言的資源,例如es.lprojhe.lproj.
  • XLIFF:是一種基於 XML 的雙文本格式,它標準化了在本地化過程中如何在工具之間傳遞可本地化的數據。

🔗資源 » 在 Apple 文檔中了解有關 XLIFF 格式的更多信息。

我如何處理語言回退?

我知道您可能會問自己,如果用戶使用您的App 不支持的語言或者您的App  支持該語言但並非該特定語言的每個字符串都已本地化,會發生什麼情況?

  • 對於完全不支持的語言,iOS 將默認使用基本語言或開發語言。
  • 對於部分翻譯的語言,Apple 使用一種算法來幫助確定用戶應該看到哪種語言。以下是偽代碼中的算法:
func determineTheLanguageToUse() {
    for each user's preferredLanguages
      if app supports the language
        return the language
      if app supports a more generic dialect
        return the generic language

     // Exhausted preferredLanguages and still cannot determine..
     return CFBundleDevelopmentRegion
}代碼語言: Swift  斯威夫特

🗒️ 注意 »用戶preferredLanguages是在 iOS 的設置應用程序 ➞ 常規 ➞ 語言和地區中列出的用戶。

通用方言

語言選擇的偽代碼非常簡單,只是它不涵蓋通用方言。iOS 支持的語言不止一種方言。en英語可以有不同的方言,例如en-GB英語(英國)、en-US英語(美國)、en-IE英語(愛爾蘭)等。在我們當前的應用程序中,如果用戶願意en-GBen將使用 , 因為它是最接近通用方言en-GB.

注意 »反之則不然。如果應用程序支持en-GB(而不是en),那麼如果用戶更喜歡en,則en-GB不會是後備方案,因為en-GB它不是更通用。在這種情況下,它默認為CFBundleDevelopmentRegion,這是應用程序的默認語言和區域。

🤿更深入 »官方文檔有更多關於如何進行語言環境匹配和回退決策的詳細信息。

程序化回退

為了防止任何意外行為,我們可以創建一個擴展函數,該函數封裝了當找不到首選語言時NSLocalizedString所需的回退。defaultLanguage這將在整個項目中使用。

/*
Utils.swift
*/

extension String {

     func localize(comment: String = "") -> String {
         let defaultLanguage = "en"
         let value = NSLocalizedString(self, comment: comment)
         if value != self || NSLocale.preferredLanguages.first == defaultLanguage {
             return value // String localization was found
         }

				 // Load resource for default language to be used as
         // the fallback language
         guard let path = Bundle.main.path(forResource: defaultLanguage, ofType: "lproj"), let bundle = Bundle(path: path) else {
             return value
         }

         return NSLocalizedString(self, bundle: bundle, comment: "")
    }
}代碼語言: Swift  斯威夫特

我們可以localize()如下使用。

// Prints the translation of the key localised to the user's
// language or default to English
print("translation.key".localize()) 

使用 Localizable.strings

Localizable.strings將要在應用程序中使用的字符串存儲為鍵值對,並將用於以您支持的語言進行本地化。

讓我們Localizable.strings通過轉到文件新建文件或只需按Cmd+N來創建。搜索“字符串”,您將在資源窗格中看到字符串文件

選擇如上圖所示的Strings File ,然後點擊Next。命名文件Localizable創建文件。

點擊新創建的Localizable.strings文件,然後點擊檢查器中的本地化在出現的警告中,點擊“本地化”以創建英語的本地化文件。

Inspector中,在 Localization 部分下檢查您的應用程序的所有其他受支持的本地化,以創建這些語言的本地化字符串。

為譯員導出可本地化的文件

本地化可能需要大量工作。來自谷歌的直接翻譯並不總是足夠好。您可能需要像 LANCER 這樣的專家來為您解決這個難題,這樣您就可以專注於構建產品。您可以為翻譯導出您的字符串。在專家完成翻譯後,只需將翻譯後的字符串導入回您的應用程序中即可使用。

在這種方法中,我們將看到如何為本地化人員(翻譯人員)導出可本地化的文件。為此,首先為 Localization 創建一個單獨的文件夾(如下所示):

如您所見,Localization文件夾中有兩個文件夾。To Localizers是我們作為開發人員為翻譯人員導出可本地化文件的文件夾。From Localizers是我們將本地化文件從翻譯器導入到我們的項目的文件夾。創建文件夾後,返回我們的 Xcode 項目並再次打開根文件夾信息設置。讓我們通過轉到產品菜單導出本地化來導出。

點擊“導出本地化”選項後,Xcode 會要求您將可本地化的文件保存到指定的文件夾中,如下所示:

這將以 XLIFF 格式導出所有選定的本地化,本地化人員可以使用該格式來本地化您的應用程序。翻譯完成後,他們會發回一個 XLIFF 文件,您應該保存該文件From Localizers以便導入。要導入本地化,請轉至產品菜單導入本地化在 中選擇文件 From Localizers

如何本地化我的故事板?

本地化可以在 UIKit 中主要在 2 個級別上完成。直接在故事板上本地化,主要用於靜態文本,並以編程方式進行本地化。我們將從如何直接本地化故事板開始。

我們已經在設置步驟中為故事板本地化奠定了基礎。在“語言支持後項目的更改”部分中,我們看到它Main.strings是為我們的非基礎支持語言創建的。這些Main.strings包含故事板中標籤的 ID。

當我們選擇Main(Spanish)文件時,我們會看到對象 ID 及其文本的鍵值對,表示這些字符串將如何以西班牙語顯示。如您所見,它仍然是英文的,因此我們必須將其本地化為西班牙文。

翻譯後。

現在讓我們以西班牙語運行該應用程序,看看我們的本地化是否有效。默認情況下,每次運行應用程序時,它都會使用基本語言。您可以通過Option + 點擊Play) Start active scheme button使用不同的語言環境運行您的應用程序,然後轉到Run → Options → App Language → Change to a supported language(在本例中為西​​班牙語)→ 點擊Run

文件Main(Spanish)已翻譯。應用程序的其餘部分將隨著我們的移動而逐漸翻譯。現在我們剛剛學習瞭如何本地化情節提要,您可以按照相同的步驟將情節提要本地化為希伯來語。

如何本地化 Swift 代碼中的字符串?

我們還可以使用這些Localizable文件以編程方式本地化我們的應用程序。Localizable文件還使用格式中的鍵值"key" = "value";對進行本地化。在Localizable(English)文件中,我們將添加表示音樂數據的其餘字符串。

/*
Localizable.strings
*/

/* Titles of Sleep albums */
"slumber" = "Slumber";
"white.noise" = "White Noise";
"soothing" = "Soothing";
"paino" = "Piano";
"wind" = "Wind";
"cold.fusion" = "Cold Fusion";

/* Categories of Sleep albums */
"zen" = "Zen";
"instrumental" = "Instrumental";
"nature" = "Nature";

/* About of Sleep albums */
"about1" = "An acoustic mix has been specially selected for you. The camping atmosphere will help you improve your sleep and your body as a whole. Your dreams will be delightful and vivid.";代碼語言: Swift  斯威夫特

iOS 已經為我們提供了一種輕鬆的方式來使用它們的鍵來顯示這些字符串,以便於本地化。NSLocalizedString從默認表返回字符串的本地化版本,Xcode 在導出本地化時自動生成。

回顧編程回退****部分,我們創建的擴展函數使用了NSLocalizedString兩個最常見的實現。

  • NSLocalizedString(key, comment):key對於默認表中的字符串,並comment有助於為翻譯人員提供有關如何在應用程序中使用該字符串的上下文。
  • NSLocalizedString(key, tableName, bundle, value, comment):當您想將字符串文件拆分為更小、易於管理的大小時,此簽名會很有用。當您正在開發一個非常大的應用程序並且您不想將所有可本地化的字符串集中在一起時,這一點尤其重要。Localizable.strings****文件。默認NSLocalizedString(key, comment)只讀取文件。Localizable.strings在這個簽名中:
    • tableName 是包含鍵值對的表的名稱。
    • bundle是文件系統中的一個目錄,它將可執行代碼和相關資源集中在一個地方。我們經常只是Bundle.main在這裡使用。
    • value是您想要默認的字符串,以防找不到所key提供的字符串。

有了這些新知識,讓我們針對西班牙語和希伯來語進行本地化,並使用localize()我們已經在Programmatic fallback中創建的擴展函數。

/*
Localizable.strings
*/

/* Titles of Sleep albums */
"slumber" = "תְנוּמָה";
"white.noise" = "רעש לבן";
"soothing" = "הַרגָעָה";
"paino" = "פְּסַנְתֵר";
"wind" = "רוּחַ";

/* Categories of Sleep albums */
"cold.fusion" = "זן";
"zen" = "מוֹעִיל";
"instrumental" = "טִבעִי";

/* About Sleep albums */
"about.acoustic" = "מיקס אקוסטי נבחר במיוחד עבורכם. אווירת הקמפינג תעזור לכם לשפר את השינה ואת הגוף כולו. החלומות שלך יהיו מענגים וחיים.";
代碼語言: Swift  斯威夫特

Utils.swift我們將使用擴展功能本地化歌曲數據。如果未找到翻譯,這將本地化字符串並回退到默認語言。

/*
Utils.swift
*/

SleepData(
    image: "image1",
    title: "slumber".localize(),
    numberOfSongs: 4,
    category: "zen".localize(),
    songs: ["Friday Night Lights", "4 your eyes only", "Love yours"],
    about: "about.acoustic".localize())

🗒注意 » title6是英文的Cold Fusion沒有翻譯,因此我們轉而使用英文來翻譯該字符串。

如何使用用戶的首選系統區域設置?

當應用程序支持當前語言環境時,iOS 系統會自動處理應用程序的語言環境切換,例如,如果手機的語言設置為希伯來語,我將看到該應用程序的希伯來語版本。如果語言切換為西班牙語,iOS 系統會將應用程序版本更改為西班牙語。如果語言更改為沒有本地化的語言,則應用程序將使用基本語言。

應用內語言環境切換

最好讓操作系統處理用戶的首選語言環境,並讓您的應用程序適應它。事實上,Apple 警告應用程序不要自行切換語言環境:所有編程方法都可能導致無法預料的更改,並且在 iOS 更新後可能無法正常工作。處理此問題的首選方法是以編程方式打開應用程序的首選語言設置,以便用戶可以自行更改設置。

這是打開應用程序設置以供用戶更改語言的代碼片段。在您應用程序的任何適當部分使用它,例如在 Sleepy 中,我們可以在主屏幕的菜單中使用它。

if let settingsURL = URL(string: UIApplication.openSettingsURLString) {
    UIApplication.shared.open(settingsURL, options: [:], completionHandler: nil)
}代碼語言: Swift  斯威夫特

編程語言切換

儘管 Apple 不推薦,但用例不同,您可能需要通過代碼更改語言環境。iOS 使用密鑰將區域設置保存在用戶默認值中AppleLanguages,更改此設置將更新應用程序的區域設置。問題是必須重新打開應用程序才能看到更改。我們將使用通知來提示用戶重新打開應用程序。您可以選擇顯示警告或表格來解釋為什麼用戶在更改語言後需要重新打開應用程序。解決此問題的最佳用戶體驗可能會有所不同,因此我們讓您自己做出決定。我們將為我們的應用程序 Sleepy 使用通知。

/*
ViewController.swift
*/

private func setLangauge(languageCode: String, language: String) {
     let alert = UIAlertController(title: nil, message: "changing.language".localize(), preferredStyle: .alert)

      alert.addAction(UIAlertAction(title: "exit.sleepy".localize() , style: .default, handler: { [weak self](_) in
						// Update app's language with the language code
            UserDefaults.standard.set([languageCode], forKey: "AppleLanguages")
            UserDefaults.standard.synchronize()

            self?.closeApplicationWithNotification(language: language)
    }))

		 // Show change language alert to user
     self.present(alert, animated: true, completion: nil)
}

 private func closeApplicationWithNotification(language: String) {
     let content = UNMutableNotificationContent()
     content.title = "Language changed to \(language)"
     content.body = "Tap to reopen the application"
     content.sound = UNNotificationSound.default

     let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.5, repeats: false)
     let identifier = "sleepy"
     let request = UNNotificationRequest.init(identifier: identifier, content: content, trigger: trigger)
     let center = UNUserNotificationCenter.current()
     center.add(request)

     exit(EXIT_SUCCESS)
}代碼語言: JavaScript  javascript 

這兩個函數將幫助我們更改應用程序的區域設置並向用戶發送通知以點擊它以打開應用程序。該功能closeApplicationWithNotification是可選的,重新打開應用程序的用戶體驗應該按照您認為合適的方式進行處理。我們使用exit(EXIT_SUCCESS)關閉應用程序來重新啟動本地化更改以完全應用到應用程序,例如希伯來語切換到從右到左。

🔗資源 »查看如何以編程方式退出我的 iOS 應用程序?在蘋果官方文檔中。

讓我們看看我們如何在我們的應用程序中使用我們的函數。我們將有一個菜單顯示支持的語言,選擇一種語言將更改應用程序語言。

/*
ViewController.swift
*/

func configureActionItemMenu() {
    let menuItems = [
         UIAction(title: "English", handler: { [weak   self] (_) in
             self?.setLangauge(languageCode: "en", language: "English")
        }),
         UIAction(title: "Hebrew",handler: { [weak   self] (_) in
             self?.setLangauge(languageCode: "he", language: "Hebrew")
        }),
         UIAction(title: "Spanish", handler: { [weak   self] (_) in
         self?.setLangauge(languageCode: "es", language: "Spanish")
        })
    ]

    let languageMenu = UIMenu(
			title: "choose.language".localize(), 
			image: nil, 
			identifier: nil, 
			options: [], 
			children: menuItems
		)

    navigationItem.rightBarButtonItem = UIBarButtonItem(
			title: "choose.language".localize(), 
			image: UIImage(systemName: "gear"), 
			primaryAction: nil, 
			menu: languageMenu
		)
    navigationItem.rightBarButtonItem?.tintColor = .white
}

如何在我的翻譯字符串中使用動態值?

插值是字符串最常見的用例之一,那麼當您想將它與本地化字符串一起使用時會發生什麼?再一次,我們將構建我們的擴展,使整個項目的插值變得簡單和乾淨。

/*
Utils.swift
SleepyUIKit
*/

extension String {
    // ...

    func localizeFormat(args: [CVarArg], comment: String = "") -> String {
        return self.localizeStringFormat(key: self, comment: comment, args: args)
    }

    func localizeStringFormat(key: String, comment: String = "", args: CVarArg... ) -> String {
        let format = NSLocalizedString(key, comment: comment)
        let result = withVaList(args) {
            (NSString(format: format, locale: NSLocale.current, arguments: $0) as String)
        }
        return result
    }
}代碼語言: Swift  斯威夫特

添加以下本地化Localizable.strings以用於插值。字符串說明符是特殊字符,指示插值參數的類型。您可以將單個或多個說明符添加到同一字符串插值中。可以在此處找到我們可用的所有說明符的完整列表。

"sleep.points" = "%1lu Sleep Points"; // Number interpolation
"hello.user" = "Hello %1$@"; // String interpolation
"share" = "Share %1lu song to %2$@"; // Multiple interpolations代碼語言: Swift  斯威夫特

現在在我們的代碼中,我們可以將這些字符串與擴展函數一起使用。數字格式將在本文後面更深入地解決。

// Output assumes English (en-US) is the active locale

someLabel.text = "sleep.points".localizeFormat(args: [3000])
// => 3,000 Sleep Points

someLabel.text = "hello.user".localizeFormat(args: ["John"])
// => Hello John

someLabel.text = "share".localizeFormat(args: [1, "Norris"])
// => Share 1 song to Norris

如何使用本地化複數字符串?

目前,在我們的應用程序中,即使睡眠專輯只有 1 首“歌曲”,我們也會顯示“歌曲”。複數有助於管理此類情況,以確保您的應用程序遵循每種語言的正確語法規則。Xcode 使用.stringsdict文件為複數生成本地化,讓我們創建一個,以便我們可以修復應用程序中的複數問題。

讓我們.stringsdict通過轉到文件 ➞ 新建 ➞ 文件或只需點擊Ctrl+N或來創建Cmd+N。搜索“stringsdict”,您將在資源窗格中看到字符串文件。點擊下一步並按照提示創建文件。

點擊新創建的Localizable.stringsdict文件,然後點擊Inspector中的Localize在出現的警告中,點擊“本地化”以創建英語的本地化文件。在Inspector中,在Localization部分下檢查您的應用程序的所有其他受支持的本地化,以便為這些語言創建本地化字符串。

<!-- Localizable(English).stringsdict -->

<?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>songs</key> <!-- Localized String Key -->
	<dict>
		<key>NSStringLocalizedFormatKey</key>
		<string>%#@songsCount@</string>
		<key>songsCount</key> <!-- Variable -->
		<dict>
			<key>NSStringFormatSpecTypeKey</key>
			<string>NSStringPluralRuleType</string>
			<key>NSStringFormatValueTypeKey</key>
			<string>d</string>
			<key>zero</key>
			<string>No Songs</string>
			<key>one</key>
			<string>%d Song</string>
			<key>other</key>
			<string>%d Songs</string>
		</dict>
	</dict>
</dict>
</plist>代碼語言: Swift  斯威夫特

讓我們逐步了解它。

  • Localized String Key:要在 NSLocalizedString 中使用的鍵。
  • NSStringLocalizedFormatKey
    • 要本地化的文本,即。%#@songsCount@.
    • 變量應以格式定義,%#@併後跟@.
    • 只為有復數的參數定義變量。
  • 變量:適用於特定變量的規則。您為在 ie 中定義的每個變量創建一個NSStringLocalizedFormatKeysongsCount.
  • NSStringFormatSpecTypeKey:處理參數的規則。它已經設置為NSStringPluralRuleType所以我們可以保持原樣。
  • NSStringFormatValueTypeKey:參數的格式,如d表示整數或f表示雙精度。有關完整列表,您可以查看Apple 的字符串格式說明符
  • CLDR 語言複數規則:您可以選擇不同的複數規則,例如zeroonetwofewmany, 和other。對於某些語言,例如英語,您只需要配置兩個規則,oneother. 其他語言只有一個複數規則,有些語言有兩個以上。此處提供了詳細指南。

讓我們更改我們的代碼以正確格式化複數。好消息:我們不需要創建一個新的擴展函數來處理這個,localizeFormat已經處理了複數。

someLabel.text = "songs".localizeFormat(args: [1])

如何本地化數字?

格式化數字是本地化中經常被遺忘的一個方面,因為並非所有語言都以相同的方式格式化數字。iOS 提供了一個NumberFormatter負責處理不同語言環境格式的工具。我們的應用程序中缺少的是顯示專輯的價格,我們將以此為契機利用NumberFormatter.

/*
SleepDetailViewController.swift
*/
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .currency
priceButton.setTitle(numberFormatter.string(from: 99.99), for: .normal)代碼語言: Swift  斯威夫特

運行應用程序,應用程序語言為希伯來語,應用程序區域為以色列。

數字格式化的另一個常見用例是小數。格式numberFormatter.numberStyle = .currency樣式正確顯示數字以適合用戶的區域設置,例如 123456789 對於英語、美國 ( en-US) 將顯示為 $123,456,789.00,對於西班牙語、西班牙 ( es-ES) 將顯示為 1.234.567.899,00。

注意 »數字格式因地區而異。默認情況下使用用戶的區域設置,但您可以指定數字的區域設置以numberFormatter.locale = Locale(identifier: "en-US")避免任何意外,例如使用 123456789 將是 $123,456,789.00en-US和 ₹1,234,567,899.00 en-IN

🔗資源 » NumberFormatter可以做的不僅僅是貨幣本地化,請查看文檔中的完整樣式列表。

如何本地化日期?

以用戶的語言環境顯示日期是一種很好的做法。該DateFormatter課程使這變得容易。讓我們在打開相冊時顯示當前日期。

🔗資源 » DateFormatter提供更多內容,請閱讀文檔以深入研究。

/*
	SleepDetailViewController.swift
*/

let dateformatter = DateFormatter()
dateformatter.dateStyle = .long
dateLabel.text = dateformatter.string(from: Date())

我們已經了解瞭如何在解決最常見的本地化問題的同時本地化我們的應用程序。現在讓我們將注意力轉移到如何使用 SwiftUI 進行本地化。

如何本地化我的 SwiftUI 視圖?

SwiftUI 是一個聲明式現代框架,可幫助在所有 Apple 平台上構建應用程序。SwiftUI 具有強大的本地化支持並且需要更少的工作。Text,最常見的 SwiftUI 視圖已經預先構建並支持LocalizedStringKey,這意味著傳遞本地化字符串的鍵就可以了。本地化的設置與 UIKit 中的相同,因此請繼續並按照相同的步驟進行設置。

讓我們使用 SwiftUI 中的通用視圖Text來演示這一點。Localizable.strings由於 SwiftUI 中沒有故事板,因此讓我們將故事板本地化字符串複製到其中。

/*
Localizable.strings
*/
"list.of.songs" = "LIST OF SONGS";
"about.this.pack" = "About this pack";代碼語言: Swift  斯威夫特
/*
SleepDetailView.swift
*/

Text("about.this.pack")
    .font(.title3)
    .fontWeight(.semibold)
    .foregroundColor(.white)

通過僅傳遞本地化字符串的鍵,About pack 已本地化為希伯來語和西班牙語。

SwiftUI 翻譯預覽

借助 SwiftUI 預覽的強大功能,您可以通過將語言環境指示為環境來預覽本地化。Xcode 中默認顯示預覽,但如果您的預覽未顯示,則可以使用快捷方式Option + Command + Return來打開和關閉它。

/*
SleepDetailView.swift
*/

struct SleepDetailView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
         SleepDetailView(sleeper: SleepData.list.first!)
            .environment(\.locale, .init(identifier: "en"))

         SleepDetailView(sleeper: SleepData.list.first!)
            .environment(\.locale, .init(identifier: "he"))
        }
    }
}

插值

插值可以通過對我們的進行一些更改來實現Localizable.strings,當我們為 SwiftUI 進行本地化時,我們的字符串的鍵需要包含說明符。

// UIKit
"hello.user" = "Hello %@";代碼語言: Swift  斯威夫特

……變成……

// SwiftUI
"hello.user %@" = "Hello %@";代碼語言: Swift  斯威夫特

然後我們可以在我們的視圖中使用它。

let user = "Conan"

Text("hello.user \(user)") // Hello Conan
.foregroundColor(.white.opacity(0.7))
.font(.subheadline)

複數

SwiftUI 中的複數遵循與 UIKit 中相同的模式,通過使用Localizable.stringsdict. SwiftUI 的變化是我們必須將說明符添加到Localized String Key

<?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>songs %d</key> <!-- Localized String Key -->
	<dict>
		<key>NSStringLocalizedFormatKey</key>
		<string>%#@songsCount@</string>
		<key>songsCount</key>
		<dict>
			<key>NSStringFormatSpecTypeKey</key>
			<string>NSStringPluralRuleType</string>
			<key>NSStringFormatValueTypeKey</key>
			<string>d</string>
			<key>zero</key>
			<string>No Songs</string>
			<key>one</key>
			<string>%d Song</string>
			<key>other</key>
			<string>%d Songs</string>
		</dict>
	</dict>
</dict>
</plist>代碼語言: Swift  斯威夫特
/*
SleeperView.swift
*/

Text("\(5) songs")
    .foregroundColor(.white.opacity(0.7))
    .font(.subheadline)

組合複數和插值

在構建您的應用程序時,事情可能並不總是一帆風順。可以有復數、插值等各種組合,全部混合。讓我們看一下組合複數和插值。

<!-- Localizable(English).stringsdict -->

<?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>%lld songs %@</key>
    <dict>
        <key>NSStringLocalizedFormatKey</key>
        <string>%#@songsCount@</string>
        <key>songsCount</key>
        <dict>
            <key>NSStringFormatSpecTypeKey</key>
            <string>NSStringPluralRuleType</string>
            <key>NSStringFormatValueTypeKey</key>
            <string>d</string>
            <key>zero</key>
            <string>No Songs • %@</string>
            <key>one</key>
            <string>%d Song • %@</string>
            <key>other</key>
            <string>%d Songs • %@</string>
        </dict>
    </dict>
</dict>
</plist>代碼語言: Swift  斯威夫特
/*
SleepDetailView.swift
*/

Text("\(sleeper.numberOfSongs) songs • \(sleeper.category)")
    .foregroundColor(.white.opacity(0.7))
    .font(.subheadline)

添加評論

我們已經看到在本地化字符串時添加註釋的重要性。讓我們繼續我們在 SwiftUI 中的最佳實踐。

Text("sleepy", comment: "Navigation title")

為非文本視圖添加本地化字符串

對於文本視圖以外的任何內容,請使用文本視圖初始化視圖或為您的應用添加字符串以提供本地化視圖。您可以本地化其他視圖,例如LabelPicker,因為它們接受LocalizedStringKey. 最簡單的方法是傳遞Text到接受它的視圖或使用localize()我們在 UIKit 中一直使用的擴展函數。

"sleep.points" = "%1lu Sleep Points";代碼語言: Swift  斯威夫特
navigationTitle(Text("\(3000) sleep.points"))
// => 3000 Sleep Points代碼語言: Swift  斯威夫特
navigationTitle("sleep.points".localizeFormat(args: [3000]))
// => 3000 Sleep Points

編程語言切換

我們將利用 UIKit 示例中的相同功能在 SwiftUI 中實現這一點。

/*
ContentView.swift
*/
...
.alert("changing.language", isPresented: $showRestartApplication, actions: {
  Button("exit.sleepy") {
      UserDefaults.standard.set([selectedLanguage.code], forKey: "AppleLanguages")
      UserDefaults.standard.synchronize()
      self.closeApplicationWithNotification(language: selectedLanguage.name)
  }
})

總結

現在我們準備好與全世界分享我們美妙的睡眠專輯。我們已經了解瞭如何使用 UIKit 和 SwiftUI 實現行業標準的 iOS App 本地化水平。我們經歷了常規場景和復雜場景。有了這個,您的App就可以征服國際市場了。

就這麼簡單,LANCER 甚至可以讓它變得更簡單。作為專業的App本地化解決方案,LANCER 具有強大的 Web 管理控制台,可幫助翻譯人員和開發人員更高效地協作和 App 本地化應用程序。它還為開發人員提供了一個功能齊全的 API 來連接,以及越來越多的第三方集成。LANCER 可以從頭到尾簡化您團隊的App本地化工作流程。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *