Cambiar idioma haciendo clic en un botón
El objetivo es ofrecer un botón/selector desplegable o similar para cambiar el idioma de la interfaz pública1) al instante.
Lo que estoy buscando
- Plugin o código para el Theme...
- ... o Ideas
- Se agradecería usar una solución alternativa con
load_textdomain()
para manejar las traducciones mediante archivos .po/.mo - Ideas sobre cómo procesar las cadenas en la interfaz (ej. ajax/php plano/ini, json, archivos xml) cuando no se usan funciones de textdomain
Nota:
1) No se trata de publicar en diferentes idiomas.
2) No necesito código para crear el desplegable/botón/etc. Solo el código/sistema que proporcione las cadenas para la UI.
¡Gracias!

Sin duda, la mejor (y más fácil) manera es usar el filtro de localización (dentro de get_locale()
).
Primero configura una función rápida para recuperar un idioma diferente que se usará en el filtro locale
.
/**
* Una función que devuelve la localización seleccionada por el usuario, si está almacenada.
*/
function wpse35622_get_new_locale($locale=false){
$new_locale = get_user_meta(get_current_user_id(), 'wpse_locale', true);
if($new_locale)
return $new_locale;
return $locale;
}
He dejado esto como una función global, podría ser útil...? El resto del plugin lo he envuelto dentro de una clase.
Crea un menú desplegable de idiomas posibles para seleccionar.
Desventajas
- Busca en
wp-content/languages
archivos del tipoxx_xx.mo
. Si no tienen ese formato (no todos los archivos .mo lo tienen), ¡el plugin no los detectará! - El menú desplegable muestra una lista de las localizaciones encontradas para elegir, pero se muestran en el formato 'xx_xx' de localizaciones, no de una forma amigable para humanos - ¿alguna idea?
- ¿Hace algo más
$locale
además del idioma? Si es así, sigue siendo posible obtener la misma localización pero proporcionar traducciones alternativas. Aunque es mucho más desordenado...
El código
class SH_Pick_Lang{
/**
* Un nombre único para este plugin
*/
static $name = 'sh_pick_lang';
/**
* Engancha las funciones
*/
public function __construct(){
if( isset($_POST[self::$name]) ){
add_action('locale',array($this,'update_user'));
}
add_filter( 'locale', 'wpse35622_get_new_locale',20 );
add_action( 'wp_before_admin_bar_render', array( $this, 'admin_bar') );
}
/**
* Actualiza la opción del usuario justo a tiempo! Solo una vez, claro...
*/
function update_user($locale){
$save_locale = $_POST[self::$name];
update_user_meta(get_current_user_id(), 'wpse_locale', $save_locale);
remove_filter(current_filter(),__FUNCTION__);
return $locale;
}
/**
* Añade un menú desplegable de aspecto horrible que estoy seguro de que Kaiser hará que se vea fantástico.
*/
function admin_bar(){
global $wp_admin_bar;
$wp_admin_bar->add_menu( array(
'id' => 'shlangpick',
'title' => $this->wpse_language_dropown(),
) );
}
/**
* Genera una lista de localizaciones disponibles.
* Busca en la carpeta wp-content/languages archivos del tipo xx_xx.mo
*
* TODO No todas las localizaciones son del tipo xx_xx.mo - podríamos perder algunas.
* TODO ¿Mejor manera de obtener la carpeta wp-content/languages sin una constante?
*/
function wpse_language_dropown(){
$name = self::$name;
$locale = get_locale();
$langs = get_available_languages();
$langs[] = 'en_US';
//Para las etiquetas (format_code_lang)
require_once( ABSPATH . 'wp-admin/includes/ms.php');
$html = "<form method='post'> ";
$html .= "<select name='{$name}'>";
foreach($langs as $lang){
$label = format_code_lang( $lang );
$html .= "<option ".selected( $lang, $locale, false)." value='{$lang}'>{$label}</option>";
}
$html .= "</select>";
$html .= get_submit_button('Cambiar Idioma','secondary', 'submit', true);
$html .= "</form >";
return $html;
}
} // FIN Clase
//Iniciar...
$sh_pick_lang = new SH_Pick_Lang();

Voto positivo realizado (riéndome también de todos los comentarios en línea). La recompensa está establecida y se te otorgará tan pronto como me sea permitido (faltan 23 horas - avísame si lo olvido).

Actualizado para reflejar la respuesta a esta pregunta.

