- Trạng thái
- Đã giải quyết
- Loại
- Sẽ không sửa
- Được báo cáo cho
- WPML Multilingual CMS 5.0
- Thẻ chủ đề
- Compatibility
Tổng quan về sự cố
Từ WPML 5.0, các lệnh chuyển đổi ngôn ngữ được lồng vào nhau. Mỗi mã ngôn ngữ mở ra một phạm vi mới và chỉ có null mới đóng phạm vi đó.
Các plugin được viết cho WPML 4.x thường chuyển lại bằng cách gọi tên ngôn ngữ mà chúng đã lưu:
$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 đã chấp nhận điều này. Nó giữ một vị trí ngôn ngữ, do đó ngôn ngữ hiện tại cuối cùng vẫn đúng và lệnh chuyển đổi không cân bằng đó không bị phát hiện. Đó chưa bao giờ là cách chính xác để đóng một lệnh chuyển đổi. WPML 5.0 không còn chấp nhận điều đó nữa: lệnh gọi cuối cùng mở ra một phạm vi thứ hai thay vì đóng phạm vi đầu tiên, và WPML tiếp tục báo cáo rằng ngôn ngữ đã được chuyển đổi.
WPML không thể phát hiện điều này, vì chính lệnh gọi đó cũng là một lệnh chuyển đổi hợp lệ sang ngôn ngữ gốc của đoạn mã xung quanh.
Triệu chứng này bị trì hoãn. Ngay sau cặp lệnh đó, ngôn ngữ hiện tại vẫn đúng, do đó một bài kiểm tra chỉ kiểm tra điều này sẽ vượt qua. Lệnh khôi phục đúng tiếp theo ở lớp ngoài sau đó sẽ đóng phạm vi đang mở của bạn thay vì của chính nó, và đoạn mã đó sẽ chạy sai ngôn ngữ. Các email, phản hồi REST và các màn hình trang quản trị là nơi điều này hiển thị.
Một lệnh chuyển đổi không có lệnh khôi phục, hoặc có mã ngôn ngữ trống, cũng sẽ để ngỏ một phạm vi theo cách tương tự.
Giải pháp tạm thời
Đóng mọi phạm vi bằng null, trong một khối finally:
do_action( 'wpml_switch_language', 'de' );
try {
// ...your work in German...
} finally {
do_action( 'wpml_switch_language', null ); // Closes the scope above.
}
Hỗ trợ WPML 4.x và 5.0 trong cùng một phiên bản phát hành
Sao chép các hàm trợ giúp này vào và đổi tên tiền tố:
// 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 );
}
Mỗi vị trí gọi sau đó sẽ trở thành:
$previous = myplugin_wpml_open_language_switch( 'de' );
try {
// ... work ...
} finally {
myplugin_wpml_close_language_switch( $previous );
}
Chạy grep -rn "wpml_switch_language" . để tìm mọi vị trí gọi. Mỗi vị trí cần một lệnh đóng tương ứng. Không bao giờ khôi phục bằng cách gọi tên ngôn ngữ và không bao giờ chuyển đổi trên một mã có thể trống.
Các hook email cũng lồng nhau: gọi wpml_restore_language_from_email một lần cho mỗi wpml_switch_language_for_email.