Eloquence has uploaded a new change for review. https://gerrit.wikimedia.org/r/315935
Change subject: Remove redundant RubyYamlFFS class, use ArrayFlattener in YamlFFS ...................................................................... Remove redundant RubyYamlFFS class, use ArrayFlattener in YamlFFS Note that we now have to set parseCLDPlurals for all message groups that use the CLDR syntax ("one", "few" "other", etc.) for pluralization rules. Change-Id: I4a5b98acd7d7bc1fb6fc907c6c0ff091821db87c --- M Autoload.php D ffs/RubyYamlFFS.php M ffs/YamlFFS.php D tests/phpunit/ffs/RubyYamlFFSTest.php 4 files changed, 22 insertions(+), 423 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Translate refs/changes/35/315935/1 diff --git a/Autoload.php b/Autoload.php index 0f12e88..2e5e109 100644 --- a/Autoload.php +++ b/Autoload.php @@ -191,7 +191,6 @@ $al['JavaScriptFFS'] = "$dir/ffs/JavaScriptFFS.php"; $al['JsonFFS'] = "$dir/ffs/JsonFFS.php"; $al['MediaWikiExtensionFFS'] = "$dir/ffs/MediaWikiExtensionFFS.php"; -$al['RubyYamlFFS'] = "$dir/ffs/RubyYamlFFS.php"; $al['ShapadoJsFFS'] = "$dir/ffs/JavaScriptFFS.php"; $al['SimpleFFS'] = "$dir/ffs/SimpleFFS.php"; $al['XliffFFS'] = "$dir/ffs/XliffFFS.php"; diff --git a/ffs/RubyYamlFFS.php b/ffs/RubyYamlFFS.php deleted file mode 100644 index f0c978d..0000000 --- a/ffs/RubyYamlFFS.php +++ /dev/null @@ -1,170 +0,0 @@ -<?php - -/** - * Extends YamlFFS with Ruby (on Rails) style plural support. Supports subkeys - * zero, one, many, few, other and two for each message using plural with - * {{count}} variable. - * @ingroup FFS - */ -class RubyYamlFFS extends YamlFFS { - protected static $pluralWords = array( - 'zero' => 1, - 'one' => 1, - 'many' => 1, - 'few' => 1, - 'other' => 1, - 'two' => 1 - ); - - public function getFileExtensions() { - return array( '.yml', '.yaml' ); - } - - /** - * Flattens ruby plural arrays into special plural syntax. - * - * @param array $messages Array of keys and values - * - * @throws MWException - * @return bool|string - */ - public function flattenPlural( $messages ) { - - $pluralKeys = false; - $nonPluralKeys = false; - foreach ( $messages as $key => $value ) { - if ( is_array( $value ) ) { - # Plurals can only happen in the lowest level of the structure - return false; - } - - # Check if we find any reserved plural keyword - if ( isset( self::$pluralWords[$key] ) ) { - $pluralKeys = true; - } else { - $nonPluralKeys = true; - } - } - - # No plural keys at all, we can skip - if ( !$pluralKeys ) { - return false; - } - - # Mixed plural keys with other keys, should not happen - if ( $nonPluralKeys ) { - $keys = implode( ', ', array_keys( $messages ) ); - throw new MWException( "Reserved plural keywords mixed with other keys: $keys." ); - } - - $pls = '{{PLURAL'; - foreach ( $messages as $key => $value ) { - if ( $key === 'other' ) { - continue; - } - - $pls .= "|$key=$value"; - } - - // Put the "other" alternative last, without other= prefix. - $other = isset( $messages['other'] ) ? '|' . $messages['other'] : ''; - $pls .= "$other}}"; - - return $pls; - } - - /** - * Converts the special plural syntax to array or ruby style plurals - * - * @param string $key Message key prefix - * @param string $message The plural string - * - * @return bool|array - */ - public function unflattenPlural( $key, $message ) { - // Quick escape. - if ( strpos( $message, '{{PLURAL' ) === false ) { - return array( $key => $message ); - } - - /* - * Replace all variables with placeholders. Possible source of bugs - * if other characters that given below are used. - */ - $regex = '~\{[a-zA-Z_-]+}~'; - $placeholders = array(); - $match = array(); - - while ( preg_match( $regex, $message, $match ) ) { - $uniqkey = TranslateUtils::getPlaceholder(); - $placeholders[$uniqkey] = $match[0]; - $search = preg_quote( $match[0], '~' ); - $message = preg_replace( "~$search~", $uniqkey, $message ); - } - - // Then replace (possible multiple) plural instances into placeholders. - $regex = '~\{\{PLURAL\|(.*?)}}~s'; - $matches = array(); - $match = array(); - - while ( preg_match( $regex, $message, $match ) ) { - $uniqkey = TranslateUtils::getPlaceholder(); - $matches[$uniqkey] = $match; - $message = preg_replace( $regex, $uniqkey, $message, 1 ); - } - - // No plurals, should not happen. - if ( !count( $matches ) ) { - return false; - } - - // The final array of alternative plurals forms. - $alts = array(); - - /* - * Then loop trough each plural block and replacing the placeholders - * to construct the alternatives. Produces invalid output if there is - * multiple plural bocks which don't have the same set of keys. - */ - $pluralChoice = implode( '|', array_keys( self::$pluralWords ) ); - $regex = "~($pluralChoice)\s*=\s*(.+)~s"; - foreach ( $matches as $ph => $plu ) { - $forms = explode( '|', $plu[1] ); - - foreach ( $forms as $form ) { - if ( $form === '' ) { - continue; - } - - $match = array(); - if ( preg_match( $regex, $form, $match ) ) { - $formWord = "$key.{$match[1]}"; - $value = $match[2]; - } else { - $formWord = "$key.other"; - $value = $form; - } - - if ( !isset( $alts[$formWord] ) ) { - $alts[$formWord] = $message; - } - - $string = $alts[$formWord]; - $alts[$formWord] = str_replace( $ph, $value, $string ); - } - } - - // Replace other variables. - foreach ( $alts as &$value ) { - $value = str_replace( array_keys( $placeholders ), array_values( $placeholders ), $value ); - } - - if ( !isset( $alts["$key.other"] ) ) { - wfWarn( "Other not set for key $key" ); - - return false; - } - - return $alts; - } -} diff --git a/ffs/YamlFFS.php b/ffs/YamlFFS.php index 41fe5ad..40f9085 100644 --- a/ffs/YamlFFS.php +++ b/ffs/YamlFFS.php @@ -12,6 +12,20 @@ return array( '.yaml', '.yml' ); } + /** + * @param $group FileBasedMessageGroup + */ + public function __construct( FileBasedMessageGroup $group ) { + parent::__construct( $group ); + $nestingSeparator = isset( $this->extra['nestingSeparator'] ) ? + $this->extra['nestingSeparator'] : '.'; + $parseCLDRPlurals = isset( $this->extra['parseCLDRPlurals'] ) ? + $this->extra['parseCLDRPlurals'] : false; + + // Instantiate helper class for flattening and unflattening nested arrays + $this->flattener = new ArrayFlattener( $nestingSeparator, $parseCLDRPlurals ); + } + /** * @param $data * @return array Parsed data. @@ -30,7 +44,7 @@ $messages = array_shift( $messages ); } - $messages = $this->flatten( $messages ); + $messages = $this->flattener->flatten( $messages ); $messages = $this->group->getMangler()->mangle( $messages ); foreach ( $messages as &$value ) { $value = rtrim( $value, "\n" ); @@ -72,7 +86,7 @@ return false; } - $messages = $this->unflatten( $messages ); + $messages = $this->flattener->unflatten( $messages ); // Some groups have messages under language code. if ( isset( $this->extra['codeAsRoot'] ) ) { @@ -122,131 +136,6 @@ return $output; } - /** - * Flattens multidimensional array by using the path to the value as key - * with each individual key separated by a dot. - * - * @param $messages array - * - * @return array - */ - protected function flatten( $messages ) { - $flat = true; - - foreach ( $messages as $v ) { - if ( !is_array( $v ) ) { - continue; - } - - $flat = false; - break; - } - - if ( $flat ) { - return $messages; - } - - $array = array(); - foreach ( $messages as $key => $value ) { - if ( !is_array( $value ) ) { - $array[$key] = $value; - } else { - $plural = $this->flattenPlural( $value ); - if ( $plural ) { - $array[$key] = $plural; - } else { - $newArray = array(); - foreach ( $value as $newKey => $newValue ) { - $newArray["$key.$newKey"] = $newValue; - } - $array += $this->flatten( $newArray ); - } - } - - /** - * Can as well keep only one copy around. - */ - unset( $messages[$key] ); - } - - return $array; - } - - /** - * Performs the reverse operation of flatten. Each dot in the key starts a - * new subarray in the final array. - * - * @param $messages array - * - * @return array - */ - protected function unflatten( $messages ) { - $array = array(); - foreach ( $messages as $key => $value ) { - $plurals = $this->unflattenPlural( $key, $value ); - - if ( $plurals === false ) { - continue; - } - - foreach ( $plurals as $keyPlural => $valuePlural ) { - $path = explode( '.', $keyPlural ); - if ( count( $path ) === 1 ) { - $array[$keyPlural] = $valuePlural; - continue; - } - - $pointer = &$array; - do { - /** - * Extract the level and make sure it exists. - */ - $level = array_shift( $path ); - if ( !isset( $pointer[$level] ) ) { - $pointer[$level] = array(); - } - - /** - * Update the pointer to the new reference. - */ - $tmpPointer = &$pointer[$level]; - unset( $pointer ); - $pointer = &$tmpPointer; - unset( $tmpPointer ); - - /** - * If next level is the last, add it into the array. - */ - if ( count( $path ) === 1 ) { - $lastKey = array_shift( $path ); - $pointer[$lastKey] = $valuePlural; - } - } while ( count( $path ) ); - } - } - - return $array; - } - - /** - * @param $value - * @return bool - */ - public function flattenPlural( $value ) { - return false; - } - - /** - * Override this. Return false to skip processing this value. Otherwise - * - * @param $key string - * @param $value string - * - * @return array with keys and values. - */ - public function unflattenPlural( $key, $value ) { - return array( $key => $value ); - } public static function getExtraSchema() { $schema = array( @@ -259,6 +148,12 @@ 'codeAsRoot' => array( '_type' => 'boolean', ), + 'nestingSeparator' => array( + '_type' => 'text', + ), + 'parseCLDRPlurals' => array( + '_type' => 'boolean', + ) ) ) ) diff --git a/tests/phpunit/ffs/RubyYamlFFSTest.php b/tests/phpunit/ffs/RubyYamlFFSTest.php deleted file mode 100644 index 3629b2e..0000000 --- a/tests/phpunit/ffs/RubyYamlFFSTest.php +++ /dev/null @@ -1,125 +0,0 @@ -<?php - -class RubyYamlFFSTest extends MediaWikiTestCase { - /** @var MessageGroup */ - protected $group; - - /** @var FFS */ - protected $ffs; - - protected $groupConfiguration = array( - 'BASIC' => array( - 'class' => 'FileBasedMessageGroup', - 'id' => 'test-id', - 'label' => 'Test Label', - 'namespace' => 'NS_MEDIAWIKI', - 'description' => 'Test description', - ), - 'FILES' => array( - 'class' => 'RubyYamlFFS', - ), - ); - - protected function setUp() { - parent::setUp(); - $group = MessageGroupBase::factory( $this->groupConfiguration ); - /** @var YamlFFS $ffs */ - $this->ffs = $group->getFFS(); - } - - public function testFlattenPluralWithNoPlurals() { - $input = array( - 'much' => 'a lot', - 'less' => 'not so much', - ); - $output = false; - $this->assertEquals( $output, $this->ffs->flattenPlural( $input ) ); - } - - public function testFlattenPluralWithPlurals() { - $input = array( - 'one' => 'just a tiny bit', - 'two' => 'not so much', - 'other' => 'maybe a lot', - ); - $output = '{{PLURAL|one=just a tiny bit|two=not so much|maybe a lot}}'; - $this->assertEquals( $output, $this->ffs->flattenPlural( $input ) ); - } - - public function testFlattenPluralWithArrays() { - $input = array( - 'one' => array( - 'multi' => 'he lives in a multistorey house', - 'row' => 'he lives in a row house', - ), - 'other' => array( - 'multi' => 'he lives in mountain cave', - 'row' => 'he lives in a cave near the river', - ), - ); - $output = false; - $this->assertEquals( $output, $this->ffs->flattenPlural( $input ) ); - } - - /** - * @expectedException MWException - * @expectedExceptionMessage Reserved plural keywords mixed with other keys - * @dataProvider flattenPluralsWithMixedKeywordsProvider - */ - - public function testFlattenPluralsWithMixedKeywords( $input, $comment ) { - $this->ffs->flattenPlural( $input ); - } - - public function flattenPluralsWithMixedKeywordsProvider() { - return array( - array( - array( - 'carrot' => 'I like carrots', - 'other' => 'I like milk', - ), - 'reserved keyword at the end', - ), - array( - array( - 'one' => 'I am the one leader', - 'club' => 'I am the club leader', - ), - 'reserved keyword at the beginning', - ) - ); - } - - /** - * @dataProvider unflattenDataProvider - */ - public function testUnflattenPural( $key, $value, $result ) { - $this->assertEquals( - $result, - $this->ffs->unflattenPlural( $key, $value ) - ); - } - - public function unflattenDataProvider() { - return array( - array( 'key', '{{PLURAL}}', false ), - array( 'key', 'value', array( 'key' => 'value' ) ), - array( 'key', '{{PLURAL|one=cat|other=cats}}', - array( 'key.one' => 'cat', 'key.other' => 'cats' ) - ), - array( 'key', '{{PLURAL|one=шляху %{related_ways}|шляхоў %{related_ways}}}', - array( - 'key.one' => 'шляху %{related_ways}', - 'key.other' => 'шляхоў %{related_ways}' - ) - ), - array( 'key', '{{PLURAL|foo=cat}}', - array( 'key.other' => 'foo=cat' ) - ), - array( 'key', '{{PLURAL|zero=0|one=1|two=2|few=3|many=160|other=898}}', - array( 'key.zero' => '0', 'key.one' => '1', 'key.two' => '2', - 'key.few' => '3', 'key.many' => '160', 'key.other' => '898' ) - ), - ); - } -} -- To view, visit https://gerrit.wikimedia.org/r/315935 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I4a5b98acd7d7bc1fb6fc907c6c0ff091821db87c Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Translate Gerrit-Branch: master Gerrit-Owner: Eloquence <eloque...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits