Problem/Motivation

We have a multilingual site (German - default, English - second language) and enabled config entity translations for webform entities.
The site has a webform which was originally created in English and has a German translation.

English (source) element values:

first_name:
  '#title': 'First name'
  '#type': textfield
  '#required': true
last_name:
  '#title': 'Last name'
  '#type': textfield
  '#required': true

German translation:

first_name:
  '#title': Vorname
last_name:
  '#title': Nachname

Our site was on webform-beta15 version and we wanted to webform-beta17 version.

After an update to webform-beta17, our webform has disappeared from the page.

After some investigation, we realized that English element (YAML) values were replaced with a German translation and thus lost their field type identifiers which resulted in no display.

This is our understanding of what happened:

  1. composer update drupal/webform
  2. drush updb triggered webform_update_8072() which loaded a webform entity. Because the site's default language is German the webform entity replaced elements property with a german translation values which contains no field type keys. webform_update_8072() calls save() on a webform entity which replaced the original elements values.
  3. Webform failed to display a webform as there is no field #type identifiers in the source elements property

Notes

Below are the quickest step to reproduce this bug

  • Install Webform in English
  • Enable Configuration Translation (/admin/modules)
  • Add 'Spanish' language (/admin/config/regional/language/add)
  • Translate at least one element for the default Contact webform into Spanish (/admin/structure/webform/manage/contact/translate/es/add)
  • Switch the site's default language to Spanish (/admin/config/regional/language)
  • Execute this Drush command drush php-eval '\Drupal\webform\Entity\Webform::load('contact')->save()';
  • Confirm that the Contact webform element's are replaced with the Spanish translation (/es/admin/structure/webform/manage/contact/source)

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

mbovan created an issue. See original summary.

jrockowitz’s picture

Priority: Normal » Critical
jrockowitz’s picture

Here are my steps to reproduce the issue...

  • Setup a clean install with 'English' as the default language.
  • Enable the webform_test_translate.module
  • Switch the site from 'English' to 'Spanish'
  • Confirm that the Test: Translation webform (/form/test-translation) still works.
  • Run drush ev "module_load_install('webform'); webform_update_8072();"
  • Confirm that the Test: Translation webform (/form/test-translation) is now completely broken.

  • jrockowitz committed f50f295 on 2913548-translation-replaced
    Issue #2913548: Source element values are replaced with translated...
jrockowitz’s picture

This seems like a core issue because I can reproduce the issue with any config entity.

Here are my steps...

  • Setup new install in English
  • Enable Configuration Translation (/admin/modules)
  • Add 'Spanish' (/admin/config/regional/language)
  • Translate the 'Article 'content type to Spanish (/admin/structure/types/manage/article/translate)
  • Confirm Article in 'English' (/en/admin/structure/types/manage/article)
  • Confirm Article in 'Spanish' (/admin/structure/types/manage/article/translate/es/edit)
  • Change Default language to 'Spanish' (/admin/config/regional/language)
  • Execute drush command to resave 'Article' content type. `drush ev "\Drupal\node\Entity\NodeType::load('article')->save();""`
  • Confirm Article title is now 'Spanish' (/admin/structure/types/manage/article/translate)

The issue is that when a config is loaded, the site's current/default language load the translated strings, and then saving the config will replace the original values with the translated strings.

References

  • jrockowitz committed 6ad3a50 on 2913548-translation-replaced
    Issue #2913548: Source element values are replaced with translated...
jrockowitz’s picture

Status: Active » Needs review
FileSize
6.55 KB

The attached patch is EXPERIMENTAL.

During the update hook, it switches the configuration management system's language to "not specified" (und) which forces the default webform config to be loaded and saved.

Please test it and see if it fixes the issue. If this does fix the issue, there is still some work that needs to be done.

BTW, if a Webform's config is about to overwritten by a translation, a fatal exception should be thrown.

I am almost certain that this entire issue is triggered when the default language of a site is changed.

mbovan’s picture

I can confirm that patch #7 fixes the update problem.

However, it makes de/admin/structure/webform/manage/webform_id/source unsavable in case it was triggered in a non-source language:
Exception: Unable to save webform because the original translation would overwritten in Drupal\webform\Entity\Webform->preSave() (line 1733 of modules/contrib/webform/src/Entity/Webform.php).

  • jrockowitz committed 6d24dd1 on 2913548-translation-replaced
    Issue #2913548: Source element values are replaced with translated...
jrockowitz’s picture

Okay, the attached patch is detecting if the webform can be saved.

This is a MAJOR issue in core which is just starting to be realized/documented in #2910353: Prevent saving config entities when configuration overrides are applied.

@mbovan I think this issue is going to continually impact your website and any config entities that are in English. What I think is going to keep happening on your site is any English config entity that is saved via an update hook or CLI will have it English translated strings replace with German. You might want to consider reviewing all your exported config and maybe manually converting any English config into German.

mbovan’s picture

