Skip to content

Commit

Permalink
fix(@formatjs/intl-displaynames): follow ES2021 spec and make type op…
Browse files Browse the repository at this point in the history
…tion required (#2103)
  • Loading branch information
pyrocat101 committed Sep 17, 2020
1 parent 9988a8a commit 3e00688
Show file tree
Hide file tree
Showing 21 changed files with 1,015 additions and 1,001 deletions.
8 changes: 6 additions & 2 deletions packages/intl-displaynames/index.ts
Expand Up @@ -17,7 +17,7 @@ import {
export interface DisplayNamesOptions {
localeMatcher?: 'lookup' | 'best fit';
style?: 'narrow' | 'short' | 'long';
type?: 'language' | 'region' | 'script' | 'currency';
type: 'language' | 'region' | 'script' | 'currency';
fallback?: 'code' | 'none';
}

Expand Down Expand Up @@ -69,8 +69,12 @@ export class DisplayNames {
'type',
'string',
['language', 'currency', 'region', 'script'],
'language'
undefined
);
if (type === undefined) {
throw TypeError(`Intl.DisplayNames constructor requires "type" option`);
}

setSlot(this, 'type', type);

const fallback = GetOption(
Expand Down
22 changes: 13 additions & 9 deletions packages/intl-displaynames/tests/index.test.ts
Expand Up @@ -20,22 +20,26 @@ describe('.of()', () => {
});

it('preserves unrecognized region subtag in language code when fallback option is code', () => {
expect(new DisplayNames('zh', {fallback: 'code'}).of('zh-Hans-Xy')).toBe(
'简体中文(XY)'
);
expect(
new DisplayNames('zh', {type: 'language', fallback: 'code'}).of(
'zh-Hans-Xy'
)
).toBe('简体中文(XY)');
});

describe('with fallback set to "none"', () => {
it('returns undefined when called with language code that has unrecognized region subtag', () => {
expect(new DisplayNames('zh', {fallback: 'none'}).of('zh-Hans-XY')).toBe(
undefined
);
expect(
new DisplayNames('zh', {type: 'language', fallback: 'none'}).of(
'zh-Hans-XY'
)
).toBe(undefined);
});

it('returns undefined when called with language code that valid region subtag but invalid language subtag', () => {
expect(new DisplayNames('zh', {fallback: 'none'}).of('xx-CN')).toBe(
undefined
);
expect(
new DisplayNames('zh', {type: 'language', fallback: 'none'}).of('xx-CN')
).toBe(undefined);
});
});
});
Expand Down
2 changes: 1 addition & 1 deletion packages/intl/src/displayName.ts
Expand Up @@ -24,7 +24,7 @@ export function formatDisplayName(
},
getDisplayNames: Formatters['getDisplayNames'],
value: Parameters<IntlFormatters['formatDisplayName']>[0],
options: Parameters<IntlFormatters['formatDisplayName']>[1] = {}
options: Parameters<IntlFormatters['formatDisplayName']>[1]
): string | undefined {
const DisplayNames: typeof IntlDisplayNames = (Intl as any).DisplayNames;
if (!DisplayNames) {
Expand Down
2 changes: 1 addition & 1 deletion packages/intl/src/types.ts
Expand Up @@ -134,7 +134,7 @@ export interface IntlFormatters<T = any, R = T> {
): T | string | Array<string | T>;
formatDisplayName(
value: Parameters<DisplayNames['of']>[0],
opts?: FormatDisplayNameOptions
opts: FormatDisplayNameOptions
): string | undefined;
}

Expand Down
7 changes: 5 additions & 2 deletions packages/intl/tests/formatDisplayNames.test.ts
Expand Up @@ -42,17 +42,20 @@ describe('format API', () => {
});

it('should return locale display name as string', function () {
expect(formatDisplayName('zh-Hans-SG')).toBe(
expect(formatDisplayName('zh-Hans-SG', {type: 'language'})).toBe(
'Simplified Chinese (Singapore)'
);
});

it('will return undefined if Intl.DisplayName would return undefined', function () {
const displayName = new (Intl as any).DisplayNames('en', {
type: 'language',
fallback: 'none',
});
expect(displayName.of('xx-XX')).toBeUndefined();
expect(formatDisplayName('xx-XX', {fallback: 'none'})).toBeUndefined();
expect(
formatDisplayName('xx-XX', {type: 'language', fallback: 'none'})
).toBeUndefined();
});
});
});
Expand Up @@ -12,6 +12,7 @@ exports[`<FormattedDisplayName /> accepts Intl.DisplayNames options 1`] = `
exports[`<FormattedDisplayName /> renders an empty <> when the underlying DisplayNames would return undefined 1`] = `
<FormattedDisplayName
fallback="none"
type="language"
value="xx-XX"
/>
`;
2 changes: 2 additions & 0 deletions packages/react-intl/tests/unit/components/displayName.tsx
Expand Up @@ -41,13 +41,15 @@ describe('<FormattedDisplayName />', () => {
it('renders an empty <> when the underlying DisplayNames would return undefined', () => {
// When fallback is none, it will return undefined if no display name is available.
const displayNames = new (Intl as any).DisplayNames('en', {
type: 'language',
fallback: 'none',
});
expect(displayNames.of('xx-XX')).toBeUndefined();

// Now let's do the same with <FormattedDisplayNames />
const rendered = mountWithProvider(
{
type: 'language',
fallback: 'none',
value: 'xx-XX',
},
Expand Down

0 comments on commit 3e00688

Please sign in to comment.