Nasrul Hazim Bin Mohamad
Posted on October 15, 2024
Translations play a crucial role in making your Laravel application accessible to users in multiple languages. However, manually identifying all instances of the __()
helper across your codebase can be tedious, especially for large projects. What if you could automatically extract all translatable strings and output them to a JSON file ready for localization?
In this blog post, I will walk you through creating a custom Artisan command that scans your Laravel codebase, extracts all text used within the __()
helper, and outputs the translations to a locale-specific JSON file. This solution will save time and make localization more efficient, especially when dealing with a growing number of strings to translate.
Why Automate Translation Extraction?
As your Laravel application grows, so does the number of translatable strings. These strings are typically defined using the __()
helper, which allows developers to localize their application by referring to language lines. However, manually tracking down all instances of __()
across controllers, Blade views, and other parts of your code can be overwhelming.
With this custom command, you can:
- Automatically find all instances of the
__()
helper. - Output these strings into a JSON file ready for translation.
- Specify the locale and output directory for the extracted strings.
Step-by-Step Guide: Building the lang:extract
Artisan Command
Step 1: Create the Artisan Command
Let’s start by generating the Artisan command using Laravel’s built-in make:command
feature:
php artisan make:command ExtractLangText
This creates a new command file located in app/Console/Commands/ExtractLangText.php
.
Step 2: Write the Command Logic
Now, let’s implement the command logic. We want the command to:
- Accept a locale (e.g.,
ms
for Malay) as an argument. - Optionally allow users to provide a custom output path for the JSON file (defaulting to
base_path('/lang')
). - Scan through the application directories (e.g.,
app
,routes
, andresources/views
) to find all occurrences of the__()
helper. - Write the extracted strings into a locale-specific JSON file.
Here’s the full command code:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
class ExtractLangText extends Command
{
// Define the command signature to accept a locale argument and an optional path
protected $signature = 'lang:extract {locale} {path?}';
protected $description = 'Extract all text within the __() helper and output to the /lang/{locale}.json file or a custom path';
// Execute the command
public function handle()
{
// Get the locale and optional output path from the command arguments
$locale = $this->argument('locale');
$path = $this->argument('path') ?: base_path('lang'); // Default to base_path('/lang') if no path is provided
// Ensure the directory exists
if (! is_dir($path)) {
mkdir($path, 0755, true);
}
$outputFile = $path."/$locale.json";
if (file_exists($outputFile) && ! $this->confirm("$outputFile already exists. Are you sure want to overwrite it?")) {
return;
} else {
unlink($outputFile);
$this->components->info("$outputFile removed.");
}
// Find all files in app, routes, and resources/views directories
$directories = [
base_path('app'),
base_path('routes'),
base_path('resources/views'),
];
$translations = [];
foreach ($directories as $directory) {
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
foreach ($files as $file) {
if ($file->isFile() && in_array($file->getExtension(), ['php', 'blade.php'])) {
$content = file_get_contents($file->getPathname());
// Regex to find all instances of __()
preg_match_all("/__\(\s*[\'\"](.*?)[\'\"]\s*\)/", $content, $matches);
// Store the results
foreach ($matches[1] as $key) {
if (! isset($translations[$key])) {
$translations[$key] = $key; // Initial extraction without translation
}
}
}
}
}
ksort($translations);
// Write translations to a JSON file in the target directory
file_put_contents($outputFile, json_encode($translations, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
$this->components->info("Translations extracted successfully and saved to $outputFile");
}
}
Step 3: How the Command Works
-
Locale Argument: The
locale
argument is mandatory and will determine the name of the output file (e.g.,ms.json
for Malay translations). -
Path Argument: The
path
argument is optional and allows you to specify where the output JSON file should be saved. If no path is provided, it defaults tobase_path('lang')
. -
Directory Scanning: The command scans through the
app
,routes
, andresources/views
directories, searching for all instances of the__()
helper. -
Regex Matching: A regular expression is used to extract the text within the
__()
helper. - JSON Output: The extracted text is saved in a JSON file, where the keys are the translatable strings and the values are initially set to the same strings. This file can then be manually updated or passed to translators for localization.
Step 4: Running the Command
To use the command, you can run it like this:
-
Using Default Path (
base_path('lang')
):
php artisan lang:extract ms
This will create a file at base_path('lang/ms.json')
containing all the extracted translatable strings.
- Using Custom Path:
If you need to specify a different path (for example, resources/lang
for older Laravel versions), you can do so:
php artisan lang:extract ms resources/lang
This will create the file at resources/lang/ms.json
.
Example JSON Output
The output file will look something like this:
{
"Active": "Active",
"Inactive": "Inactive",
"You have successfully updated the record.": "You have successfully updated the record.",
"Welcome": "Welcome",
"Dashboard": "Dashboard"
}
You can then translate the values as needed.
Why This Command is Useful
- Efficiency: Instead of manually combing through your files, this command automates the extraction of all translatable strings.
- JSON Format: Since Laravel supports JSON-based translation files, this command outputs the strings directly in JSON format, making it easy to integrate with Laravel’s localization system.
- Customizable Output: By allowing users to specify the output path, this command works for both newer and older Laravel projects that might have different default language directories.
Conclusion
With this custom Artisan command, you can now easily automate the extraction of translatable strings from your Laravel application. Whether you're preparing your app for a single language or multiple locales, this tool simplifies the process, saving you valuable time.
Feel free to extend this solution, customize it to fit your workflow, or even share it with your team to enhance your localization efforts!
I hope this tutorial helps you streamline the localization process in your Laravel projects. If you have any questions or suggestions, feel free to drop a comment below!
Happy coding! 🎉
Posted on October 15, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.