Skip to content

Commit 9429773

Browse files
authored
Merge pull request #211 from a-drew/master
feat: retrieve a list of supported languages
2 parents 3e4dbbf + 9885bb5 commit 9429773

6 files changed

+206
-3
lines changed

README.md

+36-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Free Google Translate API PHP Package. Translates totally free of charge.
1111
- **[Basic Usage](#basic-usage)**
1212
- [Advanced Usage](#advanced-usage)
1313
- [Language Detection](#language-detection)
14+
- [Supported Languages](#supported-languages)
1415
- [Preserving Parameters](#preserving-parameters)
1516
- [Using Raw Response](#using-raw-response)
1617
- [Custom URL](#custom-url)
@@ -92,7 +93,41 @@ echo $tr->getLastDetectedSource(); // Output: en
9293

9394
Return value will be `null` if the language couldn't be detected.
9495

95-
Supported languages are listed in [Google API docs](https://cloud.google.com/translate/docs/languages).
96+
### Supported Languages
97+
98+
You can get a list of all the supported languages using the `languages` method.
99+
100+
```php
101+
$tr = new GoogleTranslate();
102+
103+
$languages = $tr->languages(); // Get supported languages in iso-639 format
104+
105+
// Output: [ 'ab', 'ace', 'ach', 'aa', 'af', 'sq', 'alz', ... ]
106+
```
107+
108+
Optionally, pass a target language code to retrieve supported languages with names displayed in that language.
109+
110+
```php
111+
$tr = new GoogleTranslate();
112+
113+
$languages = $tr->languages('en'); // Get supported languages, display name in english
114+
// Output: [ 'en' => English', 'es' => 'Spanish', 'it' => 'Italian', ... ]
115+
116+
echo $languages['en']; // Output: 'English'
117+
echo $languages['ka']; // Output: 'Georgian'
118+
```
119+
120+
Same as with the `translate`/`trans` methods, you can also use a static `langs` method:
121+
122+
```php
123+
GoogleTranslate::langs();
124+
// Output: [ 'ab', 'ace', 'ach', 'aa', 'af', 'sq', 'alz', ... ]
125+
126+
GoogleTranslate::langs('en');
127+
// Output: [ 'en' => English', 'es' => 'Spanish', 'it' => 'Italian', ... ]
128+
```
129+
130+
Supported languages are also listed in [Google API docs](https://cloud.google.com/translate/docs/languages).
96131

97132
### Preserving Parameters
98133

@@ -241,4 +276,3 @@ If this package helped you reduce your time to develop something, or it solved a
241276

242277
- [Patreon](https://www.patreon.com/stichoza)
243278
- [PayPal](https://paypal.me/stichoza)
244-

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"require": {
1515
"php": "^8.0",
1616
"guzzlehttp/guzzle": "^7.0",
17+
"ext-dom": "*",
1718
"ext-json": "*",
1819
"ext-mbstring": "*"
1920
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Stichoza\GoogleTranslate\Exceptions;
4+
5+
use ErrorException;
6+
7+
class LanguagesRequestException extends ErrorException
8+
{
9+
//
10+
}

src/GoogleTranslate.php

+79-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use GuzzleHttp\Client;
66
use GuzzleHttp\Exception\GuzzleException;
77
use JsonException;
8+
use Stichoza\GoogleTranslate\Exceptions\LanguagesRequestException;
89
use Stichoza\GoogleTranslate\Exceptions\LargeTextException;
910
use Stichoza\GoogleTranslate\Exceptions\RateLimitException;
1011
use Stichoza\GoogleTranslate\Exceptions\TranslationDecodingException;
@@ -366,7 +367,7 @@ protected function injectParameters(string $string, array $replacements): string
366367
{
367368
// Remove space added by google in the parameters
368369
$string = preg_replace('/#\{\s*(\d+)\s*\}/', '#{$1}', $string);
369-
370+
370371
return preg_replace_callback(
371372
'/\#{(\d+)}/',
372373
fn($matches) => $replacements[$matches[1]],
@@ -456,4 +457,81 @@ protected function isValidLocale(string $lang): bool
456457
{
457458
return (bool) preg_match('/^([a-z]{2,3})(-[A-Za-z]{2,4})?$/', $lang);
458459
}
460+
461+
/**
462+
* Fetch the list of supported languages from Google Translate
463+
*
464+
* @param string|null $target iso code of display language, when null returns only iso codes
465+
* @return string[]|array<string, string>
466+
* @throws RateLimitException
467+
* @throws LanguagesRequestException
468+
*/
469+
public static function langs(?string $target = null): array
470+
{
471+
return (new self)->languages($target);
472+
}
473+
474+
/**
475+
* Fetch the list of supported languages from Google Translate
476+
*
477+
* @param string|null $target iso code of display language, when null returns only iso codes
478+
* @return string[]|array<string, string>
479+
* @throws RateLimitException
480+
* @throws LanguagesRequestException
481+
*/
482+
public function languages(?string $target = null): array
483+
{
484+
$languages = $this->localizedLanguages($target ?? $this->target ?? $this->source ?? '');
485+
486+
if ($target === null) {
487+
return array_keys($languages);
488+
}
489+
490+
return $languages;
491+
}
492+
493+
/**
494+
* Fetch the list of supported languages from Google Translate
495+
*
496+
* @param string $target iso code of localized display language
497+
* @return array<string, string>
498+
* @throws RateLimitException
499+
* @throws LanguagesRequestException
500+
*/
501+
public function localizedLanguages(string $target): array
502+
{
503+
$menu = 'sl'; // 'tl';
504+
$url = parse_url($this->url);
505+
$url = $url['scheme'].'://'.$url['host']."/m?mui=$menu&hl=$target";
506+
507+
try {
508+
$response = $this->client->get($url, $this->options);
509+
} catch (GuzzleException $e) {
510+
match ($e->getCode()) {
511+
429, 503 => throw new RateLimitException($e->getMessage(), $e->getCode()),
512+
default => throw new LanguagesRequestException($e->getMessage(), $e->getCode()),
513+
};
514+
} catch (Throwable $e) {
515+
throw new LanguagesRequestException($e->getMessage(), $e->getCode());
516+
}
517+
518+
// add a meta tag to ensure the HTML content is treated as UTF-8, fixes xpath node values
519+
$html = preg_replace('/<head>/i', '<head><meta charset="UTF-8">', $response->getBody()->getContents());
520+
521+
// Prepare to crawl DOM
522+
$dom = new \DOMDocument();
523+
$dom->loadHTML($html);
524+
$xpath = new \DOMXPath($dom);
525+
526+
$nodes = $xpath->query('//div[@class="language-item"]/a');
527+
528+
$languages = [];
529+
foreach ($nodes as $node) {
530+
$href = $node->getAttribute('href');
531+
$code = strtok(substr($href, strpos($href, "$menu=") + strlen("$menu=")), '&');
532+
$languages[$code] = $node->nodeValue;
533+
}
534+
535+
return $languages;
536+
}
459537
}

tests/ExceptionTest.php

+8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use ErrorException;
66
use PHPUnit\Framework\TestCase;
7+
use Stichoza\GoogleTranslate\Exceptions\LanguagesRequestException;
78
use Stichoza\GoogleTranslate\Exceptions\LargeTextException;
89
use Stichoza\GoogleTranslate\Exceptions\RateLimitException;
910
use Stichoza\GoogleTranslate\Exceptions\TranslationDecodingException;
@@ -68,4 +69,11 @@ public function testInheritanceForErrorException(): void
6869

6970
$this->tr->setUrl('https://httpstat.us/413')->translate('Test');
7071
}
72+
73+
public function testLanguagesRequestException(): void
74+
{
75+
$this->expectException(LanguagesRequestException::class);
76+
77+
$this->tr->setUrl('https://httpstat.us/418')->languages();
78+
}
7179
}

tests/SupportedLanguagesTest.php

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
namespace Stichoza\GoogleTranslate\Tests;
4+
5+
use PHPUnit\Framework\TestCase;
6+
use Stichoza\GoogleTranslate\GoogleTranslate;
7+
8+
class SupportedLanguagesTest extends TestCase
9+
{
10+
public GoogleTranslate $tr;
11+
12+
public function setUp(): void
13+
{
14+
$this->tr = new GoogleTranslate();
15+
}
16+
17+
public function testLanguageCodesRequest(): void
18+
{
19+
$result = $this->tr->languages();
20+
$this->assertContains('en', $result);
21+
$this->assertContains('fr', $result);
22+
$this->assertContains('ka', $result);
23+
$this->assertContains('it', $result);
24+
$this->assertContains('pt', $result);
25+
$this->assertContains('pt-PT', $result);
26+
$this->assertContains('pl', $result);
27+
$this->assertContains('vi', $result);
28+
$this->assertContains('ja', $result);
29+
$this->assertContains('et', $result);
30+
$this->assertContains('hr', $result);
31+
$this->assertContains('es', $result);
32+
$this->assertContains('zh-CN', $result);
33+
$this->assertContains('zh-TW', $result);
34+
}
35+
36+
public function testLocalizedLanguages(): void
37+
{
38+
$result = $this->tr->languages('en');
39+
$this->assertEquals('English', $result['en']);
40+
$this->assertEquals('French', $result['fr']);
41+
$this->assertEquals('Georgian', $result['ka']);
42+
$this->assertEquals('Italian', $result['it']);
43+
$this->assertEquals('Portuguese (Brazil)', $result['pt']);
44+
45+
$result = $this->tr->languages('ka');
46+
$this->assertEquals('ინგლისური', $result['en']);
47+
$this->assertEquals('ფრანგული', $result['fr']);
48+
$this->assertEquals('ქართული', $result['ka']);
49+
$this->assertEquals('იტალიური', $result['it']);
50+
$this->assertEquals('პორტუგალიური (ბრაზილია)', $result['pt']);
51+
52+
$result = $this->tr->languages('pt');
53+
$this->assertEquals('Inglês', $result['en']);
54+
$this->assertEquals('Francês', $result['fr']);
55+
$this->assertEquals('Georgiano', $result['ka']);
56+
$this->assertEquals('Italiano', $result['it']);
57+
$this->assertEquals('Português (Brasil)', $result['pt']);
58+
}
59+
60+
public function testLanguagesEquality(): void
61+
{
62+
$resultOne = GoogleTranslate::langs();
63+
$resultTwo = $this->tr->languages();
64+
65+
$this->assertEqualsIgnoringCase($resultOne, $resultTwo, 'Static and instance methods should return same result.');
66+
67+
$resultOne = GoogleTranslate::langs('pt');
68+
$resultTwo = $this->tr->languages('pt');
69+
70+
$this->assertEqualsIgnoringCase($resultOne, $resultTwo, 'Static and instance methods should return same result.');
71+
}
72+
}

0 commit comments

Comments
 (0)