Просмотр исходного кода

Add new translate action: `move`, `make i18n-move-key` (#8214)

So that renaming something like `conf.shortcut.toggle_sidebar` to `conf.shortcut.toggle_aside` can be done easily even after already having added `conf.shortcut.toggle_sidebar` and translated it in multiple languages.

Example of usage:
```console
./cli/manipulate.translation.php -a move -k conf.shortcut.toggle_sidebar -n conf.shortcut.toggle_aside
```
```console
make i18n-move-key key="conf.shortcut.toggle_sidebar" new-key="conf.shortcut.toggle_aside"
```

The key will be moved and all values/states will be kept.
Inverle 4 месяцев назад
Родитель
Сommit
b9abe70690
5 измененных файлов с 69 добавлено и 7 удалено
  1. 11 0
      Makefile
  2. 25 2
      cli/i18n/I18nData.php
  3. 15 2
      cli/manipulate.translation.php
  4. 6 1
      docs/en/internationalization.md
  5. 12 2
      tests/cli/i18n/I18nDataTest.php

+ 11 - 0
Makefile

@@ -114,6 +114,17 @@ endif
 	@$(PHP) ./cli/manipulate.translation.php --action add --key $(key) --value "$(value)"
 	@echo Key added.
 
+.PHONY: i18n-move-key
+i18n-move-key: ## Move an existing key into a new location
+ifndef key
+	$(error To move a key, you need to provide one in the "key" variable)
+endif
+ifndef new-key
+	$(error To specify a location to move the key to, you need to provide it in the "new-key" variable)
+endif
+	@$(PHP) ./cli/manipulate.translation.php --action move --key $(key) --new-key "$(new-key)"
+	@echo Key moved.
+
 .PHONY: i18n-add-language
 i18n-add-language: ## Add a new supported language
 ifndef lang

+ 25 - 2
cli/i18n/I18nData.php

@@ -98,7 +98,7 @@ class I18nData {
 	 */
 	public function addLanguage(string $language, ?string $reference = null): void {
 		if (array_key_exists($language, $this->data)) {
-			throw new Exception('The selected language already exist.');
+			throw new Exception('The selected language already exists.');
 		}
 		if (!is_string($reference) || !array_key_exists($reference, $this->data)) {
 			$reference = static::REFERENCE_LANGUAGE;
@@ -221,7 +221,7 @@ class I18nData {
 		}
 
 		if ($this->isKnown($key)) {
-			throw new Exception('The selected key already exist.');
+			throw new Exception('The selected key already exists.');
 		}
 
 		$parentKey = $this->getParentKey($key);
@@ -248,6 +248,29 @@ class I18nData {
 		}
 	}
 
+	/**
+	 * Move an existing key into a new location
+	 * @throws Exception
+	 */
+	public function moveKey(string $key, string $newKey): void {
+		if (!$this->isKnown($key) && !$this->isKnown($this->getEmptySibling($key))) {
+			throw new Exception('The selected key does not exist');
+		}
+		if ($this->isKnown($newKey)) {
+			throw new Exception('Cannot move key to a location that already exists.');
+		}
+
+		$keyPrefix = $this->isParent($key) ? $key . '.' : $key;
+		foreach ($this->getAvailableLanguages() as $language) {
+			foreach ($this->data[$language][$this->getFilenamePrefix($key)] as $k => $v) {
+				if (str_starts_with($k, $keyPrefix)) {
+					$this->data[$language][$this->getFilenamePrefix($newKey)][str_replace($key, $newKey, $k)] = $v;
+					unset($this->data[$language][$this->getFilenamePrefix($key)][$k]);
+				}
+			}
+		}
+	}
+
 	/**
 	 * Add a value for a key for the selected language.
 	 *

+ 15 - 2
cli/manipulate.translation.php

@@ -9,6 +9,7 @@ require_once dirname(__DIR__) . '/constants.php';
 $cliOptions = new class extends CliOptionsParser {
 	public string $action;
 	public string $key;
+	public string $newKey;
 	public string $value;
 	public string $language;
 	public string $originLanguage;
@@ -18,6 +19,7 @@ $cliOptions = new class extends CliOptionsParser {
 	public function __construct() {
 		$this->addRequiredOption('action', (new CliOption('action', 'a')));
 		$this->addOption('key', (new CliOption('key', 'k')));
+		$this->addOption('newKey', (new CliOption('new-key', 'n')));
 		$this->addOption('value', (new CliOption('value', 'v')));
 		$this->addOption('language', (new CliOption('language', 'l')));
 		$this->addOption('originLanguage', (new CliOption('origin-language', 'o')));
@@ -56,6 +58,14 @@ switch ($cliOptions->action) {
 			exit;
 		}
 		break;
+	case 'move':
+		if (isset($cliOptions->key) && isset($cliOptions->newKey)) {
+			$i18nData->moveKey($cliOptions->key, $cliOptions->newKey);
+		} else {
+			error('You need to specify the key to move and its new location.');
+			exit;
+		}
+		break;
 	case 'delete':
 		if (isset($cliOptions->key)) {
 			$i18nData->removeKey($cliOptions->key);
@@ -131,7 +141,7 @@ DESCRIPTION
 	Manipulate translation files.
 
 	-a, --action=ACTION
-				select the action to perform. Available actions are add, delete,
+				select the action to perform. Available actions are add, move, delete,
 				exist, format, ignore, and ignore_unmodified. This option is mandatory.
 	-k, --key=KEY		select the key to work on.
 	-v, --value=VAL		select the value to set.
@@ -176,6 +186,9 @@ Example 10:	check if a key exist.
 
 Example 11:	add a new file to all languages
 	php $file -a add -k my_file.php
-HELP;
+
+Example 12:\tmove an existing key into a new location
+	php $file -a move -k my_key -n new_location
+HELP, PHP_EOL;
 	exit();
 }

+ 6 - 1
docs/en/internationalization.md

@@ -83,7 +83,7 @@ make i18n-ignore-key lang=fr key=index.about.version
 
 This command adds an IGNORE comment on the translation so the key can be considered as translated.
 
-## Add/remove/update a key
+## Add/remove/update/rename a key
 
 If you’re developing a new part of the application, you might want to declare a new translation key. Your first impulse would be to add the key to each file manually: don’t do that, it’s very painful. We provide another command:
 
@@ -107,6 +107,11 @@ make i18n-update-key key=the.key.to.change value='The new string in English'
 
 The key will simply be removed and added back with the new value.
 
+If you want to move/rename a key, you can use:
+```sh
+make i18n-move-key key=the.key.to.move new-key=new.location.of.the.key
+```
+
 ## How to access a translation programmatically
 
 To access these translations, you must use the `_t()` function (which is a shortcut for `Minz_Translate::t()`). Code example:

+ 12 - 2
tests/cli/i18n/I18nDataTest.php

@@ -34,6 +34,16 @@ final class I18nDataTest extends \PHPUnit\Framework\TestCase {
 		];
 	}
 
+	public function testMoveKey(): void {
+		$data = new I18nData($this->referenceData);
+		$value = $data->getData()['en']['file2.php']['file2.l1.l2.k2'];
+		self::assertTrue($data->isKnown('file2.l1.l2.k2'));
+		self::assertFalse($data->isKnown('file2.l1.nkl2'));
+		$data->moveKey('file2.l1.l2.k2', 'file2.l1.nkl2');
+		self::assertFalse($data->isKnown('file2.l1.l2.k2'));
+		self::assertTrue($data->isKnown('file2.l1.nkl2'));
+	}
+
 	public function testConstructWhenReferenceOnly(): void {
 		$data = new I18nData($this->referenceData);
 		self::assertSame($this->referenceData, $data->getData());
@@ -302,7 +312,7 @@ final class I18nDataTest extends \PHPUnit\Framework\TestCase {
 
 	public function testAddLanguageWhenLanguageExists(): void {
 		$this->expectException(\Exception::class);
-		$this->expectExceptionMessage('The selected language already exist.');
+		$this->expectExceptionMessage('The selected language already exists.');
 		$data = new I18nData($this->referenceData);
 		$data->addLanguage('en');
 	}
@@ -430,7 +440,7 @@ final class I18nDataTest extends \PHPUnit\Framework\TestCase {
 
 	public function testAddKeyWhenKeyExists(): void {
 		$this->expectException(\Exception::class);
-		$this->expectExceptionMessage('The selected key already exist.');
+		$this->expectExceptionMessage('The selected key already exists.');
 		$data = new I18nData($this->referenceData);
 		$data->addKey('file2.l1.l2.k1', 'value');
 	}