Using Laravel localization with JavaScript and VueJS

We do know that Laravel has a wonderful localization support out of box which by default is located in resources/lang folder. We can use it in PHP calling helper function like trans('auth.email') (or you can use also __ in newer versions). Laravel’s Blade template engine also has support of this helper:

<label for="email">{{ trans('auth.email') }}</label>
or (newer versions)
<label for="email">@lang('auth.email')</label>
So the code above would be rendered as:
<label for="email">Email:</label>

Passing Laravel language strings to JavaScript

But what about JS? It has neither trans() nor __() functions by default (at least up to version 5.6). And it doesn’t even know anything about localization strings, which by the way could be organized as JSON objects in PHP (since L5.4).
Yeah, we can use any package dedicated to bringing localization to JS, but let’s keep in mind that as many packages we have as dependencies as harder our application gets supportable. Dependency hell, right?

Passing JSON object with localization strings to the browser

All we need to do is add the following piece of code to our routes/web.php file (or app/Http/routes.php for earlier Laravel versions):
// Localization
Route::get('/js/lang.js', function () {
    $strings = Cache::rememberForever('lang.js', function () {
        $lang = config('app.locale');

        $files   = glob(resource_path('lang/' . $lang . '/*.php'));
        $strings = [];

        foreach ($files as $file) {
            $name           = basename($file, '.php');
            $strings[$name] = require $file;
        }

        return $strings;
    });

    header('Content-Type: text/javascript');
    echo('window.i18n = ' . json_encode($strings) . ';');
    exit();
})->name('assets.lang');
So here we’re walking through all language files for a current system language and combining them down together and making them accessible via special route lang.js. Now we just need to pull this route in our HTML to make this object globally visible:
<script src="/js/lang.js"></script>
Done! From this moment we are able to use it referring to window.i18n object, for example:
console.log(i18n.auth.email);
We can even define a missing helper (es6 syntax)
// script.jsconst _ = import('lodash');window.trans = (string) => _.get(window.i18n, string);
Really cool.

VueJS meets Laravel localization

There’s no much code here as well:
// App.vueconst _ = import('lodash');Vue.prototype.trans = string => _.get(window.i18n, string);
Now we are completely free to use the same syntax in our .vue files (or even string templates in literal) as we use in Blade!
// LoginForm.vue<template>
    <label for="email">{{ trans('auth.email') }}</label>
</template>
Exactly the same as we use in Blade. Unified solution.
From now on, we can easily migrate our templates from Blade to .vue.
Mission accomplished! We just have simplified our lives.

BONUS
If we need a support for parameterized language strings, we can easily modify the helper like this:
Vue.prototype.trans = (string, args) => {
    let value = _.get(window.i18n, string);

    _.eachRight(args, (paramVal, paramKey) => {
        value = _.replace(value, `:${paramKey}`, paramVal);
    });
    return value;
};
But this time you can’t use Blade syntax as-is because of difference between PHP’s associative arrays and JS’ objects:
<strong>
    {{ trans('validation.required', {attribute: 'email'}) }}
</strong>
But anyway, it’s a minor side-effect. This is still pretty usable feature and nice way to add a support for your Laravel application in Vue components with less efforts.

Post a Comment

0 Comments