π Overview
The Laravel Gemini AI Translation Synchronization Tool is a powerful Artisan command that revolutionizes the localization workflow for modern Laravel applications, including those built with nwidart/laravel-modules. It goes beyond simple key extraction by discovering keys from all sourcesβyour code, existing language files, and the frameworkβand then intelligently synchronizes them across all target languages using Gemini AI.
Full Module Support
Scans are correctly isolated between the main app and modules. A new feature also lets you choose to keep module translations separate or consolidate them into the main `lang` directory.
AI-First Translation
Trusts the AI to interpret both namespaced keys (e.g., messages.welcome) and literal strings to generate accurate,
                            context-aware translations.
True Synchronization
Discovers keys from your code and existing files to create a complete picture, ensuring no
                            translation is left behind. Use --skip-existing to only add
                            missing keys.
High Performance
Features a fork driver for lightning-fast parallel
                            processing on Linux/macOS/WSL, and a stable sync driver for
                            Windows.
π Installation
Step 1: Install via Composer
composer require jayesh/laravel-gemini-translator
                Step 2: Publish Configuration
php artisan vendor:publish --provider="Gemini\Laravel\GeminiServiceProvider"
                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"
                GEMINI_API_KEY, it will automatically switch to Offline Mode,
                    generating placeholder files so your application doesn't break.
                βοΈ 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 (e.g., Gemini 2.5 Flash-Lite)
 - Request timeout settings
 - Default language preferences
 - Retry logic parameters
 
π― Usage
Basic Command
Simply run the command to start the interactive process. It will guide you through selecting which parts of your application and which files to 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 (Synchronization)
To add new translations without overwriting existing ones, use the --skip-existing flag. This is the recommended workflow for ongoing
                    projects.
# Find and translate only the keys that are missing in Spanish and German
php artisan translations:extract-and-generate --skip-existing --langs=es,de
            π§© Module Support (nwidart/laravel-modules)
                The tool is designed from the ground up to support modular applications. Scans are now correctly isolated, so selecting the "Main Application" will not incorrectly scan `Modules/` directories, preventing key contamination.
1. Select Scan Targets
First, you will be prompted to choose which parts of your application to scan.
 β Which parts of the application would you like to scan and process? β
 β Module: Settings                                                   β
 ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
                2. Consolidating Module Translations (New Feature)
If you select any modules, you'll be asked a new question. This gives you full control over your project's structure.
 β Consolidate all module translations into the main application's `lang` directory? β
 β No                                                                                β
 βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
                - Default (No): Translations are kept separate. A key from the `Settings` module is written to `Modules/Settings/lang/en.json`.
 - Consolidate (Yes): All translations, regardless of origin, are written to the main application's `lang` directory (e.g., `lang/en.json`).
 
You can bypass this prompt for automated scripts using the --consolidate-modules flag.
π Advanced Usage & Output
Fork Driver Output (Linux/macOS)
The high-performance `fork` driver shows a real-time progress bar for all keys being processed concurrently.
β
 Key discovery complete! Found 451 unique keys from all sources combined.
Press the 'q' key at any time to gracefully stop the process.
π Total keys needing translation: 7
π¦ Total chunks to process: 2
β‘ Using 'fork' driver for high-performance concurrency.
π 7/7 [============================] 100% -- β
 Chunk 2/2 - SUCCESS (5 keys) β±οΈ     3 s
ββ πΎ Phase 3: Writing Language Files βββββββββββββββββββββββββββββββββββββ
 β
 Updated: lang/en/auth.php (8 total keys)
 β
 Updated: lang/ru/auth.php (8 total keys)
 β
 Updated: lang/uz/auth.php (8 total keys)
                Sync Driver Output (Windows)
The stable `sync` driver processes chunks sequentially and provides feedback for each one, which is ideal for environments that don't support forking.
β
 Key discovery complete! Found 222 unique keys from all sources combined.
 π Running in synchronous mode - this will be slower but more stable!
  -> Processing chunk 1/3... β Done
  -> Processing chunk 2/3... β Done
  -> Processing chunk 3/3... β Failed
     Error: File: __MAIN__::__JSON__, Keys: An unknown error occurred.,... - Error: Syntax error
ββ πΎ Phase 3: Writing Language Files ββββββββββββββββββββββββββββββββββββββββ
  β
 Wrote: lang/es.json (222 total keys)
  β
 Wrote: lang/fr.json (222 total keys)
                Example 1: Updating a Single Module (Separate)
This output shows the workflow for updating only the `Settings` module and keeping its translations separate.
Scanning 1 target(s): Module: Settings
 β Consolidate all module translations into the main application's `lang` directory? β
 β No                                                                                β
 βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
