Nội dung bài viết

Theme gốc mua ngoài thị trường thường đã kèm sẵn file ngôn ngữ, bạn chỉ cần dịch file đó sang tiếng Việt là xong. Vấn đề phát sinh khi bạn viết thêm chức năng trong child theme và muốn những chuỗi mới đó cũng dịch được.

Text domain là gì

Mỗi theme và plugin trong WordPress có một định danh riêng gọi là text domain. Khi bạn viết:

_e( 'Xem thêm', 'web99' );

WordPress hiểu là: tìm bản dịch của chuỗi Xem thêm trong tập hợp bản dịch mang tên web99. Nếu chưa có bản dịch nào được nạp cho web99, nó in nguyên văn chuỗi gốc.

Đây chính là lý do chuỗi trong child theme không tự dịch được: theme cha đã nạp text domain của nó, còn text domain của bạn thì chưa ai nạp cả.

Nạp text domain cho child theme

Thêm đoạn sau vào functions.php của child theme:

<?php
add_action( 'after_setup_theme', 'child_load_text_domain' );

function child_load_text_domain() {
    // Ghi đè bản dịch của theme cha (ví dụ Flatsome)
    load_theme_textdomain( 'flatsome', get_stylesheet_directory() . '/languages/flatsome' );

    // Nạp bản dịch cho text domain riêng của child theme
    load_child_theme_textdomain( 'web99', get_stylesheet_directory() . '/languages' );
}

Hai hàm này làm hai việc khác nhau:

  • load_theme_textdomain() với text domain của theme cha cho phép bạn ghi đè bản dịch có sẵn mà không đụng vào file gốc. Bản cập nhật theme cha sẽ không xóa mất công sức của bạn.
  • load_child_theme_textdomain() nạp bản dịch cho các chuỗi bạn tự viết.

Đoạn code trên dùng được cho mọi theme WordPress, không riêng gì Flatsome. Chỉ cần thay flatsome bằng text domain của theme bạn đang dùng, tìm thấy trong file style.css của theme cha hoặc bằng cách xem chuỗi thứ hai trong các lời gọi __() của theme đó.

Vì sao phải là after_setup_theme

Hook after_setup_theme chạy đủ sớm để bản dịch sẵn sàng trước khi bất kỳ chuỗi nào được in ra. Nạp muộn hơn, ví dụ trong init hoặc wp_head, sẽ khiến một phần chuỗi đã kịp hiển thị nguyên văn tiếng Anh.

Tạo file .po và .mo bằng Poedit

WordPress không đọc file văn bản thường mà đọc file .mo đã biên dịch. Quy trình như sau:

  1. Tải và cài Poedit (bản miễn phí là đủ dùng).
  2. Chọn File > New rồi chọn ngôn ngữ đích là Vietnamese.
  3. Vào Catalog > Properties > Sources paths, trỏ tới thư mục child theme.
  4. Sang tab Sources keywords, thêm các hàm dịch của WordPress: __, _e, esc_html__, esc_html_e, esc_attr__, esc_attr_e, _n, _x.
  5. Bấm Update from code để Poedit quét toàn bộ chuỗi trong code.
  6. Dịch từng chuỗi rồi lưu lại. Poedit sinh ra đồng thời hai file .po.mo.

Quy tắc đặt tên file

Đây là chỗ hay sai nhất. Tên file phải khớp chính xác với mã ngôn ngữ (locale), nếu không WordPress sẽ không tìm thấy:

  • Cho load_child_theme_textdomain: đặt tên theo locale, ví dụ vi.povi.mo
  • Cho load_theme_textdomain ghi đè theme cha: đặt tên {text-domain}-{locale}, ví dụ flatsome-vi.mo

Locale tiếng Việt trong WordPress là vi. Bạn có thể kiểm tra locale hiện tại bằng cách gọi get_locale().

Sau khi có file, upload lên đúng thư mục đã khai báo trong code, tức /languages trong child theme.

Viết chuỗi cho đúng ngay từ đầu

Bản dịch chỉ hoạt động nếu chuỗi trong code được viết đúng cách:

// Đúng: chuỗi và text domain đều là literal
esc_html_e( 'Liên hệ ngay', 'web99' );

// Sai: dùng biến thì Poedit không quét được
esc_html_e( $label, 'web99' );

// Sai: nối chuỗi làm mất ngữ cảnh của người dịch
_e( 'Còn ' . $n . ' sản phẩm', 'web99' );

// Đúng: dùng placeholder
printf(
    esc_html__( 'Còn %d sản phẩm', 'web99' ),
    $n
);

Poedit quét mã nguồn tĩnh, nên bất cứ chỗ nào bạn truyền biến vào thay cho chuỗi literal đều sẽ bị bỏ sót.

Khi bản dịch không hiện

Vài chỗ nên kiểm tra theo thứ tự:

  1. File .mo đã tồn tại chưa, và tên có đúng locale không. Poedit chỉ sinh .mo khi bạn bật tùy chọn biên dịch trong Preferences.
  2. Ngôn ngữ site đã đặt sang Tiếng Việt trong Cài đặt > Tổng quan chưa.
  3. Text domain trong code có khớp với text domain khai báo trong load_child_theme_textdomain() không. Sai một ký tự là hỏng.
  4. Có plugin cache nào đang giữ trang cũ không. Xóa cache rồi thử lại.