My use case for this module is to provide enough demo content with an installation profile to make the "unboxing experience" of the distribution pleasant. The default content is kind of english but it's really just there to look pretty: http://glazed-demo.sooperthemes.com/news/500-growth-lorem-ipsum

If a user select a language other than english in the Drupal installer the demo content import will stop the installation process with this error:

InvalidArgumentException: Invalid translation language (fr) specified. in Drupal\Core\Entity\ContentEntityBase->addTranslation()

It's the same error as in https://www.drupal.org/node/2680135 but somehow that issue was closed with reference to a core issue. I guess this must be a different problem, or that op's problem actually was never solved..

I created a patch that checks before import if language fields are in the list of enable languages. If not, the content will be naturalised to the site's default language so that import doesn't fail. I think this should work without regressions for anyone. It should fix the use case of content that is only there for a pleasant unboxing experience that expects the user to edit or delete all default content.

Comments

JurriaanRoelofs created an issue. See original summary.

jurriaanroelofs’s picture

jurriaanroelofs’s picture

Issue summary: View changes

Status: Needs review » Needs work

The last submitted patch, 2: naturalize-content-language-2900089-2.patch, failed testing. View results

andypost’s picture

Assigned: Unassigned » larowlan
Status: Needs work » Needs review
Issue tags: +Needs tests

Called retest, Idea is interesting but is it fine to import EN content for RU/FR/... by overriding default labnuage... not sure

Instead of that for multilingual install profiles better to export all possible translations, we use that actively so each file contains content in all languages

Personally I prefer to enable default_content fixtures after custom profile install, so all languages from profile imported.

Other workaround is put all required languages into module with default_content