He notado que simplemente incluir 'wp-admin/includes/ms.php'
activa un aviso de administración para actualizar tus sitios de red (¡cuando tienes un solo sitio!). Puede que format_code_lang()
necesite ser duplicada dentro de una función personalizada.

Agregué un Gist con mi limpieza - no tuve tiempo de probarlo, ya que estoy trabajando con carpetas de plugins actualmente y esto significa que ningún otro plugin funciona. Espero que puedas trabajar con el gist proporcionado y tal vez hacer fork/actualizarlo. Puedo otorgar la recompensa en media hora, pero tengo que irme ahora, así que lo enviaré mañana. Gracias por todo tu trabajo - debería estar en cualquier instalación predeterminada :)

Hmm.. podrías usar ajax para reemplazar el body o toda la etiqueta html de la página, después de ejecutar el código anterior (en la misma solicitud ajax), al hacer clic en tu botón o algo por el estilo.

+1. Acabo de ver tu pastebin. Esto significa que tu configuración es http://example.com/idioma/lo-que-sea/
, ¿verdad?

@kaiser Sí, esa es la configuración en el sitio de donde viene el código. Si solo te importa el idioma de la interfaz, pasar una cadena de consulta URL o establecer una variable $_SESSION
para activar la redefinición de WPLANG
en la siguiente carga de página debería funcionar. Si te interesa replicar esto en un sitio multilingüe, ten en cuenta que, como dice el comentario con el pastebin, el código en él funciona con WPML, última versión gratuita. No se puede replicar 1 a 1 con qTranslate, porque esas URI no son físicas sino reescritas mediante el módulo mod_rewrite
de apache. Estoy seguro de que se puede ajustar, pero no funcionará "tal cual".

No usaré qTranslate ni WPML. Realmente solo se trata del idioma de la interfaz de usuario. Ad $_SESSION
) Mi problema es que, por lo que sé, son bastante difíciles de manejar y las cosas entre globales y el array pueden mezclarse fácilmente. Entonces, si intentara encontrar una manera de cambiar WPLANG
, necesitaría encontrar una forma sólida de pasarlo de una solicitud a otra. Tal vez add_query_arg/get_query_var
haga el truco...

http://www.qianqin.de/qtranslate/
es lo que necesitas...
Edición I - después del comentario. Primero - gracias a todos los que contribuyeron al torrente de votos negativos. (esto es lo que pasa cuando uno no visita con suficiente frecuencia :-) )
ahora - La función que maneja el cambio está en qtranslate-core. (comienza más o menos en la línea 80 - depende de la versión que quieras.)
Como no puedes mirar un código NO OOP, y ahora no tengo nada más que hacer - tomé 10 minutos para sintetizar, parafrasear y compilar ese código no-OOP con otro código no-OOP para ti.
(lo siento, - vieja escuela primitiva aquí)
Asumiendo que entendí la pregunta && Asumiendo que quieres el código para admin && asumiendo que sabrás cómo portarlo al frontend si quieres && asumiendo que entiendes que el código no es óptimo:
<?php
/*
Plugin Name: k99 language switcher
Plugin URI: http://www.krembo99.com
Description: Admin Language switcher proof of concept only - do not use in production.
Version: 0.0.0.0.0.0.0.1
Author: Krembo99
Author URI: http://www.krembo99.com
*/
?>
<?php function k99_add_language_menu() {
// k99_load_ajax_display_functions();
?>
<div class="mgmb_help_setting">
<?php _e('Idioma:','your_text_domain'); ?>
<select name="mgmb_language_setting_help" id="mgmb_language_setting_help" onChange="mgmb_set_language_cookies(this.value);" >
<option value="en_US" <?php if($_COOKIE['k99_userLang']=="en_US"){echo "selected";} ?>><?php _e('Inglés','your_text_domain');?></option>
<option value="de_DE" <?php if($_COOKIE['k99_userLang']=="de_DE"){echo "selected";} ?>><?php _e('Alemán','your_text_domain');?></option>
<option value="zh_CN" <?php if($_COOKIE['k99_userLang']=="zh_CN"){echo "selected";} ?>><?php _e('Chino','your_text_domain');?></option>
</select>
</div>
<?php
}
// Ahora configuramos esa función para que se ejecute cuando se llame a la acción de ayuda
add_filter('contextual_help', 'k99_add_language_menu');
// Supongo que esto es tu misterioso "cosas del navegador"
function k99_language_change($lang){
global $locale;
// wp_cache_set( "language", $lang, 'options' );
if ( isset($_COOKIE['k99_userLang'])) {
$lang = $_COOKIE['k99_userLang'];
}
define( 'WPLANG', $lang );
if($locale!= $lang) {
$locale = $lang;
load_plugin_textdomain('your_text_domain', false, dirname( plugin_basename(__FILE__) ) . '/lang'); // ejemplo de uso para textdomain de plugins
load_plugin_textdomain('your_text_domain2', false, dirname( plugin_basename(__FILE__) ) . '/lang');
load_plugin_textdomain('your_text_domain3', false, dirname( plugin_basename(__FILE__) ) . '/lang');
}
return $locale;
}
add_filter('locale', 'k99_language_change',99);
////////// +++++++++++++++ INICIO CREACIÓN DE COOKIES +++++++++++++++//////////////////
// Función Javascript para establecer las cookies de idioma
// acceso externo
// @param lang - código de idioma
// @return NULL
// o quizás esto es el misterioso "cosas del navegador" del OP??
function mgmb_print_script() {
?>
<script type="text/javascript" >
function mgmb_set_language_cookies(lang){
var Then = new Date();
Then.setTime(Then.getTime() + 10000*60*60*1000 ); //establece la expiración de la cookie a 10000 horas (hora*minuto*segundos*1000)
document.cookie = "k99_userLang="+lang+";expires="+ Then.toGMTString();
window.location.reload();
}
</script>
<?php
}
add_action('admin_print_scripts', 'mgmb_print_script'); // esta no es la forma correcta de hacerlo... pero no hay tiempo ahora.
?>
OBSERVACIONES:
1 - Esto fue construido en 10 min. en máquina local mientras estaba en el aeropuerto. La razón por la que digo esto es que la única instalación de WordPress lista que tengo aquí es bastante vieja (2.9 creo).
Esto significa que probablemente el menú de idiomas aparecerá DEBAJO del div de ayuda contextual, debido al hecho de que recientemente se introdujo una nueva estructura de div (con pestañas) - pero aún así debería funcionar. (Prometo volver a esto más tarde si tengo tiempo)
Si tuviera más tiempo (y un código nuevo de WordPress aquí) probablemente integraría esto en la nueva barra de admin con add_action( 'admin_bar_menu', 'k99_add_language_menu_2', 1000 );
(ya prometí volver a esto)
2 - deberías tener los archivos de idiomas listados dentro de la carpeta "languages" en wp-content (¿mejor??) o wp-include. respecto a este punto - el código es solo una prueba de concepto - y por supuesto si uno tiene más tiempo el menú debería construirse de forma dinámica y no como se hizo aquí.
3 - tu WPLANG en config debería estar vacío. No estoy seguro de que funcione en versiones más nuevas de wp si ya hay un idioma establecido.
4 - es una simple prueba de concepto sintetizada y parafraseada construida sobre lo visto en el código de qtranslate (también versión antigua) - así que la mayoría de las cosas están hechas de la forma "rápida", no necesariamente la forma "correcta" (como añadir JS, sin textdomain dedicado etc..).
EDICIÓN II
¡alguien tiene suerte hoy! (Retraso de vuelo)
Como estabas buscando "ideas" para enfoques, aquí hay otra famosa.
No encajará en un plugin, o en realidad en cualquier otro entorno no exclusivo, pero podría darte otra dirección sobre cómo manejar las "cosas del navegador".
Esto permitirá obtener el idioma con un GET como: <a href="index.php?lang=de">Alemán</a>
o <a href="whatever.php?lang=ml">mi Idioma</a>
Para usar, puedes crear un código (llamémoslo wp-langswitch.php)
session_start();
if ( isset( $_GET['lang'] ) ) {
$_SESSION['WPLANG'] = $_GET['lang'];
define ('WPLANG', $_SESSION[WPLANG]);
} else {
if(isset($_SESSION['WPLANG'])) {
define ('WPLANG', $_SESSION['WPLANG']);
$_GET['lang'] = $_SESSION['WPLANG'];
} else {
if ( isset( $_SERVER["HTTP_ACCEPT_LANGUAGE"] ) ) {
$languages = strtolower( $_SERVER["HTTP_ACCEPT_LANGUAGE"] );
$languages = explode( ",", $languages );
$_SESSION['WPLANG'] = $languages[0];
$_SESSION['WPLANG'] = str_replace("-", "_", $_SESSION['WPLANG']);
$_GET['lang'] = substr($_SESSION['WPLANG'],0,2);
define ('WPLANG', $_SESSION[WPLANG]);
} else {
define ('WPLANG', '');
}
}
}
ahora, en wp-config, justo antes de la constante WPLANG, necesitamos incluir nuestro código.
require_once(dirname(__FILE__).'/wp-langswitch.php');
define ('WPLANG', '');
Ahora - obviamente sería mejor añadir algunas cookies a la mezcla para almacenar los idiomas.
EDICIÓN III
Prometí volver a esto más tarde - aquí está cómo (de una manera muy incorrecta y primitiva) podría integrarse dentro de la barra de admin (en lugar del menú de ayuda contextual)
function k99_add_language_menu_bar() {
global $wp_admin_bar, $wpdb;
if ( !is_super_admin() || !is_admin_bar_showing() )
return;
// Estoy seguro de que puedes encontrar una manera de construir el array leyendo la carpeta. Si no, comenta y actualizaré de nuevo.
if($_COOKIE['k99_userLang']=="en_US"){$sel==$_COOKIE['k99_userLang'];}
if($_COOKIE['k99_userLang']=="de_DE"){$sel==$_COOKIE['k99_userLang'];}
if($_COOKIE['k99_userLang']=="zh_CN"){$sel==$_COOKIE['k99_userLang'];}
$k99_lang = '';
$k99_lang .= '<select name="mgmb_language_setting_help" id="mgmb_language_setting_help" onChange="mgmb_set_language_cookies(this.value);" >';
$k99_lang .= '<option value="en_US" >Inglés</option>';
$k99_lang .= '<option value="de_DE" >Alemán</option>';
$k99_lang .= '<option value="zh_CN" >Chino</option></select>';
/* Añade el ítem principal del menú de admin */
$wp_admin_bar->add_menu( array( 'id' => 'Language', 'title' => __( 'idioma', 'your_text_domain3' ), 'href' => FALSE ) );
$wp_admin_bar->add_menu( array( 'parent' => 'Language', 'title' => $k99_lang, 'href' => FALSE ) );
}
add_action( 'admin_bar_menu', 'k99_add_language_menu_bar', 999 );
Solo reemplaza esta función (o añade) al código antiguo (el original NO-OOP no-plugin).
Como dije, no tengo una instalación nueva de WordPress aquí en local que tenga barra de admin - pero debería funcionar.
(y de nuevo, podría no funcionar... pero estoy seguro de que podrías arreglarlo si realmente quieres - aunque no sea OOP) :-)
tengo que irme ahora. espero que ayude de alguna manera.
EDICIÓN IV - cambié la edición III a versión funcional para barra de menú admin (al menos en mi wp 3.4)
como no tenía una instalación funcional de 3.4 - y ahora que volví y la tengo - he editado la solución de Edición III - y funciona para mí.
Sobre los votos positivos, no me importan. Y no necesito ninguna "recompensa" (lo que sea que sean...). Fue solo por el ejercicio. Quizás deberías dárselo al autor de qTranslate. :-) a pesar de que no es OOP - es un plugin genial con mucho que aprender en muchas áreas. considerando el "cuándo" del lanzamiento de este plugin, es incluso asombroso. vale el indescriptible esfuerzo de leer un código NO OOP - incluso si no es - OOP. E incluso si no está correctamente indentado (¡Dios mío!).

Quizás haya una solución enterrada en las profundidades de este código, pero es casi imposible descifrar todas las formas, ya que no está escrito en OOP. Si sabes exactamente dónde se encuentra la detección de idioma (lo del navegador) y cómo filtra las cadenas gettext, por favor házmelo saber.

@kaiser ...y mira la edición II para más sobre el "navegador" - y la edición III para cómo incorporar lo del "navegador" dentro del "navegador (cosas)".

Ok, lo he votado positivamente (no negativo para revertir aquí), por tu esfuerzo. La idea de usar una cookie es buena. De todos modos, aquí hay algunas notas: Edición II lanzará un error después del require()
. No puedes usar define()
con la misma cadena dos veces. La Edición III tiene algunos problemas con los idiomas. Seleccionar en_US
no haría nada(?), pero de_DE
lo establecería a English
;). Para resumir: otorgo recompensas y las doy (por ejemplo a StephenHarris) por una respuesta completa y funcional. Si tienes algo así, actualiza tu respuesta (el enfoque de la cookie es interesante) y podría añadir y recompensarte con una recompensa.
