uam/twig-i18n-extension
uam/twig-i18n-extension adds internationalization helpers to Twig, providing translation filters and functions for localizing strings in PHP templates. A lightweight way to support multilingual Twig-based applications.
This is a Twig extension, not a Laravel package. Laravel ships Blade, so before anything else confirm you actually have Twig wired into your app — typically via rcrowe/twigbridge or a custom Twig\Environment binding in a service provider. If you are on pure Blade, this package gives you nothing; port the handful of i18n helpers into a Blade directive instead.
Minimal path:
composer require uam/twig-i18n-extensionUam\Twig\...). With 1 star and 0 dependents there is no ecosystem to copy examples from, so read the source directly — it is small enough to skim in a few minutes.config/twigbridge.php under extensions, or tagging it in a service provider:$twig->addExtension(new \Uam\Twig\I18nExtension($translator));
Illuminate\Contracts\Translation\Translator if the extension accepts a PSR-15/Symfony-style translator, or write a thin adapter.First use case: drop a translatable string into a template and confirm the filter/function resolves against lang/en/.... Start with a single hard-coded key, verify output, then roll out.
Register once, resolve per request. The extension itself is stateless; the locale should come from the request, not be baked into the extension constructor. Register the extension in a singleton service provider, but read app()->getLocale() at render time so App::setLocale() mid-request still works.
Template usage. Depending on what the extension exposes, you will be using one of a filter, function, or tag. Typical shapes:
{{ 'messages.welcome'|trans }}
{{ trans('messages.welcome', {'name': user.name}) }}
{% trans %}messages.welcome{% endtrans %}
Confirm from the source which of these it actually implements — do not assume all three exist.
Keep keys in translation files, not templates. Treat the Twig layer as a lookup only. Put interpolation params in the template, keep the message bodies in lang/{locale}/*.php (or JSON). This keeps the extension swappable.
Adapter pattern for translator mismatch. If the extension expects a Symfony TranslatorInterface and you are on Laravel, wrap Laravel's translator:
class LaravelTranslatorAdapter implements TranslatorInterface
{
public function __construct(private Translator $translator) {}
public function trans($id, array $params = [], $domain = null, $locale = null): string
{
return $this->translator->get($id, $params, $locale);
}
}
Locale-aware rendering in jobs and mailables. If you render Twig outside the HTTP stack (queued mail, PDF generation), explicitly set the locale before rendering — there is no request to infer it from.
Testing. Add a feature test that renders a template through the same Twig environment the app uses, asserting both a translated string and a fallback for a missing key. Because the package is unmaintained-looking, this test is your regression net for future upgrades.
config/twig-i18n.php. You own the wiring. Budget for a custom provider.composer.json and consider vendoring the extension class into app/Twig/ if it is under ~200 lines. A one-file i18n extension is cheap to own; a broken transitive dependency is not.storage/framework/views (or wherever TwigBridge caches compiled templates). Stale compiled templates are the most common "my filter doesn't exist" cause.TranslationExtension, filter/function names can collide. Whichever is registered last wins — check $twig->getFilters() to see what actually resolved.twig.debug and use {{ dump(_context) }} plus {{ dump('key'|trans) }} to isolate whether the failure is in the extension, the translator, or the message file. Also check config/app.php locale and fallback_locale — mismatches there masquerade as extension bugs.__() will cover 90% of use cases and removes the dependency entirely.How can I help you explore Laravel packages today?