Fix hreflang canonical + LangToggle: use centralized ES/EN slug map

- Add src/i18n/hreflang-map.ts with getHreflangUrl() for translated slugs
- Fix BaseLayout.astro hreflang tags (was hardcoding ES='/', 404 URLs)
- Fix LangToggle.astro to use hreflang map instead of naive path swap
- Fix htaccess.conf: remove !-f / !-d that blocked .html redirects
This commit is contained in:
Mauricio López Coria
2026-07-05 20:34:15 -03:00
parent ff3e57051f
commit b26959a041
4 changed files with 58 additions and 14 deletions
+1 -3
View File
@@ -12,9 +12,7 @@
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
# Quitar .html de la URL (limpieza opcional)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Quitar .html de la URL — evita duplicados index.html vs /
RewriteCond %{REQUEST_URI} ^(.+)\.html$ [NC]
RewriteRule ^(.+)\.html$ /$1 [R=301,L]
</IfModule>
+8 -9
View File
@@ -1,5 +1,6 @@
---
import { LANGUAGES, DEFAULT_LANG, type Lang } from '@/i18n/utils';
import { LANGUAGES, type Lang } from '@/i18n/utils';
import { getHreflangUrl } from '@/i18n/hreflang-map';
interface Props {
lang: Lang;
@@ -7,19 +8,17 @@ interface Props {
const { lang } = Astro.props;
const path = Astro.url.pathname;
function otherLangUrl(): string {
const cleanPath = path.replace(/^\/(en|es)/, '') || '/';
if (lang === DEFAULT_LANG) {
return `/en${cleanPath === '/' ? '' : cleanPath}`;
}
return cleanPath;
}
const otherLang = lang === 'en' ? 'es' : 'en';
const fullUrl = getHreflangUrl(path, lang, otherLang);
const href = fullUrl
? fullUrl.replace('https://hostingdelsur.net', '')
: otherLang === 'en' ? '/en/' : '/';
const other = LANGUAGES.find((l) => l.code !== lang);
const isEn = lang === 'en';
---
<a
href={otherLangUrl()}
href={href}
hreflang={other?.code}
class="text-xs font-semibold tracking-wider px-2.5 py-1.5 rounded border transition-colors"
style="border-color: var(--hds-line); color: var(--hds-fg-soft);"
+44
View File
@@ -0,0 +1,44 @@
import type { Lang } from './ui';
const esToEnOverrides: Record<string, string | null> = {
'/nosotros/': '/en/about/',
'/contacto/': '/en/contact/',
'/planes/': '/en/plans/',
'/instructivos/': '/en/tutorials/',
'/legal/privacidad/': '/en/legal/privacy/',
'/legal/terminos/': '/en/legal/terms/',
'/preguntas/': null,
};
const enToEsMap: Record<string, string> = {};
for (const [esPath, enPath] of Object.entries(esToEnOverrides)) {
if (enPath) enToEsMap[enPath] = esPath;
}
const SITE_URL = 'https://hostingdelsur.net';
export function getHreflangUrl(
pathname: string,
currentLang: Lang,
targetLang: Lang
): string | null {
if (currentLang === targetLang) {
return `${SITE_URL}${pathname}`;
}
if (currentLang === 'es' && targetLang === 'en') {
const override = esToEnOverrides[pathname];
if (override === null) return null;
if (override) return `${SITE_URL}${override}`;
return `${SITE_URL}/en${pathname}`;
}
if (currentLang === 'en' && targetLang === 'es') {
const override = enToEsMap[pathname];
if (override) return `${SITE_URL}${override}`;
const esPath = pathname.replace(/^\/en/, '') || '/';
return `${SITE_URL}${esPath}`;
}
return null;
}
+5 -2
View File
@@ -1,5 +1,6 @@
---
import { getLangFromUrl, useTranslations, type Lang } from '@/i18n/utils';
import { getHreflangUrl } from '@/i18n/hreflang-map';
interface Props {
title: string;
@@ -15,6 +16,8 @@ const currentLang = lang ?? getLangFromUrl(Astro.url);
const t = useTranslations(currentLang);
const siteUrl = Astro.site?.toString().replace(/\/$/, '') ?? 'https://hostingdelsur.net';
const canonicalUrl = canonical ? `${siteUrl}${canonical}` : `${siteUrl}${Astro.url.pathname}`;
const esHreflang = getHreflangUrl(Astro.url.pathname, currentLang, 'es');
const enHreflang = getHreflangUrl(Astro.url.pathname, currentLang, 'en');
import '@/styles/global.css';
import Navbar from '@/components/Navbar.astro';
@@ -95,8 +98,8 @@ const localBusinessJsonLd = {
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={`${siteUrl}${ogImage}`} />
<link rel="alternate" hreflang="es" href={`${siteUrl}${currentLang === 'en' ? '/' : Astro.url.pathname.replace(/^\/en/, '')}`} />
<link rel="alternate" hreflang="en" href={`${siteUrl}/en${Astro.url.pathname.replace(/^\/en/, '') || ''}`} />
{esHreflang && <link rel="alternate" hreflang="es" href={esHreflang} />}
{enHreflang && <link rel="alternate" hreflang="en" href={enHreflang} />}
<script type="application/ld+json" set:html={JSON.stringify(orgJsonLd)} />
<script type="application/ld+json" set:html={JSON.stringify(localBusinessJsonLd)} />