localization optimization to avoid regex
Sonarqube Scanner / Prepare environment (push) Successful in 15s
Sonarqube Scanner / Build and test (push) Successful in 43s
Sonarqube Scanner / SonarQube analysis (push) Failing after 2m10s
Sonarqube Scanner / Deploy to Server (push) Successful in 10s

This commit is contained in:
Florian Zumpe
2026-10-01 17:00:08 +02:00
parent 5c4d20bd1d
commit ad09fecfd5
2 changed files with 138 additions and 13 deletions
+33
View File
@@ -31,6 +31,39 @@ test('HTML generation escapes text and attributes, preserves i18n markers and up
assert.equal(localizeHtml(result, translate), result);
});
test('HTML scanning respects quoted tag delimiters, comments, boolean attributes and nested content', () => {
const source = '<!-- <h1 data-i18n="ignored">do not translate</h1> -->'
+ '<button disabled title=old data-i18n-title="label" data-note="a > b">?</button>'
+ "<h1 data-i18n='heading'>old</h1>"
+ '<p data-i18n="parent"><strong>Keep nested text</strong></p>';
const calls = [];
const result = localizeHtml(source, key => {
calls.push(key);
return { heading: 'New heading', label: 'Sam\'s "label"' }[key];
});
assert.deepEqual(calls, ['label', 'heading']);
assert.ok(result.includes('<!-- <h1 data-i18n="ignored">do not translate</h1> -->'));
assert.ok(result.includes('disabled title="Sam&#39;s &quot;label&quot;"'));
assert.ok(result.includes('data-note="a > b"'));
assert.ok(result.includes("<h1 data-i18n='heading'>New heading</h1>"));
assert.ok(result.includes('<p data-i18n="parent"><strong>Keep nested text</strong></p>'));
});
test('HTML scanning preserves incomplete tags, quoted attributes and comments', () => {
for (const tail of ['<h1 data-i18n="title"', '<button title="unfinished >', '<!-- unfinished <h1>']) {
const source = `Plain text${tail}`;
assert.equal(localizeHtml(source, () => assert.fail('Incomplete markup must not be translated')), source);
}
});
test('HTML scanning handles long malformed input without regex backtracking', { timeout: 2000 }, () => {
const source = '<'.repeat(200000) + ' unfinished';
assert.equal(localizeHtml(source, () => assert.fail('Malformed markup must not be translated')), source);
const attribute = 'x'.repeat(200000);
const html = `<h1 data-note="${attribute}" data-i18n="heading">old</h1>`;
assert.equal(localizeHtml(html, () => 'New heading'), `<h1 data-note="${attribute}" data-i18n="heading">New heading</h1>`);
});
test('translations support placeholders, plurals and German fallback without treating text as HTML', async () => {
const context = {};
const i18n = await loadI18n(context);