gettext/translator
Lightweight PHP translation layer for gettext/gettext. Use Translator to load PHP array translations without the native gettext extension, or GettextTranslator to leverage the extension with the same API. Includes global helper functions for template-friendly __().
Install the package:
composer require gettext/translator
Create a translator instance in app/Providers/AppServiceProvider.php:
use Gettext\Translator;
use Gettext\TranslatorFunctions;
public function register()
{
$translator = new Translator();
$translator->setLanguage(config('app.locale'));
// Load translations from PHP arrays (generated from .po files)
$translator->loadTranslations(
resource_path('lang/gl/messages.php'),
resource_path('lang/gl/validation.php')
);
// Register global translation functions
TranslatorFunctions::register($translator);
}
Use translations in Blade:
<h1><?= __('Welcome') ?></h1>
<p><?= _e('Hello, %s!', ['name' => 'John']) ?></p>
Generate translation files (one-time setup):
.po files to PHP arrays using Gettext\Extractors\PhpArray:
vendor/bin/php-gettext extract --format=php --output-dir=resources/lang/gl messages.po
// In a controller
public function showForm()
{
$errors = [
'email' => 'The email field is required.',
];
return view('form', [
'errors' => $errors,
]);
}
<!-- resources/views/form.blade.php -->
<form>
<div class="error">
@if($errors->has('email'))
<p>{{ trans('validation.required', ['attribute' => __('Email')]) }}</p>
@endif
</div>
</form>
Leverage domains to organize translations (e.g., messages, validation, auth):
$translator->loadDomain('validation', resource_path('lang/gl/validation.php'));
echo $translator->gettext('validation.required', ['attribute' => 'Email']);
Laravel Integration Tip:
Map Laravel’s default domains to this package’s domains in AppServiceProvider:
$translator->loadDomain('messages', resource_path('lang/gl/messages.php'));
$translator->loadDomain('validation', resource_path('lang/gl/validation.php'));
Use GettextTranslator in production if the gettext extension is available:
use Gettext\GettextTranslator;
if (extension_loaded('gettext')) {
$translator = new GettextTranslator();
$translator->setLanguage(config('app.locale'));
$translator->loadDomain('messages', base_path('resources/lang/gl/LC_MESSAGES'));
} else {
$translator = new Translator();
// Fallback to pure PHP
}
Workflow:
Translator for debugging (e.g., missing translations).GettextTranslator via AppServiceProvider.Handle pluralization with ngettext:
echo $translator->ngettext(
'There is %d item.',
'There are %d items.',
$count,
['count' => $count]
);
Laravel Compatibility:
Override Laravel’s pluralization logic in app/Providers/AppServiceProvider:
$translator->setPluralForm(
Translator::PLURAL_RULES['es'] // Spanish plural rules
);
Register global functions in AppServiceProvider:
TranslatorFunctions::register($translator);
Now use __(), _e(), trans(), etc., in Blade:
<p>{{ __('Hello, :name!', ['name' => $user->name]) }}</p>
<p>{{ _e('Escaped HTML: <b>bold</b>') }}</p>
Extraction Tip:
Use Gettext\Extractors\PhpCode to scan Blade files for translation strings:
vendor/bin/php-gettext extract --format=php --output-dir=resources/lang/gl app/Views/*.blade.php
Change language per request (e.g., for user preferences):
$translator->setLanguage($request->get('locale', config('app.locale')));
Middleware Example:
public function handle($request, Closure $next)
{
app('translator')->setLanguage($request->get('locale', 'en'));
return $next($request);
}
Ensure missing translations fall back to default locale:
$translator->setFallbackLocale('en');
echo $translator->gettext('missing.key'); // Falls back to 'en/messages.php'
Laravel Sync:
Mirror Laravel’s fallback chain in config/app.php:
'fallback_locale' => 'en',
File Path Confusion:
GettextTranslator expects .mo files in locale/LC_MESSAGES/domain.mo, while Translator uses .php arrays.Pluralization Mismatches:
gettext standards.$translator->setPluralForm(Translator::PLURAL_RULES['es']);
Caching .mo Files:
GettextTranslator compiles .po to .mo at runtime. Pre-compile for production:
msgfmt resources/lang/gl/LC_MESSAGES/messages.po -o resources/lang/gl/LC_MESSAGES/messages.mo
Blade Escaping:
_e() escapes HTML, but __() does not. Mixing them may cause XSS._e() for user-generated content.Domain Loading Order:
loadDomain() calls override earlier ones.validation before messages).Missing Translations:
.php/.mo file exists and paths are correct.$translator->setDebug(true);
Locale Not Switching:
setLanguage() is called before translations are loaded.gl_ES vs. gl).Performance Issues:
GettextTranslator vs. Translator:
$start = microtime(true);
$translator->gettext('key');
echo microtime(true) - $start; // Compare results
Pluralization Errors:
ngettext() directly to isolate issues.Custom Extractors:
Gettext\Extractors\ExtractorInterface to support new file formats (e.g., JSON).Translation Middleware:
public function handle($request, Closure $next)
{
$locale = $request->cookie('locale') ?: config('app.locale');
app('translator')->setLanguage($locale);
return $next($request);
}
Translation Commands:
php artisan translate:extract
php artisan translate:compile
Service Provider Integration:
$this->app->singleton('translator', function () {
$translator = new Translator();
$translator->setLanguage(config('app.locale'));
return $translator;
});
trans() helper:
app()->bind('translator', function () {
return app('gettext.translator');
});
Locale Directory Structure:
GettextTranslator expects:
/locale/
/gl/
LC_MESSAGES/
messages.mo
Translator expects:
/resources/lang/
gl/
messages.php
Default Locale:
AppServiceProvider:
$translator->setLanguage(config('app.locale'));
Character Encoding:
.po files use UTF-8. Convert with:
iconv -f ISO-8859-1 -t UTF-8 input.po
How can I help you explore Laravel packages today?