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.
Everything below is new since v5.0.1.
/translations-manager (prefix, enable flag, and middleware are configurable). Routes and JSON APIs register automatically: data, languages, existing map, scan, save, add-languages. Guests must sign in when the host already has login/register/sign-in routes (browser redirect or JSON 401 + unauthenticated view). If the host has no auth routes, the manager is open. Publish tags: gemini-translator-config, gemini-translator-views, gemini-translator-assets, gemini-translator-manager. ManagerViewComposer inlines CSS/JS so the page works without publishing assets. Optional [@include](https://github.com/include)('gemini-translator::partials.workspace') for an existing layout. Writes name the PHP process user in errors (not a hard-coded www-data). Add-languages continues if one lang tree writes and another is not writable.<dialog> / <search> / popover, light/dark theme (localStorage key gemini-translator-theme), sticky KEY column, pagination footer (default 5 rows, last two pages always visible with an ellipsis; pager labels are not taken from lang/{locale}/pagination.php), Type / Module / Pack / Scope / PHP-files / Language / “show only missing” / Highlight script faults filters, Add Languages, Sync, Save. Checkboxes use a ✓ mark on the monochromatic tokens (sun stays yellow, Save stays green).gemini-translator-malform-detector). Uses LocaleHelper::detectorCatalog() / malformReasons(). Flags letters that do not belong to the cell’s locale — including Latin inside Gujarati/Hindi/etc. Placeholders (:name, {0}, [2,*]) and Common marks (danda ।) are ignored. Faulty editors get an amber outline/background and a tooltip of the unexpected scripts. Stricter than the CLI hasDisallowedScript() check, which still allows Latin in native scripts.lang/app3/ and lang/web/ are first-class trees, separate from lang/. A 2–3 letter folder name (web) is a pack when it holds locale JSON or locale dirs, not a locale. Nested PHP such as foo/bar.php stays on the root pack unless the first segment is a known pack. The manager Pack filter appears only after you select a module (or Non-module) that actually has more than one pack. PHP file pickers list files from the selected pack. A selected language lists only keys that exist in that locale file.loadJsonTranslationsFrom() / loadTranslationsFrom() directories (for example base_path('custom_dir')) and published resources/lang/modules/{name} (published copy wins on the same key). Composer vendor/ lang trees are skipped.translations:extract-and-generate asks which packs to process. The JSON/PHP file list is then limited to those packs. Modules with only lang/ skip the prompt. Pack PHP files load and write as lang/{pack}/{locale}/messages.php.LanguageCatalog) with display names and fallbacks (zh → zh_CN, pt → pt_BR, pa → pa_GURU, and similar). Short file codes still resolve to the primary variant.PromptInterface and TaskRunnerInterface via PlatformFactory on PHP_OS_FAMILY
spatie/fork (pcntl)kernel32.dll FFI console binder + Symfony Process workerssync runner on every OS, with cooperative stop--driver=process: concurrent Symfony Process workers (also used when --driver=fork is selected on Windows)translations:run-payload worker command for Windows/process child jobsext-pcntl (fork) and ext-ffi (native Windows menus)--refresh-clean: rebuild existing keys only, ignoring stale file wording. Official Laravel English is the source for auth / pagination / passwords / validation (not ucwords of the key)config/gemini-translator.php (as of 2026-08-13). Add, raise, lower, zero, or remove rows when Google changes RPM/RPD. 0 RPM/RPD is “no free-tier budget”, not a crash. GEMINI_TRANSLATOR_APPLY_FREE_TIER_CAPS can turn snapshot caps off--model=, GEMINI_MODEL / GEMINI_TRANSLATOR_MODEL, then config/gemini-translator.php, then config('gemini.model'), then the package default. Paid/ListModels ids are allowed and are not free-tier capped unless listed in the snapshotLocaleHelper (Unicode sc= so shared danda । is Common, not a mix) plus looksUntranslated / disallowed-script checks that reduce mixed-script output (they do not eliminate it). Map now includes Tibetan, N’Ko, Tifinagh, Ol Chiki, Meitei, Canadian Aboriginal, extra Devanagari/Cyrillic/Arabic catalog codes, and script tags (_latn, _cyrl, _arab, _deva, _guru, _hans/_hant, _tfng, _olck, _syll)PHP_OS_FAMILY inside the command/services--driver=fork on Windows runs Process workers instead of silently falling back to sync--refresh is the original refresh again: existing keys only, current file wording is the sourcegemini-3.5-flash-lite (15 RPM / 500 RPD in the snapshot and present in ListModels). Snapshot rows for ids missing from ListModels (gemini-2.5-flash-exp, gemini-3-flash) were removedmessages.welcome, validation.required) when that group is selected. Blank literal JSON values are filled from the key; empty/whitespace source is treated as missingprocessed_chunks from the translation runnerlang/{pack}/{file}.phpೋ, Hindi + Gujarati, leftover English in Indic locales). It does not eliminate those cases; some mixed or leftover-English rows can still be writtenfile.subkey keys that belong to a PHP lang group as JSON keys when that PHP group is also in playarray_keys of a list)driftingly/rector-laravel plus rector:dry / rector:debug composer scriptsSleep::usleep(), sprintf(), strict comparisons)declare(strict_types=1) to all PHP files for type safetyLocaleHelper and TextHelper utilitiesCommandRegistration, ServiceProvider, ScannerService, and FileSystemServiceempty() with explicit array/string comparisons (=== [], !== [])in_array(): Added true parameter for strict type checking(int) casts for chunk-size, retry-delay, and concurrency optionsALL_FILES_KEY, ALL_TARGETS_KEY, FILE_KEY_SEPARATOR)usleep() calls to use int instead of floatlang/{locale}) during JSON-only runs.auth.php, pagination.php, passwords.php, validation.php) when only JSON File (*.json) groups are selected.en.json, hi.json, etc.) without forcing PHP file creation.buildTranslationTasks() and staticTranslateKeysWithGemini()config/gemini.php type casting requirement--source option in favor of interactive target selection--no-advanced pattern detection option--dry-run is usedNew Operational Modes
--refresh flag: Re-translate only existing keys from language directories; do NOT generate translations for new/missing keys--dry-run flag: Run full extraction + mapping but show what files would be modified without writing anything--concurrency=N option: Configure number of concurrent processes when using fork driver (defaults to 15)Enhanced Locale & Translation Quality
LocaleHelper utility class with locale canonicalization, script type detection, and humanization ruleslooksMachineKey() detection with comprehensive pattern matching for PascalCase, snake_case, kebab-case, and dot.notationlooksMachineKey() with fast-path checks for common patterns combined with robust regex validationFramework Integration
New Extractor Features
:v-t, :x-text, v-bind:v-t, v-bind:x-text)/s (PCRE_DOTALL) modifierx-text="__('messages.hello')")AI Translation Improvements
withSystemInstruction() from Gemini PHP SDK v2.0Command Signature
--source option--no-advanced option--langs to clarify English is used as sourceTranslation Flow
--refresh and --skip-existing togetherLocaleHelper::canonicalize()File Writing
array() to [] in generated translation filesConcurrency Handling
--concurrency optionError Handling
Critical Security & Safety
Translation Logic
Module Support
Regex Extraction
/s modifierUser Interface & Selection
Memory Optimization
$sourceTextMap to each closureConcurrency Improvements
--source option (now unused, was for deprecated interactive scanning)--no-advanced option (advanced pattern detection removed as it caused false positives)--refresh and --dry-run modes enables safer integration into deployment pipelinesHow can I help you explore Laravel packages today?