要求程式設計師熟記用於特定訊息的魔法鍵並不切合實際,因此,本地化系統應提供符合人體工學的方式,以符號的方式參照這些鍵 (請參閱上述 MSG_Hello_World
的抽象範例)。
遵循 18n 和 l10n 的最佳做法,來源字串會儲存在 XML 檔案中 (在此為 strings.xml
),如下所述。以下是 strings.xml
檔案的範例。這個檔案的目標是宣告程式使用的所有外部字串,並為這些字串提供本機專屬的 name
。字串會做為翻譯的依據,而 name
會做為符號 xml
<!-- comment -->
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- comment -->
<string
name="STRING_NAME"
>text_string</string>
<string
name="STRING_NAME_2"
>text_string_2</string>
<string
name="STRING_NAME_3"
>string with
an intervening newline</string>
</resources>
的依據
檔案 strings.xml
會經過一系列轉換作業,其中翻譯人員會產生同一個檔案的特定語言變化版本。翻譯程序的輸入/輸出行為如下:strings.xml
檔案會輸入字串,這些字串以某種原始 (人類) 語言編寫,並輸出多種 strings.xml
,每種都以特定單一語言翻譯。整個翻譯程序可能相當複雜,在大型機構中,可能會將工作外包給世界各地的翻譯人員,並使用大量專屬的翻譯工具。不過,只要維持輸入/輸出行為,我們就不需要太在意箱子中的確切運作機制,因為我們通常都知道翻譯作業可能需要一段時間。產生的檔案會轉換為機器可讀取的格式,並與 Fuchsia 程式一併在同一個位置中提供。
Fuchsia 套件的重要功能是,它們本質上並非封存檔,而是根據內容雜湊指向檔案的資訊清單。因此,多個程式可以共用相同的檔案,且密切相關的語言 (例如「en-US」、「en-GB」) 可能會共用訊息磁碟空間。下圖簡要說明字串的生命週期。
strings.xml
我們會重複使用 Android 字串資源 XML 格式,以表示可本地化的字串。由於我們不會在 strings.xml 格式中新增任何內容,因此功能的完整討論內容會轉交至字串資源頁面。
雖然上述圖表中的所有 XML 都讓這個討論看起來像是從某個直接連結至 1990 年代的蟲洞中冒出來,但 XML 其實非常適合用來描述註解文字。strings.xml 是經過時間考驗的 Android 格式,因此我們知道它很合適,而且開發人員也熟悉這個格式。
舉例來說,您可以使用註解宣告字串資源,並將註解交錯插入來源文字。
<!-- … -->
<string name="title"
>Best practices for <annotation font="title_emphasis">text</annotation> look like so</string>
<!-- … -->
上圖:翻譯文字和註解交錯的示例。_
您可以交錯不應翻譯的文字,例如:
<string name="countdown">
<xliff:g id="time" example="5 days"
>{1}</xliff:g> until holiday</string>
上圖:範例說明如何交錯使用區隔的參數,並以註解提供示例值,以及使用不屬於字串資源資料結構定義的標記進行保護。_
我們也可以視需要在資料結構定義中加入自訂項目,並在現有結構定義中透明地交錯該資料結構定義。
上述檔案內容必須符合以下限制:
- 檔案中的每個
name
屬性都必須不重複。 - 名稱 ID 可包含大小寫 ASCII 字母、數字和底線,但開頭不得為數字。舉例來說,
_H_e_L_L_o_wo_1_rld
可以使用,但0cool
不行。 - 檔案中不得有重複的
name
-message
組合。
目前,系統不支援在專案中使用多個字串檔案。
訊息 ID
系統會根據 strings.xml
檔案的內容產生訊息 ID (每則訊息的「神奇」數字常數)。每個字串訊息都會取得專屬 ID,這項 ID 是根據 name
上的單向雜湊和訊息本身的內容計算而得。這項 ID 指派作業可確保兩則不同訊息不會意外產生相同的 ID。
這些訊息的產生作業會由 Fuchsia 中的 GN 建構規則自動執行,但最終是由名為 strings_to_fidl 的程式執行。這個程式會為訊息 ID 產生 FIDL 中繼表示法,而一般 FIDL 工具鍊則用於產生該資訊的語言專屬版本。舉例來說,C++ 風格會是包含以下內容的標頭檔案:
namespace fuchsia {
namespace intl {
namespace l10n {
enum class MessageIds : uint64_t {
STRING_NAME = 42u,
STRING_NAME_2 = 43u,
STRING_NAME_3 = 44u,
};
} // namespace l10n
} // namespace intl
} // namespace fuchsia
上述範例中,為每個特定列舉值指派的精確值並不相關。由於所有 ID 都是在編譯時產生,因此目前產生方法也無關緊要,也不會出現版本偏差。我們目前可以安全地假設相同的名稱-內容組合會一律指派相同的郵件 ID。
將產生的檔案納入 C++ 程式相當容易。以下提供最簡單的範例,但請參閱完整的範例,瞭解連線的確切細節。程式庫參數 fuchsia.intl.l10n
是由作者直接提供,做為 strings_to_fidl
的標記;如果使用適當的 GN 範本,則做為 GN 範本的參數。
#include <iostream>
// This header file has been generated from the strings library fuchsia.intl.l10n.
#include "fuchsia/intl/l10n/cpp/fidl.h"
// Each library name segment between dots gets its own nested namespace in
// the generated C++ code.
using fuchsia::intl::l10n::MessageIds;
int main() {
std::cout << "Constant: " << static_cast<uint64_t>(MessageIds::STRING_NAME) << std::endl;
return 0;
}
*.json
FIDL 和 C++ 程式碼產生功能可讓程式作者使用訊息 ID。在包裝方面,我們也必須為支援的每種語言提供本地化素材資源。目前這項資訊的編碼為 JSON。這項決定是為了加快速度,但我們可以針對這項決定做出許多改善,以提升效能和安全性。
產生這項資訊的任務會委派給名為 strings_to_json 的程式,該程式會將原始 strings.xml
與特定語言的檔案合併 (例如,法文翻譯會位於 strings_fr.xml
中)。同樣地,對於由 GN 驅動的建構作業,strings_to_json
的叫用會封裝在建構規則中。
以下是產生 JSON 檔案的內容範例。
{
"locale_id": "fr",
"source_locale_id": "en-US",
"num_messages": 3,
"messages": {
"42": "le string",
"43": "le string 2",
"44": "le string\nwith intervening newline"
}
}
JSON 格式目前定義了下列欄位。如果下方表格已過時,JSON 結構的真相來源為 字串模型。
欄位 | 類型 | 說明 |
---|---|---|
locale_id |
語言代碼 ID (字串) | 訊息翻譯的語言代碼。 |
source_locale_id |
語言代碼 ID (字串) | 來源訊息檔案的語言代碼。 |
num_messages |
正整數 | 原始 strings.xml 中訊息的數量。這樣一來,我們就能比較訊息數量與 JSON 檔案中的訊息數量,快速估算翻譯品質。 |
messages |
在地圖上顯示[u64->string] |
將郵件 ID 對應至適當的郵件。 |