astro native i18n + i18n utils
This commit is contained in:
parent
99ef7634e3
commit
b7ce5b7f20
16 changed files with 266 additions and 163 deletions
|
@ -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
150
src/i18n/ui.ts
Normal 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 à l’accueil'
|
||||
},
|
||||
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
|
|
@ -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">
|
||||
|
|
|
@ -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 : <time datetime={frontmatter.pubDate}>
|
||||
{t('article.published')} : <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>
|
||||
))
|
||||
|
|
|
@ -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
28
src/utils/i18n.ts
Normal 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
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue