astro native i18n + i18n utils

This commit is contained in:
nico 2024-12-28 11:52:32 +01:00
parent 99ef7634e3
commit b7ce5b7f20
Signed by: Nicolas
SSH key fingerprint: SHA256:ELi8eDeNLl5PTn64G+o2Kx5+XVDfHF5um2tZigfwWkM
16 changed files with 266 additions and 163 deletions

View file

@ -1,38 +1,12 @@
---
import { l, astroI18n } from "astro-i18n";
// get all the locales available on the website and remove the one currently in use
const availableLocales = astroI18n.langCodes.filter(
(locale) => locale !== astroI18n.langCode
);
// current path
const currentRoute = Astro.url.pathname;
function localeName(locale) {
let localeName = "";
switch (locale) {
case "fr":
localeName = "Français";
break;
case "en":
localeName = "English";
break;
}
return localeName;
}
import { languages } from '../i18n/ui'
---
<ul role="list">
<ul>
{
// create a list of available alternative locale
availableLocales.map((locale) => (
Object.entries(languages).map(([lang, label]) => (
<li>
<a
href={l(currentRoute as any, {}, locale as any)}
class="clean-link nice-link"
>
{localeName(locale)}
</a>
<a href={`/${lang}/`}>{label}</a>
</li>
))
}

150
src/i18n/ui.ts Normal file
View file

@ -0,0 +1,150 @@
export const languages = {
en: 'English',
fr: 'Français'
}
export const defaultLang = 'fr'
export const ui = {
en: {
accueil: 'home',
tagline: 'Freelance web developer specialized in accessibility.',
copyright: '(re)Made with Astro',
contact: {
title: 'contact',
email: 'Send me an email (open in application).',
tel: 'Call or text me (open in application).',
contenuVide: 'Soon: really nice content.'
},
header: {
skipLink: 'Skip to content',
mainNav: 'Main menu',
homeLink: 'Back to homepage'
},
sitemap: 'Site map',
prevNext: {
contenus: 'Similar content',
precedent: 'Previous',
suivant: 'Next'
},
article: {
titre: 'articles',
tagline: 'I blog, sometimes.',
published: 'Published on {datetime|date(options)}'
},
meta: {
publication: 'Published on',
modification: 'Last updated on',
credit: 'Image by'
},
fragments: {
titre: 'snippets',
tagline: 'School with Nicool.'
},
references: {
titre: 'work',
slug: 'work',
cta: 'Visit website',
tagline: 'Some work.'
},
veille: {
titre: 'Around the web',
tagline: 'Some links that interested me.'
},
erreur: {
introuvable: 'Sorry, page not found.',
autre: 'Oups… sorry about that.',
lienRetour: 'Back to the home page'
},
seo: {
meta: {
description:
'Web developer specialized in accessibility and eco-design in Toulouse, France. Development of custom websites, RGAA compliance, maintenance, etc.'
},
article: {
title: 'Articles',
description:
'A few articles about graphic design and front-end development.'
},
code: {
title: 'Snippets',
description: 'Snippets of fresh, easy and accessible code.'
},
references: {
title: 'Work',
description: 'A few case studies I worked on as a front-end developer.'
}
}
},
fr: {
accueil: 'accueil',
tagline: 'Développeur web spécialisé en accessibilité.',
copyright: '(re)Fait avec Astro',
contact: {
title: 'contact',
email: 'Envoyez-moi un mail (ouverture du logiciel automatique).',
tel: 'Contactez-moi par téléphone (ouverture du logiciel automatique).'
},
contenuVide: 'Bientôt ici : du contenu de qualité',
header: {
skipLink: 'Accéder au contenu',
mainNav: 'Menu principal',
homeLink: 'Accueil du site'
},
sitemap: 'Plan du site',
prevNext: {
contenus: 'Contenus similaires',
precedent: 'Précédent',
suivant: 'Suivant'
},
article: {
titre: 'articles',
tagline: 'Je blog, un peu.',
published: 'Publié le {datetime|date(options)}'
},
meta: {
publication: 'Publié le',
modification: 'Mis à jour le',
credit: 'Image par'
},
fragments: {
titre: 'fragments',
tagline: 'Les tutos de Nico mdr.'
},
references: {
titre: 'références',
slug: 'references',
cta: 'Consulter le site',
tagline: 'Quelques références.'
},
veille: {
titre: 'veille',
tagline: 'Des liens, en vrac.'
},
erreur: {
introuvable: 'Page introuvable',
autre: 'Oups… désolé pour cette erreur.',
lienRetour: 'Retour à laccueil'
},
seo: {
meta: {
description:
'Développeur web spécialisé en accessibilité numérique et éco-conception à Toulouse. Création de sites web sur mesure, mise en conformité RGAA, maintenance, etc.'
},
article: {
title: 'Articles',
description:
"Quelques articles sur le développement web front-end et l'informatique à Toulouse."
},
code: {
title: 'Fragments',
description: 'Fragments de codes stylés, faciles et accessibles.'
},
references: {
title: 'Références',
description:
'Quelques travaux réalisés en tant que et développeur web front-end à Toulouse.'
}
}
}
} as const

View file

@ -1,6 +1,5 @@
---
import { astroI18n } from "astro-i18n";
astroI18n.init(Astro);
const locale = Astro.currentLocale;
import "../styles/style.css";
@ -11,7 +10,7 @@ import Footer from "../components/Footer.astro";
const { pageTitle } = Astro.props;
---
<html lang={astroI18n.langCode} dir="ltr">
<html lang={locale} dir="ltr">
<Head pageTitle={pageTitle} />
<body>
<div class="wrapper">

View file

@ -1,33 +1,27 @@
---
import { l, t, astroI18n } from "astro-i18n";
// import AstroImage from "../components/AstroImage.astro";
import BaseLayout from "../layouts/BaseLayout.astro";
import BaseLayout from '../layouts/BaseLayout.astro'
import { getLangFromUrl, useTranslations } from '../utils/i18n'
const { frontmatter, image, title } = Astro.props;
const publishedDate = new Date(frontmatter.pubDate);
const localizedDate = new Intl.DateTimeFormat(astroI18n.langCode, {
dateStyle: "long",
}).format(publishedDate);
const locale = getLangFromUrl(Astro.url)
const t = useTranslations(locale)
const { frontmatter, image, title } = Astro.props
const publishedDate = new Date(frontmatter.pubDate)
const localizedDate = new Intl.DateTimeFormat(locale, {
dateStyle: 'long'
}).format(publishedDate)
---
<BaseLayout pageTitle={title}>
<p>
Publié le&nbsp;: <time datetime={frontmatter.pubDate}>
{t('article.published')}&nbsp;: <time datetime={frontmatter.pubDate}>
{localizedDate}.
</time>
</p>
<p>
{
t("article.published", {
datetime: frontmatter.pubDate,
options: { dateStyle: "long" },
})
}
</p>
<div class="tags">
<div class='tags'>
{
frontmatter.tags.map((tag) => (
<p class="tag">
<p class='tag'>
<a href={l(`/tags/${[tag]}`)}>{tag}</a>
</p>
))

View file

@ -1,8 +1,5 @@
---
// init i18n
import { getLocale } from "astro-i18n-aut";
const locale = getLocale(Astro.url);
const locale = Astro.currentLocale;
// import stuff
import BaseLayout from "../layouts/BaseLayout.astro";

28
src/utils/i18n.ts Normal file
View file

@ -0,0 +1,28 @@
import { defaultLang, ui } from '../i18n/ui'
export function getLangFromUrl(url: URL) {
const [, lang] = url.pathname.split('/')
if (lang in ui) return lang as keyof typeof ui
return defaultLang
}
type NestedKeyOf<T> = {
[K in keyof T]: T[K] extends object
? `${K & string}.${NestedKeyOf<T[K]> & string}`
: K & string
}[keyof T]
export function useTranslations(lang: keyof typeof ui) {
return function t(key: NestedKeyOf<(typeof ui)[typeof defaultLang]>) {
const keys = key.split('.')
let value = ui[lang]
let fallback = ui[defaultLang]
for (const k of keys) {
value = value?.[k]
fallback = fallback?.[k]
}
return value || fallback
}
}