|
| 1 | +import {DomUtils, parseDocument} from 'htmlparser2'; |
1 | 2 | import type {TranslationTargetLocale} from '@src/CONST/LOCALES'; |
2 | 3 |
|
3 | 4 | /** |
@@ -55,23 +56,21 @@ abstract class Translator { |
55 | 56 | const TRANSLATABLE_ATTRIBUTES = ['alt', 'title', 'placeholder', 'aria-label', 'aria-describedby', 'aria-labelledby', 'value']; |
56 | 57 |
|
57 | 58 | const parseHTMLStructure = (s: string) => { |
58 | | - const tags = Array.from(s.matchAll(/<([^>]+)>/g)); |
59 | | - return tags.map((match) => { |
60 | | - const tagContent = match[1]; |
61 | | - const tagName = tagContent.split(/\s/).at(0)?.toLowerCase(); |
| 59 | + const doc = parseDocument(s); |
| 60 | + const elements = DomUtils.getElementsByTagName(() => true, doc, true); |
| 61 | + |
| 62 | + return elements.map((element) => { |
| 63 | + const tagName = element.name.toLowerCase(); |
62 | 64 |
|
63 | 65 | // Extract attributes, excluding translatable ones |
64 | 66 | const attributes: string[] = []; |
65 | | - const attrMatches = Array.from(tagContent.matchAll(/(\w+)(?:=["']([^"']*)["'])?/g)); |
66 | | - |
67 | | - for (const attrMatch of attrMatches) { |
68 | | - const attrName = attrMatch[1].toLowerCase(); |
69 | | - const attrValue = attrMatch[2] || ''; |
70 | | - |
71 | | - // Only include non-translatable attributes in comparison |
72 | | - if (!TRANSLATABLE_ATTRIBUTES.includes(attrName)) { |
73 | | - attributes.push(`${attrName}="${attrValue}"`); |
74 | | - } |
| 67 | + if (element.attribs) { |
| 68 | + Object.entries(element.attribs).forEach(([attrName, attrValue]) => { |
| 69 | + const normalizedAttrName = attrName.toLowerCase(); |
| 70 | + if (!TRANSLATABLE_ATTRIBUTES.includes(normalizedAttrName)) { |
| 71 | + attributes.push(`${normalizedAttrName}="${attrValue ?? ''}"`); |
| 72 | + } |
| 73 | + }) |
75 | 74 | } |
76 | 75 |
|
77 | 76 | return { |
|
0 commit comments