跳转到内容

翻译组件


概览

该组件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变量然后在视图中进行翻译。

<!-- welcome -->
<!-- String: hi => 'Hello' -->
<p><?php echo $t->_('hi'), ' ', $name; ?></p>

对于 Volt:

<p>{{ t._('hi') }} {{ name }}</p>

占位符

The _()方法将返回传递键的翻译字符串。在上面的例子中,它将返回存储在键hi中的值。该组件还可以使用[插值][#interpolation]解析占位符。因此,对于以下翻译:

Hello %name%!

您需要在$name调用中传递_()变量,组件将为您执行替换。

<!-- welcome -->
<!-- String: hi-name => 'Hello %name%' -->
<p><?php echo $t->_('hi-name', ['name' => $name]); ?></p>

对于 Volt:

<p>{{ t._('hi-name', ['name' => name]) }}</p>

插件

上述实现可以扩展以在整个应用程序中提供翻译功能。当然,我们可以将方法移动到基础控制器并将其可见性更改为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 容器:

<?php

use MyApp\Locale;

$container->set('locale', (new Locale())->getTranslator());

现在您可以从控制器和任何需要的地方访问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;
    }
}

或直接在视图中

<?php echo $locale->_('hi-name', ['name' => 'Mike']);

对于 Volt:

<p>{{ locale._('hi-name', ['name' => 'Mike']) }}</p>

路由

一些应用程序使用请求的 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);

推荐的用法是为每种语言创建一个文件,并将其存储在文件系统中。之后,您可以根据所选语言加载相关文件。一个示例结构可以是:

app/messages/en.php
app/messages/es.php
app/messages/fr.php
app/messages/zh.php
或者以 JSON 格式
app/messages/en.json
app/messages/es.json
app/messages/fr.json
app/messages/zh.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%',
];
创建此适配器可以通过使用[Translate Factory][translate-factory]实现,但您也可以直接实例化它:
<?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);

在上面的示例中,您可以看到delimiterenclosure的使用。在大多数情况下,您不需要提供这些选项,但如果您的 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 文件的域。这是文件的实际名称。两个pomo文件必须具有相同的名称。
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孵化器

插值

在许多情况下,翻译后的字符串需要带有数据。通过插值,你可以在特定位置将代码中的变量注入到翻译后的消息中。消息中的占位符用%字符包围。

Hello %name, good %time%!
Salut %name%, bien %time%!

假设上下文不会根据每种语言的字符串而改变,你可以将这些占位符添加到翻译后的字符串中。翻译组件及其适配器将为你正确执行插值。

更改插值器

要更改适配器使用的插值器,你只需在选项中传递插值器的名称,使用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工厂提供了一种简单的方式来创建插值器。它是必须传递给翻译适配器和翻译工厂的对象,以便它们可以创建适配器将使用的相关插值类。

<?php

use Phalcon\Translate\InterpolatorFactory;
use Phalcon\Translate\TranslateFactory;

$interpolator = new InterpolatorFactory();
$factory      = new TranslateFactory($interpolator);

$translator = $factory->newInstance(
    'array',
    [
        'content' => [
            'hi'  => 'Hello',
            'bye' => 'Good Bye',
        ],
    ]
);
无噪 Logo
无噪文档
25 年 6 月翻译
文档源↗