关于hyperf:hyperf-框架完善之国际化多语言连载中

108次阅读

共计 5004 个字符,预计需要花费 13 分钟才能阅读完成。

转发自白狼栈:查看原文

明天咱们来看一下如何让 hyperf 反对国际化。

所谓的国际化就是多语言,比方后面抛出的异样信息“id 有效”,咱们心愿客户端抉择中文的时候提醒“id 有效”,抉择英文的时候提醒“id is invalid”,抉择日语的时候提醒“ID が無効です”等等,这里的国际化指的并不是全站内容的国际化,比方用户发问的问题内容。

首先多语言须要依赖 hyperf/translation 组件,容器内应用 composer 装置。

composer require hyperf/translation:3.0.*

生成 Translation 组件的配置文件 config/autoload/translation.php。

/data/project/questions # php bin/hyperf.php vendor:publish hyperf/translation
[DEBUG] Event Hyperf\Framework\Event\BootApplication handled by Hyperf\Config\Listener\RegisterPropertyHandlerListener listener.
[DEBUG] Event Hyperf\Framework\Event\BootApplication handled by Hyperf\ExceptionHandler\Listener\ExceptionHandlerListener listener.
[DEBUG] Event Hyperf\Framework\Event\BootApplication handled by Hyperf\DbConnection\Listener\RegisterConnectionResolverListener listener.
[hyperf/translation] publishes [config] successfully.

config/autoload/translation.php 内容如下:

<?php

declare(strict_types=1);

return [
    // 默认语言
    'locale' => 'zh_CN',
    // 回退语言,当默认语言的语言文本没有提供时,就会应用回退语言的对应语言文本
    'fallback_locale' => 'en',
    // 语言文件寄存的文件夹
    'path' => BASE_PATH . '/storage/languages',
];

其中 path 指的是语言文件寄存的门路,默认配置在 storage/languages 上面。

参考上面的命令,别离创立 3 个语言包目录并别离创立 3 个 params.php 文件。

/data/project/questions # mkdir -p storage/languages/en
/data/project/questions # mkdir -p storage/languages/zh_CN
/data/project/questions # mkdir -p storage/languages/ja
/data/project/questions # touch storage/languages/en/params.php
/data/project/questions # touch storage/languages/zh_CN/params.php
/data/project/questions # touch storage/languages/ja/params.php

params.php 内容别离如下:

storage/languages/en/params.php

<?php 
declare(strict_types=1);

return ['id_invalid' => 'id is invalid',];

storage/languages/ja/params.php

<?php
declare(strict_types=1);

return ['id_invalid' => 'ID が無効です',];

storage/languages/zh_CN/params.php

<?php
declare(strict_types=1);

return ['id_invalid' => 'id 有效',];

这 3 个文件别离示意对应 3 种语言,中文简体、英文和日语,前面如果咱们有新的货色要翻译,只须要参考 params.php 这样配置即可。

上面尝试翻译一下,IndexService::info 办法改写如下:

public function info(int $id)
{if ($id <= 0) {throw new BusinessException(trans('params.id_invalid'));
    }

    return ['info' => 'data info'];
}

之前写的“id 有效”曾经被咱们替换成 trans(‘params.id_invalid’) 了,其中 trans 是全局翻译函数,函数的第一个参数应用键(指应用翻译字符串作为键的键)或者是 文件. 键 的模式,这个很好了解。

curl 测试一下。

curl http://127.0.0.1:9501/index/info?id=0
{"code":0,"message":"id 有效"}%

这与咱们配置的默认语言(config/autoload/translation.php 内配置的 locale)相符。

然而,咱们要反对现 locale 追随客户端动静更新能力满足需要。

IndexService::info 更改如下:

public function info(int $id)
{if ($id <= 0) {$translator = ApplicationContext::getContainer()->get(TranslatorInterface::class);
        $translator->setLocale('ja');
        throw new BusinessException(trans('params.id_invalid'));
    }

    return ['info' => 'data info'];
}

IndexService::info 更改如下:

public function info(int $id)
{if ($id <= 0) {$translator = ApplicationContext::getContainer()->get(TranslatorInterface::class);
        $translator->setLocale('ja');
        throw new BusinessException(trans('params.id_invalid'));
    }

    return ['info' => 'data info'];
}

在这段代码中,咱们通过容器(Container)获取对象,容器取得的对象都是单例,也就是说在整个生命周期,通过容器取得的对象会更加高效,缩小了大量无意义的对象创立和销毁。

容器参考 https://hyperf.wiki/3.0/#/zh-…

此时咱们再试一下

curl http://127.0.0.1:9501/index/info?id=0
{"code":0,"message":"ID が無効です"}%

然而所有须要应用语言包的中央都要 setLocale 吗?天然有更好的解决方案。

引入中间价,全局解决这个问题。

中间件参考 https://hyperf.wiki/3.0/#/zh-…

中间件的生成能够在终端应用 php bin/hyperf.php gen:migration xxx 生成,hyperf 提供了 gen 系列的一堆命令,大家能够在控制台输出 php bin/hyperf.php 后回车查看 php bin/hyperf.php 所反对的所有命令,这里就不列举了。

咱们在终端输出下列命令,生成一个叫 GlobalMiddleware 的中间件。

/data/project/questions # php bin/hyperf.php  gen:middleware GlobalMiddleware

生成好的 GlobalMiddleware.php 位于 App\Middleware 目录,全局中间件还须要在 config/autoload/middlewares.php 文件内配置才会失效。

config/autoload/middlewares.php 配置如下:

<?php

declare(strict_types=1);

return [
    'http' => [\App\Middleware\GlobalMiddleware::class, // 全局中间件],
];

当初咱们把 IndexService::info 办法内 setLocale 的逻辑移到 App\Middleware\GlobalMiddleware::process 办法内试试。

App\Middleware\GlobalMiddleware::class 代码如下:

<?php

declare(strict_types=1);

namespace App\Middleware;

use Hyperf\Contract\TranslatorInterface;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

class GlobalMiddleware implements MiddlewareInterface
{
    /**
     * @var TranslatorInterface
     */
    protected $translator;

    public function __construct(ContainerInterface $container, TranslatorInterface $translator)
    {$this->translator = $translator;}

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {if ($lang = $request->getHeaderLine('lang')) {$this->translator->setLocale($lang);
        }
        
        return $handler->handle($request);
    }
}

中间价中接管来自申请头的 lang 参数来 setLocale,如此一来就实现了动静设置语言的性能。

curl 申请测试下

✗ curl http://127.0.0.1:9501/index/info?id=0 --header "lang:en"
{"code":0,"message":"id is invalid"}%
✗ curl http://127.0.0.1:9501/index/info?id=0 --header "lang:ja"
{"code":0,"message":"ID が無効です"}%
✗ curl http://127.0.0.1:9501/index/info?id=0 --header "lang:zh_CN"
{"code":0,"message":"id 有效"}%
✗ curl http://127.0.0.1:9501/index/info?id=0 --header "lang:abc"
{"code":0,"message":"id is invalid"}%

最初一个 “lang:abc” 是轻易输出的,即不存在的语言包时默认是以 translation.php 的 fallback_locale 配置为准。

到此,框架即轻松实现国际化多语言的性能了。

咱们自认为写的框架曾经十分完满了,拿去和客户端对接,客户端一来说就说你没发现问题吗,你 response 的 code 都是 0,我怎么辨别接口申请胜利还是失败?举个例子,id 有效的时候能不能给个 code = 100001 之类的,不便判断?

巴拉巴拉一堆,说的仿佛也有点情理。

下节课,咱们持续欠缺。

正文完
 0