转发自WhiteWolfStack:查看原文今天我们就来看看如何让hyperf支持国际化。所谓国际化就是多语言。比如前面抛出的异常信息“id无效”,我们想让客户端在选择中文时提示“id无效”,在选择英文时提示“id无效”,在选择日语时提示“IDガ无效desu”等等,这里的国际化不是指整个站点内容的国际化,比如用户提问的内容。首先,多语言需要依赖hyperf/translation组件,在容器中使用composer安装。composerrequirehyperf/translation:3.0.*生成Translation组件的配置文件config/autoload/translation.php。/data/project/questions#phpbin/hyperf.phpvendor:publishhyperf/translation[DEBUG]事件Hyperf\Framework\Event\BootApplication由Hyperf\Config\Listener\RegisterPropertyHandlerListener监听器处理。[DEBUG]事件Hyperf\Framework\Event\BootApplicationhandledbyHyperf\ExceptionHandler\Listener\ExceptionHandlerListenerlistener.[DEBUG]EventHyperf\Framework\Event\BootApplicationhandleredbyHyperf\DbConnection\Listener\RegisterConnectionResolverListener监听器.[hyperf/translation]发布[config]toully/auconfig的内容translation.php如下:'zh_CN',//回退语言,当没有提供默认语言的语言文本时,返回将使用回退语言对应的语言文本'fallback_locale'=>'en',//存储语言文件的文件夹'path'=>BASE_PATH.'/存储/语言',];其中path是指语言文件存放的路径,默认配置在storage/languages下。参考以下命令分别创建3个语言包目录和3个params.php文件。/data/project/questions#mkdir-pstorage/languages/en/data/project/questions#mkdir-pstorage/languages/zh_CN/data/project/questions#mkdir-pstorage/languages/ja/data/project/questions#touchstorage/languages/en/params.php/data/project/questions#touchstorage/languages/zh_CN/params.php/data/project/questions#touchstorage/languages/ja/params.phpparams.php内容分别如下:storage/languages/en/params.php'idisinvalid',];storage/languages/ja/params.php'IDgainvaliddesu',];storage/languages/zh_CN/params.php'idinvalid',];这3个文件对应简体中文、英文、日文3种语言。如果后面有新的翻译,我们只需要参考params.php进行配置即可。我们试着翻译一下,IndexService::info方法重写如下:publicfunctioninfo(int$id){if($id<=0){thrownewBusinessException(trans('params.id_invalid'));}return['info'=>'datainfo'];}之前写的“idisinvalid”已经换成了trans('params.id_invalid'),其中trans是全局翻译函数,函数的第一个参数useskey(指使用翻译字符串作为key的key)或者以file.key的形式,这样比较容易理解。卷曲来测试它。curlhttp://127.0.0.1:9501/index/info?id=0{"code":0,"message":"idinvalid"}%这个和我们配置的默认语言一样(config/autoload/translation.php里面配置的locale)匹配。但是,我们需要支持当前的语言环境跟随客户端的动态更新来满足要求。IndexService::info更改如下:publicfunctioninfo(int$id){if($id<=0){$translator=ApplicationContext::getContainer()->get(TranslatorInterface::class);$translator->setLocale('ja');抛出新的BusinessException(trans('params.id_invalid'));}return['info'=>'datainfo'];}IndexService::info更改如下:publicfunctioninfo(int$id){if($id<=0){$translator=ApplicationContext::getContainer()->get(TranslatorInterface::class);$translator->setLocale('ja');抛出新的BusinessException(trans('params.id_invalid'));}return['info'=>'datainfo'];}在这段代码中,我们通过容器(Container)获取对象,容器获取的对象都是单例的,也就是说在整个生命周期中,通过容器获取的对象会更高效,减少很多无意义的对象创建和销毁。容器参考https://hyperf.wiki/3.0/#/zh-...现在让我们尝试curlhttp://127.0.0.1:9501/index/info?id=0{"code":0,"message":"IDgainvaliddesu"}%但是需要用到语言包的地方都需要setLocale吗?自然有更好的解决方案。引入中间价来在全球范围内解决这个问题。中间件参考https://hyperf.wiki/3.0/#/zh-...中间件生成可以在终端使用phpbin/hyperf.phpgen:migrationxxx生成,hyperf提供了gen系列的一堆命令,可以在控制台输入phpbin/hyperf.php回车查看phpbin/hyperf.php支持的所有命令,这里不一一列举。我们在终端中输入以下命令,生成一个名为GlobalMiddleware的中间件。/data/project/questions#phpbin/hyperf.phpgen:middlewareGlobalMiddleware生成的GlobalMiddleware.php位于App\Middleware目录下,全局中间件需要在config/autoload/middlewares.php文件中进行配置生效。config/autoload/middlewares.php配置如下:[\App\Middleware\GlobalMiddleware::class,//全局中间件],];现在我们把IndexService::info方法中的setLocale的逻辑移到App\Middleware\GlobalMiddleware::process方法中试试看。App\Middleware\GlobalMiddleware::class代码如下:translator=$translator;}publicfunctionprocess(ServerRequestInterface$request,RequestHandlerInterface$handler):ResponseInterface{if($lang=$request->getHeaderLine('lang')){$this->translator->setLocale($lang);}返回$handler->handle($request);}}从中间价格的请求头中接收lang参数给setLocale,从而实现语言的动态设置语言函数curl请求测试?curlhttp://127.0.0.1:9501/index/info?id=0--header"lang:en"{"code":0,"message":"idisinvalid"}%?curlhttp://127.0.0.1:9501/index/info?id=0--header"lang:ja"{"code":0,"message":"IDgainvaliddesu"}%?curlhttp://127.0.0.1:9501/index/info?id=0--header"lang:zh_CN"{"code":0,"message":"idinvalid"}%?curlhttp://127.0.0.1:9501/index/info?id=0--header"lang:abc"{"code":0,"message":"idisinvalid"}%最后一个"lang:abc"随便输入,即If没有语言包,默认以translation.php中的fallback_locale配置为准。至此,框架可以轻松实现国际化、多语言化的功能。我们认为我们写的框架是完美的,我们用它来连接客户端。客户端一说,就说你没发现什么问题。你的response的code全是0,怎么区分接口请求成功还是失败?比如id无效的时候,能不能给个code=100001之类的方便判断?一堆废话,说的好像也有道理。下一节课,我们会继续提高。
