📋 Overview
The Laravel Gemini AI Translation Extractor is a powerful Artisan command that revolutionizes the localization process for Laravel applications. It combines intelligent key extraction with AI-powered translation to dramatically speed up the creation and maintenance of multi-language applications.
Smart Key Detection
Scans Blade, PHP, Vue, JS, and TypeScript files using precise regular expressions to find translation keys across your entire codebase.
Context-Aware AI
Leverages Google's Gemini AI and an optional --context
flag
to provide high-quality, domain-specific translations.
High Performance
Features a fork
driver for Linux/macOS enabling
lightning-fast parallel processing, and a stable sync
driver for Windows compatibility.
Interactive & Incremental
An interactive interface lets you choose which files to process, while the --skip-existing
flag allows for efficient incremental
updates.
🚀 Installation
Step 1: Install via Composer
For Linux, macOS, or WSL users:
composer require jayesh/laravel-gemini-translator
pcntl
extension, you must use the following command to ignore it
during installation:
composer require jayesh/laravel-gemini-translator --ignore-platform-reqs=ext-pcntl
Step 2: Publish Configuration
php artisan gemini:install
This creates the config/gemini.php
file.
Step 3: Add API Key
Add your Gemini API key to your .env
file. You can get a key from
the Google AI Studio.
GEMINI_API_KEY="YOUR_GEMINI_API_KEY"
⚙️ Configuration
Environment Variables
Add these variables to your .env
file:
GEMINI_API_KEY="YOUR_GEMINI_API_KEY"
GEMINI_REQUEST_TIMEOUT=600
Getting Your API Key
1. Visit Google AI Studio
2. Sign in with your Google account
3. Create a new API key
4. Copy and paste it into your .env
file
Configuration File
The config/gemini.php
file allows you to customize:
- AI model selection (default: Gemini 2.0 Flash-Lite)
- Request timeout settings
- Default language preferences
- Retry logic parameters
🎯 Usage
Basic Command
Simply run the command to start the interactive process.
php artisan translations:extract-and-generate
Platform-Specific Recommendations
For the best experience, specify a driver based on your operating system.
# Linux/macOS/WSL (fastest performance)
php artisan translations:extract-and-generate --driver=fork
# Windows (maximum stability)
php artisan translations:extract-and-generate --driver=sync
Incremental Updates
To add new translations without overwriting existing ones, use the --skip-existing
flag. This is perfect for ongoing projects.
# Only translate missing keys for Spanish and German
php artisan translations:extract-and-generate --skip-existing --langs=es,de
The Interactive Process
The command guides you through a seamless workflow:
- Scanning: Searches your project for translation keys based on supported patterns.
- File Selection: Prompts you to choose which translation file groups (e.g., `messages.php`, `auth.php`, JSON file) you wish to process.
- Analysis: Reports which keys are missing in your target languages.
- Translation: Sends key chunks to Gemini AI with a real-time progress bar.
- File Generation: Writes the new or updated translations to the correct language files.
q
' key at any time during
translation to gracefully stop the process. All completed translations up to that point will be
saved.
💡 Context-Aware Translations
Providing project-specific context is one of the most powerful features for achieving high-quality, accurate translations. It helps Gemini resolve ambiguity for words that have different meanings in different domains.
The Problem of Ambiguity
Without context, an AI might misinterpret terms. For example:
Term | General Meaning | Domain-Specific Meaning |
---|---|---|
Position | A physical location | A financial holding (Finance) |
Security | Safety or protection | A tradable financial asset (Finance) |
Cloud | A white puff in the sky | Cloud computing infrastructure (Tech) |
Container | A box or receptacle | A Docker container (Tech) |
The Solution: The --context
Flag
Use the optional --context
flag to guide the AI, ensuring it uses
the correct terminology for your project's domain.
Example: Financial Application
Imagine you are translating for a stock trading platform.
# Without context, translations may be generic or wrong.
php artisan translations:extract-and-generate --langs=ar
# With correct context, translations are precise.
php artisan translations:extract-and-generate --langs=ar \
--context="A SaaS platform for financial trading of stocks. Terms like 'position' and 'security' refer to financial concepts."
Example: Children's Storybook vs. DevOps
This shows how context prevents nonsensical translations. The source text is from a children's story.
# Wrong Context: Telling the AI it's a tech tool.
php artisan translations:extract-and-generate --langs=ar \
--context="A CI/CD pipeline monitoring tool for DevOps that uses Docker containers."
# AI might incorrectly translate "The wooden container" to "The wooden Docker container".
# Correct Context: Telling the AI it's a storybook.
php artisan translations:extract-and-generate --langs=ar \
--context="A children's storybook. The language should be simple and whimsical."
# The AI will now correctly translate "container" as a simple box.
Best Practices for Writing Context
- Be Specific: Mention the industry (e.g., "Healthcare", "Legal", "E-commerce").
- Define Ambiguous Terms: Explicitly state what key terms mean in your domain.
- Describe the Tone: Mention the target audience (e.g., "for professional lawyers," "for young children," "formal and corporate").
🔧 Command Options
Option | Description |
---|---|
--langs |
Comma-separated language codes to translate to (e.g., es,fr,de ). |
--driver |
Concurrency driver: fork (fast, for Linux/macOS) or
sync (stable, for Windows). |
--skip-existing |
A flag to only find and translate keys that are missing from target language files. |
--context |
Provide a project-specific description to Gemini for more accurate, domain-aware translations. |
--chunk-size |
Number of keys to send to the AI in a single request. Default: 100. |
--source |
The root directory of the application to scan for keys. Default: ".". |
--target-dir |
Root directory for the final Laravel translation files. Default: "lang". |
--exclude |
Comma-separated directories to exclude from the scan. |
--extensions |
Comma-separated file extensions to search within. |
--max-retries |
Maximum number of retries for a failed API call. Default: 5. |
--retry-delay |
Base delay in seconds between retries (uses exponential backoff). Default: 3. |
💡 Usage Examples
Basic Translation
# Translate to Spanish, French, and German
php artisan translations:extract-and-generate --langs=es,fr,de
High-Performance Processing
# Use fork driver with smaller chunks for faster processing
php artisan translations:extract-and-generate --driver=fork --chunk-size=50
Selective File Processing
# Only scan Blade files and exclude additional directories
php artisan translations:extract-and-generate \
--exclude=vendor,tests,docs,storage \
--extensions=blade.php
Incremental Updates
# Only translate missing keys, skip existing ones
php artisan translations:extract-and-generate \
--skip-existing \
--langs=es,fr
Context-Aware Translation
# Provide context for a healthcare application
php artisan translations:extract-and-generate \
--langs=es,fr \
--context="A patient management system for hospitals. 'Discharge' means patient release, 'case' means patient case."
🚀 Advanced Usage
Example Output
Fork Driver Output (Linux/macOS)
┌ Which translation files would you like to process? ────────┐
● messages.php
○ auth.php
● Root JSON file
└────────────────────────────────────────────────────────────┘
Press the 'q' key at any time to gracefully stop the process.
⚡ Using 'fork' driver for high-performance concurrency.
📊 Total keys to translate: 156
📦 Total chunks to process: 2
🚀 156/156 [============================] 100% -- ✅ Chunk 2/2 - SUCCESS (156 keys) ⏱️ 18s
╔═ 💾 Phase 3: Writing Language Files ═════════════════════════════╗
✅ Wrote: lang/es.json (78 total keys)
✅ Wrote: lang/es/messages.php (78 total keys)
✅ Wrote: lang/fr.json (78 total keys)
✅ Wrote: lang/fr/messages.php (78 total keys)
Sync Driver Output (Windows)
┌ Which translation files would you like to process? ───────────────┐
● Root JSON file
└───────────────────────────────────────────────────────────────────┘
🐌 Running in synchronous mode - this will be slower but more stable!
Processing file: __JSON__
-> Processing keys 1-100 of 222... ✓ Done
-> Processing keys 101-200 of 222... ✓ Done
-> Processing keys 201-222 of 222... ✓ Done
╔═ 💾 Phase 3: Writing Language Files ═══════════════════════════════════════╗
✅ Wrote: lang/es.json (222 total keys)
✅ Wrote: lang/fr.json (222 total keys)
Generated File Structure
The command intelligently organizes translations based on Laravel conventions:
lang/
├── es/
│ ├── auth.php
│ └── messages.php
├── fr/
│ ├── auth.php
│ └── messages.php
├── es.json
└── fr.json
Supported Functions & Patterns
The scanner is pre-configured to find keys used in the most common Laravel and JavaScript localization functions.
Pattern | Example | Typical Context |
---|---|---|
__() , trans() , @lang() |
__('messages.welcome') |
PHP & Blade |
trans_choice() , @choice() |
trans_choice('messages.apples', 5) |
PHP & Blade (Pluralization) |
$t() , i18n.t() |
$t('user.profile') |
Vue.js, JavaScript (i18n Libraries) |
v-t , x-text |
<span v-t="'buttons.submit'"> |
Vue.js & Alpine.js Directives |
Logging & Debugging
For transparency and debugging, the command creates two log files in your project root:
translation_extraction_log.json
: A detailed log of every unique key found and the file paths where it was located.failed_translation_keys.json
: A list of any keys that failed to be translated by the AI, so you can easily retry them.
🔧 Troubleshooting
Error / Issue | Common Cause | Solution |
---|---|---|
"Invalid API key" | The GEMINI_API_KEY in your .env file is incorrect or missing. |
Verify the key is correct and has no extra spaces. Run php artisan config:cache after changes. |
"Quota exceeded" or "Rate limit" errors | The free tier API limit (e.g., 30 requests/minute) has been reached. |
Lower the chunk size with --chunk-size=25 and/or wait a
few minutes before retrying.
|
"Call to undefined function pcntl_fork()" | You are trying to use --driver=fork on an environment
without the pcntl PHP extension (like standard
Windows). |
Use the stable driver: --driver=sync . |
Script hangs or runs very slowly | Processing a very large number of keys with the sync
driver. |
Be patient, as sync mode is sequential. For large projects, use the fork driver on Linux/macOS/WSL if possible. |
"Invalid JSON response from Gemini" | A rare API issue where the response is not valid JSON, or a network interruption. | The built-in retry logic usually handles this. If it persists, try reducing the --chunk-size . |
❓ Frequently Asked Questions
Q: Can I use this with existing translation files?
A: Yes! Use the --skip-existing
option to only translate missing keys
while preserving your existing translations. The command will merge new translations with your
existing files.
Q: How accurate are the AI translations?
A: Gemini AI provides high-quality translations, but we always recommend a final
review before deploying to production, especially for critical user-facing content or nuanced
language. Using the --context
flag dramatically improves accuracy
for domain-specific projects.
Q: What happens if the translation fails?
A: The command has built-in retry logic with exponential backoff. If a key
consistently fails, it is logged in failed_translation_keys.json
in your project root,
so you can review and handle it manually.
Q: Is this suitable for production applications?
A: Absolutely. It's designed to be a powerful developer tool to accelerate the localization workflow. By using it in development and staging, then committing the generated files, you can safely deploy them to production after a review.
📋 Contributing & Support
How to Contribute
- Report bugs and request features via GitHub Issues.
- Submit pull requests for improvements.
- Star the repository if you find it useful.
Support
If you encounter issues, please check the troubleshooting section first. If the problem persists, create a new issue on GitHub with detailed information, including your OS, PHP version, and the exact command used.