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

Translations Laravel Package

escolalms/translations

Translation management for Laravel applications from EscolaLMS. Organize and edit language strings, manage locale files, and expose translations through the API, making multilingual content easy to maintain.

View on GitHub
Deep Wiki
Context7

Getting Started

escolalms/translations is the EscolaLMS package that moves Laravel translations out of lang/*.php and into the database, then exposes them over an authenticated REST API so non-developers can edit copy without a deploy. It is a 0.1.x package — treat it as moving fast and pin it.

composer require escolalms/translations

# publish config + migrations (tags vary; check the README for the exact tag list)
php artisan vendor:publish --provider="EscolaLMS\Translations\Providers\TranslationsServiceProvider"
php artisan migrate

Where to look first, in order:

  1. The package README — it is the only reliable source for route prefix and permission names at this version.
  2. config/escolalms-translations.php — locale list, table name, cache toggle, and whether the DB loader is enabled.
  3. src/Providers/* — confirm the service provider is auto-discovered and see whether it rebinds translation.loader.
  4. src/Http/Controllers + src/Routes — the actual API surface, including the Swagger-annotated admin endpoints that 0.1.1 touched.
  5. src/Console — any import/export commands; this is where file→DB migration lives.

First use case to prove the install end-to-end: import your existing lang/ files into the DB, hit the admin list endpoint for a locale, edit one key, and confirm the change appears via __() without clearing anything manually.

php artisan tinker
>>> __('validation.required')   // should resolve from DB after import

If that returns the file value and not your DB edit, the loader is not swapped and nothing else in the package will behave as documented.

Implementation Patterns

Bootstrap the DB from files once, then stop shipping strings. Use the package's import command (or wrap it in your own Artisan command iterating lang/*/*.php) inside a seeder so fresh environments are populated deterministically. Keep the lang/ files in the repo as the seed of truth, but treat the DB as the runtime source after that.

Scope edits by group/namespace. Translations are keyed by group (Laravel's file.group.key convention). Give the admin API consumers a group filter rather than exposing the whole table — it maps cleanly to how the frontend admin panel organizes screens, and it keeps permission scoping sane.

Wire the admin routes behind EscolaLMS's usual stack. These packages assume auth + the strict-permission middleware for admin endpoints. Register the permissions in your seeder and gate the translation table on a dedicated permission (e.g. a translations-manage ability) rather than reusing a general admin role — translation editing is a content role, not an engineering one.

Serve translations to SPAs as a single locale payload. Rather than letting the frontend issue per-key requests, add a thin controller over the package's repository that returns { group: { key: value } } for one locale and cache it. This is the highest-leverage integration point: one cached endpoint covers the whole UI.

Invalidate cache on write. If the config enables translation caching, an update through the API must bust the relevant locale/group key. Do it in a model observer or an event listener on the package's save event, not in the controller, so seeders and console edits get the same behavior.

In tests, seed translations explicitly. Use RefreshDatabase, then run a small fixture seeder that inserts only the keys under test. Asserting on __() against a half-imported translation table produces failures that look like logic bugs but are data bugs.

Wrap the package behind your own thin service. One class with get, set, import, export methods that delegates to the package. When 0.1.x breaks something (it will), you change one file.

Gotchas and Tips

  • Precedence surprises. DB-backed loaders typically sit in front of the file loader with a fallback. A key that exists in both places resolves to whichever the loader checks first — usually the DB. If you edit a lang/ file and see no change, that is why. Decide the precedence deliberately and document it.
  • Stale cache is the #1 false bug report. After any manual UPDATE on the translations table (bypassing the API), run php artisan cache:clear or the package's own cache command before debugging anything else.
  • Swagger annotations are not runtime code. The 0.1.1 change (fix swagger) is documentation metadata only — no schema, route, or behavior change. You only observe it if you run php artisan l5-swagger:generate and inspect the generated spec for the translation endpoints. Nothing to migrate, nothing to re-test beyond your normal suite. Do regenerate and commit the spec if you vendor it.
  • 0.x version pinning. 0.1.0 → 0.1.1 looks like a patch, but pre-1.0 packages reserve the right to break in patch releases. Pin to an exact version in composer.json rather than ^0.1.
  • Missing keys fail silently. Laravel returns the key string itself when a translation is absent. Add a middleware or a listener in non-production environments that logs keys which come back equal to their lookup string — otherwise untranslated UI ships unnoticed.
  • Locale list is configured, not inferred. Adding a language means adding it to the package config and seeding its rows. A locale present in config with no rows renders as raw keys everywhere.
  • Character encoding. Non-Latin locales need utf8mb4 on the translations table and matching collation; the default Laravel migration may not be enough depending on your DB version.
  • Publishing migrations vs. running the package's. Pick one. Running both creates duplicate-table errors on fresh installs that are annoying to diagnose.
  • Extension points. The loader binding and any translation-saved event are the two seams worth knowing — they are where you add a CDN purge, an audit log of who changed what, or a second cache layer. Anything else, subclass or decorate rather than editing vendor code.
  • Debugging checklist when a translation "doesn't work": config enabled? row exists in the translations table for that locale+group+key? cache cleared? loader rebound? __() returns DB value in tinker? Work top-down — in practice it is almost always step 2 or 3.
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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums