Skip to content

Commit 55d2ca6

Browse files
Copilotneilime
authored andcommitted
feat: add better i18n support
Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
1 parent 995c73c commit 55d2ca6

55 files changed

Lines changed: 2457 additions & 2708 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: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
import { languages, defaultLang } from '~/i18n/ui';
3+
4+
const currentPath = Astro.url.pathname;
5+
6+
// Extract the current language from the path
7+
const pathParts = currentPath.split('/').filter(Boolean);
8+
9+
// Get the path without language prefix
10+
const pathWithoutLang = pathParts[0] in languages ? '/' + pathParts.slice(1).join('/') : currentPath;
11+
12+
// Ensure path ends consistently
13+
const normalizedPath = pathWithoutLang === '/' ? '/' : pathWithoutLang.replace(/\/$/, '');
14+
15+
if (!Astro.site) {
16+
throw new Error('Astro.site is required for generating language alternates');
17+
}
18+
19+
const baseUrl = Astro.site.origin;
20+
---
21+
22+
{
23+
Object.keys(languages).map((lang) => (
24+
<link rel="alternate" hreflang={lang} href={`${baseUrl}/${lang}${normalizedPath}`} />
25+
))
26+
}
27+
<link rel="alternate" hreflang="x-default" href={`${baseUrl}/${defaultLang}${normalizedPath}`} />
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
import { languages } from '~/i18n/ui';
3+
import { getLangFromUrl } from '~/i18n/utils';
4+
import { translatePathToLang } from '~/i18n/routes';
5+
6+
const lang = getLangFromUrl(Astro.url);
7+
const currentPath = Astro.url.pathname;
8+
---
9+
10+
<div class="relative inline-block text-left">
11+
<div class="flex items-center space-x-2">
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+
}
28+
</div>
29+
</div>

