hyperlinkgroup/linguist

A package to manage your translation files from Linguist

Maintainers

Package info

github.com/hyperlinkgroup/linguist-package

Homepage

pkg:composer/hyperlinkgroup/linguist

Transparency log

Statistics

Installs: 15 983

Dependents: 0

Suggesters: 0

Stars: 2

Open Issues: 0

2.0.0 2026-07-01 06:14 UTC

README

Latest Version on Packagist GitHub Tests Action Status Total Downloads

A package to help you manage your translation files with Linguist — A better way to manage your language files.

linguist-package-header

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:

  1. API Token - Enter your Linguist API token
  2. Project Selection - Choose an existing project or create a new one
  3. 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
  4. 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\SyncCompleted
  • Hyperlinkgroup\Linguist\Events\PullCompleted
  • Hyperlinkgroup\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 projects
  • POST /v2/projects - Create new project
  • GET /v2/projects/{project} - Get project details (including source language)
  • PATCH /v2/projects/{project} - Update project
  • GET /v2/projects/{project}/languages - List project languages
  • GET /v2/projects/{project}/export/json/{language} - Get export URL
  • GET /v2/projects/{project}/translation-keys - List translation keys
  • POST /v2/projects/{project}/translation-keys - Create/update key
  • PATCH /v2/projects/{project}/translation-keys/{key} - Update key
  • DELETE /v2/projects/{project}/translation-keys/{key} - Delete key
  • POST /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.