feat(i18n): French and German localization (phase 5)
- Add full message catalogs and content for French (fr) and German (de) - Implement ASCII canonical slugs for French and German routes - Add language-specific search endpoints (/api/busca/fr, /api/busca/de) - Configure strict 404 responses for /fr/livro and /de/livro - Localize SEO, OpenGraph (fr_FR, de_DE), Twitter and JSON-LD schemas - Add localized code example comments across 14 examples for fr and de - Enable 'fr' and 'de' in ENABLED_LOCALES with root negotiation and redirect - Extend test suite in check-i18n, smoke-imagem and verifica-vazamentos Co-Authored-By: Antigravity <noreply@google.com>
This commit is contained in:
1 parent
7b673aeb4b
commit
7fce46b9e1
104 files changed
+33369
-686
No files matched your search
+29
-3
@@ -15,6 +15,8 @@ export default function PageHero({
|
||||
children,
|
||||
isEn: isEnProp,
|
||||
isEs: isEsProp,
|
||||
isFr: isFrProp,
|
||||
isDe: isDeProp,
|
||||
locale: localeProp,
|
||||
}) {
|
||||
const center = align === "center";
|
||||
@@ -30,13 +32,37 @@ export default function PageHero({
|
||||
: localeProp
|
||||
? localeProp === "es"
|
||||
: trail.some((t) => t.isEs || (t.href && t.href.startsWith("/es")));
|
||||
const isFr =
|
||||
isFrProp !== undefined
|
||||
? isFrProp
|
||||
: localeProp
|
||||
? localeProp === "fr"
|
||||
: trail.some((t) => t.isFr || (t.href && t.href.startsWith("/fr")));
|
||||
const isDe =
|
||||
isDeProp !== undefined
|
||||
? isDeProp
|
||||
: localeProp
|
||||
? localeProp === "de"
|
||||
: trail.some((t) => t.isDe || (t.href && t.href.startsWith("/de")));
|
||||
|
||||
const homeHref = isEn ? "/en" : isEs ? "/es" : isFr ? "/fr" : isDe ? "/de" : "/";
|
||||
const homeLabel = isEn ? "Home" : isEs ? "Inicio" : isFr ? "Accueil" : isDe ? "Startseite" : "Início";
|
||||
const breadcrumbAria = isEn
|
||||
? "Breadcrumb navigation"
|
||||
: isEs
|
||||
? "Navegación por migas de pan"
|
||||
: isFr
|
||||
? "Fil d'Ariane"
|
||||
: isDe
|
||||
? "Brotkrumennavigation"
|
||||
: "Trilha de navegação";
|
||||
|
||||
return (
|
||||
<section className="shell pt-8 sm:pt-12">
|
||||
{trail.length > 0 && (
|
||||
<nav aria-label={isEn ? "Breadcrumb navigation" : isEs ? "Navegación por migas de pan" : "Trilha de navegação"} className="flex flex-wrap items-center gap-2 text-sm text-muted">
|
||||
<Link href={isEn ? "/en" : isEs ? "/es" : "/"} className="inline-flex min-h-11 min-w-11 items-center justify-center transition-colors hover:text-accent">
|
||||
{isEn ? "Home" : isEs ? "Inicio" : "Início"}
|
||||
<nav aria-label={breadcrumbAria} className="flex flex-wrap items-center gap-2 text-sm text-muted">
|
||||
<Link href={homeHref} className="inline-flex min-h-11 min-w-11 items-center justify-center transition-colors hover:text-accent">
|
||||
{homeLabel}
|
||||
</Link>
|
||||
{trail.map((item, i) => (
|
||||
<span key={item.label} className="flex min-h-11 items-center gap-2">
|
||||
|
||||
Reference in new issue
Block a user