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:
@@ -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>
|
||||
|
||||
@@ -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);"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)} />
|
||||
|
||||
Reference in New Issue
Block a user