Tasks run via command line don't apply default locale
Affected Version of Concrete CMS
9.x
Description
When a task is run directly from the dashboard, the 'runtime' used appears to be the default one, which will automatically load up the default locale for a site.
When a task is run through the CLI however, it runs a different leaner, runtime, but that doesn't appear to load anything to do with locales.
This means as a practical example, if a task does something where locale is important, such as translate a string, or format a date, there is a behaviour difference between the dashboard and the CLI.
How to reproduce
I noticed this via sending emails, where emails would translate correctly when send via the task triggered via the dashboard - but would remain untranslated when sent via the CLI.
Possible Solution
What I'm not 100% sure of is whether this is expected behaviour, or just something that is missing from the CLI boot process.
What I've been doing is adding to the start of the getTaskRunner() function of my tasks the following:
$u = app()->make(User::class);
$lan = $u->getUserLanguageToDisplay();
$loc = Localization::getInstance();
$loc->setContextLocale(Localization::CONTEXT_UI, $lan);
Additional Context
No response
Thoughts @mlocati ? Is this something we should add to the startup sequence of a console commands?
The CLI environment doesn't load any translation: it always uses en_US.
When I write CLI commands that need to be language-aware I ser the language manually.
Of course we could load the language of the default multilingual tree of the default site, but:
- Very few CLI commands use localization
- Users may still need to manually load languages (for example, every user may have his own preferred language, so you have to load it when sending emails to users)
- The core CLI commands output strings without t(), so they'll always display English messages. But those commands may print the output of some core service that uses t(), so we may have outputs with mixed languages.
Long story short: if you write a CLI command that needs the site language (or any other language), I'd simply load it in the CLI command, not in the core.
I think my main concern here is just the difference in behaviour between when a job is run from the dashboard, versus using the CLI.
I would think that a command should not alter its behaviour based on the context in which it is run, it should be a self contained piece of functionality. Perhaps it's actually the fact that when it's triggered from the dashboard it has things like the site language loaded is the issue.
Or maybe it just needs a mention in the doco. Might be a bit too obscure though.
@Mesuva you are talking about the task:... CLI command, right?
If so, I agree: we could let it load the default language of the default site.
Yes, for example I have a task that checks to see if some orders have been placed and sends an email follow up. The package's emails and naturally in English, but the site is running in a different language by default, which also impacts things like date formatting.
If I run that test just via the 'Run Task' button on /dashboard/system/automation/tasks, it will run it with the context of the interface/dashboard, and therefore pick up the default language.
But if I enable the scheduler, schedule the task, then run it via a cron job for the concrete:scheduler:run command, that's run as the CLI context, and doesn't set the default language.
I ended up putting:
$u = app()->make(User::class);
$lan = $u->getUserLanguageToDisplay();
$loc = Localization::getInstance();
$loc->setContextLocale(Localization::CONTEXT_UI, $lan);
At the top of my getTaskRunner function, on the task controller.
If I run that test just via the 'Run Task' button on /dashboard/system/automation/tasks, it will run it with the context of the interface/dashboard, and therefore pick up the default language.
Please remark that users may login with language A, whereas the default site language may be B, so the dashboard language may not be the default one...
@mlocati yes, that's very true. I'm simplifying a bit, and shouldn't haven't used the word default.
Personally I wouldn't want a task to perform one way because i'm logged in with one language selected, and another way if I'm logged in using a different language. Setting it to the default site locale is ok I'd think, as that's a very broad site-wide setting.
Personally I wouldn't want a task to perform one way because i'm logged in with one language selected, and another way if I'm logged in using a different language
So, simply set the language you want in your task :wink:.
For example, to set the default language of the website I'd do somethink like the following:
use Concrete\Core\Localization\Localization;
$site = app('site')->getSite();
$siteLocale = $site ? $site->getDefaultLocale() : null;
$localization = app(Localization::class);
$revertLocale = $localization->getLocale();
if ($siteLocale && $siteLocale->getLocale() !== $revertLocale) {
$localization->setLocale($siteLocale->getLocale());
} else {
$revertLocale = null;
}
try {
/// Do your stuff
} finally {
if ($revertLocale !== null) {
$localization->setLocale($revertLocale);
}
}
Well that's what I'm effectively doing.
My original concern is just that without explicitly doing this, it's different between the two different contexts on how it's run. And it took a bunch of exploration to understand why.
Perhaps there's nothing to do here except add a line in the doco.
Yeah, just to add here:
- Tasks don't have a "user" context when they're run via the CLI, so we shouldn't try to get the language from the user object.
- Tasks don't have a "site" context when they're run via the CLI, so we shouldn't try to gt the language from the current site. You could make the argument that we could get it from the "default site" but even then I don't know that that's accurate.
I think we should a) make sure we're using the "Default Language" as specified in the /dashboard/system/basics/multilingual page for tasks, and also we should use that language when running tasks from the Dashboard, INSTEAD of the user's preferred language. That way we don't have different behavior between dashboard and console tasks, and we have consistency.