Skip to content

Commit 09b3518

Browse files
Copilotneilime
andcommitted
Fix privacy policy links to use correct locale-aware URLs
Co-authored-by: neilime <314088+neilime@users.noreply.github.com> Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
1 parent 5fb89a3 commit 09b3518

46 files changed

Lines changed: 750 additions & 2150 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,29 @@
11
---
22
import { languages } from '~/i18n/ui';
33
import { getLangFromUrl } from '~/i18n/utils';
4+
import { translatePathToLang } from '~/i18n/routes';
45
56
const lang = getLangFromUrl(Astro.url);
67
const currentPath = Astro.url.pathname;
7-
8-
// Get the path without the language prefix
9-
function getPathWithoutLang(path: string): string {
10-
const parts = path.split('/').filter(Boolean);
11-
if (parts.length > 0 && parts[0] in languages) {
12-
return '/' + parts.slice(1).join('/');
13-
}
14-
return path;
15-
}
16-
17-
const pathWithoutLang = getPathWithoutLang(currentPath);
188
---
199

2010
<div class="relative inline-block text-left">
2111
<div class="flex items-center space-x-2">
22-
{Object.entries(languages).map(([langCode]) => (
23-
<a
24-
href={`/${langCode}${pathWithoutLang}`}
25-
class:list={[
26-
'px-3 py-2 text-sm font-medium rounded-md transition-colors',
27-
lang === langCode
28-
? 'bg-primary text-white'
29-
: 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800'
30-
]}
31-
aria-current={lang === langCode ? 'page' : undefined}
32-
>
33-
{langCode.toUpperCase()}
34-
</a>
35-
))}
12+
{
13+
Object.entries(languages).map(([langCode]) => (
14+
<a
15+
href={translatePathToLang(currentPath, langCode as keyof typeof languages)}
16+
class:list={[
17+
'px-3 py-2 text-sm font-medium rounded-md transition-colors',
18+
lang === langCode
19+
? 'bg-primary text-white'
20+
: 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800',
21+
]}
22+
aria-current={lang === langCode ? 'page' : undefined}
23+
>
24+
{langCode.toUpperCase()}
25+
</a>
26+
))
27+
}
3628
</div>
3729
</div>

application/src/i18n/routes.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { languages } from './ui';
2+
3+
export type AppLang = keyof typeof languages;
4+
5+
export const routeSlugs = {
6+
about: { en: 'about', fr: 'a-propos' },
7+
contact: { en: 'contact', fr: 'contact' },
8+
sponsoring: { en: 'sponsoring', fr: 'sponsoring' },
9+
'brand-guidelines': { en: 'brand-guidelines', fr: 'charte-graphique' },
10+
terms: { en: 'terms-of-service', fr: 'conditions-generales-utilisation' },
11+
privacy: { en: 'privacy-policy', fr: 'politique-de-confidentialite' },
12+
} as const;
13+
14+
export type RouteKey = keyof typeof routeSlugs;
15+
16+
export const getLocalizedPagePath = (lang: AppLang, routeKey: RouteKey): string => {
17+
return `/${lang}/${routeSlugs[routeKey][lang]}`;
18+
};
19+
20+
export const getRouteKeyFromSlug = (lang: AppLang, slug: string): RouteKey | undefined => {
21+
const normalizedSlug = slug.replace(/^\/+|\/+$/g, '');
22+
const entries = Object.entries(routeSlugs) as [RouteKey, (typeof routeSlugs)[RouteKey]][];
23+
const found = entries.find(([, localizedSlugs]) => localizedSlugs[lang] === normalizedSlug);
24+
return found?.[0];
25+
};
26+
27+
export const translatePathToLang = (path: string, targetLang: AppLang): string => {
28+
const parts = path.split('/').filter(Boolean);
29+
30+
if (parts.length === 0) return `/${targetLang}`;
31+
32+
const sourceLang = parts[0] as AppLang;
33+
if (!(sourceLang in languages)) {
34+
return `/${targetLang}`;
35+
}
36+
37+
if (parts.length === 1) return `/${targetLang}`;
38+
39+
const sourceSlug = parts[1];
40+
const routeKey = getRouteKeyFromSlug(sourceLang, sourceSlug);
41+
if (!routeKey) {
42+
return `/${targetLang}/${parts.slice(1).join('/')}`;
43+
}
44+
45+
const translatedSlug = routeSlugs[routeKey][targetLang];
46+
const rest = parts.slice(2);
47+
return `/${targetLang}/${[translatedSlug, ...rest].join('/')}`;
48+
};

application/src/navigation.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,56 @@
11
import { getPermalink } from './utils/permalinks';
22
import { useTranslations } from './i18n/utils';
3+
import { getLocalizedPagePath } from './i18n/routes';
34
import type { ui } from './i18n/ui';
45
import favIcon from '~/assets/favicons/favicon.svg';
56

