Files

160 lines
10 KiB
PHP

<?php
/**
* fea-menu-i18n — Traducción de los menús FSE (issue #120).
*
* Polylang FREE no traduce los bloques `wp_navigation` (menús del header y pie).
* Este plugin engancha `render_block` sobre cada `core/navigation-link` /
* `core/navigation-submenu` y, cuando el idioma actual ≠ es:
* 1) sustituye la ETIQUETA por su traducción (mapa de abajo, hecho a mano),
* 2) remapea la URL al destino traducido si existe (post/página/categoría via
* Polylang); si no hay traducción del destino, deja la URL ES (fallback).
*
* Las etiquetas son cortas y de contexto religioso → traducidas a mano para
* máxima calidad (el contenido largo de #120 va por MiniMax + glosario).
*/
// NOTA: los mu-plugins cargan antes que Polylang → NO comprobar pll_* a nivel de
// fichero (abortaría). Se comprueba dentro del filtro, en render (ya cargado).
/** Mapa etiqueta ES => [en, fr, it, pt]. Claves normalizadas con trim. */
function fea_menu_map(): array {
static $m = null;
if ($m !== null) return $m;
$m = [
// ── Menú principal (header) ──
'PORTADA' => ['Home', 'Accueil', 'Home', 'Início'],
'Quiénes somos' => ['About us', 'À propos', 'Chi siamo', 'Quem somos'],
'Colaboradores' => ['Contributors', 'Collaborateurs', 'Collaboratori', 'Colaboradores'],
'Este portal' => ['This portal', 'Ce portail', 'Questo portale', 'Este portal'],
'Para poner al día la Fe' => ['Bringing faith up to date', 'Mettre la foi à jour', 'Aggiornare la fede', 'Atualizar a fé'],
'Cartas' => ['Letters', 'Lettres', 'Lettere', 'Cartas'],
'Esta semana' => ['This week', 'Cette semaine', 'Questa settimana', 'Esta semana'],
'Semana pasada' => ['Last week', 'Semaine dernière', 'Settimana scorsa', 'Semana passada'],
'Otras semanas' => ['Other weeks', 'Autres semaines', 'Altre settimane', 'Outras semanas'],
'Acceso a webs anteriores:' => ['Previous websites:', 'Anciens sites :', 'Siti precedenti:', 'Sites anteriores:'],
'Web V1 — FrontPage (2006-2012)' => ['Site V1 — FrontPage (2006-2012)', 'Site V1 — FrontPage (2006-2012)', 'Sito V1 — FrontPage (2006-2012)', 'Site V1 — FrontPage (2006-2012)'],
'Web V2 — Joomla (2012-2026)' => ['Site V2 — Joomla (2012-2026)', 'Site V2 — Joomla (2012-2026)', 'Sito V2 — Joomla (2012-2026)', 'Site V2 — Joomla (2012-2026)'],
'Nueva política de datos' => ['New data policy', 'Nouvelle politique de données', 'Nuova politica sui dati', 'Nova política de dados'],
'Contactar' => ['Contact', 'Contact', 'Contatti', 'Contactar'],
'Para contactar con nosotros' => ['Contact us', 'Nous contacter', 'Per contattarci', 'Para contactar-nos'],
'Para recibir la carta de novedades' => ['Subscribe to the newsletter', 'Recevoir la newsletter', 'Ricevere la newsletter', 'Receber a newsletter'],
'Para inscribirse en la Escuela' => ['Enrol in the School', 'S\'inscrire à l\'École', 'Iscriversi alla Scuola', 'Inscrever-se na Escola'],
'🎓 Escuela' => ['🎓 School', '🎓 École', '🎓 Scuola', '🎓 Escola'],
'📚 Librería 🛒' => ['📚 Bookshop 🛒', '📚 Librairie 🛒', '📚 Libreria 🛒', '📚 Livraria 🛒'],
'Buscar' => ['Search', 'Rechercher', 'Cerca', 'Pesquisar'],
// ── Menús del pie ──
'Cartas que nos llegan' => ['Letters we receive', 'Lettres que nous recevons', 'Lettere che riceviamo', 'Cartas que recebemos'],
'Tablón de anuncios' => ['Notice board', 'Tableau d\'annonces', 'Bacheca', 'Mural de avisos'],
'Asociación FeAdulta' => ['FeAdulta Association', 'Association FeAdulta', 'Associazione FeAdulta', 'Associação FeAdulta'],
'La suma de todos' => ['The sum of all', 'La somme de tous', 'La somma di tutti', 'A soma de todos'],
'Comunidades cristianas' => ['Christian communities', 'Communautés chrétiennes', 'Comunità cristiane', 'Comunidades cristãs'],
'El Evangelio de cada día' => ['The daily Gospel', 'L\'Évangile de chaque jour', 'Il Vangelo di ogni giorno', 'O Evangelho de cada dia'],
'Índice cronológico' => ['Chronological index', 'Index chronologique', 'Indice cronologico', 'Índice cronológico'],
'Índice cronológico' => ['Chronological index', 'Index chronologique', 'Indice cronologico', 'Índice cronológico'],
'Evangelios y comentarios' => ['Gospels and commentaries', 'Évangiles et commentaires', 'Vangeli e commenti', 'Evangelhos e comentários'],
'Oraciones eucarísticas' => ['Eucharistic prayers', 'Prières eucharistiques', 'Preghiere eucaristiche', 'Orações eucarísticas'],
'A modo de salmos' => ['In the manner of psalms', 'À la manière de psaumes', 'A mo\' di salmi', 'À maneira de salmos'],
'Preces y oraciones varias' => ['Prayers and various orations', 'Prières et oraisons diverses', 'Preci e orazioni varie', 'Preces e orações várias'],
'Primeras lecturas' => ['First readings', 'Premières lectures', 'Prime letture', 'Primeiras leituras'],
'Autores' => ['Authors', 'Auteurs', 'Autori', 'Autores'],
'Temas' => ['Topics', 'Thèmes', 'Temi', 'Temas'],
'Multimedia' => ['Multimedia', 'Multimédia', 'Multimedia', 'Multimédia'],
'Índice de pensamientos' => ['Index of reflections', 'Index des pensées', 'Indice dei pensieri', 'Índice de pensamentos'],
'Cantoral' => ['Hymnal', 'Recueil de chants', 'Canzoniere', 'Cancioneiro'],
'Películas' => ['Films', 'Films', 'Film', 'Filmes'],
'Reseñas de libros' => ['Book reviews', 'Critiques de livres', 'Recensioni di libri', 'Resenhas de livros'],
'In memoriam' => ['In memoriam', 'In memoriam', 'In memoriam', 'In memoriam'],
];
return $m;
}
/** Índice de columna por idioma. */
function fea_menu_lang_col(string $lang): int {
return ['en' => 0, 'fr' => 1, 'it' => 2, 'pt' => 3][$lang] ?? -1;
}
function fea_menu_tr(string $label, int $col): ?string {
$map = fea_menu_map();
$key = trim($label);
if (isset($map[$key][$col]) && $map[$key][$col] !== '') return $map[$key][$col];
return null;
}
/**
* Remapea una URL ES al destino traducido si existe (post/página/categoría).
* Devuelve la URL original si no hay traducción o no se resuelve.
*/
function fea_menu_localize_url(string $url, string $lang): string {
if ($url === '' || preg_match('~^(mailto:|tel:|javascript:|#)~i', $url)) return $url;
// Solo enlaces internos de ESTE sitio (no Librería, no webs anteriores externas).
$host = parse_url($url, PHP_URL_HOST);
if ($host) {
$site_host = parse_url(home_url('/'), PHP_URL_HOST);
if ($host !== $site_host) return $url; // externo
}
$path = trim((string) parse_url($url, PHP_URL_PATH), '/');
// quitar subcarpeta local (fea) y prefijo de idioma (es/en/…), con o sin barra final
$path = preg_replace('#^fea(/|$)#', '', $path);
$path = preg_replace('#^(es|en|fr|it|pt)(/|$)#', '', $path);
if ($path === '') {
// raíz del sitio → portada del idioma
return function_exists('pll_home_url') ? pll_home_url($lang) : $url;
}
// categoría: category/<slug>. El slug del menú es ES; buscamos SIN filtro de
// idioma de Polylang (lang => '') porque el render va en otro idioma.
if (preg_match('#^category/([^/]+)/?$#', $path, $mm)) {
$terms = get_terms(['taxonomy' => 'category', 'slug' => $mm[1], 'hide_empty' => false, 'number' => 1, 'lang' => '']);
$term = (!is_wp_error($terms) && $terms) ? $terms[0] : null;
if ($term && function_exists('pll_get_term')) {
$tr = pll_get_term($term->term_id, $lang);
if ($tr) {
$link = get_category_link($tr);
if ($link && !is_wp_error($link)) return $link;
}
}
return $url;
}
// página/post por último segmento (lang => '' para no filtrar por idioma actual)
$slug = basename($path);
$q = get_posts(['name' => $slug, 'post_type' => ['post', 'page'], 'numberposts' => 1, 'post_status' => 'publish', 'lang' => '']);
$page = $q ? $q[0] : null;
if ($page && function_exists('pll_get_post')) {
$tr = pll_get_post($page->ID, $lang);
if ($tr) {
$link = get_permalink($tr);
if ($link) return $link;
}
}
return $url;
}
add_filter('render_block', function ($content, $block) {
if (empty($block['blockName'])) return $content;
if ($block['blockName'] !== 'core/navigation-link' && $block['blockName'] !== 'core/navigation-submenu') return $content;
if (!function_exists('pll_current_language')) return $content;
$lang = pll_current_language();
$col = fea_menu_lang_col((string) $lang);
if ($col < 0) return $content; // es o desconocido → sin tocar
$label = isset($block['attrs']['label']) ? (string) $block['attrs']['label'] : '';
$url = isset($block['attrs']['url']) ? (string) $block['attrs']['url'] : '';
// 1) etiqueta
if ($label !== '') {
$tr = fea_menu_tr($label, $col);
if ($tr !== null && $tr !== $label) {
$content = str_replace('>' . esc_html($label) . '<', '>' . esc_html($tr) . '<', $content);
}
}
// 2) URL — localizar el href realmente renderizado (robusto frente a discrepancias attr/HTML)
$content = preg_replace_callback('/href=("|\')([^"\']*)\1/i', function ($m) use ($lang) {
$href = html_entity_decode($m[2], ENT_QUOTES);
$loc = fea_menu_localize_url($href, (string) $lang);
return 'href=' . $m[1] . esc_url($loc) . $m[1];
}, $content, 1);
return $content;
}, 10, 2);