使 TranslateBehavior 和可翻译字符串同时工作

Make TranslateBehavior and translatable strings work at the same time

我想做的是,根据用户浏览器发送的Accept-Language,翻译代码内字符串(__('translatable string'))和我从[=配置的字段61=] 具有 TranslateBehavior.

已添加

DispatcherFactory::add('LocaleSelector', ['locales' => ['en_US', 'el_GR']]);

in bootstrap.php 以便使用用户浏览器发送的 Accept-Language 自动设置语言环境。这工作得很好,并将语言环境设置为 en_USel_GR.

我还设置了 i18n(在 http://book.cakephp.org/3.0/en/orm/behaviors/translate.html 之后),因为我希望我的 table 的某些字段是 translatable.

当然,我的代码中有一些字符串不是来自数据库,需要翻译。为此,我使用 __() 函数。

假设用户通过 Accept-Language 请求希腊语 (el_GR),则区域设置将设置为 el_GR。函数 __() 开箱即用,因为它正是它所需要的。

但是,TranslateBehavior 将不起作用,因为它需要 gre,而不是 el_GR

我怎样才能让这 2 个同时工作,而他们期望同一种语言有不同的语言环境值?

翻译行为不对语言环境标识符格式施加任何限制。可能的值仅受数据库列 type/length.

限制

因此,只需使用 en_USel_GR 作为您的翻译 table 记录,就可以了。

经过长时间的讨论和@ndm 的帮助,我采取了以下措施使其工作:

  1. 进行适当的更改后,彻底清除 tmp 目录并更新 composer。这解决了 LocaleSelector 在设置适当的语言环境时未翻译我的数据库的问题。

  2. 问题是 Accept-Language header 可以有很多值。您希望它们中的许多与特定的语言环境相匹配。这样您就可以对所有内容使用相同的语言环境,包括您的数据库和 translatable 字符串。为了解决这个问题,我自己做了一个LocaleSelectorFilter,我把它放在了src/Routing/Filter里面。它覆盖默认 LocaleSelectorFilter:

    命名空间Cake\Routing\Filter;

    使用Cake\Event\Event; 使用 Cake\I18n\I18n; 使用 Cake\Routing\DispatcherFilter; 使用语言环境;

    class LocaleSelectorFilter 扩展了 DispatcherFilter {

    protected $_locales = [];
    
    public function __construct($config = [])
    {
        parent::__construct($config);
        if (!empty($config['locales'])) {
            $this->_locales = $config['locales'];
        }
    }
    
    private function matchLocaleWithConfigValue($localeFromHeader)
    {
        foreach ($this->_locales as $locale => $acceptableValues) {
            // $acceptableValues is either an array or a single string
            if (!$locale) {
                // single string
                if ($localeFromHeader === $acceptableValues) {
                    return $acceptableValues;
                }
            } else {
                // array
                foreach ($acceptableValues as $acceptableValue) {
                    if ($localeFromHeader === $acceptableValue) {
                        return $locale;
                    }
                }
            }
        }
    
        return false;
    }
    
    public function beforeDispatch(Event $event)
    {
        $request = $event->data['request'];
        $locale = Locale::acceptFromHttp($request->header('Accept-Language'));
    
        if (!$locale) {
            // no locale set in the headers
            return;
        }
    
        if (empty($this->_locales)) {
            // any locale value allowed
            I18n::locale($locale);
            return;
        }
    
        // search whether the requested language is in the accepted ones
        $localeConfigMatch = $this->matchLocaleWithConfigValue($locale);
    
        if (!$localeConfigMatch) {
            // no locale matches the header, leave the default one
            return;
        }
    
        // match was found, switch locale
        I18n::locale($localeConfigMatch);
    }
    

    }

是这样使用的,里面bootstrap.php:

DispatcherFactory::add('LocaleSelector', ['locales' => ['el_GR' => ['el', 'el_GR', 'el-GR'], 'en_US']]);

在上面的示例中,Accept-Language 的所有值 elel_GRel-GR 将导致区域设置 el_GR 被设置。此外,如果 Accept-Language 具有 en_US 值,它将被设置。因此,它支持将许多不同的值设置为一个特定的语言环境,它还支持默认的 LocaleSelector 行为。

  1. 您的 i18n table 的区域设置列必须设置为 'el_GR'(在本例中)。这是必要的,因为它是 in-code translatable 字符串所期望的(使用 __() 函数的字符串)。因此,通过设置 'el_GR'(而不是文档中提到的 'gre'),您将得到 in-code translatable 字符串和数据库 translatable 字段盒子的。

就是这样!