()
| 165 | // Collect translation keys from source files |
| 166 | // --------------------------------------------------------------------------- |
| 167 | function collectSourceKeys() { |
| 168 | const files = SOURCE_SCAN_DIRS.flatMap((dir) => [ |
| 169 | ...findFiles(dir, ".tsx"), |
| 170 | ...findFiles(dir, ".ts"), |
| 171 | ...findFiles(dir, ".vue"), |
| 172 | ]); |
| 173 | const keys = new Set(); |
| 174 | // Only match single/double quoted strings — template literals with ${} are dynamic keys. |
| 175 | // This covers React `t("key")`, shared-module `t("key")`, and Vue `$t("key")`. |
| 176 | const re = /\bt\(\s*["']([^"']+)["']/g; |
| 177 | // <Trans i18nKey="..."> — react-i18next component-interpolation pattern |
| 178 | const transRe = /\bi18nKey\s*=\s*["']([^"']+)["']/g; |
| 179 | for (const file of files) { |
| 180 | const src = readFileSync(file, "utf-8"); |
| 181 | re.lastIndex = 0; |
| 182 | let m; |
| 183 | while ((m = re.exec(src))) { |
| 184 | keys.add(m[1]); |
| 185 | } |
| 186 | transRe.lastIndex = 0; |
| 187 | while ((m = transRe.exec(src))) { |
| 188 | keys.add(m[1]); |
| 189 | } |
| 190 | } |
| 191 | return keys; |
| 192 | } |
| 193 | |
| 194 | // --------------------------------------------------------------------------- |
| 195 | // Collect keys from a locale (main + generated/dynamic sections) |
no test coverage detected