...
Found missing translations needing synchronization:
  File: Module: Settings -> JSON File (web/*.json)
    -> Language 'en' is missing 36 keys.
...
β‘ Using 'fork' driver for high-performance concurrency.
π 36/36 [============================] 100% -- β
 Chunk 1/1 - SUCCESS (36 keys) β±οΈ    12 s
ββ πΎ Phase 3: Writing Language Files βββββββββββββββββββββββββββββββββββββ
 β
 Updated: /.../Modules/Settings/lang/web/en.json (104 total keys)
 β
 Updated: /.../Modules/Settings/lang/web/ru.json (104 total keys)
 β
 Updated: /.../Modules/Settings/lang/web/uz.json (104 total keys)
                Example 2: Updating Only the Main Application
Notice how the scan is now correctly isolated to the main application, even though modules exist in the project.
Scanning 1 target(s): Main Application
Reading existing language files from selected targets...
...
Found missing translations needing synchronization:
  File: Main Application -> JSON File (web/*.json)
    -> Language 'en' is missing 34 keys.
...
π 34/34 [============================] 100% -- β
 Chunk 1/1 - SUCCESS (34 keys) β±οΈ    12 s
ββ πΎ Phase 3: Writing Language Files βββββββββββββββββββββββββββββββββββββ
 β
 Updated: /.../lang/web/en.json (485 total keys)
 β
 Updated: /.../lang/web/ru.json (485 total keys)
 β
 Updated: /.../lang/web/uz.json (485 total keys)
                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 in your *code* 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.
π‘ AI-First Translation
This tool adopts an "AI-First" philosophy. Instead of trying to pre-process translation keys into human-readable text (which can be buggy), it trusts the AI to correctly interpret the keys based on Laravel conventions.
How the AI Interprets Keys
The prompt sent to Gemini is specially designed to handle two types of keys:
| Key Type | Example Key | AI's Interpretation | 
|---|---|---|
| Namespaced (PHP-style) | auth.failed | 
                                "Based on Laravel conventions, this means an authentication failure. I will generate 'These credentials do not match our records.'" | 
| Literal (JSON-style) | Save Changes | 
                                "This is a literal string. I will translate 'Save Changes' directly." | 
Improving Accuracy with the --context Flag
                For domain-specific terms, you can guide the AI with the --context
                    flag. This is crucial for avoiding ambiguity.
# For a financial trading app, this context ensures accuracy.
php artisan translations:extract-and-generate \
--context="A SaaS platform for financial trading. 'Position' and 'security' refer to financial assets."
            π§ 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. Ideal for updates. | 
--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: 25. | 
--source | 
                                (Deprecated) The root directory to scan. The interactive prompt is now preferred. Default: ".". | 
--consolidate-modules | 
                                Consolidate all module translations into the main application's lang directory, skipping the interactive prompt. | 
--target-dir | 
                                Root directory for the translation files within the app/modules. 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
Fresh Translation for a Modular Project
# Generate all translations for the main app and all modules
php artisan translations:extract-and-generate --driver=fork --langs=es,fr
                Synchronize a Single Module (Separate)
# Interactively select only the 'Settings' module.
# When prompted, choose NOT to consolidate.
# This will find and update missing keys only within Modules/Settings/lang/
php artisan translations:extract-and-generate --driver=fork --skip-existing
                Translate All Modules into Main `lang` Directory
# Scan all targets (main app + all modules).
# The --consolidate-modules flag ensures all translations land in the root lang/ dir.
php artisan translations:extract-and-generate --driver=fork --consolidate-modules
                Update Only the Main Application (Ignoring Modules)
# Interactively select ONLY the "Main Application".
# The scanner will now correctly ignore the Modules/ directory.
php artisan translations:extract-and-generate --driver=fork --skip-existing
                High-Performance Synchronization
# Use fork driver with smaller chunks to find and fill only missing keys
php artisan translations:extract-and-generate --driver=fork --chunk-size=25 --skip-existing
                Context-Aware Update for a Specific Module
# Select the 'ECommerce' module, then provide context for its specific terminology
php artisan translations:extract-and-generate --skip-existing \
--context="An e-commerce module. 'Shipment' refers to a package delivery."
            π§ 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. | 
                            
| "Syntax error" from Gemini / Low success rate | The AI's safety filters may have been triggered by a batch of keys, or the model returned a malformed response. | Reduce the chunk size significantly. Try --chunk-size=20 or lower and re-run. Check
                                    `failed_translation_keys.json` for problematic keys. | 
                            
| "Quota exceeded" or "Rate limit" errors | The free tier API limit has been reached. | Lower the chunk size with --chunk-size=25 and/or
                                    wait a few minutes before retrying. The tool has built-in exponential backoff. | 
                            
| "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. | 
                            
| Keys from a module appear in the main app's files. | You selected to consolidate translations either via the prompt or the
                                    --consolidate-modules flag.
                                 | 
                                This is intended behavior when consolidation is active. If you want separate files, re-run the command and choose "No" when prompted about consolidation. | 
β Frequently Asked Questions
Q: How does this handle translations in subdirectories like lang/web/en.json?
                A: Perfectly. The tool recursively scans your `lang` directories (in both the main app and modules). It will detect `web/en.json` and present it in the selection prompt as a distinct file group, for example: `Main Application: JSON File (web/*.json)`. When it writes the files, it will place the translated versions in the correct subdirectories (`lang/web/ru.json`, etc.), preserving your structure.
Q: Can I use this with existing translation files?
A: Yes, and that's its biggest strength! The tool is designed to work with existing
                    projects. It reads all your current language files to build a complete list of every key your
                    application knows about. When you run it with --skip-existing, it
                    will only translate what's missing, perfectly synchronizing your language files while preserving all
                    your existing work.
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 AI translation fails for a chunk?
A: The command has built-in retry logic with exponential backoff. If a chunk of keys
                    consistently fails after all retries, it is logged in failed_translation_keys.json in
                    your project root,
                    so you can review the problematic keys and handle them manually or retry with a smaller chunk size.
                
π Contributing & Support
This project is open-source and maintained by Jayesh Mepani. Contributions are welcome!
How to Contribute
- Report bugs and request features on the GitHub Issues page.
 - Submit pull requests to the repository for improvements.
 - Star the repository on GitHub 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 the GitHub repository with detailed information, including your OS, PHP version, and the exact command used.