@jrockowitz I updated #2910353: Prevent saving config entities when configuration overrides are applied based on your core findings.

@mbovan I think this issue is going to continually impact your website and any config entities that are in English. What I think is going to keep happening on your site is any English config entity that is saved via an update hook or CLI will have it English translated strings replace with German. You might want to consider reviewing all your exported config and maybe manually converting any English config into German.

I agree it could be a temporary solution. The problem is that if you use the admin panel in a language other than site's default language (like I do) and create a config entity, the entity will use that language as a source's entity language. Tested it with webforms and content types for now.

jrockowitz’s picture

@mbovan Depending on the project's size/budget, I would consider going directly into the 'config' table and just fixing this issue, which is all your config should be using the site's default language. This would be incredible amount of work and worth waiting to see when people say about #2910353: Prevent saving config entities when configuration overrides are applied

My patch tries to make sure that Webform::save() is only executed for the source language, does it solve the original problem?

mErilainen’s picture

This doesn't sound very robust solution.
If I understood correctly this would mean that:
- I would need to manually change the language of the webform configuration from Finnish to English -> field labels etc. would have to be changed into English too and only after that the Finnish translations would have to be added again -> lots of work if there are lots of webforms.
- Content producers couldn't create webforms first in site's default language and later translate them into other languages when the need rises?

What is the recommendation regarding translating webforms? I suppose everything works if each language has a separate webform, but these are tedious to add and maintain for big forms with lots of fields.

jrockowitz’s picture

@mErilainen Yes, my recommendation is that all webforms are created in the default language. For now, I would never change a website's default language after it is installed.

If I had a site where the default language was changed post installation I would write a custom update hook that loops through all the existing configuration and fixes the issue. This is not a solution but a workaround until the core issue is fixed.

mErilainen’s picture

I'm not trying to change the site default language. But this means content editors cannot add forms only in other language than default. There might be forms which are not needed in English. Or if they do, they should never translate them.

jrockowitz’s picture

Maybe we need to apply the patch and wait to see how this issue is resolved in core.

@mErilainen Does the patch fix the issue for you?

mErilainen’s picture

I have not tried it, first I need to manually re-create all forms in English and add the translations in other languages.

jrockowitz’s picture

Status: Needs review » Postponed (maintainer needs more info)

  • jrockowitz committed 1be0017 on 2913548-translation-replaced
    Issue #2913548 by jrockowitz: Source element values are replaced with...
jrockowitz’s picture

Status: Postponed (maintainer needs more info) » Needs review
FileSize
12.72 KB

I rerolled the patch to only address this immediate issue #2935950: Update "webform_update_8097" destroys all my webforms....

The work-around/solution is to force all webform update hooks that use Webform::load to include _webform_update_set_config_language_not_specified(); which prevent the translation from overwriting the original.

Below is an example from the patch which also includes _webform_update_set_config_language_original(); at the end of the hook.

function _webform_update_webform_handler_class_settings($handler_class = NULL) {
  _webform_update_set_config_language_not_specified();

  /** @var \Drupal\webform\WebformInterface[] $webforms */
  $webforms = Webform::loadMultiple();
  foreach ($webforms as $webform) {
    $has_handler = FALSE;
    $handlers = $webform->getHandlers();
    foreach ($handlers as $handler) {
      if (empty($handler_class) || $handler instanceof $handler_class) {
        $has_handler = TRUE;
        $configuration = $handler->getConfiguration();

        $settings = $handler->defaultConfiguration();
        foreach ($configuration['settings'] as $settings_key => $setting_value) {
          $settings[$settings_key] = $setting_value;
        }
        $configuration['settings'] = $settings;
        $handler->setConfiguration($configuration);
      }
    }
    if ($has_handler) {
      $webform->save();
    }
  }

  _webform_update_set_config_language_original();
}

Status: Needs review » Needs work

The last submitted patch, 20: 2913548-18.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

  • jrockowitz committed ed72277 on 2913548-translation-replaced
    Issue #2913548 by jrockowitz: Source element values are replaced with...
jrockowitz’s picture

Status: Needs work » Needs review
FileSize
0 bytes

Status: Needs review » Needs work

The last submitted patch, 23: 2913548-23.patch, failed testing. View results

jrockowitz’s picture

Status: Needs work » Needs review
FileSize
12.59 KB

I need to take a day off.

Berdir’s picture

@jrockowitz: Your patch only disables the language overrides. If there are settings.php or any other override (e.g. from domain module) then it could still cause a problem.

I have been working on the core issue, would be great if you could test those patches and check if they work for webform, should not require any custom changes anymore with the current state of the patch. but note that it will currently only work with update.php, not with drush.

jrockowitz’s picture

For everyone following this ticket, below is the patch that needs to be tested.

https://www.drupal.org/project/drupal/issues/2910353#comment-12422438

@berdir I will run through my test script from #5

jrockowitz’s picture

Status: Needs review » Postponed

Marking as postponed until the core issue has been addressed.

