@prezly/theme-kit-nextjs 1.11.2 → 1.12.0-0
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.
- package/build/adapter-nextjs/index.js +5 -1
- package/build/adapter-nextjs/index.js.map +1 -1
- package/build/adapter-nextjs/page-props/index.js +5 -1
- package/build/adapter-nextjs/page-props/index.js.map +1 -1
- package/build/adapter-nextjs/page-props/sitemap/index.js +5 -1
- package/build/adapter-nextjs/page-props/sitemap/index.js.map +1 -1
- package/build/components-nextjs/PageSeo/PageSeo.js +1 -1
- package/build/components-nextjs/PageSeo/PageSeo.js.map +1 -1
- package/build/components-nextjs/PageSeo/index.js +5 -1
- package/build/components-nextjs/PageSeo/index.js.map +1 -1
- package/build/components-nextjs/StorySeo/StorySeo.js +1 -1
- package/build/components-nextjs/StorySeo/StorySeo.js.map +1 -1
- package/build/data-fetching/api/PrezlyApi.js +4 -1
- package/build/data-fetching/api/PrezlyApi.js.map +1 -1
- package/build/data-fetching/api/index.js +5 -1
- package/build/data-fetching/api/index.js.map +1 -1
- package/build/data-fetching/index.js +5 -1
- package/build/data-fetching/index.js.map +1 -1
- package/build/index.js +5 -1
- package/build/index.js.map +1 -1
- package/build/infinite-loading/index.js +5 -1
- package/build/infinite-loading/index.js.map +1 -1
- package/build/intl/index.js +5 -1
- package/build/intl/index.js.map +1 -1
- package/build/intl/languages.d.ts +2 -0
- package/build/intl/languages.js +8 -13
- package/build/intl/languages.js.map +1 -1
- package/build/intl/locale.js +5 -1
- package/build/intl/locale.js.map +1 -1
- package/build/intl/localeList.js +1 -0
- package/build/intl/localeList.js.map +1 -1
- package/build/intl/localeObject.js +1 -1
- package/build/intl/localeObject.js.map +1 -1
- package/build/newsroom-context/context.js +1 -1
- package/build/newsroom-context/context.js.map +1 -1
- package/build/newsroom-context/hooks/index.js +5 -1
- package/build/newsroom-context/hooks/index.js.map +1 -1
- package/build/newsroom-context/hooks/useGetLinkLocaleSlug.d.ts +1 -1
- package/build/newsroom-context/hooks/useGetTranslationUrl.d.ts +1 -1
- package/build/newsroom-context/index.js +5 -1
- package/build/newsroom-context/index.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/utils/index.js +5 -1
- package/build/utils/index.js.map +1 -1
- package/package.json +15 -15
- package/src/__mocks__/languages.ts +365 -0
- package/src/__mocks__/story.ts +350 -0
- package/src/data-fetching/api/PrezlyApi.ts +4 -1
- package/src/intl/languages.test.ts +217 -0
- package/src/intl/languages.ts +8 -14
- package/src/intl/locale.test.ts +94 -0
- package/src/intl/locale.ts +7 -1
- package/src/intl/localeList.js +1 -0
- package/src/intl/localeObject.test.ts +78 -0
- package/src/intl/localeObject.ts +1 -1
package/src/intl/languages.ts
CHANGED
|
@@ -71,6 +71,7 @@ export function getLanguageByNeutralLocaleCode(
|
|
|
71
71
|
|
|
72
72
|
// Prefer default language
|
|
73
73
|
const defaultLanguage = getDefaultLanguage(languages);
|
|
74
|
+
// TODO: This doesn't align with other methods logic
|
|
74
75
|
if (defaultLanguage.code === locale.toUnderscoreCode()) {
|
|
75
76
|
return defaultLanguage;
|
|
76
77
|
}
|
|
@@ -79,8 +80,7 @@ export function getLanguageByNeutralLocaleCode(
|
|
|
79
80
|
const usedLanguages = getUsedLanguages(languages);
|
|
80
81
|
const usedLanguage = usedLanguages.find(
|
|
81
82
|
({ code }) =>
|
|
82
|
-
LocaleObject.fromAnyCode(code).toNeutralLanguageCode() === neutralLanguageCode
|
|
83
|
-
code === neutralLanguageCode,
|
|
83
|
+
LocaleObject.fromAnyCode(code).toNeutralLanguageCode() === neutralLanguageCode,
|
|
84
84
|
);
|
|
85
85
|
if (usedLanguage) {
|
|
86
86
|
return usedLanguage;
|
|
@@ -89,8 +89,7 @@ export function getLanguageByNeutralLocaleCode(
|
|
|
89
89
|
// Search in all languages
|
|
90
90
|
return languages.find(
|
|
91
91
|
({ code }) =>
|
|
92
|
-
LocaleObject.fromAnyCode(code).toNeutralLanguageCode() === neutralLanguageCode
|
|
93
|
-
code === neutralLanguageCode,
|
|
92
|
+
LocaleObject.fromAnyCode(code).toNeutralLanguageCode() === neutralLanguageCode,
|
|
94
93
|
);
|
|
95
94
|
}
|
|
96
95
|
|
|
@@ -144,9 +143,6 @@ export function getLanguageFromNextLocaleIsoCode(
|
|
|
144
143
|
getLanguageByExactLocaleCode(languages, locale) ||
|
|
145
144
|
getLanguageByNeutralLocaleCode(languages, locale) ||
|
|
146
145
|
getLanguageByShortRegionCode(languages, locale);
|
|
147
|
-
if (targetLanguage) {
|
|
148
|
-
return targetLanguage;
|
|
149
|
-
}
|
|
150
146
|
} else {
|
|
151
147
|
targetLanguage = getLanguageByExactLocaleCode(languages, locale);
|
|
152
148
|
}
|
|
@@ -175,6 +171,8 @@ export function getCompanyInformation(languages: NewsroomLanguageSettings[], loc
|
|
|
175
171
|
* First: try shorting to neutral language code (there should be no locales with the same language code)
|
|
176
172
|
* Then: try shorting to region code (there should be no locales with the same region code)
|
|
177
173
|
* Finally: return the original locale code (shorting is not possible)
|
|
174
|
+
*
|
|
175
|
+
* @param locale A LocaleObject constructed from FULL locale code (taken straight from the selected language)
|
|
178
176
|
*/
|
|
179
177
|
export function getShortestLocaleCode(
|
|
180
178
|
languages: NewsroomLanguageSettings[],
|
|
@@ -189,11 +187,6 @@ export function getShortestLocaleCode(
|
|
|
189
187
|
|
|
190
188
|
// Try shorting to neutral language code
|
|
191
189
|
const neutralLanguageCode = locale.toNeutralLanguageCode();
|
|
192
|
-
// The code is already as short as possible
|
|
193
|
-
if (neutralLanguageCode === localeCode) {
|
|
194
|
-
return localeCode;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
190
|
const matchingLanguagesByNeutralCode = languages.filter(
|
|
198
191
|
({ code }) =>
|
|
199
192
|
LocaleObject.fromAnyCode(code).toNeutralLanguageCode() === neutralLanguageCode ||
|
|
@@ -209,10 +202,11 @@ export function getShortestLocaleCode(
|
|
|
209
202
|
({ code }) => LocaleObject.fromAnyCode(code).toRegionCode() === shortRegionCode,
|
|
210
203
|
);
|
|
211
204
|
// Prevent collision with neutral language codes
|
|
205
|
+
const lowerCasedShortRegionCode = shortRegionCode.toLowerCase();
|
|
212
206
|
const mathchingNeutralLanguagesByRegionCode = languages.filter(
|
|
213
207
|
({ code }) =>
|
|
214
|
-
LocaleObject.fromAnyCode(code).toNeutralLanguageCode() ===
|
|
215
|
-
code ===
|
|
208
|
+
LocaleObject.fromAnyCode(code).toNeutralLanguageCode() === lowerCasedShortRegionCode ||
|
|
209
|
+
code === lowerCasedShortRegionCode,
|
|
216
210
|
);
|
|
217
211
|
if (
|
|
218
212
|
matchingLanguagesByRegionCode.length === 1 &&
|
|
@@ -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
|
+
});
|
package/src/intl/locale.ts
CHANGED
|
@@ -51,6 +51,7 @@ const SUPPORTED_LOCALES = [
|
|
|
51
51
|
'sk',
|
|
52
52
|
'sl',
|
|
53
53
|
'sv',
|
|
54
|
+
'sw',
|
|
54
55
|
'th',
|
|
55
56
|
'tr',
|
|
56
57
|
'uk',
|
|
@@ -74,7 +75,7 @@ export function getSupportedLocaleIsoCode(locale: LocaleObject): string {
|
|
|
74
75
|
return localeIsoCode;
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
const language =
|
|
78
|
+
const language = locale.toNeutralLanguageCode();
|
|
78
79
|
const isSupportedLanguage = SUPPORTED_LOCALES.includes(language);
|
|
79
80
|
if (isSupportedLanguage) {
|
|
80
81
|
return language;
|
|
@@ -88,6 +89,11 @@ export function getSupportedLocaleIsoCode(locale: LocaleObject): string {
|
|
|
88
89
|
return 'zh-CN';
|
|
89
90
|
}
|
|
90
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
|
+
);
|
|
91
97
|
return DEFAULT_LOCALE;
|
|
92
98
|
}
|
|
93
99
|
|
package/src/intl/localeList.js
CHANGED
|
@@ -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
|
+
});
|
package/src/intl/localeObject.ts
CHANGED
|
@@ -13,7 +13,7 @@ export class LocaleObject {
|
|
|
13
13
|
private localeCode: string;
|
|
14
14
|
|
|
15
15
|
private constructor(localeCode: string) {
|
|
16
|
-
if (
|
|
16
|
+
if (!/^([a-zA-Z]+)-?([a-zA-Z\d]+)$/.test(localeCode)) {
|
|
17
17
|
throw new Error('Invalid locale code provided!');
|
|
18
18
|
}
|
|
19
19
|
|