@bleedingdev/modern-js-plugin-i18n 3.9.0-ultramodern.9 → 3.9.3-ultramodern.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.
- package/dist/cjs/cli/index.js +1 -1
- package/dist/cjs/cli/localisedRoutes.js +3 -2
- package/dist/cjs/runtime/context.js +6 -14
- package/dist/cjs/runtime/contexts.js +49 -0
- package/dist/cjs/runtime/core.js +8 -1
- package/dist/cjs/runtime/i18n/detection/middleware.js +1 -1
- package/dist/cjs/runtime/i18n/detection/middleware.node.js +10 -1
- package/dist/cjs/runtime/i18n/detection/priority.js +1 -1
- package/dist/cjs/runtime/navigation.js +48 -0
- package/dist/cjs/runtime/routerAdapter.js +3 -5
- package/dist/cjs/runtime/sharedContexts.js +43 -0
- package/dist/cjs/shared/detection.js +118 -2
- package/dist/esm/cli/index.mjs +1 -1
- package/dist/esm/cli/localisedRoutes.mjs +3 -2
- package/dist/esm/runtime/context.mjs +2 -10
- package/dist/esm/runtime/contexts.mjs +5 -0
- package/dist/esm/runtime/core.mjs +3 -2
- package/dist/esm/runtime/i18n/detection/middleware.mjs +1 -1
- package/dist/esm/runtime/i18n/detection/middleware.node.mjs +10 -1
- package/dist/esm/runtime/i18n/detection/priority.mjs +1 -1
- package/dist/esm/runtime/navigation.mjs +7 -0
- package/dist/esm/runtime/routerAdapter.mjs +2 -4
- package/dist/esm/runtime/sharedContexts.mjs +1 -0
- package/dist/esm/shared/detection.mjs +85 -1
- package/dist/esm-node/cli/index.mjs +1 -1
- package/dist/esm-node/cli/localisedRoutes.mjs +3 -2
- package/dist/esm-node/runtime/context.mjs +2 -10
- package/dist/esm-node/runtime/contexts.mjs +6 -0
- package/dist/esm-node/runtime/core.mjs +3 -2
- package/dist/esm-node/runtime/i18n/detection/middleware.mjs +1 -1
- package/dist/esm-node/runtime/i18n/detection/middleware.node.mjs +10 -1
- package/dist/esm-node/runtime/i18n/detection/priority.mjs +1 -1
- package/dist/esm-node/runtime/navigation.mjs +8 -0
- package/dist/esm-node/runtime/routerAdapter.mjs +2 -4
- package/dist/esm-node/runtime/sharedContexts.mjs +2 -0
- package/dist/esm-node/shared/detection.mjs +85 -1
- package/dist/types/cli/localisedRoutes.d.ts +3 -2
- package/dist/types/runtime/context.d.ts +2 -2
- package/dist/types/runtime/contexts.d.ts +6 -0
- package/dist/types/runtime/core.d.ts +1 -0
- package/dist/types/runtime/i18n/detection/middleware.d.ts +1 -1
- package/dist/types/runtime/i18n/detection/middleware.node.d.ts +1 -5
- package/dist/types/runtime/navigation.d.ts +10 -0
- package/dist/types/runtime/sharedContexts.d.ts +1 -0
- package/dist/types/shared/detection.d.ts +11 -1
- package/package.json +43 -25
- package/src/cli/index.ts +1 -0
- package/src/cli/localisedRoutes.ts +11 -1
- package/src/runtime/context.tsx +6 -31
- package/src/runtime/contexts.ts +16 -0
- package/src/runtime/core.tsx +12 -1
- package/src/runtime/i18n/detection/middleware.node.ts +25 -7
- package/src/runtime/i18n/detection/middleware.ts +2 -0
- package/src/runtime/i18n/detection/priority.ts +2 -0
- package/src/runtime/navigation.tsx +20 -0
- package/src/runtime/routerAdapter.tsx +2 -11
- package/src/runtime/sharedContexts.ts +8 -0
- package/src/shared/detection.ts +34 -10
- package/rslib.config.mts +0 -4
- package/rstest.config.mts +0 -50
- package/tests/backendDefaults.test.ts +0 -30
- package/tests/defaultUrlStrategy.test.ts +0 -107
- package/tests/federatedI18nBoundaryResolver.test.tsx +0 -65
- package/tests/i18nUtils.test.ts +0 -60
- package/tests/link.test.tsx +0 -139
- package/tests/localisedRouteGeneration.test.ts +0 -159
- package/tests/localisedUrls.test.ts +0 -193
- package/tests/mappedUrlStrategyDerivation.test.ts +0 -62
- package/tests/reactI18nextRuntimeBoundary.test.ts +0 -117
- package/tests/redirectPolicy.test.ts +0 -107
- package/tests/routerAdapter.test.tsx +0 -221
- package/tests/urlStrategySerialization.test.ts +0 -122
- package/tsconfig.json +0 -15
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from '@rstest/core';
|
|
2
|
-
import { shouldIgnoreRedirect as shouldIgnoreRuntimeRedirect } from '../src/runtime/utils';
|
|
3
|
-
import {
|
|
4
|
-
isStaticResourceRequest,
|
|
5
|
-
shouldIgnoreRedirect as shouldIgnoreServerRedirect,
|
|
6
|
-
} from '../src/server/redirectPolicy';
|
|
7
|
-
|
|
8
|
-
describe('native locale redirect safeguards', () => {
|
|
9
|
-
test('never locale-redirects federation artifacts, with no URL strategy configured', () => {
|
|
10
|
-
// 3.9.0-ultramodern.9 regression: with `localisedUrls: {}` no strategy is
|
|
11
|
-
// derived, and the backend federation manifest was redirected to
|
|
12
|
-
// `/en/backend-mf-manifest.json` (an HTML page) — the Node backend
|
|
13
|
-
// federation proof then read a 404 instead of the manifest.
|
|
14
|
-
const languages = ['en', 'cs'];
|
|
15
|
-
for (const pathname of [
|
|
16
|
-
'/backend-mf-manifest.json',
|
|
17
|
-
'/backendRemoteEntry.cjs',
|
|
18
|
-
'/mf-manifest.json',
|
|
19
|
-
'/mf-stats.json',
|
|
20
|
-
'/remoteEntry.js',
|
|
21
|
-
'/remoteEntry.catalog.js',
|
|
22
|
-
'/backendRemoteEntry.catalog.cjs',
|
|
23
|
-
'/cs/backend-mf-manifest.json',
|
|
24
|
-
]) {
|
|
25
|
-
expect(
|
|
26
|
-
shouldIgnoreServerRedirect(
|
|
27
|
-
pathname,
|
|
28
|
-
'/*',
|
|
29
|
-
undefined,
|
|
30
|
-
undefined,
|
|
31
|
-
languages,
|
|
32
|
-
),
|
|
33
|
-
).toBe(true);
|
|
34
|
-
expect(
|
|
35
|
-
shouldIgnoreServerRedirect(
|
|
36
|
-
`/app${pathname}`,
|
|
37
|
-
'/app/*',
|
|
38
|
-
undefined,
|
|
39
|
-
undefined,
|
|
40
|
-
languages,
|
|
41
|
-
),
|
|
42
|
-
).toBe(true);
|
|
43
|
-
expect(
|
|
44
|
-
shouldIgnoreRuntimeRedirect(pathname, languages, undefined, undefined),
|
|
45
|
-
).toBe(true);
|
|
46
|
-
}
|
|
47
|
-
// A page is still redirected.
|
|
48
|
-
expect(
|
|
49
|
-
shouldIgnoreServerRedirect(
|
|
50
|
-
'/products',
|
|
51
|
-
'/*',
|
|
52
|
-
undefined,
|
|
53
|
-
undefined,
|
|
54
|
-
languages,
|
|
55
|
-
),
|
|
56
|
-
).toBe(false);
|
|
57
|
-
expect(
|
|
58
|
-
shouldIgnoreRuntimeRedirect('/products', languages, undefined, undefined),
|
|
59
|
-
).toBe(false);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test('retains configured ignores across runtime and server entry prefixes', () => {
|
|
63
|
-
const rules = ['/private'];
|
|
64
|
-
expect(
|
|
65
|
-
shouldIgnoreRuntimeRedirect('/cs/private/data', ['en', 'cs'], rules),
|
|
66
|
-
).toBe(true);
|
|
67
|
-
expect(
|
|
68
|
-
shouldIgnoreRuntimeRedirect('/cs/private-data', ['en', 'cs'], rules),
|
|
69
|
-
).toBe(false);
|
|
70
|
-
expect(
|
|
71
|
-
shouldIgnoreServerRedirect(
|
|
72
|
-
'/app/cs/private/data',
|
|
73
|
-
'/app/*',
|
|
74
|
-
rules,
|
|
75
|
-
undefined,
|
|
76
|
-
['en', 'cs'],
|
|
77
|
-
),
|
|
78
|
-
).toBe(true);
|
|
79
|
-
expect(
|
|
80
|
-
shouldIgnoreServerRedirect(
|
|
81
|
-
'/app/cs/private-data',
|
|
82
|
-
'/app/*',
|
|
83
|
-
rules,
|
|
84
|
-
undefined,
|
|
85
|
-
['en', 'cs'],
|
|
86
|
-
),
|
|
87
|
-
).toBe(false);
|
|
88
|
-
});
|
|
89
|
-
test('retains configured and native static paths without fork policy', () => {
|
|
90
|
-
for (const pathname of [
|
|
91
|
-
'/static/app.js',
|
|
92
|
-
'/upload/a.png',
|
|
93
|
-
'/cs/assets/main.js',
|
|
94
|
-
]) {
|
|
95
|
-
expect(isStaticResourceRequest(pathname, ['/assets'], ['en', 'cs'])).toBe(
|
|
96
|
-
true,
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
expect(
|
|
100
|
-
isStaticResourceRequest(
|
|
101
|
-
'/assets-other/main.js',
|
|
102
|
-
['/assets'],
|
|
103
|
-
['en', 'cs'],
|
|
104
|
-
),
|
|
105
|
-
).toBe(false);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
InternalRuntimeContext,
|
|
3
|
-
RuntimeContext,
|
|
4
|
-
} from '@modern-js/runtime/context';
|
|
5
|
-
import type React from 'react';
|
|
6
|
-
import type { PropsWithChildren } from 'react';
|
|
7
|
-
import { act, useEffect } from 'react';
|
|
8
|
-
import { createRoot, type Root } from 'react-dom/client';
|
|
9
|
-
import { ModernI18nProvider, useModernI18n } from '../src/runtime/context';
|
|
10
|
-
import type { I18nInstance } from '../src/runtime/i18n';
|
|
11
|
-
import { Link } from '../src/runtime/Link';
|
|
12
|
-
import {
|
|
13
|
-
createI18nRootWrapper,
|
|
14
|
-
type I18nLanguageSynchronizationProps,
|
|
15
|
-
} from '../src/runtime/providerComposition';
|
|
16
|
-
import {
|
|
17
|
-
I18nNavigationProvider,
|
|
18
|
-
useI18nRouterAdapter,
|
|
19
|
-
} from '../src/runtime/routerAdapter';
|
|
20
|
-
|
|
21
|
-
(
|
|
22
|
-
globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }
|
|
23
|
-
).IS_REACT_ACT_ENVIRONMENT = true;
|
|
24
|
-
|
|
25
|
-
const requestContext = {
|
|
26
|
-
request: {},
|
|
27
|
-
response: {},
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
function createI18nInstance(language = 'en'): I18nInstance {
|
|
31
|
-
return {
|
|
32
|
-
language,
|
|
33
|
-
isInitialized: true,
|
|
34
|
-
init: () => Promise.resolve(undefined),
|
|
35
|
-
use: () => {},
|
|
36
|
-
t: (key: string | string[]) => (Array.isArray(key) ? key[0] : key),
|
|
37
|
-
createInstance: () => createI18nInstance(language),
|
|
38
|
-
setLang: rstest.fn(async () => undefined),
|
|
39
|
-
changeLanguage: rstest.fn(async () => undefined),
|
|
40
|
-
services: {},
|
|
41
|
-
options: {},
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async function renderI18nRoot(node: React.ReactNode) {
|
|
46
|
-
const container = document.createElement('div');
|
|
47
|
-
document.body.appendChild(container);
|
|
48
|
-
const root = createRoot(container);
|
|
49
|
-
|
|
50
|
-
await act(async () => {
|
|
51
|
-
root.render(
|
|
52
|
-
<RuntimeContext.Provider
|
|
53
|
-
value={{
|
|
54
|
-
isBrowser: true,
|
|
55
|
-
requestContext,
|
|
56
|
-
context: requestContext,
|
|
57
|
-
}}
|
|
58
|
-
>
|
|
59
|
-
{node}
|
|
60
|
-
</RuntimeContext.Provider>,
|
|
61
|
-
);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
container,
|
|
66
|
-
root,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function cleanup(rendered?: { container: HTMLElement; root: Root }) {
|
|
71
|
-
if (!rendered) {
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
act(() => {
|
|
75
|
-
rendered.root.unmount();
|
|
76
|
-
});
|
|
77
|
-
rendered.container.remove();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
describe('i18n runtime wrapRoot', () => {
|
|
81
|
-
let rendered: { container: HTMLElement; root: Root } | undefined;
|
|
82
|
-
|
|
83
|
-
afterEach(() => {
|
|
84
|
-
cleanup(rendered);
|
|
85
|
-
rendered = undefined;
|
|
86
|
-
rstest.useRealTimers();
|
|
87
|
-
rstest.restoreAllMocks();
|
|
88
|
-
window.history.replaceState(null, '', '/');
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test('keeps the optional i18next provider inside Modern i18n context', async () => {
|
|
92
|
-
const i18nInstance = createI18nInstance('cs');
|
|
93
|
-
const observedLanguages: string[] = [];
|
|
94
|
-
const I18nextProvider = ({
|
|
95
|
-
children,
|
|
96
|
-
i18n,
|
|
97
|
-
}: PropsWithChildren<{ i18n: I18nInstance }>) => {
|
|
98
|
-
const { language } = useModernI18n();
|
|
99
|
-
observedLanguages.push(`${language}:${i18n.language}`);
|
|
100
|
-
|
|
101
|
-
return <section data-testid="i18next-provider">{children}</section>;
|
|
102
|
-
};
|
|
103
|
-
const App = () => <main>router content</main>;
|
|
104
|
-
const I18nRoot = createI18nRootWrapper({
|
|
105
|
-
htmlLangAttr: false,
|
|
106
|
-
localePathRedirect: false,
|
|
107
|
-
languages: ['en', 'cs'],
|
|
108
|
-
fallbackLanguage: 'en',
|
|
109
|
-
getLatestI18nInstance: () => i18nInstance,
|
|
110
|
-
getI18nextProvider: () => I18nextProvider,
|
|
111
|
-
})(App);
|
|
112
|
-
|
|
113
|
-
rendered = await renderI18nRoot(<I18nRoot />);
|
|
114
|
-
|
|
115
|
-
expect(observedLanguages).toEqual(['cs:cs']);
|
|
116
|
-
expect(rendered.container.textContent).toContain('router content');
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
describe('native navigation extension contract', () => {
|
|
121
|
-
test('renders the supplied router primitive and exposes provider-scoped navigation', async () => {
|
|
122
|
-
const navigate = rstest.fn();
|
|
123
|
-
const RouterLink = ({ to, children }: any) => (
|
|
124
|
-
<a href={to} data-native="yes">
|
|
125
|
-
{children}
|
|
126
|
-
</a>
|
|
127
|
-
);
|
|
128
|
-
function Consumer() {
|
|
129
|
-
const adapter = useI18nRouterAdapter();
|
|
130
|
-
expect(adapter.navigate).toBe(navigate);
|
|
131
|
-
expect(adapter.params).toEqual({ lang: 'cs' });
|
|
132
|
-
return <Link to="/products?tag=x#detail">Products</Link>;
|
|
133
|
-
}
|
|
134
|
-
const rendered = await renderI18nRoot(
|
|
135
|
-
<I18nNavigationProvider
|
|
136
|
-
value={{
|
|
137
|
-
hasRouter: true,
|
|
138
|
-
navigate,
|
|
139
|
-
params: { lang: 'cs' },
|
|
140
|
-
location: { pathname: '/cs/products', search: '', hash: '' },
|
|
141
|
-
Link: RouterLink,
|
|
142
|
-
}}
|
|
143
|
-
>
|
|
144
|
-
<ModernI18nProvider
|
|
145
|
-
value={{
|
|
146
|
-
language: 'cs',
|
|
147
|
-
i18nInstance: createI18nInstance('cs'),
|
|
148
|
-
languages: ['en', 'cs'],
|
|
149
|
-
localePathRedirect: true,
|
|
150
|
-
}}
|
|
151
|
-
>
|
|
152
|
-
<Consumer />
|
|
153
|
-
</ModernI18nProvider>
|
|
154
|
-
</I18nNavigationProvider>,
|
|
155
|
-
);
|
|
156
|
-
try {
|
|
157
|
-
expect(rendered.container.querySelector('a')?.getAttribute('href')).toBe(
|
|
158
|
-
'/cs/products?tag=x#detail',
|
|
159
|
-
);
|
|
160
|
-
expect(
|
|
161
|
-
rendered.container.querySelector('a')?.getAttribute('data-native'),
|
|
162
|
-
).toBe('yes');
|
|
163
|
-
expect(navigate).not.toHaveBeenCalled();
|
|
164
|
-
} finally {
|
|
165
|
-
cleanup(rendered);
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
describe('native synchronization extension contract', () => {
|
|
171
|
-
test('uses the supplied component callback and preserves its state across parent renders', async () => {
|
|
172
|
-
const instance = createI18nInstance('en');
|
|
173
|
-
const synchronize = rstest.fn();
|
|
174
|
-
const mounts = rstest.fn();
|
|
175
|
-
const observed: I18nLanguageSynchronizationProps[] = [];
|
|
176
|
-
const Synchronization = (props: I18nLanguageSynchronizationProps) => {
|
|
177
|
-
observed.push(props);
|
|
178
|
-
useEffect(() => {
|
|
179
|
-
mounts();
|
|
180
|
-
props.setLang('cs');
|
|
181
|
-
}, []);
|
|
182
|
-
return props.children(synchronize);
|
|
183
|
-
};
|
|
184
|
-
const Root = createI18nRootWrapper({
|
|
185
|
-
htmlLangAttr: false,
|
|
186
|
-
localePathRedirect: true,
|
|
187
|
-
languages: ['en', 'cs'],
|
|
188
|
-
fallbackLanguage: 'en',
|
|
189
|
-
getLatestI18nInstance: () => instance,
|
|
190
|
-
getI18nextProvider: () => null,
|
|
191
|
-
LanguageSynchronization: Synchronization,
|
|
192
|
-
})(() => {
|
|
193
|
-
const { language } = useModernI18n();
|
|
194
|
-
return <main>{language}</main>;
|
|
195
|
-
});
|
|
196
|
-
window.history.replaceState(null, '', '/cs/products');
|
|
197
|
-
const rendered = await renderI18nRoot(<Root />);
|
|
198
|
-
try {
|
|
199
|
-
expect(rendered.container.textContent).toBe('cs');
|
|
200
|
-
expect(synchronize).toHaveBeenCalledWith('cs');
|
|
201
|
-
expect(observed.at(-1)?.i18nInstance).toBe(instance);
|
|
202
|
-
expect(observed.at(-1)?.pathname).toBe('/cs/products');
|
|
203
|
-
expect(observed.at(-1)?.prevLangRef.current).toBe('cs');
|
|
204
|
-
await act(async () => {
|
|
205
|
-
rendered.root.render(
|
|
206
|
-
<RuntimeContext.Provider
|
|
207
|
-
value={{ isBrowser: true, requestContext, context: requestContext }}
|
|
208
|
-
>
|
|
209
|
-
<Root unrelated="updated" />
|
|
210
|
-
</RuntimeContext.Provider>,
|
|
211
|
-
);
|
|
212
|
-
});
|
|
213
|
-
expect(mounts).toHaveBeenCalledTimes(1);
|
|
214
|
-
expect(rendered.container.textContent).toBe('cs');
|
|
215
|
-
expect(instance.changeLanguage).not.toHaveBeenCalled();
|
|
216
|
-
} finally {
|
|
217
|
-
cleanup(rendered);
|
|
218
|
-
window.history.replaceState(null, '', '/');
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
});
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from '@rstest/core';
|
|
2
|
-
import { buildLocalizedUrl, shouldIgnoreRedirect } from '../src/runtime/utils';
|
|
3
|
-
import { resolveMappedUrlStrategy } from '../src/server/mappedUrlStrategy';
|
|
4
|
-
import {
|
|
5
|
-
buildLocalizedUrl as buildServerLocalizedUrl,
|
|
6
|
-
shouldIgnoreRedirect as shouldIgnoreServerRedirect,
|
|
7
|
-
} from '../src/server/redirectPolicy';
|
|
8
|
-
import {
|
|
9
|
-
asI18nUrlStrategy,
|
|
10
|
-
isUnusableI18nUrlStrategy,
|
|
11
|
-
} from '../src/shared/urlStrategy';
|
|
12
|
-
|
|
13
|
-
// What a configured `urlStrategy` looks like after the generated runtime
|
|
14
|
-
// registration has carried it through JSON: an object with no methods left.
|
|
15
|
-
const serializedStrategy = {} as any;
|
|
16
|
-
|
|
17
|
-
const workingStrategy = {
|
|
18
|
-
localizePathname: (pathname: string, language: string) =>
|
|
19
|
-
`/${language}${pathname}`,
|
|
20
|
-
canonicalPathname: (pathname: string) => pathname,
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const createRequest = (pathname: string) =>
|
|
24
|
-
({ url: `https://example.test${pathname}` }) as any;
|
|
25
|
-
|
|
26
|
-
describe('URL strategy that lost its methods in transit', () => {
|
|
27
|
-
test('is recognised as unusable rather than accepted', () => {
|
|
28
|
-
expect(asI18nUrlStrategy(serializedStrategy)).toBeUndefined();
|
|
29
|
-
expect(isUnusableI18nUrlStrategy(serializedStrategy)).toBe(true);
|
|
30
|
-
expect(isUnusableI18nUrlStrategy(undefined)).toBe(false);
|
|
31
|
-
expect(asI18nUrlStrategy(workingStrategy)).toBe(workingStrategy);
|
|
32
|
-
expect(isUnusableI18nUrlStrategy(workingStrategy)).toBe(false);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test('a partial strategy is unusable too', () => {
|
|
36
|
-
expect(asI18nUrlStrategy({ localizePathname: () => '/x' })).toBeUndefined();
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test('the client link builder falls back instead of throwing', () => {
|
|
40
|
-
expect(() =>
|
|
41
|
-
buildLocalizedUrl('/about', 'cs', ['en', 'cs'], serializedStrategy),
|
|
42
|
-
).not.toThrow();
|
|
43
|
-
expect(
|
|
44
|
-
buildLocalizedUrl('/about', 'cs', ['en', 'cs'], serializedStrategy),
|
|
45
|
-
).toBe('/cs/about');
|
|
46
|
-
expect(
|
|
47
|
-
buildLocalizedUrl('/about', 'cs', ['en', 'cs'], workingStrategy),
|
|
48
|
-
).toBe('/cs/about');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test('the client redirect check falls back instead of throwing', () => {
|
|
52
|
-
expect(() =>
|
|
53
|
-
shouldIgnoreRedirect(
|
|
54
|
-
'/about',
|
|
55
|
-
['en', 'cs'],
|
|
56
|
-
undefined,
|
|
57
|
-
serializedStrategy,
|
|
58
|
-
),
|
|
59
|
-
).not.toThrow();
|
|
60
|
-
expect(
|
|
61
|
-
shouldIgnoreRedirect(
|
|
62
|
-
'/about',
|
|
63
|
-
['en', 'cs'],
|
|
64
|
-
undefined,
|
|
65
|
-
serializedStrategy,
|
|
66
|
-
),
|
|
67
|
-
).toBe(false);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test('the server redirect builder falls back instead of throwing', () => {
|
|
71
|
-
expect(() =>
|
|
72
|
-
buildServerLocalizedUrl(
|
|
73
|
-
createRequest('/about'),
|
|
74
|
-
'/*',
|
|
75
|
-
'cs',
|
|
76
|
-
['en', 'cs'],
|
|
77
|
-
serializedStrategy,
|
|
78
|
-
),
|
|
79
|
-
).not.toThrow();
|
|
80
|
-
expect(
|
|
81
|
-
buildServerLocalizedUrl(
|
|
82
|
-
createRequest('/about'),
|
|
83
|
-
'/*',
|
|
84
|
-
'cs',
|
|
85
|
-
['en', 'cs'],
|
|
86
|
-
serializedStrategy,
|
|
87
|
-
),
|
|
88
|
-
).toBe('/cs/about');
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test('the server redirect skip check falls back instead of throwing', () => {
|
|
92
|
-
expect(() =>
|
|
93
|
-
shouldIgnoreServerRedirect(
|
|
94
|
-
'/about',
|
|
95
|
-
'/*',
|
|
96
|
-
undefined,
|
|
97
|
-
serializedStrategy,
|
|
98
|
-
['en', 'cs'],
|
|
99
|
-
),
|
|
100
|
-
).not.toThrow();
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
describe('serializable mapped locale URLs', () => {
|
|
105
|
-
test('produce a working strategy on the server', () => {
|
|
106
|
-
const strategy = resolveMappedUrlStrategy({
|
|
107
|
-
languages: ['en', 'cs'],
|
|
108
|
-
localisedUrls: { '/about': { en: '/about', cs: '/o-nas' } },
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
expect(strategy).toBeDefined();
|
|
112
|
-
expect(strategy?.localizePathname('/about', 'cs', ['en', 'cs'])).toBe(
|
|
113
|
-
'/cs/o-nas',
|
|
114
|
-
);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
test('are absent when no map is configured', () => {
|
|
118
|
-
expect(resolveMappedUrlStrategy(undefined)).toBeUndefined();
|
|
119
|
-
expect(resolveMappedUrlStrategy({ languages: ['en'] })).toBeUndefined();
|
|
120
|
-
expect(resolveMappedUrlStrategy({ localisedUrls: {} })).toBeUndefined();
|
|
121
|
-
});
|
|
122
|
-
});
|
package/tsconfig.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "@modern-js/tsconfig/base",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"declaration": false,
|
|
5
|
-
"lib": ["DOM", "ESNext", "dom.iterable"],
|
|
6
|
-
"jsx": "preserve",
|
|
7
|
-
// FORK: `baseUrl` removed. TypeScript 7 / tsgo reject it outright (TS5102),
|
|
8
|
-
// so this package's own tsconfig could not be typechecked at all. `paths`
|
|
9
|
-
// is empty here, so nothing resolved through baseUrl.
|
|
10
|
-
"isolatedModules": true,
|
|
11
|
-
"paths": {},
|
|
12
|
-
"rootDir": "./src"
|
|
13
|
-
},
|
|
14
|
-
"include": ["src", "types"]
|
|
15
|
-
}
|