Skip to content

Commit e1ab8f0

Browse files
authored
fix(core): share i18n config across server chunks (#2198)
1 parent 494f618 commit e1ab8f0

3 files changed

Lines changed: 45 additions & 10 deletions

File tree

.changeset/fix-bundled-hreflang.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"emdash": patch
3+
---
4+
5+
Fixes missing hreflang links when EmDash UI components are used in bundled Astro deployments.

packages/core/src/i18n/config.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,33 @@ export interface I18nConfig {
1212
prefixDefaultLocale?: boolean;
1313
}
1414

15-
let _config: I18nConfig | null | undefined;
15+
const I18N_CONFIG_KEY = Symbol.for("emdash:i18n-config");
16+
17+
function configStore(): Record<symbol, I18nConfig | null | undefined> {
18+
return globalThis;
19+
}
1620

1721
/**
1822
* Initialize i18n config from virtual module data.
1923
* Called during runtime initialization.
2024
*/
2125
export function setI18nConfig(config: I18nConfig | null): void {
22-
_config = config;
26+
configStore()[I18N_CONFIG_KEY] = config;
2327
}
2428

2529
/**
2630
* Get the current i18n config.
2731
* Returns null if i18n is not configured.
2832
*/
2933
export function getI18nConfig(): I18nConfig | null {
30-
return _config ?? null;
34+
return configStore()[I18N_CONFIG_KEY] ?? null;
3135
}
3236

3337
/** Match a locale to the exact casing used by the site configuration. */
3438
export function resolveConfiguredLocale(locale: string): string {
39+
const config = getI18nConfig();
3540
return (
36-
_config?.locales.find((configured) => configured.toLowerCase() === locale.toLowerCase()) ??
41+
config?.locales.find((configured) => configured.toLowerCase() === locale.toLowerCase()) ??
3742
locale
3843
);
3944
}
@@ -43,7 +48,8 @@ export function resolveConfiguredLocale(locale: string): string {
4348
* Returns true when multiple locales are configured.
4449
*/
4550
export function isI18nEnabled(): boolean {
46-
return _config != null && _config.locales.length > 1;
51+
const config = getI18nConfig();
52+
return config != null && config.locales.length > 1;
4753
}
4854

4955
/**
@@ -52,24 +58,25 @@ export function isI18nEnabled(): boolean {
5258
* Always ends with defaultLocale.
5359
*/
5460
export function getFallbackChain(locale: string): string[] {
55-
if (!_config) return [locale];
61+
const config = getI18nConfig();
62+
if (!config) return [locale];
5663

5764
const chain: string[] = [locale];
5865
let current = locale;
5966
const visited = new Set<string>([locale]);
6067

61-
while (_config.fallback?.[current]) {
68+
while (config.fallback?.[current]) {
6269
// eslint-disable-next-line typescript/no-unnecessary-type-assertion -- noUncheckedIndexedAccess
63-
const next = _config.fallback[current]!;
70+
const next = config.fallback[current]!;
6471
if (visited.has(next)) break; // prevent cycles
6572
chain.push(next);
6673
visited.add(next);
6774
current = next;
6875
}
6976

7077
// Always end with defaultLocale if not already in chain
71-
if (!visited.has(_config.defaultLocale)) {
72-
chain.push(_config.defaultLocale);
78+
if (!visited.has(config.defaultLocale)) {
79+
chain.push(config.defaultLocale);
7380
}
7481

7582
return chain;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { afterEach, describe, expect, it, vi } from "vitest";
2+
3+
afterEach(async () => {
4+
const { setI18nConfig } = await import("../../../src/i18n/config.js");
5+
setI18nConfig(null);
6+
vi.resetModules();
7+
});
8+
9+
describe("i18n config", () => {
10+
it("shares config across duplicated module instances", async () => {
11+
const writer = await import("../../../src/i18n/config.js");
12+
writer.setI18nConfig({ defaultLocale: "en", locales: ["en", "fr"] });
13+
14+
vi.resetModules();
15+
const reader = await import("../../../src/i18n/config.js");
16+
17+
expect(reader.getI18nConfig()).toEqual({
18+
defaultLocale: "en",
19+
locales: ["en", "fr"],
20+
});
21+
expect(reader.isI18nEnabled()).toBe(true);
22+
});
23+
});

0 commit comments

Comments
 (0)