mydnic/volet
Volet is a lightweight Laravel package for feature flags. Define toggles in code or config, target users, teams, or environments, and enable or disable features at runtime with a clean API and Blade directives.
Volet is a drop-in translation manager for Laravel: it gives you a UI (and supporting backend) for browsing and editing your app's translation strings instead of hand-editing lang/**/*.php. v2.2.3 is a patch release — dependency bumps plus a rebuilt frontend bundle (the jQuery/terser conflict fix) — so nothing in the install flow changes.
composer require mydnic/voletphp artisan vendor:publish --provider="Mydnic\Volet\VoletServiceProvider" (use --tag= variants for config, assets, migrations if you only want one).config/volet.php first — that's the source of truth for the route prefix, middleware stack, and where translations are read from/written to.php artisan migrate./volet) in your browser and confirm the UI loads — if you get a blank page or 404 on the compiled asset, the assets weren't published (see Gotchas).First use case: open the UI in your local environment, pick a locale you already have files for, and edit one string. Save it, then hit the page that renders that key. This single loop tells you three things at once: where Volet persists translations (files vs DB), whether your cache is being invalidated on save, and whether the middleware you configured actually protects the route.
Where to look next, in order: config/volet.php → the published views (if you published them) → the package's route registration in the service provider. Those three cover 90% of "why isn't this behaving" questions.
Gate it to non-production by default. The most common setup is to expose Volet only where it's safe:
// config/volet.php
'middleware' => ['web', 'auth'], // or a dedicated Gate
Better: register an enabled / environment check so the routes aren't even registered in production, or protect with a Gate::define('manage-translations', ...) bound to an admin role. Translation editing is a write surface — treat it like any admin panel.
Keep files as the source of truth, DB as an override, or pick one. Decide early whether Volet writes back into lang/ files or into a table. File-based means changes are diffable and ship with deploys, but concurrent edits collide and you can't edit in a read-only filesystem (e.g. some container setups). DB-based means runtime edits without a deploy, but you now own backup, seeding, and cache invalidation. Most teams use Volet as an editing surface in local/staging and commit the resulting file changes through PRs.
Seed/import before you edit. Point Volet at your existing lang/ directory and let it enumerate keys first, so the UI shows missing-vs-present strings per locale rather than starting empty. That missing-key view is the highest-value thing in the package day-to-day — it turns "the French translation is stale" into a checklist.
Cache discipline. If translations are cached (Laravel's trans cache or a package-level cache), wire the save action to forget the relevant cache keys, and add a deploy step that clears it. A stale translation cache is the #1 "I saved it but the site still shows the old string" cause.
Localize your workflow: one developer owns merges to lang/, everyone else edits in the Volet UI against a feature branch. This avoids the classic three-way conflict inside a 900-line messages.php.
Upgrading: composer update mydnic/volet then re-publish assets and clear compiled views. v2.2.3 specifically ships a rebuilt JS bundle, so an upgrade without republishing assets leaves you running the old bundle.
--force) and run php artisan view:clear. If you serve assets from the package's vendor/ path, just hard-refresh the browser — the filename may not be hashed, so browser cache will happily serve the broken old bundle.config/volet.php, run php artisan config:clear (or config:cache in deploy). A surprising number of "middleware change did nothing" reports are stale config cache.public/vendor/... path that isn't writable in your container, or an APP_URL/asset-url mismatch behind a proxy. Check the network tab before suspecting the package.declare(strict_types=1), return type hints). Run your formatter (Pint) after a bulk edit session before committing, or your PR will be unreadable.laravel/framework to 13.x and refreshed Symfony/Guzzle internals. If you're pinned to an older Laravel, check the package's composer.json constraints before assuming the bump is free — dependency-only releases can still move your resolved lockfile.How can I help you explore Laravel packages today?