A Laravel package to synchronize translations between your Laravel application and a centralized translation management system. Pull translations from the server or push local translations back to keep everything in sync.
- 🚀 One Command Install - Get started in seconds
- 🔄 Bi-directional Sync - Pull and push translations with simple commands
- 🌍 Multi-language - Support for all languages
- 📦 Laravel Compliant - Generates proper Laravel translation files with nested arrays
- ⚡ CI/CD Ready - Perfect for automated deployments
- 🔒 Secure - API token authentication
- 🎯 Smart Filtering - Filter by language, status, or specific files
- ⬆️ Push Support - Send local translations back to the server
- PHP 8.1 or higher
- Laravel 10, 11, or 12
Install via Composer:
composer require smartness/translation-clientThe package will automatically register itself via Laravel's package auto-discovery.
php artisan vendor:publish --tag=translation-client-configThis creates a config/translation-client.php file where you can customize settings.
Add these variables to your .env file:
# Required: Your API token
TRANSLATION_API_TOKEN=your_api_token_here
# Required: API endpoint URL
TRANSLATION_API_URL=https://your-translation-service.com/api
# Optional: Override default settings
TRANSLATION_OUTPUT_DIR= # Default: lang_path()
TRANSLATION_FORMAT=php # Options: php, json, raw
TRANSLATION_STATUS=approved # Filter: approved, pending, rejected
TRANSLATION_TIMEOUT=30 # HTTP timeout in secondsNote: You'll receive your API token and endpoint URL from your translation service administrator.
Pull all translations from the server:
php artisan translations:pullPull translations for a specific language:
php artisan translations:pull --language=enPreview changes without saving (dry-run):
php artisan translations:pull --dry-runTest API connection:
php artisan translations:pull --test# Override format for this pull
php artisan translations:pull --format=json
# Override status filter
php artisan translations:pull --status=approved
# Combine multiple options
php artisan translations:pull --language=de --status=approved --dry-runPush all local translations to the server:
php artisan translations:pushPush translations for a specific language:
php artisan translations:push --language=enPush a specific translation file:
php artisan translations:push --language=en --file=messagesPreview without actually pushing:
php artisan translations:push --dry-runOverwrite existing translations on the server:
php artisan translations:push --overwriteUse a custom translation directory:
php artisan translations:push --dir=/path/to/translations# Combine multiple options
php artisan translations:push --language=en --file=auth --overwrite
# Preview what will be pushed
php artisan translations:push --dry-run --language=deThe package creates translation files following Laravel's standard structure:
lang/
├── en/
│ ├── messages.php
│ ├── validation.php
│ └── auth.php
├── de/
│ ├── messages.php
│ ├── validation.php
│ └── auth.php
└── es/
├── messages.php
├── validation.php
└── auth.php
<?php
// lang/en/auth.php
return [
'failed' => 'These credentials do not match our records.',
'password' => 'The provided password is incorrect.',
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
// Nested arrays for dot-notation keys
'verification' => [
'sent' => 'A fresh verification link has been sent to your email address.',
'verified' => 'Your email address has been verified.',
],
];You can use the Translation Client directly in your code:
<?php
namespace App\Services;
use Smartness\TranslationClient\TranslationClient;
class TranslationSync
{
public function __construct(
protected TranslationClient $client
) {}
// Pull translations
public function syncTranslations(string $language): array
{
// Fetch translations as Laravel PHP arrays
$response = $this->client->fetchAsPhp($language);
return $response['data'];
}
public function syncAsJson(string $language): array
{
// Fetch translations as JSON format
$response = $this->client->fetchAsJson($language);
return $response['data'];
}
public function getRawTranslations(string $language): array
{
// Fetch raw format with metadata
$response = $this->client->fetchRaw($language);
return $response['data'];
}
// Push translations
public function pushTranslations(array $translations, bool $overwrite = false): array
{
// Push all translations
return $this->client->push($translations, [
'overwrite' => $overwrite,
]);
}
public function pushLanguageTranslations(string $language, array $translations, bool $overwrite = false): array
{
// Push translations for a specific language
return $this->client->pushLanguage($language, $translations, $overwrite);
}
public function pushFileTranslations(string $language, string $filename, array $translations): array
{
// Push a specific translation file
return $this->client->pushFile($language, $filename, $translations);
}
public function verifyConnection(): bool
{
return $this->client->testConnection();
}
}| Method | Description | Returns |
|---|---|---|
fetchAsPhp(?string $language) |
Fetch translations as nested PHP arrays (Laravel format) | array |
fetchAsJson(?string $language) |
Fetch translations as flat JSON structure | array |
fetchRaw(?string $language) |
Fetch raw format with full metadata | array |
fetch(array $options) |
Fetch with custom options | array |
push(array $translations, array $options) |
Push translations to the server | array |
pushLanguage(string $language, array $translations, bool $overwrite) |
Push translations for a specific language | array |
pushFile(string $language, string $filename, array $translations, bool $overwrite) |
Push a specific translation file | array |
testConnection() |
Verify API connection and token | bool |
Add this workflow to automatically sync translations:
# .github/workflows/sync-translations.yml
name: Sync Translations
on:
schedule:
- cron: '0 */6 * * *' # Every 6 hours
workflow_dispatch: # Allow manual trigger
jobs:
sync-translations:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
- name: Install dependencies
run: composer install --no-dev --optimize-autoloader
- name: Pull translations
env:
TRANSLATION_API_TOKEN: ${{ secrets.TRANSLATION_API_TOKEN }}
TRANSLATION_API_URL: ${{ secrets.TRANSLATION_API_URL }}
run: php artisan translations:pull
- name: Commit and push changes
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git add lang/
if git diff --staged --quiet; then
echo "No translation changes"
else
git commit -m "chore: update translations [skip ci]"
git push
fi# .gitlab-ci.yml
sync-translations:
stage: deploy
script:
- composer install --no-dev --optimize-autoloader
- php artisan translations:pull
- git config user.name "GitLab CI"
- git config user.email "ci@gitlab.com"
- git add lang/
- git diff --staged --quiet || git commit -m "chore: update translations [skip ci]"
- git push https://${GITLAB_USER}:${GITLAB_TOKEN}@${CI_REPOSITORY_URL#*@}
only:
- schedules
variables:
TRANSLATION_API_TOKEN: $TRANSLATION_API_TOKEN
TRANSLATION_API_URL: $TRANSLATION_API_URLAll configuration options available in config/translation-client.php:
return [
// API endpoint (required)
'api_url' => env('TRANSLATION_API_URL'),
// API authentication token (required)
'api_token' => env('TRANSLATION_API_TOKEN'),
// Output directory for translation files
// Default: lang_path() resolves to 'lang/' directory
'output_dir' => env('TRANSLATION_OUTPUT_DIR', null),
// Format: json, php, or raw
'format' => env('TRANSLATION_FORMAT', 'php'),
// Status filter: approved, pending, rejected, or null (all)
'status_filter' => env('TRANSLATION_STATUS', 'approved'),
// HTTP request timeout in seconds
'timeout' => env('TRANSLATION_TIMEOUT', 30),
];The package provides clear, actionable error messages:
# Missing configuration
❌ API token not configured. Please set TRANSLATION_API_TOKEN in your .env file.
# Invalid credentials
❌ Authentication failed: Invalid API token. Please check your TRANSLATION_API_TOKEN configuration.
# Connection issues
❌ API error: Failed to connect to translation service: Connection timeout
# No translations found
⚠ No translations found matching the criteria.Solution: Add your API token to .env:
TRANSLATION_API_TOKEN=your_token_here
TRANSLATION_API_URL=https://your-service.com/apiSolution: Verify your API token is correct. Contact your translation service administrator if needed.
Solutions:
- Check your network connection
- Verify the API URL is correct
- Increase timeout:
TRANSLATION_TIMEOUT=60
Solutions:
- Run with
--dry-runto preview changes - Check status filter:
--status=approved - Verify you have translations in the system
use Smartness\TranslationClient\TranslationClient;
$client = app(TranslationClient::class);
$response = $client->fetch([
'format' => 'php',
'language' => 'en',
'status' => 'approved',
'missing' => false,
'filename' => 'messages',
]);# Save to different directory
TRANSLATION_OUTPUT_DIR=/path/to/custom/lang# Development
TRANSLATION_API_URL=https://dev-translation-service.com/api
# Production
TRANSLATION_API_URL=https://translation-service.com/api- ✅ API token authentication
- ✅ HTTPS required for API communication
- ✅ Token validation before requests
- ✅ No sensitive data in logs
Important: Never commit your API token to version control. Always use environment variables.
For issues, questions, or feature requests:
- Email: dev@smartpricing.com
- Issues: GitHub Issues
The MIT License (MIT). Please see License File for more information.