Livewire Inline Translation
darvis/livewire-inline-translation is a Laravel package with one Livewire component that shows a translation and lets an authorised user edit it on the page itself. They click the text, a modal opens, and the new value is stored in the translations table for the current locale.
It is for a site where a client or an editor wants to change wording without a CMS and without asking a developer. Your language files stay the source for every text nobody has edited.
Install it in three lines
composer require darvis/livewire-inline-translation
php artisan migrate
<div id="inline-translation-modals"></div>
The last line goes in your layout, once, before the closing body tag. Installation has every step and a check that it works.
Requirements
PHP 8.2 or higher, Laravel 11, 12 or 13, and Livewire 3 or 4. Livewire brings Alpine.js, which the modal uses. A database, because the edited values are stored there.
Your first editable translation
resources/views/welcome.blade.php:
<h1><livewire:inline-translation translation-key="website.welcome" /></h1>
website.welcome is looked up in the database first and falls back to __('website.welcome'), so the page reads the same as before until someone edits it. Someone who is logged in on the configured guard sees a dashed blue underline and can click the text. Everyone else gets the text without the underline, the click handler or the modal.
Where the text lives
| Situation | Where the text comes from |
|---|---|
| Not edited yet | your language file, through __('website.welcome') |
| Edited once | a row in the translations table, one per locale |
| Language file changed afterwards | the database row still wins; delete the row to fall back to the file |
What it does not do
- No per user or per key permissions. There is one guard check; you narrow it by overriding
isAuthorized(). - No revision history, no approval flow and no translation memory.
- No sanitising. The stored value is rendered as HTML, so whoever may edit can put any markup on the page.
- It does not change
__(). Only the component reads the database; see Usage. - No JSON translation strings: a key needs the form
group.key.
Read on
- Installation: from
composer requireto a text you can click, with a check that it works - Usage: one complete example, the HTML editor, several locales and where the component does not belong
- Configuration: the two settings, choosing a guard and narrowing who may edit
- How it works: the lookup order, the authorisation check, saving per locale and the modal
- API reference: the component, the model, the table, the config keys and the publish tags
- Testing: test a page with an editable translation in your own application
- Troubleshooting: from the symptom to the cause and the fix
- FAQ: short answers to the questions people ask first