Skip to content

Commit 05c31a5

Browse files
committed
Fix base path handling in Astro templates for GH Pages
1 parent 1761379 commit 05c31a5

6 files changed

Lines changed: 290 additions & 29 deletions

File tree

check_hardcoded.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import os
2+
import re
3+
4+
EXCLUDE_DIRS = ['node_modules', '.git', 'dist', 'build']
5+
# Simplified patterns to find potential hardcoded strings
6+
# 1. Text between tags: >Some Text<
7+
JSX_TEXT_PATTERN = re.compile(r'>\s*([A-Z][^<>{}]*)\s*<')
8+
# 2. String props: label="Some Text" or placeholder="Some Text"
9+
JSX_PROP_PATTERN = re.compile(r'\s+(?:label|placeholder|title|description|message|alt|header)="([^"]*[A-Z][^"]*)"')
10+
11+
results = []
12+
13+
for root, dirs, files in os.walk('src'):
14+
dirs[:] = [d for d in dirs if d not in EXCLUDE_DIRS]
15+
for file in files:
16+
if file.endswith('.tsx'):
17+
path = os.path.join(root, file)
18+
with open(path, 'r', encoding='utf-8') as f:
19+
content = f.read()
20+
21+
matches = []
22+
# Find text between tags
23+
for match in JSX_TEXT_PATTERN.finditer(content):
24+
text = match.group(1).strip()
25+
if len(text) > 1 and not text.isnumeric():
26+
matches.append(f" Tag text: '{text}'")
27+
28+
# Find string props
29+
for match in JSX_PROP_PATTERN.finditer(content):
30+
text = match.group(1).strip()
31+
if len(text) > 1 and not text.isnumeric():
32+
matches.append(f" Prop text: '{text}'")
33+
34+
if matches:
35+
results.append(f"--- {path} ---")
36+
results.extend(matches)
37+
38+
with open('hardcoded_audit.txt', 'w', encoding='utf-8') as f:
39+
f.write("\n".join(results))
40+
41+
print(f"Audit complete. Found suspected strings in {len(results)} locations. See hardcoded_audit.txt")

compare_locales.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import json
2+
import os
3+
import re
4+
5+
locales_dir = 'src/locales'
6+
en_file = os.path.join(locales_dir, 'en.json')
7+
8+
if not os.path.exists(en_file):
9+
print(f"Error: {en_file} not found")
10+
exit(1)
11+
12+
with open(en_file, 'r', encoding='utf-8') as f:
13+
en_data = json.load(f)
14+
15+
def get_keys(data, prefix=''):
16+
keys = {}
17+
for k, v in data.items():
18+
new_prefix = f"{prefix}.{k}" if prefix else k
19+
if isinstance(v, dict):
20+
keys.update(get_keys(v, new_prefix))
21+
else:
22+
keys[new_prefix] = v
23+
return keys
24+
25+
def extract_placeholders(text):
26+
if not isinstance(text, str):
27+
return set()
28+
return set(re.findall(r'\{[^{}]+\}', text))
29+
30+
en_keys_dict = get_keys(en_data)
31+
en_keys = set(en_keys_dict.keys())
32+
33+
results = []
34+
35+
for filename in sorted(os.listdir(locales_dir)):
36+
if filename.endswith('.json') and filename != 'en.json':
37+
with open(os.path.join(locales_dir, filename), 'r', encoding='utf-8') as f:
38+
data = json.load(f)
39+
keys_dict = get_keys(data)
40+
keys = set(keys_dict.keys())
41+
42+
missing = en_keys - keys
43+
extra = keys - en_keys
44+
45+
same_as_en = []
46+
interpolation_mismatches = []
47+
48+
for k in en_keys & keys:
49+
# Check for untranslated strings
50+
if en_keys_dict[k] == keys_dict[k] and en_keys_dict[k] != "" and not k.startswith("app.") and not k.startswith("languages."):
51+
same_as_en.append(k)
52+
53+
# Check for interpolation mismatches
54+
en_placeholders = extract_placeholders(en_keys_dict[k])
55+
loc_placeholders = extract_placeholders(keys_dict[k])
56+
if en_placeholders != loc_placeholders:
57+
interpolation_mismatches.append((k, en_placeholders, loc_placeholders))
58+
59+
res = f"--- {filename} ---\n"
60+
if missing:
61+
res += f"Missing keys ({len(missing)}): {sorted(list(missing))[:20]}\n"
62+
else:
63+
res += "No missing keys.\n"
64+
65+
if same_as_en:
66+
res += f"Untranslated keys (same as EN, {len(same_as_en)}): {sorted(same_as_en)[:20]}\n"
67+
68+
if interpolation_mismatches:
69+
res += f"Interpolation mismatches ({len(interpolation_mismatches)}):\n"
70+
for k, en_p, loc_p in interpolation_mismatches[:10]:
71+
res += f" {k}: EN {en_p} VS LOC {loc_p}\n"
72+
73+
if extra:
74+
res += f"Extra keys ({len(extra)}): {sorted(list(extra))[:20]}\n"
75+
results.append(res)
76+
77+
with open('locale_audit.txt', 'w', encoding='utf-8') as f:
78+
f.write("\n".join(results))

hardcoded_audit.txt

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
--- src/App.tsx ---
2+
Tag text: 'Loading tool...'
3+
Tag text: 'LocalPDF'
4+
Tag text: 'Sanctuary'
5+
Tag text: 'Tool Not Implemented'
6+
Tag text: 'This tool is coming soon.'
7+
Tag text: 'Tool implementation coming soon...'
8+
Prop text: 'LocalPDF'
9+
--- src/components/WelcomeScreen.tsx ---
10+
Tag text: 'Loading preview...'
11+
Tag text: 'No preview'
12+
Tag text: 'Select a tool to begin'
13+
Tag text: 'Choose a compatible tool and your files will transfer instantly.'
14+
--- src/components/ui/dialog.tsx ---
15+
Tag text: 'Close'
16+
--- src/components/tools/DeletePagesPDF.tsx ---
17+
Prop text: 'Zoomed page'
18+
--- src/components/tools/OCRPDF.tsx ---
19+
Tag text: 'OCR Results'
20+
Tag text: 'Copy Text'
21+
Prop text: 'Preview'
22+
--- src/components/tools/MergePDF.tsx ---
23+
Tag text: 'Remove'
24+
Tag text: 'Add File'
25+
--- src/components/tools/ExtractPagesPDF.tsx ---
26+
Prop text: 'Zoomed page'
27+
--- src/components/tools/PDFToWord.tsx ---
28+
Prop text: 'PDF Preview'
29+
--- src/components/tools/SignPDF.tsx ---
30+
Tag text: 'Reset'
31+
Prop text: 'Your Name'
32+
Prop text: 'PDF Preview'
33+
--- src/components/tools/PDFToImages.tsx ---
34+
Tag text: 'PNG'
35+
Tag text: 'JPEG'
36+
Prop text: 'From'
37+
Prop text: 'To'
38+
Prop text: 'Zoomed page'
39+
--- src/components/tools/WatermarkPDF.tsx ---
40+
Prop text: 'PDF Preview'
41+
Prop text: 'Watermark'
42+
Prop text: 'Selected'
43+
--- src/components/tools/ImagesToPDF.tsx ---
44+
Tag text: 'Show All'
45+
Tag text: 'Auto Orientation'
46+
Tag text: 'Add More'
47+
--- src/components/layout/Sidebar.tsx ---
48+
Tag text: 'TOOL_GROUPS[selectedGroup].includes(tool.id)
49+
);
50+
51+
return ('
52+
Tag text: 'Pro Status'
53+
Tag text: 'Active subscription'
54+
Tag text: 'Upgrade to Pro'
55+
Tag text: 'Unlock all tools & limits'
56+
Tag text: 'Resources'
57+
Prop text: 'Copy ID'
58+
--- src/components/smart/SmartCompressionPanel.tsx ---
59+
Tag text: 'AI'
60+
--- src/components/smart/SmartImageFilterPanel.tsx ---
61+
Tag text: 'AI'
62+
Tag text: 'AI'
63+
--- src/components/smart/SmartMergePanel.tsx ---
64+
Tag text: 'AI'
65+
Tag text: 'AI'
66+
--- src/components/smart/SmartOrganizePanel.tsx ---
67+
Tag text: 'AI'
68+
Tag text: 'AI'
69+
--- src/components/modals/SubscriptionModal.tsx ---
70+
Tag text: 'LocalPDF PRO'
71+
Tag text: 'Privacy Sanctuary'
72+
Tag text: 'All processing stays local. Your subscription key is verified anonymously.'
73+
Prop text: 'LS-XXXX-XXXX-XXXX-XXXX'
74+
--- src/components/common/PDFPreview.tsx ---
75+
Tag text: 'Loading...'
76+
Tag text: 'Failed to load'
77+
--- src/components/common/FeedbackDialog.tsx ---
78+
Tag text: 'Support ID:'
79+
--- src/components/common/PDFMultiPagePreview.tsx ---
80+
Tag text: 'Loading document...'
81+
Tag text: 'Failed to load preview'
82+
Tag text: 'Rendering...'
83+
--- src/components/common/preview/PreviewImage.tsx ---
84+
Tag text: 'Loading preview...'
85+
Tag text: 'Failed to load preview'
86+
--- src/components/common/preview/PreviewFrame.tsx ---
87+
Tag text: 'Rendering pages...'
88+
--- src/components/common/preview/PreviewCanvas.tsx ---
89+
Tag text: 'Loading preview...'
90+
Tag text: 'Failed to load preview'
91+
--- src/hooks/usePDFThumbnails.tsx ---
92+
Tag text: 'Promise'

locale_audit.txt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
--- de.json ---
2+
No missing keys.
3+
Untranslated keys (same as EN, 99): ['addFormFields.panel.defaultOptions', 'addFormFields.types.dropdown', 'addFormFields.types.text', 'addFormFields.zoom', 'addText.format.position', 'addText.zoom', 'common.change', 'common.clearAll', 'common.convertAnother', 'common.downloadAll', 'common.generatingPreview', 'common.newSize', 'common.nextPage', 'common.optional', 'common.originalSize', 'common.page', 'common.pages', 'common.prevPage', 'common.preview', 'common.quickActions']
4+
Interpolation mismatches (1):
5+
editText.applyChanges: EN {'{s}', '{count}'} VS LOC {'{count}'}
6+
7+
--- es.json ---
8+
No missing keys.
9+
Untranslated keys (same as EN, 88): ['addFormFields.panel.defaultOptions', 'addFormFields.zoom', 'addText.zoom', 'common.change', 'common.clickToEdit', 'common.downloadAll', 'common.error', 'common.generatingPreview', 'common.newSize', 'common.nextPage', 'common.originalSize', 'common.page', 'common.pages', 'common.prevPage', 'common.selectFiles', 'common.selected', 'common.selectedFile', 'common.useInOtherTools', 'common.zoom', 'editText.format.textColor']
10+
Interpolation mismatches (1):
11+
editText.applyChanges: EN {'{s}', '{count}'} VS LOC {'{count}'}
12+
13+
--- fr.json ---
14+
No missing keys.
15+
Untranslated keys (same as EN, 105): ['addFormFields.panel.defaultOptions', 'addText.format.position', 'addText.format.rotation', 'addText.toolbar.page', 'common.change', 'common.downloadAll', 'common.generatingPreview', 'common.nextPage', 'common.page', 'common.pages', 'common.prevPage', 'common.selectFiles', 'common.selected', 'common.zoom', 'compress.pages', 'compress.quality.high.name', 'compress.quality.low.name', 'editText.format.rotation', 'editText.xLabel', 'editText.yLabel']
16+
Interpolation mismatches (1):
17+
editText.applyChanges: EN {'{s}', '{count}'} VS LOC {'{count}'}
18+
19+
--- it.json ---
20+
No missing keys.
21+
Untranslated keys (same as EN, 69): ['addFormFields.panel.defaultOptions', 'addFormFields.zoom', 'addText.zoom', 'common.change', 'common.downloadAll', 'common.email', 'common.generatingPreview', 'common.nextPage', 'common.prevPage', 'common.selectFiles', 'common.selected', 'common.zoom', 'editText.xLabel', 'editText.yLabel', 'imagesToPdf.pageSizes.a4', 'imagesToPdf.pageSizes.letter', 'monetization.free.price', 'monetization.private_secure_fast', 'monetization.pro_badge', 'ocr.errors.limitReached']
22+
Interpolation mismatches (1):
23+
editText.applyChanges: EN {'{s}', '{count}'} VS LOC {'{count}'}
24+
25+
--- ja.json ---
26+
No missing keys.
27+
Untranslated keys (same as EN, 53): ['addFormFields.panel.defaultOptions', 'addText.defaultFileName', 'common.change', 'common.generatingPreview', 'common.nextPage', 'common.prevPage', 'common.selected', 'editText.xLabel', 'editText.yLabel', 'imagesToPdf.pageSizes.a4', 'monetization.free.price', 'monetization.private_secure_fast', 'monetization.pro_badge', 'ocr.errors.limitReached', 'ocr.errors.limitReachedDesc', 'ocr.outputFormat.hocr', 'ocr.outputFormat.hocrShort', 'ocr.outputFormat.tsv', 'rotate.nextPage', 'rotate.prevPage']
28+
Interpolation mismatches (1):
29+
editText.applyChanges: EN {'{s}', '{count}'} VS LOC {'{count}'}
30+
31+
--- pt.json ---
32+
No missing keys.
33+
Untranslated keys (same as EN, 69): ['addFormFields.panel.defaultOptions', 'addFormFields.zoom', 'addText.title', 'addText.toolbar.redo', 'addText.toolbar.undo', 'addText.zoom', 'common.change', 'common.generatingPreview', 'common.nextPage', 'common.prevPage', 'common.selected', 'common.zoom', 'editText.xLabel', 'editText.yLabel', 'imagesToPdf.pageSizes.a4', 'monetization.free.price', 'monetization.private_secure_fast', 'monetization.pro_badge', 'ocr.errors.limitReached', 'ocr.errors.limitReachedDesc']
34+
Interpolation mismatches (1):
35+
editText.applyChanges: EN {'{s}', '{count}'} VS LOC {'{count}'}
36+
37+
--- ru.json ---
38+
No missing keys.
39+
Untranslated keys (same as EN, 27): ['addText.defaultFileName', 'common.change', 'common.email', 'common.generatingPreview', 'common.nextPage', 'common.prevPage', 'common.selected', 'editText.xLabel', 'editText.yLabel', 'imagesToPdf.pageSizes.a4', 'imagesToPdf.pageSizes.letter', 'monetization.free.price', 'monetization.pro_badge', 'ocr.outputFormat.hocr', 'ocr.outputFormat.hocrShort', 'ocr.outputFormat.tsv', 'sign.errors.signFailed', 'tools.ocr-pdf.name', 'tools.unlock-pdf.description', 'tools.unlock-pdf.name']
40+
Interpolation mismatches (2):
41+
upload.errors.fileTooLargeFree: EN {'{max}'} VS LOC set()
42+
editText.applyChanges: EN {'{s}', '{count}'} VS LOC {'{count}'}
43+
44+
--- zh.json ---
45+
No missing keys.
46+
Untranslated keys (same as EN, 62): ['addFormFields.panel.defaultOptions', 'addText.defaultFileName', 'common.change', 'common.downloadAll', 'common.generatingPreview', 'common.nextPage', 'common.prevPage', 'common.selectFiles', 'common.selected', 'editText.xLabel', 'editText.yLabel', 'imagesToPdf.pageSizes.a4', 'monetization.free.price', 'monetization.private_secure_fast', 'monetization.pro_badge', 'ocr.errors.limitReached', 'ocr.errors.limitReachedDesc', 'ocr.outputFormat.hocr', 'ocr.outputFormat.hocrShort', 'ocr.outputFormat.tsv']
47+
Interpolation mismatches (1):
48+
editText.applyChanges: EN {'{s}', '{count}'} VS LOC {'{count}'}

website/src/components/Header.astro

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,29 @@ const navLabels = {
99
de: { tools: 'Tools', blog: 'Blog', learn: 'Lernen', compare: 'Vergleichen', about: 'Über uns', extension: 'Erweiterung' },
1010
ja: { tools: 'ツール', blog: 'ブログ', learn: '学ぶ', compare: '比較', about: 'ツールについて', extension: '拡張機能' }
1111
}[lang] || { tools: 'Tools', blog: 'Blog', learn: 'Learn', compare: 'Compare', about: 'About', extension: 'Extension' };
12+
const base = import.meta.env.BASE_URL.replace(/\/$/, '');
1213
---
1314
<header>
14-
<a href={langPrefix || "/"} class="logo">
15-
<img src="/logos/localpdf-header-64x64.png" alt="LocalPDF" class="logo-image" width="40" height="40" />
15+
<a href={langPrefix ? `${base}${langPrefix}` : `${base}/`} class="logo">
16+
<img src={`${base}/logos/localpdf-header-64x64.png`} alt="LocalPDF" class="logo-image" width="40" height="40" />
1617
<div class="logo-text">
1718
<div class="logo-title">LocalPDF</div>
1819
<div class="logo-subtitle">Sanctuary</div>
1920
</div>
2021
</a>
2122
<nav>
22-
<a href={langPrefix || "/"}>{navLabels.tools}</a>
23-
<a href="/blog">{navLabels.blog}</a>
24-
<a href="/learn">{navLabels.learn}</a>
25-
<a href="/comparison">{navLabels.compare}</a>
26-
<a href="/about">{navLabels.about}</a>
27-
<a href={(langPrefix || "") + "/extension"}>{navLabels.extension}</a>
23+
<a href={langPrefix ? `${base}${langPrefix}` : `${base}/`}>{navLabels.tools}</a>
24+
<a href={`${base}/blog`}>{navLabels.blog}</a>
25+
<a href={`${base}/learn`}>{navLabels.learn}</a>
26+
<a href={`${base}/comparison`}>{navLabels.compare}</a>
27+
<a href={`${base}/about`}>{navLabels.about}</a>
28+
<a href={`${base}${langPrefix || ""}/extension`}>{navLabels.extension}</a>
2829
<LanguagePicker lang={lang} />
2930
</nav>
3031

3132
<!-- Mobile actions (Visible only on mobile) -->
3233
<div class="mobile-actions">
33-
<a href={(langPrefix || "") + "/extension"} class="mobile-extension-cta">
34+
<a href={`${base}${langPrefix || ""}/extension`} class="mobile-extension-cta">
3435
{navLabels.extension}
3536
</a>
3637
<div class="mobile-lang-picker">

website/src/layouts/BaseLayout.astro

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ const localizedPages = [
125125
'/legal-privacy-pdf', '/finance-privacy-pdf', '/medical-privacy-pdf', '/extension'
126126
];
127127
const isLocalizedPath = localizedPages.includes(basePath);
128+
const base = import.meta.env.BASE_URL.replace(/\/$/, '');
128129
---
129130

130131
<!DOCTYPE html>
@@ -187,14 +188,14 @@ const isLocalizedPath = localizedPages.includes(basePath);
187188
<meta name="apple-mobile-web-app-title" content={siteName}>
188189

189190
<!-- Favicons and Icons -->
190-
<link rel="icon" type="image/png" sizes="16x16" href="/logos/localpdf-favicon-16x16.png">
191-
<link rel="icon" type="image/png" sizes="32x32" href="/logos/localpdf-header-32x32.png">
192-
<link rel="apple-touch-icon" sizes="180x180" href="/logos/localpdf-apple-180x180.png">
193-
<link rel="icon" type="image/png" sizes="192x192" href="/logos/localpdf-pwa-192x192.png">
194-
<link rel="icon" type="image/png" sizes="512x512" href="/logos/localpdf-pwa-512x512.png">
191+
<link rel="icon" type="image/png" sizes="16x16" href={`${base}/logos/localpdf-favicon-16x16.png`}>
192+
<link rel="icon" type="image/png" sizes="32x32" href={`${base}/logos/localpdf-header-32x32.png`}>
193+
<link rel="apple-touch-icon" sizes="180x180" href={`${base}/logos/localpdf-apple-180x180.png`}>
194+
<link rel="icon" type="image/png" sizes="192x192" href={`${base}/logos/localpdf-pwa-192x192.png`}>
195+
<link rel="icon" type="image/png" sizes="512x512" href={`${base}/logos/localpdf-pwa-512x512.png`}>
195196

196197
<!-- PWA Manifest -->
197-
<link rel="manifest" href="/manifest.json">
198+
<link rel="manifest" href={`${base}/manifest.json`}>
198199

199200
<script type="application/ld+json" set:html={JSON.stringify(softwareSchema)} />
200201
<slot name="head" />
@@ -237,7 +238,7 @@ const isLocalizedPath = localizedPages.includes(basePath);
237238
// Register Service Worker for PWA
238239
if ('serviceWorker' in navigator) {
239240
window.addEventListener('load', () => {
240-
navigator.serviceWorker.register('/sw.js').then(registration => {
241+
navigator.serviceWorker.register(`${base}/sw.js`).then(registration => {
241242
console.log('SW registered: ', registration);
242243
}).catch(registrationError => {
243244
console.log('SW registration failed: ', registrationError);
@@ -396,36 +397,36 @@ const isLocalizedPath = localizedPages.includes(basePath);
396397
<footer>
397398
<div class="footer-content">
398399
<div class="footer-grid">
399-
<div class="footer-section">
400400
<strong>{footerLabels.resources}</strong>
401-
<a href="/learn">{footerLabels.learn}</a>
402-
<a href="/blog">{footerLabels.blog}</a>
403-
<a href="/about">{footerLabels.about}</a>
404-
<a href="/comparison">{footerLabels.compare}</a>
405-
<a href={(lang === 'en') ? '/extension' : `/${lang}/extension`}>{footerLabels.extension}</a>
401+
<a href={`${base}/learn`}>{footerLabels.learn}</a>
402+
<a href={`${base}/blog`}>{footerLabels.blog}</a>
403+
<a href={`${base}/about`}>{footerLabels.about}</a>
404+
<a href={`${base}/comparison`}>{footerLabels.compare}</a>
405+
<a href={(lang === 'en') ? `${base}/extension` : `${base}/${lang}/extension`}>{footerLabels.extension}</a>
406406
</div>
407407
<div class="footer-section">
408408
<strong>{footerLabels.solutions}</strong>
409-
<a href={(lang === 'en') ? '/legal-privacy-pdf' : `/${lang}/legal-privacy-pdf`}>{footerLabels.legalSolutions}</a>
410-
<a href={(lang === 'en') ? '/finance-privacy-pdf' : `/${lang}/finance-privacy-pdf`}>{footerLabels.financeSolutions}</a>
411-
<a href={(lang === 'en') ? '/medical-privacy-pdf' : `/${lang}/medical-privacy-pdf`}>{footerLabels.medicalSolutions}</a>
409+
<a href={(lang === 'en') ? `${base}/legal-privacy-pdf` : `${base}/${lang}/legal-privacy-pdf`}>{footerLabels.legalSolutions}</a>
410+
<a href={(lang === 'en') ? `${base}/finance-privacy-pdf` : `${base}/${lang}/finance-privacy-pdf`}>{footerLabels.financeSolutions}</a>
411+
<a href={(lang === 'en') ? `${base}/medical-privacy-pdf` : `${base}/${lang}/medical-privacy-pdf`}>{footerLabels.medicalSolutions}</a>
412412
</div>
413413
{currentCategories.map(cat => (
414414
<div class="footer-section">
415415
<strong>{cat.name}</strong>
416-
{cat.tools.map(tool => {
416+
{cat.tools.map(tool => {
417417
const toolSlug = `/${tool.id}`;
418418
const isToolLocalized = localizedPages.includes(toolSlug);
419+
const toolHref = (isToolLocalized && lang !== 'en') ? `${base}/${lang}${toolSlug}` : `${base}${toolSlug}`;
419420
return (
420-
<a href={(isToolLocalized && lang !== 'en') ? `/${lang}${toolSlug}` : toolSlug}>{tool.name}</a>
421+
<a href={toolHref}>{tool.name}</a>
421422
);
422423
})}
423424
</div>
424425
))}
425426
<div class="footer-section">
426427
<strong>{footerLabels.legal}</strong>
427-
<a href="/privacy">{footerLabels.privacy}</a>
428-
<a href="/terms">{footerLabels.terms}</a>
428+
<a href={`${base}/privacy`}>{footerLabels.privacy}</a>
429+
<a href={`${base}/terms`}>{footerLabels.terms}</a>
429430
</div>
430431
</div>
431432

0 commit comments

Comments
 (0)