DEV Community

Daniel Werner
Daniel Werner

Posted on • Originally published at danielwerner.dev on

How to implement translations with JetStream, Intertia and Vue3 using Laravel 10

Laravel 10 comes with internationalization support out of the box, however when we use JetStream starter pack with Inertia the transaction support is not included in the Vue part. Luckily it is quite easy to make it work.

Our use case

A brand new Laravel 10 application, using JetStream with Intertia and Vue3 frontend. The app requires multilanguage support, so we need a solution that we can use in both frontend and backend code. The best would be to use the same language files for both. In the newest Laravel (in time of writing it is version 10) we can use both json files and php files for translations. The php files are located in lang/{locale}/file.php. These files can be separated by "topic" like auth, validation etc. In case of json files, we only have one file per locale, and they are located in resources/lang/{locale}.json We want to use the latter because it is easily to pass the values to the frontend in json format.

Default Laravel translation keys in json

Laravel has a built in command to publish the default language files: php artisan lang:publish ** Unfortunately this only publishes the php language files. To convert them to json I used a quick and dirty solution and replaced the return in those files by using **echo json_encode(['translation' => 'content']), and copied over the json. One caveat here is that the php file name is the translation prefix (for example auth), so in the json you need to add auth. prefix to all the translation keys (for example: auth.password ).

Share the translation data from the backend

To be able to use the same language pack in both the frontend and the backend, we need pass the translation data to the frontend. First create a helper function which reads the json file support/helpers.php :


<?php

if (! function_exists('translations')) {
    function translations($json)
    {
        if (!file_exists($json)) {
            return [];
        }

        return json_decode(file_get_contents($json), true);
    }
}

Enter fullscreen mode Exit fullscreen mode

Add this file to the composer json autoload and run composer dump-autoload :


    "autoload": {
        "files": [
            "support/helpers.php"
        ],
Enter fullscreen mode Exit fullscreen mode

We use Inertia so we share the translation object from the json by adding the following to the app/Http/Middleware/HandleInertiaRequests.php middleware:


   public function share(Request $request): array
    {
        return array_merge(parent::share($request), [
            'locale' => function () {
                return app()->getLocale();
            },
            'translations' => function () {
                return translations(
                    resource_path('lang/'. app()->getLocale() .'.json')
                );
            },
        ]);
    }

Enter fullscreen mode Exit fullscreen mode

This makes the translations available as Inertia props.

Create Vue3 plugin for translation

The localization needs to be accessible everywhere so we create a plugin and make it accessible globally. Create a file resources/js/Translator.js


export const Translator = {
    install: (v, translations) => {
        v.config.globalProperties.__ = function(key, replace = {}) {
            let translation = translations[key]
                ? translations[key]
                : key;

            Object.keys(replace).forEach(function (key) {
                translation = translation.replaceAll(':' + key, replace[key])
            });

            return translation
        };
    },
};

Enter fullscreen mode Exit fullscreen mode

This basically finds the given key in the translations object and replace the placeholders in the translation if there is any. We make our function " __" available globally by adding it to the *globalProperties. *

For further details about Vue plugin development check out the docs here: https://vuejs.org/guide/reusability/plugins.html#writing-a-plugin

Now our plugin is ready, let's use it in our app: resources/js/app.js


import './bootstrap';
import '../css/app.css';

import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/vue3';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m';
import {Translator} from './Translator.js';

const appName = import.meta.env.VITE_APP_NAME || 'Laravel';

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
    setup({ el, App, props, plugin }) {

        return createApp({ render: () => h(App, props) })
            .use(plugin)
            .use(ZiggyVue, Ziggy)
            .use(Translator, props.initialPage.props.translations)
            .mount(el);
    },
    progress: {
        color: '#4B5563',
    },
});

Enter fullscreen mode Exit fullscreen mode

Using translations

In blade files you can use the __() function as usual in Laravel, it will automatically find the proper json language file according to the app current locale. In Vue components use the same function like this:


<p>{{__('auth.failed')}}</p>

Enter fullscreen mode Exit fullscreen mode

When using options API you can use it in the code like: this.__('auth.failed').

Useful resources

I'd like to thank Dario Trbovic I took the original idea from his blog post: https://dariot.medium.com/how-to-translate-laravel-with-inertia-c34c7284544e.

Vue3 documentation about writing plugins: https://vuejs.org/guide/reusability/plugins.html#writing-a-plugin

Laravel documentation about localization: https://laravel.com/docs/10.x/localization

Top comments (0)