I am trying to set up localization on my Laravel Inerita (Vue.js). I know about https://github.com/mcamara/laravel-localization
, but this does not support Inertia (at least I was not successful with running this on my Vue.js file) {{ __("text") }}
does not work in inertia error: TypeError: _ctx.__ is not a function
.
Anyway, I am using a different localization package called laravel-vue-i18n
.
I am successful in using this on Vue.js, but I am having problems when setting the locale based on URL. How do I set my routes/middleware to use a nullable locale (en as default)?
// Can be nullable locale?
Route::middleware(['setLocale'])->prefix('{locale?}')->group(function () {
Route::resource('posts', PostController::class);
Route::resource('comments', CommentController::class);
});
class SetLocaleMiddleware
{
public function handle($request, Closure $next, $locale = 'en')
{
\Log::info($locale); // Always logs as 'en' even if I add 'ja' in the URL
\Log::info($request->route('locale')); // Locale or whatever is the text after localhost/ for some reason
if (!in_array($locale, ['en', 'ja'])) {
abort(400);
}
App::setLocale($locale);
return $next($request);
}
}
protected $middlewareAliases = [
'setLocale' => \App\Http\Middleware\SetLocaleMiddleware::class,
];
Expected results:
// Set application language to Japanese
http://localhost/ja
http://localhost/ja/posts
http://localhost/ja/comments
// Set application language to English as default
http://localhost
http://localhost/posts
http://localhost/comments
Note: it does not have to be middleware.
So I found a solution that worked for me, though I am not able to use the \ja
in the url route, but instead use laravel's Session
facade and update the locale in vue on the fly using createApp
npm install laravel-vue-i18n
php artisan lang:publish
app
lang
en
auth.php
pagination.php
password.php
post.php
validation.php
ja
auth.php
pagination.php
password.php
post.php
validation.php
i18nVue
from laravel-vue-i18n
in app.ts fileFile app.ts
// Format may be different for app.js (remove ':string') inside async
import { createApp, h, DefineComponent } from "vue";
import { createInertiaApp } from "@inertiajs/vue3";
import { i18nVue } from "laravel-vue-i18n";
createInertiaApp({
...
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
...
.use(i18nVue, {
fallbackLang: "en",
resolve: async (lang: string) => {
const langs: any = import.meta.glob("../../lang/*.json");
return await langs[`../../lang/${lang}.json`]();
},
})
...
},
});
i18n
in vite.config.jsvite.config.js
import i18n from "laravel-vue-i18n/vite";
export default defineConfig({
plugins: [
...
i18n(),
],
});
lang/php_*.json
in .gitignoreRoute::group
in your web.php. Also include the controller@method to update the locale.File web.php
Route::post('/locale', [SetLocaleController::class, 'locale'])->name('locale');
Route::middleware(['setLocale'])->group(function () {
Route::resource('posts', PostController::class);
Route::resource('comments', CommentController::class);
});
php artisan make:middleware SetLocaleMiddleware
File SetLocaleMiddleware.php
class SetLocaleMiddleware
{
public function handle($request, Closure $next)
{
// get locale from session or get default value 'en'
$locale = Session::get('locale', 'en');
App::setLocale($locale);
return $next($request);
}
}
php artisan make:controller SetLocaleController
File SetLocaleController.php
class SetLocaleController extends Controller
{
public function locale(Request $request)
{
// set locale to session
Session::put('locale', $request->get('locale'));
$data = ['locale' => $request->get('locale')];
return response()->json($data);
}
}
HandleInertiaRequests
to return locale
as propsFile HandleInertiaRequests.php
class HandleInertiaRequests extends Middleware
{
...
public function share(Request $request): array
{
return [
...parent::share($request),
...
'locale' => Session::get('locale', 'en'),
...
];
}
}
import { createApp } from "vue";
import { i18nVue } from "laravel-vue-i18n";
import axios from "axios";
const app = createApp({});
// the method to update the locale. remote ':string` if in not using typescript.
const toggleLocale = async (locale: string) => {
await axios
.post(route("locale"), { locale: locale })
.then((response) => {
app.use(i18nVue, {
lang: response.data.props.locale,
});
})
.catch((error) => {
console.log(error);
});
};
Bonus, if you are experiencing error 419 (missing csrf token), do the following in your axios (preferably in app.ts/js)
import axios from "axios";
axios.defaults.withCredentials = true;
axios.defaults.withXSRFToken = true;
lang/en/post.php
<?php
return [
'add, :title' => 'Add :title',
];
lang/ja/post.php
<?php
return [
'add, :title' => ':titleを追加',
];
any vuejs files
<template>
...
{{ trans("post.add, :title", { title: props.title,}) }}
<!-- 'post' is from post.php while add is the key -->
<!-- you can also add parameters here too. -->
...
</template>
<script setup lang="ts">
import { trans } from "laravel-vue-i18n";
</script>
Routes stays as
// Set application language to English as default
http://localhost
http://localhost/posts
http://localhost/comments