Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laminas Mvc I18N Laravel Package

laminas/laminas-mvc-i18n

Laminas MVC I18n integrates laminas-i18n with laminas-mvc, wiring translators, locale detection, and translated validators and route messages into your application via configurable service managers and view helpers.

Deep Wiki
Context7

Getting Started

  1. Install the bridge (it pulls in laminas/laminas-i18n if needed):
composer require laminas/laminas-mvc-i18n
  1. Register the module. In a laminas-mvc skeleton this is config/modules.config.php; laminas-component-installer may add it automatically:
return [
    'Laminas\Mvc\I18n',
    // ...
];
  1. Configure laminas-i18n in your module config or config/autoload/global.php:
// module/Application/config/module.config.php
return [
    'translator' => [
        'locale' => 'en_US',
        'translation_file_patterns' => [
            [
                'type'     => 'phparray',
                'base_dir' => __DIR__ . '/../language',
                'pattern'  => '%s.php',
            ],
        ],
    ],
];
  1. Create module/Application/language/en_US.php:
<?php
return [
    'Hello' => 'Hello',
    'Welcome, %s' => 'Welcome, %s',
];
  1. First use case: translate view strings.
<?= $this->translate('Hello') ?>
<?= $this->translatePlural('One item', '%d items', $count) ?>

Where to look first:

  • vendor/laminas/laminas-mvc-i18n/src/ConfigProvider.php shows the service aliases that make this package useful: translator, MvcTranslator, and Laminas\I18n\Translator\TranslatorInterface.
  • Your module’s translator config controls locale and translation file discovery.
  • vendor/laminas/laminas-mvc-i18n/src/Translator.php and DummyTranslator.php show the runtime translator wrapper and its no-op counterpart.

The Laravel mental model: MvcTranslator is roughly app('translator'), $this->translate() is roughly __(), and translation_file_patterns is roughly Laravel’s lang/ discovery. The package is a thin wiring layer, not a full localization framework.

Implementation Patterns

Locale per request

Set the locale after routing, because route params are not available during bootstrap. Attach a listener to MvcEvent::EVENT_ROUTE:

namespace Application\Listener;

use Laminas\Mvc\MvcEvent;

class LocaleListener
{
    public function onRoute(MvcEvent $event): void
    {
        $routeMatch = $event->getRouteMatch();
        $locale = $routeMatch?->getParam('locale', 'en_US') ?? 'en_US';

        $event->getApplication()
            ->getServiceManager()
            ->get('MvcTranslator')
            ->setLocale($locale);
    }
}

Register it in Module::onBootstrap():

public function onBootstrap(MvcEvent $event): void
{
    $events = $event->getApplication()->getEventManager();
    $events->attach(MvcEvent::EVENT_ROUTE, [new LocaleListener(), 'onRoute'], 1);
}

If locale comes from a session, user profile, or Accept-Language, resolve it in the same listener. For a simple route prefix:

'route' => '/{locale}/about',
'defaults' => ['locale' => 'en_US'],

Translation file organization

  • Use one file per locale, e.g. en_US.php, de_DE.php, fr_FR.php.
  • Use text domains for module-specific translations to avoid key collisions:
<?= $this->translate('Save', 'Application') ?>

Configure a domain by adding 'text_domain' => 'Application' to the file pattern, then pass the same domain in the helper.

  • Use phparray for small translation sets and gettext for larger sets or plural-heavy content. Gettext’s .mo files handle plural rules better than hand-written PHP arrays.

Validators and forms

The module aliases the laminas-i18n translator interface to MvcTranslator, so built-in validator messages resolve through the MVC translator. If you use custom validators, inject the translator or rely on the default validator translator.

Form labels are not universally auto-translated. Be explicit:

$form->add([
    'name' => 'name',
    'type' => 'Text',
    'options' => [
        'label' => $this->translator->translate('Name'),
    ],
]);

Or translate labels in the view template with $this->translate(). If your form object supports a translator, set it once and keep labels as translation keys.

Localized routes

For localized URL segments, the package ships Laminas\Mvc\I18n\Router\TranslatorAwareTreeRouteStack. Use it only if you need translated route paths; otherwise leave the default router alone.

Conceptually, route paths become translation keys. Each locale must provide a translation for every route path, or matching/assembly can break. Test route assembly per locale:

$url = $this->url('about', ['locale' => 'de_DE']);

If you adopt it, configure the router class or use a delegator to inject the MvcTranslator into the route stack. Keep a fallback locale and verify both match() and assemble().

Console and tests

The same MvcTranslator service is available in console commands. Set the locale from a CLI option or config before translating.

In tests, set the locale explicitly in the bootstrap. If you want translation to be a no-op, the package provides DummyTranslator:

$translator = new \Laminas\Mvc\I18n\DummyTranslator();

Gotchas and Tips

  • Do not casually override the translator service. The module aliases translator, MvcTranslator, and Laminas\I18n\Translator\TranslatorInterface. Replacing translator with a custom implementation can break view helpers, validators, and form integrations unless it implements the expected interfaces.
  • Locale timing matters. onBootstrap is too early to read route params. Use MvcEvent::EVENT_ROUTE for route-derived locales, or EVENT_DISPATCH if you only need the locale inside controllers/views.
  • Cache translation files in production. laminas-i18n supports a cache option. Enable it for production, but clear it on deploy. File-mtime-based caches can serve stale translations after a deployment.
  • Plural forms are a common failure point. PHP array files need explicit plural forms; gettext handles complex plural rules better. Test with counts of 0, 1, 2, and many.
  • Missing keys fail silently. translate() returns the input key when no translation exists. Add a decorator or logging wrapper around MvcTranslator during development to surface missing keys.
  • Text domains prevent collisions. Always pass the domain when using module-specific translation files. The default domain is default.
  • Route translation is opt-in and sharp. If you use TranslatorAwareTreeRouteStack, every locale needs route-path translations. A missing translation can cause a route not to match or a URL to assemble incorrectly. Test assemble() and match() for each supported locale.
  • This package is for laminas-mvc, not Mezzio. In Mezzio, use laminas/laminas-i18n directly with a PSR-11 factory and your own middleware for locale negotiation.
  • It is a thin, low-activity bridge. With 14 stars and a 2024-10-11 release, expect a small integration surface, not a feature-rich localization suite. Pin versions and rely on laminas-i18n for translation loading, plural rules, and caching.
  • Extension points: replace MvcTranslator via a custom factory, decorate it to log missing keys, register custom view helper factories, or add a delegator around the router to inject the translator into TranslatorAwareTreeRouteStack.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource