WPML
Estado
Resuelto
Tipo
No se solucionará
Informado para
WPML Multilingual CMS 5.0
Etiquetas de temática
Compatibility

Resumen del problema

Desde WPML 5.0, los cambios de idioma se anidan. Cada código de idioma abre un nuevo ámbito, y solo null cierra uno.

Los plugins escritos para WPML 4.x a menudo vuelven al idioma anterior nombrando el idioma que guardaron:

$current = apply_filters( 'wpml_current_language', null );

do_action( 'wpml_switch_language', 'de' );
// ...
do_action( 'wpml_switch_language', $current ); // Meant as "and back".

WPML 4.x toleraba esto. Mantenía un único espacio para el idioma, por lo que el idioma actual terminaba siendo correcto y el cambio desequilibrado pasaba desapercibido. Nunca fue una forma correcta de cerrar un cambio. WPML 5.0 ya no lo absorbe: la última llamada abre un segundo ámbito en lugar de cerrar el primero, y WPML sigue informando de que el idioma está cambiado.

WPML no puede detectar esto, porque la misma llamada también es un cambio válido al idioma del que provenía el código circundante.

El síntoma es diferido. Justo después del par, el idioma actual es correcto, por lo que una prueba que solo compruebe eso pasa. La siguiente restauración correcta a su alrededor cierra entonces su ámbito abierto en lugar del suyo propio, y ese código se ejecuta en el idioma equivocado. Esto se manifiesta en los correos electrónicos, las respuestas REST y las pantallas del panel de administración.

Un cambio sin restauración, o con un código de idioma vacío, deja un ámbito abierto de la misma manera.

Solución alternativa

Cierre cada ámbito con null, en un bloque finally:

do_action( 'wpml_switch_language', 'de' );

try {
	// ...your work in German...
} finally {
	do_action( 'wpml_switch_language', null ); // Closes the scope above.
}

Compatibilidad con WPML 4.x y 5.0 en una versión

Copie estas funciones auxiliares y cambie el nombre del prefijo:

// Opens a scope. Returns the value for the close helper, or false if none opened.
function myplugin_wpml_open_language_switch( $language_code ) {
	// '', false and 0 open a scope without changing the language. Only null closes one.
	if ( ! $language_code ) {
		return false;
	}
	$previous = apply_filters( 'wpml_current_language', '' );
	do_action( 'wpml_switch_language', $language_code );
	return $previous;
}

// Closes the scope the open helper opened. WPML 4.x has no stack: there null
// means "the language before the FIRST switch", so restore by name.
function myplugin_wpml_close_language_switch( $previous ) {
	if ( ! $previous ) {
		return;
	}
	$has_stack = defined( 'ICL_SITEPRESS_VERSION' )
		&& version_compare( ICL_SITEPRESS_VERSION, '5.0', '>=' );
	do_action( 'wpml_switch_language', $has_stack ? null : $previous );
}

Cada punto de llamada quedará entonces así:

$previous = myplugin_wpml_open_language_switch( 'de' );
try {
	// ... work ...
} finally {
	myplugin_wpml_close_language_switch( $previous );
}

Ejecute grep -rn "wpml_switch_language" . para encontrar cada punto de llamada. Cada uno necesita su cierre correspondiente. Nunca restaure indicando el nombre del idioma, y nunca cambie a un código que pueda estar vacío.

Los hooks de correo electrónico también se anidan: llame a wpml_restore_language_from_email una vez por cada wpml_switch_language_for_email.

Todos los problemas conocidos →