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

Translationbundle Laravel Package

object.bg/translationbundle

Symfony bundle for managing translations with a database-backed storage and an admin interface, so locale strings can be edited at runtime instead of only in files.

View on GitHub
Deep Wiki
Context7

Getting Started

Step 0 — confirm the runtime. object.bg/translationbundle is a Symfony bundle, not a Laravel package. If the project is Laravel, you are not installing this; you are copying its idea (DB-backed labels behind the Translator facade) using spatie/laravel-translation-loader or a ~40-line decorator around Illuminate\Translation\Translator. Everything below is written so the pattern survives the port.

Step 1 — read the vendor before you write a line of app code.

composer show object.bg/translationbundle
# open composer.json: type, require (symfony/framework-bundle, doctrine/orm), autoload
# then walk the tree in this order:
#   src/*Bundle.php            -> what it registers, compiler passes
#   DependencyInjection/Configuration.php -> the real config schema (there is no docs site)
#   DependencyInjection/*Extension.php    -> which services are wired, aliases, tags
#   Entity/ or Model/          -> the label table shape
#   Resources/config/services.* -> what replaces the core translator, and how

Step 2 — install pinned.

composer require object.bg/translationbundle:^1.0

One GitHub star, zero dependents, last tag 2021-03-15. Pin exactly, commit composer.lock, and assume you own the maintenance. Vendor-fork it if the diff is small — it usually is for bundles of this vintage.

Step 3 — register it. Symfony 4/5-style projects: add to config/bundles.php. Symfony 3.4 / AppKernel: new Warxcell\TranslationsBundle\...() in registerBundles(). If you're on Symfony 6/7, expect to patch getContainerExtension() and make sure the services file uses autowire/autoconfigure or is public: true as needed.

Step 4 — create the table with a migration, not schema:update.

bin/console doctrine:migrations:diff   # inspect, then migrate

Step 5 — first use case. The only reason to adopt this is non-developers editing copy without a deploy: marketing changes "Add to cart" on a Tuesday. Seed the table from your existing translations/messages.en.yaml, wire an admin CRUD over the label entity, and leave trans() calls in Twig/PHP untouched.


Implementation Patterns

Decorator over the translator, not replacement. The healthy shape is a service that implements Symfony\Contracts\Translation\TranslatorInterface, consults the database first, and falls through to the file-based translator. Verify from the extension class whether the bundle does this via decorates: translator or by swapping the alias — it changes how much of your existing %locale% / fallback config keeps working.

Import/export symmetry. You want two console commands: one that loads translations/*.yaml into rows (idempotent, keyed by domain + locale + key), and one that dumps rows back to YAML for version control. Without the round-trip, the database becomes the only source of truth and you lose code review on copy changes.

Domain discipline. Keep messages, validators, and your app's custom domains separate. Validator messages in particular get re-seeded by framework updates; mixing them with marketing copy is how you end up with a "please enter a valid email" string that says "Buy now".

Cache on write, not on read.

// after persist/flush of a label
$this->cache->delete('translations.catalog.'.$locale);

Reading a label per row on every request is an N+1 that will not show up in dev. Load the whole domain+locale catalog once into an array (or Redis), and let trans() be an array lookup. Invalidate from the entity listener on postPersist/postUpdate/postRemove.

Placeholder safety. Editors will delete %name%. Add a validation on the label entity: extract /\$\w+%|%\w+%|\{\w+\}/ from the source key's current value, and reject a save that drops a placeholder. This one rule prevents most production incidents with DB-backed translations.

Fallback chain you can explain. Row for bg → row for en → file-based en → raw key. Make it explicit in one method and unit-test it, because the bundle's 2021-era defaults probably only give you two of those four.

Laravel port sketch, if that's the actual destination:

class DbLoader implements LoaderInterface {
    public function load($locale, $group, $namespace = null) {
        return Cache::rememberForever("tr.$locale.$group", fn () =>
            Label::where(compact('locale','group'))->pluck('value','key')->all()
        );
    }
}
// then $translator->addLoader('db', ...) and set it first in the loader chain

Gotchas and Tips

  • No documentation is the documentation. Configuration.php and the service definitions are the only spec. Budget an hour to read them before integrating; you will find config keys that are half-wired, and it's cheaper to discover that than to debug it in staging.
  • Abandoned. Last release March 2021, one star, zero dependents. There will be no security fixes, no Symfony 7 support, no PHP 8.3 fixes. Treat it as code you have adopted, not a dependency you consume. Fork it, or reimplement — the surface is small enough that reimplementation is often the cheaper call.
  • translator caching is the #1 bug. bin/console cache:clear in dev hides it; prod will serve stale labels for hours. Never let an admin edit path end without an explicit cache invalidation plus translations pool clear.
  • Schema drift. If the README says doctrine:schema:update, don't. Diff a migration so the label table has a versioned shape in every environment, including the one your colleague set up manually in 2021 and never migrated.
  • Missing keys fail silently. trans('checkout.pay') returning checkout.pay in production is the classic. Add a dev-environment listener that logs a warning (or throws) whenever the translator returns the input key unchanged — this catches both missing rows and typo'd domains.
  • Debug with the framework, not the bundle.
    bin/console debug:translation en --domain=messages
    bin/console debug:container translator
    bin/console lint:yaml config/
    
    The first tells you what the composed translator actually resolves; the second tells you whether the bundle's decorator won the alias.
  • Extension points to look for before forking: a LabelRepository you can override via services.yaml, an entity you can extend with ResolveTargetEntityListener (if it used a mapped superclass), and any *Events class. If none of those exist, plan on forking — a bundle this size rarely has a clean seam.
  • Locale columns vs JSON. If the table stores one row per locale, adding a language is a data migration; if it stores a JSON blob, it's a config change but you lose per-locale indexing and WHERE locale = ? filtering. Check the entity before you promise a client "we can add Bulgarian next sprint."
  • Do not put this behind high-traffic read paths without measuring. One extra SELECT per untranslated key, times a page with 200 keys, times no cache = a database incident on launch day. Warm the catalog at deploy time like you would a config cache.
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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib