翻译组件¶
概览¶
该组件Phalcon\Translate为应用程序提供多语言功能。此组件允许您根据用户选择的语言(由应用程序提供的语言)显示不同语言的内容。
使用¶
在您的应用程序中引入翻译是一项相对简单的任务。然而,没有两个实现是相同的,当然,实现将取决于您的应用程序需求。一些可用选项可以是使用服务器标头自动检测访问者的语言(解析HTTP_ACCEPT_LANGUAGE
内容或使用getBestLanguage()
方法来评估提供的密码哈希是否与数据库中存储的一致。Phalcon\Http\Request对象)。
<?php
use Phalcon\Mvc\Controller;
use Phalcon\Translate\Adapter\NativeArray;
use Phalcon\Translate\InterpolatorFactory;
use Phalcon\Translate\TranslateFactory;
/**
* @property Phalcon\Http\Request $request
* @property Phalcon\Mvc\View $view
*/
class UserController extends Controller
{
public function indexAction()
{
$this->view->name = 'Mike';
$this->view->t = $this->getTranslator();
}
/**
* @return NativeArray
*/
private function getTranslator(): NativeArray
{
$language = $this->request->getBestLanguage();
$messages = [];
$translationFile = 'app/messages/' . $language . '.php';
if (true !== file_exists($translationFile)) {
$translationFile = 'app/messages/en.php';
}
require $translationFile;
$interpolator = new InterpolatorFactory();
$factory = new TranslateFactory($interpolator);
return $factory->newInstance(
'array',
[
'content' => $messages,
]
);
}
}
The getTranslator()
方法在控制器中对所有需要的操作可用。当然,您也可以引入一种缓存机制,将翻译适配器存储在缓存中(基于所选语言,例如传递en.cache
, de.cache
等等)。
The t
变量然后在视图中进行翻译。
对于 Volt:
占位符¶
The _()
方法将返回传递键的翻译字符串。在上面的例子中,它将返回存储在键hi
中的值。该组件还可以使用[插值][#interpolation]解析占位符。因此,对于以下翻译:
您需要在$name
调用中传递_()
变量,组件将为您执行替换。
<!-- welcome -->
<!-- String: hi-name => 'Hello %name%' -->
<p><?php echo $t->_('hi-name', ['name' => $name]); ?></p>
对于 Volt:
插件¶
上述实现可以扩展以在整个应用程序中提供翻译功能。当然,我们可以将方法移动到基础控制器并将其可见性更改为getTranslator()
method in a base controller and change its visibility to protected
。但是,我们可能希望在其他组件中使用翻译,这些组件不在控制器范围之外。
为了实现这一点,我们可以实现一个新组件作为插件并将其注册到我们的Di容器。
<?php
namespace MyApp;
use Phalcon\Di\Injectable;
use Phalcon\Translate\Adapter\NativeArray;
use Phalcon\Translate\InterpolatorFactory;
use Phalcon\Translate\TranslateFactory;
class Locale extends Injectable
{
/**
* @return NativeArray
*/
public function getTranslator(): NativeArray
{
// Ask the browser what is the best language
$language = $this->request->getBestLanguage();
$messages = [];
$translationFile = 'app/messages/' . $language . '.php';
if (true !== file_exists($translationFile)) {
$translationFile = 'app/messages/en.php';
}
require $translationFile;
$interpolator = new InterpolatorFactory();
$factory = new TranslateFactory($interpolator);
return $factory->newInstance(
'array',
[
'content' => $messages,
]
);
}
}
然后我们可以在引导程序设置服务期间将其注册到 Di 容器:
现在您可以从控制器和任何需要的地方访问Locale
插件。
<?php
use Phalcon\Mvc\Controller;
/**
* @property MyApp\Locale $locale
*/
class MyController extends Controller
{
public function indexAction()
{
$name = 'Mike';
$text = $this->locale->_(
'hi-name',
[
'name' => $name,
]
);
$this->view->text = $text;
}
}
或直接在视图中
对于 Volt:
路由¶
一些应用程序使用请求的 URL 根据不同的语言区分内容,以便帮助 SEO。示例 URL 是:```bash https://mozilla.org/es-ES/firefox/
Phalcon can implement this functionality by using a [Router][routing].
## Translate Factory
Loads Translate Adapter class using `adapter` option, the remaining options will be passed to the adapter constructor.
```php
<?php
use Phalcon\Translate\InterpolatorFactory;
use Phalcon\Translate\TranslateFactory;
$interpolator = new InterpolatorFactory();
$factory = new TranslateFactory($interpolator);
$options = [
'content' => [
'hi' => 'Hello',
'bye' => 'Good Bye',
],
];
$translator = $factory->newInstance('array', $options);
适配器¶
该组件使用适配器从不同源读取翻译消息,以统一方式实现。
适配器 | 描述 |
---|---|
Phalcon\Translate\Adapter\NativeArray | 使用 PHP 数组存储消息。 |
Phalcon\Translate\Adapter\Csv | 使用.csv 文件来存储语言的消息。 |
Phalcon\Translate\Adapter\Gettext | 使用 gettext 从.po 文件检索消息。 |
原生数组¶
此适配器将翻译后的字符串存储在 PHP 数组中。这个适配器显然是最快的,因为字符串存储在内存中。此外,它使用 PHP 数组的事实使得维护变得更加容易。字符串还可以存储在 JSON 文件中,当检索时可以转换回原生 PHP 数组格式。
<?php
use Phalcon\Translate\InterpolatorFactory;
use Phalcon\Translate\TranslateFactory;
$interpolator = new InterpolatorFactory();
$factory = new TranslateFactory($interpolator);
$options = [
'content' => [
'hi' => 'Hello',
'bye' => 'Good Bye',
],
];
$translator = $factory->newInstance('array', $options);
推荐的用法是为每种语言创建一个文件,并将其存储在文件系统中。之后,您可以根据所选语言加载相关文件。一个示例结构可以是:
或者以 JSON 格式每个文件包含 PHP 数组,其中键是翻译字符串的键,值是翻译后的消息。每个文件包含相同的键,但值当然是相应语言翻译后的消息。<?php
// app/messages/en.php
$messages = [
'hi' => 'Hello',
'bye' => 'Good Bye',
'hi-name' => 'Hello %name%',
'song' => 'This song is %song%',
];
<?php
// app/messages/fr.php
$messages = [
'hi' => 'Bonjour',
'bye' => 'Au revoir',
'hi-name' => 'Bonjour %name%',
'song' => 'La chanson est %song%',
];
<?php
use Phalcon\Translate\InterpolatorFactory;
use Phalcon\Translate\Adapter\NativeArray;
$interpolator = new InterpolatorFactory();
$options = [
'content' => [
'hi' => 'Hello',
'bye' => 'Good Bye',
],
];
$translator = new NativeArray($interpolator, $options);
未找到
如果省略了triggerError
被传递并设置为true
然后当找不到键时将调用notFound()
方法。该方法将触发错误。
<?php
use Phalcon\Translate\InterpolatorFactory;
use Phalcon\Translate\TranslateFactory;
$interpolator = new InterpolatorFactory();
$factory = new TranslateFactory($interpolator);
$options = [
'content' => [
'hi' => 'Hello',
'bye' => 'Good Bye',
],
'triggerError' => true,
];
$translator = $factory->newInstance('array', $options);
echo $translator->query('unknown');
上面的代码将在我们尝试访问unknown
条目时触发错误。
CSV¶
如果您的翻译字符串存储在.csv
文件中。该Phalcon\Translate\Adapter\Csv适配器接受插值器工厂和一个包含加载翻译所需选项的数组。选项数组接受:
选项 | 描述 |
---|---|
content | 文件系统上 CSV 文件的位置 |
delimiter | CSV 文件使用的分隔符(可选,默认为; ) |
enclosure | 包裹文本的字符(可选,默认为" ) |
<?php
use Phalcon\Translate\InterpolatorFactory;
use Phalcon\Translate\TranslateFactory;
$interpolator = new InterpolatorFactory();
$factory = new TranslateFactory($interpolator);
// `sample-key`|`sample-translated-text`
$options = [
'content' => '/path/to/translation-file.csv',
'delimiter' => '|',
'enclosure' => '`',
];
$translator = $factory->newInstance('csv', $options);
在上面的示例中,您可以看到delimiter
和enclosure
的使用。在大多数情况下,您不需要提供这些选项,但如果您的 CSV 文件有所不同,您可以选择指示适配器如何解析翻译文件的内容。
创建此适配器可以通过使用翻译工厂,但你可以直接实例化它:
<?php
use Phalcon\Translate\InterpolatorFactory;
use Phalcon\Translate\Adapter\Csv;
$interpolator = new InterpolatorFactory();
$options = [
'content' => '/path/to/translation-file.csv',
'delimiter' => '|',
'enclosure' => '`',
];
$translator = new Csv($interpolator, $options);
Gettext¶
注意
此适配器需要超全局变量。如果cookie存在于任一集合中,则返回gettextPHP 扩展。请确保您的系统已安装该扩展,以便您可以利用此适配器的功能。
The gettext格式已经存在多年,许多应用程序都在使用它,因为它已经成为标准,并且易于使用。翻译存储在.po
和.mo
文件中,内容可以轻松添加或更改,使用在线编辑器或工具如POEdit。此适配器要求文件位于特定文件夹中,以便它可以定位翻译文件。选项数组接受:
选项 | 描述 |
---|---|
locale | 你需要的语言环境 |
defaultDomain | 文件的域。这是文件的实际名称。两个po 和mo 文件必须具有相同的名称。 |
directory | 翻译文件所在的目录 |
category | A LC* PHP变量定义应使用什么类别。这映射到一个文件夹(如下所示的示例目录结构中看到)。 |
<?php
use Phalcon\Translate\InterpolatorFactory;
use Phalcon\Translate\TranslateFactory;
$interpolator = new InterpolatorFactory();
$factory = new TranslateFactory($interpolator);
$options = [
'locale' => 'de_DE.UTF-8',
'defaultDomain' => 'translations',
'directory' => '/path/to/application/locales',
'category' => LC_MESSAGES,
];
$translator = $factory->newInstance('gettext', $options);
翻译文件的一个示例目录结构是:
translations/
en_US.UTF-8/
LC_MESSAGES/
translations.mo
translations.po
de_DE.UTF-8
LC_MESSAGES/
translations.mo
translations.po
创建此适配器可以通过使用翻译工厂,但你可以直接实例化它:
<?php
use Phalcon\Translate\InterpolatorFactory;
use Phalcon\Translate\Adapter\Gettext;
$interpolator = new InterpolatorFactory();
$options = [
'locale' => 'de_DE.UTF-8',
'defaultDomain' => 'translations',
'directory' => '/path/to/application/locales',
'category' => LC_MESSAGES,
];
$translator = new Gettext($interpolator, $options);
自定义¶
The Phalcon\Translate\Adapter\AdapterInterface接口必须在创建自己的翻译适配器或扩展现有适配器时实现:
<?php
use Phalcon\Translate\Adapter\AdapterInterface;
class MyTranslateAdapter implements AdapterInterface
{
/**
* @param array $options
*/
public function __construct(array $options);
/**
* @param string $translateKey
* @param array $placeholders
*
* @return string
*/
public function t(string $translateKey, array $placeholders = []);
/**
* @param string $translateKey
* @param array $placeholders
*
* @return string
*/
public function _(
string $translateKey,
array $placeholders = []
): string;
/**
* @param string $index
* @param array $placeholders
*
* @return string
*/
public function query(string $index, array $placeholders = []): string;
/**
* @param string $index
* @return bool
*/
public function exists(string $index): bool;
}
这些组件有更多可用的适配器在Phalcon孵化器
插值¶
在许多情况下,翻译后的字符串需要带有数据。通过插值,你可以在特定位置将代码中的变量注入到翻译后的消息中。消息中的占位符用%
字符包围。
假设上下文不会根据每种语言的字符串而改变,你可以将这些占位符添加到翻译后的字符串中。翻译组件及其适配器将为你正确执行插值。
更改插值器¶
要更改适配器使用的插值器,你只需在选项中传递插值器的名称,使用defaultInterpolator
键。
<?php
use Phalcon\Translate\InterpolatorFactory;
use Phalcon\Translate\TranslateFactory;
$interpolator = new InterpolatorFactory();
$factory = new TranslateFactory($interpolator);
$options = [
'defaultInterpolator' => 'indexedArray',
'content' => [
'hi-name' => 'Hello %1$s, it\'s %2$d o\'clock',
],
];
$translator = $factory->newInstance('array', $options);
关联数组¶
Phalcon\Translate\Interpolator\AssociativeArray是默认的插值器。它允许你对占位符进行键/值替换。
<?php
use Phalcon\Translate\InterpolatorFactory;
use Phalcon\Translate\TranslateFactory;
$interpolator = new InterpolatorFactory();
$factory = new TranslateFactory($interpolator);
$options = [
'content' => [
'hi-name' => 'Hello %name%, good %time% !',
],
];
$translator = $factory->newInstance('array', $options);
$name = 'Henry';
$translator->_(
'hi-name',
[
'name' => $name,
'time' => 'day',
]
); // Hello Henry, good day!
$translator->_(
'hi-name',
[
'name' => $name,
'time' => 'night',
]
); // Hello Henry, good night!
索引数组¶
Phalcon\Translate\Interpolator\IndexedArray是你可以用作插值器的另一个选项。此插值器遵循sprintf约定。
<?php
use Phalcon\Translate\InterpolatorFactory;
use Phalcon\Translate\TranslateFactory;
$interpolator = new InterpolatorFactory();
$factory = new TranslateFactory($interpolator);
$options = [
'defaultInterpolator' => 'indexedArray',
'content' => [
'hi-name' => 'Hello %1$s, it\'s %2$d o\'clock',
],
];
$translator = $factory->newInstance('array', $options);
$name = 'Henry';
$translator->_(
'hi-name',
[
$name,
8,
]
); // Hello Henry, it's 8 o'clock
自定义插值器¶
The Phalcon\Translate\Interpolator\InterpolatorInterface接口必须在创建自己的插值器或扩展现有插值器时实现:
插值器工厂¶
The Phalcon\Translate\InterpolatorFactory工厂提供了一种简单的方式来创建插值器。它是必须传递给翻译适配器和翻译工厂的对象,以便它们可以创建适配器将使用的相关插值类。