Skip to content

Commit 1f3614b

Browse files
docs-botCopilotheiskr
authored
fix: add new Liquid corruption patterns for 8 translation languages (#60599)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Kevin Heis <heiskr@users.noreply.github.com>
1 parent 800591d commit 1f3614b

File tree

2 files changed

+108
-3
lines changed

2 files changed

+108
-3
lines changed

src/languages/lib/correct-translation-content.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ export function correctTranslatedContentStrings(
6666
content = content.replaceAll('{% nota %}', '{% note %}')
6767
content = content.replaceAll('{%- nota %}', '{%- note %}')
6868
content = content.replaceAll('{%- nota -%}', '{%- note -%}')
69+
// `{% otra %}` / `{%- otra %}` — "another/other" = else
70+
content = content.replaceAll('{% otra %}', '{% else %}')
71+
content = content.replaceAll('{%- otra %}', '{%- else %}')
72+
// `{% encabezados de fila %}` — "row headers" = rowheaders
73+
content = content.replaceAll('{% encabezados de fila %}', '{% rowheaders %}')
74+
content = content.replaceAll('{%- encabezados de fila %}', '{%- rowheaders %}')
6975
}
7076

7177
if (context.code === 'ja') {
@@ -104,6 +110,14 @@ export function correctTranslatedContentStrings(
104110
content = content.replaceAll('{% 終了コメント %}', '{% endcomment %}')
105111
content = content.replaceAll('{% エンドビジュアルスタジオ %}', '{% endvisualstudio %}')
106112
content = content.replaceAll('{% エクリプス %}', '{% eclipse %}')
113+
// `{% それ以外の %}` — truncated form of "in the other case" = else
114+
content = content.replaceAll('{% それ以外の %}', '{% else %}')
115+
content = content.replaceAll('{%- それ以外の %}', '{%- else %}')
116+
// `{% それ以外の場合 ifversion X %}` → `{% elsif X %}` (confused elsif + ifversion)
117+
content = content.replace(
118+
/\{% ifversion\s+(.+?)\s*%\}/g,
119+
'{% elsif $1 %}',
120+
)
107121
// `{%- "supported" %}` → `{%- when "supported" %}` (missing `when`)
108122
// Preserves original trim syntax (`{%-` vs `{%`)
109123
content = content.replace(/\{%-?\s*"(supported|not_supported|preview)"\s*%\}/g, (match) => {
@@ -220,6 +234,9 @@ export function correctTranslatedContentStrings(
220234
content = content.replaceAll('{% 数据可重用', '{% data reusables')
221235
content = content.replaceAll('{% 其他 %}', '{% else %}')
222236
content = content.replaceAll('{% 原始 %}', '{% raw %}')
237+
// `{% 否则 %}` — "otherwise" = else (different Chinese word than 其他)
238+
content = content.replaceAll('{% 否则 %}', '{% else %}')
239+
content = content.replaceAll('{%- 否则 %}', '{%- else %}')
223240
// Chinese `如果` = "if": `{ 如果 X %}` → `{% if X %}`
224241
content = content.replace(/\{ /g, '{% if ')
225242
// Stray Chinese `,则为` ("then") merged with `{%` before HTML: `,则为 {%<tag>` → `<tag>`
@@ -305,13 +322,17 @@ export function correctTranslatedContentStrings(
305322
content = content.replaceAll('{% данных для повторного использования.', '{% data reusables.')
306323
content = content.replaceAll('{% еще %}', '{% else %}')
307324
content = content.replaceAll('{% ещё %}', '{% else %}')
325+
// `{% иначе %}` — "otherwise" = else
326+
content = content.replaceAll('{% иначе %}', '{% else %}')
327+
content = content.replaceAll('{%- иначе %}', '{%- else %}')
308328
content = content.replaceAll('{% необработанные %}', '{% raw %}')
309329
content = content.replaceAll('{% необработанный %}', '{% raw %}')
310330
content = content.replaceAll('{% сырой %}', '{% raw %}')
311331
content = content.replaceAll('{% нарисовать %}', '{% endraw %}')
312332
content = content.replaceAll('{% эндкёрл %}', '{% endcurl %}')
313333
content = content.replaceAll('{% запроса %}', '{% endraw %}')
314-
334+
// `{% Mac %}` — capitalized mac platform tag
335+
content = content.replaceAll('{% Mac %}', '{% mac %}')
315336
// Fix double quotes in Russian YAML files that cause parsing errors
316337
content = content.replace(/href=""https:\/\//g, 'href="https://')
317338

@@ -386,6 +407,9 @@ export function correctTranslatedContentStrings(
386407
content = content.replaceAll('{% conseil %}', '{% tip %}')
387408
content = content.replaceAll('{%- conseil %}', '{%- tip %}')
388409
content = content.replaceAll('{%- conseil -%}', '{%- tip -%}')
410+
// `{% sinon %}` / `{%- sinon %}` — French "otherwise" = else
411+
content = content.replaceAll('{% sinon %}', '{% else %}')
412+
content = content.replaceAll('{%- sinon %}', '{%- else %}')
389413
// Remove orphaned {% endif %} tags when no ifversion/elsif opener exists in the content.
390414
// Caused by translations where only the closing tag survived (e.g. user-api.md reusable).
391415
if (
@@ -416,6 +440,11 @@ export function correctTranslatedContentStrings(
416440
content = content.replace(/\{%-? (?:ifversion|elsif|if) [^%]*?[^%]*?%\}/g, (match) => {
417441
return match.replace(/ /g, ' or ')
418442
})
443+
// `{% 그렇지 않으면 %}` — "otherwise" = else
444+
content = content.replaceAll('{% 그렇지 않으면 %}', '{% else %}')
445+
content = content.replaceAll('{%- 그렇지 않으면 %}', '{%- else %}')
446+
// `{% 옥티콘` — Korean transliteration of "octicon"
447+
content = content.replaceAll('{% 옥티콘 ', '{% octicon ')
419448

420449
// Korean translation of github-glossary.md
421450
content = content.replaceAll('{{ 용어집.term }}', '{{ glossary.term }}')
@@ -431,6 +460,8 @@ export function correctTranslatedContentStrings(
431460
content = content.replaceAll('{% data wiederverwendbare.', '{% data reusables.')
432461
content = content.replaceAll('{% Daten wiederverwendbare.', '{% data reusables.')
433462
content = content.replaceAll('{% Data wiederverwendbare.', '{% data reusables.')
463+
// `wiederverwendbar.` (without trailing 'e') — alternate German form
464+
content = content.replaceAll('{% Daten wiederverwendbar.', '{% data reusables.')
434465
content = content.replaceAll('{%-Daten variables', '{%- data variables')
435466
content = content.replaceAll('{%-Daten-variables', '{%- data variables')
436467
content = content.replaceAll('{%- ifversion fpt oder ghec %}', '{%- ifversion fpt or ghec %}')
@@ -453,6 +484,12 @@ export function correctTranslatedContentStrings(
453484
content = content.replace(/\{%-? für (\w+) in /g, (match) => {
454485
return match.replace('für', 'for')
455486
})
487+
// `{% ansonsten %}` / `{%- ansonsten %}` — "otherwise" = else
488+
content = content.replaceAll('{% ansonsten %}', '{% else %}')
489+
content = content.replaceAll('{%- ansonsten %}', '{%- else %}')
490+
// `{% Zeilenkopfzeilen %}` — "row headers" = rowheaders
491+
content = content.replaceAll('{% Zeilenkopfzeilen %}', '{% rowheaders %}')
492+
content = content.replaceAll('{%- Zeilenkopfzeilen %}', '{%- rowheaders %}')
456493
}
457494

458495
// --- Generic fixes (all languages) ---

src/languages/tests/correct-translation-content.ts

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,16 @@ describe('correctTranslatedContentStrings', () => {
8181
expect(fix('{%- nota -%}', 'es')).toBe('{%- note -%}')
8282
})
8383

84+
test('fixes otra → else', () => {
85+
expect(fix('{% otra %}', 'es')).toBe('{% else %}')
86+
expect(fix('{%- otra %}', 'es')).toBe('{%- else %}')
87+
})
88+
89+
test('fixes encabezados de fila → rowheaders', () => {
90+
expect(fix('{% encabezados de fila %}', 'es')).toBe('{% rowheaders %}')
91+
expect(fix('{%- encabezados de fila %}', 'es')).toBe('{%- rowheaders %}')
92+
})
93+
8494
test('fixes multiple or-translations in single ifversion', () => {
8595
expect(fix('{% ifversion fpt o ghec o ghes %}', 'es')).toBe(
8696
'{% ifversion fpt or ghec or ghes %}',
@@ -216,6 +226,21 @@ describe('correctTranslatedContentStrings', () => {
216226
// `{ endif% %}` — percent appears after "endif" instead of after the opening brace
217227
expect(fix('some content\n{ endif% %}\nmore', 'ja')).toBe('some content\n{% endif %}\nmore')
218228
})
229+
230+
test('fixes truncated それ以外の → else', () => {
231+
expect(fix('{% それ以外の %}', 'ja')).toBe('{% else %}')
232+
expect(fix('{%- それ以外の %}', 'ja')).toBe('{%- else %}')
233+
})
234+
235+
test('fixes それ以外の場合 ifversion X → elsif X', () => {
236+
expect(fix('{% それ以外の場合 ifversion codeql-rust-public-preview %}', 'ja')).toBe(
237+
'{% elsif codeql-rust-public-preview %}',
238+
)
239+
// no space before closing tag
240+
expect(fix('{% それ以外の場合 ifversion codeql-rust-public-preview%}', 'ja')).toBe(
241+
'{% elsif codeql-rust-public-preview %}',
242+
)
243+
})
219244
})
220245

221246
// ─── PORTUGUESE (pt) ───────────────────────────────────────────────
@@ -320,6 +345,11 @@ describe('correctTranslatedContentStrings', () => {
320345
expect(fix('{% ifversion fpt 或 ghec %}', 'zh')).toBe('{% ifversion fpt or ghec %}')
321346
expect(fix('{%- elsif fpt 或 ghec %}', 'zh')).toBe('{%- elsif fpt or ghec %}')
322347
})
348+
349+
test('fixes 否则 → else', () => {
350+
expect(fix('{% 否则 %}', 'zh')).toBe('{% else %}')
351+
expect(fix('{%- 否则 %}', 'zh')).toBe('{%- else %}')
352+
})
323353
})
324354

325355
// ─── RUSSIAN (ru) ──────────────────────────────────────────────────
@@ -474,6 +504,15 @@ describe('correctTranslatedContentStrings', () => {
474504
fix('{% octicon "организация" aria-hidden="true" aria-label="organization" %}', 'ru'),
475505
).toBe('{% octicon "organization" aria-hidden="true" aria-label="organization" %}')
476506
})
507+
508+
test('fixes иначе → else', () => {
509+
expect(fix('{% иначе %}', 'ru')).toBe('{% else %}')
510+
expect(fix('{%- иначе %}', 'ru')).toBe('{%- else %}')
511+
})
512+
513+
test('fixes capitalized Mac → mac platform tag', () => {
514+
expect(fix('{% Mac %}', 'ru')).toBe('{% mac %}')
515+
})
477516
})
478517

479518
// ─── FRENCH (fr) ───────────────────────────────────────────────────
@@ -548,6 +587,11 @@ describe('correctTranslatedContentStrings', () => {
548587
const input = '{% ifversion fpt %}a{% elsif ghec %}b{% endif %}'
549588
expect(fix(input, 'fr')).toBe(input)
550589
})
590+
591+
test('fixes sinon → else', () => {
592+
expect(fix('{% sinon %}', 'fr')).toBe('{% else %}')
593+
expect(fix('{%- sinon %}', 'fr')).toBe('{%- else %}')
594+
})
551595
})
552596

553597
// ─── KOREAN (ko) ──────────────────────────────────────────────────
@@ -592,6 +636,17 @@ describe('correctTranslatedContentStrings', () => {
592636
test('fixes Korean glossary template', () => {
593637
expect(fix('{{ 용어집.term }}', 'ko')).toBe('{{ glossary.term }}')
594638
})
639+
640+
test('fixes 그렇지 않으면 → else', () => {
641+
expect(fix('{% 그렇지 않으면 %}', 'ko')).toBe('{% else %}')
642+
expect(fix('{%- 그렇지 않으면 %}', 'ko')).toBe('{%- else %}')
643+
})
644+
645+
test('fixes 옥티콘 → octicon', () => {
646+
expect(fix('{% 옥티콘 "check" aria-label="Supported" %}', 'ko')).toBe(
647+
'{% octicon "check" aria-label="Supported" %}',
648+
)
649+
})
595650
})
596651

597652
// ─── GERMAN (de) ──────────────────────────────────────────────────
@@ -657,9 +712,22 @@ describe('correctTranslatedContentStrings', () => {
657712
fix('{% Data wiederverwendbare.audit_log.referenz-nach-kategorie-gruppiert %}', 'de'),
658713
).toBe('{% data reusables.audit_log.referenz-nach-kategorie-gruppiert %}')
659714
})
660-
})
715+
test('fixes wiederverwendbar (without trailing e) reusables path', () => {
716+
expect(fix('{% Daten wiederverwendbar.user-settings.access_settings %}', 'de')).toBe(
717+
'{% data reusables.user-settings.access_settings %}',
718+
)
719+
})
661720

662-
// ─── GENERIC FIXES ────────────────────────────────────────────────
721+
test('fixes ansonsten → else', () => {
722+
expect(fix('{% ansonsten %}', 'de')).toBe('{% else %}')
723+
expect(fix('{%- ansonsten %}', 'de')).toBe('{%- else %}')
724+
})
725+
726+
test('fixes Zeilenkopfzeilen → rowheaders', () => {
727+
expect(fix('{% Zeilenkopfzeilen %}', 'de')).toBe('{% rowheaders %}')
728+
expect(fix('{%- Zeilenkopfzeilen %}', 'de')).toBe('{%- rowheaders %}')
729+
})
730+
})
663731

664732
describe('Generic fixes (all languages)', () => {
665733
test('strips LLM sentinel markers and preserves word boundaries', () => {

0 commit comments

Comments
 (0)