Mar*_*łek 44 php routing localization laravel laravel-4
我想根据所选语言创建具有许多翻译路线的应用程序.我曾经用3种方法在多语言网站中创建URL来描述它.
在这种情况下,它应该是所提到主题的第一种方法,所以:
假设我已经设置默认语言pl
和其他2种语言en
和fr
.我只有3页 - 主页,联系页面和关于页面.
网站的网址应该是这样的:
/
/[about]
/[contact]
/en
/en/[about]
/en/[contact]
/fr
/fr/[about]
/fr/[contact]
Run Code Online (Sandbox Code Playgroud)
而[about]
和[contact]
应根据所选语言的翻译,例如英语应该留下contact
,但波兰应该kontakt
等等.
如何尽可能简单地完成?
Mar*_*łek 68
第一步:
转到app/lang
目录并在此处为每种语言的路线创建翻译.您需要创建3个routes.php
文件 - 每个文件位于不同的语言目录(pl/en/fr)中,因为您要使用3种语言
对于波兰语:
<?php
// app/lang/pl/routes.php
return array(
'contact' => 'kontakt',
'about' => 'o-nas'
);
Run Code Online (Sandbox Code Playgroud)
对于英语:
<?php
// app/lang/en/routes.php
return array(
'contact' => 'contact',
'about' => 'about-us'
);
Run Code Online (Sandbox Code Playgroud)
对于法语:
<?php
// app/lang/fr/routes.php
return array(
'contact' => 'contact-fr',
'about' => 'about-fr'
);
Run Code Online (Sandbox Code Playgroud)
第二步:
转到app/config/app.php
档案.
你应该找到一行:
'locale' => 'en',
Run Code Online (Sandbox Code Playgroud)
并将其更改为应该是您的主要网站语言的语言(在您的情况下为波兰语):
'locale' => 'pl',
Run Code Online (Sandbox Code Playgroud)
您还需要在此文件中添加以下行:
/**
* List of alternative languages (not including the one specified as 'locale')
*/
'alt_langs' => array ('en', 'fr'),
/**
* Prefix of selected locale - leave empty (set in runtime)
*/
'locale_prefix' => '',
Run Code Online (Sandbox Code Playgroud)
在alt_langs
配置设置可选的语言(在你的情况en
和fr
) -他们应该是一样的,从第一步骤中你的翻译创建的文件的文件名.
并且locale_prefix
是您的语言环境的前缀.您不需要默认语言环境的前缀,因此将其设置为空字符串.如果将选择除默认语言之外的其他语言,则将在运行时修改此配置.
第三步
转到您的app/routes.php
文件并放入他们的内容(这是app/routes.php
文件的全部内容):
<?php
// app/routes.php
/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the Closure to execute when that URI is requested.
|
*/
/*
* Set up locale and locale_prefix if other language is selected
*/
if (in_array(Request::segment(1), Config::get('app.alt_langs'))) {
App::setLocale(Request::segment(1));
Config::set('app.locale_prefix', Request::segment(1));
}
/*
* Set up route patterns - patterns will have to be the same as in translated route for current language
*/
foreach(Lang::get('routes') as $k => $v) {
Route::pattern($k, $v);
}
Route::group(array('prefix' => Config::get('app.locale_prefix')), function()
{
Route::get(
'/',
function () {
return "main page - ".App::getLocale();
}
);
Route::get(
'/{contact}/',
function () {
return "contact page ".App::getLocale();
}
);
Route::get(
'/{about}/',
function () {
return "about page ".App::getLocale();
}
);
});
Run Code Online (Sandbox Code Playgroud)
如您所见,首先检查url的第一段是否与您的语言名称匹配 - 如果是,则更改语言环境和当前语言前缀.
然后在微小的循环中,为所有路径名称设置要求(您提到了您想要的about
并contact
在URL中翻译),所以在此处将它们设置为与routes.php
当前语言的文件中定义的相同.
最后,您创建的路由组将具有与您的语言相同的前缀(对于默认语言,它将为空)和内部组,您只需创建路径但这些参数about
,contact
您可以variables
这样使用它们{about}
和{contact}
语法.
您需要记住,在这种情况下{contact}
,将检查所有路径是否与您在当前语言的第一步中定义的相同.如果您不想要这种效果,并且想要使用where手动为每条路线设置路线,那么app\routes.php
您可以设置不带环路的替代文件,contact
并about
为每条路线单独设置:
<?php
// app/routes.php
/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the Closure to execute when that URI is requested.
|
*/
/*
* Set up locale and locale_prefix if other language is selected
*/
if (in_array(Request::segment(1), Config::get('app.alt_langs'))) {
App::setLocale(Request::segment(1));
Config::set('app.locale_prefix', Request::segment(1));
}
Route::group(array('prefix' => Config::get('app.locale_prefix')), function()
{
Route::get(
'/',
function () {
return "main page - ".App::getLocale();
}
);
Route::get(
'/{contact}/',
function () {
return "contact page ".App::getLocale();
}
)->where('contact', Lang::get('routes.contact'));
Route::get(
'/{about}/',
function () {
return "about page ".App::getLocale();
}
)->where('about', Lang::get('routes.about'));
});
Run Code Online (Sandbox Code Playgroud)
第四步:
你没有提到它,但你可以考虑另外一件事.如果有人会使用url /en/something
哪里something
不正确Route,我认为是重定向的最佳解决方案.但你应该重定向,/
因为它是默认语言,但是/en
.
所以现在你可以打开app/start/global.php
文件并在这里为未知网址创建301重定向:
// app/start/global.php
App::missing(function()
{
return Redirect::to(Config::get('app.locale_prefix'),301);
});
Run Code Online (Sandbox Code Playgroud)
Pet*_*ter 22
什么马尔辛Nabiałek在他最初的回答为我们提供了一个坚实的解决路径定位问题.
小Bugbear:
他的解决方案唯一真正的缺点是我们不能使用缓存路由,根据Laravel's
文档,这有时会有很大的好处:
如果您的应用程序专门使用基于控制器的路由,则应该利用Laravel的路由缓存.使用路由缓存将大大减少注册所有应用程序路由所需的时间.在某些情况下,您的路线注册甚至可能会快100倍.要生成路由缓存,只需执行
route:cache
Artisan命令即可.
为什么我们不能缓存我们的路线?
因为MarcinNabiałek的方法基于locale_prefix
动态生成新路由,所以缓存它们会404
在访问缓存时访问未存储在locale_prefix
变量中的任何前缀时导致错误.
我们保留什么?
基础似乎非常坚实,我们可以保留它的大部分!
我们当然可以保留各种特定于本地化的路径文件:
<?php
// app/lang/pl/routes.php
return array(
'contact' => 'kontakt',
'about' => 'o-nas'
);
Run Code Online (Sandbox Code Playgroud)
我们还可以保留所有app/config/app.php
变量:
/**
* Default locale
*/
'locale' => 'pl'
/**
* List of alternative languages (not including the one specified as 'locale')
*/
'alt_langs' => array ('en', 'fr'),
/**
* Prefix of selected locale - leave empty (set in runtime)
*/
'locale_prefix' => '',
/**
* Let's also add a all_langs array
*/
'all_langs' => array ('en', 'fr', 'pl'),
Run Code Online (Sandbox Code Playgroud)
我们还需要一些检查路由段的代码.但是,由于这一点是利用缓存,我们需要将其移出routes.php
文件.一旦我们缓存路由,那个将不再使用.我们暂时可以将其移至app/Providers/AppServiceProver.php
例如:
public function boot(){
/*
* Set up locale and locale_prefix if other language is selected
*/
if (in_array(Request::segment(1), config('app.alt_langs'))) {
App::setLocale(Request::segment(1));
config([ 'app.locale_prefix' => Request::segment(1) ]);
}
}
Run Code Online (Sandbox Code Playgroud)
别忘了:
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\App;
Run Code Online (Sandbox Code Playgroud)
设置我们的路线:
我们的app/Http/routes.php
文件中会发生一些变化.
首先,我们必须创建一个包含所有alt_langs
以及默认值的新数组locale_prefix
,这很可能是''
:
$all_langs = config('app.all_langs');
Run Code Online (Sandbox Code Playgroud)
为了能够使用已转换的路由参数缓存所有各种lang前缀,我们需要将它们全部注册.我们怎么做?
*** Laravel aside 1: ***
我们来看看定义Lang::get(..)
:
public static function get($key, $replace = array(), $locale = null, $fallback = true){
return \Illuminate\Translation\Translator::get($key, $replace, $locale, $fallback);
}
Run Code Online (Sandbox Code Playgroud)
该函数的第三个参数是$locale
变量!太棒了 - 我们当然可以利用它!这个函数实际上让我们选择我们想要从哪个语言环境中获取翻译!
接下来我们要做的是迭代$all_langs
数组并Route
为每个语言前缀创建一个新组.不仅如此,我们还将摆脱我们之前需要的where
链条patterns
,并且只用正确的翻译注册路线(其他人将扔掉404
而不必再检查它):
/**
* Iterate over each language prefix
*/
foreach( $all_langs as $prefix ){
if ($prefix == 'pl') $prefix = '';
/**
* Register new route group with current prefix
*/
Route::group(['prefix' => $prefix], function() use ($prefix) {
// Now we need to make sure the default prefix points to default lang folder.
if ($prefix == '') $prefix = 'pl';
/**
* The following line will register:
*
* example.com/
* example.com/en/
*/
Route::get('/', 'MainController@getHome')->name('home');
/**
* The following line will register:
*
* example.com/kontakt
* example.com/en/contact
*/
Route::get(Lang::get('routes.contact',[], $prefix) , 'MainController@getContact')->name('contact');
/**
* “In another moment down went Alice after it, never once
* considering how in the world she was to get out again.”
*/
Route::group(['prefix' => 'admin', 'middleware' => 'admin'], function () use ($prefix){
/**
* The following line will register:
*
* example.com/admin/uzivatelia
* example.com/en/admin/users
*/
Route::get(Lang::get('routes.admin.users',[], $prefix), 'AdminController@getUsers')
->name('admin-users');
});
});
}
/**
* There might be routes that we want to exclude from our language setup.
* For example these pesky ajax routes! Well let's just move them out of the `foreach` loop.
* I will get back to this later.
*/
Route::group(['middleware' => 'ajax', 'prefix' => 'api'], function () {
/**
* This will only register example.com/api/login
*/
Route::post('login', 'AjaxController@login')->name('ajax-login');
});
Run Code Online (Sandbox Code Playgroud)
休斯顿,我们有一个问题!
正如你所看到的,我更喜欢使用命名路线(大多数人可能会这样做):
Route::get('/', 'MainController@getHome')->name('home');
Run Code Online (Sandbox Code Playgroud)
它们可以非常容易地在您的刀片模板中使用:
{{route('home')}}
Run Code Online (Sandbox Code Playgroud)
但到目前为止我的解决方案存在问题:路由名称相互覆盖.foreach
上面的循环只会注册带有名称的最后一个带前缀的路由.
换句话说,只会example.com/
绑定到home
路径,就像数组中locale_perfix
的最后一项一样$all_langs
.
我们可以通过在路径名前加上语言来解决这个问题$prefix
.例如:
Route::get('/', 'MainController@getHome')->name($prefix.'_home');
Run Code Online (Sandbox Code Playgroud)
我们必须为循环中的每个路由执行此操作.这造成了另一个小障碍.
但是我的大项目差不多完成了!
好吧,你可能已经猜到了,你现在必须回到你的所有文件,并route
使用locale_prefix
从app
配置加载的当前每个辅助函数调用前缀.
除了你没有!
*** Laravel aside 2: ***
让我们来看看Laravel如何实现它的route
辅助方法.
if (! function_exists('route')) {
/**
* Generate a URL to a named route.
*
* @param string $name
* @param array $parameters
* @param bool $absolute
* @return string
*/
function route($name, $parameters = [], $absolute = true)
{
return app('url')->route($name, $parameters, $absolute);
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,Laravel将首先检查route
功能是否已存在.route
只有当另一个不存在时,它才会注册它的功能!
这意味着我们可以非常轻松地解决我们的问题,而无需route
在Blade
模板中重写迄今为止所做的每一个调用.
让我们app/helpers.php
快速制作一个文件.
让我们确保Laravel在加载文件之前加载文件,方法helpers.php
是放入以下行bootstrap/autoload.php
//Put this line here
require __DIR__ . '/../app/helpers.php';
//Right before this original line
require __DIR__.'/../vendor/autoload.php';
Run Code Online (Sandbox Code Playgroud)
我们现在要做的就是route
在我们的app/helpers.php
文件中创建自己的函数.我们将使用原始实现作为基础:
<?php
//Same parameters and a new $lang parameter
use Illuminate\Support\Str;
function route($name, $parameters = [], $absolute = true, $lang = null)
{
/*
* Remember the ajax routes we wanted to exclude from our lang system?
* Check if the name provided to the function is the one you want to
* exclude. If it is we will just use the original implementation.
**/
if (Str::contains($name, ['ajax', 'autocomplete'])){
return app('url')->route($name, $parameters, $absolute);
}
//Check if $lang is valid and make a route to chosen lang
if ( $lang && in_array($lang, config('app.alt_langs')) ){
return app('url')->route($lang . '_' . $name, $parameters, $absolute);
}
/**
* For all other routes get the current locale_prefix and prefix the name.
*/
$locale_prefix = config('app.locale_prefix');
if ($locale_prefix == '') $locale_prefix = 'pl';
return app('url')->route($locale_prefix . '_' . $name, $parameters, $absolute);
}
Run Code Online (Sandbox Code Playgroud)
而已!
所以我们所做的基本上是注册所有可用的前缀组.创建了每个翻译的路线,并且其名称也带有前缀.然后排序重写的Laravel route
功能前缀与当前的所有路径名(除了一些),locale_prefix
从而使相应的网址在我们的刀片模板创建,而不必键入config('app.locale_prefix')
每一次.
哦耶:
php artisan route:cache
Run Code Online (Sandbox Code Playgroud)
只有在部署项目后才能真正完成缓存路由,因为在开发过程中很可能会弄乱它们.但您可以随时清除缓存:
php artisan route:clear
Run Code Online (Sandbox Code Playgroud)
再次感谢MarcinNabiałek的原始答案.这对我很有帮助.
小智 5
可以使用更简单的方法应用相同的结果..并不完美,但确实提供了快速且简单的解决方案。但是,在这种情况下,您必须编写每个路由,因此对于大型网站来说可能无法做到这一点。
Route::get('/contact-us', function () {
return view('contactus');
})->name('rte_contact'); // DEFAULT
Route::get('/contactez-nous', function () {
return view('contactus');
})->name('rte_contact_fr');
Run Code Online (Sandbox Code Playgroud)
只需在本地化文件中定义路由名称,如下所示:
# app/resources/lang/en.json
{ "rte_contact": "rte_contact" } //DEFAULT
// app/resources/lang/fr.json
{ "rte_contact": "rte_contact_fr" }
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用生成的区域设置变量在刀片模板中使用它们,如下所示:
<a class="nav-link" href="{{ route(__('rte_contact')) }}"> {{ __('nav_contact') }}</a>
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
43033 次 |
最近记录: |