By default Laravel has a folder in resources/lang that contains all the translations used in the application. We want to use these translations in JS, for example in the case of a SPA application.
We will use a web route where we will render translations only for the current language in the application.
We define this route right in in web.php
Route::get('js/translations.js', function () {
$lang = config('app.locale');
$strings = \Illuminate\Support\Facades\Cache::rememberForever('lang_'.$lang.'.js', function () use($lang) {
$files = [
resource_path('lang/' . $lang . '/common.php'),
resource_path('lang/' . $lang . '/validation.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('translations');
Pay attention to 2 things.
- We use Cache to store translations.
- We include only the files we need to translate, in our case: common.php and validation.php
In a blade, header or footer file, before the main scripts:
<script src="{{ route('translations') }}"></script>
Now we need to create a JS function that will help us easily translate from anywhere in our JS application. Make sure you have the lodash plugin installed. If not:
npm i --save lodash
Now we will write this in our main script, let's say app.js
import getLodash from "lodash/get";
import eachRightLodash from "lodash/eachRight";
import replaceLodash from "lodash/replace";
window.translate = function(string, args){
let value = getLodash(window.i18n, string);
eachRightLodash(args, (paramVal, paramKey) => {
value = replaceLodash(value, `:${paramKey}`, paramVal);
});
return value;
}
Now we can call our function anywhere in the application to translate a key, for example:
translate('common.years', { nr: 10 });
// The result will be: 10 years
If you use VueJS, we can create a prototype:
Vue.prototype.trans = (string, args) => {
return window.translate(string, args);
};
Then in a VueJS component:
computed:{
years(){
return this.trans('common.years', { nr: 10 });
}
}