movemoveapp/laravel-localization

支持通过域名切换本地化的Laravel本地化工具。

v1.7.2 2022-06-23 12:58 UTC

README

Build Status Latest Stable Version Total Downloads License

关于分支

此包是 mcamara/laravel-localization 的分支,支持通过域名切换本地化,例如:

  • exmaple.com - 英文版本
  • example.es - 西班牙语版本
  • example.ru - 俄语版本

或者

  • en.exmaple.com - 英文版本
  • es.example.com - 西班牙语版本
  • ru.example.com - 俄语版本

关于新特性,请参阅更多信息 通过域名切换本地化

简介

为Laravel提供简单的i18n本地化,是一个与Laravel本地化类结合使用的有用工具。

该包提供以下功能:

  • 从浏览器检测语言
  • 智能重定向(将地区保存到会话/cookie中)
  • 智能路由(只需定义一次路由,无论使用多少种语言)
  • 可翻译路由
  • 支持缓存和测试
  • 隐藏默认地区的URL选项
  • 许多片段和辅助工具(如语言选择器)
  • 域名之间的智能重定向

目录

Laravel兼容性

安装

通过composer安装包: composer require movemoveapp/laravel-localization

对于Laravel 5.4及以下版本,需要 注册服务提供者

配置文件

要编辑默认配置,您可以执行以下操作:

php artisan vendor:publish --provider="Mcamara\LaravelLocalization\LaravelLocalizationServiceProvider"

之后,将创建 config/laravellocalization.php 文件。

配置选项包括:

  • supportedLocales 应用的语言(默认:英语和西班牙语)以及本地化域名。
  • useAcceptLanguageHeader 如果为真,则自动从浏览器检测语言。
  • hideDefaultLocaleInURL 如果为真,则不在URL中显示默认地区。
  • localesOrder 按自定义顺序排序语言。
  • localesMapping 重命名URL地区。
  • utf8suffix 允许更改CentOS等的utf8suffix。
  • urlsIgnored 忽略特定URL。

注册中间件

您可以在 app/Http/Kernel.php 文件中注册包中间件

<?php namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel {
    /**
    * The application's route middleware.
    *
    * @var array
    */
    protected $routeMiddleware = [
        /**** OTHER MIDDLEWARE ****/
        'localize'                      => \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRoutes::class,
        'localizationRedirect'          => \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationRedirectFilter::class,
        'localeSessionRedirect'         => \Mcamara\LaravelLocalization\Middleware\LocaleSessionRedirect::class,
        'localeCookieRedirect'          => \Mcamara\LaravelLocalization\Middleware\LocaleCookieRedirect::class,
        'localeViewPath'                => \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationViewPath::class,
        /*** A new featrue with domain names ***/
        'localizationDomainRedirect'    => \Mcamara\LaravelLocalization\Middleware\LaravelLocalizationDomainRedirectFilter::class,
    ];
}

单域名使用

将以下内容添加到您的路由文件中

// routes/web.php

Route::group(['prefix' => LaravelLocalization::setLocale()], function()
{
	/** ADD ALL LOCALIZED ROUTES INSIDE THIS GROUP **/
	Route::get('/', function()
	{
		return View::make('hello');
	});

	Route::get('test',function(){
		return View::make('test');
	});
});

/** OTHER PAGES THAT SHOULD NOT BE LOCALIZED **/

一旦将此路由组添加到路由文件中,用户就可以访问在 supportedLocales 中添加的所有地区(默认为 enesru)。例如,上面的路由文件创建了以下地址

// Set application language to English
http://url-to-laravel/en
http://url-to-laravel/en/test

// Set application language to Spanish
http://url-to-laravel/es
http://url-to-laravel/es/test

// Set application language to English or Spanish (depending on browsers default locales)
// if nothing found set to default locale
http://url-to-laravel
http://url-to-laravel/test

该软件包根据您的URL设置您的应用程序区域设置App::getLocale()。然后,区域设置可以用于Laravel的区域设置功能

您可以将中间件添加到您的组中,如下所示

Route::group(
[
	'prefix' => LaravelLocalization::setLocale(),
	'middleware' => [ 'localeSessionRedirect', 'localizationRedirect', 'localeViewPath' ]
], function(){ //...
});

通过域名切换本地化

第一步,您应该设置域名。例如,您的项目支持三种区域设置

在您的.env配置文件中,您应该这样调用域名

LOCALIZATION_DOMAIN_NAME_EN=example.com
LOCALIZATION_DOMAIN_NAME_ES=example.es
LOCALIZATION_DOMAIN_NAME_RU=example.ru

不要忘记在config/laravellocalization.php配置文件中的supportedLocales中取消注释您的区域设置。

将以下内容添加到您的路由文件中

// routes/web.php

Route::group([
    'middleware' => [ 'localizationDomainRedirect' ]
], function()
{
	/** ADD ALL LOCALIZED ROUTES INSIDE THIS GROUP **/
	Route::get('/', function()
	{
		return View::make('hello');
	});

	Route::get('test',function(){
		return View::make('test');
	});
});

/** OTHER PAGES THAT SHOULD NOT BE LOCALIZED **/

例如,上面的路由文件创建了以下地址

// Set application language to English
https://example.com/
https://example.com/test

// Set application language to Spanish
https://example.es/
https://example.es/test

// Set application language to Russian
https://example.ru/
https://example.ru/test

域名.env属性

要为特定位置声明域名,您必须将变量声明为LOCALIZATION_DOMAIN_NAME_,并将位置转换为大写。如果位置包含破折号,则必须将其替换为下划线。

  • 区域设置en声明为LOCALIZATION_DOMAIN_NAME_EN
  • 区域设置uz-Arab声明为LOCALIZATION_DOMAIN_NAME_UZ_ARAB
  • 区域设置ca-valencia声明为LOCALIZATION_DOMAIN_NAME_CA_VALENCIA
  • 等等...

建议

1.强烈建议使用重定向中间件。没有区域设置的URL应仅用于确定浏览器/默认区域设置并重定向到本地化URL。否则,当搜索引擎机器人爬取例如http://url-to-laravel/test时,他们可能会在每次访问时获取不同语言的内容。此外,为相同的内容创建多个URL会创建SEO重复内容问题。

2.强烈建议即使使用重定向中间件,也要本地化您的链接。否则,每次用户点击链接时,至少会进行一次重定向。此外,任何来自帖子表单的动作URL都必须本地化,以防止它被重定向到GET请求。

重定向中间件

以下重定向中间件依赖于config/laravellocalization.phphideDefaultLocaleInURLuseAcceptLanguageHeader的设置

LocaleSessionRedirect

每当URL中存在区域设置时,该中间件就会将其存储在会话中。

如果没有在URL中找到区域设置,则此中间件将检查以下内容

  • 如果没有在会话中保存区域设置且useAcceptLanguageHeader设置为true,则从浏览器计算区域设置并重定向到包含区域设置的URL。
  • 如果会话中已保存区域设置,则重定向到包含区域设置的URL,除非它是默认区域设置且hideDefaultLocaleInURL设置为true。

例如,如果用户导航到http://url-to-laravel/test且当前区域设置为en,则它将自动将其重定向到http://url-to-laravel/en/test

LocaleCookieRedirect

类似于LocaleSessionRedirect,但它将值存储在cookie中而不是会话中。

只要URL中存在区域设置,此中间件就会将其存储在cookie中。

如果没有在URL中找到区域设置,则此中间件将检查以下内容

  • 如果没有在cookie中保存区域设置且useAcceptLanguageHeader设置为true,则从浏览器计算区域设置并重定向到包含区域设置的URL。
  • 如果cookie中已保存区域设置且它不是默认区域设置且hideDefaultLocaleInURL设置为true,则重定向到包含区域设置的URL。

例如,如果用户导航到http://url-to-laravel/test且当前区域设置为de,则它将自动将其重定向到http://url-to-laravel/de/test

LaravelLocalizationRedirectFilter

当默认地区存在于URL中,并且 hideDefaultLocaleInURL 设置为 true 时,中间件将重定向到不带地区的URL。

例如,如果 es 是默认地区,那么 http://url-to-laravel/es/test 将重定向到 http://url-to-laravel/test,并且 App::getLocale() 将设置为 es

辅助工具

此软件包附带一些辅助函数。

本地化URL

在生成本地化路由时,考虑了本地化URL的路线模型绑定,以及 hideDefaultLocaleInURL翻译路由 设置。

获取本地化URL

    // If current locale is Spanish, it returns `/es/test`
    <a href="{{ LaravelLocalization::localizeUrl('/test') }}">@lang('Follow this link')</a>

获取特定地区的本地化URL

获取特定地区的当前URL

// Returns current url with English locale.
{{ LaravelLocalization::getLocalizedURL('en') }}

获取清洁路由

返回任何本地化之外的URL。

// Returns /about
{{ LaravelLocalization::getNonLocalizedURL('/es/about') }}

获取特定翻译键的URL

返回一个路由,本地化 到所需地区。如果翻译键在给定的地区中不存在,此函数将返回 false。

// Returns /es/acerca
{{ LaravelLocalization::getURLFromRouteNameTranslated('es', 'routes.about') }}

获取支持的地区

返回所有支持的地区及其属性作为数组。

{{ LaravelLocalization::getSupportedLocales() }}

获取支持的地区自定义顺序

返回所有支持的地区,但按配置文件中指定的顺序。您可以使用此函数在语言选择器中打印地区。

{{ LaravelLocalization::getLocalesOrder() }}

获取支持的地区键

返回包含所有支持地区键的数组。

{{ LaravelLocalization::getSupportedLanguagesKeys() }}

获取当前地区

返回当前地区键。

{{ LaravelLocalization::getCurrentLocale() }}

获取当前地区名称

返回当前地区名称作为字符串(英语/西班牙语/阿拉伯语/等等)。

{{ LaravelLocalization::getCurrentLocaleName() }}

获取当前地区本地名称

返回当前地区本地名称作为字符串(英语/Español/عربى/等等)。

{{ LaravelLocalization::getCurrentLocaleNative() }}

获取当前地区方向

返回当前地区方向作为字符串(从左到右/ltr/从右到左/rtl)。

{{ LaravelLocalization::getCurrentLocaleDirection() }}

获取当前地区脚本

返回当前地区脚本的 ISO 15924 代码作为字符串;“Latn”,“Cyrl”,“Arab”等等。

{{ LaravelLocalization::getCurrentLocaleScript() }}

将视图基本路径设置为当前地区

注册中间件 LaravelLocalizationViewPath 以设置当前地区为视图基本路径。

现在您可以将视图包裹在基于语言的文件夹中,就像翻译文件一样。

resources/views/en/resources/views/fr,...

映射您自己的自定义语言URL段

您可以通过重命名键来修改支持的地区,因此可以使用字符串 uk 而不是 en-GB 来提供自定义语言URL段。当然,您需要防止与现有键的任何冲突,并尽可能遵守约定。但如果你使用这样的自定义键,你必须将你的映射存储在 localesMapping 数组中。此 localesMapping 是为了使语言协商者能够根据HTTP Accept Language Header正确分配所需地区。以下是一个快速示例,如何将HTTP Accept Language Header 'en-GB' 映射到URL段 'uk'

// config/laravellocalization.php

'localesMapping' => [
	'en-GB' => 'uk'
],

之后 http://url-to-laravel/en-GB/a/b/c 变为 http://url-to-laravel/uk/a/b/c

LaravelLocalization::getLocalizedURL('en-GB', 'a/b/c'); // http://url-to-laravel/uk/a/b/c
LaravelLocalization::getLocalizedURL('uk', 'a/b/c'); // http://url-to-laravel/uk/a/b/c

创建语言选择器

如果您在项目中支持多个地区,您可能希望为用户提供更改语言的方式。以下是一个简单的 blade 模板代码示例,您可以使用它来创建自己的语言选择器。

<ul>
    @foreach(LaravelLocalization::getSupportedLocales() as $localeCode => $properties)
        <li>
            <a rel="alternate" hreflang="{{ $localeCode }}" href="{{ LaravelLocalization::getLocalizedURL($localeCode, null, [], true) }}">
                {{ $properties['native'] }}
            </a>
        </li>
    @endforeach
</ul>

注意,这里默认语言将在 getLocalizedURL() 中强制存在于URL中,即使 hideDefaultLocaleInURL = true

注意,支持路线模型绑定。

已翻译路由

您可以翻译您的路由。例如,http://url/en/abouthttp://url/es/acerca(acerca 是西班牙语中的“关于”)或 http://url/en/article/important-articlehttp://url/es/articulo/important-article(article 在西班牙语中是 articulo)将重定向到相同的控制器/视图,如下所示

在您的 Route::group 中必须加载 localize 中间件(参见 安装说明)。

对于每种语言,将一个 routes.php 添加到 resources/lang/**/routes.php 文件夹中。该文件包含一个包含所有可翻译路由的数组。例如,如下所示

<?php
// resources/lang/en/routes.php
return [
    "about"    =>  "about",
    "article"  =>  "article/{article}",
];
<?php
// resources/lang/es/routes.php
return [
    "about"    =>  "acerca",
    "article"  =>  "articulo/{article}",
];

您可以在 routes/web.php 中添加路由,如下所示

Route::group(['prefix' => LaravelLocalization::setLocale(),
              'middleware' => [ 'localize' ]], function () {

    Route::get(LaravelLocalization::transRoute('routes.about'), function () {
        return view('about');
    });

    Route::get(LaravelLocalization::transRoute('routes.article'), function (\App\Article $article) {
        return $article;
    });

    //,...
});

