hyperf 十四 国际化
一 安装
composer require hyperf/translation:v2.2.33
二 配置
1、设置语言文件
文件结构:
/storage/languages/en/messages.php
/storage/languages/zh_CH/messages.php
// storage/languages/en/messages.php
return ['welcome' => 'Welcome to our application :test :test2','test' => '{2} TEST1|[3,10] TEST2|[20,*] TEST3',
];// storage/languages/zh_CH/messages.php
return ['welcome' => '欢迎-使用 :test :test2',
];
2、设置配置文件
创建文件 /config/autoload/translation.php。
#/config/autoload/translation.php
return [// 默认语言'locale' => 'zh_CN',// 回退语言,当默认语言的语言文本没有提供时,就会使用回退语言的对应语言文本'fallback_locale' => 'en',// 语言文件存放的文件夹'path' => BASE_PATH . '/storage/languages',
];
三 使用
1、临时设置语言
// storage/languages/zh_CH/messages.php
return ['welcome' => '欢迎-使用',
];#/config/autoload/translation.php
return [// 默认语言'locale' => 'en',// 回退语言,当默认语言的语言文本没有提供时,就会使用回退语言的对应语言文本'fallback_locale' => 'en',// 语言文件存放的文件夹'path' => BASE_PATH . '/storage/languages',
];//App\Controller\TestController
use Hyperf\Di\Annotation\Inject;
use Hyperf\Contract\TranslatorInterface;class TestController
{/*** @Inject* @var TranslatorInterface*/private $translator;public function index(){$value = $this->translator->trans('messages.welcome', [], 'zh_CN');var_dump($value);}
}# 输出
string(26) "欢迎-使用"
2、全局函数
// storage/languages/zh_CH/messages.php
return ['welcome' => '欢迎-使用','test1' => '测试',
];// config/autoload/translation.php
return [// 默认语言'locale' => 'zn_CH',// 回退语言,当默认语言的语言文本没有提供时,就会使用回退语言的对应语言文本'fallback_locale' => 'en',// 语言文件存放的文件夹'path' => BASE_PATH . '/storage/languages',
];// App\Controller\TestController
class TestController
{/*** @Inject* @var TranslatorInterface*/private $translator;public function test2(){echo __('message.welcome') . "\n"; //欢迎-使用echo trans('message.welcome') . "\n";//欢迎-使用}
}
4、自定义占位符
// storage/languages/en/messages.php
return ['welcome' => 'Welcome to our application :test :test2',
];// config/autoload/translation.php
return [// 默认语言'locale' => 'en',// 回退语言,当默认语言的语言文本没有提供时,就会使用回退语言的对应语言文本'fallback_locale' => 'en',// 语言文件存放的文件夹'path' => BASE_PATH . '/storage/languages',
];// App\Controller\TestController
class TestController
{/*** @Inject* @var TranslatorInterface*/private $translator;public function test2(){echo __('message.welcome',['test'=>'qqq','test2':'aaa']) . "\n"; //Welcome to our application qqq aaaecho trans('message.welcome',['test'=>'qqq','test2':'aaa']) . "\n";//Welcome to our application qqq aaa}
}
5、复数处理
// storage/languages/en/messages.php
return ['test' => '{2} TEST1|[3,10] TEST2|[20,*] TEST3',
];// config/autoload/translation.php
return [// 默认语言'locale' => 'en',// 回退语言,当默认语言的语言文本没有提供时,就会使用回退语言的对应语言文本'fallback_locale' => 'en',// 语言文件存放的文件夹'path' => BASE_PATH . '/storage/languages',
];// App\Controller\TestController
class TestController
{/*** @Inject* @var TranslatorInterface*/private $translator;public function test2(){echo $this->translator->transChoice('message.test',0)."\n";echo trans_choice('message.test',0) . "\n"; echo trans_choice('message.test',2) . "\n"; echo trans_choice('message.test',4) . "\n";echo trans_choice('message.test',22) . "\n"; }
}//输出TEST1TEST1
TEST1
TEST2
TEST3
四 详解
1、调用
多语言的调用从注入开始,即Hyperf\Translation\Translator::__construct(TranslatorLoaderInterface $loader, string $locale)方法。根据配置文件TranslatorLoaderInterface 对应Hyperf\Translation\FileLoaderFactory类。读取配置文件/storage/languages/translation.path,并返回Hyperf\Translation\FileLoader类。即注入到Translator的构造的TranslatorLoaderInterface 实体类是FileLoader。
若无/storage/languages/translation.path配置文件,可使用默认配置vendor\hyperf\translation\publish\translation.php生成。
php bin/hyperf.php vendor:publish hyperf/translation
使用的语言标志比如en、zn_ch,在上下文中读取和设置。
Translator内调用顺序:
Translator::trans()->Translator::get()->Translator::getLine()->Translator::load()->FileLoader::load()
根据FileLoader::load()调用FileLoader::loadJsonPaths(),可以将不同语言的不同文件统一放到json文件中,使用FileLoader::addJsonPath()设置对应文件。会便利对应文件加载内容,就是对应语言的全部内容。
根据FileLoader::load()调用FileLoader::loadPath(),加载对应文件。比如翻译a.b,a是对应语言的组名,b对应是键名,文件是/storage/languages/对应语言/a.php。
根据FileLoader::load()调用FileLoader::loadNamespaced(),用命名空间加载。这里所谓命名空间就是,对比默认路径,设置一个键名对应非默认路径。也是调用loadPath()实现,不过传入非默认路径,用命名空间获取路径值,用FileLoader::addNamespace()设置命名空间和路径值。
Translator::trans()->Translator::get()->Translator::getLine()->Translator::makeReplacements()->sTranslator::ortReplacements()
根据Translator::ortReplacements(),查询字符串中":占位符"或":占位符全大写"或":占位符首字母大写"。
Translator::transChoice()->Translator::choice()->Translator::makeReplacements()->Translator::getSelector()->MessageSelector::choose()
Translator::choice()也调用Translator::get()但是中心加载了本地语言的标识。Translator::getSelector()将替换值作为数字,MessageSelector::choose()解析字符串、替换字符换中对应数字条件字符,并根据不同语言处理数字,返回最终结果。
全局函数在vendor\hyperf\translation\src\Function.php中,在其composer.json中自动加载。
2、源码
#Hyperf\Translation\Translator
class Translator implements TranslatorInterface
{public function __construct(TranslatorLoaderInterface $loader, string $locale){$this->loader = $loader;$this->locale = $locale;}public function trans(string $key, array $replace = [], ?string $locale = null){return $this->get($key, $replace, $locale);}public function transChoice(string $key, $number, array $replace = [], ?string $locale = null): string{return $this->choice($key, $number, $replace, $locale);}public function get(string $key, array $replace = [], ?string $locale = null, bool $fallback = true){[$namespace, $group, $item] = $this->parseKey($key);// Here we will get the locale that should be used for the language line. If one// was not passed, we will use the default locales which was given to us when// the translator was instantiated. Then, we can load the lines and return.$locales = $fallback ? $this->localeArray($locale): [$locale ?: $this->locale()];foreach ($locales as $locale) {if (!is_null($line = $this->getLine($namespace,$group,$locale,$item,$replace))) {break;}}// If the line doesn't exist, we will return back the key which was requested as// that will be quick to spot in the UI if language keys are wrong or missing// from the application's language files. Otherwise we can return the line.return $line ?? $key;}public function choice(string $key, $number, array $replace = [], ?string $locale = null): string{$line = $this->get($key,$replace,$locale = $this->localeForChoice($locale));// If the given "number" is actually an array or countable we will simply count the// number of elements in an instance. This allows developers to pass an array of// items without having to count it on their end first which gives bad syntax.if (is_array($number) || $number instanceof Countable) {$number = count($number);}$replace['count'] = $number;return $this->makeReplacements($this->getSelector()->choose($line, $number, $locale),$replace);}protected function localeForChoice(?string $locale): string{return $locale ?: $this->locale() ?: $this->fallback;}protected function getLine(string $namespace, string $group, string $locale, $item, array $replace){$this->load($namespace, $group, $locale);if (!is_null($item)) {$line = Arr::get($this->loaded[$namespace][$group][$locale], $item);} else {// do for hyperf Arr::get$line = $this->loaded[$namespace][$group][$locale];}if (is_string($line)) {return $this->makeReplacements($line, $replace);}if (is_array($line) && count($line) > 0) {foreach ($line as $key => $value) {$line[$key] = $this->makeReplacements($value, $replace);}return $line;}return null;}}#Hyperf\Translation\FileLoaderFactory
class FileLoaderFactory
{public function __invoke(ContainerInterface $container){$config = $container->get(ConfigInterface::class);$files = $container->get(Filesystem::class);$path = $config->get('translation.path', BASE_PATH . '/storage/languages');return make(FileLoader::class, compact('files', 'path'));}
}#Hyperf\Translation\FileLoader
class FileLoader implements TranslatorLoaderInterface
{public function __construct(Filesystem $files, string $path){$this->path = $path;$this->files = $files;}public function load(string $locale, string $group, ?string $namespace = null): array{if ($group === '*' && $namespace === '*') {return $this->loadJsonPaths($locale);}if (is_null($namespace) || $namespace === '*') {return $this->loadPath($this->path, $locale, $group);}return $this->loadNamespaced($locale, $group, $namespace);}public function addNamespace(string $namespace, string $hint){$this->hints[$namespace] = $hint;}public function addJsonPath(string $path){$this->jsonPaths[] = $path;}protected function loadNamespaced(string $locale, string $group, string $namespace): array{if (isset($this->hints[$namespace])) {$lines = $this->loadPath($this->hints[$namespace], $locale, $group);return $this->loadNamespaceOverrides($lines, $locale, $group, $namespace);}return [];}protected function loadPath(string $path, string $locale, string $group): array{if ($this->files->exists($full = "{$path}/{$locale}/{$group}.php")) {return $this->files->getRequire($full);}return [];}protected function loadJsonPaths(string $locale): iterable{return collect(array_merge($this->jsonPaths, [$this->path]))->reduce(function ($output, $path) use ($locale) {if ($this->files->exists($full = "{$path}/{$locale}.json")) {$decoded = json_decode($this->files->get($full), true);if (is_null($decoded) || json_last_error() !== JSON_ERROR_NONE) {throw new RuntimeException("Translation file [{$full}] contains an invalid JSON structure.");}$output = array_merge($output, $decoded);}return $output;}, []);}
}#Hyperf\Translation\MessageSelector
class MessageSelector
{
public function choose(string $line, $number, string $locale){$segments = explode('|', $line);if (($value = $this->extract($segments, $number)) !== null) {return trim($value);}$segments = $this->stripConditions($segments);$pluralIndex = $this->getPluralIndex($locale, $number);if (count($segments) === 1 || ! isset($segments[$pluralIndex])) {return $segments[0];}return $segments[$pluralIndex];}private function extract(array $segments, $number){foreach ($segments as $part) {if (! is_null($line = $this->extractFromString($part, $number))) {return $line;}}}
private function stripConditions(array $segments): array{return collect($segments)->map(function ($part) {return preg_replace('/^[\{\[]([^\[\]\{\}]*)[\}\]]/', '', $part);})->all();}
private function stripConditions(array $segments): array{return collect($segments)->map(function ($part) {return preg_replace('/^[\{\[]([^\[\]\{\}]*)[\}\]]/', '', $part);})->all();}
public function getPluralIndex(string $locale, int $number): int{switch ($locale) {……case 'en':……return ($number == 1) ? 0 : 1;}……}
}
#vendor\hyperf\translation\src\Function.php
if (! function_exists('__')) {function __(string $key, array $replace = [], ?string $locale = null){$translator = ApplicationContext::getContainer()->get(TranslatorInterface::class);return $translator->trans($key, $replace, $locale);}
}if (! function_exists('trans')) {function trans(string $key, array $replace = [], ?string $locale = null){return __($key, $replace, $locale);}
}if (! function_exists('trans_choice')) {function trans_choice(string $key, $number, array $replace = [], ?string $locale = null): string{$translator = ApplicationContext::getContainer()->get(TranslatorInterface::class);return $translator->transChoice($key, $number, $replace, $locale);}
}
相关文章:
hyperf 十四 国际化
一 安装 composer require hyperf/translation:v2.2.33 二 配置 1、设置语言文件 文件结构: /storage/languages/en/messages.php /storage/languages/zh_CH/messages.php // storage/languages/en/messages.php return [welcome > Welcome to our applicat…...
C语言_初识C语言指针
文章目录 前言一、指针 ... 一个内存单元多大比较合适?二、地址或者编号如何产生?三、指针变量的大小 前言 内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的。 所以为了有效的使用内存,就把内存划分成一个个…...
EMQX启用双向SSL/TLS安全连接以及java连接
作为基于现代密码学公钥算法的安全协议,TLS/SSL 能在计算机通讯网络上保证传输安全,EMQX 内置对 TLS/SSL 的支持,包括支持单/双向认证、X.509 证书、负载均衡 SSL 等多种安全认证。你可以为 EMQX 支持的所有协议启用 SSL/TLS,也可…...
4399面试总结C/C++游戏开发
主要流程 首先询问了C/C知识点 然后询问操作系统,计算机组成,数据结构,计算机网络哪两门熟悉 涉及的相关问题 多态的概念 tcp,udp? tcp,udp区别 tcp可靠,udp不可靠 tcp这个链接的过程? 一个TCP连接必须要经过三次“…...
hashlib 模块学习
hashlib 是 Python 标准库中用于散列和摘要算法的模块。散列算法将输入数据转换为固定长度的散列值(也称为摘要),并且对于相同的输入始终生成相同的散列值。这对于存储密码、数字签名、数据完整性验证等领域非常有用。以下是对 hashlib 模块的…...
大模型开发05:PDF 翻译工具开发实战
大模型开发实战05:PDF 翻译工具开发实战 PDF-Translator 机器翻译是最广泛和基础的 NLP 任务 PDF-Translator PDF 翻译器是一个使用 AI 大模型技术将英文 PDF 书籍翻译成中文的工具。这个工具使用了大型语言模型 (LLMs),如 ChatGLM 和 OpenAI 的 GPT-3 以及 GPT-3.5 Turbo 来…...
LeetCode 43题:字符串相乘
题目 给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。 注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。 示例 1: 输入: num1 "2", num2 "3&…...
基于java Swing 和 mysql实现的飞机订票系统(源码+数据库+ppt+ER图+流程图+架构说明+论文+运行视频指导)
一、项目简介 本项目是一套基于java Swing 和 mysql实现的飞机订票系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含:项目源码、项目文档、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过…...
Jmeter性能综合实战 —— 签到及批量签到
提取性能测试的三个方面:核心、高频、基础功能 签 到 请 求 步 骤 1、准备工作: 签到线程组n HTTP请求默认值n HTTP cookie 管理器n 首页访问请求n 登录请求n 查看结果树n 调试取样器l HTTP代理服务器 (1)创建线程组 …...
燃气管网监测系统,提升城市燃气安全防控能力
燃气是我们日常生活中不可或缺的能源,但其具有易燃易爆特性,燃气安全使用、泄漏监测尤为重要。当前全国燃气安全事故仍呈现多发频发态势,从公共安全的视角来看,燃气已成为城市安全的重大隐忧!因此,建立一个…...
【SQL】1731. 每位经理的下属员工数量 ( 新思想:确定左表,依次添加后续字段)
leetcode题目链接 注意点 确定左表(即,确定result表中的主键),依次添加后续字段。注意:主键可能是一个字段,也可能是多个字段COUNT(DISTINCT()),一般为了防止重复,使用COUNT计数时,…...
AMD Radeon RX 7000/6000系列显卡安装ROCm 调用CUDA
A卡用户画图炼丹、跑大模型甚至是跑机器学习、深度学习的有福了~ 注意:ROCm目前仅限在Linux系统下可用,Windows暂不支持 1. 安装ROCm RX6000系列及以下显卡使用ROCm 5.4.2稳定版本命令 【支持包括桌面级AMD Radeon RX6950XT、RX6900XT、RX6800XT、RX6…...
钉钉小程序引用阿里巴巴图标
2.打开的界面如图,先建一个iconfont.acss文件,全选浏览器打开的样式代码,复制粘贴进新建的iconfont.acss文件中 3.使用...
深入了解Nginx:高性能的开源Web服务器与反向代理
一、Nginx是什么 Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,也可以作为负载均衡器和HTTP缓存服务器使用。它采用事件驱动、异步非阻塞的处理方式,能够处理大量并发连接和高流量负载ÿ…...
vue3 自定义显示内容
vue3 自定义显示内容 vue3 自定义显示内容示例uni-app封装自定义内容组件 vue3 自定义显示内容 在 Vue 3 中,你可以通过插槽(Slot)来自定义组件的显示内容。 插槽允许你将额外的内容插入到组件的特定位置,从而实现更灵活的组件…...
视频行为分析——视频图像转换与ffmpeg相关操作
工具类说明 1. 图像视频转换 1.1 视频输出gif from moviepy.editor import VideoFileClip # 设置输入视频文件路径和输出GIF文件路径 input_video video.avi output_gif output.gif # 读取视频文件 video VideoFileClip(input_video) # 将视频保存为GIF文件 video.write_…...
Bean 生命周期
Bean 生命周期 一、Bean 实例化的基本流程 Spring容器在进行初始化时,会将xml配置的的信息封装成一个BeanDefifinition对象,所有的BeanDefifinition存储到一个名为beanDefifinitionMap的Map集合中去,Spring框架在对该Map进行遍历࿰…...
JavaScript原型链污染
前言 在浏览某个论坛的时候,第一次看到了JavaScript原型链污染漏洞。当时非常的好奇,当时我一直以为js作为一种前端语言,就算存在漏洞也是针对前端,不会危害到后端,因此我以为这种漏洞危害应该不大。可当我看到他的漏…...
【Java】设计模式之单例模式与工厂模式
1、设计模式概念及分类 简单来说设计模式是被广大程序员们总结并认可的编码套路,其中最常用的莫过于单例模式与工厂模式,而单例模式也有更加细的分类,一起来学习一下这些模式的用法和特点吧。 2、单例模式 一个类只能被实例化出来一个对象…...
web自动化框架:selenium学习使用操作大全(Python版)
目录 一、浏览器驱动下载二、selenium-python安装(打开网站、操作元素)三、网页解析(HTML、xpath)四、selenium基本操作1、元素定位八种方法2、元素动态定位3、iframe切换4、填充表单_填充文本框5、填充表单_单选按钮6、填充表单_…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制
目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...
零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...
