Inertia-I18N: Internationalisation for Vue / Inertia Applications

There are over 7,000 languages in active use today. Even if you only deal in English, is that British English, American English, Caribbean English, Sinaporean English, Hong Kong English or any of the many other variations?

Supporting multiple languages and dialects in your applications is often essential in our global world, and is something that generally presents a challenge to developers.

Language is everywhere in software. It tells you what to do, when to do it, what just happened, what’s going to happen and explains the context around what you’re looking at. It’s inextricable from the software.

So naturally we have to extricate it.

Structuring for internationalisation

Take, for example, a simple text input. The text input will have a label, it may have a placeholder, it may have help text and it will have descriptive error messages. Something like this would not be unusual:

<div>
<label for="first_name">First name</label>
<input type="text" id="first_name" placeholder="e.g. John" required />
<p class="error-message"></p>
</div>

This HTML template could be located anywhere in your codebase. The error message is probably generated on the server via a validation service that is buried away something else.

Now imagine having dozens of different translations of all that text in those far reaches of your application. Completely unmanageable for all but the smallest of applications.

The Laravel answer and the Inertia problem

Laravel has internationalisation (i18n) support built in via a collection of PHP files that are accessed through a __('some_file.some_field') function. This works fine for the server and would work fine for Laravel Blade components too. Only problem is that if you’re using Inertia, you don’t have access to either Blade components or PHP functions in your application’s frontend.

Sure, you could create a separate i18n setup for your frontend, but now you have the same problem of fragmenting from the intro. Every translation would likely become the subject of a hunt as you wonder if flash messages generated on the server but shown on the frontend should be part of which package. Then also, the duplications would be many.

Ideally then, we need a way for our translations to be stored in one single place and then made available to both the server and the frontend, which is where our open-source package Inertia-I18n comes in!

Getting started

Because this package deals with both server setup and frontend features, it comes as a hybrid package (one containing both PHP and JavaScript in this case) and as such, we distribute it via Composer rather than NPM since the latter doesn’t allow any integration with PHP autoloading. So step one is to install it into your Laravel application:

composer require evo-mark/inertia-i18n

We also need our bundlers to be able to use the JavaScript parts of the package, so we can install it as a “local” package like so:

npm install ./vendor/evo-mark/inertia-i18n
# OR
pnpm add ./vendor/evo-mark/inertia-i18n

The next step is setting up Vite to convert our PHP language files into a format that JavaScript can read. The handly Vite plugin included in our package automatically handles this.

1// vite.config.js
2import InertiaI18n from "inertia-i18n/vite";
3
4export default {
5 plugins: [InertiaI18n()],
6};

Then finally we need to make our language files available to our Inertia application with a Vue plugin (also included)

1// resources/js/app.js
2import useInertiaI18nVue from "inertia-i18n/vue";
3
4createInertiaApp({
5 async setup({ el, App, props, plugin }) {
6 const inertiaI18nPlugin = useInertiaI18nVue(props);
7 // Optional, but you may get warnings without this
8 await inertiaI18nPlugin.load();
9
10 createSSRApp({ render: () => h(App, props) })
11 .use(plugin)
12 .use(inertiaI18nPlugin)
13 .mount(el);
14 },
15});

Usage

From this point, your Laravel application tells Inertia which language files to load (using App::currentLocale() and the config('app.fallback_locale') setting for your fallback language) and then we hand the rest off to the Vue-I18N library to handle the business of showing your text to users. So all of the standard methods are available to you

<template>
<div v-text="$t('messages.hello_world')"></div>
</template>

or

1<script setup>
2import { useI18n } from 'vue-i18n';
3
4const { t } = useI18n();
5const translated = computed(() => t('message.hello_world));
6</script>

Changing the language directory location

By default, the package assumes your language files are inside the lang directory at the root of your application. If you have them elsewhere though, you can pass an alternate location to your vite plugin:

1// vite.config.js
2import InertiaI18n from "inertia-i18n/vite";
3
4export default {
5 plugins: [InertiaI18n({
6 langDirectory: `${process.cwd()}/languages`
7 })],
8};
9

Conclusion

Now thanks to the power of Vite, any changes to your language PHP files will automatically build into JS compatible files and be loaded into your application (with support for HMR in dev mode).

As always, if you have any problems or feedback using our open-source software, please post in the issues or discussions part of the GitHub repository.

Bon voyage.

Part of evoMark's contribution to Free and Open Source Software (FOSS)

To read more about evoMark and our open-source software, head to our Open-Source Software page

composer require evo-mark/inertia-i18n
Get in Touch

Get in touch with us today 01202 790300

monday 09:00 - 17:00
tuesday 09:00 - 17:00
wednesday 09:00 - 17:00
thursday 09:00 - 17:00
friday 09:00 - 16:00
saturday Closed
sunday Closed