hyperlinkgroup / linguist
A package to manage your translation files from Linguist
Requires
- php: ^8.3
- guzzlehttp/guzzle: ^7.2
- illuminate/contracts: ^12.0|^13.0
- lorisleiva/laravel-actions: ^2.10
- spatie/laravel-package-tools: ^1.93
Requires (Dev)
- hyperlinkgroup/pint: ^1.0
- larastan/larastan: ^3.0
- laravel/pao: ^1.1
- nunomaduro/collision: ^8.9.3
- orchestra/testbench: ^10.0|^11.0
- pestphp/pest: ^4.4.3
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
This package is auto-updated.
Last update: 2026-07-01 06:15:54 UTC
README
A package to help you manage your translation files with Linguist — A better way to manage your language files.
Installation
You can install the package via composer:
composer require hyperlinkgroup/linguist
You can optionally publish the config file with:
php artisan vendor:publish --tag="linguist-config"
Quick Start (Setup Wizard)
The easiest way to get started is using the interactive setup wizard:
php artisan linguist:setup
This wizard will guide you through:
- API Token - Enter your Linguist API token
- Project Selection - Choose an existing project or create a new one
- Sync Mode - Select how you want to synchronize translations:
- Sync: Merge local and remote translations (two-way)
- Pull: Download from Linguist (overwrite local)
- Push: Upload local translations to Linguist
- Options - Configure setup preferences and optional auto-translation
Configuration
The published config file (config/linguist.php):
return [ /* |-------------------------------------------------------------------------- | Linguist API URL |-------------------------------------------------------------------------- */ 'url' => env('LINGUIST_URL', 'https://api.linguist.eu/v2'), /* |-------------------------------------------------------------------------- | Linguist Project Slug |-------------------------------------------------------------------------- */ 'project' => env('LINGUIST_PROJECT', ''), /* |-------------------------------------------------------------------------- | Linguist API Token |-------------------------------------------------------------------------- */ 'token' => env('LINGUIST_TOKEN', ''), /* |-------------------------------------------------------------------------- | Linguist API Token Settings URL |-------------------------------------------------------------------------- */ 'api_tokens_url' => env('LINGUIST_API_TOKENS_URL', 'https://app.linguist.eu/settings/api-tokens'), /* |-------------------------------------------------------------------------- | Temporary Directory for Translations while processing |-------------------------------------------------------------------------- */ 'temporary_directory' => 'tmp/translations', /* |-------------------------------------------------------------------------- | Pull Minified |-------------------------------------------------------------------------- | When enabled, pulled translation files are written as minified JSON. | By default, files are pretty-printed for readability and easier diffing. |-------------------------------------------------------------------------- */ 'pull_minified' => env('LINGUIST_PULL_MINIFIED', false), ];
The setup wizard automatically writes these values to your .env file.
LINGUIST_URL should point to the versioned API base URL (for example https://api.your-domain.com/v2).
LINGUIST_API_TOKENS_URL is the URL opened when users follow the Linguist API settings link printed before the token prompt (clickable in terminals that support hyperlinks; otherwise the label is still shown as plain text).
LINGUIST_PULL_MINIFIED controls whether pulled translation files are written as minified JSON. Defaults to false (pretty-printed).
Commands
linguist:setup
Interactive wizard for initial setup and configuration. Handles project creation/selection, sync mode configuration, and API token management.
linguist:sync
Runs translation synchronization in one of three modes (sync, pull, push).
php artisan linguist:sync
If run interactively, the command prompts for mode selection (same choices as setup).
For scheduler/non-interactive execution, the command defaults to sync mode unless you pass an explicit mode flag:
php artisan linguist:sync --sync php artisan linguist:sync --pull php artisan linguist:sync --push
Alternatively, use the --mode option:
php artisan linguist:sync --mode=sync php artisan linguist:sync --mode=pull php artisan linguist:sync --mode=push
Mode-specific options:
# sync mode options php artisan linguist:sync --sync --prune-remote-keys php artisan linguist:sync --sync --no-activate-missing-languages php artisan linguist:sync --sync --sync-source=local php artisan linguist:sync --sync --sync-source=remote # push mode options php artisan linguist:sync --push --overwrite php artisan linguist:sync --push --languages=EN,DE
--prune-remote-keys deletes remote keys that no longer exist locally before upload (sync mode).
--no-activate-missing-languages skips activating local languages that are not yet active in the remote project. Applies to all modes. If omitted, the command prompts interactively or activates automatically in non-interactive contexts.
--sync-source controls which side wins for existing keys in sync mode: remote (default) keeps the remote value, local overwrites with the local value.
Sync Modes
Sync Mode (Recommended)
Performs a two-phase sync:
- Uploads local keys first (
push) - Downloads the resulting remote state (
pull) into local files
Pull Mode
Downloads all translations from Linguist and overwrites local files:
- Fetches all active languages
- Downloads translation files
- Replaces local files entirely in Laravel native locale JSON format (
lang/en.json,lang/de.json, ...)
Push Mode
Uploads local translations to Linguist:
- Reads all local translation files
- Creates/updates keys on remote
- Preserves remote-only keys
Events
The package dispatches Laravel events after successful operations:
Hyperlinkgroup\Linguist\Events\SyncCompletedHyperlinkgroup\Linguist\Events\PullCompletedHyperlinkgroup\Linguist\Events\PushCompleted
Each event contains:
$projectSlug(string)$result(Hyperlinkgroup\Linguist\DTO\SyncResult)
Example listener:
use Hyperlinkgroup\Linguist\Events\SyncCompleted; use Illuminate\Support\Facades\Event; Event::listen(SyncCompleted::class, function (SyncCompleted $event): void { logger()->info('Linguist sync completed', [ 'project' => $event->projectSlug, 'keys_processed' => $event->result->keysProcessed, ]); });
Advanced Usage
Using Actions Directly
For custom implementations, you can call the provided actions directly:
use Hyperlinkgroup\Linguist\Services\LinguistApiClient; use Hyperlinkgroup\Linguist\Actions\SyncTranslations; // API Client $client = app(LinguistApiClient::class); $projects = $client->listProjects()->json('data'); // Sync Action $result = SyncTranslations::run( projectSlug: 'my-project', pruneRemoteKeys: true, ); echo $result->getSummaryMessage();
Data Transfer Objects
The package provides typed DTOs for configuration:
use Hyperlinkgroup\Linguist\DTO\SetupInput; use Hyperlinkgroup\Linguist\DTO\SetupResult; use Hyperlinkgroup\Linguist\DTO\SyncResult; $input = new SetupInput( apiToken: 'your-token', projectSlug: 'my-project', syncMode: 'sync', pruneRemoteKeys: false, activateMissingLanguages: true, ); // From array $input = SetupInput::fromArray([ 'api_token' => 'your-token', 'project_slug' => 'my-project', ]); // Setup results $setupResult = app(\Hyperlinkgroup\Linguist\Services\SetupOrchestrator::class)->execute($input); $setupResult->configPersisted; // bool $setupResult->projectCreated; // bool $setupResult->projectSlug; // ?string $setupResult->syncResult; // ?SyncResult $setupResult->autoTranslate; // bool $setupResult->hasErrors(); // bool // Sync results $result = SyncTranslations::run(projectSlug: 'my-project'); $result->overallSuccess; // bool $result->hasPartialSuccess(); // bool $result->getFailedLanguages(); // array $result->getSummaryMessage(); // string
Error Handling and Reporting
All sync operations return detailed SyncResult objects with:
- Per-language results: Success/failure status for each language
- Partial success detection: Identify which languages succeeded or failed
- Detailed error messages: Specific failure reasons per language
- Key counts: Total processed and failed key counts
Example output:
Sync Results:
Partial sync completed. 2 languages successful, 1 languages failed. (150 keys processed, 3 failed)
Per-language results:
✓ EN
✓ DE
✗ FR: Failed to download translations
API Endpoints
The package communicates with Linguist's REST API (/v2):
GET /v2/projects- List available projectsPOST /v2/projects- Create new projectGET /v2/projects/{project}- Get project details (including source language)PATCH /v2/projects/{project}- Update projectGET /v2/projects/{project}/languages- List project languagesGET /v2/projects/{project}/export/json/{language}- Get export URLGET /v2/projects/{project}/translation-keys- List translation keysPOST /v2/projects/{project}/translation-keys- Create/update keyPATCH /v2/projects/{project}/translation-keys/{key}- Update keyDELETE /v2/projects/{project}/translation-keys/{key}- Delete keyPOST /v2/projects/{project}/translate- Trigger auto-translation
All endpoints require Bearer token authentication.
Testing
composer test
The test suite includes:
- Unit tests for actions and core orchestration logic
- DTO validation tests
- Legacy integration tests
- HTTP mocking for API interactions
License
The MIT License (MIT). Please see License File for more information.
