@bleedingdev/modern-js-plugin-i18n 3.5.0-ultramodern.30 → 3.5.0-ultramodern.31
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 +2 -1
- package/dist/cjs/runtime/Link.js +8 -89
- package/dist/cjs/runtime/context.js +18 -82
- package/dist/cjs/runtime/contextHelpers.js +137 -0
- package/dist/cjs/runtime/core.js +29 -132
- package/dist/cjs/runtime/i18n/detection/cache.js +149 -0
- package/dist/cjs/runtime/i18n/detection/detector.js +100 -0
- package/dist/cjs/runtime/i18n/detection/index.js +8 -263
- package/dist/cjs/runtime/i18n/detection/initOptions.js +69 -0
- package/dist/cjs/runtime/i18n/detection/language.js +62 -0
- package/dist/cjs/runtime/i18n/detection/path.js +49 -0
- package/dist/cjs/runtime/i18n/detection/priority.js +66 -0
- package/dist/cjs/runtime/i18n/detection/ssr.js +70 -0
- package/dist/cjs/runtime/i18n/detection/types.js +18 -0
- package/dist/cjs/runtime/linkHelpers.js +148 -0
- package/dist/cjs/runtime/pluginSetup.js +102 -0
- package/dist/cjs/runtime/providerComposition.js +113 -0
- package/dist/cjs/runtime/reactI18next.js +43 -0
- package/dist/cjs/server/apiPrefix.js +72 -0
- package/dist/cjs/server/detectorOptions.js +97 -0
- package/dist/cjs/server/index.js +17 -152
- package/dist/cjs/server/redirectPolicy.js +102 -0
- package/dist/cjs/shared/localisedUrls/config.js +49 -0
- package/dist/cjs/shared/localisedUrls/index.js +75 -0
- package/dist/cjs/shared/localisedUrls/normalise.js +87 -0
- package/dist/cjs/shared/localisedUrls/pathname.js +65 -0
- package/dist/cjs/shared/localisedUrls/patterns.js +130 -0
- package/dist/cjs/shared/localisedUrls/resolve.js +91 -0
- package/dist/cjs/shared/localisedUrls/routes.js +129 -0
- package/dist/cjs/shared/localisedUrls/types.js +18 -0
- package/dist/cjs/shared/localisedUrls.js +13 -294
- package/dist/esm/cli/index.mjs +2 -1
- package/dist/esm/runtime/Link.mjs +1 -82
- package/dist/esm/runtime/context.mjs +18 -82
- package/dist/esm/runtime/contextHelpers.mjs +84 -0
- package/dist/esm/runtime/core.mjs +30 -133
- package/dist/esm/runtime/i18n/detection/cache.mjs +102 -0
- package/dist/esm/runtime/i18n/detection/detector.mjs +62 -0
- package/dist/esm/runtime/i18n/detection/index.mjs +4 -260
- package/dist/esm/runtime/i18n/detection/initOptions.mjs +28 -0
- package/dist/esm/runtime/i18n/detection/language.mjs +21 -0
- package/dist/esm/runtime/i18n/detection/path.mjs +11 -0
- package/dist/esm/runtime/i18n/detection/priority.mjs +28 -0
- package/dist/esm/runtime/i18n/detection/ssr.mjs +26 -0
- package/dist/esm/runtime/i18n/detection/types.mjs +0 -0
- package/dist/esm/runtime/linkHelpers.mjs +98 -0
- package/dist/esm/runtime/pluginSetup.mjs +64 -0
- package/dist/esm/runtime/providerComposition.mjs +75 -0
- package/dist/esm/runtime/reactI18next.mjs +5 -0
- package/dist/esm/server/apiPrefix.mjs +31 -0
- package/dist/esm/server/detectorOptions.mjs +59 -0
- package/dist/esm/server/index.mjs +4 -139
- package/dist/esm/server/redirectPolicy.mjs +52 -0
- package/dist/esm/shared/localisedUrls/config.mjs +11 -0
- package/dist/esm/shared/localisedUrls/index.mjs +6 -0
- package/dist/esm/shared/localisedUrls/normalise.mjs +37 -0
- package/dist/esm/shared/localisedUrls/pathname.mjs +24 -0
- package/dist/esm/shared/localisedUrls/patterns.mjs +86 -0
- package/dist/esm/shared/localisedUrls/resolve.mjs +50 -0
- package/dist/esm/shared/localisedUrls/routes.mjs +88 -0
- package/dist/esm/shared/localisedUrls/types.mjs +0 -0
- package/dist/esm/shared/localisedUrls.mjs +1 -283
- package/dist/esm-node/cli/index.mjs +2 -1
- package/dist/esm-node/runtime/Link.mjs +1 -82
- package/dist/esm-node/runtime/context.mjs +18 -82
- package/dist/esm-node/runtime/contextHelpers.mjs +85 -0
- package/dist/esm-node/runtime/core.mjs +30 -133
- package/dist/esm-node/runtime/i18n/detection/cache.mjs +103 -0
- package/dist/esm-node/runtime/i18n/detection/detector.mjs +63 -0
- package/dist/esm-node/runtime/i18n/detection/index.mjs +4 -260
- package/dist/esm-node/runtime/i18n/detection/initOptions.mjs +29 -0
- package/dist/esm-node/runtime/i18n/detection/language.mjs +22 -0
- package/dist/esm-node/runtime/i18n/detection/path.mjs +12 -0
- package/dist/esm-node/runtime/i18n/detection/priority.mjs +29 -0
- package/dist/esm-node/runtime/i18n/detection/ssr.mjs +27 -0
- package/dist/esm-node/runtime/i18n/detection/types.mjs +1 -0
- package/dist/esm-node/runtime/linkHelpers.mjs +99 -0
- package/dist/esm-node/runtime/pluginSetup.mjs +65 -0
- package/dist/esm-node/runtime/providerComposition.mjs +76 -0
- package/dist/esm-node/runtime/reactI18next.mjs +6 -0
- package/dist/esm-node/server/apiPrefix.mjs +32 -0
- package/dist/esm-node/server/detectorOptions.mjs +60 -0
- package/dist/esm-node/server/index.mjs +4 -139
- package/dist/esm-node/server/redirectPolicy.mjs +53 -0
- package/dist/esm-node/shared/localisedUrls/config.mjs +12 -0
- package/dist/esm-node/shared/localisedUrls/index.mjs +7 -0
- package/dist/esm-node/shared/localisedUrls/normalise.mjs +38 -0
- package/dist/esm-node/shared/localisedUrls/pathname.mjs +25 -0
- package/dist/esm-node/shared/localisedUrls/patterns.mjs +87 -0
- package/dist/esm-node/shared/localisedUrls/resolve.mjs +51 -0
- package/dist/esm-node/shared/localisedUrls/routes.mjs +89 -0
- package/dist/esm-node/shared/localisedUrls/types.mjs +1 -0
- package/dist/esm-node/shared/localisedUrls.mjs +1 -283
- package/dist/types/runtime/Link.d.ts +3 -7
- package/dist/types/runtime/context.d.ts +2 -2
- package/dist/types/runtime/contextHelpers.d.ts +28 -0
- package/dist/types/runtime/core.d.ts +3 -7
- package/dist/types/runtime/i18n/detection/cache.d.ts +14 -0
- package/dist/types/runtime/i18n/detection/detector.d.ts +8 -0
- package/dist/types/runtime/i18n/detection/index.d.ts +5 -50
- package/dist/types/runtime/i18n/detection/initOptions.d.ts +10 -0
- package/dist/types/runtime/i18n/detection/language.d.ts +11 -0
- package/dist/types/runtime/i18n/detection/path.d.ts +5 -0
- package/dist/types/runtime/i18n/detection/priority.d.ts +10 -0
- package/dist/types/runtime/i18n/detection/ssr.d.ts +9 -0
- package/dist/types/runtime/i18n/detection/types.d.ts +29 -0
- package/dist/types/runtime/i18n/react-i18next.d.ts +1 -6
- package/dist/types/runtime/linkHelpers.d.ts +17 -0
- package/dist/types/runtime/pluginSetup.d.ts +32 -0
- package/dist/types/runtime/providerComposition.d.ts +15 -0
- package/dist/types/runtime/reactI18next.d.ts +7 -0
- package/dist/types/server/apiPrefix.d.ts +7 -0
- package/dist/types/server/detectorOptions.d.ts +21 -0
- package/dist/types/server/index.d.ts +1 -6
- package/dist/types/server/redirectPolicy.d.ts +16 -0
- package/dist/types/shared/localisedUrls/config.d.ts +9 -0
- package/dist/types/shared/localisedUrls/index.d.ts +7 -0
- package/dist/types/shared/localisedUrls/normalise.d.ts +10 -0
- package/dist/types/shared/localisedUrls/pathname.d.ts +3 -0
- package/dist/types/shared/localisedUrls/patterns.d.ts +5 -0
- package/dist/types/shared/localisedUrls/resolve.d.ts +8 -0
- package/dist/types/shared/localisedUrls/routes.d.ts +3 -0
- package/dist/types/shared/localisedUrls/types.d.ts +14 -0
- package/dist/types/shared/localisedUrls.d.ts +2 -42
- package/package.json +10 -10
- package/src/cli/index.ts +3 -2
- package/src/runtime/Link.tsx +11 -138
- package/src/runtime/context.tsx +42 -196
- package/src/runtime/contextHelpers.ts +232 -0
- package/src/runtime/core.tsx +42 -273
- package/src/runtime/i18n/detection/cache.ts +175 -0
- package/src/runtime/i18n/detection/detector.ts +157 -0
- package/src/runtime/i18n/detection/index.ts +10 -641
- package/src/runtime/i18n/detection/initOptions.ts +74 -0
- package/src/runtime/i18n/detection/language.ts +64 -0
- package/src/runtime/i18n/detection/path.ts +41 -0
- package/src/runtime/i18n/detection/priority.ts +82 -0
- package/src/runtime/i18n/detection/ssr.ts +47 -0
- package/src/runtime/i18n/detection/types.ts +33 -0
- package/src/runtime/i18n/react-i18next.ts +1 -6
- package/src/runtime/linkHelpers.ts +174 -0
- package/src/runtime/pluginSetup.ts +189 -0
- package/src/runtime/providerComposition.tsx +142 -0
- package/src/runtime/reactI18next.ts +20 -0
- package/src/server/apiPrefix.ts +67 -0
- package/src/server/detectorOptions.ts +105 -0
- package/src/server/index.ts +12 -327
- package/src/server/redirectPolicy.ts +152 -0
- package/src/shared/localisedUrls/config.ts +18 -0
- package/src/shared/localisedUrls/index.ts +13 -0
- package/src/shared/localisedUrls/normalise.ts +67 -0
- package/src/shared/localisedUrls/pathname.ts +57 -0
- package/src/shared/localisedUrls/patterns.ts +160 -0
- package/src/shared/localisedUrls/resolve.ts +118 -0
- package/src/shared/localisedUrls/routes.ts +226 -0
- package/src/shared/localisedUrls/types.ts +18 -0
- package/src/shared/localisedUrls.ts +20 -629
- package/tests/link.test.tsx +111 -0
- package/tests/localisedUrls.test.ts +50 -0
- package/tests/reactI18nextRuntimeBoundary.test.ts +5 -2
- package/tests/routerAdapter.test.tsx +56 -0
package/tests/link.test.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import { act } from 'react';
|
|
|
4
4
|
import { createRoot, type Root } from 'react-dom/client';
|
|
5
5
|
import { ModernI18nProvider } from '../src/runtime/context';
|
|
6
6
|
import type { I18nInstance } from '../src/runtime/i18n';
|
|
7
|
+
import { detectLanguageWithPriority } from '../src/runtime/i18n/detection';
|
|
7
8
|
import { interpolateRouteParams, Link } from '../src/runtime/Link';
|
|
8
9
|
import {
|
|
9
10
|
canonicalPath,
|
|
@@ -270,6 +271,60 @@ describe('localization utilities', () => {
|
|
|
270
271
|
});
|
|
271
272
|
});
|
|
272
273
|
|
|
274
|
+
describe('language detection priority', () => {
|
|
275
|
+
test('path locale overrides stale SSR data', async () => {
|
|
276
|
+
const previousSsrData = (window as any)._SSR_DATA;
|
|
277
|
+
(window as any)._SSR_DATA = { data: { i18nData: { lng: 'en' } } };
|
|
278
|
+
|
|
279
|
+
try {
|
|
280
|
+
await expect(
|
|
281
|
+
detectLanguageWithPriority(createI18nInstance('en'), {
|
|
282
|
+
languages,
|
|
283
|
+
fallbackLanguage: 'en',
|
|
284
|
+
localePathRedirect: true,
|
|
285
|
+
i18nextDetector: false,
|
|
286
|
+
detection: {},
|
|
287
|
+
userInitOptions: {},
|
|
288
|
+
pathname: '/cs/produkty',
|
|
289
|
+
ssrContext: undefined,
|
|
290
|
+
}),
|
|
291
|
+
).resolves.toEqual({ detectedLanguage: 'cs', finalLanguage: 'cs' });
|
|
292
|
+
} finally {
|
|
293
|
+
if (previousSsrData === undefined) {
|
|
294
|
+
delete (window as any)._SSR_DATA;
|
|
295
|
+
} else {
|
|
296
|
+
(window as any)._SSR_DATA = previousSsrData;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
test('regional SSR language resolves to supported base language', async () => {
|
|
302
|
+
const previousSsrData = (window as any)._SSR_DATA;
|
|
303
|
+
(window as any)._SSR_DATA = { data: { i18nData: { lng: 'en-US' } } };
|
|
304
|
+
|
|
305
|
+
try {
|
|
306
|
+
await expect(
|
|
307
|
+
detectLanguageWithPriority(createI18nInstance('cs'), {
|
|
308
|
+
languages,
|
|
309
|
+
fallbackLanguage: 'cs',
|
|
310
|
+
localePathRedirect: true,
|
|
311
|
+
i18nextDetector: false,
|
|
312
|
+
detection: {},
|
|
313
|
+
userInitOptions: {},
|
|
314
|
+
pathname: '/products',
|
|
315
|
+
ssrContext: undefined,
|
|
316
|
+
}),
|
|
317
|
+
).resolves.toEqual({ detectedLanguage: 'en', finalLanguage: 'en' });
|
|
318
|
+
} finally {
|
|
319
|
+
if (previousSsrData === undefined) {
|
|
320
|
+
delete (window as any)._SSR_DATA;
|
|
321
|
+
} else {
|
|
322
|
+
(window as any)._SSR_DATA = previousSsrData;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
|
|
273
328
|
describe('framework Link', () => {
|
|
274
329
|
let rendered: { container: HTMLElement; root: Root } | undefined;
|
|
275
330
|
|
|
@@ -328,6 +383,26 @@ describe('framework Link', () => {
|
|
|
328
383
|
expect(props.hash).toBe('list');
|
|
329
384
|
});
|
|
330
385
|
|
|
386
|
+
test('preserves array search values natively', async () => {
|
|
387
|
+
const router = createTanstackRouter('/en/products', 'en');
|
|
388
|
+
rendered = await renderWithRuntime(
|
|
389
|
+
<ModernI18nProvider value={providerValue('en')}>
|
|
390
|
+
<Link
|
|
391
|
+
to="/products"
|
|
392
|
+
search={{ tag: ['boots', 'sale'], page: 2 }}
|
|
393
|
+
data-testid="q"
|
|
394
|
+
>
|
|
395
|
+
Products
|
|
396
|
+
</Link>
|
|
397
|
+
</ModernI18nProvider>,
|
|
398
|
+
createTanstackRuntimeContext(router),
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
const props = capturedLinkProps.at(-1);
|
|
402
|
+
expect(props.to).toBe('/en/products');
|
|
403
|
+
expect(props.search).toEqual({ tag: ['boots', 'sale'], page: '2' });
|
|
404
|
+
});
|
|
405
|
+
|
|
331
406
|
test('renders a plain anchor for external targets', async () => {
|
|
332
407
|
const router = createTanstackRouter('/en', 'en');
|
|
333
408
|
rendered = await renderWithRuntime(
|
|
@@ -381,6 +456,42 @@ describe('framework Link', () => {
|
|
|
381
456
|
expect(link?.hasAttribute('prefetch')).toBe(false);
|
|
382
457
|
});
|
|
383
458
|
|
|
459
|
+
test('serializes array search values for fallback anchors', async () => {
|
|
460
|
+
rendered = await renderWithRuntime(
|
|
461
|
+
<ModernI18nProvider value={providerValue('en')}>
|
|
462
|
+
<Link
|
|
463
|
+
to="/products"
|
|
464
|
+
search={{ tag: ['boots', 'sale'], page: 2 }}
|
|
465
|
+
data-testid="q"
|
|
466
|
+
>
|
|
467
|
+
Products
|
|
468
|
+
</Link>
|
|
469
|
+
</ModernI18nProvider>,
|
|
470
|
+
{ isBrowser: true, requestContext, context: requestContext } as any,
|
|
471
|
+
);
|
|
472
|
+
|
|
473
|
+
const link = rendered.container.querySelector('[data-testid="q"]');
|
|
474
|
+
expect(link?.getAttribute('href')).toBe(
|
|
475
|
+
'/en/products?tag=boots&tag=sale&page=2',
|
|
476
|
+
);
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
test('empty search prop clears query from target fallback anchors', async () => {
|
|
480
|
+
rendered = await renderWithRuntime(
|
|
481
|
+
<ModernI18nProvider value={providerValue('en')}>
|
|
482
|
+
<Link to="/products?tag=x" search="" data-testid="clear-query">
|
|
483
|
+
Products
|
|
484
|
+
</Link>
|
|
485
|
+
</ModernI18nProvider>,
|
|
486
|
+
{ isBrowser: true, requestContext, context: requestContext } as any,
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
const link = rendered.container.querySelector(
|
|
490
|
+
'[data-testid="clear-query"]',
|
|
491
|
+
);
|
|
492
|
+
expect(link?.getAttribute('href')).toBe('/en/products');
|
|
493
|
+
});
|
|
494
|
+
|
|
384
495
|
test('maps prefetch to the TanStack preload prop', async () => {
|
|
385
496
|
const router = createTanstackRouter('/en/products', 'en');
|
|
386
497
|
rendered = await renderWithRuntime(
|
|
@@ -272,6 +272,31 @@ describe('localisedUrls', () => {
|
|
|
272
272
|
).toBe('/products/cervena-bota');
|
|
273
273
|
});
|
|
274
274
|
|
|
275
|
+
test('encodes wildcard params while preserving path separators', () => {
|
|
276
|
+
const localisedUrls = {
|
|
277
|
+
'/docs/*': {
|
|
278
|
+
en: '/docs/*',
|
|
279
|
+
cs: '/dokumenty/*',
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
expect(
|
|
284
|
+
resolveLocalisedPath(
|
|
285
|
+
'/docs/a%20b/c%23d',
|
|
286
|
+
'cs',
|
|
287
|
+
['en', 'cs'],
|
|
288
|
+
localisedUrls,
|
|
289
|
+
),
|
|
290
|
+
).toBe('/dokumenty/a%20b/c%23d');
|
|
291
|
+
expect(
|
|
292
|
+
resolveCanonicalLocalisedPath(
|
|
293
|
+
'/dokumenty/a%20b/c%23d',
|
|
294
|
+
['en', 'cs'],
|
|
295
|
+
localisedUrls,
|
|
296
|
+
),
|
|
297
|
+
).toBe('/docs/a%20b/c%23d');
|
|
298
|
+
});
|
|
299
|
+
|
|
275
300
|
test('resolves static patterns before param patterns', () => {
|
|
276
301
|
const localisedUrls = {
|
|
277
302
|
'/products/:slug': {
|
|
@@ -321,6 +346,31 @@ describe('localisedUrls', () => {
|
|
|
321
346
|
).toBe('/products/cervena-bota');
|
|
322
347
|
});
|
|
323
348
|
|
|
349
|
+
test('strips case-insensitive locale prefixes before relocalising full pathnames', () => {
|
|
350
|
+
const localisedUrls = {
|
|
351
|
+
'/products/:slug': {
|
|
352
|
+
en: '/products/:slug',
|
|
353
|
+
cs: '/produkty/:slug',
|
|
354
|
+
},
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
expect(
|
|
358
|
+
localiseTargetPathname(
|
|
359
|
+
'/CS/produkty/cervena-bota',
|
|
360
|
+
'en',
|
|
361
|
+
['en', 'cs'],
|
|
362
|
+
localisedUrls,
|
|
363
|
+
),
|
|
364
|
+
).toBe('/en/products/cervena-bota');
|
|
365
|
+
expect(
|
|
366
|
+
canonicalTargetPathname(
|
|
367
|
+
'/CS/produkty/cervena-bota',
|
|
368
|
+
['en', 'cs'],
|
|
369
|
+
localisedUrls,
|
|
370
|
+
),
|
|
371
|
+
).toBe('/products/cervena-bota');
|
|
372
|
+
});
|
|
373
|
+
|
|
324
374
|
test('resolves nested optional route params with translated ancestors', () => {
|
|
325
375
|
const localisedUrls = {
|
|
326
376
|
'/checkout': {
|
|
@@ -21,11 +21,14 @@ describe('react-i18next runtime boundary', () => {
|
|
|
21
21
|
|
|
22
22
|
test('keeps the runtime plugin factory entry synchronous for federation', () => {
|
|
23
23
|
const core = readRuntimeSource('core.tsx');
|
|
24
|
+
const pluginSetup = readRuntimeSource('pluginSetup.ts');
|
|
24
25
|
|
|
25
26
|
expect(core).not.toContain("from './i18n/backend/middleware'");
|
|
26
27
|
expect(core).not.toContain("from './i18n/utils'");
|
|
27
|
-
expect(
|
|
28
|
-
expect(
|
|
28
|
+
expect(pluginSetup).not.toContain("from './i18n/backend/middleware'");
|
|
29
|
+
expect(pluginSetup).not.toContain("from './i18n/utils'");
|
|
30
|
+
expect(pluginSetup).toContain("import('./i18n/backend/middleware')");
|
|
31
|
+
expect(pluginSetup).toContain("import('./i18n/utils')");
|
|
29
32
|
});
|
|
30
33
|
|
|
31
34
|
test('keeps the Modern i18n context stable across federated runtime copies', () => {
|
|
@@ -399,6 +399,62 @@ describe('i18n router adapter', () => {
|
|
|
399
399
|
});
|
|
400
400
|
});
|
|
401
401
|
|
|
402
|
+
test('updates provider language when target locale is already in URL', async () => {
|
|
403
|
+
window.history.replaceState(null, '', '/cs/podminky-pouzivani');
|
|
404
|
+
|
|
405
|
+
const router = createTanstackRouter('/cs/podminky-pouzivani', 'cs');
|
|
406
|
+
const i18nInstance = createI18nInstance('en');
|
|
407
|
+
const updateLanguage = rstest.fn();
|
|
408
|
+
let changeLanguagePromise: Promise<void> | undefined;
|
|
409
|
+
|
|
410
|
+
const Harness = () => {
|
|
411
|
+
const { changeLanguage } = useModernI18n();
|
|
412
|
+
return (
|
|
413
|
+
<button
|
|
414
|
+
type="button"
|
|
415
|
+
onClick={() => {
|
|
416
|
+
changeLanguagePromise = changeLanguage('cs');
|
|
417
|
+
}}
|
|
418
|
+
>
|
|
419
|
+
Change language
|
|
420
|
+
</button>
|
|
421
|
+
);
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
rendered = await renderWithRuntime(
|
|
425
|
+
<ModernI18nProvider
|
|
426
|
+
value={{
|
|
427
|
+
language: 'en',
|
|
428
|
+
i18nInstance,
|
|
429
|
+
languages: ['en', 'cs'],
|
|
430
|
+
localePathRedirect: true,
|
|
431
|
+
localisedUrls,
|
|
432
|
+
updateLanguage,
|
|
433
|
+
}}
|
|
434
|
+
>
|
|
435
|
+
<Harness />
|
|
436
|
+
</ModernI18nProvider>,
|
|
437
|
+
createTanstackRuntimeContext(router),
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
const button = rendered.container.querySelector('button');
|
|
441
|
+
updateLanguage.mockClear();
|
|
442
|
+
|
|
443
|
+
await act(async () => {
|
|
444
|
+
button?.dispatchEvent(
|
|
445
|
+
new MouseEvent('click', {
|
|
446
|
+
bubbles: true,
|
|
447
|
+
cancelable: true,
|
|
448
|
+
button: 0,
|
|
449
|
+
}),
|
|
450
|
+
);
|
|
451
|
+
await changeLanguagePromise;
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
expect(updateLanguage).toHaveBeenCalledWith('cs');
|
|
455
|
+
expect(router.navigate).not.toHaveBeenCalled();
|
|
456
|
+
});
|
|
457
|
+
|
|
402
458
|
test('keeps React Router positional replacement when changeLanguage updates the URL', async () => {
|
|
403
459
|
window.history.replaceState(null, '', '/en/terms-of-service');
|
|
404
460
|
|