diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml index 3edb8057..7b658e0 100644 --- a/core/config/schema/core.data_types.schema.yml +++ b/core/config/schema/core.data_types.schema.yml @@ -650,12 +650,9 @@ field.field_settings.integer: max: type: integer label: 'Maximum' - prefix: + format_plural_string: type: label - label: 'Prefix' - suffix: - type: label - label: 'Suffix' + label: 'Plural formatted prefix/suffix' field.value.integer: type: mapping @@ -688,12 +685,9 @@ field.field_settings.decimal: max: type: float label: 'Maximum' - prefix: - type: label - label: 'Prefix' - suffix: + format_plural_string: type: label - label: 'Suffix' + label: 'Plural formatted prefix/suffix' field.value.decimal: type: mapping @@ -719,12 +713,9 @@ field.field_settings.float: max: type: float label: 'Maximum' - prefix: - type: label - label: 'Prefix' - suffix: + format_plural_string: type: label - label: 'Suffix' + label: 'Plural formatted prefix/suffix' field.value.float: type: mapping diff --git a/core/config/schema/core.entity.schema.yml b/core/config/schema/core.entity.schema.yml index 71b7ccd..984056f 100644 --- a/core/config/schema/core.entity.schema.yml +++ b/core/config/schema/core.entity.schema.yml @@ -202,6 +202,9 @@ field.widget.settings.number: placeholder: type: label label: 'Placeholder' + format_plural: + type: boolean + label: 'Whether or not to display prefix/suffix' field.widget.settings.checkbox: type: mapping @@ -292,9 +295,12 @@ field.formatter.settings.number_decimal: scale: type: integer label: 'Scale' - prefix_suffix: - type: boolean - label: 'Display prefix and suffix.' + format_plural: + type: string + label: 'Which prefix/suffix to display, if any' + format_plural_string: + type: label + label: 'Override for prefix/suffix' field.formatter.settings.number_integer: type: mapping @@ -303,9 +309,12 @@ field.formatter.settings.number_integer: thousand_separator: type: string label: 'Thousand marker' - prefix_suffix: - type: boolean - label: 'Display prefix and suffix.' + format_plural: + type: string + label: 'Which prefix/suffix to display, if any' + format_plural_string: + type: label + label: 'Override for prefix/suffix' field.formatter.settings.number_unformatted: type: mapping diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php index bee0144..9760f29 100644 --- a/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php +++ b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php @@ -141,6 +141,11 @@ public function getRenderer($field_name) { // Instantiate the widget object from the stored display properties. if (($configuration = $this->getComponent($field_name)) && isset($configuration['type']) && ($definition = $this->getFieldDefinition($field_name))) { + // Pass the language of the display configuration down to the widget, + // which otherwise doesn't have access to it because it is not a + // stand-alone config entity. It may be relevant for some operations, + // such as using plural formatting as a field prefix. + $configuration['settings']['_settings_langcode'] = $this->langcode; $widget = $this->pluginManager->getInstance(array( 'field_definition' => $definition, 'form_mode' => $this->originalMode, diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php b/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php index 86d4faa..f7d1f3c 100644 --- a/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php +++ b/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php @@ -197,8 +197,10 @@ public function getRenderer($field_name) { // Instantiate the formatter object from the stored display properties. if (($configuration = $this->getComponent($field_name)) && isset($configuration['type']) && ($definition = $this->getFieldDefinition($field_name))) { - // Record the language that the configuration was translated into, which - // is needed for plural formatting (for example). + // Pass the language of the display configuration down to the formatter, + // which otherwise doesn't have access to it because it is not a + // stand-alone config entity. It may be relevant for some operations, + // such as plural formatting. $configuration['settings']['_settings_langcode'] = $this->langcode; $formatter = $this->pluginManager->getInstance(array( 'field_definition' => $definition, diff --git a/core/lib/Drupal/Core/Entity/EntityDisplayBase.php b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php index b835327..5b374b8 100644 --- a/core/lib/Drupal/Core/Entity/EntityDisplayBase.php +++ b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php @@ -292,6 +292,11 @@ public function toArray() { if (!$definition->isDisplayConfigurable($this->displayContext)) { unset($properties['content'][$field_name]); unset($properties['hidden'][$field_name]); + // If _settings_langcode is in the settings, remove it. It should never + // be saved in the configuration. + if (isset($properties['content'][$field_name]['settings']['_settings_langcode'])) { + unset($properties['content'][$field_name]['settings']['_settings_langcode']); + } } } @@ -339,6 +344,12 @@ public function setComponent($name, array $options = array()) { // Ensure we always have an empty settings and array. $options += ['settings' => [], 'third_party_settings' => []]; + // If _settings_langcode is in the settings, remove it. It should never + // be saved in the configuration. + if (isset($options['settings']['_settings_langcode'])) { + unset($options['settings']['_settings_langcode']); + } + $this->content[$name] = $options; unset($this->hidden[$name]); unset($this->plugins[$name]); diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php index 267aa9d..12091df 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilder.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilder.php @@ -13,6 +13,7 @@ use Drupal\Core\Field\FieldItemInterface; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Language\LanguageManagerInterface; +use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Render\Element; use Drupal\Core\TypedData\TranslatableInterface; use Symfony\Component\DependencyInjection\ContainerInterface; diff --git a/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php b/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php index 2baa284..42f8248 100644 --- a/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityViewBuilderInterface.php @@ -118,9 +118,11 @@ public function resetCache(array $entities = NULL); * 'default_formatter' for the field type. The default formatter will * also be used if the requested formatter is not available. * - settings: (array) Settings specific to the formatter. Defaults to the - * formatter's default settings. If there is a '_settings_langcode' - * value, it will override the language used for formatting, which is - * normally the current interface language. + * formatter's default settings. A '_settings_langcode' entry should be + * present to indicate the language of the settings that are being + * provided (typically, the language of the configuration entity that + * contains the formatter, such as an entity view mode). If absent, the + * current interface language will be assumed. * - weight: (float) The weight to assign to the renderable element. * Defaults to 0. * diff --git a/core/lib/Drupal/Core/Field/FormatterPluginManager.php b/core/lib/Drupal/Core/Field/FormatterPluginManager.php index bf029c3..9136c13 100644 --- a/core/lib/Drupal/Core/Field/FormatterPluginManager.php +++ b/core/lib/Drupal/Core/Field/FormatterPluginManager.php @@ -73,7 +73,7 @@ public function createInstance($plugin_id, array $configuration = array()) { } /** - * Overrides PluginManagerBase::getInstance(). + * Creates a formatter instance with the provided options. * * @param array $options * An array with the following key/value pairs: @@ -92,9 +92,11 @@ public function createInstance($plugin_id, array $configuration = array()) { * also be used if the requested formatter is not available. * - settings: (array) Settings specific to the formatter. Each setting * defaults to the default value specified in the formatter definition. - * A _settings_langcode value will be added, giving the language code - * of the parent entity (entity view mode, view, etc. that the formatter - * is embedded in). + * A '_settings_langcode' entry should be present to indicate the + * language of the settings that are being provided (typically, the + * language of the configuration entity that contains the formatter, + * such as an entity view mode). If absent, the current interface + * language will be assumed. * - third_party_settings: (array) Settings provided by other extensions * through hook_field_formatter_third_party_settings_form(). * @@ -119,7 +121,7 @@ public function getInstance(array $options) { // - the formatter is not applicable to the field definition. $definition = $this->getDefinition($configuration['type'], FALSE); if (!isset($definition['class']) || !in_array($field_type, $definition['field_types']) || !$definition['class']::isApplicable($field_definition)) { - // Grab the default widget for the field type. + // Grab the default formatter for the field type. $field_type_definition = $this->fieldTypeManager->getDefinition($field_type); if (empty($field_type_definition['default_formatter'])) { return NULL; @@ -131,6 +133,7 @@ public function getInstance(array $options) { 'field_definition' => $field_definition, 'view_mode' => $options['view_mode'], ); + return $this->createInstance($plugin_id, $configuration); } diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/NumericFormatterBase.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/NumericFormatterBase.php index 29a37b7..6b3d81e 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/NumericFormatterBase.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/NumericFormatterBase.php @@ -41,7 +41,6 @@ public static function defaultSettings() { return array( 'thousand_separator' => '', - 'prefix_suffix' => TRUE, 'format_plural' => NumericFormatterBase::FORMAT_PLURAL_NONE, 'format_plural_string' => '', ) + parent::defaultSettings(); @@ -72,12 +71,16 @@ public function settingsForm(array $form, FormStateInterface $form_state) { '#title' => $this->t('Display prefix/suffix'), '#default_value' => $this->getSetting('format_plural'), '#options' => array( + NumericFormatterBase::FORMAT_PLURAL_NONE => $this->t('No prefix/suffix'), NumericFormatterBase::FORMAT_PLURAL_USE_FIELD_SETTING => $this->t('Use setting from the field settings'), NumericFormatterBase::FORMAT_PLURAL_USE_FORMATTER_SETTING => $this->t('Override the setting from the field settings'), - NumericFormatterBase::FORMAT_PLURAL_NONE => $this->t('No prefix/suffix'), ), ); + // @todo This field needs to have some kind of #states magic so that it + // only shows if the option on format_plural is + // NumericFormatterBase::FORMAT_PLURAL_USE_FORMATTER_SETTING. + // Need to do this before this patch is finalized! $elements['format_plural_values'] = array( '#type' => 'fieldset', '#title' => $this->t('Prefix/suffix override'), @@ -144,8 +147,11 @@ public function settingsSummary() { $summary = array(); $summary[] = $this->numberFormat(1234.1234567890); - if ($this->getSetting('format_plural') != NumericFormatterBase::FORMAT_PLURAL_NONE) { - $summary[] = $this->t('Display prefix/suffix.'); + if ($this->getSetting('format_plural') == NumericFormatterBase::FORMAT_PLURAL_USE_FIELD_SETTING) { + $summary[] = $this->t('Display prefix/suffix from the field settings.'); + } + elseif ($this->getSetting('format_plural') == NumericFormatterBase::FORMAT_PLURAL_USE_FORMATTER_SETTING) { + $summary[] = $this->t('Display overridden prefix/suffix.'); } return $summary; @@ -156,22 +162,22 @@ public function settingsSummary() { */ public function viewElements(FieldItemListInterface $items, $langcode) { $elements = array(); - $settings = $this->getFieldSettings(); + $field_settings = $this->getFieldSettings(); foreach ($items as $delta => $item) { $output = $this->numberFormat($item->value); // Account for prefix and suffix. - $plural_format = ''; + $format_string = ''; if ($this->getSetting('format_plural') == NumericFormatterBase::FORMAT_PLURAL_USE_FIELD_SETTING) { - $plural_format = $settings['format_plural_string']; + $format_string = $field_settings['format_plural_string']; } elseif ($this->getSetting('format_plural') == NumericFormatterBase::FORMAT_PLURAL_USE_FORMATTER_SETTING) { - $plural_format = $this->getSetting('format_plural_string'); + $format_string = $this->getSetting('format_plural_string'); } - if ($plural_format) { - $output = PluralTranslatableMarkup::createFromTranslatedString($item->value, $plural_format, ['@count' => $output], ['langcode' => $this->getSetting('_settings_langcode')]); + if ($format_string) { + $output = PluralTranslatableMarkup::createFromTranslatedString($item->value, $format_string, ['@count' => $output], ['langcode' => $this->getSetting('_settings_langcode')]); } // Output the raw value in a content attribute if the text of the HTML diff --git a/core/lib/Drupal/Core/Field/WidgetPluginManager.php b/core/lib/Drupal/Core/Field/WidgetPluginManager.php index 2bc41f1..510c685 100644 --- a/core/lib/Drupal/Core/Field/WidgetPluginManager.php +++ b/core/lib/Drupal/Core/Field/WidgetPluginManager.php @@ -55,7 +55,7 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac } /** - * Overrides PluginManagerBase::getInstance(). + * Creates a widget instance with the provided options. * * @param array $options * An array with the following key/value pairs: @@ -71,6 +71,11 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac * used if the requested widget is not available. * - settings: (array) Settings specific to the widget. Each setting * defaults to the default value specified in the widget definition. + * A '_settings_langcode' entry should be present to indicate the + * language of the settings that are being provided (typically, the + * language of the configuration entity that contains the widget, + * such as an entity form mode). If absent, the current interface + * language will be assumed. * - third_party_settings: (array) Settings provided by other extensions * through hook_field_formatter_third_party_settings_form(). * diff --git a/core/modules/field/src/Tests/Migrate/d6/MigrateFieldFormatterSettingsTest.php b/core/modules/field/src/Tests/Migrate/d6/MigrateFieldFormatterSettingsTest.php index 435c83c..d901142 100644 --- a/core/modules/field/src/Tests/Migrate/d6/MigrateFieldFormatterSettingsTest.php +++ b/core/modules/field/src/Tests/Migrate/d6/MigrateFieldFormatterSettingsTest.php @@ -75,6 +75,8 @@ public function testEntityDisplaySettings() { $expected['settings'] = array( 'thousand_separator' => ',', 'prefix_suffix' => TRUE, + 'format_plural' => 'none', + 'format_plural_string' => '', ); $component = $display->getComponent('field_test_two'); $this->assertIdentical($expected, $component); @@ -85,6 +87,8 @@ public function testEntityDisplaySettings() { 'decimal_separator' => '.', 'thousand_separator' => ',', 'prefix_suffix' => TRUE, + 'format_plural' => 'none', + 'format_plural_string' => '', ); $component = $display->getComponent('field_test_three'); $this->assertIdentical($expected, $component); diff --git a/core/modules/field/src/Tests/Migrate/d6/MigrateFieldInstanceTest.php b/core/modules/field/src/Tests/Migrate/d6/MigrateFieldInstanceTest.php index afc6703..f98dc8a 100644 --- a/core/modules/field/src/Tests/Migrate/d6/MigrateFieldInstanceTest.php +++ b/core/modules/field/src/Tests/Migrate/d6/MigrateFieldInstanceTest.php @@ -45,8 +45,7 @@ public function testFieldInstanceSettings() { $expected = array( 'min' => 10, 'max' => 100, - 'prefix' => 'pref', - 'suffix' => 'suf', + 'format_plural_string' => 'pref@count suf', 'unsigned' => FALSE, 'size' => 'normal', ); @@ -57,8 +56,7 @@ public function testFieldInstanceSettings() { $expected = array( 'min' => 100.0, 'max' => 200.0, - 'prefix' => 'id-', - 'suffix' => '', + 'format_plural_string' => 'id-@count'; ); $this->assertIdentical($expected, $field->getSettings()); diff --git a/core/modules/field/src/Tests/Migrate/d6/MigrateFieldWidgetSettingsTest.php b/core/modules/field/src/Tests/Migrate/d6/MigrateFieldWidgetSettingsTest.php index 891eb69..4cfe61c 100644 --- a/core/modules/field/src/Tests/Migrate/d6/MigrateFieldWidgetSettingsTest.php +++ b/core/modules/field/src/Tests/Migrate/d6/MigrateFieldWidgetSettingsTest.php @@ -36,7 +36,7 @@ public function testWidgetSettings() { // Text field. $component = $form_display->getComponent('field_test'); $expected = array('weight' => 1, 'type' => 'text_textfield'); - $expected['settings'] = array('size' => 60, 'placeholder' => ''); + $expected['settings'] = array('size' => 60, 'placeholder' => '', 'format_plural' => TRUE); $expected['third_party_settings'] = array(); $this->assertIdentical($expected, $component, 'Text field settings are correct.'); @@ -44,7 +44,7 @@ public function testWidgetSettings() { $component = $form_display->getComponent('field_test_two'); $expected['type'] = 'number'; $expected['weight'] = 1; - $expected['settings'] = array('placeholder' => ''); + $expected['settings'] = array('placeholder' => '', 'format_plural' => TRUE); $this->assertIdentical($expected, $component); // Float field. @@ -82,7 +82,7 @@ public function testWidgetSettings() { $component = $form_display->getComponent('field_test_phone'); $expected['type'] = 'telephone_default'; $expected['weight'] = 13; - $expected['settings'] = array('placeholder' => ''); + $expected['settings'] = array('placeholder' => '', 'format_plural' => TRUE); $this->assertIdentical($expected, $component); // Date fields. diff --git a/core/modules/field_ui/src/Tests/EntityDisplayTest.php b/core/modules/field_ui/src/Tests/EntityDisplayTest.php index 7c7a48b..91a526f 100644 --- a/core/modules/field_ui/src/Tests/EntityDisplayTest.php +++ b/core/modules/field_ui/src/Tests/EntityDisplayTest.php @@ -214,6 +214,7 @@ public function testFieldComponent() { 'type' => $default_formatter, 'settings' => $formatter_settings, 'third_party_settings' => array(), + '_settings_langcode' => 'en', ); $this->assertEqual($display->getComponent($field_name), $expected);