habr/bblslug

CLI translation tool for HTML and plain text using LLM-based APIs.

Installs: 1 030

Dependents: 0

Suggesters: 0

Security: 0

Stars: 1

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/habr/bblslug

v0.7.0 2025-08-09 01:14 UTC

This package is auto-updated.

Last update: 2025-12-24 14:51:56 UTC


README

Bblslug is a versatile translation tool that can be used as both a CLI utility and a PHP library.

It leverages LLM-based APIs to translate plain text, HTML and JSON while preserving structure, code blocks, and URLs via placeholder filters.

APIs supported:

  • Anthropic (Claude):
    • anthropic:claude-haiku-3.5 - Claude Haiku 3.5 (latest)
    • anthropic:claude-opus-4 - Claude Opus 4 (20250514)
    • anthropic:claude-sonnet-4 - Claude Sonnet 4 (20250514)
  • DeepL:
    • deepl:free - DeepL free tier
    • deepl:pro - DeepL pro tier
  • Google (Gemini):
    • google:gemini-2.5-flash - Gemini 2.5 Flash
    • google:gemini-2.5-flash-lite - Gemini 2.5 Flash Lite
    • google:gemini-2.5-pro - Gemini 2.5 Pro
    • google:gemini-2.0-flash - Gemini 2.0 Flash
  • OpenAI (GPT):
    • openai:gpt-5 - OpenAI GPT-5
    • openai:gpt-5-mini - OpenAI GPT-5 Mini
    • openai:gpt-5-nano - OpenAI GPT-5 Nano
    • openai:gpt-4o - OpenAI GPT-4o
    • openai:gpt-4o-mini - OpenAI GPT-4o Mini
    • openai:gpt-4 - OpenAI GPT-4
    • openai:gpt-4-turbo - OpenAI GPT-4 Turbo
  • Yandex:
    • yandex:gpt-lite - YandexGPT Lite
    • yandex:gpt-pro - YandexGPT Pro
    • yandex:gpt-32k - YandexGPT Pro 32K
  • X.ai:
    • xai:grok-4 - Grok 4
    • xai:grok-3 - Grok 3
    • xai:grok-3-mini - Grok 3 Mini

Features

  • Supports HTML, JSON and plain text (--format=text|html|json)
  • Placeholder-based protection with filters: html_pre, html_code, url, etc.
  • Model selection via --model=vendor:name
  • Fully configurable backend registry (via resources/models.yaml)
  • Dry-run mode to preview placeholders without making API calls
  • Variables (--variables) to send or override model-specific options
  • Verbose mode (--verbose) to print request previews
  • Can be invoked as a CLI tool or embedded in PHP code
  • Validation of container syntax for HTML or JSON; disable with --no-validate

Installation

composer require habr/bblslug
chmod +x vendor/bin/bblslug

CLI Usage

Prepare

  1. Always specify a model with --model=vendor:name option.

  2. Export your API key(s) before running:

export ANTHROPIC_API_KEY=...
export DEEPL_FREE_API_KEY=...
export DEEPL_PRO_API_KEY=...
export GOOGLE_API_KEY=...
export OPENAI_API_KEY=...
export YANDEX_API_KEY=... && export YANDEX_FOLDER_ID=...
export XAI_API_KEY=...

NB! Some vendors require additional parameters, e.g. YANDEX_FOLDER_ID.

  1. Input / output:
  • If --source is omitted, Bblslug reads from STDIN.
  • If --translated is omitted, Bblslug writes to STDOUT.
  1. Optional proxy:

To route requests through a proxy (e.g. HTTP or SOCKS5), use the --proxy option or set the BBLSLUG_PROXY environment variable:

# using CLI flag
vendor/bin/bblslug --proxy="http://localhost:8888" ...

# or set it globally
export BBLSLUG_PROXY="socks5h://127.0.0.1:9050"

