Dịch thêm các khối Gutenberg
Gato AI Translations for Polylang có thể dịch các bài viết dựa trên khối.
Plugin đi kèm với hỗ trợ sẵn cho nhiều khối. Đối với những gì vượt ra ngoài phạm vi đó — các khối tùy chỉnh của bạn, hoặc các khối từ plugin của bên thứ ba không đi kèm wpml-config.xml — bạn có thể mở rộng hỗ trợ thông qua hook PHP.
Dịch chuỗi
Để đăng ký thêm các thuộc tính có thể dịch cho một khối, hãy sử dụng bộ lọc gatompl:gutenberg_block_type_translatable_attribute_regexes.
Tại sao dùng biểu thức chính quy?
Một khối Gutenberg được lưu vào post_content dưới dạng một chú thích HTML mang các thuộc tính JSON của khối, tiếp theo là HTML đã kết xuất của khối, ví dụ:
<!-- wp:my-plugin/my-block {"title":"Hello"} -->
<div class="wp-block-my-plugin-my-block">Hello</div>
<!-- /wp:my-plugin/my-block -->Dịch một khối có nghĩa là tìm chuỗi con cụ thể cần dịch bên trong markup đó, hoán đổi nó với bản dịch, và để nguyên mọi thứ khác (tên khối, các thuộc tính khác, cấu trúc HTML, các khối xung quanh). Biểu thức chính quy là cách plugin xác định chính xác chuỗi con nào cần thay thế: phần văn bản trước và sau giá trị được thu vào các nhóm, còn giá trị chính là phần được hoán đổi.
Thuộc tính chuỗi tiêu chuẩn (lưu trong JSON của khối)
Nếu thuộc tính là một chuỗi bình thường được lưu trong các thuộc tính JSON của khối, hãy truyền true và plugin sẽ sử dụng biểu thức chính quy mặc định của nó.
Ví dụ, để dịch các thuộc tính daysLabel, hoursLabel, minutesLabel và secondsLabel của khối kadence/countdown — có markup như sau:
<!-- wp:kadence/countdown {"uniqueID":"_abc123","date":"2026-12-31 00:00:00","daysLabel":"Days","hoursLabel":"Hours","minutesLabel":"Minutes","secondsLabel":"Seconds"} -->
<div class="wp-block-kadence-countdown">…</div>
<!-- /wp:kadence/countdown -->…đăng ký các thuộc tính thông qua:
add_filter(
'gatompl:gutenberg_block_type_translatable_attribute_regexes',
static function (array $regexes): array {
$regexes['kadence/countdown'] = [
'daysLabel' => true,
'hoursLabel' => true,
'minutesLabel' => true,
'secondsLabel' => true,
];
return $regexes;
}
);Giá trị true được mở rộng nội bộ thành biểu thức chính quy mặc định này:
#(<!-- wp:%3$s \{.*?\"%2$s\":\")%1$s(\".*?\}/?-->)#…trong đó các chỗ giữ chỗ là:
%1$s→ giá trị thuộc tính%2$s→ tên thuộc tính%3$s→ tên khối
Đối với thuộc tính daysLabel trên kadence/countdown, các chỗ giữ chỗ được thay thế như sau: %3$s → kadence/countdown, %2$s → daysLabel, %1$s → Days, tạo ra:
#(<!-- wp:kadence/countdown \{.*?\"daysLabel\":\")Days(\".*?\}/?-->)#Chỉ Days bị thay thế; tên khối, các thuộc tính khác và chú thích đóng được bảo toàn bởi các nhóm thu.
Dạng của biểu thức chính quy là:
#(tất cả những gì đứng trước)giá trị thuộc tính(tất cả những gì đứng sau)#Chuỗi lưu bên trong HTML của khối
Nếu giá trị không được lưu trong các thuộc tính JSON mà bên trong HTML đã kết xuất, hãy cung cấp biểu thức chính quy của riêng bạn. Bạn có thể dùng %s (thay vì %1$s) tại vị trí giá trị thuộc tính, và mã hóa cứng tên khối cùng tên thuộc tính vào biểu thức chính quy.
Ví dụ — dịch thuộc tính content của khối generateblocks/text. Markup của nó trông như thế này — lưu ý rằng Hello world không nằm trong JSON, mà nằm giữa các thẻ đã kết xuất:
<!-- wp:generateblocks/text {"uniqueId":"abc123","tagName":"p"} -->
<p class="gb-text">Hello world</p>
<!-- /wp:generateblocks/text -->Biểu thức chính quy mặc định sẽ không bao giờ tìm thấy chuỗi con đó, vì vậy bạn cung cấp biểu thức của riêng mình:
add_filter(
'gatompl:gutenberg_block_type_translatable_attribute_regexes',
static function (array $regexes): array {
$regexes['generateblocks/text'] = [
'content' => '#(<!-- wp:generateblocks/text [^>]*?-->\n?<[a-z0-9]+ ?[^>]*?>)%s(</[a-z0-9]+>\n?<!-- /wp:generateblocks/text -->)#',
];
return $regexes;
}
);Khi cùng một giá trị xuất hiện ở nhiều nơi
Nếu cùng một thuộc tính xuất hiện cả trong thuộc tính JSON lẫn trong HTML (hoặc ở hai vị trí khác nhau), hãy truyền một mảng biểu thức chính quy — mỗi biểu thức cần kích hoạt để mọi bản sao của chuỗi đều được dịch.
Ví dụ, trên khối generateblocks/media, alt và title được lưu cả bên trong htmlAttributes trong JSON, và là các thuộc tính HTML trên <img> đã kết xuất:
<!-- wp:generateblocks/media {"mediaId":42,"htmlAttributes":{"alt":"Cat sitting","title":"My cat"}} -->
<figure class="gb-media"><img src="…" alt="Cat sitting" title="My cat"></figure>
<!-- /wp:generateblocks/media -->Hai biểu thức chính quy mỗi thuộc tính — một nhắm vào JSON, một nhắm vào <img> — đảm bảo cả hai bản sao luôn đồng bộ sau khi dịch:
add_filter(
'gatompl:gutenberg_block_type_translatable_attribute_regexes',
static function (array $regexes): array {
$regexes['generateblocks/media'] = [
'htmlAttributes.alt' => [
'#(<!-- wp:generateblocks/media \{.*?\"htmlAttributes\":\{.*?\"alt\":\")%s(\".*?\}.*?\} -->)#',
'#(<!-- wp:generateblocks/media [^>]*?-->\n?.*<img [^>]*alt=\")%s(\"[^>]*?>.*\n?<!-- /wp:generateblocks/media -->)#',
],
'htmlAttributes.title' => [
'#(<!-- wp:generateblocks/media \{.*?\"htmlAttributes\":\{.*?\"title\":\")%s(\".*?\}.*?\} -->)#',
'#(<!-- wp:generateblocks/media [^>]*?-->\n?.*<img [^>]*title=\")%s(\"[^>]*?>.*\n?<!-- /wp:generateblocks/media -->)#',
],
];
return $regexes;
}
);Nếu giá trị thuộc tính là một đối tượng JSON, bạn có thể nhắm đến một thuộc tính con cụ thể bằng cách dùng dấu . (chấm) trong tên thuộc tính, như được minh họa ở trên với htmlAttributes.alt và htmlAttributes.title trên generateblocks/media.
Vô hiệu hóa dịch cho một thuộc tính được dịch tự động
Truyền false hoặc null xóa việc dịch cho một thuộc tính mà nếu không thì plugin sẽ dịch tự động. Điều này hữu ích, chẳng hạn, để loại trừ một thuộc tính chuỗi cụ thể khỏi việc dịch tự động trong các khối chỉ PHP, hoặc đối với các khối được kéo vào từ wpml-config.xml mà bạn không muốn dịch các thuộc tính đã khai báo:
add_filter(
'gatompl:gutenberg_block_type_translatable_attribute_regexes',
static function (array $regexes): array {
// Disable translation of the `header` attribute on the
// `my-plugin/duplicate-alert` block (either form works)
unset($regexes['my-plugin/duplicate-alert']['header']);
$regexes['my-plugin/duplicate-alert']['implications'] = false;
return $regexes;
}
);Dịch tham chiếu thực thể
Tham chiếu thực thể (ID bài viết/media/thuật ngữ/menu được lưu trong một thuộc tính khối) có thể được ánh xạ lại thành thực thể tương ứng ở ngôn ngữ đích tại thời điểm dịch. Hãy sử dụng một trong các bộ lọc sau tùy thuộc vào loại tham chiếu:
| Loại tham chiếu | Bộ lọc |
|---|---|
| Custom post và media | gatompl:gutenberg_block_type_custompost_and_media_reference_attribute_regexes |
| Thuật ngữ phân loại | gatompl:gutenberg_block_type_taxonomy_term_reference_attribute_regexes |
| Menu theo ID | gatompl:gutenberg_block_type_menu_reference_by_id_attribute_regexes |
| Menu theo slug | gatompl:gutenberg_block_type_menu_reference_by_slug_attribute_regexes |
Mỗi bộ lọc nhận cùng cấu trúc như bộ lọc thuộc tính có thể dịch (true cho biểu thức chính quy mặc định, một chuỗi/mảng cho biểu thức chính quy tùy chỉnh).
Ví dụ, khối woocommerce/single-product lưu sản phẩm được liên kết dưới dạng productId số:
<!-- wp:woocommerce/single-product {"productId":42} /-->Khi bài viết được dịch, giá trị 42 đó (sản phẩm ở ngôn ngữ nguồn) cần được ánh xạ lại thành đối tác ngôn ngữ đích của nó (ví dụ 87). Đánh dấu productId là tham chiếu custom post để plugin thu và hoán đổi ID tại thời điểm dịch:
add_filter(
'gatompl:gutenberg_block_type_custompost_and_media_reference_attribute_regexes',
static function (array $regexes): array {
$regexes['woocommerce/single-product'] = [
'productId' => true,
// …or a custom regex if `productId` is not stored in the standard JSON shape:
// 'productId' => '#(<!-- wp:woocommerce/single-product \{.*?\"productId\":)%s([,\}].*? /?-->)#',
];
return $regexes;
}
);Sử dụng cùng mẫu cho các loại tham chiếu khác. Mỗi loại trông giống nhau trong markup khối — một ID số hoặc slug nhúng trong JSON — điều khác biệt là cách plugin phân giải nó thành ngôn ngữ đích:
<!-- wp:my-plugin/related-category {"categoryId":17} /-->
<!-- wp:my-plugin/menu-picker {"menuId":5} /-->
<!-- wp:my-plugin/menu-picker {"menuSlug":"main-nav"} /-->// Taxonomy term reference
add_filter(
'gatompl:gutenberg_block_type_taxonomy_term_reference_attribute_regexes',
static function (array $regexes): array {
$regexes['my-plugin/related-category'] = [
'categoryId' => true,
];
return $regexes;
}
);
// Menu reference by ID
add_filter(
'gatompl:gutenberg_block_type_menu_reference_by_id_attribute_regexes',
static function (array $regexes): array {
$regexes['my-plugin/menu-picker'] = [
'menuId' => true,
];
return $regexes;
}
);
// Menu reference by slug
add_filter(
'gatompl:gutenberg_block_type_menu_reference_by_slug_attribute_regexes',
static function (array $regexes): array {
$regexes['my-plugin/menu-picker'] = [
'menuSlug' => true,
];
return $regexes;
}
);Khám phá tên thuộc tính
Cách nhanh nhất để tìm tên thuộc tính và cách chúng được lưu là chạy queries GraphQL Translate custom posts và xem trường phản hồi blockFlattenedDataItems cho khối đang xét.
Xem hướng dẫn Truy xuất dữ liệu page builder để dịch để biết cách chạy queries đó và đọc kết quả đầu ra của nó.
Xử lý các khối có thuộc tính cần tiền xử lý
Các hook ở trên giả định rằng giá trị thuộc tính được hiển thị qua blockFlattenedDataItems đã là giá trị cần dịch (một vô hướng hoặc mảng).
Nếu giá trị bị bao bọc — ví dụ, thuộc tính lưu <li>Some text</li> và bạn chỉ muốn dịch Some text — bạn cần trích xuất nó trước thông qua bộ lọc gatompl:gutenberg_block_flattened_data_item_attributes.
Khối generateblocks/image là một ví dụ thực tế: alt và title của nó không được hiển thị dưới dạng các thuộc tính độc lập, chúng nằm bên trong HTML của innerContent và phải được trích xuất bằng biểu thức chính quy.
add_filter(
'gatompl:gutenberg_block_flattened_data_item_attributes',
static function (?\stdClass $attributes, string $blockTypeName, \stdClass $blockDataItem): ?\stdClass {
if ($attributes === null || $blockTypeName !== 'generateblocks/image') {
return $attributes;
}
$innerContent = $blockDataItem->innerContent ?? null;
if (!is_array($innerContent) || !isset($innerContent[0]) || !is_string($innerContent[0])) {
return $attributes;
}
$html = $innerContent[0];
if (preg_match('#<img [^>]*alt="([^"]*)"[^>]*?>#', $html, $matches) === 1 && $matches[1] !== '') {
$attributes->alt = $matches[1];
}
if (preg_match('#<img [^>]*title="([^"]*)"[^>]*?>#', $html, $matches) === 1 && $matches[1] !== '') {
$attributes->title = $matches[1];
}
return $attributes;
},
10,
3
);Sau khi alt và title tồn tại trên đối tượng thuộc tính, các hook dựa trên biểu thức chính quy ở trên có thể nhắm đến chúng như bất kỳ thuộc tính nào khác.
Nơi tìm ví dụ
Các tích hợp của chính plugin là những tài liệu tham khảo thực tế tốt. Khám phá các tệp này bên trong plugin bạn đã cài đặt:
- Biểu thức chính quy thuộc tính khối:
wp-content/plugins/gato-ai-translations-for-polylang/src/Constants/BlockTypeAttributeValues.php - Tiền xử lý thuộc tính khối:
wp-content/plugins/gato-ai-translations-for-polylang/src/ConditionalOnContext/LicenseIsActive/Hooks/CoreBlockFlattenedDataItemAttributesHookSet.php