From d5c57479a86c35a4e4360ffc0e085ae3acad3ef9 Mon Sep 17 00:00:00 2001 From: Francis Bouvier Date: Sun, 12 Jul 2026 11:45:10 +0200 Subject: [PATCH] webapi: implement the translate IDL attribute Fixes 7 failing files under /html/dom/elements/global-attributes/ (the-translate-attribute-007 through -012 and translate-enumerated-ascii-case-insensitive, 1 subtest each): the HTMLElement.translate property was missing entirely. The getter computes the element's translation mode per the HTML spec: translate="yes" or "" enables it, "no" disables it (both ASCII case-insensitively), anything else inherits from the closest ancestor with a valid value, defaulting to enabled. The setter reflects back as "yes"/"no". Coverage: the 7 files above each 0/1 -> 1/1 (fully green). Co-Authored-By: Claude Fable 5 --- src/browser/webapi/element/Html.zig | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) 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, .{});