Localization for Laravel Inertia VueJs

478 Views Asked by At

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)?

File web.php

// Can be nullable locale?
Route::middleware(['setLocale'])->prefix('{locale?}')->group(function () {
  Route::resource('posts', PostController::class);
  Route::resource('comments', CommentController::class);

});

File SetLocaleMiddleware.php

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);
    }
}

File app/Kernel.php

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.

1

There are 1 best solutions below

0
Mr. Kenneth On BEST ANSWER

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

  1. npm install laravel-vue-i18n
  2. publish the lang files: php artisan lang:publish
  3. copy the en directory and change to your desired new locale (mine was ja)
  4. optional (create a post.php or any other php file inside the directory)
app
  lang
    en
      auth.php
      pagination.php
      password.php
      post.php
      validation.php
    ja
      auth.php
      pagination.php
      password.php
      post.php
      validation.php
  1. Add i18nVue from laravel-vue-i18n in app.ts file

File 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`]();
                },
            })
            ...
    },
});
  1. add i18n in vite.config.js

vite.config.js

import i18n from "laravel-vue-i18n/vite";

export default defineConfig({
    plugins: [
        ...
        i18n(),
    ],
});
  1. add lang/php_*.json in .gitignore
  2. add a Route::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);
});
  1. create new middleware 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);
    }
}
  1. create new controller 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);
    }
}
  1. Update HandleInertiaRequests to return locale as props

File HandleInertiaRequests.php

class HandleInertiaRequests extends Middleware
{
    ...
    public function share(Request $request): array
    {
        return [
            ...parent::share($request),
            ...
            'locale' => Session::get('locale', 'en'),
            ...
        ];
    }
}
  1. In your VueJS File, there are multiple ways to toggle locale select, radio, etc. Use what you want and maybe use below how to switch the locale:
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;

How to use

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