1
votes

Has anyone gotten Aurelia Validation to work with the i18n Plugin for multi-lingual error messages? My app won't even start when I add in the code from the Aurelia documentation http://aurelia.io/hub.html#/doc/article/aurelia/validation/latest/validation-basics/12.

Here's my main.js:

import environment from './environment';
import {I18N} from 'aurelia-i18n';
import XHR from 'i18next-xhr-backend';
import {ValidationMessageProvider} from 'aurelia-validation';

//Configure Bluebird Promises.
//Note: You may want to use environment-specific configuration.
Promise.config({
  warnings: {
    wForgottenReturn: false
  }
});

export function configure(aurelia) {
  aurelia.use
    .standardConfiguration()
    .feature('resources')
    .plugin('aurelia-validation');

  aurelia.use.plugin('aurelia-i18n', (instance) => {
      // register backend plugin
      instance.i18next.use(XHR);

      // adapt options to your needs (see http://i18next.com/docs/options/)
      instance.setup({
        backend: {                                  
          loadPath: '/locales/{{lng}}/{{ns}}.json',
        },
        lng : 'en',
        ns: ['translation'],
        defaultNS: 'translation',
        attributes : ['t','i18n'],
        fallbackLng : 'en',
        debug : false
      });
    });

  // Straight from Aurelia Documentation
  const i18n = aurelia.container.get(i18n);
  ValidationMessageProvider.prototype.getMessage = function(key) {
    const translation = i18n.tr(`errorMessages.${key}`);
    return this.parser.parseMessage(translation);
  };

  // Straight from Aurelia Documentation
  ValidationMessageProvider.prototype.getDisplayName = function(propertyName) {
    return i18n.tr(propertyName);
  };

  if (environment.debug) {
    aurelia.use.developmentLogging();
  }

  if (environment.testing) {
    aurelia.use.plugin('aurelia-testing');
  }

  aurelia.start().then(() => aurelia.setRoot());
}

The error I get is vendor-bundle.js:3394 Error: key/value cannot be null or undefined. Are you trying to inject/register something that doesn't exist with DI?(…)

If I delete the two sections marked // Straight from Aurelia Documentation, it works fine (but only in one language).

If you see an error in my code, please point it out. Or, if you have a working example using aurelia-validation and aurelia-i18n working together, please pass on a link. Thanks!

3

3 Answers

2
votes

Ran into this issue as well. It appears that the line

// Straight from Aurelia Documentation
const i18n = aurelia.container.get(i18n);

is getting (or more likely creating) a different instance of i18n than the

aurelia.use.plugin('aurelia-i18n', (instance) =>

I fixed this by getting the i18n instance directly from the aurelia.use.plugin() as follows (this is typescript but same principle applies to pure js):

let i18n:I18N = null;
aurelia.use.plugin('aurelia-i18n', (instance:I18N) => {
    i18n = instance;
    //rest of plugin code here
}
1
votes

Use the imported I18N instead:

const i18n = aurelia.container.get(I18N);

But indeed, i18n seems to stop working afterward. My solution was to update the i18n singleton instance in the first page (app.js), the first time it gets injected:

  constructor(i18n) {
    this.i18n = i18n;
    this.initAureliaSingletons();
  }

  /**
   * Some configurations breaks in 'main.js'
   * singletons can be configure here
   * @return {void}
   */
  initAureliaSingletons() {
    const i18n = this.i18n;
    ValidationMessageProvider.prototype.getMessage = function(key) {
      const translation = i18n.tr(`validation-${key}`);
      return this.parser.parseMessage(translation);
    };
  }
0
votes

I put it on my main and it works. I think that the trick was to use the variable that was initialized in the plug-in initialization:

  var i18n;
  aurelia.use.plugin('aurelia-i18n', (instance) => {
      // register backend plugin
      instance.i18next.use(Backend.with(aurelia.loader)).use(LngDetector);
      i18n = instance;

(...)

      aurelia.use.plugin('aurelia-validation');

      var standardGetMessage = ValidationMessageProvider.prototype.getMessage;
      ValidationMessageProvider.prototype.getMessage = function (key) {
          if (i18n.i18next.exists(key)) {
              const translation = i18n.tr(key);
               return this.parser.parse(translation);
          } else {
              return standardGetMessage(key);
          }
      };

      ValidationMessageProvider.prototype.getDisplayName = function (propertyName, displayName) {
          if (displayName !== null && displayName !== undefined) {
              return displayName;
          }
          return i18n.tr(propertyName);
      };