application/src/components/widgets/Header.astro

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Icon } from 'astro-icon/components';
33
import Logo from '~/components/Logo.astro';
44
import ToggleTheme from '~/components/common/ToggleTheme.astro';
55
import ToggleMenu from '~/components/common/ToggleMenu.astro';
6+
import LanguageSwitcher from '~/components/common/LanguageSwitcher.astro';
67
import Button from '~/components/ui/Button.astro';
78
89
import { getHomePermalink } from '~/utils/permalinks';
@@ -136,7 +137,8 @@ const currentPath = `/${trimSlash(new URL(Astro.url).pathname)}`;
136137
]}
137138
>
138139
<div class="items-center flex justify-between w-full md:w-auto">
139-
<div class="flex">
140+
<div class="flex items-center space-x-2">
141+
<LanguageSwitcher />
140142
{showToggleTheme && <ToggleTheme iconClass="w-6 h-6 md:w-5 md:h-5 md:inline-block" />}
141143
{
142144
showRssFeed && (
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
export default {
2+
metadata: {
3+
title: 'About',
4+
},
5+
hero: {
6+
tagline: 'Cloud Native Provence 2026',
7+
title: 'The Cloud Native community <br /><span class="text-accent dark:text-white">in the heart of Provence</span>',
8+
subtitle:
9+
'On December 10, 2026 in Aix-en-Provence, join us for an immersive day of conferences, workshops and discussions around Kubernetes, DevOps and Cloud Native.',
10+
imageAlt: 'Cloud Native & Kubernetes',
11+
},
12+
team: {
13+
title: 'Who are we?',
14+
subtitle: 'A team of enthusiasts who animate the Cloud Native community in Provence',
15+
tagline: 'Team',
16+
},
17+
objectives: {
18+
title: 'Our objectives',
19+
subtitle:
20+
'Cloud Native Provence aims to bring together the local tech community around modern and collaborative technologies.',
21+
items: [
22+
{
23+
title: 'Knowledge sharing',
24+
description: 'Technical talks to discover, learn and deepen Cloud Native practices.',
25+
icon: 'tabler:book',
26+
},
27+
{
28+
title: 'Community meetings',
29+
description: 'Encourage exchanges between developers, engineers, architects and enthusiasts.',
30+
icon: 'tabler:users',
31+
},
32+
{
33+
title: 'Visibility for sponsors',
34+
description: 'An opportunity to show your commitment to a dynamic technical community.',
35+
icon: 'tabler:speakerphone',
36+
},
37+
],
38+
},
39+
values: {
40+
title: 'Our values',
41+
subtitle: 'Driven by the community, Cloud Native Provence defends values of sharing, inclusiveness and openness.',
42+
items: [
43+
{
44+
title: 'Community',
45+
description: 'Non-profit event, organized by volunteers and open to all enthusiasts.',
46+
},
47+
{
48+
title: 'Accessibility',
49+
description: 'An affordable day with accessible tickets and sponsors who make it possible.',
50+
},
51+
{
52+
title: 'Quality',
53+
description: 'Carefully selected presentations, without intrusive commercial approach.',
54+
},
55+
],
56+
},
57+
location: {
58+
title: 'Location',
59+
tagline: 'Join us in Aix-en-Provence',
60+
items: [
61+
{
62+
title: 'Aix-en-Provence',
63+
description: 'Exact location to come. Accessible by train, car and local transport.',
64+
},
65+
],
66+
},
67+
contact: {
68+
title: 'Contact',
69+
tagline: 'The Cloud Native Provence team',
70+
items: [
71+
{
72+
title: 'Write to us',
73+
description: 'info@cloudnative-provence.fr',
74+
icon: 'tabler:mail',
75+
},
76+
{
77+
title: 'Sponsoring',
78+
description: 'sponsors@cloudnative-provence.fr',
79+
icon: 'tabler:briefcase',
80+
},
81+
],
82+
},
83+
} as const;
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
export default {
2+
metadata: {
3+
title: 'À propos',
4+
},
5+
hero: {
6+
tagline: 'Cloud Native Provence 2026',
7+
title: 'La communauté Cloud Native <br /><span class="text-accent dark:text-white">au cœur de la Provence</span>',
8+
subtitle:
9+
"Le 10 décembre 2026 à Aix-en-Provence, rejoignez-nous pour une journée immersive de conférences, d'ateliers et d'échanges autour de Kubernetes, DevOps et du Cloud Native.",
10+
imageAlt: 'Cloud Native & Kubernetes',
11+
},
12+
team: {
13+
title: 'Qui sommes-nous ?',
14+
subtitle: 'Une équipe de passionnés qui anime la communauté Cloud Native en Provence',
15+
tagline: 'Équipe',
16+
},
17+
objectives: {
18+
title: 'Nos objectifs',
19+
subtitle:
20+
'Cloud Native Provence vise à rassembler la communauté tech locale autour de technologies modernes et collaboratives.',
21+
items: [
22+
{
23+
title: 'Partage de connaissances',
24+
description: 'Des talks techniques pour découvrir, apprendre et approfondir les pratiques Cloud Native.',
25+
icon: 'tabler:book',
26+
},
27+
{
28+
title: 'Rencontres communautaires',
29+
description: 'Favoriser les échanges entre développeurs, ingénieurs, architectes et passionnés.',
30+
icon: 'tabler:users',
31+
},
32+
{
33+
title: 'Visibilité pour les sponsors',
34+
description: "Une opportunité de montrer votre engagement auprès d'une communauté technique dynamique.",
35+
icon: 'tabler:speakerphone',
36+
},
37+
],
38+
},
39+
values: {
40+
title: 'Nos valeurs',
41+
subtitle:
42+
"Porté par la communauté, Cloud Native Provence défend des valeurs de partage, d'inclusivité et d'ouverture.",
43+
items: [
44+
{
45+
title: 'Communauté',
46+
description: 'Événement à but non lucratif, organisé par des bénévoles et ouvert à tous les passionnés.',
47+
},
48+
{
49+
title: 'Accessibilité',
50+
description: 'Une journée abordable avec des tickets accessibles et des sponsors qui rendent cela possible.',
51+
},
52+
{
53+
title: 'Qualité',
54+
description: 'Des interventions sélectionnées avec soin, sans démarche commerciale intrusive.',
55+
},
56+
],
57+
},
58+
location: {
59+
title: 'Localisation',
60+
tagline: 'Rejoignez-nous à Aix-en-Provence',
61+
items: [
62+
{
63+
title: 'Aix-en-Provence',
64+
description: 'Lieu exact à venir. Accessible en train, voiture et transport local.',
65+
},
66+
],
67+
},
68+
contact: {
69+
title: 'Contact',
70+
tagline: "L'équipe Cloud Native Provence",
71+
items: [
72+
{
73+
title: 'Écrivez-nous',
74+
description: 'info@cloudnative-provence.fr',
75+
icon: 'tabler:mail',
76+
},
77+
{
78+
title: 'Sponsoring',
79+
description: 'sponsors@cloudnative-provence.fr',
80+
icon: 'tabler:briefcase',
81+
},
82+
],
83+
},
84+
} as const;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
export const teamMembers = [
2+
{
3+
title: 'Frédéric Leger',
4+
image: { src: '~/assets/images/team/frederic-leger.jpg' },
5+
},
6+
{
7+
title: 'Henrik Rexed',
8+
image: { src: '~/assets/images/team/henrik-rexed.jpg' },
9+
},
10+
{
11+
title: 'Sébastien Blanc',
12+
image: { src: '~/assets/images/team/sebastien-blanc.jpg' },
13+
},
14+
{
15+
title: 'Shérine Khoury',
16+
image: { src: '~/assets/images/team/sherine-khoury.jpg' },
17+
},
18+
{
19+
title: 'Emilien Escalle',
20+
image: { src: '~/assets/images/team/emilien-escalle.jpg' },
21+
},
22+
{
23+
title: 'Luc Juggery',
24+
image: { src: '~/assets/images/team/luc-juggery.jpg' },
25+
},
26+
{
27+
title: 'Thomas Perelle',
28+
image: { src: '~/assets/images/team/thomas-perelle.jpg' },
29+
},
30+
{
31+
title: 'Rémi Verchère',
32+
image: { src: '~/assets/images/team/remi-verchere.jpg' },
33+
},
34+
];

0 commit comments

Comments
 (0)