Skip to content

Commit cecf026

Browse files
Copilotneilime
andcommitted
Refactor i18n: separate translation files, use translation helpers, remove hardcoded defaults
Co-authored-by: neilime <[email protected]>
1 parent b2cf628 commit cecf026

5 files changed

Lines changed: 134 additions & 117 deletions

File tree

application/src/components/common/LanguageAlternates.astro

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
import { languages } from '~/i18n/ui';
2+
import { languages, defaultLang } from '~/i18n/ui';
33
44
const currentPath = Astro.url.pathname;
55
@@ -14,7 +14,11 @@ const pathWithoutLang = pathParts[0] in languages
1414
// Ensure path ends consistently
1515
const normalizedPath = pathWithoutLang === '/' ? '/' : pathWithoutLang.replace(/\/$/, '');
1616
17-
const baseUrl = Astro.site ? Astro.site.origin : 'https://cloudnative-provence.fr';
17+
if (!Astro.site) {
18+
throw new Error('Astro.site is required for generating language alternates');
19+
}
20+
21+
const baseUrl = Astro.site.origin;
1822
---
1923

2024
{Object.keys(languages).map((lang) => (
@@ -27,5 +31,5 @@ const baseUrl = Astro.site ? Astro.site.origin : 'https://cloudnative-provence.f
2731
<link
2832
rel="alternate"
2933
hreflang="x-default"
30-
href={`${baseUrl}/fr${normalizedPath}`}
34+
href={`${baseUrl}/${defaultLang}${normalizedPath}`}
3135
/>

application/src/i18n/locales/en.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
export default {
2+
'nav.sponsoring': 'Sponsoring',
3+
'nav.about': 'About',
4+
'nav.contact': 'Contact',
5+
'nav.brandGuidelines': 'Brand Guidelines',
6+
7+
'footer.event': 'Event',
8+
'footer.organization': 'Organization',
9+
'footer.sponsoring': 'Sponsoring',
10+
'footer.program': 'Program',
11+
'footer.practicalInfo': 'Practical Information',
12+
'footer.about': 'About',
13+
'footer.brandGuidelines': 'Brand Guidelines',
14+
'footer.contact': 'Contact',
15+
'footer.terms': 'Terms of Service',
16+
'footer.privacy': 'Privacy Policy',
17+
'footer.note': 'Designed by the <a class="text-blue-600 underline dark:text-muted" href="https://cloudnative-provence.fr/">Cloud Native Provence community</a> · All rights reserved.',
18+
19+
'home.hero.cta.participate': 'I want to participate',
20+
'home.hero.cta.learnMore': 'Learn more',
21+
'home.hero.title': 'Cloud Native & Kubernetes',
22+
'home.hero.date': 'December 10, 2026',
23+
'home.hero.location': 'in Aix-en-Provence',
24+
'home.hero.subtitle': 'A day of discussions and conferences around Kubernetes and Cloud Native technologies, driven by the community.',
25+
'home.note.title': 'Our philosophy:',
26+
'home.note.description': 'Community, Sharing and Open Source Technologies',
27+
'home.features.tagline': 'Why attend?',
28+
'home.features.title': 'Cloud Native Provence at a glance',
29+
30+
'meta.title.default': 'Cloud Native Provence',
31+
'meta.title.template': '%s — Cloud Native Provence',
32+
'meta.description': 'The Cloud Native & Kubernetes day in Aix-en-Provence, organized by the community.',
33+
} as const;

application/src/i18n/locales/fr.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
export default {
2+
'nav.sponsoring': 'Sponsoring',
3+
'nav.about': 'À propos',
4+
'nav.contact': 'Contact',
5+
'nav.brandGuidelines': 'Charte Graphique',
6+
7+
'footer.event': 'Événement',
8+
'footer.organization': 'Organisation',
9+
'footer.sponsoring': 'Sponsoring',
10+
'footer.program': 'Programme',
11+
'footer.practicalInfo': 'Infos pratiques',
12+
'footer.about': 'À propos',
13+
'footer.brandGuidelines': 'Charte Graphique',
14+
'footer.contact': 'Contact',
15+
'footer.terms': 'Mentions légales',
16+
'footer.privacy': 'Politique de confidentialité',
17+
'footer.note': 'Conçu par la <a class="text-blue-600 underline dark:text-muted" href="https://cloudnative-provence.fr/">communauté Cloud Native Provence</a> · Tous droits réservés.',
18+
19+
'home.hero.cta.participate': 'Je veux participer',
20+
'home.hero.cta.learnMore': 'En savoir plus',
21+
'home.hero.title': 'Cloud Native & Kubernetes',
22+
'home.hero.date': '10 décembre 2026',
23+
'home.hero.location': 'à Aix-en-Provence',
24+
'home.hero.subtitle': 'Une journée d\'échanges et de conférences autour de Kubernetes et des technologies Cloud Native, portée par la communauté.',
25+
'home.note.title': 'Notre philosophie :',
26+
'home.note.description': 'Communauté, Partage et Technologies Open Source',
27+
'home.features.tagline': 'Pourquoi venir ?',
28+
'home.features.title': 'Cloud Native Provence en un clin d\'œil',
29+
30+
'meta.title.default': 'Cloud Native Provence',
31+
'meta.title.template': '%s — Cloud Native Provence',
32+
'meta.description': 'La journée Cloud Native & Kubernetes à Aix-en-Provence, organisée par la communauté.',
33+
} as const;

application/src/i18n/ui.ts

Lines changed: 6 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import fr from './locales/fr';
2+
import en from './locales/en';
3+
14
export const languages = {
25
fr: 'Français',
36
en: 'English',
@@ -6,70 +9,7 @@ export const languages = {
69
export const defaultLang = 'fr';
710

811
export const ui = {
9-
fr: {
10-
'nav.sponsoring': 'Sponsoring',
11-
'nav.about': 'À propos',
12-
'nav.contact': 'Contact',
13-
'nav.brandGuidelines': 'Charte Graphique',
14-
15-
'footer.event': 'Événement',
16-
'footer.organization': 'Organisation',
17-
'footer.sponsoring': 'Sponsoring',
18-
'footer.program': 'Programme',
19-
'footer.practicalInfo': 'Infos pratiques',
20-
'footer.about': 'À propos',
21-
'footer.brandGuidelines': 'Charte Graphique',
22-
'footer.contact': 'Contact',
23-
'footer.terms': 'Mentions légales',
24-
'footer.privacy': 'Politique de confidentialité',
25-
'footer.note': 'Conçu par la <a class="text-blue-600 underline dark:text-muted" href="https://cloudnative-provence.fr/">communauté Cloud Native Provence</a> · Tous droits réservés.',
26-
27-
'home.hero.cta.participate': 'Je veux participer',
28-
'home.hero.cta.learnMore': 'En savoir plus',
29-
'home.hero.title': 'Cloud Native & Kubernetes',
30-
'home.hero.date': '10 décembre 2026',
31-
'home.hero.location': 'à Aix-en-Provence',
32-
'home.hero.subtitle': 'Une journée d\'échanges et de conférences autour de Kubernetes et des technologies Cloud Native, portée par la communauté.',
33-
'home.note.title': 'Notre philosophie :',
34-
'home.note.description': 'Communauté, Partage et Technologies Open Source',
35-
'home.features.tagline': 'Pourquoi venir ?',
36-
'home.features.title': 'Cloud Native Provence en un clin d\'œil',
37-
38-
'meta.title.default': 'Cloud Native Provence',
39-
'meta.title.template': '%s — Cloud Native Provence',
40-
'meta.description': 'La journée Cloud Native & Kubernetes à Aix-en-Provence, organisée par la communauté.',
41-
},
42-
en: {
43-
'nav.sponsoring': 'Sponsoring',
44-
'nav.about': 'About',
45-
'nav.contact': 'Contact',
46-
'nav.brandGuidelines': 'Brand Guidelines',
47-
48-
'footer.event': 'Event',
49-
'footer.organization': 'Organization',
50-
'footer.sponsoring': 'Sponsoring',
51-
'footer.program': 'Program',
52-
'footer.practicalInfo': 'Practical Information',
53-
'footer.about': 'About',
54-
'footer.brandGuidelines': 'Brand Guidelines',
55-
'footer.contact': 'Contact',
56-
'footer.terms': 'Terms of Service',
57-
'footer.privacy': 'Privacy Policy',
58-
'footer.note': 'Designed by the <a class="text-blue-600 underline dark:text-muted" href="https://cloudnative-provence.fr/">Cloud Native Provence community</a> · All rights reserved.',
59-
60-
'home.hero.cta.participate': 'I want to participate',
61-
'home.hero.cta.learnMore': 'Learn more',
62-
'home.hero.title': 'Cloud Native & Kubernetes',
63-
'home.hero.date': 'December 10, 2026',
64-
'home.hero.location': 'in Aix-en-Provence',
65-
'home.hero.subtitle': 'A day of discussions and conferences around Kubernetes and Cloud Native technologies, driven by the community.',
66-
'home.note.title': 'Our philosophy:',
67-
'home.note.description': 'Community, Sharing and Open Source Technologies',
68-
'home.features.tagline': 'Why attend?',
69-
'home.features.title': 'Cloud Native Provence at a glance',
70-
71-
'meta.title.default': 'Cloud Native Provence',
72-
'meta.title.template': '%s — Cloud Native Provence',
73-
'meta.description': 'The Cloud Native & Kubernetes day in Aix-en-Provence, organized by the community.',
74-
},
12+
fr,
13+
en,
7514
} as const;
15+

application/src/navigation.ts

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,64 @@
11
import { getPermalink } from './utils/permalinks';
2+
import { useTranslations } from './i18n/utils';
23
import favIcon from '~/assets/favicons/favicon.svg';
34

45
// Function to get locale-aware navigation
5-
export const getHeaderData = (locale: string = 'fr') => ({
6-
links: [
7-
{
8-
text: locale === 'en' ? 'Sponsoring' : 'Sponsoring',
9-
href: getPermalink(`/${locale}/sponsoring`),
10-
},
11-
{
12-
text: locale === 'en' ? 'About' : 'À propos',
13-
href: getPermalink(`/${locale}/about`),
14-
},
15-
{
16-
text: locale === 'en' ? 'Contact' : 'Contact',
17-
href: getPermalink(`/${locale}/contact`),
18-
},
19-
],
20-
});
6+
export const getHeaderData = (locale: string = 'fr') => {
7+
const t = useTranslations(locale as 'fr' | 'en');
8+
9+
return {
10+
links: [
11+
{
12+
text: t('nav.sponsoring'),
13+
href: getPermalink(`/${locale}/sponsoring`),
14+
},
15+
{
16+
text: t('nav.about'),
17+
href: getPermalink(`/${locale}/about`),
18+
},
19+
{
20+
text: t('nav.contact'),
21+
href: getPermalink(`/${locale}/contact`),
22+
},
23+
],
24+
};
25+
};
2126

22-
export const getFooterData = (locale: string = 'fr') => ({
23-
links: [
24-
{
25-
title: locale === 'en' ? 'Event' : 'Événement',
26-
links: [
27-
{ text: locale === 'en' ? 'Sponsoring' : 'Sponsoring', href: getPermalink(`/${locale}/sponsoring`) },
28-
{ text: locale === 'en' ? 'Program' : 'Programme', href: '#' },
29-
{ text: locale === 'en' ? 'Practical info' : 'Infos pratiques', href: '#' },
30-
],
31-
},
32-
{
33-
title: locale === 'en' ? 'Organization' : 'Organisation',
34-
links: [
35-
{ text: locale === 'en' ? 'About' : 'À propos', href: getPermalink(`/${locale}/about`) },
36-
{ text: locale === 'en' ? 'Brand Guidelines' : 'Charte Graphique', href: getPermalink(`/${locale}/brand-guidelines`) },
37-
{ text: locale === 'en' ? 'Contact' : 'Contact', href: getPermalink(`/${locale}/contact`) },
38-
],
39-
},
40-
],
41-
secondaryLinks: [
42-
{ text: locale === 'en' ? 'Terms of Service' : 'Mentions légales', href: getPermalink(`/${locale}/terms`) },
43-
{ text: locale === 'en' ? 'Privacy Policy' : 'Politique de confidentialité', href: getPermalink(`/${locale}/privacy`) },
44-
],
45-
socialLinks: [],
46-
footNote: `
47-
<img class="w-5 h-5 md:w-6 md:h-6 md:-mt-0.5 bg-cover mr-1.5 rtl:mr-0 rtl:ml-1.5 float-left rtl:float-right rounded-sm" src="${favIcon.src}" alt="Logo Cloud Native Provence" loading="lazy" />
48-
${locale === 'en'
49-
? 'Designed by the <a class="text-blue-600 underline dark:text-muted" href="https://cloudnative-provence.fr/">Cloud Native Provence community</a> · All rights reserved.'
50-
: 'Conçu par la <a class="text-blue-600 underline dark:text-muted" href="https://cloudnative-provence.fr/">communauté Cloud Native Provence</a> · Tous droits réservés.'
51-
}
52-
`,
53-
});
27+
export const getFooterData = (locale: string = 'fr') => {
28+
const t = useTranslations(locale as 'fr' | 'en');
29+
30+
return {
31+
links: [
32+
{
33+
title: t('footer.event'),
34+
links: [
35+
{ text: t('footer.sponsoring'), href: getPermalink(`/${locale}/sponsoring`) },
36+
{ text: t('footer.program'), href: '#' },
37+
{ text: t('footer.practicalInfo'), href: '#' },
38+
],
39+
},
40+
{
41+
title: t('footer.organization'),
42+
links: [
43+
{ text: t('footer.about'), href: getPermalink(`/${locale}/about`) },
44+
{ text: t('footer.brandGuidelines'), href: getPermalink(`/${locale}/brand-guidelines`) },
45+
{ text: t('footer.contact'), href: getPermalink(`/${locale}/contact`) },
46+
],
47+
},
48+
],
49+
secondaryLinks: [
50+
{ text: t('footer.terms'), href: getPermalink(`/${locale}/terms`) },
51+
{ text: t('footer.privacy'), href: getPermalink(`/${locale}/privacy`) },
52+
],
53+
socialLinks: [],
54+
footNote: `
55+
<img class="w-5 h-5 md:w-6 md:h-6 md:-mt-0.5 bg-cover mr-1.5 rtl:mr-0 rtl:ml-1.5 float-left rtl:float-right rounded-sm" src="${favIcon.src}" alt="Logo Cloud Native Provence" loading="lazy" />
56+
${t('footer.note')}
57+
`,
58+
};
59+
};
5460

5561
// Keep backward compatibility - default to French
5662
export const headerData = getHeaderData('fr');
5763
export const footerData = getFooterData('fr');
64+

0 commit comments

Comments
 (0)