保存文件后,您就可以无问题地访问 http://url/en/abouthttp://url/es/acercahttp://url/en/article/important-articlehttp://url/es/articulo/important-article

可翻译路由参数

也许您已经注意到了上一个例子中西班牙语 URL 中的英语 slug

http://url/es/articulo/important-article

可以拥有已翻译的 slug,例如这样

http://url/en/article/important-change
http://url/es/articulo/cambio-importante

但是,为了做到这一点,每篇文章都必须有多个 slug(每个区域一个)。这取决于您如何实现这种关系。可翻译路由参数的唯一要求是,相关的模型实现了接口 LocalizedUrlRoutable

实现 LocalizedUrlRoutable

要实现 \Mcamara\LaravelLocalization\Interfaces\LocalizedUrlRoutable,必须创建一个函数 getLocalizedRouteKey($locale),该函数必须返回给定区域的翻译 slug。在上面的例子中,在文章模型内部,getLocalizedRouteKey('en') 应该返回 important-change,而 getLocalizedRouteKey('es') 应该返回 cambio-importante

路由模型绑定

要使用 route-model-binding,应覆盖模型中的函数 resolveRouteBinding($slug)。该函数应返回属于翻译 slug $slug 的模型。例如

public function resolveRouteBinding($slug)
{
        return static::findByLocalizedSlug($slug)->first() ?? abort(404);
}

教程视频

您可以查看这个 视频,它展示了如何设置可翻译的路由参数。

事件

如果您希望翻译 URL 参数,可以在翻译过程中捕获它们。为此,只需为 routes.translation 事件创建一个事件监听器,如下所示

Event::listen('routes.translation', function($locale, $attributes)
{
	// Do your magic

	return $attributes;
});

请确保将区域和属性作为参数传递给闭包。您还可以使用事件订阅者,请参阅:https://laravel.net.cn/docs/events#event-subscribers

缓存路由

要缓存您的路由,请使用

php artisan route:trans:cache

... 而不是正常的 route:cache 命令。使用 artisan route:cache不会 正确工作!

要使路由缓存解决方案正常工作,需要对您的应用程序路由配置进行少量调整。

在您的 App 的 RouteServiceProvider 中,使用 LoadsTranslatedCachedRoutes 特性

<?php
class RouteServiceProvider extends ServiceProvider
{
    use \Mcamara\LaravelLocalization\Traits\LoadsTranslatedCachedRoutes;

有关更多详细信息,请参阅 此处

常见问题

POST请求不工作

这可能发生在您没有对位于您的 Routes::group 内部的操作路由进行本地化时。这可能导致重定向,然后将其转换为 GET 请求。为了防止这种情况,请简单地使用 localize 辅助函数

例如,如果您使用 Auth::routes() 并将它们放入您的 Route::group 中,那么

<form action="/logout" method="POST">
<button>Logout</button>
</form>

将不会工作。相反,必须使用

<form action="{{  \LaravelLocalization::localizeURL('/logout') }} " method="POST">
<button>Logout</button>
</form>

MethodNotAllowedHttpException

如果您没有本地化您的帖子 URL 并使用重定向中间件,则帖子请求将作为 GET 请求重定向。如果您没有定义此类 GET 路由,您将引发此异常。

要本地化您的帖子 URL,请参阅帖子不工作部分的示例。

验证消息仅在默认语言中

如果您没有本地化您的帖子 URL,也会发生这种情况。如果您不本地化帖子 URL,则在验证时设置默认语言,当返回到 back() 时将显示默认语言中的验证消息。

要本地化您的帖子 URL,请参阅帖子不工作部分的示例。

测试

在测试设置期间,尚未知道调用的路由。这意味着无法设置语言。在测试期间发起请求时,这会导致 404 - 没有设置前缀的本地化路由似乎不存在。

要修复此问题,您可以使用此函数手动设置语言前缀

// TestCase.php
protected function refreshApplicationWithLocale($locale)
{
    self::tearDown();
    putenv(LaravelLocalization::ENV_ROUTE_KEY . '=' . $locale);
    self::setUp();
}

protected function tearDown()
{
    putenv(LaravelLocalization::ENV_ROUTE_KEY);
    parent::tearDown();
}

// YourTest.php
public function testBasicTest()
{
    $this->refreshApplicationWithLocale('en');
    // Testing code
}

协作者

如果您想成为其中的一员,请询问 mcamara

变更日志

在此处查看变更日志 -> 变更日志

许可

Laravel Localization 是一个开源的 Laravel 包,许可协议为 MIT 协议