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

Concrete5 Translation Library Laravel Package

mlocati/concrete5-translation-library

A PHP library for managing Concrete CMS (concrete5) translations: extract translatable strings from core and package source code, build and update translation dictionaries, and generate the .mo files needed to localize sites and add-ons.

View on GitHub
Deep Wiki
Context7

Getting Started

This is not a Laravel package — it is the standalone localization library extracted from Concrete CMS. There is no service provider, facade, config file, or Artisan command. You add it with composer require concrete5-community/translation-library and drive it through its own singleton:

use Concrete\Core\Localization\Translation;

$translator = Translation::getInstance();
$translator->getTranslator()->translate('Some key');

Look at these first, in this order:

  1. Translation::getInstance() — the global entry point and the thing you will wrap.
  2. TranslatorAdapterInterface — the seam where you can plug your own translator implementation.
  3. The translation file loaders (CoreTranslationFileLoader, GettextTranslationFileLoader, Zend/Symfony variants) — these decide which on-disk format you must author.
  4. The new Twig bridge (1.11.0) — only relevant if you render Twig alongside Blade.

The realistic first use case is not greenfield Laravel i18n — use __()/@lang for that. You reach for this package when you are porting or co-hosting a Concrete CMS site (or a theme/addon's translation files) inside a Laravel app and need its dictionary formats and locale resolution to keep working unchanged.

1.11.0 specifically: the minimum PHP is now 7.2, up from 5.3. That is fine for any Laravel you'd run today (Laravel 6+ already requires 7.2), but if you pin platform.php in composer.json or run a legacy PHP 7.0/7.1 job in CI, the upgrade will fail resolution. Check your CI matrix and any config.platform override before bumping.

Implementation Patterns

Wrap the singleton in the container. Never let Translation::getInstance() leak into application code. Bind a small adapter in a service provider so locale and adapter state are explicit and testable:

$this->app->singleton(TranslationService::class, function ($app) {
    $translation = Translation::getInstance();
    $translation->setAdapter(new CoreTranslatorAdapter($translation));
    return new TranslationService($translation);
});

Adapter + loader is the composition point. The adapter decides how lookup happens; the loader decides where strings come from. For dictionaries already shipped as PHP arrays (the Concrete default), use the core adapter with the core file loader. For .mo catalogs, use the Gettext path — but see the gotchas about ext-gettext and system locales.

Bridge to Laravel's translator rather than replacing it. The cleanest integration is a custom TranslatorAdapterInterface implementation that delegates to Illuminate\Translation\Translator. That way your legacy Concrete keys resolve through the same loader chain, placeholder replacement, and fallback locale as the rest of the app, and you keep one source of truth for the active locale.

Locale switching belongs in middleware. Set the locale once per request from the same source your Laravel middleware uses (App::setLocale() plus the library's locale setter), so the two systems cannot drift.

Twig (new in 1.11.0). If you are porting a Concrete theme that renders Twig, the optional integration lets those templates call the same translation API as Blade. Install Twig explicitly — it is an optional, not a hard, dependency:

composer require twig/twig

Treat this as a migration aid, not a reason to introduce Twig into a Blade app.

Cache aggressively. File loaders hit disk. Load the dictionary once per locale into a repository or Laravel cache keyed by locale + file mtime; translation lookups should never touch the filesystem in a request loop.

Gotchas and Tips

  • Global mutable state. Translation::getInstance() is a process-wide singleton holding the active adapter and locale. Under Octane, Swoole, or a queue worker, a locale set by one request/job bleeds into the next. Reset the locale in middleware terminate() or a job finally block, or bind a scoped instance.
  • PHP 7.2 floor is now hard. The 1.11.0 bump is a genuine breaking change for anyone on 7.0/7.1 or with a stale config.platform.php. Conversely, if you were blocked on this library because of the 5.3 floor, 1.11.0 unblocks you — but re-audit the code you assumed was PHP-5-era before adopting patterns from older docs.
  • Twig version conflicts. Because Twig is optional, the package won't constrain its version for you. If another dependency already pulls Twig, verify compatibility; an unconstrained twig/twig in your root composer.json can resolve to a major version the bridge was not tested against. Pin it.
  • Gettext is environment-sensitive. ext-gettext must be installed and the target locales generated on the host (locale -a). Container images routinely lack them, producing silently untranslated output rather than errors. Prefer PHP-array dictionaries where you control the deployment.
  • Silent misses. Missing keys typically return the key itself. Add a debug-mode assertion or logging around the translate call during development; there is no built-in "missing translation" event you can listen to.
  • No Laravel ergonomics. No config/translation.php to publish, no Facade, no lang:publish. All configuration is imperative PHP. Budget for a thin wrapper class and document it, or the next developer will call the singleton directly.
  • Blade interop. Blade's {{ }} and the library's placeholder conventions are unrelated. If your dictionaries use Concrete-style placeholders, translate first and pass the result through — do not expect Blade's escaping or :attribute replacement to apply.
  • Extension point to remember: TranslatorAdapterInterface is the only sane integration seam. Subclassing or monkey-patching the singleton will break on minor upgrades.
  • Upgrade risk assessment for 1.11.0: low for Laravel users. One breaking constraint (PHP 7.2) and one additive optional feature (Twig). No API removals or deprecations in the notes, so existing adapter code should carry over unchanged.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource