diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php index f455a9c..89df04d 100644 --- a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php @@ -175,10 +175,6 @@ public function formatPluralTranslated($count, $translation, array $args = array $args['@count'] = $count; $translated_array = explode(LOCALE_PLURAL_DELIMITER, $translation); - if ($count == 1) { - return String::format($translated_array[0], $args); - } - // Get the plural index through the gettext formula. // @todo implement static variable to minimize function_exists() usage. $index = (function_exists('locale_get_plural')) ? locale_get_plural($count, isset($options['langcode']) ? $options['langcode'] : NULL) : -1; @@ -193,9 +189,9 @@ public function formatPluralTranslated($count, $translation, array $args = array } else { // If the index cannot be computed or there's no translation, use - // the second plural form as a fallback (which allows for most flexibility - // with the replaceable @count value). - $return = $translated_array[1]; + // the most common rules of using the first item for 1 and the second + // item for all other numbers. + $return = $translated_array[(int)($count != 1)]; } } diff --git a/core/modules/locale/src/Tests/LocalePluralFormatTest.php b/core/modules/locale/src/Tests/LocalePluralFormatTest.php index e6b51f1..8dd85ba 100644 --- a/core/modules/locale/src/Tests/LocalePluralFormatTest.php +++ b/core/modules/locale/src/Tests/LocalePluralFormatTest.php @@ -131,6 +131,7 @@ public function testGetPluralFormat() { $expected_plural_index = ($count == 1) ? 0 : $expected_plural_index; $expected_plural_string = str_replace('@count', $count, $plural_strings[$langcode][$expected_plural_index]); $this->assertIdentical(\Drupal::translation()->formatPlural($count, '1 hour', '@count hours', array(), array('langcode' => $langcode)), $expected_plural_string, 'Plural translation of 1 hours / @count hours for count ' . $count . ' in ' . $langcode . ' is ' . $expected_plural_string); + $this->assertIdentical(\Drupal::translation()->formatPluralTranslated($count, \Drupal::translation()->translate('1 hour' . LOCALE_PLURAL_DELIMITER . '@count hours', array(), array('langcode' => $langcode)), array(), array('langcode' => $langcode)), $expected_plural_string, 'Translated plural lookup of 1 hours / @count hours for count ' . $count . ' in ' . $langcode . ' is ' . $expected_plural_string); } } } diff --git a/core/modules/views/src/Tests/Plugin/NumericFormatPluralTest.php b/core/modules/views/src/Tests/Plugin/NumericFormatPluralTest.php new file mode 100644 index 0000000..705279a --- /dev/null +++ b/core/modules/views/src/Tests/Plugin/NumericFormatPluralTest.php @@ -0,0 +1,158 @@ +web_user = $this->drupalCreateUser(array('administer views', 'administer languages')); + $this->drupalLogin($this->web_user); + } + + /** + * Test plural formatting setting on a numeric views handler. + */ + function testNumericFormatPlural() { + // Create a file. + $file = $this->createFile(); + + // Assert that the starting configuration is correct. + $config = $this->config('views.view.numeric_test'); + $field_config_prefix = 'display.default.display_options.fields.count.'; + $this->assertEqual($config->get($field_config_prefix . 'format_plural'), TRUE); + $this->assertEqual($config->get($field_config_prefix . 'format_plural_string'), '1' . LOCALE_PLURAL_DELIMITER . '@count'); + + // Assert that the value is displayed. + $this->drupalGet('numeric-test'); + $this->assertRaw('0'); + + // Assert that the user interface has controls to change it. + $this->drupalGet('admin/structure/views/nojs/handler/numeric_test/page_1/field/count'); + $this->assertFieldByName('options[format_plural_values][0]', '1'); + $this->assertFieldByName('options[format_plural_values][1]', '@count'); + + // Assert that changing the settings will change configuration properly. + $edit = ['options[format_plural_values][0]' => '1 time', 'options[format_plural_values][1]' => '@count times']; + $this->drupalPostForm(NULL, $edit, t('Apply')); + $this->drupalPostForm(NULL, array(), t('Save')); + + $config = $this->config('views.view.numeric_test'); + $field_config_prefix = 'display.default.display_options.fields.count.'; + $this->assertEqual($config->get($field_config_prefix . 'format_plural'), TRUE); + $this->assertEqual($config->get($field_config_prefix . 'format_plural_string'), '1 time' . LOCALE_PLURAL_DELIMITER . '@count times'); + + // Assert that the value is displayed with some sample values. + $numbers = [0, 1, 2, 3, 4, 42]; + foreach ($numbers as $i => $number) { + \Drupal::service('file.usage')->add($file, 'views_ui', 'dummy', $i, $number); + } + $this->drupalGet('numeric-test'); + foreach ($numbers as $i => $number) { + $this->assertRaw('' . $number . ($number == 1 ? ' time' : ' times') . ''); + } + + // Add Slovenian and set its plural formula to test multiple plural forms. + $edit = ['predefined_langcode' => 'sl']; + $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language')); + $formula = 'nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0);'; + $header = new PoHeader(); + list($nplurals, $formula) = $header->parsePluralForms($formula); + debug($formula); + \Drupal::state()->set('locale.translation.plurals', ['sl' => ['plurals' => $nplurals, 'formula' => $formula]]); + + // @todo change the language of the view here once the handler considers that + + // Assert that the user interface has controls with more inputs now. + $this->drupalGet('sl/admin/structure/views/nojs/handler/numeric_test/page_1/field/count'); + $this->assertFieldByName('options[format_plural_values][0]', '1 time'); + $this->assertFieldByName('options[format_plural_values][1]', '@count times'); + $this->assertFieldByName('options[format_plural_values][2]', ''); + $this->assertFieldByName('options[format_plural_values][3]', ''); + + // Assert that changing the settings will change configuration properly. + $edit = [ + 'options[format_plural_values][0]' => '@count time0', + 'options[format_plural_values][1]' => '@count time1', + 'options[format_plural_values][2]' => '@count time2', + 'options[format_plural_values][3]' => '@count time3', + ]; + $this->drupalPostForm(NULL, $edit, t('Apply')); + $this->drupalPostForm(NULL, array(), t('Save')); + $config = $this->config('views.view.numeric_test'); + $field_config_prefix = 'display.default.display_options.fields.count.'; + $this->assertEqual($config->get($field_config_prefix . 'format_plural'), TRUE); + $this->assertEqual($config->get($field_config_prefix . 'format_plural_string'), implode(LOCALE_PLURAL_DELIMITER, array_values($edit))); + + // The view should now use the new plural configuration. + $this->drupalGet('sl/numeric-test'); + $this->assertRaw('0 time0'); + $this->assertRaw('1 time1'); + $this->assertRaw('2 time2'); + $this->assertRaw('3 time3'); + $this->assertRaw('4 time3'); + $this->assertRaw('42 time0'); + } + + /** + * Creates and saves a test file. + * + * @return \Drupal\Core\Entity\EntityInterface + * A file entity. + */ + protected function createFile() { + // Create a new file entity. + $file = entity_create('file', array( + 'uid' => 1, + 'filename' => 'druplicon.txt', + 'uri' => 'public://druplicon.txt', + 'filemime' => 'text/plain', + 'created' => 1, + 'changed' => 1, + 'status' => FILE_STATUS_PERMANENT, + )); + file_put_contents($file->getFileUri(), 'hello world'); + + // Save it, inserting a new record. + $file->save(); + + return $file; + } +} diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.numeric_test.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.numeric_test.yml new file mode 100644 index 0000000..e8e99ad --- /dev/null +++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.numeric_test.yml @@ -0,0 +1,189 @@ +uuid: 6f602122-2918-44c7-8b05-5d6c1e93e6ac +langcode: en +status: true +dependencies: + module: + - file + - user +id: numeric_test +label: 'Numeric test' +module: views +description: '' +tag: '' +base_table: file_managed +base_field: fid +core: 8.x +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: perm + options: + perm: 'administer views' + cache: + type: none + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + replica: false + query_comment: '' + query_tags: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: full + options: + items_per_page: 10 + offset: 0 + id: 0 + total_pages: null + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + tags: + previous: '‹ previous' + next: 'next ›' + first: '« first' + last: 'last »' + quantity: 9 + style: + type: default + row: + type: fields + fields: + filename: + id: filename + table: file_managed + field: filename + entity_type: file + entity_field: filename + label: '' + alter: + alter_text: false + make_link: false + absolute: false + trim: false + word_boundary: false + ellipsis: false + strip_tags: false + html: false + hide_empty: false + empty_zero: false + link_to_file: true + plugin_id: file + relationship: none + group_type: group + admin_label: '' + exclude: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_alter_empty: true + count: + id: count + table: file_usage + field: count + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + set_precision: false + precision: 0 + decimal: . + separator: ',' + format_plural: true + format_plural_string: "1\x03@count" + prefix: '' + suffix: '' + plugin_id: numeric + filters: { } + sorts: { } + title: 'Numeric test' + header: { } + footer: { } + empty: { } + relationships: { } + arguments: { } + display_extenders: { } + cache_metadata: + contexts: + - language + cacheable: false + page_1: + display_plugin: page + id: page_1 + display_title: Page + position: 1 + display_options: + display_extenders: { } + path: numeric-test + cache_metadata: + contexts: + - language + cacheable: false