# 翻译 <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"); ```