@prezly/theme-kit-nextjs 1.11.4 → 1.12.0-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,94 @@
1
+ import {
2
+ DEFAULT_LOCALE,
3
+ DUMMY_DEFAULT_LOCALE,
4
+ getLocaleDirection,
5
+ getRedirectToCanonicalLocale,
6
+ getSupportedLocaleIsoCode,
7
+ } from './locale';
8
+ import { LocaleObject } from './localeObject';
9
+
10
+ describe('getSupportedLocaleIsoCode', () => {
11
+ it('returns a code by exact match', () => {
12
+ expect(getSupportedLocaleIsoCode(LocaleObject.fromAnyCode('en'))).toBe('en');
13
+ expect(getSupportedLocaleIsoCode(LocaleObject.fromAnyCode('af'))).toBe('af');
14
+ expect(getSupportedLocaleIsoCode(LocaleObject.fromAnyCode('pt-BR'))).toBe('pt-BR');
15
+ });
16
+
17
+ it('returns a code by neutral language code match', () => {
18
+ expect(getSupportedLocaleIsoCode(LocaleObject.fromAnyCode('en-US'))).toBe('en');
19
+ expect(getSupportedLocaleIsoCode(LocaleObject.fromAnyCode('de-DE'))).toBe('de');
20
+ expect(getSupportedLocaleIsoCode(LocaleObject.fromAnyCode('uk-UA'))).toBe('uk');
21
+ });
22
+
23
+ it('returns custom mapped codes for Chinese locales', () => {
24
+ expect(getSupportedLocaleIsoCode(LocaleObject.fromAnyCode('zh-Hant'))).toBe('zh-TW');
25
+ expect(getSupportedLocaleIsoCode(LocaleObject.fromAnyCode('zh-HK'))).toBe('zh-CN');
26
+ });
27
+
28
+ it('returns default locale code for unsupported languages', () => {
29
+ const consoleSpy = jest.spyOn(console, 'warn');
30
+
31
+ // @ts-expect-error
32
+ expect(getSupportedLocaleIsoCode(new LocaleObject('aa'))).toBe(DEFAULT_LOCALE);
33
+ expect(consoleSpy).toHaveBeenCalledWith(
34
+ 'Unsupported locale provided. Please use `LocaleObject.fromAnyCode` to ensure you are using a correct language code',
35
+ );
36
+ });
37
+ });
38
+
39
+ describe('getRedirectToCanonicalLocale', () => {
40
+ it('returns undefined when no locale or dummy locale is provided', () => {
41
+ expect(getRedirectToCanonicalLocale('en', undefined, '/')).toBe(undefined);
42
+ expect(getRedirectToCanonicalLocale('en', DUMMY_DEFAULT_LOCALE, '/')).toBe(undefined);
43
+ });
44
+
45
+ it('returns undefined when locale is already canonical', () => {
46
+ expect(getRedirectToCanonicalLocale('en', 'en', '/')).toBe(undefined);
47
+ expect(getRedirectToCanonicalLocale('nl_BE', 'nl-be', '/')).toBe(undefined);
48
+ });
49
+
50
+ it('returns a redirect object when requested locale is not canonical', () => {
51
+ expect(getRedirectToCanonicalLocale(false, 'en-us', '/test')).toEqual({
52
+ destination: '/test',
53
+ permanent: false,
54
+ });
55
+
56
+ expect(getRedirectToCanonicalLocale('en', 'en-us', '/test')).toEqual({
57
+ destination: '/en/test',
58
+ permanent: false,
59
+ });
60
+
61
+ expect(getRedirectToCanonicalLocale('en', 'en-us', 'test')).toEqual({
62
+ destination: '/en/test',
63
+ permanent: false,
64
+ });
65
+ });
66
+
67
+ it('preserves query parameters', () => {
68
+ expect(
69
+ getRedirectToCanonicalLocale('en', 'en-us', '/test', {
70
+ page: '1',
71
+ tags: ['story', 'media'],
72
+ }),
73
+ ).toEqual({
74
+ destination: '/en/test?page=1&tags=story&tags=media',
75
+ permanent: false,
76
+ });
77
+ });
78
+ });
79
+
80
+ describe('getLocaleDirection', () => {
81
+ it('returns `rtl` for right-to-left languages', () => {
82
+ const RTL_LANGUAGES = ['ar', 'ar-AE', 'ar-BH', 'ar-QA', 'ar-SA', 'he-IL', 'ur-PK'];
83
+ RTL_LANGUAGES.forEach((language) => {
84
+ expect(getLocaleDirection(LocaleObject.fromAnyCode(language))).toBe('rtl');
85
+ });
86
+ });
87
+
88
+ it('returns `ltr` for other languages', () => {
89
+ const LTR_LANGUAGES = ['en', 'en-US', 'fr-FR', 'fil', 'pt-BR', 'nl', 'nl-BE'];
90
+ LTR_LANGUAGES.forEach((language) => {
91
+ expect(getLocaleDirection(LocaleObject.fromAnyCode(language))).toBe('ltr');
92
+ });
93
+ });
94
+ });
@@ -75,7 +75,7 @@ export function getSupportedLocaleIsoCode(locale: LocaleObject): string {
75
75
  return localeIsoCode;
76
76
  }
