laravel-lang/json-fallback
Laravel Lang JSON Fallback adds a reliable fallback mechanism for Laravel JSON translations, ensuring missing keys resolve to a default locale instead of breaking UX. Simple to install via Composer and integrates cleanly with Laravel’s localization system.
Installation:
composer require laravel-lang/json-fallback
Add the service provider to config/app.php:
LaravelLang\JsonFallback\JsonFallbackServiceProvider::class,
Publish Config (optional):
php artisan vendor:publish --provider="LaravelLang\JsonFallback\JsonFallbackServiceProvider" --tag="config"
This generates config/json-fallback.php with default settings:
'fallback_locale' => 'en', // Default fallback locale
'json_path' => 'lang/json', // Default JSON path (adjust if custom)
First Use Case:
Place JSON translation files in lang/json/{locale}.json (e.g., lang/json/fr.json).
Use trans() as usual:
// In Blade or PHP
{{ trans('auth.login') }} // Falls back to 'en' if 'fr' key is missing
config/json-fallback.php for fallback locale/path overrides.JsonFallbackServiceProvider registers the custom JsonLoader.JsonFallbackLoader in src/JsonFallbackLoader.php for advanced customization.Standard JSON Translations:
// lang/json/fr.json
{
"auth": {
"login": "Connexion",
"register": "Inscription"
}
}
// lang/json/en.json (fallback)
{
"auth": {
"login": "Login",
"register": "Register"
}
}
// Blade or PHP
{{ trans('auth.login') }} // Uses 'fr' if available, falls back to 'en'
Dynamic Fallback Locale: Override the fallback locale per request:
app('json-fallback')->setFallbackLocale('es');
trans('auth.login'); // Falls back to 'es' if 'fr' key is missing
Custom JSON Paths:
Configure in config/json-fallback.php:
'json_path' => 'resources/lang/custom-json',
Then place files in resources/lang/custom-json/{locale}.json.
Integration with Frontend: Use JSON files directly in JavaScript (e.g., via Laravel Mix/Vite):
// public/js/translations.js
import fr from '../../lang/json/fr.json';
import en from '../../lang/json/en.json';
const translations = { ...fr, ...en }; // Fallback logic in JS
Or fetch dynamically:
// In a controller
return response()->json([
'translations' => trans()->getLoader()->load('fr', 'json')
]);
Translation Workflow:
en.json (fallback).php artisan lang:publish to sync JSON files.CI/CD Validation:
php artisan lang:json-validate --fallback=en
auth.login) are missing in primary locales.Multi-Locale Apps:
fallback_locale to a "super-fallback" (e.g., en).app()->setLocale() to switch languages dynamically.public/lang/ during build:
// vite.config.js
copy({
targets: [
{ src: 'lang/json/*.json', dest: 'public/lang/json' }
]
})
return response()->json([
'data' => $data,
'translations' => trans()->getLoader()->load(app()->getLocale(), 'json')
]);
$this->app->instance(
'translation.loader',
new JsonFallbackLoader($this->app)
);
Nested JSON Structures:
The package assumes flat key-value pairs. Nested JSON (e.g., {"key": {"subkey": "value"}}) will not work without preprocessing. Flatten keys manually:
// Before (broken)
{ "auth": { "login": "Connexion" } }
// After (fixed)
{ "auth.login": "Connexion" }
Caching Issues: Clear translation cache after adding new JSON files:
php artisan view:clear
php artisan cache:clear
Fallback Locale Overrides:
Changing fallback_locale dynamically affects all subsequent translations. Reset carefully:
app('json-fallback')->setFallbackLocale('en'); // Reset to default
Missing JSON Files:
If lang/json/{locale}.json doesn’t exist, the package will fail silently (no fallback). Ensure all locales have a JSON file, even if empty:
// lang/json/fr.json (empty is fine)
{}
Conflicts with Other Loaders:
If using multiple translation loaders (e.g., spatie/laravel-translation-loader), ensure JsonFallbackLoader is registered last to avoid priority conflicts.
Check Loaded Translations: Dump the loaded JSON for debugging:
dd(app('translation')->getLoader()->load('fr', 'json'));
Verify Fallback Logic: Temporarily disable fallbacks to test:
app('json-fallback')->disableFallbacks();
trans('auth.login'); // Will return null if key is missing
JSON Syntax Errors: Validate JSON files with:
php artisan lang:json-validate --locale=fr
Key Consistency:
Use a tool like laravel-lang/macroable to enforce key naming conventions across JSON files.
Performance: For large JSON files, consider compressing or lazy-loading translations:
// In JsonFallbackLoader.php
public function load($locale, $group, $namespace = null) {
$file = $this->getFile($locale, $group, $namespace);
return json_decode(file_get_contents($file), true) ?: [];
}
Fallback Hierarchies:
For multi-level fallbacks (e.g., fr-CA → fr-FR → en), extend the loader:
// app/Providers/JsonFallbackServiceProvider.php
public function register() {
$this->app->bind('translation.loader', function ($app) {
return new CustomJsonFallbackLoader($app, [
'fr-CA' => ['fr-FR', 'en'],
'fr-FR' => ['en']
]);
});
}
Dynamic Fallbacks: Set fallback locales per request based on user preferences:
$fallback = auth()->user()->preferred_fallback ?? 'en';
app('json-fallback')->setFallbackLocale($fallback);
Testing Fallbacks:
Use Translatable facade for assertions:
use LaravelLang\JsonFallback\Facades\Translatable;
$this->assertEquals(
'Fallback Value',
Translatable::trans('missing.key', [], 'fr')
);
Backup Fallback: Add a "super-fallback" for critical keys:
// In a middleware or service provider
app('json-fallback')->setSuperFallback(function ($key, $locale) {
return "Default: {$key}";
});
How can I help you explore Laravel packages today?