# 翻譯
<p class="uk-article-lead">Pagekit 具有以不同語言顯示信息的能力。這就允許界面可以被本地化為任意語言。</p>
**Note** 語言和本地化有一個區別,比如一種語言可能在特定地區有不同的版本(比如 `en_GB` vs. `en_US`)。
## 語言文件
Pagekit 程序核心帶有多種語言文件。
```
/app/system/languages
/en_US
messages.php
formats.json
languages.json
territories.json
/de_DE
messages.php
formats.json
languages.json
territories.json
messages.pot
```
|路徑 | 描述|
|------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------|
|`messages.pot` | 這是包含所有可翻譯字符串的主文件。用作創建本地化版本的基礎。Pagekit 維護者會定期上傳到 Transifex。|
|`/en_US` <br> `/de_DE` | 每個文件夾對應一個地區|
|`xx_XX/formats.json` | 本地化格式的字符串|
|`xx_XX/languages.json` | 本地化的語言名稱|
|`xx_XX/territories.json` | 本地化的地域名稱|
格式、語言和地域都有 [Unicode Common Locale Data Repository](http://cldr.unicode.org/) 進行定義。
翻譯就是簡單地從字符串的英文版本映射到本地化版本 (`de_DE/messages.php`)。
```php
"No database connection." => "Keine Datenbankverbindung."
```
## 用法
要獲取字符串的本地化版本,可以在 PHP 文件中使用全局函數 `__(...)`。在 Vue 模板中,對字符串使用 trans 過濾器。
Pagekit 會自動檢查激活的地區,并返回可用的字符串的本地化版本。
在 PHP 文件中:
```php
echo __('Save');
```
在 Vue 模板中:
```vue
{{ 'Save' | trans }}
```
### 變量
假設你有一個名稱保存在 `$name` 中,并想將它包含到本地化字符串中。可以向翻譯函數傳遞參數實現簡單的字符串替換。
```php
$message = __("Hello %name%!", ["%name%" => $name]);
```
在 Vue 模板中,傳遞參數到 `trans` 過濾器。
```vue
{{ 'Installing %title%' | trans {title:pkg.title} }}
```
### 復數形式
要從幾個信息中進行選擇,取決于一個數字,你可以使用一個指定替換選擇的語法,然后確認數字以及區間(intervals)。使用 `_c(...)` 函數也能支持替換參數。
```php
$message = _c('{0} No Item enabled.|{1} Item enabled.|]1,Inf[ Items enabled.', count($ids))
```
在 Vue 模板中使用 `transChoice` 過濾器。
```vue
{{ '{0} %count% Files|{1} %count% File|]1,Inf[ %count% Files' | transChoice count {count:count} }}
```
要指定匹配的數字,可以在花括號中使用數字 `{0}`,標簽使其更可讀`one:` `more:` 或者區間(intervals) `]1,Inf]`。這些變體也可以混合。
區間表示數字的有限集合: `{1,2,3,4}` ,它也可以表示兩個數字之間的數字: `[1, +Inf]`, `]-1,2[`。左邊的定界符可以是 `[` (包含) 或 `]` (不包含)。右邊的定界符可以是 `[` (不包含) 或 `]` (包含)。除了數字,還可以使用`-Inf` 和 `+Inf` 表示無窮。
## 為擴展創建語言文件
翻譯自己的擴展,使用命令行工具來提取所有可翻譯的字符串。
```bash
./pagekit extension:translate pagekit/extension-hello
```
它會創建包含所有已找到的字符串的 `/packages/pagekit/extensions-hello/languages/messages.pot` 文件。這是通過查找所有調用翻譯函數 `__()`, `_c()` 或 Vue 組件的 `trans` 和 `transchoice` 過濾器來收集的。
然而,自動檢測在動態確認信息時會 _失敗/fail_ 。失敗的例子:
```php
<?php
// 不能檢測到字符串:沒有使用字符串
echo __($message);
// 不能檢測到字符串:使用了格式字符串
echo __('Hello' + $name);
```
```vue
// 不使用翻譯過濾器的字符串
UIkit.notify('Item deleted');
```
有時,你并不能避免這種情況,因為你必須在運行時間(run-time)動態確定字符串。這種問題推薦的解決方式是在擴展內部定位一個可以被翻譯命令找到的 包含所有字符串的 `languages/messages.php` 文件。
```php
<?php
__('Message One');
__('Message Two');
_c('{0} %count% Files|one: File|more %count% File', 0);
```
對于已創建的 `messages.pot`,你現在可以創建擴展的翻譯了。你也可以使用 [poEdit](http://www.poedit.net/) 這樣的工具手動創建翻譯,也可以使用 Transifex。
完成后的翻譯文件必須放在擴展的 `languages` 目錄中,比如放在 `languages/de_DE/` 中。
## 地區是怎么確定的
在安裝程序運行時,地區就被手動選擇了。可以稍后在 Pagekit 管理面板 (_System / Localization_) 中修改,可以為前端和管理面板設置不同的地區。
**Note** 你只能選擇系統擴展可用的語言。
## Working with message domains
`__(...)` / `_c(...)` 函數和 `trans`/ `transChoice` 過濾器有第三個參數,用來設置 _domain_。默認的 domain 叫做 `messages`,這就是為何我們一直在處理 `messages.*` 文件。所有擴展都在這個 domain 中分享它們的字符串。這就是為什么系統擴展翻譯的字符串立即就能使用,而不需要再次翻譯。包括 _Save_,_Error_,_month_ 名稱等等常規術語。
確實,當我們早些調用 `./pagekit extension:translate hello`,得到的 `messages.pot` 就不會包含任何系統消息,即使這些系統消息是發生在 Hello 擴展中。
這可能是這種情況,你并不想從默認 domain 中分享信息。只需要設置自有的 domain 并重新生成 `*.pot` 文件。可以這樣處理個別字符串,或者為所有字符串設置參數使你的本地化與系統徹底分離。
```php
$msg = __("Hello Universe", [], "hello");
```