67
// Function to get locale-aware navigation
78
export const getHeaderData = (locale: keyof typeof ui) => {
89
const t = useTranslations(locale);
9-
10+
1011
return {
1112
links: [
1213
{
1314
text: t('nav.sponsoring'),
14-
href: getPermalink(`/${locale}/sponsoring`),
15+
href: getPermalink(getLocalizedPagePath(locale, 'sponsoring')),
1516
},
1617
{
1718
text: t('nav.about'),
18-
href: getPermalink(`/${locale}/about`),
19+
href: getPermalink(getLocalizedPagePath(locale, 'about')),
1920
},
2021
{
2122
text: t('nav.contact'),
22-
href: getPermalink(`/${locale}/contact`),
23+
href: getPermalink(getLocalizedPagePath(locale, 'contact')),
2324
},
2425
],
2526
};
2627
};
2728

2829
export const getFooterData = (locale: keyof typeof ui) => {
2930
const t = useTranslations(locale);
30-
31+
3132
return {
3233
links: [
3334
{
3435
title: t('footer.event'),
3536
links: [
36-
{ text: t('footer.sponsoring'), href: getPermalink(`/${locale}/sponsoring`) },
37+
{ text: t('footer.sponsoring'), href: getPermalink(getLocalizedPagePath(locale, 'sponsoring')) },
3738
{ text: t('footer.program'), href: '#' },
3839
{ text: t('footer.practicalInfo'), href: '#' },
3940
],
4041
},
4142
{
4243
title: t('footer.organization'),
4344
links: [
44-
{ text: t('footer.about'), href: getPermalink(`/${locale}/about`) },
45-
{ text: t('footer.brandGuidelines'), href: getPermalink(`/${locale}/brand-guidelines`) },
46-
{ text: t('footer.contact'), href: getPermalink(`/${locale}/contact`) },
45+
{ text: t('footer.about'), href: getPermalink(getLocalizedPagePath(locale, 'about')) },
46+
{ text: t('footer.brandGuidelines'), href: getPermalink(getLocalizedPagePath(locale, 'brand-guidelines')) },
47+
{ text: t('footer.contact'), href: getPermalink(getLocalizedPagePath(locale, 'contact')) },
4748
],
4849
},
4950
],
5051
secondaryLinks: [
51-
{ text: t('footer.terms'), href: getPermalink(`/${locale}/terms`) },
52-
{ text: t('footer.privacy'), href: getPermalink(`/${locale}/privacy`) },
52+
{ text: t('footer.terms'), href: getPermalink(getLocalizedPagePath(locale, 'terms')) },
53+
{ text: t('footer.privacy'), href: getPermalink(getLocalizedPagePath(locale, 'privacy')) },
5354
],
5455
socialLinks: [],
5556
footNote: `
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
---
2+
import Layout from '~/layouts/PageLayout.astro';
3+
import { languages } from '~/i18n/ui';
4+
import { getRouteKeyFromSlug, routeSlugs, type AppLang, type RouteKey } from '~/i18n/routes';
5+
6+
import aboutEn from '~/pages/about/en';
7+
import aboutFr from '~/pages/about/fr';
8+
import AboutContent from '~/pages/about/_content.astro';
9+
10+
import contactEn from '~/pages/contact/en';
11+
import contactFr from '~/pages/contact/fr';
12+
import ContactContent from '~/pages/contact/_content.astro';
13+
14+
import sponsoringEn from '~/pages/sponsoring/en';
15+
import sponsoringFr from '~/pages/sponsoring/fr';
16+
import SponsoringContent from '~/pages/sponsoring/_content.astro';
17+
18+
import { enContent as brandEnContent } from '~/pages/brand-guidelines/en';
19+
import { frContent as brandFrContent } from '~/pages/brand-guidelines/fr';
20+
import BrandGuidelinesContent from '~/pages/brand-guidelines/_content.astro';
21+
22+
import termsEn from '~/pages/terms/en';
23+
import termsFr from '~/pages/terms/fr';
24+
import TermsContent from '~/pages/terms/_content.astro';
25+
26+
import privacyEn from '~/pages/privacy/en';
27+
import privacyFr from '~/pages/privacy/fr';
28+
import PrivacyContent from '~/pages/privacy/_content.astro';
29+
30+
export function getStaticPaths() {
31+
const langs = Object.keys(languages) as AppLang[];
32+
const routeKeys = Object.keys(routeSlugs) as RouteKey[];
33+
34+
return langs.flatMap((lang) =>
35+
routeKeys.map((routeKey) => ({
36+
params: { lang, page: routeSlugs[routeKey][lang] },
37+
}))
38+
);
39+
}
40+
41+
const lang = Astro.params.lang as AppLang;
42+
const page = Astro.params.page ?? '';
43+
44+
const routeKey = getRouteKeyFromSlug(lang, page);
45+
46+
if (!routeKey) {
47+
throw new Error(`Unknown localized route: /${lang}/${page}`);
48+
}
49+
50+
const aboutData = lang === 'en' ? aboutEn : aboutFr;
51+
const contactData = lang === 'en' ? contactEn : contactFr;
52+
const sponsoringData = lang === 'en' ? sponsoringEn : sponsoringFr;
53+
const brandData = lang === 'en' ? brandEnContent : brandFrContent;
54+
const termsData = lang === 'en' ? termsEn : termsFr;
55+
const privacyData = lang === 'en' ? privacyEn : privacyFr;
56+
---
57+
58+
{
59+
routeKey === 'about' && (
60+
<Layout metadata={aboutData.metadata}>
61+
<AboutContent
62+
hero={aboutData.hero}
63+
team={aboutData.team}
64+
objectives={aboutData.objectives}
65+
values={aboutData.values}
66+
location={aboutData.location}
67+
contact={aboutData.contact}
68+
/>
69+
</Layout>
70+
)
71+
}
72+
73+
{
74+
routeKey === 'contact' && (
75+
<Layout metadata={contactData.metadata}>
76+
<ContactContent
77+
tagline={contactData.tagline}
78+
title={contactData.title}
79+
featuresTitle={contactData.featuresTitle}
80+
items={contactData.items}
81+
/>
82+
</Layout>
83+
)
84+
}
85+
86+
{
87+
routeKey === 'sponsoring' && (
88+
<Layout metadata={sponsoringData.metadata}>
89+
<SponsoringContent
90+
hero={sponsoringData.hero}
91+
pricing={sponsoringData.pricing}
92+
features={sponsoringData.features}
93+
faqs={sponsoringData.faqs}
94+
materials={sponsoringData.materials}
95+
contact={sponsoringData.contact}
96+
callToAction={sponsoringData.callToAction}
97+
/>
98+
</Layout>
99+
)
100+
}
101+
102+
{
103+
routeKey === 'brand-guidelines' && (
104+
<BrandGuidelinesContent
105+
metadata={brandData.metadata}
106+
hero={brandData.hero}
107+
colorPalette={brandData.colorPalette}
108+
typography={brandData.typography}
109+
logoDownloads={brandData.logoDownloads}
110+
usageGuidelines={brandData.usageGuidelines}
111+
note={brandData.note}
112+
/>
113+
)
114+
}
115+
116+
{
117+
routeKey === 'terms' && (
118+
<Layout metadata={termsData.metadata}>
119+
<TermsContent
120+
lastUpdatedLabel={termsData.lastUpdatedLabel}
121+
lastUpdated={termsData.lastUpdated}
122+
intro={termsData.intro}
123+
sections={termsData.sections}
124+
/>
125+
</Layout>
126+
)
127+
}
128+
129+
{
130+
routeKey === 'privacy' && (
131+
<Layout metadata={privacyData.metadata}>
132+
<PrivacyContent
133+
lastUpdatedLabel={privacyData.lastUpdatedLabel}
134+
lastUpdated={privacyData.lastUpdated}
135+
intro={privacyData.intro}
136+
sections={privacyData.sections}
137+
/>
138+
</Layout>
139+
)
140+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
import Layout from '~/layouts/PageLayout.astro';
3+
import { languages } from '~/i18n/ui';
4+
import type { AppLang } from '~/i18n/routes';
5+
import homeEn from '~/pages/home/en';
6+
import homeFr from '~/pages/home/fr';
7+
import Content from '~/pages/home/_content.astro';
8+
9+
export function getStaticPaths() {
10+
return (Object.keys(languages) as AppLang[]).map((lang) => ({
11+
params: { lang },
12+
}));
13+
}
14+
15+
const lang = Astro.params.lang as AppLang;
16+
const t = lang === 'en' ? homeEn : homeFr;
17+
---
18+
19+
<Layout metadata={t.metadata}>
20+
<Content
21+
hero={t.hero}
22+
note={t.note}
23+
features={t.features}
24+
contentSection={t.content}
25+
steps={t.steps}
26+
stats={t.stats}
27+
callToAction={t.callToAction}
28+
/>
29+
</Layout>

application/src/pages/en/about.astro

Lines changed: 0 additions & 16 deletions
This file was deleted.

application/src/pages/en/brand-guidelines.astro

Lines changed: 0 additions & 14 deletions
This file was deleted.

application/src/pages/en/contact.astro

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)