nativecodein/laravel-translation-scanner
## Getting Started
### Minimal Steps
1. **Installation**:
```bash
composer require nativecodein/laravel-translation-scanner
No additional configuration is required—auto-discovery handles the service provider.
First Scan: Run the scanner to extract all translation strings from your project:
php artisan translations:scan
This will:
.php, .blade.php, .js, .ts, .jsx, and .tsx files.resources/lang/en.json with the key as the default value.vendor/, node_modules/, etc.).First Use Case: After scanning, use the extracted translations in your code:
// Blade
{{ __('Dashboard') }}
// PHP
return trans('Welcome Back');
// Inertia React (TSX)
t("Login");
Scanning:
translations:scan into your CI/CD pipeline (e.g., GitHub Actions) to ensure translations are always up-to-date.git add .
composer require nativecodein/laravel-translation-scanner
php artisan translations:scan
git commit -m "feat: add translations for new dashboard"
Translation Generation:
translations:translate to generate translations for target locales (e.g., Spanish, Arabic):
php artisan translations:translate es ta ar
// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
$schedule->command('translations:translate es ta ar')->weekly();
}
Inertia.js Integration:
t() calls are consistent:
// Good: Direct string
t("Settings")
// Good: Template literal
t(`Welcome, ${user.name}`)
// Good: Variable (scanner resolves it)
const key = "Dashboard";
t(key)
t(user.customKey)) unless you handle them via custom logic.Blade/PHP Patterns:
__() for static strings and trans() for dynamic keys with replacements:
// Static
__('Homepage')
// Dynamic (with replacements)
trans('Welcome back, :name!', ['name' => $user->name])
{{ __('Post :count', ['count' => $posts->count()]) }}
Testing:
php artisan translations:scan --dry-run
public function test_translations_are_scanned()
{
$this->artisan('translations:scan')
->expectsOutputToContain('Added: Dashboard');
$this->assertFileExists(database_path('lang/en.json'));
}
Dynamic Keys:
t(user.key). Workaround:
t(user.key) with t(user.key || 'fallback') in your JS/TS.False Positives:
t as a variable name). Exclude files/folders via:
php artisan translations:scan --exclude=path/to/file.js
const t = 'temp' → const temp = 'temp').Locale-Specific Issues:
key.with.dots) may cause parsing issues in some translation APIs. Sanitize keys:
// In a custom provider
$key = preg_replace('/[^a-zA-Z0-9._-]/', '_', $key);
API Rate Limits:
usleep(300000) delay (configurable in the package).php artisan translations:translate es --cache
Inertia.js Edge Cases:
t({ key: variable }) are not supported. Use:
t(variable) // Supported
t() calls (e.g., in useEffect) may not be scanned. Ensure strings are defined as constants first.Merge Conflicts:
en.json but may conflict with manual edits. Use:
php artisan translations:scan --force # Overwrites en.json (use with caution)
en.json separately from code changes to avoid merge hell.Dry Run:
php artisan translations:scan --dry-run
Verbose Mode:
php artisan translations:scan -v
Custom Paths:
php artisan translations:scan --path=app/Http/Controllers --path=resources/js
Provider Debugging:
php artisan translations:translate es --provider=google
debug flag to see API responses:
php artisan translations:translate es --debug
Custom Providers:
php artisan vendor:publish --provider="NativeCodeIn\TranslationScanner\TranslationScannerServiceProvider" --tag="config"
NativeCodeIn\TranslationScanner\Contracts\TranslationProvider:
class DeepLProvider implements TranslationProvider {
public function translate(string $text, string $locale): string {
// Custom DeepL API logic
}
}
config/translation-scanner.php:
'providers' => [
'deepl' => \App\Providers\DeepLProvider::class,
],
Pre/Post-Scan Hooks:
translations.scanned event to process results:
// app/Providers/EventServiceProvider.php
protected $listen = [
'NativeCodeIn\TranslationScanner\Events\TranslationsScanned' => [
\App\Listeners\ProcessTranslations::class,
],
];
public function handle(TranslationsScanned $event) {
foreach ($event->newKeys as $key) {
Log::info("New translation key: $key");
}
}
Excluding Keys:
.translationignore file:
# .translationignore
/^internal\./
/^temp\./
--ignore flag:
php artisan translations:scan --ignore="internal.*"
Post-Processing:
translations:scan output to generate TypeScript types for your translations:
php artisan translations:scan | grep 'Added:' | awk '{print "const " $2 " = \"" $2 "\";"}' > resources/js/translations.d.ts
Incremental Scanning:
php artisan translations:scan --path=resources/views
--changed to scan only modified files (requires Git):
php artisan translations:scan --changed
Parallel Processing:
// app/Console/Commands/ScanTranslations.php
public function handle() {
$files =
How can I help you explore Laravel packages today?