Open ju5t opened 3 years ago
@ju5t which kind of translation issues do you get? Just beginning to use laravel-localization for a side project
@pmochine most details are in https://github.com/laravel/octane/issues/113.
We ended up writing our own simplified localisation support. This was much easier for us. It isn't something we can share at this point in time, as it's not packaged up nicely.
We haven't moved onto Octane though. We're using Forge and you can't switch; you have to migrate.
can't seem to get this to work on octane, tried what is suggested here https://github.com/laravel/octane/issues/113. No luck
Did someone managed to resolve this guys ??
Hello, I have my own package very similar to this one, and I adapted it to laravel octane, therefore, adapting this package to octane has not been very difficult, here I tell you how to make it work in octane. Routes are always required to be cached.
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Mcamara\LaravelLocalization\LaravelLocalization;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
//Remove singleton
$this->app->offsetUnset(LaravelLocalization::class);
//Add bind (Necessary for each cycle to restart)
$this->app->bind(LaravelLocalization::class, function () {
return new LaravelLocalization();
});
}
}
namespace App\Listeners;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
class ReloadRoutes
{
private static $_last_locale = null;
/**
* Handle the event.
*
* @param mixed $event
* @return void
*/
public function handle($event): void
{
$locale = LaravelLocalization::setLocale();
$path = $this->makeLocaleRoutesPath($event->sandbox, $locale);
if (self::$_last_locale != $locale && file_exists($path) && is_file($path)) {
self::$_last_locale = $locale;
include $path;
}
}
/**
* @param Application $app
* @param string $locale
* @return string
*/
protected function makeLocaleRoutesPath($app, $locale = '')
{
$path = $app->getCachedRoutesPath();
if (!$locale) {
return $path;
}
return substr($path, 0, -4) . '_' . $locale . '.php';
}
}
In config/octane.php add:
...
'listeners' => [
...
RequestReceived::class => [
...Octane::prepareApplicationForNextOperation(),
...Octane::prepareApplicationForNextRequest(),
App\Listeners\ReloadRoutes::class,
],
...
],
...
With this it should work, but I have to do more tests.
Hi gents,
I've also managed to partially make it work with Octane. My way is as per described below:
Since the service provider registers its facade as a singleton we need to switch it to a way proposed by Octane's documentation:
What I did?
composer.json
: "extra": {
"laravel": {
"dont-discover": [
"mcamara/laravel-localization"
]
}
},
namespace App\Providers;
use Mcamara\LaravelLocalization\LaravelLocalization;
use Mcamara\LaravelLocalization\LaravelLocalizationServiceProvider;
class LocalizationServiceProvider extends LaravelLocalizationServiceProvider
{
protected function registerBindings()
{
$this->app->bind(LaravelLocalization::class, fn () => new LaravelLocalization());
$this->app->alias(LaravelLocalization::class, 'laravellocalization');
}
}
app.php
/*
* Application Service Providers...
*/
App\Providers\LocalizationServiceProvider::class,
...
App\Providers\AppServiceProvider::class,
'aliases' => [
...
'LaravelLocalization' => Mcamara\LaravelLocalization\Facades\LaravelLocalization::class,
]
I'm still struggling with routes and the homepage without locale chunk doesn't work even with the solution of foreach (LaravelLocalization::getSupportedLocales() ...
Will keep you guys updated if I achieve any meaningful results.
Yeah guys, I've managed to make it work completely!
Once setup Laravel Octane via Roadrunner, I discovered several issues with this package:
Here is my solution, it fixes all the issues above:
namespace App\Listeners;
use Illuminate\Foundation\Application;
use Laravel\Octane\Events\RequestReceived;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
class LoadLocalizedRoutesCache
{
private static $lastLocale;
public function handle(RequestReceived $event): void
{
// passing request segment is crucial because the package doesn't
// know the current locale as it was instantiated in service provider
// there is also an option to don't pass the request segment in case
// you don't use translatable routes (transRoute() in web.php) in your project
// in this case the package will correctly resolve the locale and you
// don't need to pass the 3rd param when binding in service provider
$locale = LaravelLocalization::setLocale($event->request->segment(1));
$path = $this->makeLocaleRoutesPath($event->sandbox, $locale);
if (self::$lastLocale != $locale && is_file($path)) {
self::$lastLocale = $locale;
include $path;
}
}
protected function makeLocaleRoutesPath(Application $app, $locale = ''): string
{
$path = $app->getCachedRoutesPath();
if (!$locale) {
return $path;
}
return substr($path, 0, -4) . '_' . $locale . '.php';
}
}
'listeners' => [
RequestReceived::class => [
...Octane::prepareApplicationForNextOperation(),
...Octane::prepareApplicationForNextRequest(),
\App\Listeners\LoadLocalizedRoutesCache::class
],
composer.json
: "extra": {
"laravel": {
"dont-discover": [
"mcamara/laravel-localization"
]
}
},
composer.json
:namespace App\Providers;
use Mcamara\LaravelLocalization\LaravelLocalization;
use Mcamara\LaravelLocalization\LaravelLocalizationServiceProvider;
class LocalizationServiceProvider extends LaravelLocalizationServiceProvider
{
protected function registerBindings()
{
$fn = fn () => new LaravelLocalization();
// the conditional check below is important
// when you do caching routes via `php artisan route:trans:cache` if binding
// via `bind` used you will get incorrect serialized translated routes in cache
// files and that's why you'll get broken translatable route URLs in UI
// again, if you don't use translatable routes, you may get rid of this check
// and leave only 'bind()' here
// the 3rd parameter is important to be passed to 'bind'
// otherwise the package's instance will be instantiated every time
// you reference it and it won't get proper data for 'serialized translatable routes'
// class variable, this will make impossible to use translatable routes properly
// but oveall the package will still work stable except generating the same URLs
// for translatable routes independently of locale
if ($this->runningInOctane()) {
$this->app->bind(LaravelLocalization::class, $fn, true);
} else {
$this->app->singleton(LaravelLocalization::class, $fn);
}
$this->app->alias(LaravelLocalization::class, 'laravellocalization');
}
private function runningInOctane(): bool
{
return !$this->app->runningInConsole() && env('LARAVEL_OCTANE');
}
}
/*
* Application Service Providers...
*/
App\Providers\LocalizationServiceProvider::class,
...
App\Providers\AppServiceProvider::class,
'aliases' => [
...
'LaravelLocalization' => Mcamara\LaravelLocalization\Facades\LaravelLocalization::class,
]
My project is a typical Laravel project:
We use several translatable routes in the project. Most of problems get from there. Basically adapting the package appeared not so hard, but making translatable routes work made me a bit nervous :-)
Notes:
foreach (...)
over locales as described in posts above.php artisan route:trans:cache
)@mcamara , can I prepare a PR with those changes?
@Jangaraev please go ahead, we will really appreciate it
can I prepare a PR with those changes?
@jangaraev Are you still planning to make a PR?
@jangaraev you've saved my day dude. Thank you so much for the great solution :)
@jangaraev Are you still planning to make a PR?
sorry, was sick for a long time. yep, in a week will try to propose something there.
@jangaraev please use markdown correctly for highlight ```php
, thanks
Is anybody using one of the workarounds described in this issue and everything still works? I just tested both and I had problems with all of them. Just wondering if I did something wrong or if this workaround just don't work anymore.
Hi @jangaraev, I am trying your workaround, but it doesn't work. The octane route cache file for the selected locale was not created, so the listener doesn't include it and octane returns 404.
I'm using Laravel 10 and PHP 8.2
How can I fix this issue?
Thanks, Vincenzo
@vic-pic I already wrote in the PR #833, but not in here maybe this helps you as well:
I tried the solution and it didn't solve the problem for me. I also looked into the code of the solution, and it seems a bit hacky, but I'm not that deep into this plugin.
Since this broke my production environment and I needed a multi-language solution fast, I uninstalled this plugin and used this instead: https://github.com/codezero-be/laravel-localized-routes
Worked with Octane out of the box and the migration process was surprisingly easy. I think it is also nice that
route:cache
works normally there.
Hello guys,
Here's my workaround. First of all you need to understand sandbox is an isolated instance of your app. Whenever you have any request one of these instances are getting handle the request.
So, it means that you need to load localed routes whenever you have request. Because you do not know which sandboxed instance of your app is going to handle "the" request and what language is currently adjusted for that isolated instance.
Here's my LoadLocalizedRoutesCache
namespace App\Listeners;
use Barryvdh\Debugbar\LaravelDebugbar;
use Illuminate\Foundation\Application;
use Laravel\Octane\Events\RequestReceived;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
class LoadLocalizedRoutesCache
{
/**
* Handle request received event
*
* @param RequestReceived $event
* @return void
*/
public function handle(RequestReceived $event): void
{
// Fix routes
$this->fixRoutes($event);
// Fix debugbar
$this->fixDebugbar($event->sandbox);
}
/**
* Create the path to the locale routes file
*
* @param Application $sandbox
* @param string $locale
* @return string
*/
protected function makeLocaleRoutesPath(Application $sandbox, string $locale = 'en'): string
{
// Get the path to the cached routes file
$path = $sandbox->getCachedRoutesPath();
// Return the path to the locale routes file
return substr($path, 0, -4) . '_' . $locale . '.php';
}
/**
* @param Application $sandbox
* @return void
*/
protected function fixDebugbar(Application $sandbox): void
{
$sandbox->singleton(LaravelDebugbar::class, function ($sandbox) {
return new LaravelDebugbar($sandbox);
});
}
/**
* @param RequestReceived $event
* @return void
*/
protected function fixRoutes(RequestReceived $event): void
{
// Get the sandbox
$sandbox = $event->sandbox;
// Get default locale
$defaultLocale = LaravelLocalization::getDefaultLocale();
// Get the locale code from the request
$currentCode = $event->request->segment(1, $defaultLocale);
// Set the locale
$sandbox->setLocale($currentCode);
LaravelLocalization::setLocale($currentCode);
// Get the path to the locale routes file
$path = $this->makeLocaleRoutesPath($sandbox, $currentCode);
// If the locale the file exists, include it
if (is_file($path)) {
include $path;
}
// Fix home route not found, this is required for auto redirection
$sandbox['router']->addRoute('GET', '/', function () use ($currentCode) {
return redirect(LaravelLocalization::localizeUrl('/', $currentCode));
});
}
}
You need to add this event handle to octane.php
like below.
I hope this helps to you too.
Laravel has recently released a beta version of Laravel Octane.
Because a lot of things are cached, the list of routes doesn't update between requests. This means all prefixed routes do not exist, as Octane didn't make them available. Although Octane is a beta, this caching is unlikely to change.
It would be awesome if Octane support can be added.
edit: See https://github.com/laravel/octane/issues/113 for a workaround/solution. For me this still caused some translation issues, which I will try to demonstrate in more detail later, unless someone beats me to it :)