+++ b/src/Importer.php
@@ -174,12 +185,25 @@ class Importer implements ImporterInterface {
+          // Decode check language, if language unavailable set to default language
+          $decoded = $this->serializer->decode($contents, 'hal_json');
+          if (isset($decoded['langcode']) && !in_array($decoded['langcode'][0]['value'], $langs_available)) {
+            $decoded['langcode'][0]['value'] = $current_lang;
+          }
+          array_walk_recursive($decoded, function (&$value, $key, $userdata) {
+            if (($key == 'lang') && (!in_array($value, $userdata[1]))) {
+              $value = $userdata[0];
+            }
+          }, [$current_lang, $langs_available]);
+          $contents = $this->serializer->encode($decoded, 'hal_json');

When no language available for translation I suppose it should be skipped but if no translations for selected in installer language available... here could be a fallback, but to which translation?

larowlan’s picture

Assigned: larowlan » Unassigned

Sorry, not an expert on i18n, one for @Berdir

Couple of general nitpicks

  1. +++ b/src/Importer.php
    @@ -174,12 +185,25 @@ class Importer implements ImporterInterface {
    +      $langs_available = array_keys($this->languageManager->getLanguages());
    +      $current_lang = $this->languageManager->getCurrentLanguage()->getId();
    

    Can we use full word here, languages_available, current_language

    thanks

  2. +++ b/src/Importer.php
    @@ -174,12 +185,25 @@ class Importer implements ImporterInterface {
    +          // Decode check language, if language unavailable set to default language
    

    nit: > 80 chars, needs trailing .

  3. +++ b/src/Importer.php
    @@ -174,12 +185,25 @@ class Importer implements ImporterInterface {
    +          if (isset($decoded['langcode']) && !in_array($decoded['langcode'][0]['value'], $langs_available)) {
    ...
    +            if (($key == 'lang') && (!in_array($value, $userdata[1]))) {
    

    Can we use third arg, TRUE - we expect these to be strings so lets be type safe

  4. +++ b/src/Importer.php
    @@ -174,12 +185,25 @@ class Importer implements ImporterInterface {
    +              $value = $userdata[0];
    ...
    +          }, [$current_lang, $langs_available]);
    

    I really dislike overloading an array like this. We should either create a value object or pass along $this->languageManager as user data instead, then we can typehint.

jurriaanroelofs’s picture

Called retest, Idea is interesting but is it fine to import EN content for RU/FR/... by overriding default labnuage... not sure

Instead of that for multilingual install profiles better to export all possible translations, we use that actively so each file contains content in all languages

@andypost I think you are judging this based on your own use case(s) for the default_content. To illustrate my use case, look at this page for example: http://glazed-logistics.sooperthemes.com/ – People do not install this default content because they appreciate my copywriting for a fictitious logistics company. The default content just makes the distribution look great out of the box and people will rewrite all content in whatever language they happen to be using.
If ever I translate my demo content I might only translate it to Chinese so that the content does not look completely alien to asian customers.

People will simply rewrite my default content and they will want expect the page to be in the language they selected in the installer, because they will be editing the default content in that language.

This patch doesn't conflict with use cases where multiple languages are installed and default content is provided in multiple languages, the patch is for the alternative use case where you want "vanity/designed content" that users will edit in their own language. I think this is a common use case for demo content.

jurriaanroelofs’s picture

1. Fixed
2. Fixed
3. Fixed
4.

I really dislike overloading an array like this. We should either create a value object or pass along $this->languageManager as user data instead, then we can typehint.

Sorry this is beyond me, I'm not very familiar with OOP programming. It's on my todo list but I think we'll have to assign this to someone else if this is important. Don't mean to be crass, this is my first patch for a Drupal 8 project and I'm just getting the hang of all the new stuff.

andypost’s picture

Assigned: Unassigned » berdir

@JurriaanRoelofs I understand your case perfectly, and another workaround for that could be implementation that config using in core - override language of modules' provided config to language that pointed in installer

IMO that's more workaround (hijack default language), primary because you breaks relations in default content that are language-dependent
OTOH it works for single language sites with single language default content - exactly like core works(

Let's get Berdir's opinion on it

Status: Needs review » Needs work

The last submitted patch, 8: naturalize-content-language-2900089-8.patch, failed testing. View results

andypost’s picture

Also please provide interdiff it makes easy to review changes you made between patches

andypost’s picture

To elaborate my idea check

- fallback to 'en' for unknown languages http://cgit.drupalcode.org/drupal/tree/core/modules/locale/src/LocaleCon...
- how locale module iterates localized config http://cgit.drupalcode.org/drupal/tree/core/modules/locale/src/LocaleCon...

I can't find where I seen overriding of default config language but translations do fallback to 'en' as well http://cgit.drupalcode.org/drupal/tree/core/modules/locale/src/LocaleCon...

jurriaanroelofs’s picture

StatusFileSize
new2.02 KB

Thx.

rajab natshah’s picture

Assigned: berdir » Unassigned
Status: Needs work » Needs review
StatusFileSize
new4.72 KB
rajab natshah’s picture

The patch is the same Jurriaan's patch, only corrected the in_array call function

in_array($decoded['langcode'][0]['value'], $languages_available, TRUE)
司南’s picture

I get this error too, but in different context.

1. Create an installation profile as a distribution.
2. Add `default_content` module as dependency.
3. Add `content` folder in installation profile's root directory, then add some entity of hal_json format file.
4. Install drush form composer.
5. Run command: drush site-install my_profile ...
6. then the error occurs .......

542Step 11/13 : RUN drush -y site-install catshop install_configure_form.site_default_country=CN install_configure_form.site_default_timezone='Asia/Hong_Kong' install_configure_form.enable_update_status_module=NULL install_configure_form.enable_update_status_emails=NULL --db-url="sqlite://sites/default/files/.ht.sqlite" --account-name=admin --account-pass=123 --account-mail=164713332@qq.com --site-name=测试网站 --locale=zh-hans
543 ---> Running in b38ea6ec4282
544You are about to create a /var/www/html/sites/default/settings.php file and CREATE the 'sites/default/files/.ht.sqlite' database. Do you want to continue? (y/n): y
545Starting Drupal installation. This takes a while. Consider using the [ok]
546--notify global option.
547InvalidArgumentException: Invalid translation language (zh-hans) [error]
548specified. in
549/var/www/html/core/lib/Drupal/Core/Entity/ContentEntityBase.php:863
550Stack trace:
551#0
552/var/www/html/core/modules/hal/src/Normalizer/FieldItemNormalizer.php(113):
553Drupal\Core\Entity\ContentEntityBase->addTranslation('zh-hans')
554#1
555/var/www/html/core/modules/hal/src/Normalizer/FieldItemNormalizer.php(65):
556Drupal\hal\Normalizer\FieldItemNormalizer->createTranslatedInstance(Object(Drupal\language\DefaultLanguageItem),
557'zh-hans')
558#2 /var/www/html/vendor/symfony/serializer/Serializer.php(250):
559Drupal\hal\Normalizer\FieldItemNormalizer->denormalize(Array,
560'Drupal\\language...', 'hal_json', Array)
561#3 /var/www/html/vendor/symfony/serializer/Serializer.php(160):
562Symfony\Component\Serializer\Serializer->denormalizeObject(Array,
563'Drupal\\language...', 'hal_json', Array)
564#4
565/var/www/html/core/modules/serialization/src/Normalizer/FieldNormalizer.php(52):
566Symfony\Component\Serializer\Serializer->denormalize(Array,
567'Drupal\\language...', 'hal_json', Array)
568#5 /var/www/html/vendor/symfony/serializer/Serializer.php(250):
569Drupal\serialization\Normalizer\FieldNormalizer->denormalize(Array,
570'Drupal\\Core\\Fie...', 'hal_json', Array)
571#6 /var/www/html/vendor/symfony/serializer/Serializer.php(160):
572Symfony\Component\Serializer\Serializer->denormalizeObject(Array,
573'Drupal\\Core\\Fie...', 'hal_json', Array)
574#7
575/var/www/html/core/modules/serialization/src/Normalizer/FieldableEntityNormalizerTrait.php(135):
576Symfony\Component\Serializer\Serializer->denormalize(Array,
577'Drupal\\Core\\Fie...', 'hal_json', Array)
578#8
579/var/www/html/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php(172):
580Drupal\hal\Normalizer\ContentEntityNormalizer->denormalizeFieldData(Array,
581Object(Drupal\commerce_store\Entity\Store), 'hal_json', Array)
582#9 /var/www/html/vendor/symfony/serializer/Serializer.php(250):
583Drupal\hal\Normalizer\ContentEntityNormalizer->denormalize(Array,
584'Drupal\\commerce...', 'hal_json', Array)
585#10 /var/www/html/vendor/symfony/serializer/Serializer.php(160):
586Symfony\Component\Serializer\Serializer->denormalizeObject(Array,
587'Drupal\\commerce...', 'hal_json', Array)
588#11 /var/www/html/vendor/symfony/serializer/Serializer.php(118):
589Symfony\Component\Serializer\Serializer->denormalize(Array,
590'Drupal\\commerce...', 'hal_json', Array)
591#12
592/var/www/html/modules/contrib/default_content/src/Importer.php(183):
593Symfony\Component\Serializer\Serializer->deserialize(Array,
594'Drupal\\commerce...', 'hal_json', Array)
595#13
596/var/www/html/modules/contrib/default_content/default_content.module(15):
597Drupal\default_content\Importer->importContent('catshop')
598#14 [internal function]: default_content_modules_installed(Array)
599#15
600/var/www/html/core/lib/Drupal/Core/Extension/ModuleHandler.php(402):
601call_user_func_array('default_content...', Array)
602#16
603/var/www/html/core/lib/Drupal/Core/Extension/ModuleInstaller.php(305):
604Drupal\Core\Extension\ModuleHandler->invokeAll('modules_install...',
605Array)
606#17
607/var/www/html/core/lib/Drupal/Core/ProxyClass/Extension/ModuleInstaller.php(83):
608Drupal\Core\Extension\ModuleInstaller->install(Array, false)
609#18 /var/www/html/core/includes/install.core.inc(1572):
610Drupal\Core\ProxyClass\Extension\ModuleInstaller->install(Array,
611false)
612#19 /var/www/html/core/includes/install.core.inc(662):
613install_install_profile(Array)
614#20 /var/www/html/core/includes/install.core.inc(540):
615install_run_task(Array, Array)
616#21 /var/www/html/core/includes/install.core.inc(117):
617install_run_tasks(Array)
618#22 /var/www/html/vendor/drush/drush/includes/drush.inc(726):
619install_drupal(Object(Composer\Autoload\ClassLoader), Array)
620#23 /var/www/html/vendor/drush/drush/includes/drush.inc(711):
621drush_call_user_func_array('install_drupal', Array)
622#24
623/var/www/html/vendor/drush/drush/commands/core/drupal/site_install.inc(82):
624drush_op('install_drupal', Object(Composer\Autoload\ClassLoader),
625Array)
626#25
627/var/www/html/vendor/drush/drush/commands/core/site_install.drush.inc(255):
628drush_core_site_install_version('catshop', Array)
629#26 /var/www/html/vendor/drush/drush/includes/command.inc(422):
630drush_core_site_install('catshop', 'install_configu...',
631'install_configu...', 'install_configu...', 'install_configu...')
632#27 /var/www/html/vendor/drush/drush/includes/command.inc(231):
633_drush_invoke_hooks(Array, Array)
634#28 /var/www/html/vendor/drush/drush/includes/command.inc(199):
635drush_command('catshop', 'install_configu...', 'install_configu...',
636'install_configu...', 'install_configu...')
637#29 /var/www/html/vendor/drush/drush/lib/Drush/Boot/BaseBoot.php(67):
638drush_dispatch(Array)
639#30 /var/www/html/vendor/drush/drush/includes/preflight.inc(66):
640Drush\Boot\BaseBoot->bootstrap_and_dispatch()
641#31 phar:///usr/local/bin/drush/bin/drush.php(159): drush_main()
642#32 /usr/local/bin/drush(10): require('phar:///usr/loc...')
643#33 {main}
644The command '/bin/sh -c drush -y site-install catshop install_configure_form.site_default_country=CN install_configure_form.site_default_timezone='Asia/Hong_Kong' install_configure_form.enable_update_status_module=NULL install_configure_form.enable_update_status_emails=NULL --db-url="sqlite://sites/default/files/.ht.sqlite" --account-name=admin --account-pass=123 --account-mail=164713332@qq.com --site-name=测试网站 --locale=zh-hans' returned a non-zero code: 1
645{"exitCode":8, "message":"docker build failed or timeout "}

How can i avoid this error?

my site's langcode is zh-hans and it is same with my default content.

geek-merlin’s picture

I had this problem on a drutopia drush install and the patch fixes it for me.
Thought a bit about the approach, and a fallback like this totally makes sense to me.

psf_’s picture

Status: Needs review » Reviewed & tested by the community

Work for me :)

anruether’s picture

This patch does not apply together with #2698425: Do not re-import existing entities. Not sure if the error I get is related to the patch, but it didn't come up when the patch applied. Anyways, it would be great to get one of the patches or both in to have them working together.

TypeError: Argument 8 passed to Drupal\default_content\Importer::__construct() must be an instance of Drupal\default_content\LanguageManagerInterface, instance of Drupal\language\ConfigurableLanguageManager given, called in /var/www/html/web/core/lib/Drupal/Component/DependencyInjection/Container.php on line 290 in Drupal\default_content\Importer->__construct() (line 122 of modules/contrib/default_content/src/Importer.php).

Drupal\default_content\Importer->__construct(Object, Object, Object, Object, Object, 'http://drupal.org', Object, Object) (Line: 290)
Drupal\Component\DependencyInjection\Container->createService(Array, 'default_content.importer') (Line: 171)
Drupal\Component\DependencyInjection\Container->get('default_content.importer') (Line: 158)
Drupal::service('default_content.importer') (Line: 15)
default_content_modules_installed(Array)
call_user_func_array('default_content_modules_installed', Array) (Line: 403)
Drupal\Core\Extension\ModuleHandler->invokeAll('modules_installed', Array) (Line: 325)
Drupal\Core\Extension\ModuleInstaller->install(Array, 1) (Line: 83)
Drupal\Core\ProxyClass\Extension\ModuleInstaller->install(Array) (Line: 458)
Drupal\system\Form\ModulesListForm->submitForm(Array, Object)
call_user_func_array(Array, Array) (Line: 111)
Drupal\Core\Form\FormSubmitter->executeSubmitHandlers(Array, Object) (Line: 51)
Drupal\Core\Form\FormSubmitter->doSubmitForm(Array, Object) (Line: 589)
Drupal\Core\Form\FormBuilder->processForm('system_modules', Array, Object) (Line: 318)
Drupal\Core\Form\FormBuilder->buildForm('system_modules', Object) (Line: 93)
Drupal\Core\Controller\FormController->getContentResult(Object, Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 582)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 151)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 99)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 78)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 693)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
berdir’s picture

Status: Reviewed & tested by the community » Closed (won't fix)
Issue tags: -Needs tests

I've recently created the 2.0.x branch, see the project page on all the improvements in the 2.0.x branch. Testing that and providing feedback would be very welcome. The 1.x branch isn't actively maintained and won't receive new features anymore, so I'm closing this and other issues as won't fix.

2.0.x explicitly supports multiple translations and also handles language mismatches.. non-existing languages are ignored and if the default language doesn't exist, it will either pick one of the available translations or fall back to the default language of the site being installed.

eduardo morales alberti’s picture

Version: 8.x-1.x-dev » 2.0.x-dev
Status: Closed (won't fix) » Needs review
StatusFileSize
new5.09 KB

@Berdir, its still happens on 2.0x branch.
I refactor this issue patch after applying the issue https://www.drupal.org/project/default_content/issues/2698425 patch as comment @anruether

eduardo morales alberti’s picture

Status: Needs review » Needs work

Still getting the message, so the patch does not fix the error

My solution was delete all the entities generated and regenerate it again.

eduardo morales alberti’s picture

Status: Needs work » Closed (won't fix)