At Drupalcon, Jay Callicott and I presented “Multilingual in Drupal 8: A soup to nuts guide featuring VisitTheUSA.com and Habitat.org”, which featured a step-by-step guide to setting up a Drupal 8 site for content, interface and config translation. We ended up getting a lot of questions (I took this as a good sign), especially about how translation worked with the Paragraphs module. Paragraphs as a content structure has indeed gotten very popular. To maintain its place as a top multilingual CMS solution, Drupal translation must work well with Paragraphs. So does it?

Mediacurrent has launched a number of sites that involve paragraph translation, including www.habitat.org and www.visittheusa.com. We recommend “full steam ahead” in terms of taking on multilingual projects in D8, including those with paragraphs. However, there are definitely some rough edges that may require workarounds.

Current paragraph translation model

Below is a diagram of how paragraph translation currently works.

Figure 1: Today’s Paragraph translation model
Today’s Paragraph translation model

This article goes on to explain more about this, including how to configure it.

The key thing to note is that the node only reference one set of paragraphs. These paragraphs are fully translatable though, so as long as you’re okay with your Spanish, English, etc versions containing the same translated paragraph entities, you’ll be fine. But is this a realistic expectation?

Problem: Untranslated paragraph bleed

In some projects, this constraint didn’t give us any trouble. However, we did encounter the following scenario:

  • Client was using TMS (e.g. Lingotek)
  • Client wanted to add a paragraph to a page with translations, and wrote the English version first.
  • They published the English version
  • It then showed up in all of the other translations, and the translated content wasn’t ready yet.

Figure 2: Untranslated paragraph bleed
Untranslated paragraph bleed

Solution: Paragraph-level language field

To fix this problem, we added an optional field to paragraphs to let editors pick a set of languages that each paragraph is allowed to display within. For example, to fix the problem as shown in Figure 2, we would set the value of our new “allowed languages” field to just “English,” at least until the Spanish translation was ready.

To add this new field, go to your paragraph type and add a new field. Pick “Language” as the type and set it to multivalue:

Figure 3: Custom language field configuration
Custom language field configuration

Then, go to your default translation (English in our case) for a node containing one of these paragraphs where you only want it to display in the English/default translation. Set the language value to “English.”

Figure 4: Setting paragraph allowed language
Figure 4: Setting paragraph allowed language

Now you need to write some custom code to implement the language restrictions. There are a lot of ways to do this. See below for an example that uses a theme preprocessor, assuming that you are attaching paragraphs to a node:

/**
 * Implements hook_preprocess_node().
 */
function mymodule_preprocess_node(&$variables) {
  $content = $variables['content'];
  // Loop over your paragraph reference field render element.
  foreach (Element::children($content['field_paragraphs']) as $field_name) {
    $element = &$content['field_paragraphs'][$field_name];
    $paragraph = $element['#paragraph'];
    // Don't show the paragraph if it has specified a language set and the
    // current node's language is not in that set.
    if ($paragraph->hasField('field_language') && $paragraph->field_language->value && !in_array($paragraph->field_language->value, $variables['langcode'])) {
      $element['#access'] = FALSE;
    }
  }
}

Other methods include altering the node template and looping over the paragraph field content there, or you could even make a new field formatter for paragraphs. The idea is the same: loop over the paragraph output, load the paragraph object, compare its language preferences to the current node language and remove the paragraph from the display if necessary.

I hope that this helps anyone stuck on this issue!