Marcin Nabiałek在他最初的回答中为我们提供了一个坚实的解决方案,以解决路线本地化问题。
小虫熊:
他的解决方案唯一真正的缺点是我们不能使用缓存的路由,这有时可能会非常有益于文档:Laravel's
如果您的应用程序专门使用基于控制器的路由,则应利用 Laravel 的路由缓存。使用路由缓存将大大减少注册应用程序的所有路由所需的时间。在某些情况下,您的路线注册速度甚至可能提高100倍。要生成路由缓存,只需执行 Artisan 命令。route:cache
为什么我们不能缓存我们的路由?
由于 Marcin Nabiałek 的方法基于动态生成新路由,因此缓存它们将导致在缓存时访问变量中未存储的任何前缀时出错。locale_prefix
404
locale_prefix
我们保留什么?
基础似乎非常坚实,我们可以保留大部分!
我们当然可以保留各种特定于本地化的路由文件:
<?php
// app/lang/pl/routes.php
return array(
'contact' => 'kontakt',
'about' => 'o-nas'
);
我们还可以保留所有变量: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'),
我们还需要检查路由段的代码位。但是,由于这样做的目的是利用缓存,因此我们需要将其移动到文件之外。一旦我们缓存路由,将不再使用该路由。例如,我们可以暂时将其移动到: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) ]);
}
}
别忘了:
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\App;
设置我们的路线:
我们的文件中将发生一些更改。app/Http/routes.php
首先,我们必须使一个新数组包含所有以及默认值,这很可能是:alt_langs
locale_prefix
''
$all_langs = config('app.all_langs');
为了能够使用转换的路由参数缓存所有各种 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);
}
该函数的第三个参数是变量!太好了 - 我们当然可以利用这一点来发挥我们的优势!这个函数实际上让我们选择要从哪个区域设置获取翻译!$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');
});
休斯顿,我们有一个问题!
如您所见,我更喜欢使用命名路线(大多数人可能会这样做):
Route::get('/', 'MainController@getHome')->name('home');
它们可以在刀片模板中非常轻松地使用:
{{route('home')}}
但是到目前为止,我的解决方案存在一个问题:路由名称相互覆盖。上面的循环将仅使用其名称注册最后一个带前缀的路由。foreach
换句话说,只有像数组中的最后一项一样绑定到路由。example.com/
home
locale_perfix
$all_langs
我们可以通过在路由名称前面加上语言来解决此问题。例如:$prefix
Route::get('/', 'MainController@getHome')->name($prefix.'_home');
我们必须为循环中的每个路由执行此操作。这又造成了另一个小障碍。
但是我的大型项目几乎完成了!
正如您可能猜到的那样,您现在必须返回所有文件,并在每个帮助程序函数调用之前使用从配置加载的当前值作为前缀。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);
}
}
如您所见,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';
LARAVEL 7+ 更新
该文件不再存在,您必须在文件中添加上面的代码。bootstrap/autoload.php
public/index.php
我们现在要做的就是在文件中创建自己的函数。我们将使用原始实现作为基础: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);
}
就是这样!
因此,我们所做的基本上是注册了所有可用的前缀组。创建了每个已翻译的路由,并且其名称也带有前缀。然后覆盖Laravel函数,以在所有路由名称(某些路由名称除外)前面加上当前值,以便在我们的边栏选项卡模板中创建适当的URL,而无需每次都键入。route
locale_prefix
config('app.locale_prefix')
哦,是的:
php artisan route:cache
缓存路由应该只在部署项目后真正完成,因为在开发过程中可能会弄乱它们。但您始终可以清除缓存:
php artisan route:clear
再次感谢Marcin Nabiałek的原始答案。这对我真的很有帮助。