Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(@formatjs/intl-displaynames): follow ES2021 spec and make type option required #2103

Merged
merged 1 commit into from Sep 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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