jayesh/laravel-gemini-translator
Interactive Artisan command to scan Laravel projects for translation keys, translate them via Google Gemini AI, and generate language files. Supports Blade/PHP/JS/Vue/TS, concurrency, safe atomic writes, and Laravel Modules integration with skip/refresh modes.
Installation
composer require jayesh/laravel-gemini-translator
php artisan vendor:publish --provider="Jayesh\GeminiTranslator\GeminiTranslatorServiceProvider" --tag="config"
Configuration
Edit config/gemini-translator.php and set:
gemini_api_key (from Google AI Studio)default_locale (e.g., en)target_locales (e.g., ['es', 'fr'])file_paths (customize scan paths if needed)First Translation Run
php artisan gemini:translate
Follow the interactive prompts to confirm translation keys and locales.
For a new Laravel project with 50+ Blade files:
php artisan gemini:translate --skip-existing --concurrency=4
This skips already-translated keys and uses 4 concurrent requests for faster processing.
Key Extraction
// In a controller/service
$translatableKeys = app(\Jayesh\GeminiTranslator\Scanners\FileScanner::class)
->scan([resource_path('views/*.blade.php')]);
Useful for pre-scanning before running the Artisan command.
Interactive Mode
php artisan gemini:translate --interactive
CI/CD Integration
# .github/workflows/translate.yml
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: composer install
- run: php artisan gemini:translate --refresh --skip-existing
env:
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
Custom Scanners
Extend Jayesh\GeminiTranslator\Contracts\Scanner to handle domain-specific files (e.g., Markdown docs):
class MarkdownScanner implements Scanner {
public function scan(array $paths): array {
// Custom logic
}
}
Post-Translation Hooks
Use the translated event:
// In EventServiceProvider
protected $listen = [
'Jayesh\GeminiTranslator\Events\TranslationGenerated' => [
\App\Listeners\NotifyTranslationTeam::class,
],
];
Batch Processing For large projects, split by file type:
php artisan gemini:translate --paths="resources/views" --concurrency=2
php artisan gemini:translate --paths="resources/lang" --mode=refresh
API Rate Limits
GeminiApiException: Quota exceeded--delay=2 to introduce 2-second delays between requests or increase concurrency cautiously (default: 1).File Permission Issues
FileNotWritableException in lang/ directorystorage:link is run and lang/ is writable:
chmod -R 775 resources/lang
Key Context Loss
"Save" vs. "Save Draft")--context-depth=2 flag to include surrounding lines in the prompt.Windows Path Handling
InvalidArgumentException with Windows paths--driver=sync or configure file_paths with forward slashes:
'file_paths' => [
'resources/views/{*.blade.php,*.php}',
],
Dry Run Mode
php artisan gemini:translate --dry-run
Lists keys without sending to Gemini.
Verbose Logging
php artisan gemini:translate --verbose
Shows raw API responses and scanner details.
API Key Validation Test connectivity first:
php artisan gemini:test-connection
Custom Prompt Templates
Override GeminiTranslatorServiceProvider::boot() to modify the prompt:
$this->app->singleton('gemini.prompt', function () {
return "Translate the following Laravel translation key with context:
**Key**: {key}
**Context**: {context}
**Target Locale**: {locale}
**Rules**:
1. Keep length under 50 chars if possible.
2. Preserve original meaning and tone.
3. Use Laravel’s translation conventions.";
});
Post-Processing Filters
Use the translation.filter event to sanitize or transform translations:
event(new TranslationFilterEvent($key, $translation, $locale));
Fallback Translations
Configure fallback logic in config/gemini-translator.php:
'fallbacks' => [
'es' => 'en', // Spanish falls back to English
'custom' => function ($key, $locale) {
return "Fallback for {$key} in {$locale}";
},
],
--verbose.file_paths.php artisan cache:clear
How can I help you explore Laravel packages today?