matthiasnoback/microsoft-translator
PHP client for the Microsoft Translator API that lets you translate text between languages through a clean, object-oriented interface. It handles authentication, HTTP requests, and responses, making it easy to add translation features to any PHP or Laravel application.
Install the package and an HTTP layer. This library is deliberately thin: it builds API requests and parses responses, but it does not ship an HTTP client. You must provide PSR-18 (psr/http-client) and PSR-17 (psr/http-factory) implementations:
composer require matthiasnoback/microsoft-translator guzzlehttp/guzzle
(Symfony’s symfony/http-client with psr18 adapters works equally well.)
Collect credentials from Azure. In the Azure portal create a Translator resource (Cognitive Services). Copy the key and the region (e.g. westeurope). The region is not optional — it is required by the V3 API and is a common source of 401s.
Wire up the client. The package exposes a MicrosoftTranslator\Client that is constructed with an API key, a region, and PSR-18/PSR-17 dependencies (check the constructor signature in src/Client.php for the exact order in your installed version):
use GuzzleHttp\Client as HttpClient;
use GuzzleHttp\Psr7\HttpFactory;
use MicrosoftTranslator\Client;
use MicrosoftTranslator\ApiCall\Translate;
$factory = new HttpFactory();
$client = new Client(
new HttpClient(),
$factory, // PSR-17 request factory
$factory, // PSR-17 stream factory
config('services.microsoft_translator.key'),
config('services.microsoft_translator.region'),
);
$result = $client->execute(
new Translate('en', 'nl', ['Hello world'])
);
echo $result->getTranslation();
First real use case: translate an array of UI strings from a source language to a target language. Because the API accepts arrays, translating a batch is a single call — this is the fastest win compared with looping over individual strings.
Where to look first.
src/ApiCall/ — one class per API endpoint (Translate, TranslateArray, Detect, GetLanguages, etc.). This is your map of what is supported.README.md — the only narrative documentation; read it once, then treat the source as the reference.Wrap the client in your own service. Do not sprinkle new Translate(...) calls through controllers. Create a TranslationService (or Translator facade) that owns the MicrosoftTranslator\Client, chooses the correct ApiCall object, and returns a normalized result your domain understands:
class TranslationService
{
public function __construct(private Client $client) {}
public function translate(string $text, string $from, string $to): string
{
$result = $this->client->execute(new Translate($from, $to, [$text]));
return $result->getTranslation();
}
}
Bind everything in the container. Register the PSR-18 client, the PSR-17 factories, and MicrosoftTranslator\Client as singletons in a Laravel service provider. Keep the key and region in config/services.php backed by .env, never inline. This makes the code testable and lets you swap in a mock client.
Batch aggressively, but chunk. The API is designed for arrays; sending 50 strings in one request is dramatically cheaper and faster than 50 requests. Enforce a chunk size in your service (see limits below) and array_chunk() the input before building Translate/TranslateArray calls.
Detect before translate when the source is unknown. Chain an ApiCall\Detect call and pass the resulting language code into the Translate call. Cache the detected language per string — detection is a second billed request.
Cache translated strings. Translation is deterministic for a given source/target/text, so a key like sha1("{$from}|{$to}|{$text}") stored in Redis or the database is a genuine cost saver. Invalidate only when you deliberately change terminology or the target language.
Push bulk work onto a queue. For catalog imports, documentation translation, or any batch larger than a handful of strings, dispatch a job per chunk. This keeps request latency out of the user path and gives you a natural place to implement retry/backoff.
Integrate with Laravel’s HTTP client for testing. Because the package depends only on PSR-18, you can inject GuzzleHttp\Client backed by a MockHandler, or use Symfony’s MockHttpClient, and assert the outgoing request body and URL without hitting Azure. Alternatively, mock MicrosoftTranslator\Client itself in feature tests and reserve fake responses for the unit tests of your service.
Extend for missing endpoints. The library covers the common V3 endpoints but not necessarily every one. If you need an endpoint that has no ApiCall class, implement the ApiCall interface (or subclass an existing call) to provide the HTTP method, path, and JSON payload; the Client will execute it like any other call. This is the intended extension point.
Decorate the client for cross-cutting concerns. If you need logging, metrics, or retry logic, write a decorator around your own TranslationService (or around the client) rather than modifying the package. This keeps upgrades safe.
Ocp-Apim-Subscription-Region header. Double-check the region matches the resource, not the data center you assume.execute() in your service and add exponential backoff; respect any Retry-After header.Throwable around execute() in the service layer, log the request context (source, target, batch size — never the key), and decide whether to fail the job, skip the batch, or return the original text. For UI-facing translation, silently returning the source string is often better than showing an error.en, nl, pt-br, zh-Hans. Use a GetLanguages call (or a checked-in snapshot of the result) to validate codes at boot/test time rather than discovering a typo in production.Translate call, otherwise tags get mangled. Plain text is the default; don’t assume it is safe for rich content.composer.json, read the changelog before upgrading, and be prepared to patch or wrap it. The 2024-08-23 release is recent enough to be usable, but the maintenance cadence is not that of a large vendor SDK.How can I help you explore Laravel packages today?