Rebuild du site sur Astro : i18n multilingue, faits verifies, Docker, CI, tests
- Astro statique, EN par defaut + /fr/ + /nl/, detection langue navigateur - i18n par fichiers JSON, ajouter une langue = ajouter des traductions - Contenu original porte a l'identique (diff d'inventaire par langue) - Chronologie legislative corrigee sur sources primaires (PE, Conseil, votes) - Timeline 23 precedents + observatoire 35 items + annuaire 66 outils FOSS, chaque affirmation verifiee et sourcee - Zero requete tierce (teste), lisible JS coupe, axe WCAG AA x2 themes - Version offline monofichier par langue a chaque build - Docker multi-stage vers nginx + CSP stricte auto-generee - CI GitHub Actions (SHA-pinnees) + verification hebdo des liens - CONTRIBUTING : divulgation d'affiliation obligatoire, allowlist de domaines testee en CI
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import en from './en.json'
|
||||
import fr from './fr.json'
|
||||
import nl from './nl.json'
|
||||
import { defaultLocale, locales, type Locale } from './locales'
|
||||
|
||||
export { locales, defaultLocale, localeNames, localeFlags, type Locale } from './locales'
|
||||
|
||||
type Dict = typeof en
|
||||
// fr/nl are type-checked against the English shape: a missing key is a
|
||||
// build error, not a silent English fallback.
|
||||
const dicts: Record<Locale, Dict> = { en, fr, nl }
|
||||
|
||||
function lookup(dict: Dict, path: string): unknown {
|
||||
return path.split('.').reduce<unknown>((node, key) => {
|
||||
if (node && typeof node === 'object' && key in node) {
|
||||
return (node as Record<string, unknown>)[key]
|
||||
}
|
||||
return undefined
|
||||
}, dict)
|
||||
}
|
||||
|
||||
/** Returns the UI string for `path` in `locale`, falling back to English. */
|
||||
export function useT(locale: Locale) {
|
||||
return (path: string): string => {
|
||||
const hit = lookup(dicts[locale], path) ?? lookup(dicts[defaultLocale], path)
|
||||
if (typeof hit !== 'string') {
|
||||
throw new Error(`Missing i18n key "${path}" (locale: ${locale})`)
|
||||
}
|
||||
return hit
|
||||
}
|
||||
}
|
||||
|
||||
/** Path prefix for a locale: '' for the default locale (served at /). */
|
||||
export function localePath(locale: Locale): string {
|
||||
return locale === defaultLocale ? '' : `/${locale}`
|
||||
}
|
||||
|
||||
/** The non-default locales, e.g. for getStaticPaths of the [lang] route. */
|
||||
export const translatedLocales = locales.filter((l) => l !== defaultLocale)
|
||||
Reference in New Issue
Block a user