Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions src/static/js/vendors/html10n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,16 @@ export class Html10n {
// @ts-ignore
node[prop] = str.str!
populateAriaLabel()
} else if (node.tagName === 'SELECT' || node.tagName === 'INPUT' ||
node.tagName === 'TEXTAREA') {
// Form-controllable elements carry their accessible name on aria-label
// rather than as text content — a <select>'s text is its <option>
// labels, not its own name. Plugins that put `data-l10n-id` on a
// <select> (ep_headings2, ep_align, ep_font_size, …) used to trigger a
// spurious "could not translate element content" warning here because
// the text-node hunt below finds nothing to write. Short-circuit and
// just localize aria-label. See ether/ep_align#182 review.
populateAriaLabel()
} else {
let children = node.childNodes,
found = false
Expand All @@ -697,17 +707,6 @@ export class Html10n {
if (!found) {
console.warn('Unexpected error: could not translate element content for key '+str.id, node)
}
// Form-controllable elements (<select>, <input>, <textarea>) carry their
// accessible name on aria-label rather than as text content (a <select>'s
// text is its <option> labels, not its own name). The textContent branch
// above doesn't fall through to populateAriaLabel(), so plugins that put
// data-l10n-id on a <select> and rely on the auto-population (introduced
// in #7584) end up with no accessible name. Populate aria-label here so
// those controls stay localized too. See ether/ep_align#182 review.
const tag = node.tagName;
if (tag === 'SELECT' || tag === 'INPUT' || tag === 'TEXTAREA') {
populateAriaLabel()
}
}
}

Expand Down
35 changes: 35 additions & 0 deletions src/tests/frontend-new/specs/html10n_form_controls_aria.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,41 @@ test('html10n auto-populates aria-label on <textarea> with data-l10n-id', async
await expect(ta).toHaveAttribute('data-l10n-aria-label', 'true');
});

test('no "could not translate element content" warning for <select data-l10n-id>', async ({page}) => {
// Regression: thm reported the warning on Etherpad 3.1.0 because the
// <select data-l10n-id="ep_headings.style"> in ep_headings2 has only
// <option> element children — the text-node hunt in translateNode finds
// nothing and used to warn before the SELECT/INPUT/TEXTAREA short-circuit
// landed. The accessible name still ends up on aria-label.
const warnings: string[] = [];
page.on('console', (msg) => {
if (msg.type() === 'warning') warnings.push(msg.text());
});

await page.evaluate(() => {
const sel = document.createElement('select');
sel.id = 'html10n-test-no-warn';
sel.setAttribute('data-l10n-id', 'pad.toolbar.bold.title');
for (const v of ['a', 'b', 'c']) {
Comment thread
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.
Outdated
const opt = document.createElement('option');
opt.value = v;
opt.textContent = v.toUpperCase();
sel.appendChild(opt);
}
document.body.appendChild(sel);
// @ts-ignore
window.html10n.localize(['en']);
});

// Give html10n a tick to run.
await page.waitForTimeout(50);

const offending = warnings.filter((m) =>
m.includes('could not translate element content') &&
m.includes('pad.toolbar.bold.title'));
expect(offending).toEqual([]);
});

test('an author-supplied aria-label on a form control is preserved', async ({page}) => {
// Mirror the existing semantics for non-form-control elements: if the
// template author wrote their own aria-label, html10n must not
Expand Down
Loading