diff --git a/src/browser/webapi/element/Html.zig b/src/browser/webapi/element/Html.zig
index 4cd12b702..67924b0c5 100644
--- a/src/browser/webapi/element/Html.zig
+++ b/src/browser/webapi/element/Html.zig
@@ -345,6 +345,28 @@ pub fn setHidden(self: *HtmlElement, hidden: bool, frame: *Frame) !void {
}
}
+// The translate IDL attribute reflects the element's translation mode:
+// translate="yes"/"" enables it, "no" disables it, anything else (or no
+// attribute) inherits from the parent, defaulting to enabled.
+pub fn getTranslate(self: *HtmlElement) bool {
+ var node: ?*Node = self.asElement().asNode();
+ while (node) |n| : (node = n.parentNode()) {
+ const el = n.is(Element) orelse continue;
+ const value = el.getAttributeSafe(comptime .wrap("translate")) orelse continue;
+ if (value.len == 0 or std.ascii.eqlIgnoreCase(value, "yes")) {
+ return true;
+ }
+ if (std.ascii.eqlIgnoreCase(value, "no")) {
+ return false;
+ }
+ }
+ return true;
+}
+
+pub fn setTranslate(self: *HtmlElement, translate: bool, frame: *Frame) !void {
+ try self.asElement().setAttributeSafe(comptime .wrap("translate"), .wrap(if (translate) "yes" else "no"), frame);
+}
+
pub fn getPopover(self: *HtmlElement) ?[]const u8 {
const s = popover.getState(self.asElement()) orelse return null;
return @tagName(s);
@@ -1707,6 +1729,7 @@ pub const JsApi = struct {
pub const autofocus = bridge.accessor(HtmlElement.getAutofocus, HtmlElement.setAutofocus, .{ .ce_reactions = true });
pub const dir = bridge.accessor(HtmlElement.getDir, HtmlElement.setDir, .{ .ce_reactions = true });
pub const hidden = bridge.accessor(HtmlElement.getHidden, HtmlElement.setHidden, .{ .ce_reactions = true });
+ pub const translate = bridge.accessor(HtmlElement.getTranslate, HtmlElement.setTranslate, .{ .ce_reactions = true });
pub const popover = bridge.accessor(HtmlElement.getPopover, HtmlElement.setPopover, .{ .ce_reactions = true });
pub const showPopover = bridge.function(HtmlElement.showPopover, .{});
pub const hidePopover = bridge.function(HtmlElement.hidePopover, .{});