laravel-translation-client maintained by our-edu
Laravel Translation Client
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
Sync Translations
Manually fetch and cache translations:
# Sync all locales
php artisan translations:sync
# Sync specific locale
php artisan translations:sync --locale=ar
# Force refresh (clear cache first)
php artisan translations:sync --force
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
Scheduled Sync
Add to app/Console/Kernel.php to sync translations hourly:
protected function schedule(Schedule $schedule): void
{
$schedule->command('translations:sync')->hourly();
}
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.