Skip to content

Commit e7391ee

Browse files
feat(footer): add i18n support for footer site links
Localize footer site link labels and descriptions using the builder's i18n locale resolution chain with fallback to the default language. - Update fetch-sites-snapshot script to normalize localized fields - Refresh snapshot data with per-locale title/description entries - Refactor resolveBuilderFooterSiteLinks to resolve localized fields - Update SiteFooter to pass the full resolved locale - Move test file to __tests__ directory and add localized assertions Co-Authored-By: Hagicode <noreply@hagicode.com> Signed-off-by: newbe36524 <newbe36524@qq.com>
1 parent cff6a0f commit e7391ee

5 files changed

Lines changed: 634 additions & 64 deletions

File tree

scripts/fetch-sites-snapshot.mjs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import path from 'node:path';
33
import { fileURLToPath } from 'node:url';
44

55
const FOOTER_SITES_SNAPSHOT_URL = 'https://index.hagicode.com/sites.json';
6+
const FOOTER_SITE_LOCALES = ["zh-CN","zh-Hant","en-US","ja-JP","ko-KR","de-DE","fr-FR","es-ES","pt-BR","ru-RU"];
67

78
function assert(condition, message) {
89
if (!condition) {
@@ -19,6 +20,22 @@ function assertNonEmptyString(value, fieldName) {
1920
return value.trim();
2021
}
2122

23+
function normalizeLocalizedField(value, fieldName) {
24+
if (typeof value === 'string') {
25+
const normalized = assertNonEmptyString(value, fieldName);
26+
return Object.fromEntries(FOOTER_SITE_LOCALES.map((locale) => [locale, normalized]));
27+
}
28+
29+
assert(isRecord(value), `Invalid footer sites snapshot payload: ${fieldName} must be a localized object`);
30+
31+
return Object.fromEntries(
32+
FOOTER_SITE_LOCALES.map((locale) => [
33+
locale,
34+
assertNonEmptyString(value[locale], `${fieldName}.${locale}`),
35+
]),
36+
);
37+
}
38+
2239
function normalizeHttpsUrl(value, fieldName) {
2340
const raw = assertNonEmptyString(value, fieldName);
2441
let parsed;
@@ -49,8 +66,8 @@ function normalizeFooterSitesSnapshotPayload(payload) {
4966
assert(isRecord(group), `Invalid footer sites snapshot payload: groups[${index}] must be an object`);
5067
return {
5168
id: assertNonEmptyString(group.id, `groups[${index}].id`),
52-
label: assertNonEmptyString(group.label, `groups[${index}].label`),
53-
description: assertNonEmptyString(group.description, `groups[${index}].description`),
69+
label: normalizeLocalizedField(group.label, `groups[${index}].label`),
70+
description: normalizeLocalizedField(group.description, `groups[${index}].description`),
5471
};
5572
});
5673

@@ -73,12 +90,12 @@ function normalizeFooterSitesSnapshotPayload(payload) {
7390

7491
return {
7592
id,
76-
title: assertNonEmptyString(entry.title, `entries[${index}].title`),
77-
label: assertNonEmptyString(entry.label, `entries[${index}].label`),
78-
description: assertNonEmptyString(entry.description, `entries[${index}].description`),
93+
title: normalizeLocalizedField(entry.title, `entries[${index}].title`),
94+
label: normalizeLocalizedField(entry.label, `entries[${index}].label`),
95+
description: normalizeLocalizedField(entry.description, `entries[${index}].description`),
7996
groupId,
8097
url: normalizeHttpsUrl(entry.url, `entries[${index}].url`),
81-
actionLabel: assertNonEmptyString(entry.actionLabel, `entries[${index}].actionLabel`),
98+
actionLabel: normalizeLocalizedField(entry.actionLabel, `entries[${index}].actionLabel`),
8299
};
83100
});
84101

@@ -115,11 +132,12 @@ async function updateFooterSitesSnapshot({
115132

116133
const payload = normalizeFooterSitesSnapshotPayload(await response.json());
117134
await mkdir(path.dirname(outputPath), { recursive: true });
118-
await writeFile(outputPath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
135+
await writeFile(outputPath, `${JSON.stringify(payload, null, 2)}
136+
`, 'utf8');
119137
}
120138

121139
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
122-
const outputPath = path.join(repoRoot, 'src', 'data', 'footer-sites.snapshot.json');
140+
const outputPath = path.join(repoRoot, "src", "data", "footer-sites.snapshot.json");
123141

124142
await updateFooterSitesSnapshot({ outputPath });
125143
console.log(`Footer sites snapshot updated at ${path.relative(repoRoot, outputPath)}`);

src/components/Footer/SiteFooter.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { resolveBuilderFooterSiteLinks } from '@/lib/footer-site-links';
55

66
export function SiteFooter() {
77
const { i18n, t } = useTranslation();
8-
const locale = resolveBuilderLanguageCode(i18n.resolvedLanguage).startsWith('zh') ? 'zh-CN' : 'en-US';
8+
const locale = resolveBuilderLanguageCode(i18n.resolvedLanguage);
99
const relatedLinks = resolveBuilderFooterSiteLinks(locale);
1010

1111
return (

0 commit comments

Comments
 (0)