Skip to content

Commit

Permalink
Merge pull request #32 from Laravel-Lang/1.x
Browse files Browse the repository at this point in the history
Added command to translate keys
  • Loading branch information
andrey-helldar authored Jan 21, 2023
2 parents 36ce47c + 5271a19 commit f2865b5
Show file tree
Hide file tree
Showing 22 changed files with 490 additions and 3 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ vendor/bin/lang status
vendor/bin/lang sync
```

### Translate keys with Google Translate

```bash
vendor/bin/lang translate
```

### Upgrade from previous structure

```bash
Expand Down
8 changes: 5 additions & 3 deletions bin/lang
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use LaravelLang\StatusGenerator\Commands\Create;
use LaravelLang\StatusGenerator\Commands\Download;
use LaravelLang\StatusGenerator\Commands\Status;
use LaravelLang\StatusGenerator\Commands\Sync;
use LaravelLang\StatusGenerator\Commands\Translate;
use LaravelLang\StatusGenerator\Commands\Upgrade;
use Symfony\Component\Console\Application;

Expand All @@ -17,9 +18,9 @@ if (PHP_SAPI !== 'cli' || (PHP_MAJOR_VERSION < 8 && PHP_MINOR_VERSION < 1)) {
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);

$possible_files = [
__DIR__ . '/../../../autoload.php',
__DIR__ . '/../../autoload.php',
__DIR__ . '/../vendor/autoload.php',
__DIR__ . '/../../../autoload.php',
__DIR__ . '/../../autoload.php',
__DIR__ . '/../vendor/autoload.php',
];

$file = null;
Expand All @@ -43,6 +44,7 @@ $application->add(new Create());
$application->add(new Download());
$application->add(new Status());
$application->add(new Sync());
$application->add(new Translate());
$application->add(new Upgrade());

$application->run();
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
"guzzlehttp/guzzle": "^7.4",
"illuminate/console": "^8.0 || ^9.0",
"illuminate/container": "^8.0 || ^9.0",
"laravel-lang/publisher": "^14.5",
"phpunit/phpunit": "^9.5",
"stichoza/google-translate-php": "^5.1",
"symfony/console": "^5.0 || ^6.0",
"symfony/finder": "^5.0 || ^6.0"
},
Expand Down
22 changes: 22 additions & 0 deletions src/Commands/Translate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace LaravelLang\StatusGenerator\Commands;

use LaravelLang\StatusGenerator\Constants\Command as CommandName;
use LaravelLang\StatusGenerator\Processors\Translate\Translate as TranslateProcessor;

class Translate extends Command
{
protected array|string $processor = [
TranslateProcessor::class,
];

protected function configure(): Command
{
return parent::configure()
->setName(CommandName::TRANSLATE())
->setDescription('Translation of untranslated keys');
}
}
3 changes: 3 additions & 0 deletions src/Constants/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* @method static string DOWNLOAD()
* @method static string STATUS()
* @method static string SYNC()
* @method static string TRANSLATE()
* @method static string UPGRADE()
*/
enum Command: string
Expand All @@ -23,5 +24,7 @@ enum Command: string

case SYNC = 'sync';

case TRANSLATE = 'translate';

case UPGRADE = 'upgrade';
}
118 changes: 118 additions & 0 deletions src/Helpers/GoogleLocale.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php

declare(strict_types=1);

namespace LaravelLang\StatusGenerator\Helpers;

use DragonCode\Support\Facades\Helpers\Arr;
use LaravelLang\Publisher\Constants\Locales;
use LaravelLang\StatusGenerator\Objects\Translatable;
use Stichoza\GoogleTranslate\GoogleTranslate;

