Skip to content

Commit fde4d26

Browse files
committed
fix(android): validate resource apostrophe syntax
1 parent cf67008 commit fde4d26

3 files changed

Lines changed: 15 additions & 2 deletions

File tree

apps/android/app/src/main/res/values-it/strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<string name="use_tls">Usa TLS</string>
2121
<string name="token_optional">Token (opzionale)</string>
2222
<string name="password">Password</string>
23-
<string name="run_onboarding_again">Esegui di nuovo l&apos;onboarding</string>
23+
<string name="run_onboarding_again">Esegui di nuovo lonboarding</string>
2424
<string name="resolved_endpoint">Endpoint risolto</string>
2525
<string name="gateway_setup">Configurazione gateway</string>
2626
<string name="connect_to_gateway">Connettiti al tuo Gateway</string>

apps/android/app/src/main/res/values-tr/strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
<string name="scan_setup_code">Kurulum kodunu tara</string>
2828
<string name="use_gateway_qr">Gateway QR kodunuzu veya kurulum kodunuzu kullanın</string>
2929
<string name="nearby_gateway">Yakındaki ağ geçidi</string>
30-
<string name="enter_gateway_url">Ağ geçidi URL&apos;sini girin</string>
30+
<string name="enter_gateway_url">Ağ geçidi URLsini girin</string>
3131
<string name="connect_manual_url">Manuel URL kullanarak bağlan</string>
3232
<string name="permissions">İzinler</string>
3333
<string name="done">Bitti</string>

scripts/android-app-i18n.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const localeDirectory = (locale: string) => `values-${ANDROID_QUALIFIERS[locale]
1717
const LOCALES = ["values", ...NATIVE_I18N_LOCALES.map(localeDirectory)] as const;
1818
const STRING_RE = /<string\s+name="([A-Za-z0-9_]+)"[^>]*>([\s\S]*?)<\/string>/gu;
1919
const FORMAT_RE = /%\d+\$[a-z]/giu;
20+
const INVALID_APOSTROPHE_RE = /(?:&apos;|(?<!\\)')/u;
2021

2122
async function readStrings(locale: string): Promise<Map<string, string>> {
2223
const source = await readFile(path.join(RESOURCE_ROOT, locale, "strings.xml"), "utf8");
@@ -46,6 +47,16 @@ async function readAndroidSource(root = SOURCE_ROOT): Promise<string> {
4647
return sources.join("\n");
4748
}
4849

50+
function findInvalidResourceSyntax(strings: Map<string, string>): string[] {
51+
return [...strings]
52+
.filter(([, value]) => {
53+
const trimmed = value.trim();
54+
const isQuoted = trimmed.startsWith('"') && trimmed.endsWith('"');
55+
return !isQuoted && INVALID_APOSTROPHE_RE.test(trimmed);
56+
})
57+
.map(([key]) => key);
58+
}
59+
4960
export async function checkAndroidAppI18n() {
5061
const [source, localeStrings] = await Promise.all([
5162
readAndroidSource(),
@@ -69,8 +80,10 @@ export async function checkAndroidAppI18n() {
6980
[`${locale} missing`, [...baseKeys].filter((key) => !keys.has(key))],
7081
[`${locale} extra`, [...keys].filter((key) => !baseKeys.has(key))],
7182
[`${locale} placeholders`, placeholderMismatches],
83+
[`${locale} syntax`, findInvalidResourceSyntax(strings)],
7284
] as const;
7385
});
86+
problems.push(["English syntax", findInvalidResourceSyntax(base)]);
7487
const unusedBaseKeys = [...baseKeys].filter(
7588
(key) => !source.includes(`R.string.${key}`) && !source.includes(`@string/${key}`),
7689
);

0 commit comments

Comments
 (0)