Localizing a Laravel app with Vue.js and Inertia.js without any dependencies

set up the variables that inertia.js will share with the views

The “locale” variable will contain the user’s current language choice.
The “language” variable will store the JSON translations used by the frontend.

// Providers/AppServiceProvider.php
use Inertia\Inertia;

public function boot()
{
    Inertia::share([
        'locale' => function () {
            return app()->getLocale();
        },
        'language' => function () {
            return translations(
                resource_path('lang/'. app()->getLocale() .'.json')
            );
        },
    ]);
}

Add translations Function TO PHP helper function

This function returns the JSON translation file used in the language variable above.

// app/helpers.php

<?php
function translations($json)
{
    if(!file_exists($json)) {
	return [];
    }
    return json_decode(file_get_contents($json), true);
}
?>

We should add the helper file to composer.json file.

// composer.json
 
"autoload": {
    // ...
    "files": [
        "app/helpers.php"
    ]
},

After adding it “composer dump-autoload” terminal command should be run in the root of the Laravel application. (Keep in mind: If you deploy the changes to server you may need to run this command on the server too.)

Language Switching component

We need a Vue component so that the user can toggle their language preference. The selectable_locale defines the language choice using the two-letter language code.
I am using tailwind styles. You can change the styling according to your needs.

// resources/js/Language/LanguageSelector.vue
 
<template>
    <div class="ml-4">
        <inertia-link :href="route('language', [selectable_locale])" :class="classes">
            <div v-if="selectable_locale == 'fr'">FR</div>
            <div v-else>EN</div>
        </inertia-link>
    </div>
</template>
 
<script> 
export default {
 
    computed: {
        selectable_locale() {
            if(this.$page.locale == 'fr') {
                return 'en';
            }
            return 'fr'
        },
        classes() {
            return 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-red-900 hover:text-red-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out'
        }
    },
}
</script>

Route

We have an inertia link to the “/language” route. It is needed to be added in web.php.

// routes/web.php

Route::get('/language/{language}', function ($language) {
    Session()->put('locale', $language);
 
    return redirect()->back();
})->name('language');

Check:

php artisan route:list

if language is not in the list we need to run:

php artisan route:cache

Now we can import LanguageSelector component into our AppLayout.vue file.

// path/of/your/layout/view/AppLayout.vue

// ...
import LanguageSelector from '@/Language/LanguageSelector'

export default {
    components: {
        // ...
        LanguageSelector,
    },
// ...

Language Setting Middleware

We need to add middleware to check that value on each page request and make sure we pass the correct variable to the view.

If we want to use our application’s default language here is our solution:

// Http/Middleware/SetLocale.php

namespace App\Http\Middleware;
 
use Closure;
 
class SetLocale
{
    public function handle($request, Closure $next)
    {
        app()->setLocale(config('app.locale'));
        if(session()->has('locale')) {
            app()->setLocale(session('locale'));
        }
 
        return $next($request);
    }
}

Otherwise, we can use the browser’s language so that the users can see the page automatically with their preferred language. Here is the solution:

// Http/Middleware/SetLocale.php

namespace App\Http\Middleware;

use Closure;
use Session;
use App;
use Config;

class SetLocale
{
    public function handle($request, Closure $next)
    {
        if (Session::has('locale')) {
            $locale = Session::get('locale', Config::get('app.locale'));
        } else {
            $locale = substr($request->server('HTTP_ACCEPT_LANGUAGE'), 0, 2);

            if ($locale != 'fr' && $locale != 'en') {
                $locale = 'en';
            }
        }

        App::setLocale($locale);

        return $next($request);
    }
}

Register SetLocale Middleware

Next, register the middleware. Ensure it is registered after we have initialized Laravel’s Session middleware.

// Http/Kernel.php

protected $middlewareGroups = [
    'web' => [
        // ...
        \App\Http\Middleware\SetLocale::class,
        // ...
    ],
];
 
protected $middlewarePriority = [
    // ...
    \Illuminate\Session\Middleware\StartSession::class,
    \App\Http\Middleware\SetLocale::class,
    // ...
];

Register vue.js helper mixin file for translating

This registers our vue.js mixins required for translating the JSON file on the frontend.

// resources/js/app.js
 
Vue.mixin(require('./base'))

Add helper mixins to base.js

Add the mixins below, the first method is for translating a normal string, the last is for translating a string with basic pluralization.

// resources/js/base.js
 
module.exports = {
    methods: {
        /**
         * Translate the given key.
         */
        __(key, replace = {}) {
            var translation = this.$page.language[key]
                ? this.$page.language[key]
                : key
 
            Object.keys(replace).forEach(function (key) {
                translation = translation.replace(':' + key, replace[key])
            });
 
            return translation
        },
 
        /** 
        * Translate the given key with basic pluralization. 
        */
        __n(key, number, replace = {}) { 
            var options = key.split('|');   
 
            key = options[1]; 
            if(number == 1) { 
                key = options[0]; 
            }   
 
            return tt(key, replace); 
        },
    },
}

Add JSON translation file

Next, we need to add the JSON translation file in lang folder. For my case it is fr.json.
You can find all laravel language files from https://github.com/Laravel-Lang/lang 

In the fr.json file we can add all the translations we need for our application. Here is the basic example:

// resources/lang/fr.json
 
{
    "Status": "Statut",
    "Location": "Lieu",
    "Title": "Titre",
    "Name": "Nom",
    "Email": "Email",
    "Phone": "Téléphone",
    "phone number": "numéro de téléphone",
    
    // ...
}

Translate the application

Next, we will need to go through our application and translate it. We need to edit all of our vue pages.

Check if all is done

To have the whole app translated the following tasks need to be completed.

  • All the strings in the resources/js/ would need to be translated and placed in fr.json.
  • If you are using mail notifications (e.g. password reset) those also need to be added to fr.json. (See https://github.com/Laravel-Lang/lang  json folder)
  • The contents of resources/lang/en need to be duplicated into resources/lang/fr and translated. (See https://github.com/Laravel-Lang/lang  src folder)