Commit 77b9dbc1 authored by alexpott's avatar alexpott

Issue #2454829 by maxocub, eiriksm, rvilar, Gábor Hojtsy, penyaskito,...

Issue #2454829 by maxocub, eiriksm, rvilar, Gábor Hojtsy, penyaskito, tstoeckler, Jose Reyero: Configuration translation UI does not support plural sources/targets
parent 22d8e4b6
......@@ -56,6 +56,11 @@ label:
label: 'Label'
translatable: true
# String containing plural variants, separated by EXT.
plural_label:
type: label
label: 'Plural variants'
# Internal Drupal path
path:
type: string
......
......@@ -188,6 +188,7 @@ function config_translation_config_schema_info_alter(&$definitions) {
'text_format' => '\Drupal\config_translation\FormElement\TextFormat',
'mapping' => '\Drupal\config_translation\FormElement\ListElement',
'sequence' => '\Drupal\config_translation\FormElement\ListElement',
'plural_label' => '\Drupal\config_translation\FormElement\PluralVariants',
);
// Enhance the text and date type definitions with classes to generate proper
......
......@@ -91,7 +91,6 @@ 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 = '<span lang="' . $source_language->getId() . '">' . nl2br($source_config) . '</span>';
}
......@@ -162,7 +161,6 @@ 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 <span class="visually-hidden">(!source_language)</span>', array(
'!label' => $this->t($this->definition['label']),
......
<?php
/**
* @file
* Contains \Drupal\config_translation\FormElement\PluralVariants.
*/
namespace Drupal\config_translation\FormElement;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Config\Config;
use Drupal\Core\Language\LanguageInterface;
use Drupal\language\Config\LanguageConfigOverride;
/**
* Defines form elements for plurals in configuration translation.
*/
class PluralVariants extends FormElementBase {
/**
* {@inheritdoc}
*/
protected function getSourceElement(LanguageInterface $source_language, $source_config) {
$plurals = $this->getNumberOfPlurals($source_language->getId());
$values = explode(LOCALE_PLURAL_DELIMITER, $source_config);
$element = array(
'#type' => 'fieldset',
'#title' => SafeMarkup::format('@label <span class="visually-hidden">(@source_language)</span>', array(
'@label' => $this->t($this->definition->getLabel()),
'@source_language' => $source_language->getName(),
)),
'#tree' => TRUE,
);
for ($i = 0; $i < $plurals; $i++) {
$element[$i] = array(
'#type' => 'item',
// @todo Should use better labels https://www.drupal.org/node/2499639
'#title' => $i == 0 ? $this->t('Singular form') : $this->formatPlural($i, 'First plural form', '@count. plural form'),
'#markup' => SafeMarkup::format('<span lang="@langcode">@value</span>', array(
'@langcode' => $source_language->getId(),
'@value' => isset($values[$i]) ? $values[$i] : $this->t('(Empty)'),
)),
);
}
return $element;
}
/**
* {@inheritdoc}
*/
protected function getTranslationElement(LanguageInterface $translation_language, $source_config, $translation_config) {
$plurals = $this->getNumberOfPlurals($translation_language->getId());
$values = explode(LOCALE_PLURAL_DELIMITER, $translation_config);
$element = array(
'#type' => 'fieldset',
'#title' => SafeMarkup::format('@label <span class="visually-hidden">(@translation_language)</span>', array(
'@label' => $this->t($this->definition->getLabel()),
'@translation_language' => $translation_language->getName(),
)),
'#tree' => TRUE,
);
for ($i = 0; $i < $plurals; $i++) {
$element[$i] = array(
'#type' => 'textfield',
// @todo Should use better labels https://www.drupal.org/node/2499639
'#title' => $i == 0 ? $this->t('Singular form') : $this->formatPlural($i, 'First plural form', '@count. plural form'),
'#default_value' => isset($values[$i]) ? $values[$i] : '',
'#attributes' => array('lang' => $translation_language->getId()),
);
}
return $element;
}
/**
* {@inheritdoc}
*/
public function setConfig(Config $base_config, LanguageConfigOverride $config_translation, $config_values, $base_key = NULL) {
$config_values = implode(LOCALE_PLURAL_DELIMITER, $config_values);
parent::setConfig($base_config, $config_translation, $config_values, $base_key);
}
}
......@@ -89,6 +89,7 @@ protected function setUp() {
'administer themes',
'bypass node access',
'administer content types',
'translate interface',
]
);
// Create and login user.
......@@ -609,6 +610,96 @@ public function testViewsTranslationUI() {
$this->assertFieldByName('translation[config_names][views.view.frontpage][display][default][display_options][title]', $display_options_master . " FR");
}
/**
* Test the number of source elements for plural strings in config translation forms.
*/
public function testPluralConfigStringsSourceElements() {
$this->drupalLogin($this->adminUser);
// Languages to test, with various number of plural forms.
$languages = array(
'vi' => array('plurals' => 1, 'expected' => array(TRUE, FALSE, FALSE, FALSE)),
'fr' => array('plurals' => 2, 'expected' => array(TRUE, TRUE, FALSE, FALSE)),
'sl' => array('plurals' => 4, 'expected' => array(TRUE, TRUE, TRUE, TRUE)),
);
foreach ($languages as $langcode => $data) {
// Import a .po file to add a new language with a given number of plural forms
$name = tempnam('temporary://', $langcode . '_') . '.po';
file_put_contents($name, $this->getPoFile($data['plurals']));
$this->drupalPostForm('admin/config/regional/translate/import', array(
'langcode' => $langcode,
'files[file]' => $name,
), t('Import'));
// Change the config langcode of the 'files' view.
$config = \Drupal::service('config.factory')->getEditable('views.view.files');
$config->set('langcode', $langcode);
$config->save();
// Go to the translation page of the 'files' view.
$translation_url = 'admin/structure/views/view/files/translate/' . $langcode . '/add';
$this->drupalGet($translation_url);
// Check if the expected number of source elements are present.
foreach ($data['expected'] as $index => $expected) {
if ($expected) {
$this->assertRaw('edit-source-config-names-viewsviewfiles-display-default-display-options-fields-count-format-plural-string-' . $index);
}
else {
$this->assertNoRaw('edit-source-config-names-viewsviewfiles-display-default-display-options-fields-count-format-plural-string-' . $index);
}
}
}
}
/**
* Test translation of plural strings with multiple plural forms in config.
*/
public function testPluralConfigStrings() {
$this->drupalLogin($this->adminUser);
// First import a .po file with multiple plural forms.
// This will also automatically add the 'sl' language.
$name = tempnam('temporary://', "sl_") . '.po';
file_put_contents($name, $this->getPoFile(4));
$this->drupalPostForm('admin/config/regional/translate/import', array(
'langcode' => 'sl',
'files[file]' => $name,
), t('Import'));
// Translate the files view, as this one uses numeric formatters.
$description = 'Singular form';
$field_value = '1 place';
$field_value_plural = '@count places';
$translation_url = 'admin/structure/views/view/files/translate/sl/add';
$this->drupalGet($translation_url);
// Make sure original text is present on this page, in addition to 2 new
// empty fields.
$this->assertRaw($description);
$this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][0]', $field_value);
$this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][1]', $field_value_plural);
$this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][2]', '');
$this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][3]', '');
// Then make sure it also works.
$edit = [
'translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][0]' => $field_value . ' SL',
'translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][1]' => $field_value_plural . ' 1 SL',
'translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][2]' => $field_value_plural . ' 2 SL',
'translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][3]' => $field_value_plural . ' 3 SL',
];
$this->drupalPostForm($translation_url, $edit, t('Save translation'));
// Make sure the values have changed.
$this->drupalGet($translation_url);
$this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][0]', "$field_value SL");
$this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][1]', "$field_value_plural 1 SL");
$this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][2]', "$field_value_plural 2 SL");
$this->assertFieldByName('translation[config_names][views.view.files][display][default][display_options][fields][count][format_plural_string][3]', "$field_value_plural 3 SL");
}
/**
* Test translation storage in locale storage.
*/
......@@ -936,4 +1027,43 @@ protected function assertDisabledTextarea($id) {
)));
}
/**
* Helper function that returns a .po file with a given number of plural forms.
*/
public function getPoFile($plurals) {
$po_file = array();
$po_file[1] = <<< 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=1; plural=0;\\n"
EOF;
$po_file[2] = <<< 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=2; plural=(n>1);\\n"
EOF;
$po_file[4] = <<< 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=4; plural=(((n%100)==1)?(0):(((n%100)==2)?(1):((((n%100)==3)||((n%100)==4))?(2):3)));\\n"
EOF;
return $po_file[$plurals];
}
}
......@@ -123,6 +123,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
for ($i = 0; $i < $plurals; $i++) {
$form['strings'][$string->lid]['translations'][$i] = array(
'#type' => 'textarea',
// @todo Should use better labels https://www.drupal.org/node/2499639
'#title' => ($i == 0 ? $this->t('Singular form') : $this->formatPlural($i, 'First plural form', '@count. plural form')),
'#rows' => $rows,
'#default_value' => isset($translation_array[$i]) ? $translation_array[$i] : '',
......
......@@ -117,8 +117,8 @@ views.field.numeric:
type: boolean
label: 'Format plural'
format_plural_string:
type: label
label: 'Singular and one or more plurals'
type: plural_label
label: 'Plural variants'
prefix:
type: label
label: 'Prefix'
......
......@@ -102,6 +102,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
for ($i = 0; $i < $plurals; $i++) {
$form['format_plural_values'][$i] = array(
'#type' => 'textfield',
// @todo Should use better labels https://www.drupal.org/node/2499639
'#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.'),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment