Yii 2 —— 基于Mustache的页面多语言解决方案
admin
2023-01-27 13:40:51
0

在Yii 2中,官方的页面多语言解决方案有两个:

方案1,使用Yii::t()函数,在页面中需要输出文字的地方,使用类似如下代码:

这样做的后果是页面上大量充斥着类似的代码,导致页面可读性很差,而且对于同一个页面来说,Yii::t()函数的第一个参数基本上都是一样的,看到这些重复代码,也是心塞。我曾经在项目中采用这种方式实现多语言,一个简单的登录页面都能写到心烦的要命。

方案2,为指定语言做一个专门的视图,假设你有个页面是英文的,想再做个中文页面,可是中英文页面布局等相差很大,不是简单的翻译文字,那么在Yii 2中,可以在该页面的目录下,再建立一个zh-CN目录,然后在这个目录下建立一个同名的视图文件,页面内容用中文实现即可。这个我会专门再有文章说明如何实现。

如果中英文页面布局基本一样,只是文字有变化,那么建议还是不要用方案2了,宁可用方案1降低可读性,否则一旦页面内容有修改,两个页面之间的内容同步会搞到你怀疑人生。

总之,不管是方案1还是2,我都不喜欢,想要寻找一种简洁明了的页面多语言方案,页面看起来干净清爽,又不需要为每个语言做单独的页面。

那么怎样才能做到呢,我从Mustache中找到了实现的方案,假设下面是一个视图的代码:

{{基本信息}}

{{下载队列}} {{等待队列}}
{{已安装}} {{当前GameInfo}}
{{剩余电量}} {{是否允许OTA}}

如果把想要多语言显示的文字用Mustache的变量符号给括起来,然后假设上面的内容已经存到一个字符串$content里,那么在Action中,可以用Mustache将其输出为英文:

$content = $this->render('mypage', $params);
$m = new Mustache_Engine();
$content = $m->render($content, [
    '基本信息' => 'Base Information',
    '下载队列' => 'Downloading',
    '等待队列' => 'Waiting',
    '已安装' => 'Installed',
    '当前GameInfo' => 'GameInfo',
    '剩余电量' => 'Battery Level',
    '是否允许OTA' => 'Is can OTA',
]);

return $content;

这里的要点是先用Yii的render函数,得到要输出页面的字符串,然后使用Mustache,将指定的文字转换为英文,最后通过return输出。

上面这段代码就是使用Mustache实现页面多语言的核心思想,首先看页面的代码,完全没有任何PHP的代码,都是标准的HTML元素,页面看起来非常的干净清爽,前端开发人员可以直接用这个页面做前端的各种效果,完美实现前后端开发的解耦。

当然,上面展示的是核心的思想,但是要实际使用,还是需要进一步的完善。

首先,翻译的文字其实不适合放到Action的代码里,这样不好维护,应该按照Yii 2的设计思想,放到messages目录下,为指定语言建立messages文件,类似如下:

return [
    'device/views/deviceLog/mypage => [
        '基本信息' => 'Base Information',
        '下载队列' => 'Downloading',
        '等待队列' => 'Waiting',
        '已安装' => 'Installed',
        '当前GameInfo' => 'GameInfo',
        '剩余电量' => 'Battery Level',
        '是否允许OTA' => 'Is can OTA',
    ],
];

使用视图的路径作为键值,方便为每个页面确定翻译的内容。

其次,做一个自己的Controller的基类,重载render函数:

public function render($view, $params = [])
{
    $content = parent::render($view, $params);

    $path = $this->getViewPath() . '/' . $view;
    $list = EonI18nUtils::getMsgs($path);
    if (empty($list)) {
        return $content;
    }
    $m = new Mustache_Engine([
        'delimiters' => '## ##',
    ]);
    $content = $m->render($content, $list);

    return $content;
}

这里,先调用父类的render函数,得到正常输出的视图字符串,再调用EonI18nUtils::getMsgs(),根据视图文件的路径,得到该页面的多语言键值对,然后创建Mustache对象,将视图字符串中的指定键值修改为翻译后的文字。

为了保证页面上基于JavaScript的Mustache可以使用,这里将Mustache的键值标签由{{}}改为####,页面代码类似如下:

##基本信息##

##下载队列## {{downloading}} ##等待队列## {{waitting}}
##已安装## {{installed}} ##当前GameInfo## {{gameinfo}}
##剩余电量## {{battery_level}}% ##是否允许OTA## {{allowOTA}}

这样,上面代码中用##括起来的文字会被翻译,而用{{}}括起来的,则由页面上的JS代码使用Mustache方案替换文字。

EonI18nUtils::getMsgs()的参考代码如下:

public static function getMsgs($category, $lang = null)
{
    $category = str_replace('\\', '/', $category);
    $arr = explode("/", $category);
    $arr = array_slice($arr, count($arr) - 4);
    $category = implode("/", $arr);

    $messageSource = \Yii::$app->getI18n()->getMessageSource('messages');
    $list = $messageSource->getMsgList($category, $lang);
    return $list;
}

getMsgList()代码类似如下:

public function getMsgList($langPath, $language)
{
    $language = $this->getLanguage($language);
    if (!isset($this->_messages[$language])) {
        $this->_messages[$language] = $this->loadMessages('messages', $language);
    }
    if (isset($this->_messages[$language][$langPath])) {
        return $this->_messages[$language][$langPath];
    }
    return false;
}

相关内容

热门资讯

德国总理:美国正在被伊朗羞辱 德国之声4月27日报道,德国总理默茨在访问一所学校时表示,在当前的持续冲突中,伊朗领导层正试图羞辱美...
理响中国|“长”歌以行,风云激... 光阴如梭,东方潮阔。这里是中国的长三角,世界的长三角。无论过去、现在还是未来,这片土地都因时代而生,...
白宫:特朗普及其国安团队开会讨... 新华社华盛顿4月27日电 美国白宫新闻秘书莱维特27日在记者会上证实,总统特朗普及其国家安全团队当天...
人民日报刊文:日本放开杀伤性武... 日本放开杀伤性武器出口推高地缘冲突风险(国际论坛)常思纯《人民日报》(2026年04月28日 第 0...
医疗保障法草案二审:明确生育保... 满足多样化健康保障需求本报记者 彭 波4月27日,医疗保障法草案二审稿提请十四届全国人大常委会第二十...
天津一景区发生自转旋翼机事故1... 澎湃新闻记者 吕新文中国民用航空华北地区管理局4月22日公布《豪客通航“10•1”天津长芦汉盐旅游区...
卡塔尔埃米尔与美国总统特朗普通... 当地时间24日,卡塔尔埃米尔塔米姆与美国总统特朗普通电话,重点就中东地区局势以及伊朗与美国谈判问题交...
男子30年前被扣押2859克黄... 澎湃新闻记者 王鑫家住辽宁省大连市的潘永嘉近日向澎湃新闻反映称,三十年前,他在大连周水子机场被盖州市...
商务部:取消反制欧盟两家金融机... 中华人民共和国商务部令二〇二六年 第1号鉴于欧盟已取消对中国两家金融机构的制裁措施,现公布《关于取消...
过去24小时共有5艘船只通过霍... 总台记者当地时间24日获悉,过去24小时内,共有5艘船只通过霍尔木兹海峡,其中包括一艘伊朗油轮。(总...