deegitalbe/laravel-localization-extendable

为 Laravel 提供简单的本地化

v2.0.0 2023-08-11 13:31 UTC

This package is auto-updated.

Last update: 2024-09-05 21:11:31 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 允许更改 utf8suffix 以适应 CentOS 等。
  • 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. 强烈建议即使使用重定向中间件,也要 本地化链接。否则,每次用户点击链接时,至少会发生一次重定向。此外,任何来自表单的 action 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中保存了语言区域,则重定向到包含语言区域的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

在生成本地化路由时,考虑了路由模型绑定,以及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

返回任何本地化之外的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() }}

获取当前语言区域区域名称

以字符串形式返回当前语言区域的区域名称(en_GB/en_US/fr_FR/等等)。

{{ LaravelLocalization::getCurrentLocaleRegional() }}

获取当前语言区域方向

以字符串形式返回当前语言区域的文本方向(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是西班牙语中的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),该函数必须返回给定语言的翻译后的别名。在上面的示例中,在模型文章内部,getLocalizedRouteKey('en') 应返回 important-change,而 getLocalizedRouteKey('es') 应返回 cambio-importante

路由模型绑定

要使用 路由模型绑定,应在模型中重写函数 resolveRouteBinding($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>

另一种解决方法是,将 HTTP 方法配置到 'laravellocalization.httpMethodsIgnored' 中以防止处理此类请求

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(): void
{
    putenv(LaravelLocalization::ENV_ROUTE_KEY);
    parent::tearDown();
}

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

合作者

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

变更日志

在此查看更改日志 -> 更改日志

许可证

Laravel Localization 是一个开源的 Laravel 包,使用 MIT 许可证授权