Internationalization for Ember projects
I removed the base helper -format-base.js
so that the code for each helper is easier to understand and maintain.
[!IMPORTANT] If you happened to create a helper that extends
-format-base.js
(private implementation), please extend theHelper
class from@ember/component/helper
and inject theintl
service instead. For reference, please check the{{t}}
helper.
/* addon/helpers/legacy-format-money.ts */
import BaseHelper from 'ember-intl/helpers/-format-base';
import { legacyFormatMoney } from '../utils/index';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Type 'typeof AbstractHelper' is not a constructor function type.
export default class LegacyFormatMoneyHelper extends BaseHelper {
format(money, options): string {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Property 'intl' does not exist on type 'LegacyFormatMoneyHelper'
return legacyFormatMoney(this.intl, money, options);
}
}
/* addon/helpers/legacy-format-money.ts */
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
import type { IntlService } from 'ember-intl';
import { legacyFormatMoney } from '../utils/index';
export default class LegacyFormatMoneyHelper extends Helper {
@service declare intl: IntlService;
constructor() {
// eslint-disable-next-line prefer-rest-params
super(...arguments);
// @ts-expect-error: Property 'onLocaleChanged' is private and only accessible within class 'IntlService'.
this.intl.onLocaleChanged(this.recompute, this);
}
compute([money], options): string {
return legacyFormatMoney(this.intl, money, options);
}
}
Compared to v6.2.2
, the unpacked size may be slightly larger (~2 kB). On the plus side, a few type errors and hidden bugs (runtime errors) should be fixed now. Since the code change is large, I went with a minor release to be on the safe side.
[!WARNING] There is a known issue for Glint users, caused by the
{{t}}
helper returningSafeString
andundefined
as possible types. This will be addressed soon.app/templates/form.hbs:1:14 - error TS2345: Argument of type 'string | SafeString | undefined' is not assignable to parameter of type 'string'. Type 'undefined' is not assignable to type 'string'. 1 {{page-title (t "routes.form.title")}} ~~~~~~~~~~~~~~~~~~~~~~~ app/templates/form.hbs:6:6 - error TS2322: Type 'string | SafeString | undefined' is not assignable to type 'string | undefined'. Type 'SafeString' is not assignable to type 'string'. 6 @instructions={{t ~~~~~~~~~~~~
If you encountered TypeScript errors of the following form after installing 6.2.0
or 6.2.1
,
tests/integration/components/my-component.ts:59:23 - error TS2345: Argument of type 'string | SafeString' is not assignable to parameter of type 'string'.
Type 'SafeString' is not assignable to type 'string'.
59 .hasText(t('some.key'));
please try installing 6.2.2
instead. As a temporary fix, I cast the return type of the test helper t()
to be string
.
In CI (continuous integration), we can now show that ember-intl
(still a v1 addon) passes embroider-safe
and embroider-optimized
scenarios.
To ease maintenance, I removed 3 dependencies (lodash.omit
, has-unicode
, and locale-emoji
) that affect the private implementation. The removal shouldn't affect the public API, so I believe we can do with a patch release.
I changed the project structure to resemble that of a v2 addon. Workspaces should also help us understand the dependencies of each package and the origin of an error. The latter is demonstrated by the ability to update @glint/*
packages from 0.9.7
to the latest.
[!NOTE] To refactor code in increments, I replaced default exports with named exports, for paths that begin with
ember-intl/test-support/
.If you made use of
ember-intl
's test helpers but didn't import them from theindex
file, i.e.import { ... } from 'ember-intl/test-support'
, I recommend doing so after installing[email protected]
.
/* Before */
import t from 'ember-intl/test-support/t';
/* After (Option 1) */
import { t } from 'ember-intl/test-support/t';
/* After (Option 2, recommended) */
import { t } from 'ember-intl/test-support';
[!NOTE] If you had to patch
[email protected]
due to TS errors resulting from unnecessary@ts-expect-error
, you may not have to inv6.1.2
.
[email protected]
diff --git a/addon/-private/formatters/format-message.ts b/addon/-private/formatters/format-message.ts
--- a/addon/-private/formatters/format-message.ts
+++ b/addon/-private/formatters/format-message.ts
@@ -12,7 +12,7 @@ import type { PrimitiveType } from 'intl-messageformat';
import Formatter from './-base';
const {
Handlebars: {
- // @ts-expect-error Upstream types are incomplete.
+ // @ts-ignore: Upstream types are incomplete.
Utils: { escapeExpression },
},
} = Ember;
@@ -35,12 +35,13 @@ function escapeOptions<T extends Record<string, unknown>>(object?: T) {
// formatter won't know what to do with it. Instead, we cast
// the SafeString to a regular string using `toHTML`.
// Since it was already marked as safe we should *not* escape it.
- // @ts-expect-error: see comment above
+ // @ts-ignore: see comment above
escapedOpts[key] = val.toHTML();
} else if (typeof val === 'string') {
+ // @ts-ignore: see comment above
escapedOpts[key] = escapeExpression(val);
} else {
- // @ts-expect-error: see comment above
+ // @ts-ignore: see comment above
escapedOpts[key] = val; // copy as-is
}
});
[!NOTE] Update:
I tried installing
[email protected]
and realized there's no change tofast-glob
. Will need to investigate other possible solutions again.
[!IMPORTANT] ~
[email protected]
should resolve a high-severity report from Dependabot. A regression is possible, because the patch forbroccoli-merge-files
involved a major-version update offast-glob
.~
Title: glob-parent before 5.1.2 vulnerable to Regular Expression Denial of Service in enclosure regex
Description: This affects the package glob-parent before 5.1.2. The enclosure regex used to check for strings ending in enclosure containing path separator.
Almost 2 years passed since 5.7.2
had been released. Many thanks to those who have continued to use ember-intl
and even tried out 6.0.0-beta.x
.
[!IMPORTANT] As you may know,
6.0.0
had been released by accident and isn't a stable version. So6.1.0
marks the beginning of the6.x
series.Going forward, I think that we'll do a better job with documenting code changes and will continue to improve DX (e.g. simplify API, provide types that work with
@tsconfig/ember
and Glint).
If you run into a breaking change that hasn't been documented, please let us know by opening an issue and/or creating a pull request.
https://ember-intl.github.io/ember-intl/docs/guide/migration-5-0-to-6-1
typescript@v4
has been limited to 4.8.x
and 4.9.x
. Note, the minimum version matches that required by Glint from versions 1.0.x
and 1.1.x
.peerDependencies
have been updated to support typescript@v5
.After setting the minimum supported Node version to 16
, I updated some of the dependencies for ember-intl
to their latest version.
Since the Ember and Node tests continued to pass, I'm hoping that there were no bugs and regressions since v6.0.0-beta.5
. However, if you notice an issue with v6.0.0-beta.6
, please let us know.
The docs-app now runs on [email protected]
.
⚠️ This beta will be the last version that supports Ember 3.24 and Node 14.
⚠️ There is a known bug for the Glint support: https://github.com/ember-intl/ember-intl/issues/1764
For Glint users, how to add the Registry
from ember-intl
:
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
}
}
I'm currently working on updating the project setup so that we may be able to release ember-intl
more frequently.
Note, there is now a CHANGELOG
at the root folder. (I can use your help with retroactively filling out entries from previous versions. This would involve adding a label to the merged pull requests.)