官方網(wǎng)址:Hyperf
一 安裝
composer require hyperf/translation:v2.2.33
二 配置
1、設(shè)置語言文件
文件結(jié)構(gòu):
????????/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、設(shè)置配置文件
創(chuàng)建文件 /config/autoload/translation.php。
#/config/autoload/translation.php
return [
// 默認(rèn)語言
'locale' => 'zh_CN',
// 回退語言,當(dāng)默認(rèn)語言的語言文本沒有提供時,就會使用回退語言的對應(yīng)語言文本
'fallback_locale' => 'en',
// 語言文件存放的文件夾
'path' => BASE_PATH . '/storage/languages',
];
三 使用
1、臨時設(shè)置語言
// storage/languages/zh_CH/messages.php
return [
'welcome' => '歡迎-使用',
];
#/config/autoload/translation.php
return [
// 默認(rèn)語言
'locale' => 'en',
// 回退語言,當(dāng)默認(rèn)語言的語言文本沒有提供時,就會使用回退語言的對應(yīng)語言文本
'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、全局函數(shù)
// storage/languages/zh_CH/messages.php
return [
'welcome' => '歡迎-使用',
'test1' => '測試',
];
// config/autoload/translation.php
return [
// 默認(rèn)語言
'locale' => 'zn_CH',
// 回退語言,當(dāng)默認(rèn)語言的語言文本沒有提供時,就會使用回退語言的對應(yīng)語言文本
'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 [
// 默認(rèn)語言
'locale' => 'en',
// 回退語言,當(dāng)默認(rèn)語言的語言文本沒有提供時,就會使用回退語言的對應(yīng)語言文本
'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 aaa
echo trans('message.welcome',['test'=>'qqq','test2':'aaa']) . "\n";
//Welcome to our application qqq aaa
}
}
5、復(fù)數(shù)處理
// storage/languages/en/messages.php
return [
'test' => '{2} TEST1|[3,10] TEST2|[20,*] TEST3',
];
// config/autoload/translation.php
return [
// 默認(rèn)語言
'locale' => 'en',
// 回退語言,當(dāng)默認(rèn)語言的語言文本沒有提供時,就會使用回退語言的對應(yīng)語言文本
'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";
}
}
//輸出
TEST1
TEST1
TEST1
TEST2
TEST3
四 詳解
1、調(diào)用
多語言的調(diào)用從注入開始,即Hyperf\Translation\Translator::__construct(TranslatorLoaderInterface $loader, string $locale)方法。根據(jù)配置文件TranslatorLoaderInterface 對應(yīng)Hyperf\Translation\FileLoaderFactory類。讀取配置文件/storage/languages/translation.path,并返回Hyperf\Translation\FileLoader類。即注入到Translator的構(gòu)造的TranslatorLoaderInterface 實(shí)體類是FileLoader。
若無/storage/languages/translation.path配置文件,可使用默認(rèn)配置vendor\hyperf\translation\publish\translation.php生成。
php bin/hyperf.php vendor:publish hyperf/translation
使用的語言標(biāo)志比如en、zn_ch,在上下文中讀取和設(shè)置。
Translator內(nèi)調(diào)用順序:
Translator::trans()->Translator::get()->Translator::getLine()->Translator::load()->FileLoader::load()
根據(jù)FileLoader::load()調(diào)用FileLoader::loadJsonPaths(),可以將不同語言的不同文件統(tǒng)一放到j(luò)son文件中,使用FileLoader::addJsonPath()設(shè)置對應(yīng)文件。會便利對應(yīng)文件加載內(nèi)容,就是對應(yīng)語言的全部內(nèi)容。
根據(jù)FileLoader::load()調(diào)用FileLoader::loadPath(),加載對應(yīng)文件。比如翻譯a.b,a是對應(yīng)語言的組名,b對應(yīng)是鍵名,文件是/storage/languages/對應(yīng)語言/a.php。
根據(jù)FileLoader::load()調(diào)用FileLoader::loadNamespaced(),用命名空間加載。這里所謂命名空間就是,對比默認(rèn)路徑,設(shè)置一個鍵名對應(yīng)非默認(rèn)路徑。也是調(diào)用loadPath()實(shí)現(xiàn),不過傳入非默認(rèn)路徑,用命名空間獲取路徑值,用FileLoader::addNamespace()設(shè)置命名空間和路徑值。
Translator::trans()->Translator::get()->Translator::getLine()->Translator::makeReplacements()->sTranslator::ortReplacements()
根據(jù)Translator::ortReplacements(),查詢字符串中":占位符"或":占位符全大寫"或":占位符首字母大寫"。
Translator::transChoice()->Translator::choice()->Translator::makeReplacements()->Translator::getSelector()->MessageSelector::choose()
Translator::choice()也調(diào)用Translator::get()但是中心加載了本地語言的標(biāo)識。Translator::getSelector()將替換值作為數(shù)字,MessageSelector::choose()解析字符串、替換字符換中對應(yīng)數(shù)字條件字符,并根據(jù)不同語言處理數(shù)字,返回最終結(jié)果。文章來源:http://www.zghlxwxcb.cn/news/detail-681353.html
全局函數(shù)在vendor\hyperf\translation\src\Function.php中,在其composer.json中自動加載。文章來源地址http://www.zghlxwxcb.cn/news/detail-681353.html
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);
}
}
到了這里,關(guān)于hyperf 十四 國際化的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!