Ralf Eisler’s picture

The issue is that when a config is loaded, the site's current/default language load the translated strings, and then saving the config will replace the original values with the translated strings.

I run in this issue with a website, which is now translated in 10 languages.
Considering that the core-issue https://www.drupal.org/project/drupal/issues/2910353#comment-12422438 is not solved yet, would it be worth the wait until it is solved? An other but combersome option would be to have separate webforms for each language.

About the issue
I made regular updates of Webforms in the past; I even had to change the default language of the site, and I yet never had issues with forms.

Original setup
Construction of the website in German (default) and English as second language.

Several updates
No issues

Change of the default language of the site
No issues.

Update and addtion of a third language
Core: 8.4.3 to 8.4.6
Webform: 8.x-5.0-beta25 to 8.x-5.0-rc7

Original language of the webforms: German
1st translation of the webforms: English
2nd translation the webforms: Russian

Problem #1:
-- After the update and the addition of the third language the forms on the website have disappeared.
Problem #2:
–– Under /admin/structure/webform/manage/my_form/source the YAML-source is correct (in German)
–– Under /admin/structure/webform/manage/my_form some elements are randomly translated to English and some stay German

dubcanada’s picture

Not sure if related but I am having a problem with if I update my English version of the webform it overrides the other languages?

So if I have English and French enabled on my site.

If I update English it updates it globally (changing a label from X to Y will change it from X to Y on English and French). If I update the labels on French only it doesn't not change it on English.

jrockowitz’s picture

@dubcanada If English is the webform's source language English label changes for untranslated labels will appear on all translations.

It sounds like you are saying changes to the English source labels is overwriting the translation's labels

parijke’s picture

I have a site in two languages (dutch default) and english. For some reason, I my webforms are default English (original), and I have to translate them into dutch.

Does this issue effect this situation as well? If so, how can I manage to protect the forms from being deleted. Applying patch #25??

BTW I am on rc21

jrockowitz’s picture

I have not tested my patch from #25 in a while.

I recommend testing and reviewing the patches in #2910353: Prevent saving config entities when configuration overrides are applied which are addressing the larger issue in core.

BTW, I have specifically started writing the Webform module's update hooks in a way to avoid this issue. As long as you test your translated webforms after updating the webform module you should be okay.

hudri’s picture

Is there any news or workarounds on this issue? I've a dozen smaller, but multi-lingual projects with 1-3 webforms each, locked at 5.0.0-rcXX in Composer, because the update would destroy their translation. So far this is not yet a problem, but I'm afraid of the day when a security advisory might be published.

jrockowitz’s picture

FileSize
1.73 KB

I want to emphasize that this issue is related to someone changing their website's default language after creating a webform.

The overwriting of a webform's data occurs during a Webform::save(). After this issue was discovered, I started to avoid calling Webform::save() in update hooks.

The attached patch comments out any update hooks that calls Webform::save() and you might be able to use it to upgrade to the latest release.

Another approach is we can try to fix the broken webform configuration. I am guessing we can swap the langcodes and labels via a drush command.

hudri’s picture

Hm, thats strange, because I'm having this issue on all my sites, and all sites start with german as default, and english as secondary. I also checked for the correct langcode in /config/sync/webform.webform.NAME.yml

It might be a side-effect of the initial cross-site config import with Drupal console's skip-validate-site-uuid then.

hudri’s picture

One more question: My own "de" contact form uses the same machine name "contact" as the default example, which has "en" as default. Can this cause issues during updating?

jrockowitz’s picture

Issue summary: View changes

I don't know the answer to #37.

I just updated the issue summary with steps on how to quickly reproduce this issue.

  • jrockowitz committed 2d400b8 on 2913548-translation-replaced
    Issue #2913548 by jrockowitz: Source element values are replaced with...
Manuel Garcia’s picture

Landed here after a few days of debugging a related issue caused by this.

We're running webform 8.x-5.0-rc6 , and we are seeing this issue. I assume the latest stable release would also see this issue.

Has anyone been able to re-mediate the situation? Any workarounds?

jrockowitz’s picture

The best workaround which the Webform module is currently using for update hook is not to use Webform::load($id) and Webform::save() and using manipulate a webform's configuration.

For example, instead of...

  /** @var \Drupal\webform\WebformInterface $webform */
  $webform = Webform::load('contact');
  $webform->set('title', 'My Contact Form');
  $webform->save();

...use....

  $config_factory = \Drupal::configFactory();
  $webform_config = $config_factory->getEditable('webform.webform.contact');
  $webform_config->set('title', 'My Contact Form');
  $webform_config->save();
dspachos’s picture

@jrockowitz Unfortunately, this workaround doesn't work with setThirdPartySetting (I'm working on a solution, will update as soon as I have results)

seanB’s picture

FileSize
1.13 KB

The attached patch seems to solve (at least part) of the issue for us. It's probably not a long-term solution, so just uploading this in case it helps anyone.