our-edu / laravel-translation-client
Laravel client package for consuming centralized translation service
Package info
github.com/our-edu/laravel-translation-client
pkg:composer/our-edu/laravel-translation-client
Requires
- php: ^8.1|^8.2|^8.3
- illuminate/cache: ^10.0|^11.0
- illuminate/http: ^10.0|^11.0
- illuminate/support: ^10.0|^11.0
- illuminate/translation: ^10.0|^11.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^10.0
This package is auto-updated.
Last update: 2026-08-19 11:34:18 UTC
README
A Laravel package for consuming centralized translation services. This package replaces Laravel's file-based translation loader with an API-based loader that fetches translations from a remote translation service.
Features
- API-based translations - Fetch translations from a centralized service
- Write translations - Push translations back to the service
- Multi-level caching - Memory, Laravel cache, and service-side caching
- Automatic updates - Translations update without redeployment
- Multi-tenant support - Per-tenant translation isolation
- Zero code changes - Works with existing
trans()and__()calls - High performance - Sub-millisecond translation lookups
- Graceful degradation - Falls back to stale cache on API failures
- Import from files - Migrate existing Laravel translations
Requirements
- PHP 8.1 or higher
- Laravel 10.x or 11.x
Installation
1. Install via Composer
composer require ouredu/laravel-translation-client
2. Publish Configuration
php artisan vendor:publish --provider="OurEdu\TranslationClient\TranslationServiceProvider"
This will create config/translation-client.php.
3. Configure Environment
Add the following to your .env file:
TRANSLATION_SERVICE_URL=https://your-translation-service.com TRANSLATION_PRELOAD=true TRANSLATION_CLIENT=backend
4. Configure Available Locales
In config/translation-client.php, add:
'available_locales' => ['en', 'ar', 'fr'],
Configuration
All configuration options are in config/translation-client.php:
return [ // Translation service base URL 'service_url' => env('TRANSLATION_SERVICE_URL', 'http://localhost'), // Cache TTL in seconds 'manifest_ttl' => env('TRANSLATION_MANIFEST_TTL', 300), // 5 minutes 'bundle_ttl' => env('TRANSLATION_BUNDLE_TTL', 3600), // 1 hour // Client type: backend, frontend, mobile 'client' => env('TRANSLATION_CLIENT', 'backend'), // HTTP timeout in seconds 'http_timeout' => env('TRANSLATION_HTTP_TIMEOUT', 10), // Use stale cache on API failure 'fallback_on_error' => env('TRANSLATION_FALLBACK_ON_ERROR', true), // Cache store (null = default) 'cache_store' => env('TRANSLATION_CACHE_STORE'), // Logging 'logging' => [ 'enabled' => env('TRANSLATION_LOGGING', false), 'channel' => env('TRANSLATION_LOG_CHANNEL', 'stack'), ], /* |-------------------------------------------------------------------------- | Available Locales |-------------------------------------------------------------------------- | | The list of available locales to sync translations for | */ 'available_locales' => [ 'ar', 'en', ], ];
Usage
Basic Usage
Once installed, use Laravel's translation functions as normal:
// In controllers __('messages.welcome') trans('validation.required') // With replacements trans('messages.hello', ['name' => 'Ahmed'])
Commands
Clear Cache
Clear translation caches:
# Clear all translation caches php artisan translations:clear-cache # Clear specific locale php artisan translations:clear-cache --locale=ar
Import Translations
Import translations from Laravel lang files to the service:
# Import all locales php artisan translations:import # Import specific locale php artisan translations:import --locale=ar # Import from custom path php artisan translations:import --path=/path/to/lang
Keeping Translations Fresh
Nothing needs scheduling. Translations are fetched on first use and cached, and each cached bundle carries the version it was built from. That version is checked against the service's manifest on every read, so a bundle cannot go stale indefinitely.
There is a lag, though, and it is worth knowing. The manifest is itself cached
for manifest_ttl — 300 seconds by default. Until that entry expires the version
comparison is against a stale manifest, so it agrees with the cached bundle and
serves it. An edit in the service therefore appears within manifest_ttl, not on
the very next request.
Measured against a real consuming app: a value created in the service was still absent immediately afterwards, and present once the manifest cache was cleared.
Lower TRANSLATION_MANIFEST_TTL if you need edits to land faster — it costs one
small request per locale per interval — or run translations:clear-cache to force
it immediately.
Middleware for Locale Detection
Add to app/Http/Kernel.php:
protected $middlewareGroups = [ 'web' => [ // ... \OurEdu\TranslationClient\Middleware\SetLocaleFromRequest::class, ], ];
This middleware detects locale from:
- Query parameter (
?locale=ar) - Header (
X-Locale: ar) - Accept-Language header
- Authenticated user preference
Using the Facade
Reading Translations
use OurEdu\TranslationClient\Facades\Translation; // Check version $manifest = Translation::checkVersion('ar'); // Returns: ['version' => 42, 'etag' => '...', 'updated_at' => '...'] // Fetch specific groups $translations = Translation::fetchBundle('ar', ['messages', 'validation']); // Load all translations $all = Translation::loadTranslations('ar'); // Clear cache Translation::clearCache('ar');
Writing Translations
// Push single translation Translation::pushTranslation( locale: 'ar', group: 'messages', key: 'welcome', value: 'مرحبا' ); // Push multiple translations Translation::pushTranslations([ [ 'locale' => 'ar', 'group' => 'messages', 'key' => 'hello', 'value' => 'مرحباً', 'client' => 'backend', ], ]); // Import from Laravel lang files Translation::importFromFiles('ar', lang_path());
Programmatic Access
use OurEdu\TranslationClient\Services\TranslationClient; class MyService { public function __construct( private TranslationClient $translationClient ) {} public function getTranslations() { return $this->translationClient->fetchBundle('ar', ['messages']); } }
How It Works
Architecture
Laravel App → trans() → ApiTranslationLoader → TranslationClient → Translation Service API
↓
Memory Cache (in-memory)
↓
Laravel Cache (Redis/File)
↓
Translation Service (Redis + DB)
Caching Strategy
- Memory Cache: Loaded translations stored in PHP memory
- Laravel Cache: Persistent cache with configurable TTL
- Version Checking: Manifest API checked every 5 minutes
- Automatic Invalidation: Cache refreshed when version changes
Performance
- Cached Translation: ~1-5ms (from memory)
- Laravel Cache Hit: ~5-10ms
- API Call (first time): ~50-200ms
- Manifest Check: ~10-50ms
Multi-Tenant Support
For multi-tenant applications:
// Set tenant dynamically based on request config(['translation-client.tenant_id' => $currentTenant->id]); // Or extend the TranslationClient class MultiTenantTranslationClient extends TranslationClient { public function __construct() { parent::__construct(); $this->tenantUuid = auth()->user()?->tenant_uuid; } }
Error Handling
The package handles errors gracefully:
- API Unavailable: Uses stale cache if available
- Network Timeout: Falls back to cached data
- Invalid Response: Logs error and returns empty array
- Missing Translations: Falls back to key name (Laravel default)
Enable logging for debugging:
TRANSLATION_LOGGING=true TRANSLATION_LOG_CHANNEL=stack
Testing
When testing, you may want to disable API calls:
// In tests/TestCase.php protected function setUp(): void { parent::setUp(); // Mock the translation client $this->mock(TranslationClient::class, function ($mock) { $mock->shouldReceive('loadTranslations') ->andReturn(['messages.welcome' => 'Welcome']); }); }
Troubleshooting
Translations not loading
- Check service URL is correct:
php artisan config:cache - Verify API is accessible:
curl https://your-service.com/translation/manifest?locale=en - Enable logging:
TRANSLATION_LOGGING=true - Check logs:
tail -f storage/logs/laravel.log
Cache not clearing
php artisan cache:clear php artisan translations:clear-cache php artisan config:cache
Performance issues
- Use Redis for caching instead of file cache
- Increase cache TTL if translations rarely change
License
This package is open-sourced software licensed under the MIT license.
Support
For issues and questions, please use the GitHub issue tracker.