diff --git a/VERSION b/VERSION index 945273a..96aeaa6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.00 \ No newline at end of file +1.01 \ No newline at end of file diff --git a/src/Helper/LanguageMapper.php b/src/Helper/LanguageMapper.php index 88f60b1..ef52487 100644 --- a/src/Helper/LanguageMapper.php +++ b/src/Helper/LanguageMapper.php @@ -11,10 +11,21 @@ /** * Map given list of language tags to supported ones * + * For example some speller supports de_DE, en_US and ru_RU languages. But your application uses + * short versions of language tags: de, en, ru. LanguageMapper maps your list of language tags + * to supported by speller. + * * @since 1.00 */ class LanguageMapper { + /** + * Preferred mappings + * + * @var array + */ + private $preferred = []; + /** * Map given list of language tags to supported ones * @@ -26,7 +37,7 @@ class LanguageMapper * @link http://tools.ietf.org/html/bcp47 * @since 1.00 */ - public static function map(array $requested, array $supported) + public function map(array $requested, array $supported) { $index = []; foreach ($supported as $tag) { @@ -36,6 +47,17 @@ public static function map(array $requested, array $supported) $result = []; foreach ($requested as $source) { + + if (array_key_exists($source, $this->preferred)) { + $preferred = $this->preferred[$source]; + foreach ($preferred as $tag) { + if (in_array($tag, $supported, true)) { + $result []= $tag; + continue 2; + } + } + } + if (in_array($source, $supported, true)) { $result []= $source; continue; @@ -51,4 +73,27 @@ public static function map(array $requested, array $supported) } return $result; } + + /** + * Set preferred mappings + * + * Examples: + * + * ``` + * $mapper->setPreferredMappings(['en' => ['en_US', 'en_GB']]); + * ``` + * + * @param array $mappings + * + * @since 1.01 + */ + public function setPreferredMappings(array $mappings) + { + foreach ($mappings as $language => $map) { + if (!is_array($map)) { + $map = [$map]; + } + $this->preferred[$language] = $map; + } + } } diff --git a/src/Hunspell/Hunspell.php b/src/Hunspell/Hunspell.php index d0d3b21..df6138b 100644 --- a/src/Hunspell/Hunspell.php +++ b/src/Hunspell/Hunspell.php @@ -57,6 +57,13 @@ class Hunspell implements Speller */ private $supportedLanguages = null; + /** + * Language mapper + * + * @var LanguageMapper|null + */ + private $lanuageMapper = null; + /** * Create new hunspell adapter * @@ -86,7 +93,7 @@ public function __construct($hunspellBinary = 'hunspell') */ public function checkText(Source $source, array $languages) { - $dictionaries = LanguageMapper::map($languages, $this->getSupportedLanguages()); + $dictionaries = $this->getLanguageMapper()->map($languages, $this->getSupportedLanguages()); $dictionaries = array_merge($dictionaries, $this->customDictionaries); $process = $this->createProcess( @@ -209,6 +216,18 @@ public function setCustomDictionaries(array $customDictionaries) $this->customDictionaries = $customDictionaries; } + /** + * Set language mapper + * + * @param LanguageMapper $mapper + * + * @since 1.01 + */ + public function setLanguageMapper(LanguageMapper $mapper) + { + $this->lanuageMapper = $mapper; + } + /** * Set hunspell execution timeout * @@ -231,6 +250,22 @@ public function setTimeout($seconds) * @return Process */ private function createProcess($args = null, array $env = []) + { + $command = $this->composeCommand($args, $env); + $process = new Process($command); + $process->setTimeout($this->timeout); + return $process; + } + + /** + * Compose shell command line + * + * @param string|string[]|null $args hunspell arguments + * @param array $env environment variables + * + * @return string + */ + private function composeCommand($args, array $env = []) { $command = $this->binary; if ($this->customDictPath) { @@ -242,14 +277,22 @@ private function createProcess($args = null, array $env = []) } } if (is_array($args)) { - $args = array_map('escapeshellarg', $args); $args = implode(' ', $args); - } else { - $args = escapeshellarg($args); } $command .= ' ' . $args; - $process = new Process($command); - $process->setTimeout($this->timeout); - return $process; + return $command; + } + + /** + * Return language mapper + * + * @return LanguageMapper + */ + private function getLanguageMapper() + { + if (null === $this->lanuageMapper) { + $this->lanuageMapper = new LanguageMapper(); + } + return $this->lanuageMapper; } } diff --git a/tests/Helper/LanguageMapperTest.php b/tests/Helper/LanguageMapperTest.php index 34977c0..bcec2b3 100644 --- a/tests/Helper/LanguageMapperTest.php +++ b/tests/Helper/LanguageMapperTest.php @@ -18,12 +18,30 @@ */ class LanguageMapperTest extends TestCase { + /** + * Test basic mapping + */ public function testBasics() { - $result = LanguageMapper::map( + $mapper = new LanguageMapper(); + $result = $mapper->map( ['de', 'en', 'ru'], ['de_DE', 'en_GB.UTF-8', 'en_US', 'ru_RU', 'ru'] ); static::assertEquals(['de_DE', 'en_GB.UTF-8', 'ru'], $result); } + + /** + * Test preferred mapping + */ + public function testPreferred() + { + $mapper = new LanguageMapper(); + $mapper->setPreferredMappings(['en' => ['en_US', 'en_GB']]); + $result = $mapper->map( + ['de', 'en', 'ru'], + ['de_DE', 'en_GB.UTF-8', 'en_US', 'ru_RU', 'ru'] + ); + static::assertEquals(['de_DE', 'en_US', 'ru'], $result); + } } diff --git a/tests/Hunspell/HunspellTest.php b/tests/Hunspell/HunspellTest.php index fdccbea..d6bb8cb 100644 --- a/tests/Hunspell/HunspellTest.php +++ b/tests/Hunspell/HunspellTest.php @@ -11,6 +11,7 @@ use Mekras\Speller\Hunspell\Hunspell; use Mekras\Speller\Source\StringSource; use PHPUnit_Framework_TestCase as TestCase; +use ReflectionMethod; /** * Tests for Mekras\Speller\Hunspell\Hunspell @@ -19,6 +20,17 @@ */ class HunspellTest extends TestCase { + /** + * Test hunspell argument escaping + */ + public function testArgumentEscaping() + { + $hunspell = new Hunspell(); + $method = new ReflectionMethod(get_class($hunspell), 'composeCommand'); + $method->setAccessible(true); + static::assertEquals('hunspell -d foo,bar', $method->invoke($hunspell, ['-d foo,bar'])); + } + /** * Test retrieving list of supported languages */