Problem/Motivation

For the life of me, I have no idea what component an issue for items under the `Core\StringTranslation` would belong to. There is no "translation system." I am assuming "base system."

\Drupal\Core\StringTranslation\TranslationManager implements \Drupal\Core\StringTranslation\TranslationInterface and \Drupal\Core\StringTranslation\Translator\TranslatorInterface.

When constructed it sets the langcode to be used in translations from the language ID derived from the default language service:

  public function __construct(LanguageDefault $default_language) {
    $this->defaultLangcode = $default_language->get()->getId();
  }

That means if the default language is ever changed, the translation manager's langcode is never updated.

There is, however, the \Drupal\Core\StringTranslation\TranslationManager::setDefaultLangcode method. This allows changing the default language code for the translation manager (ie: updating to match the changed default language.) The problem is that this method is not on any of its implementing interfaces.

In order to provide a translation that is different than the site's current language (ie: destination email, something over cron or CLI) you need checks like:

        use StringTranslationTrait;

        $string_translation = $this->getStringTranslation();
        if ($string_translation instanceof TranslationManager) {
          $string_translation->setDefaultLangcode($language->getId());
          $string_translation->reset();
        }

Proposed resolution

Add a mechanism to ConfigurableLanguageManager to temporarily switch the render language to another value analogous to the switching of the language config override.

Remaining tasks

  1. Review
  2. Commit

User interface changes

N/A

API changes

API additions:

Drupal\Core\Language\LanguageManagerInterface

  • public function setRenderOverrideLanguage(?LanguageInterface $language = NULL, $type = LanguageInterface::TYPE_INTERFACE): static;
  • public function getRenderOverrideLanguage($type = LanguageInterface::TYPE_INTERFACE): ?LanguageInterface;

Data model changes

N/A

Release notes snippet

✄ TBD?

Issue fork drupal-3029003

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

mglaman created an issue. See original summary.

mglaman’s picture

Issue summary: View changes

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

smustgrave’s picture

This came up as the daily BSI target.

Checking TranslationManager and this still seems to be the case.

Would be +1 for adding to TranslationInterface

May be a good novice task as the summary is pretty clear (does need solution cleared up if agreed upon)

penyaskito’s picture

Status: Active » Closed (works as designed)
Issue tags: -Novice, -Needs change record

If you need to translate a string, you can pass $options['langcode'] to translate() / t().
For config, \Drupal\Core\Language\LanguageManager::setConfigOverrideLanguage.

I agree we could document this better. But this is not an overlook.

Setting the default language happens:

  • Very early in a request to the installer (\install_begin_request)
  • Very early in a regular request (\Drupal\language\EventSubscriber\LanguageRequestSubscriber)
  • Very few other snowflakes (e.g. \Drupal\help\Plugin\HelpSection\HelpTopicSection::renderTopicForSearch for indexing help topics, which are twig templates, but not actually Drupal templates)

This is not in any interface because you are (almost) never supposed to call it. This is the most low level part of the translation system.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

mglaman’s picture

Status: Closed (works as designed) » Active

See the linked issues. This is about rendering in a different language. We can change and retitle it if this isn't the right approach.

It's like renderInContext but if we could substitute a language in that one context. Or like wkrkspace has a way to execute in or out of a workspace.

Drupal Commerce has this hack still to allow emails to go into a user's language vs the current site language when rendering the template (not just input strings from config)

penyaskito’s picture

Missed those, sorry!

I'd rather add a new \Drupal\Core\Language\LanguageManagerInterface::setDefaultLanguage() than exposing this one.

gábor hojtsy’s picture

Hm does this mean that it is not possible to set the options language and be applied to what it needs to, we need to globally set the language manager language too? I think setDefaultLanguage() could be confusing if used generally dynamically because it does not persist.

znerol made their first commit to this issue’s fork.

znerol’s picture

Status: Active » Needs review

Opened an MR, no tests yet. Looking for feedback from reporter and maintainer whether this is going into the right direction.

mglaman’s picture

setRenderOverrideLanguage on LanguageManagerInterface is the right surface for this API since the naming clearly signals a temporary contextual override, it eliminates the instanceof TranslationManager workaround that projects like Commerce have long relied on. +1 from me

smustgrave’s picture

Status: Needs review » Needs work

Thanks for following up @mglaman

@znerol does that help? Besides tests not sure if major tweaks are needed.

znerol’s picture

Status: Needs work » Needs review
znerol’s picture

Issue summary: View changes
smustgrave’s picture

This is looking good to me @mglaman as the original reporter what do you think?

mglaman’s picture

Status: Needs review » Needs work

Following up on #10 with a closer look at the MR.

The direction is right. A language override on the language manager beats exposing TranslationManager::setDefaultLangcode(), and it keeps that method internal like @penyaskito asked.

This should be a scoped API instead of a setter/getter pair:

 public function executeInLanguage(LanguageInterface $language, callable $callback): mixed;

With setRenderOverrideLanguage(), every caller has to restore the language in a finally block. Nested overrides also break: passing NULL falls back to the negotiated language, not the previous override. executeInLanguage() can save and restore the previous state itself, the same way RendererInterface::executeInRenderContext() does.

It should also cover everything needed to render in another language. HelpTopicSection still calls LanguageDefault::set(). Commerce's MailHandler::changeActiveLanguage() does too, plus setConfigOverrideLanguage(), to get TYPE_CONTENT and config translated. One call should handle all of that. Otherwise Commerce swaps one workaround for three.

This needs a change record for the interface addition.

znerol’s picture

Status: Needs work » Needs review

Fixed BC and removed getNegotiatedLanguage from the interface.

Re #27

This should be a scoped API instead of a setter/getter pair:

I think this MR should just provide the low-level API (analogous to the existing setConfigOverrideLanguage()/getConfigOverrideLanguage(). There is #3536307: Execution environment: Safely run code inside an environment with partially substituted system state / config for a more generic high level API. In the long run commerce, search and mailer should be switched to that one.

HelpTopicSection still calls LanguageDefault::set().

I think LanguageDefault shouldn't be changed at all. I cannot reconstruct whether the call to set() was necessary at the times of #2664830: Add search capability to help topics, but nowadays it isn't. I removed the dependency and verified the result manually (with the ex core search module which recently moved to contrib).

znerol’s picture

Added a change record.

nicxvan’s picture

Component: base system » language system