Documentation Index
Fetch the complete documentation index at: https://mintlify.com/abisai7/diccionario-chapin/llms.txt
Use this file to discover all available pages before exploring further.
Chapinismos implements comprehensive SEO with structured data (JSON-LD), meta tags, Open Graph, and hreflang for multilingual support.
The src/layouts/Base.astro component handles all SEO meta tags:
---
const {
title = "Chapinismos",
description = "Glosario de chapinismos guatemaltecos con definiciones y ejemplos",
keywords = "chapinismos, diccionario guatemalteco, palabras chapinas, guatemaltequismos, jerga guatemalteca, modismos Guatemala",
ogImage = "/og-image.svg",
canonicalUrl = Astro.url.pathname,
type = "website",
lang = "es",
alternateUrls = {},
} = Astro.props;
const siteUrl = Astro.site || "https://chapinismos.org";
const fullCanonicalUrl = new URL(canonicalUrl, siteUrl).toString();
const fullOgImage = new URL(ogImage, siteUrl).toString();
---
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{title}</title>
<meta name="title" content={title} />
<meta name="description" content={description} />
<meta name="keywords" content={keywords} />
<meta name="author" content="Diccionario Chapín" />
<meta name="robots" content="index, follow" />
<meta name="language" content="Spanish" />
<link rel="canonical" href={fullCanonicalUrl} />
</head>
Key features:
- Canonical URLs prevent duplicate content issues
- Robots directive allows indexing
- Author metadata for content attribution
<!-- Hreflang tags for multilingual SEO -->
{
alternateUrls.es && (
<link rel="alternate" hreflang="es" href={new URL(alternateUrls.es, siteUrl).toString()} />
)
}
{
alternateUrls.en && (
<link rel="alternate" hreflang="en" href={new URL(alternateUrls.en, siteUrl).toString()} />
)
}
{
alternateUrls.xDefault && (
<link
rel="alternate"
hreflang="x-default"
href={new URL(alternateUrls.xDefault, siteUrl).toString()}
/>
)
}
Usage in pages:
<Base
lang={lang}
alternateUrls={{
es: "/es/buscar/",
en: "/en/buscar/",
xDefault: "/es/buscar/",
}}
/>
This tells search engines:
- Spanish version is at
/es/buscar/
- English version is at
/en/buscar/
- Default language for unlisted regions is Spanish
const ogLocale = lang === "en" ? "en_US" : "es_GT";
const alternateOgLocale = lang === "en" ? "es_GT" : "en_US";
<!-- Open Graph / Facebook -->
<meta property="og:type" content={type} />
<meta property="og:url" content={fullCanonicalUrl} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={fullOgImage} />
<meta property="og:locale" content={ogLocale} />
{
alternateUrls.es && alternateUrls.en && (
<meta property="og:locale:alternate" content={alternateOgLocale} />
)
}
<meta property="og:site_name" content="Diccionario Chapín" />
Benefits:
- Rich previews on Facebook, LinkedIn, WhatsApp
- Proper language tagging for international content
- Custom Open Graph images for better engagement
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content={fullCanonicalUrl} />
<meta property="twitter:title" content={title} />
<meta property="twitter:description" content={description} />
<meta property="twitter:image" content={fullOgImage} />
Card type:
summary_large_image displays a large image preview
- Optimized for sharing on X/Twitter
<meta name="geo.region" content="GT" />
<meta name="geo.placename" content="Guatemala" />
Indicates content is targeted to Guatemala, helping with local search rankings.
Structured Data Components
Chapinismos uses multiple schema components for rich search results:
OrganizationSchema
Location: src/components/schemas/OrganizationSchema.astro
Defines the organization behind the site (automatically included in Base layout):
<OrganizationSchema lang={lang} siteUrl={siteUrl} />
WebsiteSchema
Location: src/components/schemas/WebsiteSchema.astro
---
import { useTranslations } from "../../utils/i18n";
interface Props {
lang: string;
siteUrl: string | URL;
}
const { lang, siteUrl } = Astro.props;
const t = useTranslations(lang);
const websiteSchema = {
"@context": "https://schema.org",
"@type": "WebSite",
name: t("schema.site.name"),
alternateName: t("schema.site.alternateName"),
url: siteUrl.toString(),
description: t("schema.site.fullDescription"),
inLanguage: ["es", "en"],
potentialAction: {
"@type": "SearchAction",
target: {
"@type": "EntryPoint",
urlTemplate: new URL(`/${lang}/buscar/?q={search_term_string}`, siteUrl).toString(),
},
"query-input": "required name=search_term_string",
},
publisher: {
"@type": "Organization",
name: t("schema.site.name"),
},
};
---
<script type="application/ld+json" set:html={JSON.stringify(websiteSchema)} />
Benefits:
- Enables Google’s sitewide search box in results
- Defines site structure and purpose
- Multi-language support declaration
WordSchema (DefinedTerm)
Location: src/components/schemas/WordSchema.astro
---
import { useTranslations } from "../../utils/i18n";
interface Props {
lang: string;
siteUrl: string | URL;
word: {
word: string;
meaning: string;
category?: string;
synonyms?: string[];
};
slug: string;
}
const { lang, siteUrl, word, slug } = Astro.props;
const t = useTranslations(lang);
const wordUrl = new URL(`/${lang}/palabras/${slug}/`, siteUrl).toString();
// JSON-LD DefinedTerm Schema
const definedTermSchema = {
"@context": "https://schema.org",
"@type": "DefinedTerm",
"@id": wordUrl,
name: word.word,
description: word.meaning,
inDefinedTermSet: {
"@type": "DefinedTermSet",
name: t("schema.dictionary.name"),
url: siteUrl.toString(),
},
termCode: slug,
...(word.category && { additionalType: word.category }),
...(word.synonyms?.length && { sameAs: word.synonyms }),
inLanguage: lang,
isPartOf: {
"@type": "WebSite",
name: t("schema.site.name"),
url: siteUrl.toString(),
},
};
// JSON-LD Article Schema
const articleSchema = {
"@context": "https://schema.org",
"@type": "Article",
headline: t("schema.word.headline", { word: word.word }),
description: word.meaning,
url: wordUrl,
inLanguage: lang,
about: {
"@type": "DefinedTerm",
name: word.word,
},
publisher: {
"@type": "Organization",
name: t("schema.site.name"),
url: siteUrl.toString(),
},
mainEntityOfPage: {
"@type": "WebPage",
"@id": wordUrl,
},
};
---
<script type="application/ld+json" set:html={JSON.stringify(definedTermSchema)} />
<script type="application/ld+json" set:html={JSON.stringify(articleSchema)} />
Schema features:
DefinedTerm: Marks content as a dictionary definition
Article: Provides article context for search engines
- Links to parent DefinedTermSet (the dictionary)
- Conditional fields (category, synonyms) only if present
FAQSchema
Location: src/components/schemas/FAQSchema.astro
---
import { useTranslations } from "../../utils/i18n";
interface Props {
lang: string;
word: {
word: string;
meaning: string;
examples?: string[];
category?: string;
synonyms?: string[];
};
}
const { lang, word } = Astro.props;
const t = useTranslations(lang);
// Build FAQ items dynamically based on available content
const faqItems: { question: string; answer: string }[] = [];
// Q1: What does {word} mean?
faqItems.push({
question: t("schema.faq.meaning.question", { word: word.word }),
answer: word.meaning,
});
// Q2: How to use {word}? (if examples exist)
if (word.examples?.length) {
const examplesFormatted = word.examples.map((ex) => `"${ex}"`).join("; ");
faqItems.push({
question: t("schema.faq.usage.question", { word: word.word }),
answer: t("schema.faq.usage.answer", { examples: examplesFormatted }),
});
}
// Q3: What type of word is {word}? (if category exists)
if (word.category) {
faqItems.push({
question: t("schema.faq.category.question", { word: word.word }),
answer: t("schema.faq.category.answer", { word: word.word, category: word.category }),
});
}
// Q4: Synonyms (if they exist)
if (word.synonyms?.length) {
faqItems.push({
question: t("schema.faq.synonyms.question", { word: word.word }),
answer: t("schema.faq.synonyms.answer", { synonyms: word.synonyms.join(", ") }),
});
}
const faqSchema = {
"@context": "https://schema.org",
"@type": "FAQPage",
mainEntity: faqItems.map((item) => ({
"@type": "Question",
name: item.question,
acceptedAnswer: {
"@type": "Answer",
text: item.answer,
},
})),
};
---
<script type="application/ld+json" set:html={JSON.stringify(faqSchema)} />
Dynamic FAQ generation:
- Always includes: Meaning question
- Conditionally adds: Usage examples, category, synonyms
- Creates rich FAQ snippets in Google search results
BreadcrumbSchema
Location: src/components/schemas/BreadcrumbSchema.astro
---
import { useTranslations } from "../../utils/i18n";
interface BreadcrumbItem {
name: string;
url: string;
}
interface Props {
lang: string;
siteUrl: string | URL;
items: BreadcrumbItem[];
}
const { lang, siteUrl, items } = Astro.props;
const t = useTranslations(lang);
const breadcrumbSchema = {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: [
{
"@type": "ListItem",
position: 1,
name: t("nav.home"),
item: new URL(`/${lang}/`, siteUrl).toString(),
},
...items.map((item, index) => ({
"@type": "ListItem",
position: index + 2,
name: item.name,
item: new URL(item.url, siteUrl).toString(),
})),
],
};
---
<script type="application/ld+json" set:html={JSON.stringify(breadcrumbSchema)} />
Usage:
<BreadcrumbSchema
slot="schema"
lang={lang}
siteUrl={siteUrl}
items={[
{ name: t("nav.search"), url: `/${lang}/buscar/` },
]}
/>
Benefits:
- Shows breadcrumb trail in search results
- Improves site structure understanding
- Better navigation for users from search
SearchPageSchema
Location: src/components/schemas/SearchPageSchema.astro
Marks the search page with appropriate schema (used in buscar.astro).
Using Schemas in Pages
Schemas are inserted via named slots in the Base layout:
<Base
title={t("search.title") + " — " + t("schema.site.name")}
description={t("search.description")}
keywords={t("search.keywords")}
lang={lang}
alternateUrls={alternateUrls}
>
<BreadcrumbSchema
slot="schema"
lang={lang}
siteUrl={siteUrl}
items={[{ name: t("nav.search"), url: `/${lang}/buscar/` }]}
/>
<SearchPageSchema
slot="schema"
lang={lang}
siteUrl={siteUrl}
title={t("search.title")}
description={t("search.description")}
url={`/${lang}/buscar/`}
/>
<!-- Page content -->
</Base>
Base layout schema slot:
<head>
<!-- ... other head content ... -->
<!-- Global schemas -->
<OrganizationSchema lang={lang} siteUrl={siteUrl} />
<WebsiteSchema lang={lang} siteUrl={siteUrl} />
<!-- Page-specific schemas -->
<slot name="schema" />
</head>
Preconnect to External Resources
<link rel="preconnect" href="https://api-gateway.umami.dev" crossorigin />
<link rel="dns-prefetch" href="https://api-gateway.umami.dev" />
<link rel="preconnect" href="https://cloud.umami.is" crossorigin />
<link rel="dns-prefetch" href="https://cloud.umami.is" />
Establishes early connections to analytics servers.
Preload Background Image
<link rel="preload" href="/images/bg.webp" as="image" fetchpriority="low" />
Preloads non-critical images with low priority to avoid blocking rendering.
Async Analytics
<script
async
src="https://cloud.umami.is/script.js"
data-website-id="7e8f3679-b1bd-4ee9-97e8-cc136e9416f2"
data-endpoint="/api/umami-proxy"
></script>
Loads analytics asynchronously to prevent render blocking.
Sitemap Integration
<link rel="sitemap" href="/sitemap-index.xml" />
Points search engines to the XML sitemap for complete site indexing.
Best Practices
Always use canonical URLs
Prevent duplicate content penalties:const fullCanonicalUrl = new URL(canonicalUrl, siteUrl).toString();
<link rel="canonical" href={fullCanonicalUrl} />
Implement hreflang for multilingual sites
Helps Google show the right language version:alternateUrls={{
es: "/es/palabras/chucho/",
en: "/en/palabras/chucho/",
xDefault: "/es/palabras/chucho/",
}}
Use specific schema types
Match schema to content type:
DefinedTerm for dictionary entries
FAQPage for Q&A content
BreadcrumbList for navigation
SearchAction for search functionality
Use Google’s Rich Results Test: Optimize Open Graph images
Ensure images:
- Are at least 1200x630px
- Use absolute URLs
- Have relevant alt text
- Are properly sized (< 300KB)