160 lines
10 KiB
PHP
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);
|