generated from amazon-archives/__template_Apache-2.0
-
Notifications
You must be signed in to change notification settings - Fork 7
feat: add locale normalization and merging utilities #176
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
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
5a8a782
feat: add locale normalization and merging utilities
Pixselve ed550f3
style: lint
Pixselve 9cd34ac
fix: imports
Pixselve 124976b
refactor: move locale utilities to internal API
Pixselve f716264
test(locale): add unit tests for normalizeStartOfWeek function
Pixselve File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| import { mergeLocales } from '../merge-locales'; | ||
|
|
||
| test('should return the first locale if it is fully specified', () => { | ||
| expect(mergeLocales('en-US', 'fr-CA')).toEqual('en-US'); | ||
| }); | ||
|
|
||
| test('should return the second locale if it extends the first', () => { | ||
| expect(mergeLocales('en', 'en-US')).toEqual('en-US'); | ||
| }); | ||
|
|
||
| test('should return the first locale if the second is different', () => { | ||
| expect(mergeLocales('en', 'fr-CA')).toEqual('en'); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| import { normalizeLocale } from '../normalize-locale'; | ||
| import setOptions from './utils/intl-polyfill'; | ||
|
|
||
| function withDocumentLang(lang: string, callback: () => void) { | ||
| const htmlElement = document.querySelector('html'); | ||
| htmlElement!.setAttribute('lang', lang); | ||
| callback(); | ||
| htmlElement!.removeAttribute('lang'); | ||
| } | ||
|
|
||
| describe('normalizeLocale', () => { | ||
| let consoleSpy: jest.SpyInstance; | ||
| beforeEach(() => { | ||
| consoleSpy = jest.spyOn(console, 'warn'); | ||
| setOptions({ locale: 'en-US' }); | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| expect(consoleSpy).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| test('should return the provided value', () => { | ||
| expect(normalizeLocale('DatePickerTest', 'en-US')).toBe('en-US'); | ||
| }); | ||
|
|
||
| test('should extend provided value if it is short form', () => { | ||
| expect(normalizeLocale('DatePickerTest', 'en')).toBe('en-US'); | ||
| setOptions({ locale: 'en-GB' }); | ||
| expect(normalizeLocale('DatePickerTest', 'en')).toBe('en-GB'); | ||
| }); | ||
|
|
||
| test('should not extend the provided value if it starts from different language', () => { | ||
| expect(normalizeLocale('DatePickerTest', 'fr')).toBe('fr'); | ||
| }); | ||
|
|
||
| test('should replace underscores with dashes', () => { | ||
| expect(normalizeLocale('DatePickerTest', 'zh_CN')).toBe('zh-CN'); | ||
| }); | ||
|
|
||
| test('should warn if the provided value is in invalid format', () => { | ||
| expect(normalizeLocale('DatePickerTest', 'not-locale')).toBe('en-US'); | ||
| expect(consoleSpy).toHaveBeenCalledWith( | ||
| '[AwsUi] [DatePickerTest] Invalid locale provided: not-locale. Falling back to default' | ||
| ); | ||
| consoleSpy.mockReset(); | ||
| }); | ||
|
|
||
| test('should return document language by default', () => { | ||
| withDocumentLang('en', () => { | ||
| expect(normalizeLocale('DatePickerTest', null)).toBe('en-US'); | ||
| }); | ||
| }); | ||
|
|
||
| test('should not extend document language with locale if they do not match', () => { | ||
| withDocumentLang('fr', () => { | ||
| expect(normalizeLocale('DatePickerTest', null)).toBe('fr'); | ||
| }); | ||
| }); | ||
|
|
||
| test('should combine values from document lang and browser locale', () => { | ||
| setOptions({ locale: 'fr-CA' }); | ||
| withDocumentLang('fr', () => { | ||
| expect(normalizeLocale('DatePickerTest', null)).toBe('fr-CA'); | ||
| }); | ||
| }); | ||
|
|
||
| test('should replace underscores with dashes in document lang', () => { | ||
| withDocumentLang('zh_CN', () => { | ||
| expect(normalizeLocale('DatePickerTest', null)).toBe('zh-CN'); | ||
| }); | ||
| }); | ||
| }); |
46 changes: 46 additions & 0 deletions
46
src/internal/locale/__tests__/normalize-start-of-week.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| import { normalizeStartOfWeek } from '../normalize-start-of-week'; | ||
|
|
||
| // Mock the weekstart module | ||
| jest.mock('weekstart', () => ({ | ||
| getWeekStartByLocale: jest.fn(), | ||
| })); | ||
|
|
||
| import { getWeekStartByLocale } from 'weekstart'; | ||
|
|
||
| const mockGetWeekStartByLocale = getWeekStartByLocale as jest.MockedFunction<typeof getWeekStartByLocale>; | ||
|
|
||
| describe('normalizeStartOfWeek', () => { | ||
| beforeEach(() => { | ||
| mockGetWeekStartByLocale.mockReset(); | ||
| }); | ||
|
|
||
| describe('when startOfWeek is undefined', () => { | ||
| test('should call getWeekStartByLocale with the provided locale', () => { | ||
| mockGetWeekStartByLocale.mockReturnValue(0); | ||
| const result = normalizeStartOfWeek(undefined, 'en-US'); | ||
|
|
||
| expect(mockGetWeekStartByLocale).toHaveBeenCalledWith('en-US'); | ||
| expect(mockGetWeekStartByLocale).toHaveBeenCalledTimes(1); | ||
| expect(result).toBe(0); | ||
| }); | ||
|
|
||
| test('should return Sunday (0) for US locale', () => { | ||
| mockGetWeekStartByLocale.mockReturnValue(0); | ||
| expect(normalizeStartOfWeek(undefined, 'en-US')).toBe(0); | ||
| }); | ||
|
|
||
| test('should return Monday (1) for French locale', () => { | ||
| mockGetWeekStartByLocale.mockReturnValue(1); | ||
| expect(normalizeStartOfWeek(undefined, 'fr-FR')).toBe(1); | ||
| }); | ||
| }); | ||
|
|
||
| test('should prioritize provided number over locale', () => { | ||
| mockGetWeekStartByLocale.mockReturnValue(0); | ||
| expect(normalizeStartOfWeek(1, 'en-US')).toBe(1); | ||
| expect(mockGetWeekStartByLocale).not.toHaveBeenCalled(); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| // We use resolvedOptions to detect browser locale. This method allows us to override the value for testing. | ||
| export default function setResolvedOptions(newValue: { locale: string }): void { | ||
| const dateTimeFormat = new Intl.DateTimeFormat(newValue.locale); | ||
| const resolvedOptions = dateTimeFormat.resolvedOptions(); | ||
|
|
||
| window.Intl.DateTimeFormat.prototype.resolvedOptions = () => ({ ...resolvedOptions, ...newValue }); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| export { mergeLocales } from './merge-locales'; | ||
| export { normalizeLocale } from './normalize-locale'; | ||
| export { DayIndex, normalizeStartOfWeek } from './normalize-start-of-week'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| export function mergeLocales(locale: string, fullLocale: string) { | ||
| const isShort = locale.length === 2; | ||
| if (isShort && fullLocale.indexOf(locale) === 0) { | ||
| return fullLocale; | ||
| } | ||
| return locale; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| import { warnOnce } from '../logging'; | ||
|
|
||
| import { mergeLocales } from './merge-locales'; | ||
|
|
||
| export function normalizeLocale(component: string, locale: string | null): string { | ||
| locale = checkLocale(component, locale); | ||
| const browserLocale = getBrowserLocale(); | ||
| if (locale) { | ||
| return mergeLocales(locale, browserLocale); | ||
| } | ||
| const htmlLocale = checkLocale(component, getHtmlElement()?.getAttribute('lang')); | ||
| if (htmlLocale) { | ||
| return mergeLocales(htmlLocale, browserLocale); | ||
| } | ||
| return browserLocale; | ||
| } | ||
|
|
||
| function checkLocale(component: string, locale: string | null | undefined): string { | ||
| if (!locale || locale === '') { | ||
| return ''; | ||
| } | ||
|
|
||
| // Support underscore-delimited locales | ||
| locale = locale && locale.replace(/^([a-z]{2})_/, '$1-'); | ||
| // Check that the value matches aa-BB pattern | ||
| // TODO: support full BCP 47 spec? | ||
|
Check warning on line 29 in src/internal/locale/normalize-locale.ts
|
||
| if (locale && !locale.match(/^[a-z]{2}(-[A-Z]{2})?$/)) { | ||
| warnOnce(component, `Invalid locale provided: ${locale}. Falling back to default`); | ||
| locale = ''; | ||
| } | ||
| return locale; | ||
| } | ||
|
|
||
| function getHtmlElement() { | ||
| return typeof document !== 'undefined' ? document.querySelector('html') : null; | ||
| } | ||
|
|
||
| function getBrowserLocale() { | ||
| return new Intl.DateTimeFormat().resolvedOptions().locale; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| import { getWeekStartByLocale } from 'weekstart'; | ||
|
|
||
| export type DayIndex = 0 | 1 | 2 | 3 | 4 | 5 | 6; | ||
|
|
||
| export function normalizeStartOfWeek(startOfWeek: number | undefined, locale: string) { | ||
| return (typeof startOfWeek === 'number' ? startOfWeek % 7 : getWeekStartByLocale(locale)) as DayIndex; | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I see that this function does not have its own coverage (also not in components) and since we are now exporting as part of this package, I think it is more necessary. Could you add some coverage? A couple cases where the start of the week is different would suffice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added 👍