I have a Laravel app in 9 difference languages:
/resources
-- /lang
-- -- /en_US.json
-- -- /fr_FR.json
-- -- /...
I'm trying to set up localized URL's like:
Route::get(__("link.projects"), 'GuestController#projects');
All content on the website is displayed in the correct language but routing returns 404 pages except for default fallback language.
My web.php
Route::group(['middleware' => ['web', 'locale']], function () {
/* GUEST */
Route::get('/', 'GuestController#index');
Route::get(__("link.projects"), 'GuestController#projects');
Route::get(__("link.participants"), 'GuestController#participants');
Route::get(__("link.participant")."/{public_id}", 'GuestController#participant');
Route::get(__("link.about"), 'GuestController#about');
Route::get(__("link.contact"), 'GuestController#contact');
});
My locale middleware:
<?php
namespace App\Http\Middleware;
use Closure;
class SetLocale
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if($request->getHost() == "domain.com") {
$locale = 'en_US';
} elseif($request->getHost() == "domain.dk") {
$locale = 'da_DK';
} elseif($request->getHost() == "domain.de") {
$locale = 'de_DE';
} elseif($request->getHost() == "domain.se") {
$locale = 'sv_SE';
} elseif($request->getHost() == "domain.fi") {
$locale = 'fi_FI';
} elseif($request->getHost() == "domain.es") {
$locale = 'es_ES';
} elseif($request->getHost() == "domain.fr") {
$locale = 'fr_FR';
} elseif($request->getHost() == "domain.it") {
$locale = 'it_IT';
} elseif($request->getHost() == "domain.nl") {
$locale = 'nl_NL';
} else {
$locale = 'en_US';
}
if (in_array($locale, [
"en_US",
"da_DK",
"de_DE",
"sv_SE",
"fi_FI",
"es_ES",
"fr_FR",
"it_IT",
"nl_NL"
]
)) {
session()->put('locale', $locale);
} else {
session()->put('locale', 'en_US');
}
if(session()->has('locale')) {
app()->setLocale(session('locale'));
}
return $next($request);
}
}
Using the fallback language URLs in production i'm able to get the content localized but URL's in the web.php won't allow translation.
I don't want to have prefix in URL's since the different locales are set by domain instead.
Okay so i took a small break and figured out a possible solution which seems to be working perfectly.
$locales = array("en_US","de_DE","es_ES","it_IT","fr_FR","da_DK","sv_SE","fi_FI","nl_NL");
foreach($locales as $locale) {
/* GUEST */
Route::get(__("link.projects", [], $locale), 'GuestController#projects');
Route::get(__("link.participants", [], $locale), 'GuestController#participants');
Route::get(__("link.participant", [], $locale)."/{public_id}", 'GuestController#participant');
Route::get(__("link.about", [], $locale), 'GuestController#about');
Route::get(__("link.contact", [], $locale), 'GuestController#contact');
Route::get(__("link.cookies", [], $locale), 'GuestController#cookies');
Route::get(__("link.terms_of_use", [], $locale), 'GuestController#terms_of_use');
Route::get(__("link.privacy_policy", [], $locale), 'GuestController#privacy_policy');
Route::get(__("link.disclaimer", [], $locale), 'GuestController#disclaimer');
}
Let me know if this has any potential breaks, but for me it's working.
The way I handle this is to use two routes, one for the home page (which generally contains more complex logic like news, pick up articles, banners, etc), and a catch all for any other page.
Routes
// Home page
Route::get('/', [
'as' => 'home',
'uses' => 'PageController#index'
]);
// Catch all page controller (place at the very bottom)
Route::get('{slug}', [
'uses' => 'PageController#getPage'
])->where('slug', '([A-Za-z0-9\-\/]+)');
The important part to note in the above is the ->where() method chained on the end of the route. This allows you to declare regex pattern matching for the route parameters. In this case I am allowing alphanumeric characters, hyphens and forward slashes for the {slug} parameter.
This will match slugs like
test-page
test-page/sub-page
another-page/sub-page
you can set your own pattern.
I think i found a perfect solution for you.
After a quick google search I found the following:
Check it out!
https://github.com/codezero-be/laravel-localized-routes
Related
I managed to get some routes working with and without a prefix. Having routes that do not have the prefix work properly is important as it's too much work to go back and change all get/post links to the correct localized ones.
For example with the code below the URL localhost/blog redirects to localhost/en/blog (or any other language stored in session).
However, I noticed that URLs with parameters don't work, so /blog/read/article-name will result in a 404 instead of redirecting to /en/blog/read/article-name.
Routes:
Route::group([
'prefix' => '{locale}',
'middleware' => 'locale'],
function() {
Route::get('blog', 'BlogController#index');
Route::get('blog/read/{article_permalink}', 'BlogController#view');
}
);
Middleware is responsible for the redirects which don't seem to fire at all for some routes as if the route group isn't matching the URL.
public function handle($request, Closure $next)
{
if ($request->method() === 'GET') {
$segment = $request->segment(1);
if (!in_array($segment, config('app.locales'))) {
$segments = $request->segments();
$fallback = session('locale') ?: config('app.fallback_locale');
$segments = array_prepend($segments, $fallback);
return redirect()->to(implode('/', $segments));
}
session(['locale' => $segment]);
app()->setLocale($segment);
}
return $next($request);
}
Currently, my system is using 2 languages which is English and German. my goal is to browse following routes by switching between the mentioned language -
base-url/contact - for english
base-url/kontakte - for german
Currently, I have required routes file in the resource folder, where I have put the necessary translated words.
resources/lang/en/routes.php
resources/lang/de/routes.php
In web.php I have currently -
Route::get(r('contact'), 'TestController#index')->name('contact');
by r() helper function I am getting the active translated word.
On my user table, I have locale column where I am storing the active language when I am updating the language from user profile -
\Session::put('locale', $request->input('locale'));
I have created a middleware Localization where I have currently -
public function handle($request, Closure $next)
{
if ( \Session::has('locale')) {
\App::setLocale(\Session::get('locale'));
Carbon::setLocale(\Session::get('locale'));
}
return $next($request);
}
Currently, the code is working fine for blade translated word. but the translated routes are not working. whenever I switch and visit any route, it gives me 404 error. but if I restart the server by PHP artisan serve, it works with changed language.
So how fix the issue?
:) Try to put \App::setLocale(\Session::get('locale') in the beginning of the routes file (routes.php, or web.php/api.php)
With PHP 8.1.0, Laravel 9.x
resources/lang/en/routes.php:
return [
'post' => '/post/',
'product' => '/product/',
'contact' => '/contact/',
'aboutUs' => '/about-us/'
];
Create LanguageType enum:
enum LanguageType: string
{
case EN = 'en';
case DE = 'de';
public function label(): string
{
return trans(match ($this) {
self::EN => 'English',
self::DE => 'German',
});
}
}
In web.php:
Route::get('{contactTranslation}', [ContactController::class, 'index']);
Route::get('{aboutUsTranslation}', [AboutUsController::class, 'index']);
Route::get('{productTranslation}', [ProductController::class, 'index']);
Route::get('{postTranslation}', [PostController::class, 'index']);
//...
In RouteServiceProvider.php/boot(), add:
foreach (trans('routes') as $key => $value) {
Route::pattern($key . 'Translation', $this->getTranslation($key));
}
And function:
private function getTranslation($slug): string
{
$slugList = collect();
foreach (LanguageType::cases() as $language) {
$slugList = $slugList->merge(trim(trans('routes.' . $slug, [], $language->value), '/'));
}
return $slugList->implode('|');
}
I have a simple routing setup to address different languages. The goal is to have the language as a first parameter in the url like /en/docs or /de/docs. The language definitions are set as scopes as show below:
$builder = function ($routes)
{
$routes->connect('/:controller', ['action' => 'index']);
$routes->connect('/:controller/:action/*', ['action' => 'index']);
};
$languages = ['en', 'de'];
foreach ($languages as $lang) {
Router::scope('/'.$lang, ['language' => $lang], $builder);
}
Router::addUrlFilter(function ($params, $request) {
if ($request->param('language')) {
$params['language'] = $request->param('language');
}
else {
$params['language'] = 'en';
}
return $params;
});
Each of the scopes is working as expected. Even with some more complex connects and prefixes (I removed them from the code above to make the code more readable).
The problem is now: how to create a link to switch between the languages (scopes)?
I tried different urls, but depending on the current url (e.g. /de/docs), the language parameter does not have any effect on the created urls:
Router::url(['language' => 'en', 'controller' => 'docs']);
// -> /de/docs (expected: /en/docs)
Router::url(['language' => 'de', 'controller' => 'docs']);
// -> /de/docs
How to fix the routes to get the expected urls?
I found the reason for this behaviour. The function addUrlFilter replaced the language parameter when generating the urls and the result was always the current language. An updated version of this function does the job:
Router::addUrlFilter(function ($params, $request) {
if (!isset($params['language'])) {
$params['language'] = $request->param('language');
}
return $params;
});
Puuh, one hour of searching and trying...
is there a simple way to translate my routes in Laravel 5.4. My translation files located in here:
/resources
/lang
/en
routes.php
/de
routes.php
In my web.php i define my routes like this:
Route::get('/{locale}', function ($locale) {
App::setLocale($locale);
return view('welcome');
});
Route::get('{locale}/contact', 'ContactController#index');
I have found very elaborate solutions or solutions for Laravel 4. I am sure that Laravel has also provided a simple solution. Can someone explain to me the best approach?
Thanks.
we usually do it like this
to get the current language:
$request = request()->segment(1);
$language = null;
if (!empty($request) && in_array($request,config('translatable.locales'))) {
$language = $request;
App::setLocale($language);
} else {
$language = 'nl';
}
routes:
Route::group(['prefix' => $language], function () {
Route::get(trans('routes.newsletter'), array('as' => 'newsletter.index', 'uses' => 'NewsletterController#index'));
I created a file translatable.php in my config folder:
<?php
return [
'locales' => ['en', 'de'],
];
web.php:
$request = request()->segment(1);
$language = null;
if (!empty($request) && in_array($request,config('translatable.locales'))) {
$language = $request;
App::setLocale($language);
} else {
$language = 'de';
}
Route::get('/', function() {
return redirect()->action('WelcomeController#index');
});
Route::group(['prefix' => $language], function () {
/*
Route::get('/', function(){
return View::make('welcome');
});
*/
Route::get('/',
array( 'as' => 'welcome.index',
'uses' => 'WelcomeController#index'));
Route::get(trans('routes.contact'),
array('as' => 'contact.index',
'uses' => 'ContactController#index'));
});
Works fine - Thanks. Is the redirect also the best practice?
Best regards
How to I redirect following urls to lower case url?
http://domain.com/City/really-long-slug-from-db/photos
http://domain.com/city/Really-Long-Slug-From-Db/photos
http://domain.com/City/really-long-slug-from-db/Photos
to
http://domain.com/city/really-long-slug-from-db/photos
This is my route:
Route::any('/{city}/{slug}/{page?}',
array(
'as' => 'slug-page',
function($city, $slug, $page="info"){
return View::make('default.template.'.$page)
->with('city', $city)
->with('page',$page)
->with('slug', $slug);
}
))
->where(
array(
'city' => '[a-z ]+',
'page' => '[a-z-]+',
'slug' => '(about|photos|videos)'
));
Currently I used regex [a-z-]+ to match only smaller case strings and that throws NotFoundHttpException for obvious reasons.
How do I accept all these parameters in case insensitive strings and 301 redirect(to avoid duplicate urls) to smaller case urls in Laravel 5.1?
You could easily do that with a route middleware. The middleware should check if there are any uppercase characters in the path and redirect to lowercased version.
First, define the middleware class:
class RedirectToLowercase
{
public function handle($request, Closure $next) {
$path = $request->path();
$pathLowercase = strtolower($path); // convert to lowercase
if ($path !== $pathLowercase) {
// redirect if lowercased path differs from original path
return redirect($pathLowercase);
}
return $next($request);
}
}
Then register the new middleware in your Kernel.php:
protected $routeMiddleware = array(
// ... some other middleware classes ...
'lowercase' => 'App\Http\Middleware\RedirectToLowercase'
);
Finally, apply the middleware to your route:
Route::any('/{city}/{slug}/{page?}', array(
'as' => 'slug-page',
'middleware' => 'lowercase',
function() {
// your code
})
);