I’ve started a web application with Laravel 5 back in 2015 using plain Blade templates and some basic JavaScript. As I lost my job in november 2023 because of layoffs in the company I worked for, I decided to rebuild it from scratch using InertiaJS. InertiaJS gave me the opportunity to focus on the frontend and keeping most of the backend using the technologies I wanted.
After all those years of building the multilingual application, I had a lot of PHP translation files which don’t work together with i18next. I didn’t want to create a complete new JSON file and I didn’t want to split out translations for frontend & backend. The current solution is that I created a command to convert those translations to JSON using a Laravel command.
We start with some configuration:
- Create a disk in config/filesystems.php for the existing PHP languages files.
- Create a symbolic link for the newly created JSON translation files.
<?php
return [
/*
|--------------------------------------------------------------------------
| Filesystem Disks
|--------------------------------------------------------------------------
|
| Here you may configure as many filesystem "disks" as you wish, and you
| may even configure multiple disks of the same driver. Defaults have
| been set up for each driver as an example of the required values.
|
| Supported Drivers: "local", "ftp", "sftp", "s3"
|
*/
'disks' => [
'languages' => [
'driver' => 'local',
'root' => base_path('lang'),
'throw' => true,
],
],
/*
|--------------------------------------------------------------------------
| Symbolic Links
|--------------------------------------------------------------------------
|
| Here you may configure the symbolic links that will be created when the
| `storage:link` Artisan command is executed. The array keys should be
| the locations of the links and the values should be their targets.
|
*/
'links' => [
public_path('storage') => storage_path('app/public'),
public_path('locales') => storage_path('app/public/locales'),
],
];
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Storage;
class CreateI18nForFrontend extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:create-i18n-for-frontend';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command to generate json files from Laravel language resource files.';
/**
* Execute the console command.
*/
public function handle()
{
$serverStorage = Storage::disk('languages');
$directories = $serverStorage->directories();
foreach ($directories as $locale) {
$translationFiles = $serverStorage->allFiles($locale);
$translations = [];
foreach ($translationFiles as $file) {
$baseName = str_replace('.php', '', basename($file));
$contents = require $serverStorage->path($file);
$translations[$baseName] = $contents;
}
$filePath = sprintf('locales/%s/translation.json', $locale);
$contents = json_encode($translations, JSON_PRETTY_PRINT);
Storage::disk('public')->put($filePath, preg_replace("/:(\w+)/", '{{$1}}', $contents));
}
$this->info('Files generated');
return 0;
}
}
This command converts the PHP files and translates the variables names from :foo to {{ foo }} which is how I18next expects it to be.
You can run the command like this:
php artisan app:create-i18n-for-frontend
These JSON files shouldn’t be uploaded to your version control system as our PHP files are currently the single source of truth. When changing the PHP translations, you need to re-run this command to make them available in your frontend.
If you are using Deployer you can add the following task to run this after every successful deploy:
// Set php binary file path
set('bin/php', '/usr/bin/php8.2');
after('deploy', 'create-frontend-translations');
task('create-frontend-translations', function () {
cd('{{release_path}}');
run('{{bin/php}} artisan app:create-i18n-for-frontend');
});