hyperf 十四 国际化

这篇具有很好参考价值的文章主要介绍了hyperf 十四 国际化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

官方网址: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 aaa
        echo 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";  
    }
}

//输出
 TEST1
 TEST1
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中自动加载。文章来源地址https://www.toymoban.com/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);
    }
}

到了这里,关于hyperf 十四 国际化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 微信小程序国际化

    微信小程序国际化

    参考文件: 国际化(微信小程序+TS 微信小程序国际化 https://github.com/wechat-miniprogram/miniprogram-i18n 注意:一定要注意项目目录结构,新建文件夹miniprogram,并把前面新建的文件移到这个目录中 在NEW-FAN-CLOCK1 中安装根目录依赖 在NEW-FAN-CLOCK1 / minprogram 中安装依赖 1、初始化仓库: 一

    2023年04月26日
    浏览(12)
  • springcloud微服务国际化

    springcloud微服务国际化

    单体应用完成国际化还是比较简单的,可以看下面的示例代码。 引入必要的依赖 创建一个拦截器 创建一个配置类 然后在 resource 下创建 i18n 目录,选中右键 New = Resource Bundle 填入 base name ,选择 Project locales ,再 Add All ,确定即可。 打开配置文件,填写对应的中英文数据 配置

    2023年04月09日
    浏览(83)
  • vue2+element-ui使用vue-i18n进行国际化的多语言/国际化

    vue2+element-ui使用vue-i18n进行国际化的多语言/国际化

    注意:vue2.0要用8版本的,使用9版本的会报错 在src目录下,创建新的文件夹,命名为i18n zh.js en.js index.js main.js 使用方式一 效果图 使用方式二 效果图 使用方式三,在 效果图 ` 注意:这种方式存在更新this.$i18n.locale的值时无法自动切换的问题,需要刷新页面才能切换语言。解

    2024年02月07日
    浏览(14)
  • Spring MVC(三) 国际化

    随着全球化的加速发展,Web应用的多语言支持变得越来越重要。对于开发者来说,如何实现应用的国际化成为了一个不可忽视的问题。作为Java Web开发的重要框架,Spring MVC在处理国际化方面有着丰富的功能和灵活的解决方案。本文将探讨Spring MVC的国际化部分内容,并通过自己

    2024年01月18日
    浏览(9)
  • Spring Boot实现国际化

    config controller 在Thymeleaf模板中引用国际化消息:

    2024年01月23日
    浏览(13)
  • Flutter GetX 之 国际化

    今天给大家介绍一下 GetX 的国际化功能,在日常开发过程中,我们经常会使用到国际化功能,需要们的应用支持 国际化,例如我们需要支持 简体、繁体、英文等等。 上几篇文章介绍了GetX的 路由管理 和 状态管理,看到大家的点赞和收藏,还是很开心的,说明这两篇文章给大

    2024年01月19日
    浏览(20)
  • 如何优雅的实现前端国际化?

    如何优雅的实现前端国际化?

    JavaScript 中每个常见问题都有许多成熟的解决方案。当然,国际化 (i18n) 也不例外,有很多成熟的 JavaScript i18n 库可供选择,下面就来分享一些热门的前端国际化库! i18next 是一个用 JavaScript 编写的全面的国际化框架,提供标准的 i18n 功能,包括复数、上下文、插值、格式等。

    2024年01月23日
    浏览(19)
  • Android国际化各国语言简写

    2024年02月16日
    浏览(13)
  • 第七十一回:国际化设置

    我们在上一章回中介绍了Card Widget相关的内容,本章回中将介绍 国际化设置 .闲话休提,让我们一起Talk Flutter吧。 我们在这里说的国际化设置是指在App设置相关操作,这样可以让不同国家的用户使用App时呈现不同的语言。总之,就是通过相关的操作,让App支持多个国家的语言

    2024年02月11日
    浏览(52)
  • SpringBoot集成国际化多语言配置

    SpringBoot集成国际化多语言配置

    在当今全球化的环境下,为了更好地满足用户的多语言需求,越来越多的应用程序需要支持国际化多语言配置。Spring Boot作为一种快速开发框架,提供了方便的国际化支持,使得应用程序可以轻松地适应不同的语言环境。通过集成Spring Boot的国际化多语言配置,应用程序可以根

    2024年02月07日
    浏览(14)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包