fix(i18n): extract navigation links module and restore verbatim pt footer
- Move getLocalizedHref, LOCALES, and CANONICAL_ROUTES to i18n/links.js to resolve SSR 500 error on home - Import from @/i18n/links in page.jsx, Header.jsx, Footer.jsx, and LanguageSelector.jsx - Restore exact production footer texts, author links, and SVG icons in pt - Verify 100% visible text parity on all pt pages against production with cmp-pt.py Co-Authored-By: Antigravity <noreply@google.com>
This commit is contained in:
1 parent
02dee65b2b
commit
dcd4ef7e1b
5 files changed
+170
-157
No files matched your search
@@ -5,7 +5,7 @@ import Link from "next/link";
|
|||||||
import seriesData from "@/public/series.json";
|
import seriesData from "@/public/series.json";
|
||||||
import frameworksData from "@/public/frameworks.json";
|
import frameworksData from "@/public/frameworks.json";
|
||||||
import { SITE } from "@/lib/seo";
|
import { SITE } from "@/lib/seo";
|
||||||
import { getLocalizedHref } from "@/components/LanguageSelector";
|
import { getLocalizedHref } from "@/i18n/links";
|
||||||
import {
|
import {
|
||||||
AlertTriangle,
|
AlertTriangle,
|
||||||
ArrowRight,
|
ArrowRight,
|
||||||
|
|||||||
+36
-31
@@ -6,16 +6,16 @@ import Logo from "@/components/Logo";
|
|||||||
import GiteaMark from "@/components/GiteaMark";
|
import GiteaMark from "@/components/GiteaMark";
|
||||||
import { ArrowUpRight } from "lucide-react";
|
import { ArrowUpRight } from "lucide-react";
|
||||||
import { SITE } from "@/lib/seo";
|
import { SITE } from "@/lib/seo";
|
||||||
import { LOCALES, getLocalizedHref } from "@/components/LanguageSelector";
|
import { LOCALES, getLocalizedHref } from "@/i18n/links";
|
||||||
|
|
||||||
const BASE_COLUMNS = [
|
const COLUMNS = [
|
||||||
{
|
{
|
||||||
title: "Explorar",
|
title: "Explorar",
|
||||||
links: [
|
links: [
|
||||||
{ href: "/series", label: "Séries ESP32" },
|
{ href: "/series", label: "Séries ESP32" },
|
||||||
{ href: "/comparacao", label: "Comparador" },
|
{ href: "/comparacao", label: "Comparador" },
|
||||||
{ href: "/catalogo", label: "Catálogo de placas" },
|
{ href: "/catalogo", label: "Catálogo de placas" },
|
||||||
{ href: "/livro", label: "O livro", livroOnly: true },
|
{ href: "/livro", label: "O livro" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -48,9 +48,9 @@ export default function Footer() {
|
|||||||
|
|
||||||
const getLinkHref = (href) => getLocalizedHref(`/${currentLocale}${href}`, currentLocale);
|
const getLinkHref = (href) => getLocalizedHref(`/${currentLocale}${href}`, currentLocale);
|
||||||
|
|
||||||
const columns = BASE_COLUMNS.map((col) => ({
|
const columns = COLUMNS.map((column) => ({
|
||||||
...col,
|
...column,
|
||||||
links: col.links.filter((l) => !l.livroOnly || isPt),
|
links: column.links.filter((link) => link.href !== "/livro" || isPt),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -139,40 +139,45 @@ export default function Footer() {
|
|||||||
<br />
|
<br />
|
||||||
<span className="text-xs text-faint">Ciência Embarcada</span>
|
<span className="text-xs text-faint">Ciência Embarcada</span>
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-2 flex flex-wrap gap-x-4 gap-y-1 text-sm">
|
<div className="mt-4 flex items-center gap-2">
|
||||||
<a href={SITE.autorUrl} target="_blank" rel="noopener noreferrer" className="inline-flex min-h-11 items-center text-muted transition-colors hover:text-accent">
|
<a
|
||||||
Site pessoal
|
href={SITE.repositorio}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="Gitea do projeto (abre em nova aba)"
|
||||||
|
className="grid h-11 w-11 place-items-center rounded-full border border-line text-ink transition-colors hover:border-line-strong hover:bg-surface"
|
||||||
|
>
|
||||||
|
<GiteaMark className="h-4 w-4" />
|
||||||
</a>
|
</a>
|
||||||
<a href={SITE.autorLinkedin} target="_blank" rel="noopener noreferrer" className="inline-flex min-h-11 items-center text-muted transition-colors hover:text-accent">
|
<a
|
||||||
LinkedIn
|
href={SITE.autorLinkedin}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="LinkedIn do autor (abre em nova aba)"
|
||||||
|
className="grid h-11 w-11 place-items-center rounded-full border border-line text-ink transition-colors hover:border-line-strong hover:bg-surface"
|
||||||
|
>
|
||||||
|
<svg className="h-4 w-4" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||||
|
<path d="M4.98 3.5a2.5 2.5 0 1 1 0 5.001 2.5 2.5 0 0 1 0-5zM3 8.98h4v12H3v-12zm6.5 0h3.8v1.6h.1c.5-.9 1.8-1.9 3.6-1.9 3.8 0 4.5 2.5 4.5 5.8v6.5h-4v-5.8c0-1.4-.1-3.2-2-3.2-2 0-2.3 1.6-2.3 3.1v5.9h-4v-12z" />
|
||||||
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-12 flex flex-col items-center justify-between gap-4 border-t border-line pt-8 text-xs text-muted sm:flex-row">
|
<div className="mt-14 flex flex-col gap-4 border-t border-line pt-6 text-xs leading-relaxed text-faint md:flex-row md:items-center md:justify-between">
|
||||||
<p>© {year} ESPDocs · Conteúdo sob licença MIT. Feito para a comunidade de sistemas embarcados.</p>
|
<p>© {year} ESPDocs. Projeto independente, sem afiliação com a Espressif Systems.</p>
|
||||||
<div className="flex items-center gap-6">
|
<p className="flex flex-wrap items-center gap-x-5 gap-y-2">
|
||||||
<a
|
<a href={SITE.blog} target="_blank" rel="noopener noreferrer" className="inline-flex min-h-11 items-center gap-1 transition-colors hover:text-accent">
|
||||||
href={SITE.repositorio}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="inline-flex min-h-11 items-center gap-1.5 transition-colors hover:text-accent"
|
|
||||||
>
|
|
||||||
<GiteaMark className="h-4 w-4" aria-hidden="true" />
|
|
||||||
<span>Gitea</span>
|
|
||||||
</a>
|
|
||||||
<span>·</span>
|
|
||||||
<a
|
|
||||||
href={SITE.blog}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="inline-flex min-h-11 items-center transition-colors hover:text-accent"
|
|
||||||
>
|
|
||||||
Ciência Embarcada
|
Ciência Embarcada
|
||||||
|
<ArrowUpRight className="h-3 w-3" aria-hidden="true" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
<a href={SITE.autorUrl} target="_blank" rel="noopener noreferrer" className="inline-flex min-h-11 items-center gap-1 transition-colors hover:text-accent">
|
||||||
|
lucasrguerra.dev.br
|
||||||
|
<ArrowUpRight className="h-3 w-3" aria-hidden="true" />
|
||||||
|
</a>
|
||||||
|
<span>Fontes oficiais: Espressif Systems.</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import { createPortal } from "react-dom";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Logo from "@/components/Logo";
|
import Logo from "@/components/Logo";
|
||||||
import SearchDialog from "@/components/SearchDialog";
|
import SearchDialog from "@/components/SearchDialog";
|
||||||
import LanguageSelector, { LOCALES, getLocalizedHref } from "@/components/LanguageSelector";
|
import LanguageSelector from "@/components/LanguageSelector";
|
||||||
|
import { LOCALES, getLocalizedHref } from "@/i18n/links";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -3,131 +3,9 @@
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { ChevronDown, Globe } from "lucide-react";
|
import { ChevronDown, Globe } from "lucide-react";
|
||||||
|
import { LOCALES, getLocalizedHref } from "@/i18n/links";
|
||||||
|
|
||||||
export const LOCALES = [
|
export { LOCALES, getLocalizedHref };
|
||||||
{ 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" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const CANONICAL_ROUTES = [
|
|
||||||
{
|
|
||||||
id: "series_item",
|
|
||||||
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:series|serien)\/([^/]+)/,
|
|
||||||
getSlug: (loc, key) => (loc === "de" ? `/serien/${key}` : `/series/${key}`),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "frameworks_item",
|
|
||||||
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/frameworks\/([^/]+)/,
|
|
||||||
getSlug: (loc, key) => `/frameworks/${key}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "series",
|
|
||||||
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:series|serien)(?:\/|$)/,
|
|
||||||
getSlug: (loc) => (loc === "de" ? "/serien" : "/series"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "catalogo",
|
|
||||||
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:catalogo|catalog|catalogue|katalog)(?:\/|$)/,
|
|
||||||
getSlug: (loc) => {
|
|
||||||
if (loc === "de") return "/katalog";
|
|
||||||
if (loc === "fr") return "/catalogue";
|
|
||||||
if (loc === "en" || loc === "zh-CN") return "/catalog";
|
|
||||||
return "/catalogo";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "comparacao",
|
|
||||||
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:comparacao|compare|comparacion|comparaison|vergleich)(?:\/|$)/,
|
|
||||||
getSlug: (loc) => {
|
|
||||||
if (loc === "en" || loc === "zh-CN") return "/compare";
|
|
||||||
if (loc === "es") return "/comparacion";
|
|
||||||
if (loc === "fr") return "/comparaison";
|
|
||||||
if (loc === "de") return "/vergleich";
|
|
||||||
return "/comparacao";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "componentes",
|
|
||||||
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:componentes|components|composants|komponenten)(?:\/|$)/,
|
|
||||||
getSlug: (loc) => {
|
|
||||||
if (loc === "en" || loc === "zh-CN") return "/components";
|
|
||||||
if (loc === "fr") return "/composants";
|
|
||||||
if (loc === "de") return "/komponenten";
|
|
||||||
return "/componentes";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "diagnostico",
|
|
||||||
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:diagnostico|diagnostics|diagnostic|diagnose)(?:\/|$)/,
|
|
||||||
getSlug: (loc) => {
|
|
||||||
if (loc === "en" || loc === "zh-CN") return "/diagnostics";
|
|
||||||
if (loc === "fr") return "/diagnostic";
|
|
||||||
if (loc === "de") return "/diagnose";
|
|
||||||
return "/diagnostico";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "frameworks",
|
|
||||||
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/frameworks(?:\/|$)/,
|
|
||||||
getSlug: () => "/frameworks",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "glossario",
|
|
||||||
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:glossario|glossary|glosario|glossaire|glossar)(?:\/|$)/,
|
|
||||||
getSlug: (loc) => {
|
|
||||||
if (loc === "en" || loc === "zh-CN") return "/glossary";
|
|
||||||
if (loc === "es") return "/glosario";
|
|
||||||
if (loc === "fr") return "/glossaire";
|
|
||||||
if (loc === "de") return "/glossar";
|
|
||||||
return "/glossario";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "seletor",
|
|
||||||
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:seletor|selector|selecteur|auswahl)(?:\/|$)/,
|
|
||||||
getSlug: (loc) => {
|
|
||||||
if (loc === "en" || loc === "es" || loc === "zh-CN") return "/selector";
|
|
||||||
if (loc === "fr") return "/selecteur";
|
|
||||||
if (loc === "de") return "/auswahl";
|
|
||||||
return "/seletor";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "sobre",
|
|
||||||
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:sobre|about|acerca|a-propos|ueber-uns)(?:\/|$)/,
|
|
||||||
getSlug: (loc) => {
|
|
||||||
if (loc === "en" || loc === "zh-CN") return "/about";
|
|
||||||
if (loc === "es") return "/acerca";
|
|
||||||
if (loc === "fr") return "/a-propos";
|
|
||||||
if (loc === "de") return "/ueber-uns";
|
|
||||||
return "/sobre";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "livro",
|
|
||||||
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/livro(?:\/|$)/,
|
|
||||||
getSlug: (loc) => (loc === "pt" ? "/livro" : ""),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export function getLocalizedHref(pathname, targetLocale) {
|
|
||||||
if (!pathname || pathname === "/" || pathname === `/${targetLocale}` || pathname === `/${targetLocale}/`) {
|
|
||||||
return `/${targetLocale}/`;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const route of CANONICAL_ROUTES) {
|
|
||||||
const m = pathname.match(route.match);
|
|
||||||
if (m) {
|
|
||||||
const slug = route.getSlug(targetLocale, m[1]);
|
|
||||||
return slug ? `/${targetLocale}${slug}` : `/${targetLocale}/`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return `/${targetLocale}/`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function LanguageSelector() {
|
export default function LanguageSelector() {
|
||||||
const pathname = usePathname() || "";
|
const pathname = usePathname() || "";
|
||||||
|
|||||||
+129
@@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
* Utilitários de rotas e navegação internacionalizada.
|
||||||
|
* 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" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const CANONICAL_ROUTES = [
|
||||||
|
{
|
||||||
|
id: "series_item",
|
||||||
|
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:series|serien)\/([^/]+)/,
|
||||||
|
getSlug: (loc, key) => (loc === "de" ? `/serien/${key}` : `/series/${key}`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "frameworks_item",
|
||||||
|
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/frameworks\/([^/]+)/,
|
||||||
|
getSlug: (loc, key) => `/frameworks/${key}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "series",
|
||||||
|
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:series|serien)(?:\/|$)/,
|
||||||
|
getSlug: (loc) => (loc === "de" ? "/serien" : "/series"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "catalogo",
|
||||||
|
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:catalogo|catalog|catalogue|katalog)(?:\/|$)/,
|
||||||
|
getSlug: (loc) => {
|
||||||
|
if (loc === "de") return "/katalog";
|
||||||
|
if (loc === "fr") return "/catalogue";
|
||||||
|
if (loc === "en" || loc === "zh-CN") return "/catalog";
|
||||||
|
return "/catalogo";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "comparacao",
|
||||||
|
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:comparacao|compare|comparacion|comparaison|vergleich)(?:\/|$)/,
|
||||||
|
getSlug: (loc) => {
|
||||||
|
if (loc === "en" || loc === "zh-CN") return "/compare";
|
||||||
|
if (loc === "es") return "/comparacion";
|
||||||
|
if (loc === "fr") return "/comparaison";
|
||||||
|
if (loc === "de") return "/vergleich";
|
||||||
|
return "/comparacao";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "componentes",
|
||||||
|
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:componentes|components|composants|komponenten)(?:\/|$)/,
|
||||||
|
getSlug: (loc) => {
|
||||||
|
if (loc === "en" || loc === "zh-CN") return "/components";
|
||||||
|
if (loc === "fr") return "/composants";
|
||||||
|
if (loc === "de") return "/komponenten";
|
||||||
|
return "/componentes";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "diagnostico",
|
||||||
|
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:diagnostico|diagnostics|diagnostic|diagnose)(?:\/|$)/,
|
||||||
|
getSlug: (loc) => {
|
||||||
|
if (loc === "en" || loc === "zh-CN") return "/diagnostics";
|
||||||
|
if (loc === "fr") return "/diagnostic";
|
||||||
|
if (loc === "de") return "/diagnose";
|
||||||
|
return "/diagnostico";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "frameworks",
|
||||||
|
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/frameworks(?:\/|$)/,
|
||||||
|
getSlug: () => "/frameworks",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "glossario",
|
||||||
|
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:glossario|glossary|glosario|glossaire|glossar)(?:\/|$)/,
|
||||||
|
getSlug: (loc) => {
|
||||||
|
if (loc === "en" || loc === "zh-CN") return "/glossary";
|
||||||
|
if (loc === "es") return "/glosario";
|
||||||
|
if (loc === "fr") return "/glossaire";
|
||||||
|
if (loc === "de") return "/glossar";
|
||||||
|
return "/glossario";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "seletor",
|
||||||
|
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:seletor|selector|selecteur|auswahl)(?:\/|$)/,
|
||||||
|
getSlug: (loc) => {
|
||||||
|
if (loc === "en" || loc === "es" || loc === "zh-CN") return "/selector";
|
||||||
|
if (loc === "fr") return "/selecteur";
|
||||||
|
if (loc === "de") return "/auswahl";
|
||||||
|
return "/seletor";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "sobre",
|
||||||
|
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/(?:sobre|about|acerca|a-propos|ueber-uns)(?:\/|$)/,
|
||||||
|
getSlug: (loc) => {
|
||||||
|
if (loc === "en" || loc === "zh-CN") return "/about";
|
||||||
|
if (loc === "es") return "/acerca";
|
||||||
|
if (loc === "fr") return "/a-propos";
|
||||||
|
if (loc === "de") return "/ueber-uns";
|
||||||
|
return "/sobre";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "livro",
|
||||||
|
match: /^\/(?:pt|en|es|fr|de|zh-CN)\/livro(?:\/|$)/,
|
||||||
|
getSlug: (loc) => (loc === "pt" ? "/livro" : ""),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function getLocalizedHref(pathname, targetLocale) {
|
||||||
|
if (!pathname || pathname === "/" || pathname === `/${targetLocale}` || pathname === `/${targetLocale}/`) {
|
||||||
|
return `/${targetLocale}/`;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const route of CANONICAL_ROUTES) {
|
||||||
|
const m = pathname.match(route.match);
|
||||||
|
if (m) {
|
||||||
|
const slug = route.getSlug(targetLocale, m[1]);
|
||||||
|
return slug ? `/${targetLocale}${slug}` : `/${targetLocale}/`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return `/${targetLocale}/`;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user