rivalex/lingua
Database-driven translations for Laravel with a polished Livewire + Flux admin UI. Install and manage languages, edit strings in real time, and sync translations both ways between DB and PHP/JSON files via artisan commands. Supports Laravel 11–13, PHP 8.3+.
Run migrations to create the new lingua_settings table:
php artisan migrate
If you previously published assets, they are no longer needed. The package now serves its own compiled assets
automatically. You can safely delete public/vendor/lingua/ from your project.
If you have customised config/lingua.php, your values continue to work as fallback — no changes required.
All notable changes to lingua will be documented in this file.
Lingua::isDefaultLocale() — missing null-safe operator caused a TypeError when called with a locale code that has no matching record in the database; now returns false safely.LinguaServiceProvider::registerTranslator() — Language::default()->code replaced with Language::default()?->code to avoid TypeError during bootstrap when the languages table is empty or not yet migrated.LinguaMiddleware — same nullsafe fix: Language::default()->code → Language::default()?->code.Translation\Delete::mount() — accessing ->name on the result of Language::first() without a null guard caused a TypeError when the locale was absent from the database; now falls back to the locale code string.LanguageSelector::changeLocale() — the method accepted any arbitrary string passed as $locale and stored it directly in the session without validating it against the installed languages, allowing an attacker to inject arbitrary locale codes. It now silently returns early if the locale is not found in the database.Language::setDefault() — the two separate UPDATE queries ran outside a transaction, leaving a window where no language was marked as default. Both queries are now wrapped in DB::transaction().Language\Create — misleading log message "Languages reorder failed" corrected to "Add language failed".Lingua::addLanguage(string $locale) — facade method (and docblock) for installing language files via lang:add.Lingua::removeLanguage(string $locale) — new facade method for removing language files via lang:rm --force; mirrors the file-management step of lingua:remove.[@method](https://github.com/method) docblocks for addLanguage() and removeLanguage() in the Lingua facade class.Lingua facade.addLanguage() and removeLanguage() with a note distinguishing them from the full lingua:add / lingua:remove Artisan commands.addLanguage and removeLanguage smoke tests added to LinguaFacadeTest.Language/Delete Livewire component: replaced direct Artisan::call('lang:rm …') call with Lingua::removeLanguage() so the component goes through the facade consistently.Lingua facade fully implemented with a complete API surface:
getLocale(), getDefaultLocale(), hasLocale(), isDefaultLocale(), setDefaultLocale()getLocaleName(), getLocaleNative(), getDirection()languages(), languagesWithStatistics()translations(), getTranslation(), getTranslations(), getTranslationByGroup(), getLocaleStats()setTranslation(), forgetTranslation()syncToDatabase(), syncToLocal()getVendorTranslations(), setVendorTranslation()VendorTranslationProtectedException — thrown when attempting to delete a vendor-owned translation.
Vendor translation protection — vendor translations cannot be deleted from the UI; attempting to do so dispatches a vendor_translation_protected event and closes the modal instead.
Vendor translation locking in Update — when editing a vendor translation, group and key fields are locked; only the text value and type may be changed.
isVendor property exposed on the Translation/Update Livewire component for view-layer awareness.
Feature tests: LinguaFacadeTest and VendorTranslationTest covering the full facade API and vendor-protection behaviour.
Helper unit tests extended to cover new utility cases.
Translation/Update: vendor translations skip the group/key update path and only persist type and text changes.Translation/Delete: vendor translations are intercepted before deletion and trigger a protected event instead.LinguaServiceProvider: updated to register the vendor protection exception and related bindings.Lingua facade fully implemented with a complete API surface:
getLocale(), getDefaultLocale(), hasLocale(), isDefaultLocale(), setDefaultLocale()getLocaleName(), getLocaleNative(), getDirection()languages(), languagesWithStatistics()translations(), getTranslation(), getTranslations(), getTranslationByGroup(), getLocaleStats()setTranslation(), forgetTranslation()syncToDatabase(), syncToLocal()getVendorTranslations(), setVendorTranslation()VendorTranslationProtectedException — thrown when attempting to delete a vendor-owned translation.
Vendor translation protection — vendor translations cannot be deleted from the UI; attempting to do so dispatches a vendor_translation_protected event and closes the modal instead.
Vendor translation locking in Update — when editing a vendor translation, group and key fields are locked; only the text value and type may be changed.
isVendor property exposed on the Translation/Update Livewire component for view-layer awareness.
Feature tests: LinguaFacadeTest and VendorTranslationTest covering the full facade API and vendor-protection behaviour.
Helper unit tests extended to cover new utility cases.
Translation/Update: vendor translations skip the group/key update path and only persist type and text changes.Translation/Delete: vendor translations are intercepted before deletion and trigger a protected event instead.LinguaServiceProvider: updated to register the vendor protection exception and related bindings.Translation/Create — group preserved after creation — the group field is now retained after a successful save, allowing multiple keys to be added to the same group consecutively without reselecting it. Only key, translationType, and value fields are reset.Translation/Create and Translation/Update — whitespace normalization — group and key values are sanitized with Str::squish()->trim() before being persisted, preventing keys with leading, trailing, or excess internal spaces from being stored.CreateTest: corrected group assertions to reflect preservation after creation; added whitespace normalization test for group and key.UpdateTest: added whitespace normalization test for group and key; added test confirming that vendor translation group and key fields are immutable.Lingua::isDefaultLocale() — missing null-safe operator caused a TypeError when called with a locale code that has no matching record in the database; now returns false safely.LinguaServiceProvider::registerTranslator() — Language::default()->code replaced with Language::default()?->code to avoid TypeError during bootstrap when the languages table is empty or not yet migrated.LinguaMiddleware — same nullsafe fix: Language::default()->code → Language::default()?->code.Translation\Delete::mount() — accessing ->name on the result of Language::first() without a null guard caused a TypeError when the locale was absent from the database; now falls back to the locale code string.LanguageSelector::changeLocale() — the method accepted any arbitrary string passed as $locale and stored it directly in the session without validating it against the installed languages, allowing an attacker to inject arbitrary locale codes. It now silently returns early if the locale is not found in the database.Language::setDefault() — the two separate UPDATE queries ran outside a transaction, leaving a window where no language was marked as default. Both queries are now wrapped in DB::transaction().Language\Create — misleading log message "Languages reorder failed" corrected to "Add language failed".Lingua::addLanguage(string $locale) — facade method (and docblock) for installing language files via lang:add.Lingua::removeLanguage(string $locale) — new facade method for removing language files via lang:rm --force; mirrors the file-management step of lingua:remove.[@method](https://github.com/method) docblocks for addLanguage() and removeLanguage() in the Lingua facade class.Lingua facade.addLanguage() and removeLanguage() with a note distinguishing them from the full lingua:add / lingua:remove Artisan commands.addLanguage and removeLanguage smoke tests added to LinguaFacadeTest.Language/Delete Livewire component: replaced direct Artisan::call('lang:rm …') call with Lingua::removeLanguage() so the component goes through the facade consistently.es, fr, it, ja, pt, ru, zh_CN.translation/create, translation/row, and translation/update views.LanguageSelector, Selector/Icon) made more flexible with improved prop/slot handling.LinguaType enum updated to align with the simplified placeholder approach.language/row and selector/* Blade views updated for consistency.editor Blade component cleaned up.language-flag component updated.AddLangCommand — artisan command to add a new language to the application.RemoveLangCommand and UpdateLangCommand registered in LinguaServiceProvider (commands existed previously but were not registered).AddLangCommandTest, RemoveLangCommandTest, UpdateLangCommandTest, SyncToDatabaseCommandTest, SyncToLocalCommandTest.CreateTest, DeleteTest, RowTest, UpdateTest.BladeComponentsTest.TranslationsTest coverage.style=flat-square from badge URLs.laravel-lang/common bumped from 6.7.2 to 6.8.0.laravel/pint bumped from 1.28.0 to 1.29.0.Language management UI — Livewire-powered CRUD for application languages (create, delete, set default, reorder).
Translation management UI — Livewire-powered interface for browsing and editing translations per locale, including rich-text (TipTap) and plain-text editor modes.
Language selector — embeddable Livewire component in three styles: dropdown, modal, and sidebar.
Artisan commands:
lingua:sync-to-database — import local translation files into the database.lingua:sync-to-local — export database translations back to local files.lingua:update-lang — update language files via laravel-lang.LinguaMiddleware — sets the active locale from the authenticated user's language preference.
LinguaSeeder — seeds the database with language records.
Database migration — creates the lingua_languages and lingua_translations tables.
Language and Translation Eloquent models with factory support.
Lingua facade stub (fully implemented in Unreleased above).
LinguaType enum for translation content types (plain, HTML, Markdown).
Blade components: clipboard, editor, language-flag.
Publishable assets: config, views, migrations, language files (en baseline), compiled CSS/JS.
Frontend assets: TipTap-based rich-text editor, autocomplete, flag icons via outhebox/blade-flags, Livewire Flux UI.
CI workflows: test runner, PHP code-style fixer (Pint), Dependabot auto-merge, changelog updater.
Dependabot enabled for Composer and GitHub Actions dependencies.
actions/checkout bumped from 5 to 6.
Codecov integration in the test workflow.
PHPStan baseline configuration.
How can I help you explore Laravel packages today?