How to work with laravel, inertia js, and vue-i18n

Changelogfy still has some code in laravel livewire, but I'm moving everything to inertia js.

But the news feed is multilingual and part of the job is making sure i18n works as well as the current version.

Last week I lost some hours trying to make inertiajs and vue-i18n works together. But some people from inertia js discord help to understand and make it works.

To help some people to understand the process, I decided to create this post blog.

I will centralize all my languages files at laravel default translates, in the folder resources/lang.

Project Folder Structure Laravel

I think is a great way to deliver i18n to the front and backend with the same translated files.

But VueJS will require JSON language files, not PHP.

To convert all our PHP translate files to JSON, we will install the composer package below:

composer require librenms/laravel-vue-i18n-generator

Publish the package configs:

php artisan vendor:publish --provider="MartinLindhe\VueInternationalizationGenerator\GeneratorProvider"

Now let's run this command to convert files:

php artisan vue-i18n:generate

A file will be created by default in resources/js/vue-i18n-locales.generated.js

This file contains all your languages.

Important:

You need to run this command every time you added new translations or every deployment of your application!

Now let's install the vue-i18n package.

npm install vue-i18n@next

If you like to give power to user changes automatically your language, you can send locale to view by HandleInertiaRequests middleware.

<?php

namespace App\Http\Middleware;

use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Inertia\Middleware;

class HandleInertiaRequests extends Middleware
{
    protected $rootView = 'app';

    public function version(Request $request)
    {
        return parent::version($request);
    }

    public function share(Request $request)
    {
        return array_merge(parent::share($request), [
            'user' => function () use ($request) {
                if (!$request->user()) {
                    return;
                }
            },
            'locale' => app()->getLocale()
        ]);
    }
}

Now let's set up the resources/js/app.js, to use vue-18n and use the current user language send by HandleInertiaRequests middleware.

import { createI18n } from "vue-i18n";
import localeMessages from "./vue-i18n-locales.generated";

import { createApp, h } from "vue";
import { createInertiaApp } from "@inertiajs/inertia-vue3";

createInertiaApp({
    resolve: (name) => require(`./Pages/${name}.vue`),
    setup({ el, app, props, plugin }) {
        const i18n = createI18n({
            locale: props.initialPage.props.locale, // user locale by props
            fallbackLocale: "en", // set fallback locale
            messages: localeMessages, // set locale messages
        });

        return createApp({ render: () => h(app, props) })
            .use(plugin)
            .use(i18n)
            .mixin({
                methods: {
                    route
                },
            })
            .mount(el);
    },
});

Now you can use vue-18n in any view like this:

<template>
    <h1>
        {{ t("home.title") }}
    </h1>
</template>
<script>
import { useI18n } from "vue-i18n";
export default {
    setup() {
        const { t } = useI18n({});
        return { t };
    },
}
</script>

I hope I helped you ✌️