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

Merge pull request #1829 from aledeg/improve-i18n-tools

Improve i18n tools
Alexis Degrugillier 8 лет назад
Родитель
Сommit
a891df3283

+ 32 - 4
cli/i18n/I18nData.php

@@ -49,7 +49,8 @@ class I18nData {
 	 * @throws Exception
 	 */
 	public function addKey($key, $value) {
-		if (array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) {
+		if (array_key_exists($this->getFilenamePrefix($key), $this->data[static::REFERENCE_LANGUAGE]) &&
+		    array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) {
 			throw new Exception('The selected key already exist.');
 		}
 		$this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)][$key] = $value;
@@ -67,7 +68,8 @@ class I18nData {
 		if (!in_array($language, $this->getAvailableLanguages())) {
 			throw new Exception('The selected language does not exist.');
 		}
-		if (!array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) {
+		if (!array_key_exists($this->getFilenamePrefix($key), $this->data[static::REFERENCE_LANGUAGE]) ||
+		    !array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) {
 			throw new Exception('The selected key does not exist for the selected language.');
 		}
 		$this->data[$language][$this->getFilenamePrefix($key)][$key] = $value;
@@ -80,7 +82,8 @@ class I18nData {
 	 * @throws Exception
 	 */
 	public function duplicateKey($key) {
-		if (!array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) {
+		if (!array_key_exists($this->getFilenamePrefix($key), $this->data[static::REFERENCE_LANGUAGE]) ||
+		    !array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) {
 			throw new Exception('The selected key does not exist.');
 		}
 		$value = $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)][$key];
@@ -102,7 +105,8 @@ class I18nData {
 	 * @throws Exception
 	 */
 	public function removeKey($key) {
-		if (!array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) {
+		if (!array_key_exists($this->getFilenamePrefix($key), $this->data[static::REFERENCE_LANGUAGE]) ||
+		    !array_key_exists($key, $this->data[static::REFERENCE_LANGUAGE][$this->getFilenamePrefix($key)])) {
 			throw new Exception('The selected key does not exist.');
 		}
 		foreach ($this->getAvailableLanguages() as $language) {
@@ -112,6 +116,30 @@ class I18nData {
 		}
 	}
 
+	/**
+	 * WARNING! This is valid only for ignore files. It's not the best way to
+	 * handle that but as it's meant to be used only for the cli tool, there
+	 * is no point of spending time on making it better than that.
+	 *
+	 * Ignore a key from a language, or reverse it.
+	 *
+	 * @param string $key
+	 * @param string $language
+	 * @param boolean $reverse
+	 */
+	public function ignore($key, $language, $reverse = false) {
+		$index = array_search($key, $this->data[$language]);
+
+		if ($index && $reverse) {
+			unset($this->data[$language][$index]);
+			return;
+		}
+		if ($index && !$reverse) {
+			return;
+		}
+		$this->data[$language][] = $key;
+	}
+
 	/**
 	 * Check if the data has changed
 	 *

+ 3 - 1
cli/i18n/I18nFile.php

@@ -1,8 +1,9 @@
 <?php
 
 require_once __DIR__ . '/I18nData.php';
+require_once __DIR__ . '/I18nFileInterface.php';
 
-class i18nFile {
+class I18nFile implements I18nFileInterface{
 
 	private $i18nPath;
 
@@ -11,6 +12,7 @@ class i18nFile {
 	}
 
 	public function load() {
+		$i18n = array();
 		$dirs = new DirectoryIterator($this->i18nPath);
 		foreach ($dirs as $dir) {
 			if ($dir->isDot()) {

+ 10 - 0
cli/i18n/I18nFileInterface.php

@@ -0,0 +1,10 @@
+<?php
+
+require_once __DIR__ . '/I18nData.php';
+
+interface I18nFileInterface {
+
+	public function load();
+
+	public function dump(I18nData $i18n);
+}

+ 64 - 0
cli/i18n/I18nIgnoreFile.php

@@ -0,0 +1,64 @@
+<?php
+
+require_once __DIR__ . '/I18nData.php';
+require_once __DIR__ . '/I18nFileInterface.php';
+
+class I18nIgnoreFile implements I18nFileInterface {
+
+	private $i18nPath;
+
+	public function __construct() {
+		$this->i18nPath = __DIR__ . '/ignore';
+	}
+
+	public function dump(I18nData $i18n) {
+		foreach ($i18n->getData() as $language => $content) {
+			$filename = $this->i18nPath . DIRECTORY_SEPARATOR . $language . '.php';
+			file_put_contents($filename, $this->format($content));
+		}
+	}
+
+	public function load() {
+		$i18n = array();
+		$files = new DirectoryIterator($this->i18nPath);
+		foreach ($files as $file) {
+			if (!$file->isFile()) {
+				continue;
+			}
+			$i18n[$file->getBasename('.php')] = (include $file->getPathname());
+		}
+
+		return new I18nData($i18n);
+	}
+
+	/**
+	 * Format an array of translation
+	 *
+	 * It takes an array of translation and format it to be dumped in a
+	 * translation file. The array is first converted to a string then some
+	 * formatting regexes are applied to match the original content.
+	 *
+	 * @param array $translation
+	 * @return string
+	 */
+	private function format($translation) {
+		$translation = var_export(($translation), true);
+		$patterns = array(
+			'/array \(/',
+			'/=>\s*array/',
+			'/ {2}/',
+			'/\d+ => /',
+		);
+		$replacements = array(
+			'array(',
+			'=> array',
+			"\t", // Double quoting is mandatory to have a tab instead of the \t string
+			'',
+		);
+		$translation = preg_replace($patterns, $replacements, $translation);
+
+		// Double quoting is mandatory to have new lines instead of \n strings
+		return sprintf("<?php\n\nreturn %s;\n", $translation);
+	}
+
+}

+ 79 - 45
cli/manipulate.translation.php

@@ -1,45 +1,60 @@
 <?php
 
-$options = getopt("h");
+$options = getopt("a:hk:l:rv:");
 
 if (array_key_exists('h', $options)) {
 	help();
 }
 
-if (1 === $argc || 5 < $argc) {
-	help();
+if (!array_key_exists('a', $options)) {
+	error('You need to specify the action to perform.');
 }
 
-require_once __DIR__ . '/i18n/I18nFile.php';
-
-$i18nFile = new I18nFile();
+if ('ignore' === $options['a']) {
+	require_once __DIR__ . '/i18n/I18nIgnoreFile.php';
+	$i18nFile = new I18nIgnoreFile();
+} else {
+	require_once __DIR__ . '/i18n/I18nFile.php';
+	$i18nFile = new I18nFile();
+}
 $i18nData = $i18nFile->load();
 
-switch ($argv[1]) {
-	case 'add_language' :
-		$i18nData->addLanguage($argv[2]);
-		break;
-	case 'add_key' :
-		if (3 === $argc) {
-			help();
+switch ($options['a']) {
+	case 'add' :
+		if (array_key_exists('k', $options) && array_key_exists('v', $options) && array_key_exists('l', $options)) {
+			$i18nData->addValue($options['k'], $options['v'], $options['l']);
+		} elseif (array_key_exists('k', $options) && array_key_exists('v', $options)) {
+			$i18nData->addKey($options['k'], $options['v']);
+		} elseif (array_key_exists('l', $options)) {
+			$i18nData->addLanguage($options['l']);
+		} else {
+			error('You need to specify a valid set of options.');
 		}
-		$i18nData->addKey($argv[2], $argv[3]);
 		break;
-	case 'add_value':
-		if (4 === $argc) {
-			help();
+	case 'delete' :
+		if (array_key_exists('k', $options)) {
+			$i18nData->removeKey($options['k']);
+		} else {
+			error('You need to specify the key to delete.');
 		}
-		$i18nData->addValue($argv[2], $argv[3], $argv[4]);
 		break;
-	case 'duplicate_key' :
-		$i18nData->duplicateKey($argv[2]);
-		break;
-	case 'delete_key' :
-		$i18nData->removeKey($argv[2]);
+	case 'duplicate' :
+		if (array_key_exists('k', $options)) {
+			$i18nData->duplicateKey($options['k']);
+		} else {
+			error('You need to specify the key to duplicate');
+		}
 		break;
 	case 'format' :
 		$i18nFile->dump($i18nData);
 		break;
+	case 'ignore' :
+		if (array_key_exists('l', $options) && array_key_exists('k', $options)) {
+			$i18nData->ignore($options['k'], $options['l'], array_key_exists('r', $options));
+		} else {
+			error('You need to specify a valid set of options.');
+		}
+		break;
 	default :
 		help();
 }
@@ -48,47 +63,66 @@ if ($i18nData->hasChanged()) {
 	$i18nFile->dump($i18nData);
 }
 
+/**
+ * Output error message.
+ */
+function error($message) {
+	$error = <<<ERROR
+WARNING
+	%s\n\n
+ERROR;
+	echo sprintf($error, $message);
+	help();
+}
+
 /**
  * Output help message.
  */
 function help() {
 	$help = <<<HELP
 NAME
-	%s
+	%1\$s
 
 SYNOPSIS
-	php %s [OPTION] [OPERATION] [KEY] [VALUE] [LANGUAGE]
+	php %1\$s [OPTIONS]
 
 DESCRIPTION
-	Manipulate translation files. Available operations are 
-	Check if translation files have missing keys or missing translations.
-
+	Manipulate translation files.
+
+	-a=ACTION
+		select the action to perform. Available actions are add, delete,
+		duplicate, format, and ignore. This option is mandatory.
+	-k=KEY	select the key to work on.
+	-v=VAL	select the value to set.
+	-l=LANG	select the language to work on.
 	-h	display this help and exit.
 
-OPERATION
-	add_language
-		add a new language by duplicating the referential. This operation
-		needs only a KEY.
+EXEMPLE
+Exemple 1: add a language. It adds a new language by duplicating the referential.
+	php %1\$s -a add -l my_lang
+
+Exemple 2: add a new key. It adds the key in the referential.
+	php %1\$s -a add -k my_key -v my_value
 
-	add_key	add a new key in the referential. This operation needs a KEY and
-		a VALUE.
+Exemple 3: add a new value. It adds a new value for the selected key in the selected language.
+	php %1\$s -a add -k my_key -v my_value -l my_lang
 
-	add_value
-		add a value in the referential. This operation needs a KEY, a
-		VALUE, and a LANGUAGE.
+Exemple 4: delete a key. It deletes the selected key in every languages.
+	php %1\$s -a delete -k my_key
 
-	duplicate_key
-		duplicate a referential key in other languages. This operation
-		needs only a KEY.
+Exemple 5: duplicate a key. It duplicates the key from the referential in every languages.
+	php %1\$s -a duplicate -k my_key
 
-	delete_key
-		delete a referential key from all languages. This operation needs
-		only a KEY.
+Exemple 6: format i18n files.
+	php %1\$s -a format
 
-	format  format i18n files.
+Exemple 7: ignore a key. It adds the key in the ignore file to mark it as translated.
+	php %1\$s -a ignore -k my_key -l my_lang
 
+Exemple 8: revert ignore a key. It removes the key from the ignore file.
+	php %1\$s -a ignore -r -k my_key -l my_lang\n\n
 HELP;
 	$file = str_replace(__DIR__ . '/', '', __FILE__);
-	echo sprintf($help, $file, $file);
+	echo sprintf($help, $file);
 	exit;
 }