Hiding non translatable fields with custom form displays not working

Created on 17 October 2024, 2 months ago

Problem/Motivation

The feature "Hide non translatable fields on translation forms" isn't working as expected when using custom form display modes.

Steps to reproduce

  • Create a new test content type
  • Add some fields
  • Create a new test form display mode
  • Create a simple module with a route, controller and a service. The service has to use the `entityFormBuilder::getForm` method to build the form and return it to the controller. You can use it something like this $this->entityFormBuilder->getForm($entity, 'user_form'); where 'user_form' is the id of your custom form display mode
  • Render your form in a template
  • Go to the content translation settings (/admin/config/regional/content-language) and disable some fields
  • Check the 'Hide non translatable fields on translation forms'.
  • Nothing happens in your form. The fields aren't hidden when you see your form in another lang than the original
  • Replace 'user_form' with 'default' when you build the form and you'll see that it works perfectly

Expected behaviour

The method EntityFormBuilder::getForm($entity, 'user_form') should take in consideration the content language and translation settings and hide the fields.

More information

  • 10.3.3
  • 8.1.24
  • Chromium (Arc latest)
🐛 Bug report
Status

Active

Version

10.3

Component

content_translation.module

Created by

🇨🇭Switzerland zilloww

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @zilloww
  • First commit to issue fork.
  • 🇮🇳India nmudgal

    I think it's better suited as a custom solution and not something that should go into core.

    Firstly, this kind of change introduces a lot of complexity. Core has to handle a wide variety of use cases, and enforcing this behavior across all entity forms and translations might create unintended side effects. For some workflows, users may actually need those non-translatable fields visible even during translation.

    There are also performance concerns. Iterating through every field in a form to determine if it should be displayed or hidden based on translation settings adds overhead, particularly on complex forms with many fields. Making this a default behavior could negatively impact sites with complex content models or custom workflows that require all fields during translation.

    Finally, Drupal core has to maintain flexibility, and this solution might limit that for users relying on more nuanced control. It could lead to breaking existing sites where those fields are expected to be available, potentially causing validation or data handling issues.

    Example Code (Basically overriding core EntityFormBuilder in a custom module):

     public function getForm(EntityInterface $entity, $operation = 'default', array $form_state_additions = []) {
        $form = parent::getForm($entity, $operation, $form_state_additions);
      
        // Check if translation settings are enabled for the entity.
        // This allows us to manage multilingual content appropriately.
        if (\Drupal::service('content_translation.manager')->isEnabled($entity->getEntityTypeId(), $entity->bundle())) {
            $current_language = \Drupal::languageManager()->getCurrentLanguage();
      
            // Check if the entity has a translation for the current language.
            if ($entity->hasTranslation($current_language->getId())) {
                // Load the translated entity.
                // This allows us to modify the entity in the user's preferred language.
                $translated_entity = $entity->getTranslation($current_language->getId());
      
                // Get all translatable fields.
                // We need to differentiate translatable from non-translatable fields.
                $translatable_fields = array_filter($entity->getFieldDefinitions(), function ($field_definition) {
                    return $field_definition->isTranslatable();
                });
      
                // This ensures the form only displays fields relevant to the current translation.
                foreach ($form as $field_name => &$field) {
                    // Check if the field is defined in the entity and is non-translatable.
                    if (isset($entity->getFieldDefinitions()[$field_name]) && !isset($translatable_fields[$field_name])) {
                        $field['#access'] = FALSE;
                    }
                }
            }
        }
      
        return $form;
    }
    
    
Production build 0.71.5 2024