Internacionalización (i18n)
EmDash se integra con el enrutamiento i18n incorporado de Astro para proporcionar gestión de contenido multilingüe. Astro maneja el enrutamiento de URL y la detección de configuración regional; EmDash maneja el almacenamiento y recuperación de contenido traducido.
Cada traducción es una entrada de contenido completa e independiente con su propio slug, estado e historial de revisiones. La versión en francés de una publicación puede estar en borrador mientras que la versión en inglés está publicada.
Configuración
Sección titulada «Configuración»Habilita i18n agregando un bloque i18n a tu configuración de Astro. EmDash lee esta configuración automáticamente — no hay una configuración de configuración regional separada en EmDash.
import { defineConfig } from "astro/config";import emdash, { local } from "emdash/astro";import { sqlite } from "emdash/db";
export default defineConfig({ i18n: { defaultLocale: "en", locales: ["en", "fr", "es"], fallback: { fr: "en", es: "en" }, }, integrations: [ emdash({ database: sqlite({ url: "file:./data.db" }), storage: local({ directory: "./uploads", baseUrl: "/_emdash/api/media/file", }), }), ],});Cuando i18n no está presente en la configuración de Astro, todas las funciones de i18n están deshabilitadas y EmDash se comporta como un CMS de un solo idioma.
Cómo Funcionan las Traducciones
Sección titulada «Cómo Funcionan las Traducciones»EmDash utiliza un modelo fila por configuración regional. Cada traducción es su propia fila en la base de datos con su propio ID, slug y estado, vinculada a otras traducciones a través de un identificador compartido translation_group.
ec_posts:id | slug | locale | translation_group | status---------|-------------|--------|-------------------|----------01ABC... | my-post | en | 01ABC... | published01DEF... | mon-article | fr | 01ABC... | draft01GHI... | mi-entrada | es | 01ABC... | publishedEste diseño significa:
- Slugs por configuración regional —
/blog/my-posty/fr/blog/mon-articlefuncionan naturalmente - Publicación por configuración regional — publica la versión en inglés mientras mantienes la francesa en borrador
- Revisiones por configuración regional — cada traducción tiene su propio historial de revisiones
- Sin complejidad de consultas entre configuraciones regionales — las consultas de lista devuelven entradas para una sola configuración regional
Consultando Contenido Traducido
Sección titulada «Consultando Contenido Traducido»Entrada única
Sección titulada «Entrada única»Pasa locale a getEmDashEntry para recuperar una traducción específica. Cuando se omite, por defecto utiliza la configuración regional actual de la solicitud (establecida por el middleware i18n de Astro).
astro title="src/pages/[...slug].astro"---import { getEmDashEntry } from "emdash";
const { slug } = Astro.params;const { entry: post, error } = await getEmDashEntry("posts", slug, { locale: Astro.currentLocale,});
if (!post) return Astro.redirect("/404");---
<article> <h1>{post.data.title}</h1></article>Cadena de respaldo (fallback)
Sección titulada «Cadena de respaldo (fallback)»Cuando no existe contenido para la configuración regional solicitada, EmDash sigue la cadena de respaldo definida en tu configuración de Astro. Dado fallback: { fr: "en" }:
- Intenta la configuración regional solicitada (
fr) - Intenta la configuración regional de respaldo (
en) - Intenta la configuración regional predeterminada
El respaldo solo se aplica a consultas de entrada única. Las consultas de lista devuelven entradas solo para la configuración regional solicitada — sin mezcla entre configuraciones regionales.
Listado de colección
Sección titulada «Listado de colección»Filtra una colección por configuración regional:
astro title="src/pages/posts.astro"---import { getEmDashCollection } from "emdash";
const { entries: posts } = await getEmDashCollection("posts", { locale: Astro.currentLocale, status: "published",});---
<ul> {posts.map((post) => ( <li><a href={`/${post.data.slug}`}>{post.data.title}</a></li> ))}</ul>Selector de Idioma
Sección titulada «Selector de Idioma»Usa getTranslations para construir un selector de idioma que enlace a las traducciones existentes de la entrada actual:
astro title="src/components/LanguageSwitcher.astro"---import { getTranslations } from "emdash";import { getRelativeLocaleUrl } from "astro:i18n";
interface Props { collection: string; entryId: string;}
const { collection, entryId } = Astro.props;const { translations } = await getTranslations(collection, entryId);---
<nav aria-label="Language"> <ul> {translations.map((t) => ( <li> <a href={getRelativeLocaleUrl(t.locale, `/blog/${t.slug}`)} aria-current={t.locale === Astro.currentLocale ? "page" : undefined} > {t.locale.toUpperCase()} </a> </li> ))} </ul></nav>La función getTranslations devuelve todas las variantes de configuración regional en el mismo grupo de traducción:
const { translationGroup, translations } = await getTranslations("posts", post.entry.id);// translations: [// { locale: "en", id: "01ABC...", slug: "my-post", status: "published" },// { locale: "fr", id: "01DEF...", slug: "mon-article", status: "draft" },// ]Gestionando Traducciones en el Administrador
Sección titulada «Gestionando Traducciones en el Administrador»Lista de contenido
Sección titulada «Lista de contenido»Cuando i18n está habilitado, la lista de contenido muestra:
- Una columna de configuración regional que muestra la configuración regional de cada entrada
- Un filtro de configuración regional en la barra de herramientas para cambiar entre configuraciones regionales
Creando traducciones
Sección titulada «Creando traducciones»Abre cualquier entrada de contenido en el editor. La barra lateral muestra un panel de Traducciones que enumera todas las configuraciones regionales configuradas. Para cada configuración regional:
- “Traducir” aparece para configuraciones regionales sin traducción — haz clic para crear una
- “Editar” aparece para configuraciones regionales con una traducción existente — haz clic para navegar a ella
- La configuración regional actual está marcada con una marca de verificación
Al crear una traducción, la nueva entrada se prellena con datos de la configuración regional de origen y se le asigna un slug predeterminado de {source-slug}-{locale}. Ajusta el slug y el contenido según sea necesario, luego guarda.
Publicación por configuración regional
Sección titulada «Publicación por configuración regional»Cada traducción tiene su propio estado. Publica, despublica o programa traducciones de forma independiente. La versión en francés puede estar en borrador mientras que la versión en inglés está activa.
API de Contenido
Sección titulada «API de Contenido»Parámetro de configuración regional
Sección titulada «Parámetro de configuración regional»Todas las rutas de la API de contenido aceptan un parámetro de consulta opcional locale:
GET /_emdash/api/content/posts?locale=frGET /_emdash/api/content/posts/my-post?locale=frCuando se omite, por defecto utiliza la configuración regional predeterminada configurada.
Creando traducciones vía API
Sección titulada «Creando traducciones vía API»Crea una traducción pasando locale y translationOf al endpoint de creación de contenido:
POST /_emdash/api/content/postsContent-Type: application/json
{ "locale": "fr", "translationOf": "01ABC...", "data": { "title": "Mon Article", "slug": "mon-article" }}La nueva entrada comparte el translation_group de la entrada de origen y comienza como borrador.
Listando traducciones
Sección titulada «Listando traducciones»Recupera todas las traducciones para una entrada dada:
GET /_emdash/api/content/posts/01ABC.../translationsDevuelve el ID del grupo de traducción y un array de variantes de configuración regional con sus IDs, slugs y estados.
La CLI admite banderas --locale en comandos de contenido:
# List French postsemdash content list posts --locale fr
# Obtener una entrada específica en francésemdash content get posts my-post --locale fr
# Crear una traducción al francés de una entrada existenteemdash content create posts --locale fr --translation-of 01ABC...Sembrando Contenido Multilingüe
Sección titulada «Sembrando Contenido Multilingüe»Los archivos de semilla (seed) expresan traducciones usando locale y translationOf:
json title=".emdash/seed.json"{ "content": { "posts": [ { "id": "welcome", "slug": "welcome", "locale": "en", "status": "published", "data": { "title": "Welcome" } }, { "id": "welcome-fr", "slug": "bienvenue", "locale": "fr", "translationOf": "welcome", "status": "draft", "data": { "title": "Bienvenue" } } ] }}La entrada de la configuración regional de origen debe aparecer antes de sus traducciones en el archivo de semilla para que las referencias translationOf se resuelvan correctamente.
Capacidad de Traducción de Campos
Sección titulada «Capacidad de Traducción de Campos»Cada campo tiene una configuración translatable (predeterminado: true). Al crear una traducción:
- Campos traducibles se prellenan desde la configuración regional de origen para su edición
- Campos no traducibles se copian y se mantienen sincronizados en todas las traducciones del grupo
Los campos del sistema como status, published_at y author_id son siempre por configuración regional y nunca se sincronizan.
Estrategia de URL
Sección titulada «Estrategia de URL»EmDash no gestiona las URLs de localización — Astro maneja el enrutamiento. Patrones comunes:
# prefix-other-locales (Astro default)/blog/my-post → en (default locale, no prefix)/fr/blog/mon-article → fr
# prefix-always/en/blog/my-post → en/fr/blog/mon-article → frUsa getRelativeLocaleUrl de astro:i18n para construir URLs correctas independientemente del modo de enrutamiento.
Importando Contenido Multilingüe
Sección titulada «Importando Contenido Multilingüe»WordPress con WPML o Polylang
Sección titulada «WordPress con WPML o Polylang»La fuente de importación del plugin de WordPress detecta WPML y Polylang automáticamente. Cuando se detectan, el contenido importado incluye metadatos de localización y grupo de traducción, preservando la estructura multilingüe.
Archivos WXR
Sección titulada «Archivos WXR»Las exportaciones WXR no incluyen metadatos de WPML/Polylang. Importa como una sola localización y crea traducciones manualmente, o usa la bandera --locale para asignar una localización a todos los elementos importados:
# Import a French WXR exportemdash import wordpress export-fr.xml --execute --locale fr
# Coincidir con contenido existente en inglés por slugemdash import wordpress export-fr.xml --execute --locale fr --translation-of-locale enPróximos Pasos
Sección titulada «Próximos Pasos»- Consultando Contenido — Referencia completa de la API de consultas
- Trabajando con Contenido — Gestión de contenido en el administrador
- Enrutamiento i18n de Astro — Configuración de enrutamiento de Astro