class GoogleLocale
{
protected static Locales $default = Locales::ENGLISH;

public static function translate(string $value, string $locale): string
{
if ($resolved = self::locale($locale)) {
return self::get($value, $resolved, self::$default->value);
}

return $value;
}

protected static function get(string $value, string $targetLocale, string $sourceLocale): string
{
$object = self::prepare($value);

$translated = GoogleTranslate::trans($object->value, $targetLocale, $sourceLocale);

return $object->compile($translated);
}

protected static function prepare(string $value): Translatable
{
return Translatable::make(compact('value'));
}

protected static function locale(string $locale): ?string
{
return Arr::get(self::locales(), $locale);
}

protected static function locales(): array
{
return [
Locales::AFRIKAANS->value => 'af',
Locales::ALBANIAN->value => 'sq',
Locales::ARABIC->value => 'ar',
Locales::ARMENIAN->value => 'hy',
Locales::AZERBAIJANI->value => 'az',
Locales::BASQUE->value => 'eu',
Locales::BELARUSIAN->value => 'be',
Locales::BENGALI->value => 'bn',
Locales::BOSNIAN->value => 'bs',
Locales::BULGARIAN->value => 'bg',
Locales::CATALAN->value => 'ca',
Locales::CHINESE->value => 'zh-CN',
Locales::CHINESE_T->value => 'zh-TW',
Locales::CROATIAN->value => 'hr',
Locales::CZECH->value => 'cs',
Locales::DANISH->value => 'da',
Locales::DUTCH->value => 'nl',
Locales::ESTONIAN->value => 'et',
Locales::PILIPINO->value => 'fil',
Locales::FINNISH->value => 'fi',
Locales::FRENCH->value => 'fr',
Locales::GALICIAN->value => 'gl',
Locales::GEORGIAN->value => 'ka',
Locales::GERMAN->value => 'de',
Locales::GREEK->value => 'el',
Locales::GUJARATI->value => 'gu',
Locales::HEBREW->value => 'he',
Locales::HINDI->value => 'hi',
Locales::HUNGARIAN->value => 'hu',
Locales::ICELANDIC->value => 'is',
Locales::INDONESIAN->value => 'id',
Locales::ITALIAN->value => 'it',
Locales::JAPANESE->value => 'ja',
Locales::KANNADA->value => 'kn',
Locales::KAZAKH->value => 'kk',
Locales::CENTRAL_KHMER->value => 'km',
Locales::KOREAN->value => 'ko',
Locales::LATVIAN->value => 'lv',
Locales::LITHUANIAN->value => 'lt',
Locales::MACEDONIAN->value => 'mk',
Locales::MALAY->value => 'ms',
Locales::MARATHI->value => 'mr',
Locales::MONGOLIAN->value => 'mn',
Locales::NEPALI->value => 'ne',
Locales::PASHTO->value => 'ps',
Locales::PERSIAN->value => 'fa',
Locales::POLISH->value => 'pl',
Locales::PORTUGUESE->value => 'pt',
Locales::PORTUGUESE_BRAZIL->value => 'pt',
Locales::ROMANIAN->value => 'ro',
Locales::RUSSIAN->value => 'ru',
Locales::SERBIAN_CYRILLIC->value => 'sr',
Locales::SINHALA->value => 'si',
Locales::SLOVAK->value => 'sk',
Locales::SLOVENIAN->value => 'sl',
Locales::SPANISH->value => 'es',
Locales::SWAHILI->value => 'sw',
Locales::SWEDISH->value => 'sv',
Locales::TAGALOG->value => 'tl',
Locales::TAJIK->value => 'tg',
Locales::THAI->value => 'th',
Locales::TURKISH->value => 'tr',
Locales::TURKMEN->value => 'tk',
Locales::UKRAINIAN->value => 'uk',
Locales::URDU->value => 'ur',
Locales::UIGHUR->value => 'ug',
Locales::UZBEK_CYRILLIC->value => 'uz',
Locales::VIETNAMESE->value => 'vi',
Locales::WELSH->value => 'cy',
];
}
}
56 changes: 56 additions & 0 deletions src/Objects/Translatable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

namespace LaravelLang\StatusGenerator\Objects;

use DragonCode\SimpleDataTransferObject\DataTransferObject;
use DragonCode\Support\Facades\Helpers\Str;

class Translatable extends DataTransferObject
{
public ?string $value = null;

public array $replaces = [];

public function compile(string $translated): string
{
return Str::replace($translated, array_values($this->replaces), array_keys($this->replaces));
}

protected function castValue(string $value): string
{
$this->extractReplaces($value);

return $this->replaceValue($value);
}

protected function extractReplaces(string $value): void
{
Str::of($value)
->trim()
->trim('.?!')
->explode(' ')
->map(function (string $item) {
if (Str::startsWith($item, ':')) {
return $this->numerify($item);
}

return $item;
});
}

protected function replaceValue(string $value): string
{
return Str::replace($value, array_keys($this->replaces), array_values($this->replaces));
}

protected function numerify(string $value): int
{
if (isset($this->replaces[$value])) {
return $this->replaces[$value];
}

return $this->replaces[$value] = (count($this->replaces) + 1) * 100;
}
}
72 changes: 72 additions & 0 deletions src/Processors/Translate/Translate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

