eugene-erg / google-informal-icu-i18n-translate
Text translation using multiple neural network APIs
Package info
github.com/EugeneErg/google-informal-icu-i18n-translator
pkg:composer/eugene-erg/google-informal-icu-i18n-translate
Requires
- ext-intl: *
- eugene-erg/icu-i18n-translator: ^1.0
- psr/http-client: ^1.0
- psr/http-factory: ^1.1
- psr/http-message: ^2.0
- psr/simple-cache: ^3.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.95
- phpstan/phpstan: ^2.2
- phpunit/phpunit: ^12.5
README
A PHP library for translating ICU message format strings using the Google Translate unofficial API. Designed to integrate with the eugene-erg/icu-i18n-translator ecosystem and any PSR-18 HTTP client.
Table of Contents
- Requirements
- Installation
- Quick Start
- Core Concepts
- Usage
- Architecture
- Configuration
- Exception Handling
- Response Structure
- Comparison with Alternatives
- Development
- License
Requirements
| Requirement | Version |
|---|---|
| PHP | ^8.2 |
| ext-intl | * |
| psr/http-client | ^1.0 |
| psr/http-message | ^2.0 |
| psr/http-factory | ^1.1 |
| psr/simple-cache | ^3.0 |
| eugene-erg/icu-i18n-translator | ^1.0 |
You also need a PSR-18 compatible HTTP client installed (e.g. Guzzle, Symfony HttpClient, or any other). The library does not ship one by default to remain transport-agnostic.
Installation
composer require eugene-erg/google-informal-icu-i18n-translate
Then install a PSR-18 HTTP client. Any of the following will work:
# Guzzle composer require guzzlehttp/guzzle guzzlehttp/psr7 # Symfony HttpClient composer require symfony/http-client nyholm/psr7 # Buzz (lightweight) composer require kriswallsmith/buzz nyholm/psr7
Quick Start
use EugeneErg\GoogleInformalIcuI18nTranslator\Client\Client; use EugeneErg\GoogleInformalIcuI18nTranslator\Client\PsrClient; use EugeneErg\GoogleInformalIcuI18nTranslator\GoogleInformalTranslator; use EugeneErg\ICUMessageFormatParser\Parser; use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\Psr16Cache; // 1. Wire up your PSR-18 HTTP client (example with Guzzle) $httpClient = new \GuzzleHttp\Client(); $requestFactory = new \GuzzleHttp\Psr7\HttpFactory(); $streamFactory = new \GuzzleHttp\Psr7\HttpFactory(); // 2. Build the transport adapter $psrClient = new PsrClient($httpClient, $requestFactory, $streamFactory); // 3. Build the low-level Google client $client = new Client($psrClient, 'https://translate.googleapis.com'); // 4. Build the translator (requires a PSR-16 cache) $cache = new Psr16Cache(new ArrayAdapter()); $translator = new GoogleInformalTranslator($client, new Parser(), $cache); // 5. Translate $result = $translator->translate(['Hello, world!'], 'en_EN', 'ru_RU'); // $result = ['Привет, мир!']
Core Concepts
ICU Message Format
ICU messages allow you to express pluralization, gender, and variable substitution in a locale-aware way:
You have {count, plural, one {# message} other {# messages}}.
This library translates ICU patterns while preserving the structure — variables and formatting directives are never sent through Google Translate. Only the human-readable text fragments are translated.
Pattern = array<string|Variable>
Rather than a plain string, the translator works with a pattern — an array of strings and Variable objects. This keeps ICU variables intact during translation:
use EugeneErg\IcuI18nTranslator\DataTransferObjects\Variable; $pattern = ['Hello, ', new Variable(0), '! You have ', new Variable(1), ' messages.']; $translated = $translator->translate($pattern, 'en_EN', 'ru_RU'); // ['Привет, ', Variable(0), '! У вас ', Variable(1), ' сообщений.']
Variable placeholders are encoded as {{_0_}}, {{_1_}} etc. when sent to Google and restored in the result.
Usage
Basic Translation
$translated = $translator->translate( pattern: ['Good morning!'], fromLocale: 'en_EN', toLocale: 'de_DE', ); // ['Guten Morgen!']
Locale format is language_REGION — the library extracts the region part as the language code sent to Google. Passing just 'en' or 'ru' (no underscore) is also supported and will be lowercased.
// Both forms are valid $translator->translate(['Hello'], 'en', 'ru'); $translator->translate(['Hello'], 'en_EN', 'ru_RU');
Translation with Language Detection
When the source language is unknown, use translateWithDetect(). Google will detect it automatically and return it alongside the translation:
use EugeneErg\IcuI18nTranslator\ValueObjects\Translated; $result = $translator->translateWithDetect( pattern: ['Bonjour le monde'], toLocale: 'en_EN', ); echo $result->locale; // 'fr' echo $result->pattern[0]; // 'Hello world'
Check Language Support
Before translating you can verify that the target (and optionally source) language is supported by Google Translate. The result is cached for 24 hours via your PSR-16 cache.
// Is Russian a supported target? $translator->canTranslate('ru_RU'); // true // Can we translate from English to Russian? $translator->canTranslate('ru_RU', 'en_EN'); // true // Unsupported target $translator->canTranslate('xx_XX'); // false
Using the Low-Level Client Directly
If you need more control over the Google Translate response — alternative translations, dictionary entries, romanization, etc. — use Client directly:
use EugeneErg\GoogleInformalIcuI18nTranslator\Client\Client; use EugeneErg\GoogleInformalIcuI18nTranslator\Client\ValueObjects\GoogleTranslateType; $response = $client->single( text: 'Hello', targetLanguage: 'ru', types: [ GoogleTranslateType::Translation, GoogleTranslateType::Dictionary, GoogleTranslateType::AlternativeTranslations, ], sourceLanguage: 'en', ); echo $response->translates[0]->translatedText; // 'Привет' echo $response->detectedSourceLanguage; // 'en' var_dump($response->dictionary); // raw dictionary data
Requesting Specific Data Types
GoogleTranslateType is an enum controlling what data Google returns:
| Case | Value | Description |
|---|---|---|
Translation |
t |
Main translation result |
AlternativeTranslations |
at |
Alternative phrasings |
Romanization |
rm |
Romanized (transliterated) form |
Dictionary |
bd |
Dictionary entries with examples |
QualityCheck |
qc |
Quality check information |
Examples |
ex |
Usage examples |
Synonyms |
ss |
Synonyms |
RelatedWords |
rw |
Related words |
Morphology |
md |
Morphological info |
You can request multiple types at once. Types not requested will have null in the corresponding response fields.
List Supported Languages
$response = $client->getSupportedLanguages(); foreach ($response->languages as $code => $language) { echo sprintf( "%s: %s (source: %s, target: %s)\n", $code, $language->name, $language->source ? 'yes' : 'no', $language->target ? 'yes' : 'no', ); }
Architecture
GoogleInformalTranslator — TranslatorInterface implementation
│ uses Parser (ICU parser)
│ uses CacheInterface (PSR-16)
└─ Client — Google Translate API wrapper
│ uses ClientInterface
└─ PsrClient — ClientInterface over PSR-18
│ uses Psr\Http\Client\ClientInterface (PSR-18)
│ uses RequestFactoryInterface (PSR-17)
└─ uses StreamFactoryInterface (PSR-17)
GoogleInformalTranslator implements TranslatorInterface from eugene-erg/icu-i18n-translator. It converts ICU pattern arrays to plain text (escaping ICU syntax via Parser::quote()), translates via Client, then parses variable placeholders back out of the response.
Client wraps the unofficial Google Translate endpoint (translate.googleapis.com). It maps the raw array response into typed value objects (GoogleTranslateResponse, Translate, Confidence, QualityCheck, Model) and maps HTTP/PSR errors into its own exception hierarchy.
PsrClient is a thin adapter that converts the library's simplified sendRequest(method, uri, body, headers) interface into proper PSR-7 RequestInterface calls, allowing any PSR-18 client to be used as transport.
Configuration
Custom API URL
By default the library targets https://translate.googleapis.com. You can override it — useful for testing, proxying, or regional endpoints:
$client = new Client($psrClient, 'https://your-proxy.example.com');
Cache TTL
Supported languages are cached for 24 hours (P1D). The cache key is GoogleInformalTranslator:getSupportedLanguages. To change the TTL, extend GoogleInformalTranslator and override getSupportedLanguages(), or wrap it with your own caching layer.
Custom HTTP Adapter
Implement ClientInterface to use any transport, add authentication, logging, or retry logic:
use EugeneErg\GoogleInformalIcuI18nTranslator\Client\ClientInterface; use Psr\Http\Message\ResponseInterface; final class LoggingClient implements ClientInterface { public function __construct( private ClientInterface $inner, private LoggerInterface $logger, ) {} public function sendRequest( string $method, string $uri, string|null $body = null, array $headers = [], ): ResponseInterface { $this->logger->debug("[$method] $uri"); return $this->inner->sendRequest($method, $uri, $body, $headers); } }
Exception Hierarchy
\RuntimeException
└─ Exception
├─ ClientException — 4xx response or generic PSR-18 error
│ ├─ NetworkException — 5xx response or PSR-18 NetworkExceptionInterface
│ └─ TimeoutException — PSR-18 RequestExceptionInterface (timeout/abort)
└─ ResponseJsonException — response body is not valid JSON (on 2xx)
All exceptions live under EugeneErg\GoogleInformalIcuI18nTranslator\Client\Exceptions.
use EugeneErg\GoogleInformalIcuI18nTranslator\Client\Exceptions\ClientException; use EugeneErg\GoogleInformalIcuI18nTranslator\Client\Exceptions\NetworkException; use EugeneErg\GoogleInformalIcuI18nTranslator\Client\Exceptions\TimeoutException; use EugeneErg\GoogleInformalIcuI18nTranslator\Client\Exceptions\ResponseJsonException; try { $response = $client->single('Hello', 'ru'); } catch (TimeoutException $e) { // request timed out or was aborted } catch (NetworkException $e) { // server error (5xx) or network-level failure } catch (ClientException $e) { // client error (4xx) or unexpected HTTP problem } catch (ResponseJsonException $e) { // got a 2xx but body wasn't JSON }
Response Structure
GoogleTranslateResponse
| Property | Type | Description |
|---|---|---|
translates |
`Translate[] | null` |
dictionary |
`mixed[] | null` |
detectedSourceLanguage |
`string | null` |
alternativeTranslations |
`mixed[] | null` |
confidenceValue |
`float | null` |
qualityCheck |
`QualityCheck | null` |
confidence |
`Confidence | null` |
additional |
mixed[] |
Undocumented fields from the API |
Translate
| Property | Type | Description |
|---|---|---|
translatedText |
`string | null` |
originalText |
`string | null` |
transliteration |
`string | null` |
models |
`Model[] | null` |
additional |
mixed[] |
Undocumented fields |
Comparison with Alternatives
| Feature | This library | stichoza/google-translate-php |
google/cloud-translate |
|---|---|---|---|
| API | Unofficial (free) | Unofficial (free) | Official (paid) |
| ICU message format | ✅ Native support | ❌ | ❌ |
| Variable preservation | ✅ | ❌ | ❌ |
| PSR-18 transport | ✅ Bring your own | ❌ Uses curl directly | ✅ |
| PSR-16 cache | ✅ | ❌ | ❌ |
| Language detection | ✅ | ✅ | ✅ |
| Typed response objects | ✅ | ❌ plain string | ✅ |
| Alternative translations | ✅ | ❌ | ✅ |
| Dictionary / examples | ✅ | ❌ | ✅ |
| Quality check data | ✅ | ❌ | ❌ |
| Auth required | ❌ | ❌ | ✅ API key / OAuth |
| Rate limits | Google informal | Google informal | Quota-based billing |
| PHP version | ^8.2 |
^8.0 |
^8.0 |
| Static analysis | PHPStan level 9 | — | — |
| Test coverage | 100% | partial | — |
Note: The unofficial Google Translate API has no SLA and may change without notice. It is suitable for development, tooling, and low-traffic use cases. For production workloads at scale, consider the official Cloud Translation API.
Development
Setup
git clone https://github.com/EugeneErg/google-informal-icu-i18n-translator
cd google-informal-icu-i18n-translator
composer install
Running Tests
./vendor/bin/phpunit
With coverage (requires Xdebug or PCOV):
XDEBUG_MODE=coverage ./vendor/bin/phpunit --coverage-filter src --coverage-text
Static Analysis
./vendor/bin/phpstan analyse
Level 9 (maximum). Covers both src/ and tests/.
Code Style
# Check ./vendor/bin/php-cs-fixer fix --dry-run --diff # Fix ./vendor/bin/php-cs-fixer fix
Project Structure
src/
├── GoogleInformalTranslator.php # Main TranslatorInterface implementation
└── Client/
├── Client.php # Google Translate API wrapper
├── ClientInterface.php # HTTP transport abstraction
├── PsrClient.php # PSR-18 adapter
├── Exceptions/
│ ├── Exception.php
│ ├── ClientException.php
│ ├── NetworkException.php
│ ├── TimeoutException.php
│ └── ResponseJsonException.php
└── ValueObjects/
├── GoogleTranslateResponse.php
├── GoogleTranslateType.php
├── Translate.php
├── Confidence.php
├── QualityCheck.php
├── Model.php
├── Language.php
└── SupportedLanguagesResponse.php
tests/
├── GoogleInformalTranslatorTest.php
└── Client/
├── ClientTest.php
├── PsrClientTest.php
└── Stubs/
└── FakeRequest.php
License
MIT — see LICENSE.