Skip to content

Commit c5a6f91

Browse files
committed
feat: Adding reference language feature
1 parent fd11969 commit c5a6f91

File tree

5 files changed

+65
-18
lines changed

5 files changed

+65
-18
lines changed

README.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -213,12 +213,8 @@ php artisan vendor:publish --provider="Kargnas\LaravelAiTranslator\ServiceProvid
213213
214214
This will create a `config/ai-translator.php` file where you can modify the following settings:
215215
216-
- `source_locale`: Change this to your default language in the Laravel project. The package will translate from this language.
217-
218216
- `source_directory`: If you use a different directory for language files instead of the default `lang` directory, you can specify it here.
219217
220-
- `chunk_size`: Set the number of strings to be translated in a single AI request. Higher values can significantly reduce API costs but may impact translation quality for very large chunks. Default is 10.
221-
222218
- `ai`: Configure the AI provider, model, and API key here. Here are our recommendation for the best models:
223219
224220
| Provider | Model | Cost (I/O per 1M tokens) | Descrpition |
@@ -247,9 +243,7 @@ Example configuration:
247243
<?php
248244
249245
return [
250-
'source_locale' => 'en',
251246
'source_directory' => 'lang',
252-
'chunk_size' => 10,
253247
254248
'ai' => [
255249
'provider' => 'openai', // or 'anthropic'

config/ai-translator.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
<?php
22

33
return [
4-
'source_locale' => 'en',
54
'source_directory' => 'lang',
6-
// Translate strings in a batch. The higher, the cheaper.
7-
'chunk_size' => 10,
85

96
'ai' => [
107
// 'provider' => 'anthropic',

src/AI/AIProvider.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,22 @@ protected function getUserPrompt($replaces = []) {
6969
$replaces = array_merge($replaces, [
7070
'sourceLanguage' => $this->sourceLanguage,
7171
'targetLanguage' => $this->targetLanguage,
72+
'filename' => $this->filename,
7273
'parentKey' => basename($this->filename, '.php'),
7374
'strings' => collect($this->strings)->map(function ($string, $key) {
7475
if (is_string($string)) {
7576
return " - `{$key}`: \"\"\"{$string}\"\"\"";
7677
} else {
7778
$text = " - `{$key}`: \"\"\"{$string['text']}\"\"\"";
78-
if ($string['context']) {
79+
if (isset($string['context'])) {
7980
$text .= "\n - Context: \"\"\"{$string['context']}\"\"\"";
8081
}
82+
if (isset($string['references']) && sizeof($string['references']) > 0) {
83+
$text .= "\n - References:";
84+
foreach ($string['references'] as $locale => $items) {
85+
$text .= "\n - {$locale}: \"\"\"" . $items . "\"\"\"";
86+
}
87+
}
8188
return $text;
8289
}
8390
})->implode("\n"),
@@ -130,7 +137,7 @@ public function getTranslatedObjects(): array {
130137

131138
// Fix Parent key issue
132139
$parentKey = basename($this->filename, '.php');
133-
foreach($result as $item) {
140+
foreach ($result as $item) {
134141
if (str_starts_with($item->key, $parentKey)) {
135142
$item->key = str_replace($parentKey . '.', '', $item->key);
136143
}

src/AI/prompt-user.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
# Target String
2-
32
The most important mission: All strings should be translated into {targetLanguage} from {sourceLanguage}.
43
- Source Language: `{sourceLanguage}`
54
- Target Language: `{targetLanguage}`
65
- Source filename: `{filename}`
76

87
## Context
98
- Parent key (Only for your reference, don't put to the key): `{parentKey}`
10-
- The source strings: (e.g. key: """(value)"""), these are the strings that you should translate into the target language.
9+
- The source strings: (e.g. `key`: """(value)"""), these are the strings that you should translate into the target language.
1110
{strings}

src/Console/TranslateStrings.php

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ class TranslateStrings extends Command
276276
protected $sourceLocale;
277277
protected $sourceDirectory;
278278
protected $chunkSize;
279+
protected array $referenceLocales = [];
279280

280281
public function __construct() {
281282
parent::__construct();
@@ -286,10 +287,15 @@ public function __construct() {
286287
}
287288

288289
public function handle() {
289-
$this->sourceLocale = config('ai-translator.source_locale');
290290
$this->sourceDirectory = config('ai-translator.source_directory');
291-
$this->chunkSize = config('ai-translator.chunk_size', 10);
292291

292+
$this->sourceLocale = $this->choiceLanguages("Choose a source language to translate from", false, 'en');
293+
294+
if ($this->ask('Do you want to add reference languages? (y/n)', 'n') === 'y') {
295+
$this->referenceLocales = $this->choiceLanguages("Choose a language to reference when translating, preferably one that has already been vetted and translated to a high quality. You can select multiple languages via ',' (e.g. '1, 2')", true);
296+
}
297+
298+
$this->chunkSize = $this->ask("Enter the chunk size for translation. Translate strings in a batch. The higher, the cheaper. (default: 10)", 10);
293299
$this->translate();
294300
}
295301

@@ -391,6 +397,25 @@ protected static function getAdditionalRules($locale): array {
391397
return array_merge(static::getAdditionalRulesFromConfig($locale), static::getAdditionalRulesDefault($locale), static::getAdditionalRulesPlural($locale));
392398
}
393399

400+
public function choiceLanguages($question, $multiple, $default = null) {
401+
$locales = $this->getExistingLocales();
402+
403+
$selectedLocales = $this->choice(
404+
$question,
405+
$locales,
406+
$default,
407+
3,
408+
$multiple);
409+
410+
if (is_array($selectedLocales)) {
411+
$this->info("Selected locales: " . implode(', ', $selectedLocales));
412+
} else {
413+
$this->info("Selected locale: " . $selectedLocales);
414+
}
415+
416+
return $selectedLocales;
417+
}
418+
394419
public function translate() {
395420
$locales = $this->getExistingLocales();
396421
foreach ($locales as $locale) {
@@ -422,6 +447,17 @@ public function translate() {
422447
})
423448
->toArray();
424449

450+
$referenceStringList = collect($this->referenceLocales)
451+
->filter(fn($referenceLocale) => !in_array($referenceLocale, [$locale, $this->sourceLocale]))
452+
->mapWithKeys(function ($referenceLocale) use ($file, $targetStringTransformer) {
453+
$referenceFile = $this->getOutputDirectoryLocale($referenceLocale) . '/' . basename($file);
454+
$referenceTransformer = new PHPLangTransformer($referenceFile);
455+
return [
456+
$referenceLocale => $referenceTransformer->flatten(),
457+
];
458+
})
459+
->toArray();
460+
425461
if (sizeof($sourceStringList) > 100) {
426462
if (!$this->confirm("{$outputFile}, Strings: " . sizeof($sourceStringList) . " -> Many strings to translate. Could be expensive. Continue?")) {
427463
$this->warn("Stopped translating!");
@@ -433,10 +469,21 @@ public function translate() {
433469
// But also this will increase the speed of the translation, and quality of continuous translation
434470
collect($sourceStringList)
435471
->chunk($this->chunkSize)
436-
->each(function ($chunk) use ($locale, $file, $targetStringTransformer) {
472+
->each(function ($chunk) use ($locale, $file, $targetStringTransformer, $referenceStringList) {
437473
$translator = new AIProvider(
438474
filename: $file,
439-
strings: $chunk->toArray(),
475+
strings: $chunk->mapWithKeys(function ($item, $key) use ($referenceStringList) {
476+
return [
477+
$key => [
478+
'text' => $item,
479+
'references' => collect($referenceStringList)->map(function ($items) use ($key) {
480+
return $items[$key] ?? "";
481+
})->filter(function ($value) {
482+
return strlen($value) > 0;
483+
}),
484+
],
485+
];
486+
})->toArray(),
440487
sourceLanguage: static::getLanguageName($this->sourceLocale) ?? $this->sourceLocale,
441488
targetLanguage: static::getLanguageName($locale) ?? $locale,
442489
additionalRules: static::getAdditionalRules($locale),
@@ -455,14 +502,17 @@ public function translate() {
455502
}
456503
}
457504

505+
/**
506+
* @return array|string[]
507+
*/
458508
public function getExistingLocales(): array {
459509
$root = $this->sourceDirectory;
460510
$directories = array_diff(scandir($root), ['.', '..']);
461511
// only directories
462512
$directories = array_filter($directories, function ($directory) use ($root) {
463513
return is_dir($root . '/' . $directory);
464514
});
465-
return $directories;
515+
return collect($directories)->values()->toArray();
466516
}
467517

468518
public function getOutputDirectoryLocale($locale) {

0 commit comments

Comments
 (0)