om/potrans
Laravel package for managing translations with import/export tools and a simple UI/API. Helps keep language files in sync, edit keys/values, detect missing strings, and streamline localization workflows across your app.
Lang facade, config/translation.php) integration..po/.pot/.mo files, not Laravel’s JSON/array-based translations. Requires manual sync between Laravel’s resources/lang and Gettext files.cache.forget('translations')).symfony/console:^7.0|^8.0; Laravel 10+ uses Symfony 6.4. High risk of breaking Laravel core if forced to upgrade.translated, translation.failed) or service container binding for Laravel’s translation pipeline..po/.mo files in resources/lang or a custom directory, with no automatic sync to Laravel’s translation loader.symfony/process, symfony/console (v6.x), or laravel/framework..env files in the working directory, not Laravel’s config/services.php or .env auto-loading. Security risk if keys are exposed in CI/CD.~/.potrans) may conflict with Laravel’s storage/framework/cache. No built-in invalidation for Laravel’s translation cache.Translation Sync Strategy:
.po/.mo files map to Laravel’s resources/lang structure? Will you use a custom loader (e.g., GettextLoader) or manual file watches?potrans’s cached API responses?CI/CD Pipeline:
potrans commands run (pre-commit, build, or deploy)? How will you trigger them without manual intervention?Fallback Mechanisms:
Performance:
potrans run in parallel for multiple languages, or sequentially? How will this impact build times?Maintenance:
potrans (e.g., Symfony 8.x migration)? Will you fork or submit PRs upstream?Laravel + Gettext Hybrid:
potrans for externalized translations (e.g., vendor docs, third-party strings) stored in .po files, while keeping Laravel’s resources/lang for app-specific translations.AppServiceProvider to auto-load .mo files via a custom GettextLoader (extend Illuminate\Translation\LoaderInterface).// app/Providers/AppServiceProvider.php
public function register()
{
$loader = new GettextLoader(base_path('resources/lang'));
$this->app->singleton('translation.loader', fn() => $loader);
}
CI/CD Pipeline:
potrans to update .po files from source code (via xgettext)..po → .mo using potrans + Google/DeepL..mo files to storage/lang or a CDN.jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: composer install
- run: ./vendor/bin/potrans google resources/lang/messages.pot resources/lang --lang=de --force
- run: msgfmt resources/lang/de/messages.po -o resources/lang/de/messages.mo
Phase 1: Pilot Project
.po files.potrans in a local dev script before committing to CI.php artisan translate:load (custom command) to verify .mo loading.Phase 2: CI/CD Integration
potrans to composer.json scripts:
"scripts": {
"translate:all": "potrans google resources/lang/messages.pot resources/lang --langs=\"de,fr,es\" --force"
}
Artisan::call() to trigger translations from a custom command:
// app/Console/Commands/TranslateCommand.php
public function handle()
{
$exitCode = Artisan::call('potrans:google', [
'source' => 'resources/lang/messages.pot',
'target' => 'resources/lang',
'--langs' => 'de,fr',
'--force' => true,
]);
if ($exitCode !== 0) throw new \RuntimeException('Translation failed');
}
Phase 3: Full Adoption
lang files with .po/.mo for all languages.resources/lang/*.php to .po files.Symfony Conflict Workaround:
potrans (e.g., vendor/bin/potrans in a monorepo) to avoid Symfony version clashes.potrans to v0.0.9 (last Symfony 6.x-compatible release) and pin dependencies:
composer require om/potrans:0.0.9 --dev
composer require symfony/console:^6.4
Laravel Translation Loader:
.mo files with Laravel’s Translator:
class GettextLoader implements LoaderInterface {
public function load($locale, $group, $namespace = null)
{
$path = resource_path("lang/{$locale}/{$group}.mo");
if (!file_exists($path)) return [];
$translations = gettext_translations($path);
return array_map(fn($t) => $t['translation'], $translations);
}
}
Prerequisites:
gettext PHP extension is enabled (php -m | grep gettext)..env or CI secrets:
DEEPL_API_KEY=your_key_here
GOOGLE_TRANSLATE_API_KEY=your_key_here
Initial Setup:
.pot template from source code:
xgettext --default-domain=messages --directory=app --output=resources/lang/messages.pot
.po files for target languages:
msginit --locale=de --input=resources/lang/messages.pot --output-file=resources/lang/de/LC_MESSAGES/messages.po
Translation Workflow:
lang files for active development.potrans to update .po files from source:
./vendor/bin/potrans google resources/lang/messages.pot resources/lang --lang=de --force
.mo files and sync to production:
msgfmt resources/lang/de/LC_MESSAGES/messages.po -o resources/lang/de/LC_MESSAGES/messages.mo
potrans for Symfony 8.x migrations. Plan to fork or patch if Laravel’s Symfony 6.x support ends.gettext PHP extension and `msgHow can I help you explore Laravel packages today?