77
77
 
78
- const language = localeIsoCode.slice(0, 2);
78
+ const language = locale.toNeutralLanguageCode();
79
79
  const isSupportedLanguage = SUPPORTED_LOCALES.includes(language);
80
80
  if (isSupportedLanguage) {
81
81
  return language;
@@ -89,6 +89,11 @@ export function getSupportedLocaleIsoCode(locale: LocaleObject): string {
89
89
  return 'zh-CN';
90
90
  }
91
91
 
92
+ // This code should never be reached, because locale code check is happening in `LocaleObject.fromAnyCode`
93
+ // eslint-disable-next-line no-console
94
+ console.warn(
95
+ 'Unsupported locale provided. Please use `LocaleObject.fromAnyCode` to ensure you are using a correct language code',
96
+ );
92
97
  return DEFAULT_LOCALE;
93
98
  }
94
99
 
@@ -0,0 +1,78 @@
1
+ import { LocaleObject } from './localeObject';
2
+
3
+ it('throws when created from invalid code', () => {
4
+ // @ts-expect-error
5
+ expect(() => new LocaleObject('en_US')).toThrow('Invalid locale code provided!');
6
+ // @ts-expect-error
7
+ expect(() => new LocaleObject('1234')).toThrow('Invalid locale code provided!');
8
+ // @ts-expect-error
9
+ expect(() => new LocaleObject('*!en-US')).toThrow('Invalid locale code provided!');
10
+ });
11
+
12
+ it('throws when created with unsupported code', () => {
13
+ const unsupportedCode = 'unknown-code';
14
+ expect(() => LocaleObject.fromAnyCode(unsupportedCode)).toThrow(
15
+ `Unsupported locale code provided: "${unsupportedCode}"`,
16
+ );
17
+ });
18
+
19
+ it('accepts any valid code type and converts it to hyphen code consistently', () => {
20
+ expect(LocaleObject.fromAnyCode('en').toHyphenCode()).toBe('en');
21
+ expect(LocaleObject.fromAnyCode('en-us').toHyphenCode()).toBe('en-US');
22
+ expect(LocaleObject.fromAnyCode('en-US').toHyphenCode()).toBe('en-US');
23
+ expect(LocaleObject.fromAnyCode('EN-US').toHyphenCode()).toBe('en-US');
24
+ expect(LocaleObject.fromAnyCode('en_us').toHyphenCode()).toBe('en-US');
25
+ expect(LocaleObject.fromAnyCode('en_US').toHyphenCode()).toBe('en-US');
26
+ expect(LocaleObject.fromAnyCode('EN_US').toHyphenCode()).toBe('en-US');
27
+ });
28
+
29
+ it('converts to underscore code consistently', () => {
30
+ expect(LocaleObject.fromAnyCode('en').toUnderscoreCode()).toBe('en');
31
+ expect(LocaleObject.fromAnyCode('en-us').toUnderscoreCode()).toBe('en_US');
32
+ expect(LocaleObject.fromAnyCode('en-US').toUnderscoreCode()).toBe('en_US');
33
+ expect(LocaleObject.fromAnyCode('EN-US').toUnderscoreCode()).toBe('en_US');
34
+ expect(LocaleObject.fromAnyCode('en_us').toUnderscoreCode()).toBe('en_US');
35
+ expect(LocaleObject.fromAnyCode('en_US').toUnderscoreCode()).toBe('en_US');
36
+ expect(LocaleObject.fromAnyCode('EN_US').toUnderscoreCode()).toBe('en_US');
37
+ });
38
+
39
+ it('converts to URL slug consistently', () => {
40
+ expect(LocaleObject.fromAnyCode('en').toUrlSlug()).toBe('en');
41
+ expect(LocaleObject.fromAnyCode('en-us').toUrlSlug()).toBe('en-us');
42
+ expect(LocaleObject.fromAnyCode('en-US').toUrlSlug()).toBe('en-us');
43
+ expect(LocaleObject.fromAnyCode('EN-US').toUrlSlug()).toBe('en-us');
44
+ expect(LocaleObject.fromAnyCode('en_us').toUrlSlug()).toBe('en-us');
45
+ expect(LocaleObject.fromAnyCode('en_US').toUrlSlug()).toBe('en-us');
46
+ expect(LocaleObject.fromAnyCode('EN_US').toUrlSlug()).toBe('en-us');
47
+ });
48
+
49
+ it('converts to neutral language code consistently', () => {
50
+ expect(LocaleObject.fromAnyCode('en').toNeutralLanguageCode()).toBe('en');
51
+ expect(LocaleObject.fromAnyCode('en-us').toNeutralLanguageCode()).toBe('en');
52
+ expect(LocaleObject.fromAnyCode('en-US').toNeutralLanguageCode()).toBe('en');
53
+ expect(LocaleObject.fromAnyCode('EN-US').toNeutralLanguageCode()).toBe('en');
54
+ expect(LocaleObject.fromAnyCode('en_us').toNeutralLanguageCode()).toBe('en');
55
+ expect(LocaleObject.fromAnyCode('en_US').toNeutralLanguageCode()).toBe('en');
56
+ expect(LocaleObject.fromAnyCode('EN_US').toNeutralLanguageCode()).toBe('en');
57
+ });
58
+
59
+ it('converts to region code consistently', () => {
60
+ expect(LocaleObject.fromAnyCode('en').toRegionCode()).toBe('EN');
61
+ expect(LocaleObject.fromAnyCode('en-us').toRegionCode()).toBe('US');
62
+ expect(LocaleObject.fromAnyCode('en-US').toRegionCode()).toBe('US');
63
+ expect(LocaleObject.fromAnyCode('EN-US').toRegionCode()).toBe('US');
64
+ expect(LocaleObject.fromAnyCode('en_us').toRegionCode()).toBe('US');
65
+ expect(LocaleObject.fromAnyCode('en_US').toRegionCode()).toBe('US');
66
+ expect(LocaleObject.fromAnyCode('EN_US').toRegionCode()).toBe('US');
67
+ });
68
+
69
+ it('can compare two objects', () => {
70
+ const enUsLocale = LocaleObject.fromAnyCode('en-US');
71
+ const enUsLocaleDuplicate = LocaleObject.fromAnyCode('en-US');
72
+ const deDeLocale = LocaleObject.fromAnyCode('de-DE');
73
+
74
+ expect(enUsLocale.isEqual(enUsLocaleDuplicate)).toBe(true);
75
+ expect(enUsLocaleDuplicate.isEqual(enUsLocale)).toBe(true);
76
+ expect(enUsLocale.isEqual(deDeLocale)).toBe(false);
77
+ expect(deDeLocale.isEqual(enUsLocale)).toBe(false);
78
+ });
@@ -13,7 +13,7 @@ export class LocaleObject {
13
13
  private localeCode: string;
14
14
 
15
15
  private constructor(localeCode: string) {
16
- if (localeCode.indexOf('_') !== -1) {
16
+ if (!/^([a-zA-Z]+)-?([a-zA-Z\d]+)$/.test(localeCode)) {
17
17
  throw new Error('Invalid locale code provided!');
18
18
  }
19
19