diff --git a/core/lib/Drupal/Component/Gettext/PoStreamReader.php b/core/lib/Drupal/Component/Gettext/PoStreamReader.php index f84d251..eb62831 100644 --- a/core/lib/Drupal/Component/Gettext/PoStreamReader.php +++ b/core/lib/Drupal/Component/Gettext/PoStreamReader.php @@ -424,6 +424,9 @@ private function readLine() { $this->_current_item['msgstr'] = []; } + // Replace @count[X] elements with @count. For compatibility with + // drupal.org translations for Drupal 7. + $quoted = preg_replace('!@count\[\d+\]!', '@count', $quoted); $this->_current_item['msgstr'][$this->_current_plural_index] = $quoted; $this->_context = 'MSGSTR_ARR'; diff --git a/core/modules/locale/locale.batch.inc b/core/modules/locale/locale.batch.inc index fade172..0e38f1e 100644 --- a/core/modules/locale/locale.batch.inc +++ b/core/modules/locale/locale.batch.inc @@ -303,3 +303,76 @@ function locale_translation_download_source($source_file, $directory = 'temporar \Drupal::logger('locale')->error('Unable to download translation file @uri.', ['@uri' => $source_file->uri]); return FALSE; } + +/** + * Implements callback_batch_operation(). + * + * Executes a batch operation for locale_update_8400(). + * + * @param array|\ArrayAccess $context + * An array of contextual key/values. + */ +function _locale_fix_old_plural_style_batch_proccess(&$context) { + $database = \Drupal::database(); + + if (!isset($context['sandbox']['progress'])) { + $context['sandbox']['progress'] = 0; + $context['sandbox']['max'] = $database->query('SELECT COUNT(lid) FROM {locales_target} WHERE translation REGEXP :pattern', [':pattern' => "@count\\[[0-9]+\\]"])->fetchField(); + } + + $limit = 100; + + $result = $database->queryRange("SELECT lid, translation FROM {locales_target} WHERE translation REGEXP '@count\\\[[0-9]+\\\]'", 0, $limit)->fetchAll(); + + foreach ($result as $row) { + $lid = $row->lid; + $old_translation = $row->translation; + $new_translation = preg_replace('!@count\[\d+\]!', '@count', $old_translation); + $database->query( + "UPDATE {locales_target} SET translation = :new_translation WHERE lid = :lid", + [ + ':new_translation' => $new_translation, + ':lid' => $lid, + ] + ); + $context['results'][] = "$lid: $old_translation ---> $new_translation"; + $context['sandbox']['progress']++; + } + + if ($context['sandbox']['progress'] != $context['sandbox']['max']) { + $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max']; + } + +} + +/** + * Implements callback_batch_finished(). + * + * Reports the 'finished' status of batch operation for node_mass_update(). + * + * @param bool $success + * A boolean indicating whether the batch mass update operation successfully + * concluded. + * @param string[] $results + * An array of rendered links to nodes updated via the batch mode process. + * @param array $operations + * An array of function calls (not used in this function). + * + * @see _locale_fix_old_plural_style_batch_proccess() + */ +function _locale_fix_old_plural_style_batch_finished($success, $results, $operations) { + if ($success) { + drupal_set_message(t('The update has been performed.')); + } + else { + drupal_set_message(t('An error occurred and processing did not complete.'), 'error'); + } + drupal_set_message(t('Count changes: @count.', ['@count' => count($results)])); +// $item_list = [ +// '#theme' => 'item_list', +// '#items' => $results, +// ]; +// $message = \Drupal::service('renderer')->renderPlain($item_list); +// drupal_set_message($message); + +} diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install index 225e952..dba403f 100644 --- a/core/modules/locale/locale.install +++ b/core/modules/locale/locale.install @@ -303,3 +303,20 @@ function locale_update_8300() { // the new key value collection. \Drupal::state()->delete('locale.translation_status'); } + +/** + * Fix old plural style. + */ +function locale_update_8400() { + $batch = [ + 'operations' => [ + ['_locale_fix_old_plural_style_batch_proccess', []] + ], + 'finished' => '_locale_fix_old_plural_style_batch_finished', + 'title' => t('Processing'), + 'progress_message' => '', + 'error_message' => t('The update has encountered an error.'), + 'file' => drupal_get_path('module', 'locale') . '/locale.batch.inc', + ]; + batch_set($batch); +} diff --git a/core/modules/locale/tests/src/Functional/LocaleImportFunctionalTest.php b/core/modules/locale/tests/src/Functional/LocaleImportFunctionalTest.php index 581c98f..97f6dee 100644 --- a/core/modules/locale/tests/src/Functional/LocaleImportFunctionalTest.php +++ b/core/modules/locale/tests/src/Functional/LocaleImportFunctionalTest.php @@ -362,6 +362,17 @@ public function testCreatedLanguageTranslation() { } /** + * Test the translation are imported with fix old plural style. + */ + public function testCreatedLanguageTranslationWithOldPluralStyle() { + $this->importPoFile($this->getPoFileWithOldPluralStyle(), ['langcode' => 'ru']); + for ($i=0; $i < 6; $i++) { + $plural = \Drupal::translation()->formatPlural($i, '1 word', '@count words', [], ['langcode' => 'ru']); + $this->assertSame("word$i", $plural->render(), 'Import old "@count[number]" plural style.'); + } + } + + /** * Helper function: import a standalone .po file in a given language. * * @param string $contents @@ -640,4 +651,29 @@ public function getPoFileWithConfigDe() { EOF; } + /** + * Helper function that returns a .po file with old plural style. + */ + public function getPoFileWithOldPluralStyle() { + return <<< EOF +msgid "" +msgstr "" +"Project-Id-Version: Drupal 8\\n" +"MIME-Version: 1.0\\n" +"Content-Type: text/plain; charset=UTF-8\\n" +"Content-Transfer-Encoding: 8bit\\n" +"Plural-Forms: nplurals=5; plural=n;\\n" + +msgid "1 word" +msgid_plural "@count words" +msgstr[0] "@count[0] word0" +msgstr[1] "@count[1] word1" +msgstr[2] "@count[2] word2" +msgstr[3] "@count[3] word3" +msgstr[4] "@count[4] word4" +msgstr[5] "@count[5] word5" + +EOF; + } + }