This works for all HTTP requests and supports authentication (http://user:pass@host:port).

Show available models

vendor/bin/bblslug --list-models

Show available prompt templates

vendor/bin/bblslug --list-prompts

Translate an HTML file and write to another file

vendor/bin/bblslug \
  --model=vendor:name \
  --format=html \
  --source=input.html \
  --translated=output.html

Translate an JSON file and write to another file

vendor/bin/bblslug \
  --model=vendor:name \
  --format=json \
  --source=input.json \
  --translated=output.json

Translate an HTML file and write to another file with filters

vendor/bin/bblslug \
  --model=vendor:name \
  --format=html \
  --source=input.html \
  --translated=output.html \
  --filters=url,html_code,html_pre

Add translation context (prompt), source and target language

vendor/bin/bblslug \
  --model=vendor:name \
  --format=html \
  --source=input.html \
  --translated=output.html \
  --target-lang=EN \
  --source-lang=DE \
  --context="Translate as a professional technical translator"

Pass model-specific variables

vendor/bin/bblslug \
  --model=vendor:name \
  --format=text \
  --variables=foo=bar,foo2=bar2 \
  --source=in.txt \
  --translated=out.txt

Choose a different prompt template

vendor/bin/bblslug \
  --model=vendor:name \
  --format=html \
  --source=input.html \
  --translated=out.html \
  --prompt-key=smart-legal

Dry-run placeholders only

vendor/bin/bblslug \
  --model=vendor:name \
  --format=text \
  --filters=url \
  --source=input.txt \
  --dry-run

Verbose mode (prints request preview to stderr)

vendor/bin/bblslug \
  --model=vendor:name \
  --format=html \
  --verbose \
  --source=input.html \
  --translated=out.html

Pipe STDIN → file

cat input.txt | vendor/bin/bblslug \
  --model=vendor:name \
  --format=text \
  --translated=out.txt

Pipe STDIN → STDOUT

echo "Hello world" | vendor/bin/bblslug \
  --model=vendor:name \
  --format=text > translated.out

Disable validation

For HTML and JSON formats, Bblslug performs basic syntax validation before and after translation. To skip this step, add:

vendor/bin/bblslug \
  --model=vendor:name \
  --format=html \
  --no-validate \
  --source=input.html \
  --translated=out.html

Statistics

  • Usage metrics

    After each translation (when not in dry-run), Bblslug prints to stderr a summary of consumed usage metrics, for example:

    Usage metrics:
        Tokens:
            Total:       1074
            -----------------
            Prompt:      631
            Completion:  443
    

PHP Library Usage

You can embed Bblslug in your PHP project.

Quickstart

  1. Install:
composer require habr/bblslug
  1. Require & Import:
require 'vendor/autoload.php';
use Bblslug\Bblslug;

Translate

Text translation function example:

$text = file_get_contents('input.html');
$result = Bblslug::translate(
    apiKey:   getenv('MODEL_API_KEY'),         // API key for the chosen model
    format:   'html',                          // 'text', 'html' of 'json'
    modelKey: 'vendor:model',                  // Model identifier (e.g. deepl:free, openai:gpt-4o, etc.)
    text:     $text,                           // Source text to be translated
    // optional:
    // Additional context/prompt pass to model
    context:    'Translate as a professional technical translator',
    filters:    ['url','html_code'],           // List of placeholder filters
    promptKey: 'translator',                   // which prompt template to use
    proxy:      getenv('BBLSLUG_PROXY'),       // Optional proxy URI (http://..., socks5h://...)
    sourceLang: 'DE',                          // Source language code (optional; autodetect if null)
    targetLang: 'EN',                          // Target language code (optional; default from driver settings)
    validate: false,                           // perform or skip syntax validation for container formats
    variables:  ['foo'=>'bar'],                // model-specific overrides
    verbose:    true,                          // If true, returns debug request/response
);
echo $result['result'];

Result structure:

[
  'original'        => string,   // Original input
  'prepared'        => string,   // After placeholder filters
  'result'          => string,   // Translated result
  'httpStatus'      => int,      // HTTP status
  'debugRequest'    => string,   // Request debug
  'debugResponse'   => string,   // Response debug
  'rawResponseBody' => string,   // Response body
  'consumed'        => [                  // Normalized usage metrics
     'tokens' => [
       'total'     => int,                // Total tokens consumed
       'breakdown' => [                   // Per-type breakdown
         'prompt'      => int,            // Name depeds of model
         'completion'  => int,            // Name depeds of model
       ],
     ],
     // additional categories if supported by the model...
  'lengths'         => [         // Text length statistics
     'original'    => int,       // - original text
     'prepared'    => int,       // - after placeholder filters
     'translated'  => int,       // - returned translated text
  ],
  'filterStats'     => [         // Placeholder stats
     ['filter'=>'url','count'=>3], …
  ],
]

List available models

$modelsByVendor = Bblslug::listModels();

foreach ($modelsByVendor as $vendor => $models) {
    echo "Vendor: {$vendor}\n";
    foreach ($models as $key => $config) {
        printf("  - %s: %s\n", $key, $config['notes'] ?? '(no notes)');
    }
}

Returns an array like:

[
  'deepl'  => ['deepl:free' => […], 'deepl:pro' => […]],
  'openai' => ['openai:gpt-4' => […], …],
  …
]

List available prompts

$prompts = Bblslug::listPrompts();

foreach ($prompts as $key => $info) {
    $formats = implode(', ', $info['formats']);
    echo "{$key} ({$formats})";
    if (! empty($info['notes'])) {
        echo "{$info['notes']}";
    }
    echo "\n";
}

Returns an array like:

[
  'translator' => [
      'formats' => ['text', 'html', 'json'],
      'notes'   => 'professional translator template',
  ],
  'legal'      => [
      'formats' => ['text'],
      'notes'   => 'legal-style translator template',
  ],
  // …
]

Error handling

try {
    $res = Bblslug::translate(...);
} catch (\InvalidArgumentException $e) {
    // invalid model, missing API key, etc.
} catch (\RuntimeException $e) {
    // HTTP error, parse failure, driver-specific error
}

Samples

You can find sample input files under the samples/ directory.

License

This project is licensed under the MIT License – see the LICENSE file for details.