Skip to main content

bern_target_api/
texts.rs

1//! Texts every native runtime shows itself, the per-language tables of
2//! runtimes that fill Bern's named placeholders, and the conversion of
3//! those placeholders to a platform's positional format specifiers.
4
5use bern_ir::Application;
6use bern_protocol::LocalizedText;
7
8/// Strings the native runtimes show themselves, with built-in translations.
9/// Every runtime receives all of them. An argument is `%@` in the texts the
10/// SwiftUI and Compose runtimes format, which convert it to their own
11/// specifier, and a `{name}` placeholder in the texts the GTK, WinUI 3 and
12/// Web runtimes fill by name.
13pub const FRAMEWORK_TEXTS: &[(&str, &[(&str, &str)])] = &[
14    // iOS shows windows other than the primary as sheets, closed with this
15    // button, and offers to open the primary window again once it closed.
16    (
17        "bern.window.done",
18        &[
19            ("zh-Hans", "完成"),
20            ("zh-Hant", "完成"),
21            ("en", "Done"),
22            ("ja", "完了"),
23            ("ko", "완료"),
24            ("ru", "Готово"),
25            ("de", "Fertig"),
26            ("fr", "Terminé"),
27            ("es", "Listo"),
28            ("pt-BR", "Concluído"),
29            ("it", "Fine"),
30            ("tr", "Bitti"),
31            ("vi", "Xong"),
32            ("pl", "Gotowe"),
33            ("uk", "Готово"),
34            ("id", "Selesai"),
35        ],
36    ),
37    (
38        "bern.window.open",
39        &[
40            ("zh-Hans", "打开“%@”"),
41            ("zh-Hant", "打開「%@」"),
42            ("en", "Open “%@”"),
43            ("ja", "“%@”を開く"),
44            ("ko", "‘%@’ 열기"),
45            ("ru", "Открыть «%@»"),
46            ("de", "„%@“ öffnen"),
47            ("fr", "Ouvrir « %@ »"),
48            ("es", "Abrir «%@»"),
49            ("pt-BR", "Abrir “%@”"),
50            ("it", "Apri “%@”"),
51            ("tr", "“%@” aç"),
52            ("vi", "Mở “%@”"),
53            ("pl", "Otwórz „%@”"),
54            ("uk", "Відкрити «%@»"),
55            ("id", "Buka “%@”"),
56        ],
57    ),
58    (
59        "bern.window.close",
60        &[
61            ("zh-Hans", "关闭"),
62            ("zh-Hant", "關閉"),
63            ("en", "Close"),
64            ("ja", "閉じる"),
65            ("ko", "닫기"),
66            ("ru", "Закрыть"),
67            ("de", "Schließen"),
68            ("fr", "Fermer"),
69            ("es", "Cerrar"),
70            ("pt-BR", "Fechar"),
71            ("it", "Chiudi"),
72            ("tr", "Kapat"),
73            ("vi", "Đóng"),
74            ("pl", "Zamknij"),
75            ("uk", "Закрити"),
76            ("id", "Tutup"),
77        ],
78    ),
79    (
80        "bern.window.minimize",
81        &[
82            ("zh-Hans", "最小化"),
83            ("zh-Hant", "最小化"),
84            ("en", "Minimize"),
85            ("ja", "しまう"),
86            ("ko", "최소화"),
87            ("ru", "Свернуть"),
88            ("de", "Minimieren"),
89            ("fr", "Réduire"),
90            ("es", "Minimizar"),
91            ("pt-BR", "Minimizar"),
92            ("it", "Riduci a icona"),
93            ("tr", "Küçült"),
94            ("vi", "Thu nhỏ"),
95            ("pl", "Minimalizuj"),
96            ("uk", "Згорнути"),
97            ("id", "Minimalkan"),
98        ],
99    ),
100    (
101        "bern.window.maximize",
102        &[
103            ("zh-Hans", "最大化"),
104            ("zh-Hant", "最大化"),
105            ("en", "Maximize"),
106            ("ja", "拡大"),
107            ("ko", "최대화"),
108            ("ru", "Развернуть"),
109            ("de", "Maximieren"),
110            ("fr", "Agrandir"),
111            ("es", "Maximizar"),
112            ("pt-BR", "Maximizar"),
113            ("it", "Ingrandisci"),
114            ("tr", "Büyüt"),
115            ("vi", "Phóng to"),
116            ("pl", "Maksymalizuj"),
117            ("uk", "Розгорнути"),
118            ("id", "Maksimalkan"),
119        ],
120    ),
121    (
122        "bern.window.restore",
123        &[
124            ("zh-Hans", "恢复"),
125            ("zh-Hant", "恢復"),
126            ("en", "Restore"),
127            ("ja", "元のサイズに戻す"),
128            ("ko", "복원"),
129            ("ru", "Восстановить"),
130            ("de", "Wiederherstellen"),
131            ("fr", "Restaurer"),
132            ("es", "Restaurar"),
133            ("pt-BR", "Restaurar"),
134            ("it", "Ripristina"),
135            ("tr", "Geri yükle"),
136            ("vi", "Khôi phục"),
137            ("pl", "Przywróć"),
138            ("uk", "Відновити"),
139            ("id", "Pulihkan"),
140        ],
141    ),
142    (
143        "bern.window.switcher",
144        &[
145            ("zh-Hans", "窗口"),
146            ("zh-Hant", "視窗"),
147            ("en", "Windows"),
148            ("ja", "ウインドウ"),
149            ("ko", "창"),
150            ("ru", "Окна"),
151            ("de", "Fenster"),
152            ("fr", "Fenêtres"),
153            ("es", "Ventanas"),
154            ("pt-BR", "Janelas"),
155            ("it", "Finestre"),
156            ("tr", "Pencereler"),
157            ("vi", "Cửa sổ"),
158            ("pl", "Okna"),
159            ("uk", "Вікна"),
160            ("id", "Jendela"),
161        ],
162    ),
163    (
164        "bern.window.reopen",
165        &[
166            ("zh-Hans", "打开“{title}”"),
167            ("zh-Hant", "打開「{title}」"),
168            ("en", "Open {title}"),
169            ("ja", "「{title}」を開く"),
170            ("ko", "{title} 열기"),
171            ("ru", "Открыть {title}"),
172            ("de", "{title} öffnen"),
173            ("fr", "Ouvrir {title}"),
174            ("es", "Abrir {title}"),
175            ("pt-BR", "Abrir {title}"),
176            ("it", "Apri {title}"),
177            ("tr", "{title} aç"),
178            ("vi", "Mở {title}"),
179            ("pl", "Otwórz {title}"),
180            ("uk", "Відкрити {title}"),
181            ("id", "Buka {title}"),
182        ],
183    ),
184    // The item of the `StatusItem`'s menu that `login_item` adds: whether
185    // the system starts the application when the user logs in.
186    (
187        "bern.app.open_at_login",
188        &[
189            ("zh-Hans", "登录时启动"),
190            ("zh-Hant", "登入時啟動"),
191            ("en", "Open at Login"),
192            ("ja", "ログイン時に開く"),
193            ("ko", "로그인 시 열기"),
194            ("ru", "Открывать при входе"),
195            ("de", "Beim Anmelden öffnen"),
196            ("fr", "Ouvrir à l’ouverture de session"),
197            ("es", "Abrir al iniciar sesión"),
198            ("pt-BR", "Abrir ao iniciar sessão"),
199            ("it", "Apri al login"),
200            ("tr", "Oturum açılınca aç"),
201            ("vi", "Mở khi đăng nhập"),
202            ("pl", "Otwórz przy logowaniu"),
203            ("uk", "Відкривати під час входу"),
204            ("id", "Buka saat masuk"),
205        ],
206    ),
207    // The last item of the `StatusItem`'s menu.
208    (
209        "bern.app.quit",
210        &[
211            ("zh-Hans", "退出"),
212            ("zh-Hant", "結束"),
213            ("en", "Quit"),
214            ("ja", "終了"),
215            ("ko", "종료"),
216            ("ru", "Завершить"),
217            ("de", "Beenden"),
218            ("fr", "Quitter"),
219            ("es", "Salir"),
220            ("pt-BR", "Encerrar"),
221            ("it", "Esci"),
222            ("tr", "Çık"),
223            ("vi", "Thoát"),
224            ("pl", "Zakończ"),
225            ("uk", "Завершити"),
226            ("id", "Keluar"),
227        ],
228    ),
229    // The standard menus of the macOS menu bar that the GPUI runtime builds
230    // itself; `{name}` is the application's name.
231    (
232        "bern.menu.about",
233        &[
234            ("zh-Hans", "关于“{name}”"),
235            ("zh-Hant", "關於「{name}」"),
236            ("en", "About {name}"),
237            ("ja", "{name}について"),
238            ("ko", "{name}에 관하여"),
239            ("ru", "О программе «{name}»"),
240            ("de", "Über „{name}“"),
241            ("fr", "À propos de {name}"),
242            ("es", "Acerca de {name}"),
243            ("pt-BR", "Sobre o {name}"),
244            ("it", "Informazioni su {name}"),
245            ("tr", "{name} Hakkında"),
246            ("vi", "Giới thiệu về {name}"),
247            ("pl", "{name} – informacje"),
248            ("uk", "Про «{name}»"),
249            ("id", "Tentang {name}"),
250        ],
251    ),
252    (
253        "bern.menu.services",
254        &[
255            ("zh-Hans", "服务"),
256            ("zh-Hant", "服務"),
257            ("en", "Services"),
258            ("ja", "サービス"),
259            ("ko", "서비스"),
260            ("ru", "Службы"),
261            ("de", "Dienste"),
262            ("fr", "Services"),
263            ("es", "Servicios"),
264            ("pt-BR", "Serviços"),
265            ("it", "Servizi"),
266            ("tr", "Servisler"),
267            ("vi", "Dịch vụ"),
268            ("pl", "Usługi"),
269            ("uk", "Служби"),
270            ("id", "Layanan"),
271        ],
272    ),
273    (
274        "bern.menu.hide",
275        &[
276            ("zh-Hans", "隐藏“{name}”"),
277            ("zh-Hant", "隱藏「{name}」"),
278            ("en", "Hide {name}"),
279            ("ja", "{name}を非表示"),
280            ("ko", "{name} 가리기"),
281            ("ru", "Скрыть «{name}»"),
282            ("de", "„{name}“ ausblenden"),
283            ("fr", "Masquer {name}"),
284            ("es", "Ocultar {name}"),
285            ("pt-BR", "Ocultar {name}"),
286            ("it", "Nascondi {name}"),
287            ("tr", "{name} Uygulamasını Gizle"),
288            ("vi", "Ẩn {name}"),
289            ("pl", "Ukryj {name}"),
290            ("uk", "Сховати «{name}»"),
291            ("id", "Sembunyikan {name}"),
292        ],
293    ),
294    (
295        "bern.menu.hide_others",
296        &[
297            ("zh-Hans", "隐藏其他"),
298            ("zh-Hant", "隱藏其他"),
299            ("en", "Hide Others"),
300            ("ja", "ほかを非表示"),
301            ("ko", "기타 가리기"),
302            ("ru", "Скрыть остальные"),
303            ("de", "Andere ausblenden"),
304            ("fr", "Masquer les autres"),
305            ("es", "Ocultar otros"),
306            ("pt-BR", "Ocultar Outros"),
307            ("it", "Nascondi altre"),
308            ("tr", "Diğerlerini Gizle"),
309            ("vi", "Ẩn mục khác"),
310            ("pl", "Ukryj pozostałe"),
311            ("uk", "Сховати інші"),
312            ("id", "Sembunyikan Lainnya"),
313        ],
314    ),
315    (
316        "bern.menu.show_all",
317        &[
318            ("zh-Hans", "全部显示"),
319            ("zh-Hant", "顯示全部"),
320            ("en", "Show All"),
321            ("ja", "すべてを表示"),
322            ("ko", "모두 보기"),
323            ("ru", "Показать все"),
324            ("de", "Alle einblenden"),
325            ("fr", "Tout afficher"),
326            ("es", "Mostrar todo"),
327            ("pt-BR", "Mostrar Tudo"),
328            ("it", "Mostra tutte"),
329            ("tr", "Tümünü Göster"),
330            ("vi", "Hiện tất cả"),
331            ("pl", "Pokaż wszystkie"),
332            ("uk", "Показати всі"),
333            ("id", "Tampilkan Semua"),
334        ],
335    ),
336    (
337        "bern.menu.quit",
338        &[
339            ("zh-Hans", "退出“{name}”"),
340            ("zh-Hant", "結束「{name}」"),
341            ("en", "Quit {name}"),
342            ("ja", "{name}を終了"),
343            ("ko", "{name} 종료"),
344            ("ru", "Завершить «{name}»"),
345            ("de", "{name} beenden"),
346            ("fr", "Quitter {name}"),
347            ("es", "Salir de {name}"),
348            ("pt-BR", "Encerrar {name}"),
349            ("it", "Esci da {name}"),
350            ("tr", "{name} Uygulamasından Çık"),
351            ("vi", "Thoát {name}"),
352            ("pl", "Zakończ {name}"),
353            ("uk", "Завершити «{name}»"),
354            ("id", "Keluar {name}"),
355        ],
356    ),
357    (
358        "bern.menu.file",
359        &[
360            ("zh-Hans", "文件"),
361            ("zh-Hant", "檔案"),
362            ("en", "File"),
363            ("ja", "ファイル"),
364            ("ko", "파일"),
365            ("ru", "Файл"),
366            ("de", "Ablage"),
367            ("fr", "Fichier"),
368            ("es", "Archivo"),
369            ("pt-BR", "Arquivo"),
370            ("it", "File"),
371            ("tr", "Dosya"),
372            ("vi", "Tệp"),
373            ("pl", "Plik"),
374            ("uk", "Файл"),
375            ("id", "File"),
376        ],
377    ),
378    (
379        "bern.menu.edit",
380        &[
381            ("zh-Hans", "编辑"),
382            ("zh-Hant", "編輯"),
383            ("en", "Edit"),
384            ("ja", "編集"),
385            ("ko", "편집"),
386            ("ru", "Правка"),
387            ("de", "Bearbeiten"),
388            ("fr", "Édition"),
389            ("es", "Edición"),
390            ("pt-BR", "Editar"),
391            ("it", "Modifica"),
392            ("tr", "Düzen"),
393            ("vi", "Sửa"),
394            ("pl", "Edycja"),
395            ("uk", "Редагування"),
396            ("id", "Edit"),
397        ],
398    ),
399    (
400        "bern.menu.undo",
401        &[
402            ("zh-Hans", "撤销"),
403            ("zh-Hant", "還原"),
404            ("en", "Undo"),
405            ("ja", "取り消す"),
406            ("ko", "실행 취소"),
407            ("ru", "Отменить"),
408            ("de", "Widerrufen"),
409            ("fr", "Annuler"),
410            ("es", "Deshacer"),
411            ("pt-BR", "Desfazer"),
412            ("it", "Annulla"),
413            ("tr", "Geri Al"),
414            ("vi", "Hoàn tác"),
415            ("pl", "Cofnij"),
416            ("uk", "Відмінити"),
417            ("id", "Urungkan"),
418        ],
419    ),
420    (
421        "bern.menu.redo",
422        &[
423            ("zh-Hans", "重做"),
424            ("zh-Hant", "重做"),
425            ("en", "Redo"),
426            ("ja", "やり直す"),
427            ("ko", "실행 복귀"),
428            ("ru", "Повторить"),
429            ("de", "Wiederholen"),
430            ("fr", "Rétablir"),
431            ("es", "Rehacer"),
432            ("pt-BR", "Refazer"),
433            ("it", "Ripeti"),
434            ("tr", "Yinele"),
435            ("vi", "Làm lại"),
436            ("pl", "Przywróć"),
437            ("uk", "Повторити"),
438            ("id", "Ulangi"),
439        ],
440    ),
441    (
442        "bern.menu.cut",
443        &[
444            ("zh-Hans", "剪切"),
445            ("zh-Hant", "剪下"),
446            ("en", "Cut"),
447            ("ja", "カット"),
448            ("ko", "오려두기"),
449            ("ru", "Вырезать"),
450            ("de", "Ausschneiden"),
451            ("fr", "Couper"),
452            ("es", "Cortar"),
453            ("pt-BR", "Recortar"),
454            ("it", "Taglia"),
455            ("tr", "Kes"),
456            ("vi", "Cắt"),
457            ("pl", "Wytnij"),
458            ("uk", "Вирізати"),
459            ("id", "Potong"),
460        ],
461    ),
462    (
463        "bern.menu.copy",
464        &[
465            ("zh-Hans", "拷贝"),
466            ("zh-Hant", "拷貝"),
467            ("en", "Copy"),
468            ("ja", "コピー"),
469            ("ko", "복사하기"),
470            ("ru", "Скопировать"),
471            ("de", "Kopieren"),
472            ("fr", "Copier"),
473            ("es", "Copiar"),
474            ("pt-BR", "Copiar"),
475            ("it", "Copia"),
476            ("tr", "Kopyala"),
477            ("vi", "Sao chép"),
478            ("pl", "Kopiuj"),
479            ("uk", "Скопіювати"),
480            ("id", "Salin"),
481        ],
482    ),
483    (
484        "bern.menu.paste",
485        &[
486            ("zh-Hans", "粘贴"),
487            ("zh-Hant", "貼上"),
488            ("en", "Paste"),
489            ("ja", "ペースト"),
490            ("ko", "붙여넣기"),
491            ("ru", "Вставить"),
492            ("de", "Einsetzen"),
493            ("fr", "Coller"),
494            ("es", "Pegar"),
495            ("pt-BR", "Colar"),
496            ("it", "Incolla"),
497            ("tr", "Yapıştır"),
498            ("vi", "Dán"),
499            ("pl", "Wklej"),
500            ("uk", "Вставити"),
501            ("id", "Tempel"),
502        ],
503    ),
504    (
505        "bern.menu.select_all",
506        &[
507            ("zh-Hans", "全选"),
508            ("zh-Hant", "全選"),
509            ("en", "Select All"),
510            ("ja", "すべてを選択"),
511            ("ko", "전체 선택"),
512            ("ru", "Выбрать все"),
513            ("de", "Alles auswählen"),
514            ("fr", "Tout sélectionner"),
515            ("es", "Seleccionar todo"),
516            ("pt-BR", "Selecionar Tudo"),
517            ("it", "Seleziona tutto"),
518            ("tr", "Tümünü Seç"),
519            ("vi", "Chọn tất cả"),
520            ("pl", "Zaznacz wszystko"),
521            ("uk", "Вибрати все"),
522            ("id", "Pilih Semua"),
523        ],
524    ),
525    (
526        "bern.menu.zoom",
527        &[
528            ("zh-Hans", "缩放"),
529            ("zh-Hant", "縮放"),
530            ("en", "Zoom"),
531            ("ja", "拡大/縮小"),
532            ("ko", "확대/축소"),
533            ("ru", "Изменить масштаб"),
534            ("de", "Zoomen"),
535            ("fr", "Réduire/agrandir"),
536            ("es", "Zoom"),
537            ("pt-BR", "Zoom"),
538            ("it", "Ridimensiona"),
539            ("tr", "Büyüt/Küçült"),
540            ("vi", "Thu phóng"),
541            ("pl", "Powiększ"),
542            ("uk", "Масштабувати"),
543            ("id", "Zoom"),
544        ],
545    ),
546    (
547        "bern.menu.front",
548        &[
549            ("zh-Hans", "前置全部窗口"),
550            ("zh-Hant", "將此程式所有視窗移至最前"),
551            ("en", "Bring All to Front"),
552            ("ja", "すべてを手前に移動"),
553            ("ko", "모두 앞으로 가져오기"),
554            ("ru", "Все окна — на передний план"),
555            ("de", "Alle nach vorne bringen"),
556            ("fr", "Tout ramener au premier plan"),
557            ("es", "Traer todo al frente"),
558            ("pt-BR", "Trazer Todas para a Frente"),
559            ("it", "Porta tutto in primo piano"),
560            ("tr", "Tümünü Öne Getir"),
561            ("vi", "Đưa tất cả ra trước"),
562            ("pl", "Przenieś wszystko na wierzch"),
563            ("uk", "Усі вікна на передній план"),
564            ("id", "Bawa Semua ke Depan"),
565        ],
566    ),
567    (
568        "bern.menu.view",
569        &[
570            ("zh-Hans", "显示"),
571            ("zh-Hant", "顯示方式"),
572            ("en", "View"),
573            ("ja", "表示"),
574            ("ko", "보기"),
575            ("ru", "Вид"),
576            ("de", "Darstellung"),
577            ("fr", "Présentation"),
578            ("es", "Visualización"),
579            ("pt-BR", "Visualizar"),
580            ("it", "Vista"),
581            ("tr", "Görüntü"),
582            ("vi", "Xem"),
583            ("pl", "Widok"),
584            ("uk", "Вигляд"),
585            ("id", "Tampilan"),
586        ],
587    ),
588    (
589        "bern.menu.help",
590        &[
591            ("zh-Hans", "帮助"),
592            ("zh-Hant", "輔助說明"),
593            ("en", "Help"),
594            ("ja", "ヘルプ"),
595            ("ko", "도움말"),
596            ("ru", "Справка"),
597            ("de", "Hilfe"),
598            ("fr", "Aide"),
599            ("es", "Ayuda"),
600            ("pt-BR", "Ajuda"),
601            ("it", "Aiuto"),
602            ("tr", "Yardım"),
603            ("vi", "Trợ giúp"),
604            ("pl", "Pomoc"),
605            ("uk", "Довідка"),
606            ("id", "Bantuan"),
607        ],
608    ),
609    (
610        "bern.window.settings",
611        &[
612            ("zh-Hans", "设置"),
613            ("zh-Hant", "設定"),
614            ("en", "Settings"),
615            ("ja", "設定"),
616            ("ko", "설정"),
617            ("ru", "Настройки"),
618            ("de", "Einstellungen"),
619            ("fr", "Réglages"),
620            ("es", "Ajustes"),
621            ("pt-BR", "Configurações"),
622            ("it", "Impostazioni"),
623            ("tr", "Ayarlar"),
624            ("vi", "Cài đặt"),
625            ("pl", "Ustawienia"),
626            ("uk", "Налаштування"),
627            ("id", "Pengaturan"),
628        ],
629    ),
630    (
631        "bern.alert.failed",
632        &[
633            ("zh-Hans", "无法完成操作"),
634            ("zh-Hant", "無法完成操作"),
635            ("en", "The action couldn’t be completed"),
636            ("ja", "操作を完了できませんでした"),
637            ("ko", "작업을 완료할 수 없습니다"),
638            ("ru", "Не удалось выполнить действие"),
639            ("de", "Die Aktion konnte nicht abgeschlossen werden"),
640            ("fr", "L’action n’a pas pu être effectuée"),
641            ("es", "No se pudo completar la acción"),
642            ("pt-BR", "Não foi possível concluir a ação"),
643            ("it", "Impossibile completare l’azione"),
644            ("tr", "İşlem tamamlanamadı"),
645            ("vi", "Không thể hoàn tất thao tác"),
646            ("pl", "Nie udało się wykonać działania"),
647            ("uk", "Не вдалося виконати дію"),
648            ("id", "Tindakan tidak dapat diselesaikan"),
649        ],
650    ),
651    (
652        "bern.alert.ok",
653        &[
654            ("zh-Hans", "好"),
655            ("zh-Hant", "好"),
656            ("en", "OK"),
657            ("ja", "OK"),
658            ("ko", "확인"),
659            ("ru", "ОК"),
660            ("de", "OK"),
661            ("fr", "OK"),
662            ("es", "Aceptar"),
663            ("pt-BR", "OK"),
664            ("it", "OK"),
665            ("tr", "Tamam"),
666            ("vi", "OK"),
667            ("pl", "OK"),
668            ("uk", "Гаразд"),
669            ("id", "OK"),
670        ],
671    ),
672    (
673        "bern.startup.failed",
674        &[
675            ("zh-Hans", "应用未能启动"),
676            ("zh-Hant", "App 無法啟動"),
677            ("en", "The app couldn’t start"),
678            ("ja", "アプリを起動できませんでした"),
679            ("ko", "앱을 시작할 수 없습니다"),
680            ("ru", "Не удалось запустить приложение"),
681            ("de", "Die App konnte nicht gestartet werden"),
682            ("fr", "L’application n’a pas pu démarrer"),
683            ("es", "No se pudo iniciar la aplicación"),
684            ("pt-BR", "Não foi possível iniciar o aplicativo"),
685            ("it", "Impossibile avviare l’app"),
686            ("tr", "Uygulama başlatılamadı"),
687            ("vi", "Không thể khởi động ứng dụng"),
688            ("pl", "Nie udało się uruchomić aplikacji"),
689            ("uk", "Не вдалося запустити застосунок"),
690            ("id", "Aplikasi tidak dapat dimulai"),
691        ],
692    ),
693    (
694        "bern.split.more",
695        &[
696            ("zh-Hans", "更多选项"),
697            ("zh-Hant", "更多選項"),
698            ("en", "More Options"),
699            ("ja", "その他のオプション"),
700            ("ko", "추가 옵션"),
701            ("ru", "Другие параметры"),
702            ("de", "Weitere Optionen"),
703            ("fr", "Plus d’options"),
704            ("es", "Más opciones"),
705            ("pt-BR", "Mais opções"),
706            ("it", "Altre opzioni"),
707            ("tr", "Diğer seçenekler"),
708            ("vi", "Tùy chọn khác"),
709            ("pl", "Więcej opcji"),
710            ("uk", "Інші параметри"),
711            ("id", "Opsi lainnya"),
712        ],
713    ),
714    (
715        "bern.query.loading",
716        &[
717            ("zh-Hans", "正在载入…"),
718            ("zh-Hant", "正在載入…"),
719            ("en", "Loading…"),
720            ("ja", "読み込み中…"),
721            ("ko", "불러오는 중…"),
722            ("ru", "Загрузка…"),
723            ("de", "Wird geladen…"),
724            ("fr", "Chargement…"),
725            ("es", "Cargando…"),
726            ("pt-BR", "Carregando…"),
727            ("it", "Caricamento…"),
728            ("tr", "Yükleniyor…"),
729            ("vi", "Đang tải…"),
730            ("pl", "Wczytywanie…"),
731            ("uk", "Завантаження…"),
732            ("id", "Memuat…"),
733        ],
734    ),
735    (
736        "bern.query.failed",
737        &[
738            ("zh-Hans", "无法载入"),
739            ("zh-Hant", "無法載入"),
740            ("en", "Couldn’t Load"),
741            ("ja", "読み込めませんでした"),
742            ("ko", "불러올 수 없음"),
743            ("ru", "Не удалось загрузить"),
744            ("de", "Laden fehlgeschlagen"),
745            ("fr", "Chargement impossible"),
746            ("es", "No se pudo cargar"),
747            ("pt-BR", "Não foi possível carregar"),
748            ("it", "Impossibile caricare"),
749            ("tr", "Yüklenemedi"),
750            ("vi", "Không thể tải"),
751            ("pl", "Nie udało się wczytać"),
752            ("uk", "Не вдалося завантажити"),
753            ("id", "Tidak dapat memuat"),
754        ],
755    ),
756    (
757        "bern.query.retry",
758        &[
759            ("zh-Hans", "重试"),
760            ("zh-Hant", "重試"),
761            ("en", "Try Again"),
762            ("ja", "再試行"),
763            ("ko", "다시 시도"),
764            ("ru", "Повторить"),
765            ("de", "Erneut versuchen"),
766            ("fr", "Réessayer"),
767            ("es", "Reintentar"),
768            ("pt-BR", "Tentar novamente"),
769            ("it", "Riprova"),
770            ("tr", "Yeniden dene"),
771            ("vi", "Thử lại"),
772            ("pl", "Spróbuj ponownie"),
773            ("uk", "Спробувати ще раз"),
774            ("id", "Coba lagi"),
775        ],
776    ),
777    (
778        "bern.media.video",
779        &[
780            ("zh-Hans", "视频"),
781            ("zh-Hant", "影片"),
782            ("en", "Video"),
783            ("ja", "ビデオ"),
784            ("ko", "동영상"),
785            ("ru", "Видео"),
786            ("de", "Video"),
787            ("fr", "Vidéo"),
788            ("es", "Vídeo"),
789            ("pt-BR", "Vídeo"),
790            ("it", "Video"),
791            ("tr", "Video"),
792            ("vi", "Video"),
793            ("pl", "Wideo"),
794            ("uk", "Відео"),
795            ("id", "Video"),
796        ],
797    ),
798    (
799        "bern.media.play",
800        &[
801            ("zh-Hans", "播放"),
802            ("zh-Hant", "播放"),
803            ("en", "Play"),
804            ("ja", "再生"),
805            ("ko", "재생"),
806            ("ru", "Воспроизвести"),
807            ("de", "Wiedergeben"),
808            ("fr", "Lire"),
809            ("es", "Reproducir"),
810            ("pt-BR", "Reproduzir"),
811            ("it", "Riproduci"),
812            ("tr", "Oynat"),
813            ("vi", "Phát"),
814            ("pl", "Odtwórz"),
815            ("uk", "Відтворити"),
816            ("id", "Putar"),
817        ],
818    ),
819    (
820        "bern.media.pause",
821        &[
822            ("zh-Hans", "暂停"),
823            ("zh-Hant", "暫停"),
824            ("en", "Pause"),
825            ("ja", "一時停止"),
826            ("ko", "일시 정지"),
827            ("ru", "Пауза"),
828            ("de", "Pause"),
829            ("fr", "Pause"),
830            ("es", "Pausa"),
831            ("pt-BR", "Pausar"),
832            ("it", "Pausa"),
833            ("tr", "Duraklat"),
834            ("vi", "Tạm dừng"),
835            ("pl", "Pauza"),
836            ("uk", "Пауза"),
837            ("id", "Jeda"),
838        ],
839    ),
840    (
841        "bern.media.mute",
842        &[
843            ("zh-Hans", "静音"),
844            ("zh-Hant", "靜音"),
845            ("en", "Mute"),
846            ("ja", "消音"),
847            ("ko", "음소거"),
848            ("ru", "Выключить звук"),
849            ("de", "Stummschalten"),
850            ("fr", "Couper le son"),
851            ("es", "Silenciar"),
852            ("pt-BR", "Silenciar"),
853            ("it", "Disattiva audio"),
854            ("tr", "Sesi kapat"),
855            ("vi", "Tắt tiếng"),
856            ("pl", "Wycisz"),
857            ("uk", "Вимкнути звук"),
858            ("id", "Bisukan"),
859        ],
860    ),
861    (
862        "bern.media.unmute",
863        &[
864            ("zh-Hans", "取消静音"),
865            ("zh-Hant", "取消靜音"),
866            ("en", "Unmute"),
867            ("ja", "消音を解除"),
868            ("ko", "음소거 해제"),
869            ("ru", "Включить звук"),
870            ("de", "Ton einschalten"),
871            ("fr", "Rétablir le son"),
872            ("es", "Activar sonido"),
873            ("pt-BR", "Ativar som"),
874            ("it", "Attiva audio"),
875            ("tr", "Sesi aç"),
876            ("vi", "Bật tiếng"),
877            ("pl", "Włącz dźwięk"),
878            ("uk", "Увімкнути звук"),
879            ("id", "Aktifkan suara"),
880        ],
881    ),
882    (
883        "bern.media.position",
884        &[
885            ("zh-Hans", "播放位置"),
886            ("zh-Hant", "播放位置"),
887            ("en", "Playback Position"),
888            ("ja", "再生位置"),
889            ("ko", "재생 위치"),
890            ("ru", "Позиция воспроизведения"),
891            ("de", "Wiedergabeposition"),
892            ("fr", "Position de lecture"),
893            ("es", "Posición de reproducción"),
894            ("pt-BR", "Posição de reprodução"),
895            ("it", "Posizione di riproduzione"),
896            ("tr", "Oynatma konumu"),
897            ("vi", "Vị trí phát"),
898            ("pl", "Pozycja odtwarzania"),
899            ("uk", "Позиція відтворення"),
900            ("id", "Posisi pemutaran"),
901        ],
902    ),
903    (
904        "bern.media.volume",
905        &[
906            ("zh-Hans", "音量"),
907            ("zh-Hant", "音量"),
908            ("en", "Volume"),
909            ("ja", "音量"),
910            ("ko", "음량"),
911            ("ru", "Громкость"),
912            ("de", "Lautstärke"),
913            ("fr", "Volume"),
914            ("es", "Volumen"),
915            ("pt-BR", "Volume"),
916            ("it", "Volume"),
917            ("tr", "Ses düzeyi"),
918            ("vi", "Âm lượng"),
919            ("pl", "Głośność"),
920            ("uk", "Гучність"),
921            ("id", "Volume"),
922        ],
923    ),
924    (
925        "bern.media.live",
926        &[
927            ("zh-Hans", "直播"),
928            ("zh-Hant", "直播"),
929            ("en", "Live"),
930            ("ja", "ライブ"),
931            ("ko", "실시간"),
932            ("ru", "Прямой эфир"),
933            ("de", "Live"),
934            ("fr", "En direct"),
935            ("es", "En directo"),
936            ("pt-BR", "Ao vivo"),
937            ("it", "In diretta"),
938            ("tr", "Canlı"),
939            ("vi", "Trực tiếp"),
940            ("pl", "Na żywo"),
941            ("uk", "Наживо"),
942            ("id", "Langsung"),
943        ],
944    ),
945    (
946        "bern.media.empty",
947        &[
948            ("zh-Hans", "没有视频"),
949            ("zh-Hant", "沒有影片"),
950            ("en", "No Video"),
951            ("ja", "ビデオがありません"),
952            ("ko", "동영상 없음"),
953            ("ru", "Нет видео"),
954            ("de", "Kein Video"),
955            ("fr", "Aucune vidéo"),
956            ("es", "Sin vídeo"),
957            ("pt-BR", "Nenhum vídeo"),
958            ("it", "Nessun video"),
959            ("tr", "Video yok"),
960            ("vi", "Không có video"),
961            ("pl", "Brak wideo"),
962            ("uk", "Немає відео"),
963            ("id", "Tidak ada video"),
964        ],
965    ),
966    (
967        "bern.media.failed",
968        &[
969            ("zh-Hans", "无法播放"),
970            ("zh-Hant", "無法播放"),
971            ("en", "Can’t Play"),
972            ("ja", "再生できません"),
973            ("ko", "재생할 수 없음"),
974            ("ru", "Не удалось воспроизвести"),
975            ("de", "Wiedergabe nicht möglich"),
976            ("fr", "Lecture impossible"),
977            ("es", "No se puede reproducir"),
978            ("pt-BR", "Não foi possível reproduzir"),
979            ("it", "Impossibile riprodurre"),
980            ("tr", "Oynatılamıyor"),
981            ("vi", "Không thể phát"),
982            ("pl", "Nie można odtworzyć"),
983            ("uk", "Не вдалося відтворити"),
984            ("id", "Tidak dapat memutar"),
985        ],
986    ),
987    (
988        "bern.media.unavailable",
989        &[
990            ("zh-Hans", "播放器不可用"),
991            ("zh-Hant", "播放器無法使用"),
992            ("en", "Player Unavailable"),
993            ("ja", "プレーヤーを使用できません"),
994            ("ko", "플레이어를 사용할 수 없음"),
995            ("ru", "Плеер недоступен"),
996            ("de", "Player nicht verfügbar"),
997            ("fr", "Lecteur indisponible"),
998            ("es", "Reproductor no disponible"),
999            ("pt-BR", "Reprodutor indisponível"),
1000            ("it", "Lettore non disponibile"),
1001            ("tr", "Oynatıcı kullanılamıyor"),
1002            ("vi", "Trình phát không khả dụng"),
1003            ("pl", "Odtwarzacz niedostępny"),
1004            ("uk", "Програвач недоступний"),
1005            ("id", "Pemutar tidak tersedia"),
1006        ],
1007    ),
1008    (
1009        "bern.close.save",
1010        &[
1011            ("zh-Hans", "存储"),
1012            ("zh-Hant", "儲存"),
1013            ("en", "Save"),
1014            ("ja", "保存"),
1015            ("ko", "저장"),
1016            ("ru", "Сохранить"),
1017            ("de", "Sichern"),
1018            ("fr", "Enregistrer"),
1019            ("es", "Guardar"),
1020            ("pt-BR", "Salvar"),
1021            ("it", "Salva"),
1022            ("tr", "Kaydet"),
1023            ("vi", "Lưu"),
1024            ("pl", "Zapisz"),
1025            ("uk", "Зберегти"),
1026            ("id", "Simpan"),
1027        ],
1028    ),
1029    (
1030        "bern.close.dont_save",
1031        &[
1032            ("zh-Hans", "不存储"),
1033            ("zh-Hant", "不儲存"),
1034            ("en", "Don’t Save"),
1035            ("ja", "保存しない"),
1036            ("ko", "저장 안 함"),
1037            ("ru", "Не сохранять"),
1038            ("de", "Nicht sichern"),
1039            ("fr", "Ne pas enregistrer"),
1040            ("es", "No guardar"),
1041            ("pt-BR", "Não salvar"),
1042            ("it", "Non salvare"),
1043            ("tr", "Kaydetme"),
1044            ("vi", "Không lưu"),
1045            ("pl", "Nie zapisuj"),
1046            ("uk", "Не зберігати"),
1047            ("id", "Jangan simpan"),
1048        ],
1049    ),
1050    (
1051        "bern.close.discard",
1052        &[
1053            ("zh-Hans", "放弃更改"),
1054            ("zh-Hant", "放棄變更"),
1055            ("en", "Discard Changes"),
1056            ("ja", "変更を破棄"),
1057            ("ko", "변경 사항 버리기"),
1058            ("ru", "Отменить изменения"),
1059            ("de", "Änderungen verwerfen"),
1060            ("fr", "Annuler les modifications"),
1061            ("es", "Descartar cambios"),
1062            ("pt-BR", "Descartar alterações"),
1063            ("it", "Annulla modifiche"),
1064            ("tr", "Değişiklikleri sil"),
1065            ("vi", "Hủy thay đổi"),
1066            ("pl", "Odrzuć zmiany"),
1067            ("uk", "Відкинути зміни"),
1068            ("id", "Buang perubahan"),
1069        ],
1070    ),
1071    (
1072        "bern.close.cancel",
1073        &[
1074            ("zh-Hans", "取消"),
1075            ("zh-Hant", "取消"),
1076            ("en", "Cancel"),
1077            ("ja", "キャンセル"),
1078            ("ko", "취소"),
1079            ("ru", "Отмена"),
1080            ("de", "Abbrechen"),
1081            ("fr", "Annuler"),
1082            ("es", "Cancelar"),
1083            ("pt-BR", "Cancelar"),
1084            ("it", "Annulla"),
1085            ("tr", "İptal"),
1086            ("vi", "Hủy"),
1087            ("pl", "Anuluj"),
1088            ("uk", "Скасувати"),
1089            ("id", "Batal"),
1090        ],
1091    ),
1092    (
1093        "bern.close.save_detail",
1094        &[
1095            ("zh-Hans", "如果不存储,你的更改将会丢失。"),
1096            ("zh-Hant", "如果不儲存,你的變更將會遺失。"),
1097            ("en", "Your changes will be lost if you don’t save them."),
1098            ("ja", "保存しないと、変更は失われます。"),
1099            ("ko", "저장하지 않으면 변경 사항이 사라집니다."),
1100            ("ru", "Несохранённые изменения будут потеряны."),
1101            ("de", "Nicht gesicherte Änderungen gehen verloren."),
1102            ("fr", "Les modifications non enregistrées seront perdues."),
1103            ("es", "Los cambios se perderán si no los guardas."),
1104            ("pt-BR", "As alterações serão perdidas se não forem salvas."),
1105            ("it", "Le modifiche non salvate andranno perse."),
1106            ("tr", "Kaydetmezseniz değişiklikler kaybolacak."),
1107            ("vi", "Các thay đổi sẽ bị mất nếu bạn không lưu."),
1108            ("pl", "Niezapisane zmiany zostaną utracone."),
1109            ("uk", "Незбережені зміни буде втрачено."),
1110            ("id", "Perubahan akan hilang jika tidak disimpan."),
1111        ],
1112    ),
1113    (
1114        "bern.close.discard_detail",
1115        &[
1116            ("zh-Hans", "关闭窗口会放弃这些更改。"),
1117            ("zh-Hant", "關閉視窗會放棄這些變更。"),
1118            ("en", "Closing the window discards these changes."),
1119            ("ja", "ウインドウを閉じると、これらの変更は破棄されます。"),
1120            ("ko", "창을 닫으면 변경 사항이 사라집니다."),
1121            ("ru", "Закрытие окна отменит эти изменения."),
1122            (
1123                "de",
1124                "Beim Schließen des Fensters werden diese Änderungen verworfen.",
1125            ),
1126            ("fr", "Fermer la fenêtre annule ces modifications."),
1127            ("es", "Al cerrar la ventana se descartan estos cambios."),
1128            ("pt-BR", "Fechar a janela descarta estas alterações."),
1129            (
1130                "it",
1131                "Chiudendo la finestra, queste modifiche verranno annullate.",
1132            ),
1133            ("tr", "Pencere kapatıldığında bu değişiklikler silinir."),
1134            ("vi", "Đóng cửa sổ sẽ hủy các thay đổi này."),
1135            ("pl", "Zamknięcie okna odrzuci te zmiany."),
1136            ("uk", "Закриття вікна скасує ці зміни."),
1137            ("id", "Menutup jendela akan membuang perubahan ini."),
1138        ],
1139    ),
1140    (
1141        "bern.navigation.back",
1142        &[
1143            ("zh-Hans", "返回"),
1144            ("zh-Hant", "返回"),
1145            ("en", "Back"),
1146            ("ja", "戻る"),
1147            ("ko", "뒤로"),
1148            ("ru", "Назад"),
1149            ("de", "Zurück"),
1150            ("fr", "Retour"),
1151            ("es", "Atrás"),
1152            ("pt-BR", "Voltar"),
1153            ("it", "Indietro"),
1154            ("tr", "Geri"),
1155            ("vi", "Quay lại"),
1156            ("pl", "Wstecz"),
1157            ("uk", "Назад"),
1158            ("id", "Kembali"),
1159        ],
1160    ),
1161    (
1162        "bern.navigation.sidebar",
1163        &[
1164            ("zh-Hans", "边栏"),
1165            ("zh-Hant", "側邊欄"),
1166            ("en", "Sidebar"),
1167            ("ja", "サイドバー"),
1168            ("ko", "사이드바"),
1169            ("ru", "Боковая панель"),
1170            ("de", "Seitenleiste"),
1171            ("fr", "Barre latérale"),
1172            ("es", "Barra lateral"),
1173            ("pt-BR", "Barra lateral"),
1174            ("it", "Barra laterale"),
1175            ("tr", "Kenar çubuğu"),
1176            ("vi", "Thanh bên"),
1177            ("pl", "Panel boczny"),
1178            ("uk", "Бічна панель"),
1179            ("id", "Bilah samping"),
1180        ],
1181    ),
1182    (
1183        "bern.navigation.hide_sidebar",
1184        &[
1185            ("zh-Hans", "隐藏边栏"),
1186            ("zh-Hant", "隱藏側邊欄"),
1187            ("en", "Hide Sidebar"),
1188            ("ja", "サイドバーを非表示"),
1189            ("ko", "사이드바 숨기기"),
1190            ("ru", "Скрыть боковую панель"),
1191            ("de", "Seitenleiste ausblenden"),
1192            ("fr", "Masquer la barre latérale"),
1193            ("es", "Ocultar barra lateral"),
1194            ("pt-BR", "Ocultar barra lateral"),
1195            ("it", "Nascondi barra laterale"),
1196            ("tr", "Kenar çubuğunu gizle"),
1197            ("vi", "Ẩn thanh bên"),
1198            ("pl", "Ukryj panel boczny"),
1199            ("uk", "Приховати бічну панель"),
1200            ("id", "Sembunyikan bilah samping"),
1201        ],
1202    ),
1203    (
1204        "bern.navigation.show_sidebar",
1205        &[
1206            ("zh-Hans", "显示边栏"),
1207            ("zh-Hant", "顯示側邊欄"),
1208            ("en", "Show Sidebar"),
1209            ("ja", "サイドバーを表示"),
1210            ("ko", "사이드바 표시"),
1211            ("ru", "Показать боковую панель"),
1212            ("de", "Seitenleiste einblenden"),
1213            ("fr", "Afficher la barre latérale"),
1214            ("es", "Mostrar barra lateral"),
1215            ("pt-BR", "Mostrar barra lateral"),
1216            ("it", "Mostra barra laterale"),
1217            ("tr", "Kenar çubuğunu göster"),
1218            ("vi", "Hiện thanh bên"),
1219            ("pl", "Pokaż panel boczny"),
1220            ("uk", "Показати бічну панель"),
1221            ("id", "Tampilkan bilah samping"),
1222        ],
1223    ),
1224    (
1225        "bern.runtime.missing",
1226        &[
1227            (
1228                "zh-Hans",
1229                "此应用需要 Windows App Runtime 2,这台电脑上还没有。\n\n要现在用浏览器下载微软的安装程序吗?安装完成后请重新打开此应用。",
1230            ),
1231            (
1232                "zh-Hant",
1233                "此 App 需要 Windows App Runtime 2,這台電腦上還沒有。\n\n要現在以瀏覽器下載 Microsoft 的安裝程式嗎?安裝完成後請重新開啟此 App。",
1234            ),
1235            (
1236                "en",
1237                "This app needs the Windows App Runtime 2, which this computer doesn’t have yet.\n\nDownload Microsoft’s installer in your browser now? Open the app again once it’s installed.",
1238            ),
1239            (
1240                "ja",
1241                "このアプリには Windows App Runtime 2 が必要ですが、このコンピューターにはまだありません。\n\nMicrosoft のインストーラーを今すぐブラウザーでダウンロードしますか?インストール後にアプリをもう一度開いてください。",
1242            ),
1243            (
1244                "ko",
1245                "이 앱에는 Windows App Runtime 2가 필요합니다. 브라우저에서 Microsoft 설치 프로그램을 다운로드하시겠습니까? 설치 후 앱을 다시 열어 주세요.",
1246            ),
1247            (
1248                "ru",
1249                "Приложению требуется Windows App Runtime 2. Скачать установщик Microsoft в браузере? После установки откройте приложение снова.",
1250            ),
1251            (
1252                "de",
1253                "Diese App benötigt Windows App Runtime 2. Das Installationsprogramm von Microsoft jetzt im Browser herunterladen? Öffne die App nach der Installation erneut.",
1254            ),
1255            (
1256                "fr",
1257                "Cette application nécessite Windows App Runtime 2. Télécharger le programme d’installation de Microsoft dans le navigateur ? Rouvrez l’application après l’installation.",
1258            ),
1259            (
1260                "es",
1261                "Esta aplicación necesita Windows App Runtime 2. ¿Descargar el instalador de Microsoft en el navegador? Vuelve a abrir la aplicación después de instalarlo.",
1262            ),
1263            (
1264                "pt-BR",
1265                "Este aplicativo precisa do Windows App Runtime 2. Baixar o instalador da Microsoft no navegador? Abra o aplicativo novamente após a instalação.",
1266            ),
1267            (
1268                "it",
1269                "Questa app richiede Windows App Runtime 2. Scaricare il programma di installazione Microsoft nel browser? Riapri l’app dopo l’installazione.",
1270            ),
1271            (
1272                "tr",
1273                "Bu uygulama Windows App Runtime 2 gerektirir. Microsoft yükleyicisi tarayıcıda indirilsin mi? Yükledikten sonra uygulamayı yeniden açın.",
1274            ),
1275            (
1276                "vi",
1277                "Ứng dụng này cần Windows App Runtime 2. Tải trình cài đặt của Microsoft trong trình duyệt? Mở lại ứng dụng sau khi cài đặt.",
1278            ),
1279            (
1280                "pl",
1281                "Ta aplikacja wymaga Windows App Runtime 2. Pobrać instalator Microsoft w przeglądarce? Po instalacji otwórz aplikację ponownie.",
1282            ),
1283            (
1284                "uk",
1285                "Цьому застосунку потрібен Windows App Runtime 2. Завантажити інсталятор Microsoft у браузері? Після встановлення знову відкрийте застосунок.",
1286            ),
1287            (
1288                "id",
1289                "Aplikasi ini memerlukan Windows App Runtime 2. Unduh penginstal Microsoft di browser sekarang? Buka kembali aplikasi setelah selesai menginstal.",
1290            ),
1291        ],
1292    ),
1293    (
1294        "bern.search.clear",
1295        &[
1296            ("zh-Hans", "清除"),
1297            ("zh-Hant", "清除"),
1298            ("en", "Clear"),
1299            ("ja", "消去"),
1300            ("ko", "지우기"),
1301            ("ru", "Очистить"),
1302            ("de", "Löschen"),
1303            ("fr", "Effacer"),
1304            ("es", "Borrar"),
1305            ("pt-BR", "Limpar"),
1306            ("it", "Cancella"),
1307            ("tr", "Temizle"),
1308            ("vi", "Xóa"),
1309            ("pl", "Wyczyść"),
1310            ("uk", "Очистити"),
1311            ("id", "Hapus"),
1312        ],
1313    ),
1314    (
1315        "bern.link.lost",
1316        &[
1317            ("zh-Hans", "与引擎的连接已断开,正在重新连接…"),
1318            ("zh-Hant", "與引擎的連線已中斷,正在重新連線…"),
1319            ("en", "Lost the connection to the engine. Reconnecting…"),
1320            ("ja", "エンジンとの接続が切れました。再接続しています…"),
1321            ("ko", "엔진과 연결이 끊겼습니다. 다시 연결하는 중…"),
1322            ("ru", "Связь с движком потеряна. Повторное подключение…"),
1323            (
1324                "de",
1325                "Verbindung zur Engine verloren. Verbindung wird wiederhergestellt…",
1326            ),
1327            ("fr", "Connexion au moteur perdue. Reconnexion…"),
1328            ("es", "Se perdió la conexión con el motor. Reconectando…"),
1329            (
1330                "pt-BR",
1331                "A conexão com o mecanismo foi perdida. Reconectando…",
1332            ),
1333            ("it", "Connessione al motore persa. Riconnessione…"),
1334            ("tr", "Motor bağlantısı kesildi. Yeniden bağlanılıyor…"),
1335            ("vi", "Mất kết nối với bộ máy. Đang kết nối lại…"),
1336            ("pl", "Utracono połączenie z silnikiem. Ponowne łączenie…"),
1337            ("uk", "Зв’язок із рушієм втрачено. Повторне підключення…"),
1338            ("id", "Koneksi ke mesin terputus. Menghubungkan kembali…"),
1339        ],
1340    ),
1341    (
1342        "bern.link.restarted",
1343        &[
1344            ("zh-Hans", "引擎已重新启动,页面将重新载入。"),
1345            ("zh-Hant", "引擎已重新啟動,頁面將重新載入。"),
1346            ("en", "The engine restarted. Reloading the page."),
1347            ("ja", "エンジンが再起動しました。ページを再読み込みします。"),
1348            ("ko", "엔진이 다시 시작되었습니다. 페이지를 새로 고칩니다."),
1349            ("ru", "Движок перезапущен. Перезагрузка страницы."),
1350            (
1351                "de",
1352                "Die Engine wurde neu gestartet. Die Seite wird neu geladen.",
1353            ),
1354            ("fr", "Le moteur a redémarré. Rechargement de la page."),
1355            ("es", "El motor se reinició. Recargando la página."),
1356            (
1357                "pt-BR",
1358                "O mecanismo foi reiniciado. Recarregando a página.",
1359            ),
1360            (
1361                "it",
1362                "Il motore è stato riavviato. Ricaricamento della pagina.",
1363            ),
1364            ("tr", "Motor yeniden başlatıldı. Sayfa yeniden yükleniyor."),
1365            ("vi", "Bộ máy đã khởi động lại. Đang tải lại trang."),
1366            (
1367                "pl",
1368                "Silnik został uruchomiony ponownie. Ponowne wczytywanie strony.",
1369            ),
1370            ("uk", "Рушій перезапущено. Перезавантаження сторінки."),
1371            ("id", "Mesin dimulai ulang. Memuat ulang halaman."),
1372        ],
1373    ),
1374    (
1375        "bern.link.failed",
1376        &[
1377            ("zh-Hans", "无法连接到引擎"),
1378            ("zh-Hant", "無法連線到引擎"),
1379            ("en", "Can’t Connect to the Engine"),
1380            ("ja", "エンジンに接続できません"),
1381            ("ko", "엔진에 연결할 수 없음"),
1382            ("ru", "Не удалось подключиться к движку"),
1383            ("de", "Verbindung zur Engine nicht möglich"),
1384            ("fr", "Connexion au moteur impossible"),
1385            ("es", "No se puede conectar con el motor"),
1386            ("pt-BR", "Não foi possível conectar ao mecanismo"),
1387            ("it", "Impossibile connettersi al motore"),
1388            ("tr", "Motora bağlanılamıyor"),
1389            ("vi", "Không thể kết nối với bộ máy"),
1390            ("pl", "Nie można połączyć się z silnikiem"),
1391            ("uk", "Не вдалося підключитися до рушія"),
1392            ("id", "Tidak dapat terhubung ke mesin"),
1393        ],
1394    ),
1395    // How a `ShortcutInput` and a menu write the space bar, and what a
1396    // `ShortcutInput` shows while it waits for a key and without a shortcut.
1397    (
1398        "bern.shortcut.space",
1399        &[
1400            ("zh-Hans", "空格"),
1401            ("zh-Hant", "空白鍵"),
1402            ("en", "Space"),
1403            ("ja", "スペース"),
1404            ("ko", "스페이스"),
1405            ("ru", "Пробел"),
1406            ("de", "Leertaste"),
1407            ("fr", "Espace"),
1408            ("es", "Espacio"),
1409            ("pt-BR", "Espaço"),
1410            ("it", "Spazio"),
1411            ("tr", "Boşluk"),
1412            ("vi", "Dấu cách"),
1413            ("pl", "Spacja"),
1414            ("uk", "Пробіл"),
1415            ("id", "Spasi"),
1416        ],
1417    ),
1418    (
1419        "bern.shortcut.prompt",
1420        &[
1421            ("zh-Hans", "按下快捷键…"),
1422            ("zh-Hant", "按下快速鍵…"),
1423            ("en", "Press a Shortcut…"),
1424            ("ja", "ショートカットを押してください…"),
1425            ("ko", "단축키를 누르세요…"),
1426            ("ru", "Нажмите сочетание…"),
1427            ("de", "Kurzbefehl drücken …"),
1428            ("fr", "Appuyez sur un raccourci…"),
1429            ("es", "Pulsa un atajo…"),
1430            ("pt-BR", "Pressione um atalho…"),
1431            ("it", "Premi una scorciatoia…"),
1432            ("tr", "Bir kısayola basın…"),
1433            ("vi", "Nhấn phím tắt…"),
1434            ("pl", "Naciśnij skrót…"),
1435            ("uk", "Натисніть сполучення…"),
1436            ("id", "Tekan pintasan…"),
1437        ],
1438    ),
1439    (
1440        "bern.shortcut.none",
1441        &[
1442            ("zh-Hans", "无"),
1443            ("zh-Hant", "無"),
1444            ("en", "None"),
1445            ("ja", "なし"),
1446            ("ko", "없음"),
1447            ("ru", "Нет"),
1448            ("de", "Keiner"),
1449            ("fr", "Aucun"),
1450            ("es", "Ninguno"),
1451            ("pt-BR", "Nenhum"),
1452            ("it", "Nessuno"),
1453            ("tr", "Yok"),
1454            ("vi", "Không có"),
1455            ("pl", "Brak"),
1456            ("uk", "Немає"),
1457            ("id", "Tidak ada"),
1458        ],
1459    ),
1460];
1461
1462/// Languages the runtime's own strings are translated into.
1463pub fn framework_languages() -> Vec<&'static str> {
1464    FRAMEWORK_TEXTS[0]
1465        .1
1466        .iter()
1467        .map(|(language, _)| *language)
1468        .collect()
1469}
1470
1471/// Convert Bern placeholders to positional format specifiers made by
1472/// `specifier` from the 1-based position, escaping `%` as `%%`. Texts
1473/// without parameters are not formatted, so only their braces are
1474/// unescaped.
1475pub fn positional(text: &str, params: &[String], specifier: impl Fn(usize) -> String) -> String {
1476    if params.is_empty() {
1477        return unescape_braces(text);
1478    }
1479    let mut out = String::new();
1480    let mut chars = text.chars().peekable();
1481    while let Some(c) = chars.next() {
1482        match c {
1483            '{' if chars.peek() == Some(&'{') => {
1484                chars.next();
1485                out.push('{');
1486            }
1487            '}' if chars.peek() == Some(&'}') => {
1488                chars.next();
1489                out.push('}');
1490            }
1491            '{' => {
1492                let mut name = String::new();
1493                for next in chars.by_ref() {
1494                    if next == '}' {
1495                        break;
1496                    }
1497                    name.push(next);
1498                }
1499                let position = params.iter().position(|param| *param == name).unwrap_or(0) + 1;
1500                out.push_str(&specifier(position));
1501            }
1502            '%' => out.push_str("%%"),
1503            c => out.push(c),
1504        }
1505    }
1506    out
1507}
1508
1509/// The text in `language`, else in the default language, else any.
1510pub fn translation<'a>(text: &'a LocalizedText, language: &str, default: &str) -> &'a str {
1511    text.get(language)
1512        .or_else(|| text.get(default))
1513        .or_else(|| text.translations.values().next().map(String::as_str))
1514        .unwrap_or("")
1515}
1516
1517/// A framework text in `language`, else in English.
1518pub fn framework(translations: &[(&str, &'static str)], language: &str) -> &'static str {
1519    translations
1520        .iter()
1521        .find(|(candidate, _)| *candidate == language)
1522        .or_else(|| {
1523            translations
1524                .iter()
1525                .find(|(candidate, _)| *candidate == "en")
1526        })
1527        .map(|(_, value)| *value)
1528        .unwrap_or("")
1529}
1530
1531/// A text without parameters as it is shown: `{{` and `}}` stand for one
1532/// brace, and nothing is filled in at run time.
1533pub fn unescape_braces(text: &str) -> String {
1534    text.replace("{{", "{").replace("}}", "}")
1535}
1536
1537/// `(language, [(key, text)])` for every supported language, for the
1538/// runtimes that fill Bern's placeholders by name: the declared texts, the
1539/// application's name as `app.name`, the framework texts, and the weekday
1540/// and month names, which fall back to English in a language Bern has none
1541/// for. Texts with parameters keep their format and escapes for the
1542/// runtime; the others are stored as they are shown.
1543pub fn tables(app: &Application) -> Vec<(String, Vec<(String, String)>)> {
1544    let default = &app.languages.default;
1545    app.languages
1546        .supported
1547        .iter()
1548        .map(|language| {
1549            let mut table: Vec<(String, String)> = app
1550                .texts
1551                .iter()
1552                .map(|text| {
1553                    let value = translation(text, language, default);
1554                    let value = if text.params.is_empty() {
1555                        unescape_braces(value)
1556                    } else {
1557                        value.to_string()
1558                    };
1559                    (text.key.clone(), value)
1560                })
1561                .collect();
1562            let name = app
1563                .app
1564                .name
1565                .get(language)
1566                .or_else(|| app.app.name.get(default))
1567                .unwrap_or(&app.app.id);
1568            table.push(("app.name".into(), name.to_string()));
1569            for (key, translations) in FRAMEWORK_TEXTS {
1570                table.push(((*key).into(), framework(translations, language).into()));
1571            }
1572            for (key, translations) in bern_protocol::format::date_names() {
1573                let value = translations
1574                    .iter()
1575                    .find(|(candidate, _)| candidate == language)
1576                    .or_else(|| {
1577                        translations
1578                            .iter()
1579                            .find(|(candidate, _)| *candidate == "en")
1580                    })
1581                    .map(|(_, value)| value.clone())
1582                    .unwrap_or_default();
1583                table.push((key, value));
1584            }
1585            (language.clone(), table)
1586        })
1587        .collect()
1588}
1589
1590#[cfg(test)]
1591pub(crate) mod tests {
1592    use super::*;
1593    use bern_ir::{AppInfo, Languages, Theme, ThemeMode, WindowCatalog};
1594    use bern_protocol::{ProtocolDescriptor, TypeTable};
1595    use std::path::Path;
1596
1597    fn text(key: &str, value: &str, params: &[&str]) -> LocalizedText {
1598        LocalizedText {
1599            key: key.into(),
1600            translations: [("en".to_string(), value.to_string())].into(),
1601            params: params.iter().map(|param| param.to_string()).collect(),
1602        }
1603    }
1604
1605    pub(crate) fn app(texts: Vec<LocalizedText>) -> Application {
1606        Application {
1607            ir_version: bern_ir::IR_VERSION,
1608            app: AppInfo {
1609                id: "test".into(),
1610                bundle_id: "test.app".into(),
1611                name: LocalizedText::default(),
1612                version: "1".into(),
1613                icon: None,
1614                platform_icons: Default::default(),
1615                alternate_icons: Default::default(),
1616                publisher: None,
1617                files_folder: false,
1618                background_audio: false,
1619                overlays: false,
1620            },
1621            languages: Languages {
1622                supported: vec!["en".into()],
1623                default: "en".into(),
1624                strict: true,
1625            },
1626            theme: Theme {
1627                mode: ThemeMode::System,
1628                brand_seed: None,
1629            },
1630            protocol: ProtocolDescriptor {
1631                descriptor_version: 1,
1632                namespace: "test".into(),
1633                version: 1,
1634                types: TypeTable::default(),
1635                state: vec![],
1636                commands: vec![],
1637                events: vec![],
1638                modules: vec![],
1639            },
1640            types: TypeTable::default(),
1641            sessions: vec![],
1642            windows: WindowCatalog {
1643                handle: "Windows".into(),
1644                primary: "main".into(),
1645                windows: vec![],
1646                accent: None,
1647                palette: None,
1648                appearance: None,
1649                icon: None,
1650                menu_bar: None,
1651                status_item: None,
1652            },
1653            players: vec![],
1654            components: vec![],
1655            texts,
1656            resources: vec![],
1657            layouts: None,
1658            contracts: vec![],
1659            style: Default::default(),
1660        }
1661    }
1662
1663    #[test]
1664    fn every_framework_text_has_every_framework_language_once() {
1665        let mut languages = framework_languages();
1666        languages.sort_unstable();
1667        let mut keys = Vec::new();
1668        for (key, translations) in FRAMEWORK_TEXTS {
1669            let mut found: Vec<_> = translations.iter().map(|(language, _)| *language).collect();
1670            found.sort_unstable();
1671            assert_eq!(found, languages, "{key}");
1672            assert!(!keys.contains(key), "{key} is defined twice");
1673            keys.push(*key);
1674        }
1675    }
1676
1677    /// Every `"bern.…"` key the runtimes and generators show is defined, so
1678    /// a new runtime text cannot ship without its translations.
1679    #[test]
1680    fn every_text_a_runtime_shows_is_defined() {
1681        let crates = Path::new(env!("CARGO_MANIFEST_DIR")).join("..");
1682        let mut dirs = vec![crates.join("bern-gtk/src")];
1683        for backend in ["swiftui", "compose", "gtk", "winui3", "web"] {
1684            let backend = crates.join(format!("bern-backend-{backend}"));
1685            dirs.push(backend.join("src"));
1686            dirs.push(backend.join("templates"));
1687        }
1688        let mut used = Vec::new();
1689        // Not every backend has templates of its own.
1690        while let Some(dir) = dirs.pop() {
1691            let Ok(entries) = std::fs::read_dir(&dir) else {
1692                continue;
1693            };
1694            for entry in entries {
1695                let path = entry.unwrap().path();
1696                if path.is_dir() {
1697                    dirs.push(path);
1698                    continue;
1699                }
1700                let Ok(source) = std::fs::read_to_string(&path) else {
1701                    continue;
1702                };
1703                for (start, _) in source.match_indices("\"bern.") {
1704                    let key: String = source[start + 1..]
1705                        .chars()
1706                        .take_while(|c| c.is_ascii_lowercase() || *c == '_' || *c == '.')
1707                        .collect();
1708                    let quoted = source[start + 1 + key.len()..].starts_with(['"', '\\']);
1709                    if quoted && key.matches('.').count() >= 2 {
1710                        used.push((key, path.clone()));
1711                    }
1712                }
1713            }
1714        }
1715        assert!(
1716            used.len() > FRAMEWORK_TEXTS.len(),
1717            "the sources were not found"
1718        );
1719        let mut defined: Vec<String> = FRAMEWORK_TEXTS
1720            .iter()
1721            .map(|(key, _)| (*key).to_string())
1722            .collect();
1723        defined.extend(
1724            bern_protocol::format::date_names()
1725                .into_iter()
1726                .map(|(key, _)| key),
1727        );
1728        for (key, path) in used {
1729            // A key ending in `.` is the start of keys the runtime completes
1730            // as it runs, such as `bern.date.month.` and the month's number.
1731            let found = match key.strip_suffix('.') {
1732                Some(_) => defined.iter().any(|defined| defined.starts_with(&key)),
1733                None => defined.contains(&key),
1734            };
1735            assert!(
1736                found,
1737                "{} shows `{key}`, which neither FRAMEWORK_TEXTS nor the date names define",
1738                path.display()
1739            );
1740        }
1741    }
1742
1743    #[test]
1744    fn tables_store_texts_without_parameters_as_shown() {
1745        let app = app(vec![
1746            text("plain", "Use {{x}} and }}", &[]),
1747            text("filled", "{n} of {{all}}", &["n"]),
1748        ]);
1749        let tables = tables(&app);
1750        assert_eq!(tables.len(), 1);
1751        let (language, table) = &tables[0];
1752        assert_eq!(language, "en");
1753        let get = |key: &str| {
1754            table
1755                .iter()
1756                .find(|(candidate, _)| candidate == key)
1757                .map(|(_, value)| value.as_str())
1758        };
1759        assert_eq!(get("plain"), Some("Use {x} and }"));
1760        // The runtime fills the placeholders and resolves the escapes.
1761        assert_eq!(get("filled"), Some("{n} of {{all}}"));
1762        // Without a translated name, the application id stands in.
1763        assert_eq!(get("app.name"), Some("test"));
1764        assert_eq!(get("bern.media.empty"), Some("No Video"));
1765        assert_eq!(
1766            table.len(),
1767            3 + FRAMEWORK_TEXTS.len() + bern_protocol::format::date_names().len()
1768        );
1769    }
1770
1771    #[test]
1772    fn positional_specifiers_and_escapes() {
1773        let params = ["name".to_string(), "count".to_string()];
1774        assert_eq!(
1775            positional("{count} for {name}, 100% {{sure}}", &params, |n| format!(
1776                "%{n}$s"
1777            )),
1778            "%2$s for %1$s, 100%% {sure}"
1779        );
1780        assert_eq!(
1781            positional("100% {{sure}}", &[], |_| unreachable!()),
1782            "100% {sure}"
1783        );
1784    }
1785}