-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathastro.config.mjs
More file actions
145 lines (129 loc) · 4.76 KB
/
Copy pathastro.config.mjs
File metadata and controls
145 lines (129 loc) · 4.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import { defineConfig } from "astro/config";
import sitemap from "@astrojs/sitemap";
import { defaultLang, localizedPath, pageSlug } from "./src/data/i18n";
import { legalDataPending } from "./src/data/legal";
import es from "./src/data/locales/es";
import en from "./src/data/locales/en";
/**
* Las cuatro URL de los documentos legales, derivadas de los mismos slugs que
* usan el Layout y el pie de página (nunca escritas a mano aquí).
*/
const LEGAL_URLS = new Set([
`https://ctgcode.com/${es.footer.privacySlug}/`,
`https://ctgcode.com/${es.footer.termsSlug}/`,
`https://ctgcode.com/en/${en.footer.privacySlug}/`,
`https://ctgcode.com/en/${en.footer.termsSlug}/`,
]);
/**
* `/plantillas/` y `/en/templates/` a secas no son páginas: solo el prefijo del
* que cuelgan las tres fichas. No los enlaza nadie y no están en el sitemap,
* pero quien recorte la URL a mano llegaría a un 404 sin salida. Se resuelven
* llevándolo a la sección de plantillas de la bitácora, que es donde vive el
* índice real.
*
* En SSG, Astro emite una página con `meta refresh` y su canónica al destino
* (GitHub Pages no sabe responder un 301). Google la trata como redirección y
* consolida, así que para una ruta sin enlaces entrantes basta y sobra —y a
* cambio la regla vive versionada aquí, no en un panel aparte.
*
* Las anclas salen del `manifest` de cada idioma; no se escriben a mano.
*/
const templatesHubAnchor = (locale) =>
locale.projectsPage.manifest.find((m) => m.href === "#plantillas")?.href ??
locale.projectsPage.manifest.find((m) => m.href === "#templates")?.href ??
"";
const siteUrl = "https://ctgcode.com";
const normalizePathname = (pathname) => {
const normalized = pathname.replace(/\/+$/, "");
return normalized || "/";
};
const localizedRouteGroups = new Map();
const routePageNames = [
"home",
"privacy",
"terms",
"projects",
"services",
"template-local-business",
"template-professional-services",
"template-startup-product",
];
for (const pageName of routePageNames) {
const defaultPath = localizedPath(
defaultLang,
pageSlug(defaultLang, pageName),
);
const englishPath = localizedPath("en", pageSlug("en", pageName));
const defaultUrl = `${siteUrl}${defaultPath}`;
const englishUrl = `${siteUrl}${englishPath}`;
const group = {
defaultUrl,
englishUrl,
defaultPath: normalizePathname(defaultPath),
englishPath: normalizePathname(englishPath),
links: [
{ lang: "es", hreflang: "es-CO", url: defaultUrl },
{ lang: "en", hreflang: "en", url: englishUrl },
],
};
localizedRouteGroups.set(group.defaultPath, group);
localizedRouteGroups.set(group.englishPath, group);
}
export default defineConfig({
output: "static",
redirects: {
"/plantillas": `/${es.projects.indexSlug}/${templatesHubAnchor(es)}`,
"/en/templates": `/en/${en.projects.indexSlug}/${templatesHubAnchor(en)}`,
},
site: "https://ctgcode.com",
integrations: [
sitemap({
i18n: {
defaultLocale: "es",
locales: {
es: "es",
en: "en",
},
},
/**
* Mientras falten los datos del responsable, los documentos legales ya
* salen del índice desde el Layout (`legalDataPending` → `noindex`).
* Sin este filtro seguían listados aquí, así que el sitio pedía indexar
* en el sitemap lo que prohibía indexar en la propia página.
*/
filter: (page) => !(legalDataPending && LEGAL_URLS.has(page)),
/**
* Agrupa cada ruta localizada en un único elemento del sitemap: el
* español queda como URL canónica y el inglés se añade como alternativa
* con su `hreflang`. Esto evita que el build emita entradas separadas para
* `/` y `/en/`, `/privacidad/` y `/en/privacy/`, etc.
*/
serialize: (item) => {
const currentPath = normalizePathname(new URL(item.url).pathname);
const group = localizedRouteGroups.get(currentPath);
if (!group) {
return item;
}
if (currentPath === group.englishPath) {
return undefined;
}
return {
...item,
url: group.defaultUrl,
links: group.links,
};
},
/**
* Las doce URL de las demos NO se listan aquí —seis de plantillas y seis
* de automatizaciones—. Se construyen con `PUBLIC_DEMO` y salen con
* `noindex`: simulan negocios que no existen y un buscador podría
* tomarlas por fichas legítimas.
*
* Quien pide indexarse es la página dedicada de cada plantilla en
* /plantillas/ (y su gemela en /en/templates/) y, en el caso de las
* automatizaciones, la sección de /proyectos que las enlaza. Son rutas
* reales y las recoge la integración sola.
*/
}),
],
});