PHPackages                             tobento/service-machine-translator - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. tobento/service-machine-translator

ActiveLibrary[HTTP &amp; Networking](/categories/http)

tobento/service-machine-translator
==================================

A flexible and extensible machine translator service built around clean interfaces.

2.0.1(1mo ago)01↑2900%1MITPHPPHP &gt;=8.4

Since Mar 27Pushed 1mo agoCompare

[ Source](https://github.com/tobento-ch/service-machine-translator)[ Packagist](https://packagist.org/packages/tobento/service-machine-translator)[ Docs](https://www.tobento.ch)[ RSS](/packages/tobento-service-machine-translator/feed)WikiDiscussions 2.x Synced 1mo ago

READMEChangelog (2)Dependencies (9)Versions (3)Used By (1)

Machine Translator Service
==========================

[](#machine-translator-service)

The Machine Translator service provides:

- A unified abstraction for translating text across multiple [translators](#translator)
- A consistent API for single and bulk translations
- Provider-specific error handling (including quota detection)
- Interchangeable translators without changing application code

It ships with multiple translator implementations, each following the same interface while preserving provider-specific capabilities and behaviors.

Table of Contents
-----------------

[](#table-of-contents)

- [Getting started](#getting-started)
    - [Requirements](#requirements)
    - [Highlights](#highlights)
- [Documentation](#documentation)
    - [Basic Usage](#basic-usage)
        - [Translating Text](#translating-text)
    - [Translator](#translator)
        - [Azure Translator](#azure-translator)
        - [DeepL Translator](#deepl-translator)
        - [Google Translator](#google-translator)
        - [Null Translator](#null-translator)
        - [Rotating Translator](#rotating-translator)
    - [Translators](#translators)
        - [Default Translators](#default-translators)
        - [Lazy Translators](#lazy-translators)
    - [Non-Translatable Strategies](#non-translatable-strategies)
        - [Composite Strategy](#composite-strategy)
        - [Null Strategy](#null-strategy)
        - [Placeholder Strategy](#placeholder-strategy)
        - [Using Strategies with Translators](#using-strategies-with-translators)
- [Credits](#credits)

---

Getting started
===============

[](#getting-started)

Add the latest version of the Machine Translator service project running this command.

```
composer require tobento/service-machine-translator

```

Requirements
------------

[](#requirements)

- PHP 8.4 or above

Highlights
----------

[](#highlights)

- Framework-agnostic, will work with any project
- Decoupled design

Documentation
=============

[](#documentation)

Basic Usage
-----------

[](#basic-usage)

### Translating Text

[](#translating-text)

To translate text, use the `translate()` or `translateMany()` method:

```
use Tobento\Service\MachineTranslator\Exception\TranslateException;
use Tobento\Service\MachineTranslator\MachineTranslatorInterface;

class SomeService
{
    public function translate(MachineTranslatorInterface $translator): void
    {
        try {
            $translated = $translator->translate(
                text: 'Hello World',
                locale: 'de'
            );

            // "Hallo Welt"
        } catch (TranslateException $e) {
            // handle
        }
    }

    public function translateMany(MachineTranslatorInterface $translator): void
    {
        try {
            $translated = $translator->translateMany(
                texts: ['Hello', 'How are you?'],
                locale: 'de'
            );

            // [
            //     "Hallo",
            //     "Wie geht es dir?"
            // ]
        } catch (TranslateException $e) {
            // handle
        }
    }
}
```

See the available [Translator](#translator) implementations to learn more about Azure, DeepL, Google, and the Null translator.

See the [Translators](#translators) section to learn how to manage multiple translators or lazy-load them.

Translator
----------

[](#translator)

### Azure Translator

[](#azure-translator)

#### Translator

[](#translator-1)

The Azure Translator provides machine translation using the Azure Cognitive Services Translator API.
It supports single and bulk translations, detects quota-related errors, and returns consistent results through the shared `MachineTranslatorInterface`.

When using `translateMany()`, all texts are translated in **one API request**, reducing latency and helping avoid rate-limit issues.

You can obtain your API key by creating a Translator resource in the Azure Portal.
Official documentation:

#### Translator Factory

[](#translator-factory)

The Azure translator can be created using the `Azure\TranslatorFactory`.
It requires an HTTP client, PSR-17 factories, and your Azure Translator configuration.

```
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Tobento\Service\MachineTranslator\Azure;
use Tobento\Service\MachineTranslator\MachineTranslatorFactoryInterface;
use Tobento\Service\MachineTranslator\MachineTranslatorInterface;

$factory = new Azure\TranslatorFactory(
    client: $client, // ClientInterface
    requestFactory: $requestFactory, // RequestFactoryInterface
    streamFactory: $streamFactory, // StreamFactoryInterface

    // Optional (defaults shown)
    defaults: [
        //'endpoint' => 'https://api.cognitive.microsofttranslator.com',
        //'region'   => 'westeurope',
    ],
);

var_dump($factory instanceof MachineTranslatorFactoryInterface);
// bool(true)

$translator = $factory->createTranslator(
    name: 'azure',
    config: [
        'apiKey'   => 'YOUR_API_KEY',

        // Optional (defaults shown)
        //'endpoint' => 'https://api.cognitive.microsofttranslator.com',
        //'region'   => 'westeurope',
    ]
);

var_dump($translator instanceof MachineTranslatorInterface);
```

> This translator supports non-translatable strategies.
> See [Using Strategies with Translators](#using-strategies-with-translators).

### DeepL Translator

[](#deepl-translator)

#### Translator

[](#translator-2)

The DeepL Translator provides machine translation using the DeepL Translation API.
It supports single and bulk translations, handles DeepL-specific error responses, and returns consistent results through the shared `MachineTranslatorInterface`.

When using `translateMany()`, all texts are translated in **one API request**, reducing latency and helping avoid rate-limit issues.

You can obtain your API key by creating a DeepL API account.
Official documentation:

#### Translator Factory

[](#translator-factory-1)

The DeepL translator can be created using the `DeepL\TranslatorFactory`.
It requires an HTTP client, PSR-17 factories, and your DeepL API configuration.

```
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Tobento\Service\MachineTranslator\DeepL;
use Tobento\Service\MachineTranslator\MachineTranslatorFactoryInterface;
use Tobento\Service\MachineTranslator\MachineTranslatorInterface;

$factory = new DeepL\TranslatorFactory(
    client: $client, // ClientInterface
    requestFactory: $requestFactory, // RequestFactoryInterface
    streamFactory: $streamFactory, // StreamFactoryInterface

    // Optional (defaults shown)
    defaults: [
        //'endpoint' => 'https://api.deepl.com/v2/translate',
    ],
);

var_dump($factory instanceof MachineTranslatorFactoryInterface);
// bool(true)

$translator = $factory->createTranslator(
    name: 'deepl',
    config: [
        'apiKey' => 'YOUR_API_KEY',

        // Optional (defaults shown)
        //'endpoint' => 'https://api.deepl.com/v2/translate',
    ]
);

var_dump($translator instanceof MachineTranslatorInterface);
// bool(true)
```

> This translator supports non-translatable strategies.
> See [Using Strategies with Translators](#using-strategies-with-translators).

### Google Translator

[](#google-translator)

#### Translator

[](#translator-3)

The Google Translator provides machine translation using the Google Cloud Translation API.
It supports single and bulk translations, handles Google-specific error responses, and returns consistent results through the shared `MachineTranslatorInterface`.

When using `translateMany()`, all texts are translated in **one API request**, reducing latency and helping avoid rate-limit issues.

You can obtain your API key by creating a Translation API resource in the Google Cloud Console.
Official documentation:

#### Translator Factory

[](#translator-factory-2)

The Google translator can be created using the `Google\TranslatorFactory`.
It requires an HTTP client, PSR-17 factories, and your Google Cloud Translation configuration.

```
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Tobento\Service\MachineTranslator\Google;
use Tobento\Service\MachineTranslator\MachineTranslatorFactoryInterface;
use Tobento\Service\MachineTranslator\MachineTranslatorInterface;

$factory = new Google\TranslatorFactory(
    client: $client, // ClientInterface
    requestFactory: $requestFactory, // RequestFactoryInterface
    streamFactory: $streamFactory, // StreamFactoryInterface

    // Optional (defaults shown)
    defaults: [
        //'endpoint' => 'https://translation.googleapis.com/language/translate/v2',
    ],
);

var_dump($factory instanceof MachineTranslatorFactoryInterface);
// bool(true)

$translator = $factory->createTranslator(
    name: 'google',
    config: [
        'apiKey' => 'YOUR_API_KEY',

        // Optional (defaults shown)
        //'endpoint' => 'https://translation.googleapis.com/language/translate/v2',
    ]
);

var_dump($translator instanceof MachineTranslatorInterface);
// bool(true)
```

> This translator supports non-translatable strategies.
> See [Using Strategies with Translators](#using-strategies-with-translators).

### Null Translator

[](#null-translator)

The Null Translator is a no-operation translator implementation.
It returns the original text unchanged and is useful for testing, development, or scenarios where translation is optional or disabled.

It supports both `translate()` and `translateMany()` and always returns the input as-is.

```
use Tobento\Service\MachineTranslator\NullMachineTranslator;
use Tobento\Service\MachineTranslator\MachineTranslatorInterface;

$translator = new NullMachineTranslator();

var_dump($translator instanceof MachineTranslatorInterface);
// bool(true)

// Examples:
var_dump($translator->translate(text: 'Hello', locale: 'de'));
// string(5) "Hello"

var_dump($translator->translateMany(texts: ['A', 'B'], locale: 'fr'));
// array(2) { [0]=> string(1) "A" [1]=> string(1) "B" }
```

### Rotating Translator

[](#rotating-translator)

The `RotatingMachineTranslator` allows you to combine multiple translators into a **single, unified translator** that automatically delegates translation to other translators based on configurable rotation rules.

This is useful when you want:

- **Failover**: if one translator fails, try the next one
- **Load balancing**: distribute translation requests across providers
- **Quota balancing**: rotate when one provider hits rate limits
- **Selective participation**: include or exclude specific translators
- **Fallback**: use a final translator if all others fail

`RotatingMachineTranslator` implements `MachineTranslatorInterface`, so it can be used anywhere a normal translator is expected.

#### Using with Lazy Translators

[](#using-with-lazy-translators)

When using [Lazy Translators](#lazy-translators), the callable receives:

- the `translator` registry (`MachineTranslatorsInterface`)
- the translator `name`
- everything else resolved by autowiring

This allows you to construct a rotating translator directly:

Example:

```
use Tobento\Service\MachineTranslator\RotatingMachineTranslator;
use Tobento\Service\MachineTranslator\MachineTranslatorInterface;
use Tobento\Service\MachineTranslator\MachineTranslatorsInterface;
use Tobento\Service\MachineTranslator\Exception\TranslateException;

'rotator' => function (
    string $name,
    MachineTranslatorInterface $translators,
): MachineTranslatorInterface {

    return new RotatingMachineTranslator(
        translators: $translators,
        name: $name,

        // Only use these translators (optional)
        only: ['azure', 'google'],

        // Exclude these translators (optional)
        except: [],

        // Fallback translator name (optional)
        fallback: 'null',
        // or:
        //fallback: null, // will throw if all fail

        // Rotation strategy
        strategy: RotatingMachineTranslator::STRATEGY_FAILOVER,
        // or:
        //strategy: RotatingMachineTranslator::STRATEGY_ROUND_ROBIN,
    );
},
```

The rotation strategy controls how translators are selected.
`STRATEGY_FAILOVER` tries translators in order until one succeeds, while
`STRATEGY_ROUND_ROBIN` cycles through translators on each request.

The fallback translator is used only if all selected translators fail.
If `fallback` is set to `null`, a `TranslateException` will be thrown instead. If the fallback translator is defined but also fails, a `TranslateException` will be thrown.
The fallback is the final step in the rotation chain.

Translators
-----------

[](#translators)

### Default Translators

[](#default-translators)

The `MachineTranslators` class provides a simple, eager registry for machine translators.
Unlike `LazyMachineTranslators`, all translators are **fully constructed upfront** and registered directly through the constructor.

This is ideal when:

- you want predictable, immediate initialization
- your translators are already created through factories
- you prefer explicit, ready-to-use translator instances
- you only need a small number of translators

`MachineTranslators` implements both `MachineTranslatorsInterface` and `MachineTranslatorInterface`, allowing it to be used either as a **registry** or as a **default translator** (delegating to the first registered translator).

**Example**

```
use Tobento\Service\MachineTranslator\MachineTranslators;
use Tobento\Service\MachineTranslator\Exception\MachineTranslatorNotFoundException;
use Tobento\Service\MachineTranslator\MachineTranslatorInterface;
use Tobento\Service\MachineTranslator\MachineTranslatorsInterface;

// Create translator instances (typically via factories):
$azure = $azureFactory->createTranslator(name: 'azure', config: [
    'apiKey' => 'azure-key',
]);

$deepl = $deeplFactory->createTranslator(name: 'deepl', config: [
    'apiKey' => 'deepl-key',
]);

// Register them:
$translators = new MachineTranslators(
    $azure,
    $deepl,
);

var_dump($translators instanceof MachineTranslatorsInterface);
// bool(true)

// Retrieve a translator by name:
$azureTranslator = $translators->get('azure');
// will throw MachineTranslatorNotFoundException if the translator does not exist

// Check if a translator exists:
if ($translators->has('azure')) {
    // translator is available
}

// Get all registered translator names:
$names = $translators->names();
// e.g. ['azure', 'deepl']

// Use Translators as the default translator:
$translated = $translators->translate(
    text: 'Hello World',
    locale: 'de'
);
```

### Lazy Machine Translators

[](#lazy-machine-translators)

The `LazyMachineTranslators` class allows you to register machine translators without creating them upfront.
Translators are instantiated **only when first accessed**, which is useful when using factories, callables, or configuration‑based setups.

`LazyMachineTranslators` implements both `MachineTranslatorsInterface` and `MachineTranslatorInterface`, so it can be used as a **registry** or as a **default translator** (delegating to the first registered translator).

**Example**

```
use Psr\Container\ContainerInterface;
use Tobento\Service\MachineTranslator\LazyMachineTranslators;
use Tobento\Service\MachineTranslator\MachineTranslatorInterface;
use Tobento\Service\MachineTranslator\MachineTranslatorsInterface;
use Tobento\Service\MachineTranslator\Exception\MachineTranslatorNotFoundException;

$translators = new LazyMachineTranslators(
    container: $container,
    translators: [

        // 1. Direct instance:
        'azure-direct' => $azureFactory->createTranslator(
            name: 'azure-direct',
            config: ['apiKey' => 'azure-key']
        ),

        // 2. Callable definition:
        'deepl-callable' => function (
            string $name,
            MachineTranslatorsInterface $translators,
            // (everything else resolved by autowiring)
            ContainerInterface $c,
        ): MachineTranslatorInterface {
            return $c->get(\Tobento\Service\MachineTranslator\DeepL\TranslatorFactory::class)
                ->createTranslator(
                    name: 'deepl-callable',
                    config: ['apiKey' => 'deepl-key']
                );
        },

        // 3. Factory definition:
        'google-factory' => [
            'factory' => \Tobento\Service\MachineTranslator\Google\TranslatorFactory::class,
            'config' => [
                'apiKey' => 'google-key',
            ],
        ],
    ]
);

var_dump($translators instanceof MachineTranslatorsInterface);
// bool(true)

// Retrieve a translator by name:
$azure = $translators->get('azure-direct');
// will throw MachineTranslatorNotFoundException if the translator does not exist

// Check if a translator exists:
if ($translators->has('azure-direct')) {
    // translator is available
}

// Get all registered translator names:
$names = $translators->names();
// e.g. ['azure-direct', 'deepl-callable', 'google-factory']

// Use LazyMachineTranslators as a default translator:
$translated = $translators->translate(
    text: 'Hello World',
    locale: 'de'
);
```

Non-Translatable Strategies
---------------------------

[](#non-translatable-strategies)

Non-translatable strategies let you protect parts of a text from being altered during translation. This is essential when working with placeholders, template variables, IDs, or any content that must remain exactly as it is. A strategy wraps these segments before sending the text to the translation API and restores them afterward, ensuring your dynamic values stay intact across all translators.

### Composite Strategy

[](#composite-strategy)

The Composite strategy allows you to combine multiple non-translatable strategies and apply them in sequence. Each strategy performs its own protection logic, making it easy to mix behaviors. For example, protecting both indicator-based placeholders like `:name` and wrapper-based placeholders like `{id}`. Protection is applied in order, while unprotection runs in reverse order to safely restore the original text.

```
use Tobento\Service\MachineTranslator\NonTranslatableStrategy;
use Tobento\Service\MachineTranslator\NonTranslatableStrategyInterface;

$strategy = new NonTranslatableStrategy\Composite(
    new NonTranslatableStrategy\Placeholder(),
);

var_dump($strategy instanceof NonTranslatableStrategyInterface);
// bool(true)
```

### Null Strategy

[](#null-strategy)

The Null strategy performs no protection at all. It simply returns the text unchanged during both protection and unprotection phases. This is useful when you want to disable placeholder handling entirely or when working with translators that do not require any special processing.

```
use Tobento\Service\MachineTranslator\NonTranslatableStrategy;
use Tobento\Service\MachineTranslator\NonTranslatableStrategyInterface;

$strategy = new NonTranslatableStrategy\NullStrategy();

var_dump($strategy instanceof NonTranslatableStrategyInterface);
// bool(true)
```

### Placeholder Strategy

[](#placeholder-strategy)

The Placeholder strategy protects placeholder segments such as `:name`, `{id}`, or `[[tag]]` from being translated. It detects both indicator-based placeholders (e.g. `:name`) and wrapper-based placeholders (e.g. `{name}`, `[[name]]`) and wraps them in configurable markers during translation. After translation, the markers are removed to restore the original placeholders exactly as they were.

```
use Tobento\Service\MachineTranslator\NonTranslatableStrategy;
use Tobento\Service\MachineTranslator\NonTranslatableStrategyInterface;

$strategy = new NonTranslatableStrategy\Placeholder(
    indicators: [':'],
    wrappers: [['{', '}']],
    marker: ['', ''],
);

var_dump($strategy instanceof NonTranslatableStrategyInterface);
// bool(true)
```

### Using Strategies with Translators

[](#using-strategies-with-translators)

In most applications, translators and non-translatable strategies are created through factories rather than being instantiated manually. A strategy's `protect()` method runs before the text is sent to the translation API, and `unprotect()` runs after the translated text is received. This ensures that placeholders, variables, or other protected segments remain unchanged throughout the translation process.

You can configure a non-translatable strategy either in the factory defaults or per translator.
Defaults are merged with the configuration passed to `createTranslator()`.

```
use Tobento\Service\MachineTranslator\Azure\MachineTranslatorFactory;
use Tobento\Service\MachineTranslator\NonTranslatableStrategy;
use Tobento\Service\MachineTranslator\MachineTranslatorFactoryInterface;

// Create a factory with your HTTP client and PSR-17 factories
$factory = new MachineTranslatorFactory(
    client: $client, // ClientInterface
    requestFactory: $requestFactory, // RequestFactoryInterface
    streamFactory: $streamFactory, // StreamFactoryInterface

    // Optional defaults (you may override any of them)
    defaults: [
        'nonTranslatableStrategy' => new NonTranslatableStrategy\Placeholder(),
        // 'endpoint' => 'https://api.cognitive.microsofttranslator.com',
        // 'region' => 'westeurope',
    ],
);

// Create a translator (only apiKey is required)
$translator = $factory->createTranslator(
    name: 'azure',
    config: [
        'apiKey' => 'YOUR_API_KEY',

        // Optional overrides (defaults shown)
        //'nonTranslatableStrategy' => new NonTranslatableStrategy\NullStrategy(),
        // 'endpoint' => 'https://api.cognitive.microsofttranslator.com',
        // 'region' => 'westeurope',
    ]
);

echo $translator->translate('Hello :name', 'de');
// "Hallo :name"
```

Credits
=======

[](#credits)

- [Tobias Strub](https://www.tobento.ch)
- [All Contributors](../../contributors)

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance90

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

3

Last Release

46d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/055d6a1b5c2384bb179c75ab0b55914231d898fdc4dffeb30770f81200e52206?d=identicon)[TOBENTOch](/maintainers/TOBENTOch)

---

Top Contributors

[![tobento-ch](https://avatars.githubusercontent.com/u/16684832?v=4)](https://github.com/tobento-ch "tobento-ch (6 commits)")

---

Tags

psrpsr-7psr-17psr-18googlepackagetranslationazuretranslatormachinedeepltobento

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/tobento-service-machine-translator/health.svg)

```
[![Health](https://phpackages.com/badges/tobento-service-machine-translator/health.svg)](https://phpackages.com/packages/tobento-service-machine-translator)
```

###  Alternatives

[laminas/laminas-diactoros

PSR HTTP Message implementations

546105.8M965](/packages/laminas-laminas-diactoros)[phpro/http-tools

HTTP tools for developing more consistent HTTP implementations.

28137.8k](/packages/phpro-http-tools)[elastic/transport

HTTP transport PHP library for Elastic products

1920.6M7](/packages/elastic-transport)[art4/requests-psr18-adapter

Use WordPress/Requests as a PSR-18 HTTP client

153.3k](/packages/art4-requests-psr18-adapter)[mezzio/mezzio-hal

Hypertext Application Language implementation for PHP and PSR-7

20456.9k6](/packages/mezzio-mezzio-hal)[vultr/vultr-php

The Official Vultr API PHP Wrapper.

2243.9k1](/packages/vultr-vultr-php)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