declare(strict_types=1);

namespace LaravelLang\StatusGenerator\Processors\Translate;

use DragonCode\Support\Facades\Filesystem\File;
use DragonCode\Support\Facades\Helpers\Arr;
use LaravelLang\StatusGenerator\Helpers\GoogleLocale;
use LaravelLang\StatusGenerator\Processors\Processor;

class Translate extends Processor
{
public function handle(): void
{
$source = $this->locales()->getSource();

foreach ($this->directories() as $locale) {
$this->output->task($locale . ' translation', function () use ($locale, $source) {
$locales = $this->locales()->getLocale($locale);

foreach ($source as $file => $source_values) {
$path = $this->getTargetFilename($locale, $file);

$locale_values = Arr::get($locales, $file, []);

$result = $this->merge($source_values, $locale_values, $locale);

! empty($result) ? $this->store($path, $result) : $this->delete($path);
}
});
}

$this->output->emptyLine();
}

protected function merge(array $source, array $target, string $locale): array
{
$target = Arr::only($target, Arr::keys($source));

foreach ($target as $key => $value) {
$source[$key] = $this->isSameKey($source, $key, $value) ? $this->translate($value, $locale) : $value;
}

return $source;
}

protected function translate(string $value, string $locale): string
{
return GoogleLocale::translate($value, $locale);
}

protected function store(string $path, array $values): void
{
$this->filesystem->store($path, $values, false);
}

protected function delete(string $path): void
{
File::ensureDelete($path);
}

protected function getTargetFilename(string $locale, string $filename): string
{
return $this->getLocalesPath($locale . '/' . $filename . '.json', false);
}

protected function isSameKey(array $source, int|string $key, string $value): bool
{
return ($source[$key] ?? null) === $value;
}
}
3 changes: 3 additions & 0 deletions tests/Fixtures/Resources/Translate/locales/de/_excludes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[
"Administrator"
]
6 changes: 6 additions & 0 deletions tests/Fixtures/Resources/Translate/locales/de/json.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"Added.": "Added.",
"Administrator": "Administrator",
"Foo": "Foo",
"Bar.": "Bar."
}
7 changes: 7 additions & 0 deletions tests/Fixtures/Resources/Translate/locales/de/php-inline.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accepted": "This field must be accepted.",
"accepted_if": "This field must be accepted when :other is :value.",
"active_url": "This field is not a valid URL.",
"custom2": "Custom field 2",
"sub.array2": "Sub Array 2"
}
10 changes: 10 additions & 0 deletions tests/Fixtures/Resources/Translate/locales/de/php.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"0": "Numeric Zero",
"10": "Numeric Ten",
"100": "Numeric One Hundred",
"accepted": "The :attribute must be accepted.",
"accepted_if": "The :attribute must be accepted when :other is :value.",
"active_url": "The :attribute is not a valid URL.",
"custom": "Custom field",
"sub.array": "Sub Array"
}
6 changes: 6 additions & 0 deletions tests/Fixtures/Resources/Translate/locales/en/json.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"Added.": "Added.",
"Administrator": "Administrator",
"Foo": "Foo",
"Bar.": "Bar."
}
7 changes: 7 additions & 0 deletions tests/Fixtures/Resources/Translate/locales/en/php-inline.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"accepted": "This field must be accepted.",
"accepted_if": "This field must be accepted when :other is :value.",
"active_url": "This field is not a valid URL.",
"custom2": "Custom field 2",
"sub.array2": "Sub Array 2"
}
10 changes: 10 additions & 0 deletions tests/Fixtures/Resources/Translate/locales/en/php.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"0": "Numeric Zero",
"10": "Numeric Ten",
"100": "Numeric One Hundred",
"accepted": "The :attribute must be accepted.",
"accepted_if": "The :attribute must be accepted when :other is :value.",
"active_url": "The :attribute is not a valid URL.",
"custom": "Custom field",
"sub.array": "Sub Array"
}
Loading

0 comments on commit f2865b5

Please sign in to comment.