Hi All!
Sorry for a very long query - I tried to make it as short as possible but it's rarely possible with the i18n related stuff :(
I'm working on a multilingual D8 site. The default language is English, other languages will be gradually added for users' convenience. All new content will be first added in English, then gradually translated into other enabled languages. Due to the dynamic nature of the content, at no point in time ALL content will be translated into ALL languages but nevertheless any user regardless of the UI language currently selected should see ALL content relevant to their query regardless of whether it has been translated to the current UI language or not. If an entity has a translation to the current user's UI language (let's make it Russian for brevity) then it should be displayed in Russian, if not - it should be displayed in English.
If I apply no language-related filters to a view at all, every translation is shown as one more row in the view output, along with its English original which is not good. If I filter on "Translation language" equals "Interface text language selected for page" then I only see the content that has been translated which is no good either. I added "Default translation (= True)" filter and chose "Interface text language selected for page" for Rendering Language. This way I see ALL content, each entity ONLY ONCE, and if it has been translated then its label in the teaser is in Russian, if not then it's displayed in English. Looks good so far BUT once I click on a link in the list leading to an untranslated entity, not only the content is displayed in English which is expected behaviour but the UI language falls back to English as well which is not quite what I want.
When I look at the links to entities generated by the view in the teaser list (which displays perfectly in itself), I see that the links to translated entities include the language in their paths (e.g. /ru/node/5) while the links to untranslated entities don't (e.g. /node/6). Obviously when I click on such a link I lose the UI language forever. But if I manually enter the URL /ru/node/6 it correctly displays Russian interface and English content (for lack of Russian translation of that particular node).
QUESTION: What do I do to the view for it to produce links to the Russian (translated) versions of node pages (always with /ru/ in them) REGARDLESS of whether there exists a Russian translation for that node or not?


blue_waters’s picture

Hi @ndlarge did you make any progress with this? I think your issues is related to... https://www.drupal.org/node/2689459

The solution we came up with for this exact same use case, was to to generate path aliases for all available languages, on post_insert, post_update for each node. Also in our case this works because we're okay with keeping URLs (path aliases) in a the site's default language (English in this case) on a multilingual site. After our hooks are run, there are path aliases available for every language, and untranslated content will not 'force the user off of the selected language' - i.e. http://sometime.com/th/my-post-in-english will show the untranslated post, and NOT force the user back to the default language at http://sometime.com/my-post-in-english

We started by installing this module... https://www.drupal.org/project/hook_post_action

And then wrote our own custom module which implements hook post actions for insert and update (also delete, which removes all path aliases). For example, here's the post entity insert hook...

 * Implements hook_post_action hook_entity_postinsert().
 * https://www.drupal.org/node/2689459
 * @param EntityInterface $entity
function foo_language_entity_postinsert(EntityInterface $entity) {
  if (($entity instanceof ContentEntityInterface) && $entity->hasField('path')) {
    $source = '/node/' . $entity->id();
    $alias_storage = \Drupal::service('path.alias_storage');
    $language_manager = \Drupal::service('language_manager');
    $defaultLanguageId = $language_manager->getDefaultLanguage()->getId();
    $defaultAlias = $alias_storage->load([
      'source' => $source,
      'langcode' => $defaultLanguageId,

    if($defaultAlias) {
      foreach ($language_manager->getLanguages() as $langcode => $language) {
        if ($langcode != $defaultLanguageId) {
          if ($translation_path = $alias_storage->load([
            'source' => $source,
            'langcode' => $langcode
          ) {
            $alias_storage->save($source, $defaultAlias['alias'], $langcode, $translation_path['pid']);
          else {
            $alias_storage->save($source, $defaultAlias['alias'], $langcode);

It's also important that you turn off URL alias translation for all content types that you'd like to use this approach for, under Content Language and Translation Settings.

Hope this helps....

ndlarge’s picture

Hi blue_waters, thanks for your reply.

did you make any progress with this?

Nope, just discovered another problem, with sorting - if I filter by "default translation is true" to ensure that I have one copy of every node, the nodes are sorted by default translation before being rendered in Russian which makes their order a total mess.
I am a bit disappointed that I can't seem to be able to attract any attention to my issues - I was reluctant to post this to the core Issues queue as it's more of a "how to" query than a bug report but I'm afraid I will have to.
I looked into the link you gave - I'm not sure it's directly related to the problem I am having - I didn't even use URL aliases when I posted that, but there might be something in it, I will think about it.
As for the solution you propose - the problem is that I don't have a target set of languages set in stone: they might be added later, so at the time of node creation I cannot know what languages might be added to the site in the future. But I will think about it, thanks again.

blue_waters’s picture

Yes - it's true that if you add or remove languages from the Drupal site, then using my approach, you'll have to regenerate all of the automatically created path aliases. It also very much a 'brute force' solution. Like you, it took me quite a while to find the relevant topics, and come up with something that worked for us.

Good luck...