feat(i18n): restrict public routes and metadata to enabled locales
CI / Lint e auditorias (push) Successful in 41s
CI / Trivy (dependências e segredos) (push) Successful in 10s
CI / Imagem Docker (linux/arm64) (push) Successful in 2m5s

- Add ENABLED_LOCALES configuration in i18n/links.js (currently ["pt"])
- Redirect inactive locale prefixes to /pt via 307 in middleware.js
- Restrict root locale negotiation to active locales with fallback to pt
- Hide LanguageSelector when only one locale is enabled
- Generate sitemap, hreflang alternates, and og:locale only for active locales
- Generate static SSG pages only for active locales in build
- Adapt check:i18n and smoke-imagem.sh to validate active vs inactive locales

Co-Authored-By: Antigravity <noreply@google.com>
This commit is contained in:
Lucas RayanandAntigravity committed 2026-11-01 12:10:25 -03:00
1 parent 3a1a095e97
commit d479a8d361
9 files changed
+219 -79

No files matched your search

+27 -7
View File
@@ -3,15 +3,23 @@
* Módulo puro (sem 'use client') seguro para Server e Client Components.
*/
export const LOCALES = [
{ code: "pt", label: "Português", short: "PT", lang: "pt-BR" },
{ code: "en", label: "English", short: "EN", lang: "en" },
{ code: "es", label: "Español", short: "ES", lang: "es-419" },
{ code: "fr", label: "Français", short: "FR", lang: "fr" },
{ code: "de", label: "Deutsch", short: "DE", lang: "de" },
{ code: "zh-CN", label: "简体中文", short: "中", lang: "zh-CN" },
// Ponto único de configuração de idiomas ATIVOS.
// Para ativar um novo idioma no site, basta adicionar seu código aqui (ex.: ["pt", "en"]).
export const ENABLED_LOCALES = ["pt"];
export const ALL_LOCALES = [
{ code: "pt", label: "Português", short: "PT", lang: "pt-BR", og: "pt_BR" },
{ code: "en", label: "English", short: "EN", lang: "en", og: "en_US" },
{ code: "es", label: "Español", short: "ES", lang: "es-419", og: "es_419" },
{ code: "fr", label: "Français", short: "FR", lang: "fr", og: "fr_FR" },
{ code: "de", label: "Deutsch", short: "DE", lang: "de", og: "de_DE" },
{ code: "zh-CN", label: "简体中文", short: "中", lang: "zh-CN", og: "zh_CN" },
];
export const ALL_LOCALE_CODES = ALL_LOCALES.map((l) => l.code);
export const LOCALES = ALL_LOCALES.filter((l) => ENABLED_LOCALES.includes(l.code));
export const CANONICAL_ROUTES = [
{
id: "series_item",
@@ -127,3 +135,15 @@ export function getLocalizedHref(pathname, targetLocale) {
}
return `/${targetLocale}/`;
}
export function getPtPath(pathname) {
if (!pathname || pathname === "/" || pathname === "/pt" || pathname === "/pt/") return "/pt";
for (const route of CANONICAL_ROUTES) {
const m = pathname.match(route.match);
if (m) {
const slug = route.getSlug("pt", m[1]);
return slug ? `/pt${slug}` : "/pt";
}
}
return "/pt";
}
+3 -2
View File
@@ -1,8 +1,9 @@
import { defineRouting } from "next-intl/routing";
import { ENABLED_LOCALES } from "./links";
export const routing = defineRouting({
locales: ["pt", "en", "es", "fr", "de", "zh-CN"],
defaultLocale: "en",
locales: ENABLED_LOCALES,
defaultLocale: ENABLED_LOCALES.includes("en") ? "en" : (ENABLED_LOCALES[0] || "pt"),
localePrefix: "always",
pathnames: {
"/": "/",