akramzerarka/laravel-localization

为 Laravel 提供的简易本地化

1.6.1 2020-10-01 07:45 UTC

README

Join the chat at https://gitter.im/mcamara/laravel-localization

Latest Stable Version Total Downloads Build Status Open Source Helpers Reviewed by Hound

Laravel 的简易国际化本地化工具,一个与 Laravel 本地化类结合使用的有用工具。

该包提供以下功能

  • 从浏览器检测语言
  • 智能重定向(在会话/cookie 中保存区域设置)
  • 智能路由(只需定义一次路由,无论使用多少种语言)
  • 可翻译的路由
  • 支持缓存和测试
  • 可选隐藏默认语言在 URL 中
  • 许多代码片段和助手(如语言选择器)

目录

Laravel 兼容性

安装

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

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

配置文件

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

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

之后,将创建 config/laravellocalization.php

配置选项如下

  • supportedLocales 您应用的语言(默认:英语 & 西班牙语)。
  • useAcceptLanguageHeader 如果为 true,则自动从浏览器检测语言。
  • hideDefaultLocaleInURL 如果为 true,则不在 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
    ];
}

使用方法

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

// 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 中添加的所有区域(默认为 enes)。例如,上述路由文件创建以下地址

// 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(){ //...
});

建议

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

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

重定向中间件

以下重定向中间件依赖于在config/laravellocalization.php中设置的hideDefaultLocaleInURLuseAcceptLanguageHeader的配置。

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中保存了语言环境,则重定向到包含语言环境的URL,除非它是默认语言环境且hideDefaultLocaleInURL设置为true。

例如,如果用户导航到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() }}

获取当前语言环境本地名称

以字符串形式返回当前语言环境的本地名称(英语/西班牙语/阿拉伯语/等)。

{{ 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接受语言头正确分配所需的区域设置所必需的。以下是一个将HTTP接受语言头 '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是西班牙语的“文章”)将重定向到以下相同的控制器/视图

必须至少在您的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中的英文别名

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

可能具有翻译过的别名,例如这样

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

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

实现LocalizedUrlRoutable

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

路由模型绑定

要使用路由模型绑定,应该在模型中重写函数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内的操作路由进行本地化的情况下。这可能会导致重定向,然后改变POST请求为GET请求。为了防止这种情况,只需使用本地化辅助函数

例如,如果您使用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

如果您没有对POST URL进行本地化并使用重定向中间件,那么POST请求将被重定向为GET请求。如果您没有定义这样的GET路由,您将引发此异常。

要本地化您的POST URL,请参阅POST不工作中的示例。

验证消息仅在默认区域设置中

这也可能发生在您没有对POST URL进行本地化的情况下。如果您没有对POST URL进行本地化,则在验证时设置默认区域设置,当返回到back()时,它将显示默认区域的验证消息。

要本地化您的POST URL,请参阅POST不工作中的示例。

测试

在测试设置期间,被调用的路由尚未确定。这意味着无法设置任何语言。当在测试期间发起请求时,这会导致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

变更日志

在此查看变更日志 -> changelog

许可协议

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