There are many great Laravel packages that offer ways to use Larave’s translation strings in front-end, like mariuzzo/laravel-js-localization and thepinecode/i18n, but what if you wanted a simple solution.
Daiyrbek Artelov wrote an awesome article on Dev.to about this, and I loved it at first. However, he uses cache to store all the translations strings and then provide them in the script tag for JavaScript to use and I didn’t want to bloat my cache with all the translations, especially since I’m building a Laravel application that’s gonna be available in three languages.
I noticed that I don’t need the strings inside the PHP files for front-end anyway, so what if I just load the JSON file in JavaScript and use those strings. That’s how I came to this solution.
Webpack configuration
Since my application is built in Vue JS, and the JS files can get pretty big I use code splitting feature in Webpack to lazy load components, and that’s exactly how I’m loading the translation JSON files.
Here’s how my Webpack config looks like:
module.exports = { output: { chunkFilename: 'js/chunks/[name].js?id=[chunkhash]' }, resolve: { alias: { '@': path.resolve('resources/js'), '__': path.resolve('resources/lang'), }, }, }
As you can see I have separated the Webpack config in another file so PHPStorm can recognize the aliases for resolving paths and code completion.
Vue Mixin
First lets get the locale from Laravel. I din’t have to publish anything from back-end since the locale is alrady defined in the html tag in app.blade.php.
<!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
Then simply get the locale in JS.
let locale = document.documentElement.getAttribute('lang');
Using lazy imports in NODE I’m loading the json file and since I have the country code I know which one to load. Since the operation is asynchronous we can use then to receive the contents of the JSON file as an object.
import(`__/${locale}.json`).then(translations => { });
Nothing fancy here. Look for the string, if it;s found get it, if not, use the one provided already and if there are parameters to replace, replace them using forEach function from lodash.
import(`__/${locale}.json`).then(translations => { translation = translations[key] ? translations[key] : key forEach(replace, (value, key) => { translation = translation.replace(':' + key, value) }); })
Below is the complete function. I’m also catching errors from the import, if by any case the JSON file is not found, and I’m throwing the error in console, but not in production.
import {forEach} from 'lodash'; export default { methods: { /** * Translate the given key. */ __(key, replace) { let locale = document.documentElement.getAttribute('lang'); let translation = key; import(`__/${locale}.json`).then(translations => { translation = translations[key] ? translations[key] : key forEach(replace, (value, key) => { translation = translation.replace(':' + key, value) }); }).catch(error => { if (process.env.NODE_ENV !== 'production') { console.error(`Language file ${locale}.json not found!`); } }); return translation; } }, }
Showcase
Let’s now import the mixin in Vue and use it inside a component.
import Vue from 'vue'; import Translations from '@/Mixins/Translations'; Vue.mixin(Translations);
<template> <h2 class="my-6 text-2xl font-semibold text-gray-700 dark:text-gray-200"> {{ __('Dashboard') }} </h2> </template>
That’s it.
Credits to Daiyrbek Artelov from Dev.to for inspiring me to write a simple solution.
Great job!
Thanks 🙂