Skip to content

Commit 41b4155

Browse files
committed
add all missing translations; add test to ensure no translations will be missed in the future
1 parent 415cbf9 commit 41b4155

File tree

10 files changed

+513
-26
lines changed

10 files changed

+513
-26
lines changed

src/i18n/de.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,22 @@ const fixedGermanMessages = {
4545
},
4646
};
4747

48+
const { add_filter: _deAddFilter, ...deNavigation } = fixedGermanMessages.ra.navigation;
49+
4850
const de: SynapseTranslationMessages = {
4951
...fixedGermanMessages,
52+
ra: {
53+
...fixedGermanMessages.ra,
54+
navigation: deNavigation,
55+
action: {
56+
...fixedGermanMessages.ra.action,
57+
reset: "Zurücksetzen",
58+
},
59+
validation: {
60+
...fixedGermanMessages.ra.validation,
61+
unique: "Muss eindeutig sein",
62+
},
63+
},
5064
synapseadmin: {
5165
auth: {
5266
base_url: "Heimserver URL",

src/i18n/fa.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,28 @@ import { SynapseTranslationMessages } from ".";
44

55
const fa: SynapseTranslationMessages = {
66
...farsiMessages,
7+
ra: {
8+
...farsiMessages.ra,
9+
action: {
10+
...farsiMessages.ra.action,
11+
reset: "بازنشانی",
12+
search_columns: "جستجوی ستون‌ها",
13+
select_all_button: "انتخاب همه",
14+
},
15+
auth: {
16+
...farsiMessages.ra.auth,
17+
email: "ایمیل",
18+
},
19+
message: {
20+
...farsiMessages.ra.message,
21+
placeholder_data_warning: "مشکل شبکه: به‌روزرسانی داده‌ها ناموفق بود.",
22+
select_all_limit_reached: "تعداد انتخاب‌ها زیاد است. فقط %{max} مورد اول انتخاب شد.",
23+
},
24+
notification: {
25+
...farsiMessages.ra.notification,
26+
offline: "بدون اتصال. داده‌ها قابل دریافت نیستند.",
27+
},
28+
},
729
synapseadmin: {
830
auth: {
931
base_url: "آدرس سرور",
@@ -15,6 +37,7 @@ const fa: SynapseTranslationMessages = {
1537
sso_sign_in: "با SSO وارد شوید",
1638
credentials: "اعتبارنامه",
1739
access_token: "توکن دسترسی",
40+
supports_specs: "پشتیبانی از مشخصات Matrix",
1841
logout_acces_token_dialog: {
1942
title: "شما در حال استفاده از یک نشانه دسترسی ماتریکس موجود هستید.",
2043
content:
@@ -28,6 +51,7 @@ const fa: SynapseTranslationMessages = {
2851
tabs: { sso: "SSO", experimental: "تجربی", limits: "محدودیت ها", account_data: "داده های کاربر" },
2952
},
3053
rooms: {
54+
details: "جزئیات اتاق",
3155
tabs: {
3256
basic: "اصلی",
3357
members: "اعضا",
@@ -161,6 +185,7 @@ const fa: SynapseTranslationMessages = {
161185
consent_version: "Consent نسخه",
162186
auth_provider: "ارائه دهنده",
163187
user_type: "نوع کاربر",
188+
erased: "پاک‌شده (GDPR)",
164189
},
165190
helper: {
166191
password_required_for_reactivation: "برای فعالسازی مجدد حساب باید رمز عبور وارد کنید.",
@@ -302,9 +327,19 @@ const fa: SynapseTranslationMessages = {
302327
format: "قالب",
303328
formatted_body: "محتوای قالب بندی شده",
304329
algorithm: "الگوریتم",
330+
url: "نشانی",
331+
info: {
332+
mimetype: "نوع",
333+
},
305334
},
306335
},
307336
},
337+
action: {
338+
erase: {
339+
title: "حذف رویداد گزارش‌شده",
340+
content: "آیا مطمئن هستید که می‌خواهید رویداد گزارش‌شده را حذف کنید؟ این کار قابل بازگشت نیست.",
341+
},
342+
},
308343
},
309344
connections: {
310345
name: "اتصالات",
@@ -343,6 +378,9 @@ const fa: SynapseTranslationMessages = {
343378
created_ts: "ایجاد شده",
344379
last_access_ts: "آخرین دسترسی",
345380
},
381+
action: {
382+
open: "باز کردن فایل رسانه در پنجره جدید",
383+
},
346384
},
347385
protect_media: {
348386
action: {

src/i18n/fr.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const fr: SynapseTranslationMessages = {
1515
sso_sign_in: "Se connecter avec l'authentification unique",
1616
credentials: "Identifiants",
1717
access_token: "Jeton d'accès",
18+
supports_specs: "prend en charge les spécifications Matrix",
1819
logout_acces_token_dialog: {
1920
title: "Vous utilisez un jeton d'accès Matrix existant.",
2021
content:
@@ -33,6 +34,7 @@ const fr: SynapseTranslationMessages = {
3334
},
3435
},
3536
rooms: {
37+
details: "Détails de la salle",
3638
tabs: {
3739
basic: "Informations de base",
3840
members: "Membres",
@@ -168,6 +170,8 @@ const fr: SynapseTranslationMessages = {
168170
creation_ts_ms: "Date de création",
169171
consent_version: "Version du consentement",
170172
auth_provider: "Fournisseur d'identité",
173+
user_type: "Type d'utilisateur",
174+
erased: "Effacé (RGPD)",
171175
},
172176
helper: {
173177
password: "Changer le mot de passe déconnectera l'utilisateur de toutes les sessions.",
@@ -309,9 +313,19 @@ const fr: SynapseTranslationMessages = {
309313
format: "Format",
310314
formatted_body: "Contenu mis en forme",
311315
algorithm: "Algorithme",
316+
url: "URL",
317+
info: {
318+
mimetype: "Type",
319+
},
312320
},
313321
},
314322
},
323+
action: {
324+
erase: {
325+
title: "Supprimer l’événement signalé",
326+
content: "Voulez-vous vraiment supprimer l’événement signalé ? Cette action est irréversible.",
327+
},
328+
},
315329
},
316330
connections: {
317331
name: "Connexions",
@@ -350,6 +364,9 @@ const fr: SynapseTranslationMessages = {
350364
created_ts: "Date de création",
351365
last_access_ts: "Dernier accès",
352366
},
367+
action: {
368+
open: "Ouvrir le fichier média dans une nouvelle fenêtre",
369+
},
353370
},
354371
protect_media: {
355372
action: {
@@ -452,6 +469,18 @@ const fr: SynapseTranslationMessages = {
452469
send_failure: "Une erreur s'est produite",
453470
},
454471
},
472+
destinations: {
473+
name: "Fédération",
474+
fields: {
475+
destination: "Destination",
476+
failure_ts: "Horodatage d’échec",
477+
retry_last_ts: "Horodatage de la dernière tentative",
478+
retry_interval: "Intervalle de nouvelle tentative",
479+
last_successful_stream_ordering: "Dernier flux réussi",
480+
stream_ordering: "Flux",
481+
},
482+
action: { reconnect: "Reconnecter" },
483+
},
455484
registration_tokens: {
456485
name: "Jetons d'inscription",
457486
fields: {

src/i18n/i18n-keys.test.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import de from "./de";
2+
import en from "./en";
3+
import fa from "./fa";
4+
import fr from "./fr";
5+
import itMessages from "./it";
6+
import ja from "./ja";
7+
import ru from "./ru";
8+
import uk from "./uk";
9+
import zh from "./zh";
10+
11+
const locales = {
12+
de,
13+
fa,
14+
fr,
15+
it: itMessages,
16+
ja,
17+
ru,
18+
uk,
19+
zh,
20+
};
21+
22+
const isPlainObject = (value: unknown): value is Record<string, unknown> => {
23+
return typeof value === "object" && value !== null && !Array.isArray(value);
24+
};
25+
26+
const collectKeys = (value: unknown, prefix = "", out = new Set<string>()) => {
27+
if (!isPlainObject(value)) return out;
28+
29+
for (const [key, child] of Object.entries(value)) {
30+
const next = prefix ? `${prefix}.${key}` : key;
31+
out.add(next);
32+
if (isPlainObject(child)) {
33+
collectKeys(child, next, out);
34+
}
35+
}
36+
return out;
37+
};
38+
39+
const diffKeys = (reference: Set<string>, target: Set<string>) => {
40+
const missing: string[] = [];
41+
const extra: string[] = [];
42+
43+
for (const key of reference) {
44+
if (!target.has(key)) missing.push(key);
45+
}
46+
for (const key of target) {
47+
if (!reference.has(key)) extra.push(key);
48+
}
49+
50+
missing.sort();
51+
extra.sort();
52+
return { missing, extra };
53+
};
54+
55+
describe("i18n translation keys", () => {
56+
const referenceKeys = collectKeys(en);
57+
58+
for (const [locale, messages] of Object.entries(locales)) {
59+
it(`${locale} matches en key set`, () => {
60+
const keys = collectKeys(messages);
61+
const { missing, extra } = diffKeys(referenceKeys, keys);
62+
63+
if (missing.length || extra.length) {
64+
const parts: string[] = [];
65+
if (missing.length) {
66+
parts.push(`missing (${missing.length}): ${missing.join(", ")}`);
67+
}
68+
if (extra.length) {
69+
parts.push(`extra (${extra.length}): ${extra.join(", ")}`);
70+
}
71+
throw new Error(parts.join(" | "));
72+
}
73+
});
74+
}
75+
});

0 commit comments

Comments
 (0)