翻译组件¶
概览¶
该组件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工厂提供了一种简单的方式来创建插值器。它是必须传递给翻译适配器和翻译工厂的对象,以便它们可以创建适配器将使用的相关插值类。