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

Json Fallback Hotfix Laravel Package

laravel-lang/json-fallback-hotfix

Restore expected JSON translation fallback behavior in Laravel with this Laravel Lang hotfix. It ensures missing JSON keys resolve through your configured fallback locale instead of returning raw keys, helping multilingual apps stay consistent. Drop-in Composer package for affected Laravel versions.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install: composer require laravel-lang/json-fallback-hotfix. There is no config to publish, no migration, no env var. Package discovery registers the service provider automatically; on a locked-down app verify it with php artisan about or php artisan package:discover output.

  • Version to land on: 2.3.0 is the current release (published 2026-03-17) and exists solely to widen the framework constraint — it adds Laravel 13 support with no code changes to the patch itself. On Laravel 13 you need ^2.3; an older 2.x constraint will not resolve. On Laravel 10–12 either version works, but install ^2.3 anyway so you're already on the line that spans your next framework bump.

  • Prerequisite check: open config/app.php (or config/app.php → .env via APP_FALLBACK_LOCALE) and confirm 'fallback_locale' is a locale you actually ship a lang/{locale}.json for. The hotfix has nothing to fall back to if that file doesn't exist.

  • Reproduce the bug before installing. This is the step people skip. With the package not installed, in php artisan tinker:

    app()->setLocale('fr');           // config app.fallback_locale = 'en'
    __('btn.save');                   // observed: "btn.save"  ← raw key leaking into the UI
    

    If you already see the English string here, your Laravel version already behaves correctly on this path and you may not need the package at all. Confirm with a semantic key (btn.save, errors.required) rather than an English sentence — see the gotcha below.

  • Where to look first: the service provider class in src/ — it is small, and reading it tells you exactly which translator method is being patched (get, has, or the JSON loader). That determines what is and isn't covered. Then check the package's composer.json for the illuminate/* constraint and confirm it covers your framework version (as of 2.3.0 that ceiling includes Laravel 13).

  • First real use case: pick one screen that renders untranslated strings for a partially-translated locale, install, and confirm the strings flip from raw keys to fallback-locale text. That single screen is your proof of value; don't roll it out fleet-wide on faith.

Implementation Patterns

  • Treat the fallback locale's JSON file as the canonical key set. With the hotfix in place, lang/en.json effectively becomes your schema. Every other lang/*.json is a sparse override of it. Write that down in the repo — it changes how translators and lang:add-style tooling should be used.

  • Guard key drift with a test, not discipline. A cheap Pest/PHPUnit test catches the case where a key exists in fr.json but was renamed in en.json:

    test('locale json keys are a subset of the fallback', function () {
        $base = array_keys(json_decode(file_get_contents(lang_path('en.json')), true));
        $fr   = array_keys(json_decode(file_get_contents(lang_path('fr.json')), true));
        expect(array_diff($fr, $base))->toBeEmpty();
    });
    
  • Assert the fallback contract in a feature test. This is your wiring, not the package's internals:

    test('missing json key resolves through fallback locale', function () {
        app()->setLocale('fr');
        expect(__('btn.save'))->toBe('Save');
    });
    

    Add a second assertion that a key present in fr.json still returns French — that's the regression the fix could plausibly introduce.

  • Keep replacements and :attributes working. Verify placeholders survive the fallback path: __('Hello :name', ['name' => 'Ada']) under the non-fallback locale must still interpolate. Retrieval and substitution happen in different layers, so this normally works — but assert it once so a future framework bump doesn't silently break it.

  • Scope it: JSON only. lang/{locale}/messages.php array files already fall back natively. Don't refactor array-file translations into JSON to "benefit from the package" — JSON files can't do pluralization (trans_choice) or nested keys. Use array files where you need those; use JSON for flat UI strings.

  • Frontend translations: if you ship a translation bundle to Vue/React/Alpine, remember the hotfix runs server-side. Any __() you call while generating the JS bundle gets the corrected value; any lookup done client-side does not. Generate bundles per-locale server-side rather than merging at runtime.

  • Locale negotiation middleware should hand off cleanly: App::setLocale($negotiated), and let Laravel + this package handle the locale → fallback_locale → raw key chain. Don't hand-roll a second fallback loop in middleware.

  • Deploy order: composer install → php artisan optimize:clear → config:cache → queue:restart. If you cache translations or compile a JS bundle, add that step after composer install so the new provider is in effect. A 2.2 → 2.3 upgrade needs nothing beyond this pipeline; there are no migrations or config changes — but re-cache if you bumped the framework at the same time.

Gotchas and Tips

  • The bug is invisible when your keys are English sentences. If lang/en.json is {"Welcome back": "Welcome back"}, the raw-key fallback is the correct English string. You only see the breakage with semantic keys (btn.save), with a non-English fallback locale, or after you change the English copy. Don't conclude "we don't have this problem" from a glance at a sentence-keyed app.
  • Missing-key-to-raw-key is a signal — don't let the hotfix bury it. After installing, a string that renders in the fallback language is still an untranslated string. Keep Lang::has() / a lint pass reporting keys missing from the active locale, otherwise coverage silently stalls. The package fixes the user-facing symptom, not the translation backlog.
  • This is a hotfix around framework internals — re-test on every Laravel upgrade. That is the highest-risk property of the package. Put the feature test from above in CI and run it on the framework version you're targeting, not just the one you're on. The 2.3.0 release is the healthy version of this story — a same-day constraint widening for a new major — but it's still a constraint bump, not a code review: the patch code is unchanged, so a Laravel 13 run is the first time that code meets the new framework. Treat "it installed" and "it works" as two separate verifications. If a Laravel minor fixes the behavior natively, the package may become redundant (usually harmless) or subtly conflict (not harmless).
  • Pin loosely, verify explicitly. Use "^2.3"-style constraints rather than 2.2.*; then composer show laravel-lang/json-fallback-hotfix in each environment to confirm what actually installed. composer why-not laravel/framework tells you whether a framework bump is blocked by this package or something else — run it before scheduling a Laravel 13 upgrade, so a stale 2.2.x pin doesn't surface as a mysterious resolution failure days later.
  • Empty-string values win over fallback. {"btn.save": ""} in fr.json is a present key returning an empty string, not a missing key. Audit for placeholder empties after bulk translation imports — the hotfix won't rescue you there.
  • File resolution quirks: the loader looks for lang/fr.json — a fr_FR locale does not automatically read fr.json unless you've configured fallback chaining. Also make sure the file is valid JSON; a trailing comma makes the loader skip the file and you'll get raw keys with no error message.
  • Debugging checklist: app()->getLocale() and config('app.fallback_locale') first (people frequently assert the wrong pair), then Lang::has('key') vs Lang::hasForLocale('key', 'fr') to see which layer disagrees, then app('translator')->getLoader()->load('fr', 'json', '*') to confirm the file was actually loaded and parsed. php artisan config:clear before believing any config value.
  • Don't patch vendor. If you need different fallback semantics (e.g., per-tenant fallback chains), implement it in your own middleware or a decorated translator binding rather than editing the package — you'll lose it on the next composer update.
  • Track the package's support policy. Hotfix packages that patch framework internals have a shelf life; when Laravel fixes the behavior upstream, this dependency should be removed rather than carried forever. The maintainer is currently tracking majors promptly (2.3.0 landed for Laravel 13 within the same release line), which is a good sign for staying, not a reason to stop watching. Note the removal check in your upgrade runbook now.
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.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
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