Skip to content

Migration from v5 to v6

Over 3 years passed since 5.0.0 had been released on May 2020. Unfortunately, whether the merged pull requests resulted in a feature, bug fix, or breaking change hasn't been documented well. (We will do a better job going forward.)

The lists below describe what you may encounter when updating ember-intl from 5.7.2, the last stable release. If there is a missing item, please create a pull request to help complete this page.

IMPORTANT

6.0.0 had been released by accident and isn't a stable version. Version 6.1.0 marks the beginning of the 6.x series.

Breaking changes

Minimum requirements

Projects with these versions are supported when issues arise.

  • Ember 3.28 and above
  • Node 16 and above
  • TypeScript 4.8 and above

In addition, ember-auto-import@v2 is required.

Missing setupIntl results in a runtime error

If a rendering test (also called an integration test) depends on ember-intl (e.g. because you used the {{t}} helper in the template, injected the intl service in the backing class, or rendered another component that depends on ember-intl), then you must add setupIntl to your test. Otherwise, you will encounter the runtime error,

sh
You attempted to update `_locale` on ..., but it had already been used previously in the same computation.

The fix is manual. To see which tests are missing setupIntl, you can run your tests (e.g. ember test --server) and check the error messages in the console.

diff
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
+ import { setupIntl } from 'ember-intl/test-support';
import { setupRenderingTest } from 'ember-qunit';
import { module, test } from 'qunit';

module('Integration | Component | hello', function (hooks) {
  setupRenderingTest(hooks);
+   setupIntl(hooks);

  test('it renders', async function (assert) {
    await render(hbs`
      <Hello @name="Zoey" />
    `);

    assert.ok(true);
  });
});

Missing other clause results in a build error

If a translation message has an argument of the plural type, then it must have the other clause. Otherwise, you will see the build error,

sh
Build Error (TranslationReducer)

An error occurred (MISSING_OTHER_CLAUSE) when extracting ICU arguments for ...

The fix is manual. Find translations with the keyword plural, then define other.

diff
- message: You have {itemCount, plural, =0 {no items} one {# item}}.
+ message: You have {itemCount, plural, =0 {no items} one {# item} other {# items}}.

Renamed re-export for the intl service

In v5.5.0, the intl service class had been re-exported in the "barrel" file (the index file). However, the name of the re-exported class, Service, happened to collide with the name of the Service class from @ember/service.

To prevent people from using the wrong Service class and help IDE suggestions pick the correct import path, the re-exported class is now named IntlService.

diff
- import { Service } from 'ember-intl';  // Bug
+ import Service from '@ember/service';

this.owner.register('service:api', class Api extends Service {
  // ...
});

Type-only re-export for the intl service

If you had used the value re-export of the intl service class, inject the service instead. The type re-export can be used to type the injected service, if you don't want to follow the service registry approach.

ts
import { service } from '@ember/service';
import Component from '@glimmer/component';
import type { IntlService } from 'ember-intl';

export default class Example extends Component {
  @service declare intl: IntlService;
}

Features

Dynamically set named arguments

v6.0.0-beta.3 introduced the ability to dynamically set named arguments. You can pass an object (a POJO) to the first positional argument.

hbs
{{t "say.hello" @user}}

For more information, visit Passing data.

Glint support

v6.0.0-beta.5 added a template registry to support Glint. This removes the need for @gavant/glint-template-types for typing ember-intl's helpers.

ts
import '@glint/environment-ember-loose';

import type EmberIntlRegistry from 'ember-intl/template-registry';

declare module '@glint/environment-ember-loose/registry' {
  export default interface Registry extends EmberIntlRegistry, /* other addon registries */ {
    // local entries
  }
}

Two ways to type the intl service

v5.5.0 introduced TypeScript support. You might have retrieved the type IntlService from 'ember-intl/services/intl', a long path to remember and type.

ts
import { service } from '@ember/service';
import Component from '@glimmer/component';
import type IntlService from 'ember-intl/services/intl';

export default class Example extends Component {
  @service declare intl: IntlService;
}

In v6, ember-intl recommends importing the type in one of two ways.

  • Import IntlService from the "barrel" file (the index file):

    ts
    import { service } from '@ember/service';
    import Component from '@glimmer/component';
    import type { IntlService } from 'ember-intl';
    
    export default class Example extends Component {
      @service declare intl: IntlService;
    }
  • Use the service registry:

    ts
    import { type Registry as Services, service } from '@ember/service';
    import Component from '@glimmer/component';
    
    export default class Example extends Component {
      @service declare intl: Services['intl'];
    }

The registry pattern may be preferred if you need to inject multiple services and want to avoid having many import statements.