diff --git a/core/core.services.yml b/core/core.services.yml index 589447d..28b7108 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -600,7 +600,7 @@ services: - { name: string_translator, priority: 30 } string_translation: class: Drupal\Core\StringTranslation\TranslationManager - arguments: ['@language_manager'] + arguments: ['@language_manager', '@state'] calls: - [initLanguageManager] tags: diff --git a/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php b/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php index ebb20e4..0946709 100644 --- a/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php +++ b/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php @@ -64,6 +64,17 @@ protected function formatPluralTranslated($count, $translated, array $args = arr } /** + * Returns number of plurals supported by a given language. + * + * See the + * \Drupal\Core\StringTranslation\TranslationInterface::getNumberOfPlurals() + * documentation for details. + */ + protected function getNumberOfPlurals($langcode = NULL) { + return $this->getStringTranslation()->getNumberOfPlurals($langcode); + } + + /** * Gets the string translation service. * * @return \Drupal\Core\StringTranslation\TranslationInterface diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php index 3e866bb..f505dd8 100644 --- a/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php @@ -120,4 +120,15 @@ public function formatPlural($count, $singular, $plural, array $args = array(), */ public function formatPluralTranslated($count, $translation, array $args = array(), array $options = array()); + /** + * Returns number of plurals supported by a given language. + * + * @param null $langcode + * (optional) The language code. If not provided, the current language + * will be used. + * @return int + * Number of plural variants supported by the given language. + */ + public function getNumberOfPlurals($langcode = NULL); + } diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php index edb391c..547bc96 100644 --- a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php @@ -9,6 +9,7 @@ use Drupal\Component\Utility\SafeMarkup; use Drupal\Core\Language\LanguageManagerInterface; +use Drupal\Core\State\StateInterface; use Drupal\Core\StringTranslation\Translator\TranslatorInterface; /** @@ -53,14 +54,24 @@ class TranslationManager implements TranslationInterface, TranslatorInterface { protected $defaultLangcode; /** + * The state service. + * + * @var \Drupal\Core\State\StateInterface + */ + protected $state; + + /** * Constructs a TranslationManager object. * - * @param \Drupal\Core\Language\LanguageManagerInterface + * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager * The language manager. + * @param \Drupal\Core\State\StateInterface $state + * (optional) The state service. */ - public function __construct(LanguageManagerInterface $language_manager) { + public function __construct(LanguageManagerInterface $language_manager, StateInterface $state = NULL) { $this->languageManager = $language_manager; $this->defaultLangcode = $language_manager->getDefaultLanguage()->getId(); + $this->state = $state; } /** @@ -229,4 +240,20 @@ public function reset() { } } + /** + * @inheritdoc. + */ + public function getNumberOfPlurals($langcode = NULL) { + // If the state service is not injected, we assume 2 plural variants are + // allowed. This may happen in the installer for simplicity. + if (isset($this->state)) { + $langcode = $langcode ?: $this->languageManager->getCurrentLanguage()->getId(); + $plural_formulas = $this->state->get('locale.translation.plurals') ?: array(); + if (isset($plural_formulas[$langcode]['plurals'])) { + return $plural_formulas[$langcode]['plurals']; + } + } + return 2; + } + } diff --git a/core/modules/config_translation/src/FormElement/FormElementBase.php b/core/modules/config_translation/src/FormElement/FormElementBase.php index 7db01e1..e13cc31 100644 --- a/core/modules/config_translation/src/FormElement/FormElementBase.php +++ b/core/modules/config_translation/src/FormElement/FormElementBase.php @@ -91,6 +91,7 @@ public function getTranslationBuild(LanguageInterface $source_language, Language * A render array for the source value. */ protected function getSourceElement(LanguageInterface $source_language, $source_config) { + // @todo Should support singular+plurals https://www.drupal.org/node/2454829 if ($source_config) { $value = '' . nl2br($source_config) . ''; } @@ -161,6 +162,7 @@ protected function getSourceElement(LanguageInterface $source_language, $source_ */ protected function getTranslationElement(LanguageInterface $translation_language, $source_config, $translation_config) { // Add basic properties that apply to all form elements. + // @todo Should support singular+plurals https://www.drupal.org/node/2454829 return array( '#title' => $this->t('!label (!source_language)', array( '!label' => $this->t($this->definition['label']), diff --git a/core/modules/file/config/optional/views.view.files.yml b/core/modules/file/config/optional/views.view.files.yml index 6783c1b..526d9fd 100644 --- a/core/modules/file/config/optional/views.view.files.yml +++ b/core/modules/file/config/optional/views.view.files.yml @@ -529,8 +529,7 @@ display: decimal: . separator: ',' format_plural: true - format_plural_singular: '1 place' - format_plural_plural: '@count places' + format_plural_string: "1 place\x03@count places" prefix: '' suffix: '' plugin_id: numeric @@ -952,8 +951,7 @@ display: decimal: . separator: ',' format_plural: false - format_plural_singular: '1' - format_plural_plural: '@count' + format_plural_string: "1\x03@count" prefix: '' suffix: '' plugin_id: numeric diff --git a/core/modules/forum/tests/modules/forum_test_views/test_views/views.view.test_forum_index.yml b/core/modules/forum/tests/modules/forum_test_views/test_views/views.view.test_forum_index.yml index 1f917f0..32a9306 100644 --- a/core/modules/forum/tests/modules/forum_test_views/test_views/views.view.test_forum_index.yml +++ b/core/modules/forum/tests/modules/forum_test_views/test_views/views.view.test_forum_index.yml @@ -141,8 +141,7 @@ display: decimal: . separator: ',' format_plural: false - format_plural_singular: '1' - format_plural_plural: '@count' + format_plural_string: "1\x03@count" prefix: '' suffix: '' plugin_id: numeric diff --git a/core/modules/statistics/tests/modules/statistics_test_views/test_views/views.view.test_statistics_integration.yml b/core/modules/statistics/tests/modules/statistics_test_views/test_views/views.view.test_statistics_integration.yml index 0b0e227..b8d3c4a 100644 --- a/core/modules/statistics/tests/modules/statistics_test_views/test_views/views.view.test_statistics_integration.yml +++ b/core/modules/statistics/tests/modules/statistics_test_views/test_views/views.view.test_statistics_integration.yml @@ -160,8 +160,7 @@ display: decimal: . separator: '' format_plural: false - format_plural_singular: '1' - format_plural_plural: '@count' + format_plural_string: "1\x03@count" prefix: '' suffix: '' plugin_id: numeric @@ -218,8 +217,7 @@ display: decimal: . separator: '' format_plural: false - format_plural_singular: '1' - format_plural_plural: '@count' + format_plural_string: "1\x03@count" prefix: '' suffix: '' plugin_id: numeric diff --git a/core/modules/views/config/schema/views.field.schema.yml b/core/modules/views/config/schema/views.field.schema.yml index 0d636ac..69365e0 100644 --- a/core/modules/views/config/schema/views.field.schema.yml +++ b/core/modules/views/config/schema/views.field.schema.yml @@ -116,12 +116,9 @@ views.field.numeric: format_plural: type: boolean label: 'Format plural' - format_plural_singular: + format_plural_string: type: label - label: 'Singular form' - format_plural_plural: - type: label - label: 'Plural form' + label: 'Singular and one or more plurals' prefix: type: label label: 'Prefix' diff --git a/core/modules/views/src/Plugin/views/field/NumericField.php b/core/modules/views/src/Plugin/views/field/NumericField.php index 5e2db03..3f895f7 100644 --- a/core/modules/views/src/Plugin/views/field/NumericField.php +++ b/core/modules/views/src/Plugin/views/field/NumericField.php @@ -34,8 +34,7 @@ protected function defineOptions() { $options['decimal'] = array('default' => '.'); $options['separator'] = array('default' => ','); $options['format_plural'] = array('default' => FALSE); - $options['format_plural_singular'] = array('default' => '1'); - $options['format_plural_plural'] = array('default' => '@count'); + $options['format_plural_string'] = array('default' => '1' . LOCALE_PLURAL_DELIMITER . '@count'); $options['prefix'] = array('default' => ''); $options['suffix'] = array('default' => ''); @@ -93,28 +92,55 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { '#description' => $this->t('If checked, special handling will be used for plurality.'), '#default_value' => $this->options['format_plural'], ); - $form['format_plural_singular'] = array( - '#type' => 'textfield', - '#title' => $this->t('Singular form'), - '#default_value' => $this->options['format_plural_singular'], - '#description' => $this->t('Text to use for the singular form.'), - '#states' => array( - 'visible' => array( - ':input[name="options[format_plural]"]' => array('checked' => TRUE), - ), - ), + $form['format_plural_string'] = array( + '#type' => 'value', + '#default_value' => $this->options['format_plural_string'], ); - $form['format_plural_plural'] = array( - '#type' => 'textfield', - '#title' => $this->t('Plural form'), - '#default_value' => $this->options['format_plural_plural'], - '#description' => $this->t('Text to use for the plural form, @count will be replaced with the value.'), - '#states' => array( - 'visible' => array( - ':input[name="options[format_plural]"]' => array('checked' => TRUE), + + // @todo Figure out how to pass in the language of the view. + $plural_array = explode(LOCALE_PLURAL_DELIMITER, $this->options['format_plural_string']); + $plurals = $this->getNumberOfPlurals(); + if ($plurals > 2) { + for ($i = 0; $i < $plurals; $i++) { + $form['format_plural_values'][$i] = array( + '#type' => 'textfield', + '#title' => ($i == 0 ? $this->t('Singular form') : $this->formatPlural($i, 'First plural form', '@count. plural form')), + '#default_value' => isset($plural_array[$i]) ? $plural_array[$i] : '', + '#description' => $this->t('Text to use for this variant, @count will be replaced with the value.'), + '#states' => array( + 'visible' => array( + ':input[name="options[format_plural]"]' => array('checked' => TRUE), + ), + ), + ); + } + } + else { + // Fallback for unknown number of plurals. + $form['format_plural_values'][0] = array( + '#type' => 'textfield', + '#title' => $this->t('Singular form'), + '#default_value' => $plural_array[0], + '#description' => $this->t('Text to use for the singular form.'), + '#states' => array( + 'visible' => array( + ':input[name="options[format_plural]"]' => array('checked' => TRUE), + ), ), - ), - ); + ); + $form['format_plural_values'][1] = array( + '#type' => 'textfield', + '#title' => $this->t('Plural form'), + '#default_value' => isset($plural_array[1]) ? $plural_array[1] : '', + '#description' => $this->t('Text to use for the plural form, @count will be replaced with the value.'), + '#states' => array( + 'visible' => array( + ':input[name="options[format_plural]"]' => array('checked' => TRUE), + ), + ), + ); + } + $form['prefix'] = array( '#type' => 'textfield', '#title' => $this->t('Prefix'), @@ -132,6 +158,18 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { } /** + * @inheritdoc + */ + public function submitOptionsForm(&$form, FormStateInterface $form_state) { + // Merge plural format options into one string and drop the individual + // option values. + $options = &$form_state->getValue('options'); + $options['format_plural_string'] = implode(LOCALE_PLURAL_DELIMITER, $options['format_plural_values']); + unset($options['format_plural_values']); + parent::submitOptionsForm($form, $form_state); + } + + /** * {@inheritdoc} */ public function render(ResultRow $values) { @@ -156,7 +194,7 @@ public function render(ResultRow $values) { // Should we format as a plural. if (!empty($this->options['format_plural'])) { - $value = $this->formatPlural($value, $this->options['format_plural_singular'], $this->options['format_plural_plural']); + $value = $this->formatPluralTranslated($value, $this->options['format_plural_string']); } return $this->sanitizeValue($this->options['prefix'], 'xss')