Laravel Gemini AI Translation Synchronization Tool Documentation
π 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 or --refresh to re-translate existing.
High Performance
Features a fork driver for lightning-fast parallel
processing with configurable --concurrency, and a
stable sync driver. Now with full
support for Windows and non-interactive CI/CD environments.
Production-Ready Safety
Atomic file writes with path validation, framework translation bootstrapping, and --dry-run mode for safe previews.
π Installation
Step 1: Install via Composer
composer require jayesh/laravel-gemini-translator
Step 2: Publish Configuration
php artisan vendor:publish --provider="Jayesh\LaravelGeminiTranslator\TranslationServiceProvider"
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
Three Operational Modes
The tool offers three distinct operational modes:
1. Normal Mode (Default)
Translates all keys, both existing and new. This is the default behavior.
2. Skip-Existing Mode
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
3. Refresh Mode
To re-translate only existing keys without adding new ones, use the --refresh flag.
# Re-translate only existing keys in Spanish and German
php artisan translations:extract-and-generate --refresh --langs=es,de
Note: --refresh and --skip-existing cannot be used together.
π§© 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." |
β¨ New in v4.0.1: Intelligent Fallbacks
The tool no longer generates useless placeholders like "NEEDS TRANSLATION". If the AI fails to provide a translation for
a
key, the system now uses this intelligent fallback logic:
- It first looks for an existing English translation for that key in your language files.
- If none is found, it uses the key itself as the placeholder text.
This ensures your generated files are always usable and immediately show you the source text that needs attention, dramatically speeding up the manual review process.
β¨ New in v4.0.1: Placeholder Mismatch Detection
Added robust placeholder validation with count checking instead of just presence. This ensures:
- Source text placeholders like
:attribute,:count,{0},{name}are preserved in translations - Count mismatches are detected and the source text is used as fallback to prevent runtime errors
- Translation quality is maintained across all language families
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).
Default is en (used as
source).
|
--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. |
--concurrency |
Number of concurrent processes when using fork driver. Default: 15. |
--refresh |
Re-translate only existing keys from lang directories; do NOT generate translations for new/missing keys. |
--dry-run |
Run full extraction + mapping but show what files would be modified without writing anything. |
--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."
Automated Run in a CI/CD Pipeline
# This command runs non-interactively, great for a GitHub Action.
# It skips prompts, consolidates modules, and only syncs missing Spanish keys.
php artisan translations:extract-and-generate --langs=es --skip-existing --consolidate-modules
Dry Run to Preview Changes
# Preview what would be changed without writing any files
php artisan translations:extract-and-generate --dry-run --langs=es,fr
Refresh Only Existing Translations
# Only re-translate existing keys, ignore new keys found in code
php artisan translations:extract-and-generate --refresh --langs=es,fr
Custom Concurrency for High-Performance
# Control the number of concurrent processes when using fork driver
php artisan translations:extract-and-generate --driver=fork --concurrency=20
π§ 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. |
| "Configuration value must be an integer, string given" | The config/gemini.php file has incorrect type
casting for request_timeout. |
Edit config/gemini.php and change:'request_timeout' => (int) env('GEMINI_REQUEST_TIMEOUT', 600),Not: env('GEMINI_REQUEST_TIMEOUT', 600)
(without cast)
|
| "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. |
| The command ran automatically without asking me any questions. | You are running in a non-interactive environment (like a CI/CD pipeline, Docker, or Git Bash on Windows). | This is the new intended behavior for automation. The tool automatically
proceeds
without prompts. If you need to limit the scope, use flags like --skip-existing. |
| All my PHP translation arrays were reordered after running the command. | This is an intentional, one-time change in v4.0.1 | The tool now performs a recursive sort on all PHP arrays to ensure a stable, deterministic order. This makes future code reviews (diffs) much cleaner. You should commit this one-time change. |
| "You cannot use --refresh and --skip-existing together" | You tried to use both --refresh and --skip-existing flags together. |
These modes are mutually exclusive. --refresh
only re-translates existing keys, while --skip-existing only adds missing keys. |
β 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: What are the different operation modes available?
A: The tool offers three distinct operation modes:
- Normal Mode: Full sync - translates all keys both new and existing
- Skip-Existing Mode: Only translate missing keys (
--skip-existing) - Refresh Mode: Only re-translate existing keys (
--refresh)
--refresh and --skip-existing cannot be used together.
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 is dry-run mode?
A: Dry-run mode (--dry-run) allows you to
preview all changes without actually writing any files to disk. It will scan, map, and process
all translations but show you what would be modified without making any changes.
Q: What happens if the AI translation fails for a chunk?
A: The tool is now much more resilient. Instead of leaving a useless
placeholder, it
uses an intelligent fallback: it will use your existing English source text for the key, or the
key
itself if no source text is found. Any keys that consistently fail after all retries are still
logged to failed_translation_keys.json for your review, but your application's
language
files will remain functional.
π 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.