3

Throughout my app I use i18n without problem. However, for email send through a cron job, I get the error:

ReferenceError: __ is not defined

In app.js I configure i18n:

const i18n = require("i18n");
i18n.configure({
    locales: ["en"],
    register: global,
    directory: path.join(__dirname, "locales"),
    defaultLocale: "en",
    objectNotation: true,
    updateFiles: false,
});
app.use(i18n.init);

Throughout my app I use it as __('authentication.flashes.not-logged-in'), like I said without problems. In a mail controller, that is called upon by a cron job, I use it in the same way: __('mailers.buttons.upgrade-now'). However there, and only there, it produces the mentioned error.

Just to try, I've changed this in the mail controller to i18n.__('authentication.flashes.not-logged-in'). But then I get another error:

(node:11058) UnhandledPromiseRejectionWarning: TypeError: logWarnFn is not a function
    at logWarn (/data/web/my_app/node_modules/i18n/i18n.js:1180:5)

Any idea how to make the emails work that are sent through a cron job?

Nick
  • 3,496
  • 7
  • 42
  • 96
  • How is your cron job set up, exactly? Does it make an HTTP request to your app, or does it try and use `node` to run the controller directly? – DylanSp Dec 04 '20 at 16:46
  • @DylanSp, I don't know much about cron and haven't set this up myself, so I hope I'm answering your question correctly. If I run `crontab -l` I have `30 14 * * * cd /data/web/portal/ && /usr/bin/timeout 120 /usr/bin/node cli.js sendemails 2>&1 | /usr/bin/logger -t portal-cron-live`. I think this means node tries to run the controller directly, does it not? – Nick Dec 04 '20 at 16:55
  • It depends what `cli.js sendemails` does. Does that script make an HTTP request, or call the controller directly? – DylanSp Dec 04 '20 at 16:57
  • Ah, that calls on the controller directly: `program.command("sendemails").action(async function () { mailController.executeCrons() ...` – Nick Dec 04 '20 at 17:01
  • There's your problem; the `i18n` global doesn't get defined that way. I'll type up an answer. – DylanSp Dec 04 '20 at 17:02

1 Answers1

4

In comments, the asker clarified that the cron job calls mailController.executeCrons() directly, instead of making an HTTP request to the app. Because of this, the i18n global object never gets defined, because the app setup code in app.js isn't run.

The best solution would be to use i18n's instance usage. You could separate the instantiation and configuration of an I18N object out into a separate function, then call it both in app.js to set it up as Express middleware, and in the mailController.executeCrons() function to use it when being called through the cronjob.

Code outline:

i18n.js (new file)

const i18n = require("i18n");

// factory function for centralizing config;
// either register i18n for global use in handling HTTP requests,
// or register it as `i18nObj` for local CLI use
const configureI18n = (isGlobal) => {
  let i18nObj = {};

  i18n.configure({
    locales: ["en"],
    register: isGlobal ? global : i18nObj,
    directory: path.join(__dirname, "locales"),
    defaultLocale: "en",
    objectNotation: true,
    updateFiles: false,
  });

  return [i18n, i18nObj];
};


module.exports = configureI18n;

app.js

const configureI18n = require('./path/to/i18n.js');

const [i18n, _] = configureI18n(true);
app.use(i18n.init);

mailController.js

const configureI18n = require('./path/to/i18n.js');

const [_, i18nObj] = configureI18n(false);

executeCrons() {
  i18nObj.__('authentication.flashes.not-logged-in');
}
Nick
  • 3,496
  • 7
  • 42
  • 96
DylanSp
  • 1,379
  • 13
  • 27
  • I'm trying the solution now, but referencing app.js it produces the error: `const [i18n, _] = configureI18n(true);` `TypeError: configureI18n is not a function or its return value is not iterable`. – Nick Dec 04 '20 at 17:31
  • Sorry, messed up the export syntax. Edited `i18n.js` to use `exports = configureI18n;`, try that. – DylanSp Dec 04 '20 at 17:41
  • It works as expected, but it doesn't add the keys to the locale file automatically. – Ali Majed HA Aug 10 '22 at 19:24