diff --git a/Cargo.lock b/Cargo.lock index f4e2afe..608e9a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -140,6 +140,15 @@ dependencies = [ "x11rb", ] +[[package]] +name = "arc-swap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" +dependencies = [ + "rustversion", +] + [[package]] name = "arrayvec" version = "0.7.6" @@ -309,6 +318,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "base62" +version = "2.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd637ac531c60eb7fbc4684dc061c2d7d90d73d758181aa02eeff0464b9eee4b" + [[package]] name = "bindgen" version = "0.72.1" @@ -1514,6 +1529,30 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "globset" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "globwalk" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" +dependencies = [ + "bitflags 1.3.2", + "ignore", + "walkdir", +] + [[package]] name = "glow" version = "0.17.0" @@ -1773,6 +1812,22 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "ignore" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + [[package]] name = "image" version = "0.25.10" @@ -1832,6 +1887,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.13.0" @@ -3053,7 +3117,7 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit", + "toml_edit 0.25.11+spec-1.1.0", ] [[package]] @@ -3112,8 +3176,10 @@ dependencies = [ "pipewire", "rfd", "rodio", + "rust-i18n", "serde", "serde_json", + "sys-locale", "system-fonts", "tokio", ] @@ -3339,6 +3405,57 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" +[[package]] +name = "rust-i18n" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21031bf5e6f2c0ae745d831791c403608e99a8bd3776c7e5e5535acd70c3b7ba" +dependencies = [ + "globwalk", + "regex", + "rust-i18n-macro", + "rust-i18n-support", + "smallvec", +] + +[[package]] +name = "rust-i18n-macro" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51fe5295763b358606f7ca26a564e20f4469775a57ec1f09431249a33849ff52" +dependencies = [ + "glob", + "proc-macro2", + "quote", + "rust-i18n-support", + "serde", + "serde_json", + "serde_yaml", + "syn", +] + +[[package]] +name = "rust-i18n-support" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69bcc115c8eea2803aa3d85362e339776f4988a0349f2f475af572e497443f6f" +dependencies = [ + "arc-swap", + "base62", + "globwalk", + "itertools 0.11.0", + "lazy_static", + "normpath", + "proc-macro2", + "regex", + "serde", + "serde_json", + "serde_yaml", + "siphasher", + "toml 0.8.23", + "triomphe", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -3392,6 +3509,12 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "same-file" version = "1.0.6" @@ -3479,6 +3602,15 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "serde_spanned" version = "1.1.1" @@ -3488,6 +3620,19 @@ dependencies = [ "serde_core", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "shlex" version = "1.3.0" @@ -3915,7 +4060,7 @@ dependencies = [ "cfg-expr", "heck", "pkg-config", - "toml", + "toml 1.1.2+spec-1.1.0", "version-compare", ] @@ -4061,6 +4206,18 @@ dependencies = [ "syn", ] +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + [[package]] name = "toml" version = "1.1.2+spec-1.1.0" @@ -4069,11 +4226,20 @@ checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" dependencies = [ "indexmap", "serde_core", - "serde_spanned", - "toml_datetime", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", "toml_writer", - "winnow", + "winnow 1.0.2", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", ] [[package]] @@ -4085,6 +4251,20 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.15", +] + [[package]] name = "toml_edit" version = "0.25.11+spec-1.1.0" @@ -4092,9 +4272,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" dependencies = [ "indexmap", - "toml_datetime", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", - "winnow", + "winnow 1.0.2", ] [[package]] @@ -4103,9 +4283,15 @@ version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow", + "winnow 1.0.2", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "toml_writer" version = "1.1.1+spec-1.1.0" @@ -4144,6 +4330,17 @@ dependencies = [ "once_cell", ] +[[package]] +name = "triomphe" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39" +dependencies = [ + "arc-swap", + "serde", + "stable_deref_trait", +] + [[package]] name = "ttf-parser" version = "0.25.1" @@ -4203,6 +4400,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "url" version = "2.5.8" @@ -5085,6 +5288,15 @@ dependencies = [ "xkbcommon-dl", ] +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + [[package]] name = "winnow" version = "1.0.2" @@ -5318,7 +5530,7 @@ dependencies = [ "uds_windows", "uuid", "windows-sys 0.61.2", - "winnow", + "winnow 1.0.2", "zbus_macros", "zbus_names", "zvariant", @@ -5346,7 +5558,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7074f3e50b894eac91750142016d30d0a89be8e67dbfd9704fb875825760e52d" dependencies = [ "serde", - "winnow", + "winnow 1.0.2", "zvariant", ] @@ -5483,7 +5695,7 @@ dependencies = [ "enumflags2", "serde", "url", - "winnow", + "winnow 1.0.2", "zvariant_derive", "zvariant_utils", ] @@ -5511,5 +5723,5 @@ dependencies = [ "quote", "serde", "syn", - "winnow", + "winnow 1.0.2", ] diff --git a/Cargo.toml b/Cargo.toml index 511b3a2..4a5883e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,22 +26,28 @@ clap = { version = "4.6.1", default-features = false, features = [ "error-context", "derive", ] } + dirs = "6.0.0" itertools = "0.14.0" +evdev = { version = "0.13.2", features = ["tokio"] } +rfd = { version = "0.17.2", default-features = false, features = [ + + "xdg-portal", + +] } +opener = { version = "0.8.4", features = ["reveal"] } +system-fonts = "0.1.0" anyhow = "1.0.102" +rust-i18n = "4.0.0" +sys-locale = "0.3.2" + rodio = { git = "https://github.com/arabianq/rodio.git", rev = "1a08f281c352622bd82b87b8731585245802d9cf", default-features = false, features = [ "symphonia-all", "symphonia-libopus", "playback", ] } pipewire = "0.9.2" -evdev = { version = "0.13.2", features = ["tokio"] } -rfd = { version = "0.17.2", default-features = false, features = [ - "xdg-portal", -] } -opener = { version = "0.8.4", features = ["reveal"] } -system-fonts = "0.1.0" egui = { version = "0.34.2", default-features = false, features = [ "default_fonts", diff --git a/locales/app.toml b/locales/app.toml new file mode 100644 index 0000000..e588665 --- /dev/null +++ b/locales/app.toml @@ -0,0 +1,277 @@ +_version = 2 + +# ---------------- +# Main page +# ---------------- + +[gui.play_file_button] +en = "Play file" +ru = "Выбрать файл" +es = "Reproducir archivo" +fr = "Lire le fichier" +zh = "播放文件" +ar = "تشغيل الملف" + +[gui.choose_mic_select] +en = "Select microphone" +ru = "Выбрать микрофон" +es = "Seleccionar micrófono" +fr = "Sélectionner le microphone" +zh = "选择麦克风" +ar = "اختر الميكروفون" + +[gui.search_placeholder] +en = "Search files..." +ru = "Поиск файлов..." +es = "Buscar archivos..." +fr = "Rechercher des fichiers..." +zh = "搜索文件..." +ar = "البحث عن ملفات..." + +[gui.context.dirs.open] +en = "Open" +ru = "Открыть" +es = "Abrir" +fr = "Ouvrir" +zh = "打开" +ar = "فتح" + +[gui.context.dirs.open_in_fm] +en = "Open in File Manager" +ru = "Открыть в менеджере файлов" +es = "Abrir en el gestor de archivos" +fr = "Ouvrir dans le gestionnaire de fichiers" +zh = "在文件管理器中打开" +ar = "فتح في مدير الملفات" + +[gui.context.dirs.remove] +en = "Remove" +ru = "Удалить" +es = "Eliminar" +fr = "Supprimer" +zh = "移除" +ar = "إزالة" + +[gui.context.files.play_solo] +en = "Play Solo" +ru = "Играть" +es = "Reproducir solo" +fr = "Jouer en solo" +zh = "单独播放" +ar = "تشغيل منفرد" + +[gui.context.files.add_new] +en = "Add New" +ru = "Добавить" +es = "Añadir nuevo" +fr = "Ajouter un nouveau" +zh = "添加新项" +ar = "إضافة جديد" + +[gui.context.files.replace_last] +en = "Replace Last" +ru = "Заменить Последний" +es = "Reemplazar último" +fr = "Remplacer le dernier" +zh = "替换上一个" +ar = "استبدال الأخير" + +[gui.context.files.show_in_fm] +en = "Show in File Manager" +ru = "Открыть в менеджере файлов" +es = "Mostrar en el gestor de archivos" +fr = "Afficher dans le gestionnaire de fichiers" +zh = "在文件管理器中显示" +ar = "عرض في مدير الملفات" + +[gui.context.files.asign_hotkey] +en = "Asign Hotkey" +ru = "Назначить Горячую Клавишу" +es = "Asignar atajo" +fr = "Assigner un raccourci" +zh = "分配快捷键" +ar = "تعيين مفتاح اختصار" + +# ---------------- +# Settings +# ---------------- + +[gui.settings.header] +en = "Settings" +ru = "Настройки" +es = "Ajustes" +fr = "Paramètres" +zh = "设置" +ar = "الإعدادات" + +[gui.settings.remember_volume] +en = "Always remember volume" +ru = "Всегда запоминать громкость" +es = "Recordar siempre el volumen" +fr = "Toujours se souvenir du volume" +zh = "始终记住音量" +ar = "تذكر مستوى الصوت دائمًا" + +[gui.settings.remember_mic] +en = "Always remember microphone" +ru = "Всегда запоминать микрофон" +es = "Recordar siempre el micrófono" +fr = "Toujours se souvenir du microphone" +zh = "始终记住麦克风" +ar = "تذكر الميكروفون دائمًا" + +[gui.settings.remember_ui_scale] +en = "Always remember UI scale factor" +ru = "Всегда запоминать масштаб интерфейса" +es = "Recordar siempre la escala de la interfaz" +fr = "Toujours se souvenir de l'échelle de l'interface" +zh = "始终记住界面缩放比例" +ar = "تذكر عامل تكبير الواجهة دائمًا" + +[gui.settings.pause_on_window_close] +en = "Pause audio playback when the window is closed" +ru = "Останавливать воспроизведение при закрытии окна" +es = "Pausar la reproducción de audio al cerrar la ventana" +fr = "Mettre en pause la lecture audio à la fermeture de la fenêtre" +zh = "关闭窗口时暂停音频播放" +ar = "إيقاف الصوت مؤقتًا عند إغلاق النافذة" + +[gui.settings.version] +en = "GUI version: %{version}" +ru = "Версия GUI: %{version}" +es = "Versión de la GUI: %{version}" +fr = "Version de l'interface : %{version}" +zh = "GUI 版本: %{version}" +ar = "إصدار الواجهة: %{version}" + +# ---------------- +# Hotkeys +# ---------------- + +[gui.hotkeys.header] +en = "Hotkeys" +ru = "Горячие клавиши" +es = "Atajos de teclado" +fr = "Raccourcis clavier" +zh = "快捷键" +ar = "اختصارات لوحة المفاتيح" + +[gui.hotkeys.search_placeholder] +en = "Search hotkeys..." +ru = "Поиск горячих клавиш..." +es = "Buscar atajos..." +fr = "Rechercher des raccourcis..." +zh = "搜索快捷键..." +ar = "البحث عن الاختصارات..." + +[gui.hotkeys.add_command_select] +en = "Add Command" +ru = "Добавить команду" +es = "Añadir comando" +fr = "Ajouter une commande" +zh = "添加命令" +ar = "إضافة أمر" + +[gui.hotkeys.toggle_pause_command] +en = "Toggle Pause" +ru = "Переключить паузу" +es = "Alternar pausa" +fr = "Basculer la pause" +zh = "切换暂停" +ar = "تبديل الإيقاف المؤقت" + +[gui.hotkeys.stop_playback_command] +en = "Stop Playback" +ru = "Остановить воспроизведение" +es = "Detener reproducción" +fr = "Arrêter la lecture" +zh = "停止播放" +ar = "إيقاف التشغيل" + +[gui.hotkeys.pause_playback_command] +en = "Pause Playback" +ru = "Поставить воспроизведение на паузу" +es = "Pausar reproducción" +fr = "Mettre en pause la lecture" +zh = "暂停播放" +ar = "إيقاف التشغيل مؤقتاً" + +[gui.hotkeys.resume_playback_command] +en = "Resume Playback" +ru = "Продолжить воспроизведение" +es = "Reanudar reproducción" +fr = "Reprendre la lecture" +zh = "恢复播放" +ar = "استئناف التشغيل" + +[gui.hotkeys.toggle_loop_command] +en = "Toggle Loop" +ru = "Переключить зацикливание" +es = "Alternar bucle" +fr = "Basculer la boucle" +zh = "切换循环" +ar = "تبديل التكرار" + +[gui.hotkeys.column_slot] +en = "Slot" +ru = "Слот" +es = "Ranura" +fr = "Emplacement" +zh = "插槽" +ar = "الخانة" + +[gui.hotkeys.column_sound] +en = "Sound" +ru = "Звук" +es = "Sonido" +fr = "Son" +zh = "声音" +ar = "الصوت" + +[gui.hotkeys.column_key_chord] +en = "Key Chord" +ru = "Клавиша" +es = "Combinación de teclas" +fr = "Combinaison de touches" +zh = "组合键" +ar = "تركيبة المفاتيح" + +[gui.hotkeys.column_actions] +en = "Actions" +ru = "Действия" +es = "Acciones" +fr = "Actions" +zh = "操作" +ar = "الإجراءات" + +[gui.hotkeys.no_hotkeys_configured] +en = "No hotkeys configured" +ru = "Горячие клавиши не настроены" +es = "No hay atajos configurados" +fr = "Aucun raccourci configuré" +zh = "未配置快捷键" +ar = "لا توجد اختصارات معينة" + +[gui.hotkeys.capture.header] +en = "Press a key combination (e.g. Ctrl+Alt+1)" +ru = "Нажмите сочетание клавиш (например, Ctrl+Alt+1)" +es = "Presione una combinación de teclas (ej. Ctrl+Alt+1)" +fr = "Appuyez sur une combinaison de touches (ex. Ctrl+Alt+1)" +zh = "按下一个组合键 (例如 Ctrl+Alt+1)" +ar = "اضغط على تركيبة مفاتيح (مثلاً Ctrl+Alt+1)" + +[gui.hotkeys.capture.for] +en = "for" +ru = "для" +es = "para" +fr = "pour" +zh = "用于" +ar = "لـ" + +[gui.hotkeys.capture.cancel] +en = "Press Escape to canel" +ru = "Нажмите Escape для отмены" +es = "Presione Escape para cancelar" +fr = "Appuyez sur Échap pour annuler" +zh = "按 Escape 取消" +ar = "اضغط Esc للإلغاء" diff --git a/packages/flatpak/cargo-sources.json b/packages/flatpak/cargo-sources.json index 0a47f91..7a570df 100644 --- a/packages/flatpak/cargo-sources.json +++ b/packages/flatpak/cargo-sources.json @@ -193,6 +193,19 @@ "dest": "cargo/vendor/arboard-3.6.1", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/arc-swap/arc-swap-1.9.1.crate", + "sha256": "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207", + "dest": "cargo/vendor/arc-swap-1.9.1" + }, + { + "type": "inline", + "contents": "{\"package\": \"6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207\", \"files\": {}}", + "dest": "cargo/vendor/arc-swap-1.9.1", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -388,6 +401,19 @@ "dest": "cargo/vendor/autocfg-1.5.0", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/base62/base62-2.2.4.crate", + "sha256": "cd637ac531c60eb7fbc4684dc061c2d7d90d73d758181aa02eeff0464b9eee4b", + "dest": "cargo/vendor/base62-2.2.4" + }, + { + "type": "inline", + "contents": "{\"package\": \"cd637ac531c60eb7fbc4684dc061c2d7d90d73d758181aa02eeff0464b9eee4b\", \"files\": {}}", + "dest": "cargo/vendor/base62-2.2.4", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -1966,6 +1992,32 @@ "dest": "cargo/vendor/glob-0.3.3", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/globset/globset-0.4.18.crate", + "sha256": "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3", + "dest": "cargo/vendor/globset-0.4.18" + }, + { + "type": "inline", + "contents": "{\"package\": \"52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3\", \"files\": {}}", + "dest": "cargo/vendor/globset-0.4.18", + "dest-filename": ".cargo-checksum.json" + }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/globwalk/globwalk-0.8.1.crate", + "sha256": "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc", + "dest": "cargo/vendor/globwalk-0.8.1" + }, + { + "type": "inline", + "contents": "{\"package\": \"93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc\", \"files\": {}}", + "dest": "cargo/vendor/globwalk-0.8.1", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -2291,6 +2343,19 @@ "dest": "cargo/vendor/idna_adapter-1.2.2", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/ignore/ignore-0.4.25.crate", + "sha256": "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a", + "dest": "cargo/vendor/ignore-0.4.25" + }, + { + "type": "inline", + "contents": "{\"package\": \"d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a\", \"files\": {}}", + "dest": "cargo/vendor/ignore-0.4.25", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -2356,6 +2421,19 @@ "dest": "cargo/vendor/indexmap-2.14.0", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/itertools/itertools-0.11.0.crate", + "sha256": "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57", + "dest": "cargo/vendor/itertools-0.11.0" + }, + { + "type": "inline", + "contents": "{\"package\": \"b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57\", \"files\": {}}", + "dest": "cargo/vendor/itertools-0.11.0", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -4298,6 +4376,45 @@ "dest": "cargo/vendor/roxmltree-0.20.0", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/rust-i18n/rust-i18n-4.0.0.crate", + "sha256": "21031bf5e6f2c0ae745d831791c403608e99a8bd3776c7e5e5535acd70c3b7ba", + "dest": "cargo/vendor/rust-i18n-4.0.0" + }, + { + "type": "inline", + "contents": "{\"package\": \"21031bf5e6f2c0ae745d831791c403608e99a8bd3776c7e5e5535acd70c3b7ba\", \"files\": {}}", + "dest": "cargo/vendor/rust-i18n-4.0.0", + "dest-filename": ".cargo-checksum.json" + }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/rust-i18n-macro/rust-i18n-macro-4.0.0.crate", + "sha256": "51fe5295763b358606f7ca26a564e20f4469775a57ec1f09431249a33849ff52", + "dest": "cargo/vendor/rust-i18n-macro-4.0.0" + }, + { + "type": "inline", + "contents": "{\"package\": \"51fe5295763b358606f7ca26a564e20f4469775a57ec1f09431249a33849ff52\", \"files\": {}}", + "dest": "cargo/vendor/rust-i18n-macro-4.0.0", + "dest-filename": ".cargo-checksum.json" + }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/rust-i18n-support/rust-i18n-support-4.0.0.crate", + "sha256": "69bcc115c8eea2803aa3d85362e339776f4988a0349f2f475af572e497443f6f", + "dest": "cargo/vendor/rust-i18n-support-4.0.0" + }, + { + "type": "inline", + "contents": "{\"package\": \"69bcc115c8eea2803aa3d85362e339776f4988a0349f2f475af572e497443f6f\", \"files\": {}}", + "dest": "cargo/vendor/rust-i18n-support-4.0.0", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -4376,6 +4493,19 @@ "dest": "cargo/vendor/rustversion-1.0.22", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/ryu/ryu-1.0.23.crate", + "sha256": "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f", + "dest": "cargo/vendor/ryu-1.0.23" + }, + { + "type": "inline", + "contents": "{\"package\": \"9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f\", \"files\": {}}", + "dest": "cargo/vendor/ryu-1.0.23", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -4506,6 +4636,19 @@ "dest": "cargo/vendor/serde_repr-0.1.20", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/serde_spanned/serde_spanned-0.6.9.crate", + "sha256": "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3", + "dest": "cargo/vendor/serde_spanned-0.6.9" + }, + { + "type": "inline", + "contents": "{\"package\": \"bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3\", \"files\": {}}", + "dest": "cargo/vendor/serde_spanned-0.6.9", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -4519,6 +4662,19 @@ "dest": "cargo/vendor/serde_spanned-1.1.1", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/serde_yaml/serde_yaml-0.9.34+deprecated.crate", + "sha256": "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47", + "dest": "cargo/vendor/serde_yaml-0.9.34+deprecated" + }, + { + "type": "inline", + "contents": "{\"package\": \"6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47\", \"files\": {}}", + "dest": "cargo/vendor/serde_yaml-0.9.34+deprecated", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -5221,6 +5377,19 @@ "dest": "cargo/vendor/tokio-macros-2.7.0", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/toml/toml-0.8.23.crate", + "sha256": "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362", + "dest": "cargo/vendor/toml-0.8.23" + }, + { + "type": "inline", + "contents": "{\"package\": \"dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362\", \"files\": {}}", + "dest": "cargo/vendor/toml-0.8.23", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -5234,6 +5403,19 @@ "dest": "cargo/vendor/toml-1.1.2+spec-1.1.0", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/toml_datetime/toml_datetime-0.6.11.crate", + "sha256": "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c", + "dest": "cargo/vendor/toml_datetime-0.6.11" + }, + { + "type": "inline", + "contents": "{\"package\": \"22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c\", \"files\": {}}", + "dest": "cargo/vendor/toml_datetime-0.6.11", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -5247,6 +5429,19 @@ "dest": "cargo/vendor/toml_datetime-1.1.1+spec-1.1.0", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/toml_edit/toml_edit-0.22.27.crate", + "sha256": "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a", + "dest": "cargo/vendor/toml_edit-0.22.27" + }, + { + "type": "inline", + "contents": "{\"package\": \"41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a\", \"files\": {}}", + "dest": "cargo/vendor/toml_edit-0.22.27", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -5273,6 +5468,19 @@ "dest": "cargo/vendor/toml_parser-1.1.2+spec-1.1.0", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/toml_write/toml_write-0.1.2.crate", + "sha256": "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801", + "dest": "cargo/vendor/toml_write-0.1.2" + }, + { + "type": "inline", + "contents": "{\"package\": \"5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801\", \"files\": {}}", + "dest": "cargo/vendor/toml_write-0.1.2", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -5325,6 +5533,19 @@ "dest": "cargo/vendor/tracing-core-0.1.36", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/triomphe/triomphe-0.1.15.crate", + "sha256": "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39", + "dest": "cargo/vendor/triomphe-0.1.15" + }, + { + "type": "inline", + "contents": "{\"package\": \"dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39\", \"files\": {}}", + "dest": "cargo/vendor/triomphe-0.1.15", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -5429,6 +5650,19 @@ "dest": "cargo/vendor/unicode-xid-0.2.6", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/unsafe-libyaml/unsafe-libyaml-0.2.11.crate", + "sha256": "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861", + "dest": "cargo/vendor/unsafe-libyaml-0.2.11" + }, + { + "type": "inline", + "contents": "{\"package\": \"673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861\", \"files\": {}}", + "dest": "cargo/vendor/unsafe-libyaml-0.2.11", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -6521,6 +6755,19 @@ "dest": "cargo/vendor/winit-0.30.13", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/winnow/winnow-0.7.15.crate", + "sha256": "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945", + "dest": "cargo/vendor/winnow-0.7.15" + }, + { + "type": "inline", + "contents": "{\"package\": \"df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945\", \"files\": {}}", + "dest": "cargo/vendor/winnow-0.7.15", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", diff --git a/src/gui/draw.rs b/src/gui/draw.rs index 29bcf20..e81780d 100644 --- a/src/gui/draw.rs +++ b/src/gui/draw.rs @@ -9,6 +9,7 @@ use egui_material_icons::icons::*; use pwsp::types::socket::Request; use pwsp::types::{audio_player::TrackInfo, gui::AppState}; use pwsp::utils::gui::{format_time_pair, make_request_async}; +use rust_i18n::t; use std::{path::Path, time::Instant}; enum TrackAction { @@ -59,17 +60,18 @@ impl SoundpadGui { ui.vertical_centered(|ui| { ui.add_space(ui.available_height() / 3.0); ui.label( - RichText::new("Press a key combination (e.g. Ctrl+Alt+1)") + RichText::new(t!("gui.hotkeys.capture.header")) .size(18.0) .color(Color32::YELLOW) .monospace(), ); ui.add_space(10.0); let target = if let Some(slot) = &self.app_state.assigning_hotkey_slot { - format!("for slot '{}'", slot) + format!("{} '{}'", t!("gui.hotkeys.capture.for"), slot) } else if let Some(path) = &self.app_state.assigning_hotkey_for_file { format!( - "for '{}'", + "{} '{}'", + t!("gui.hotkeys.capture.for"), path.file_name().unwrap_or_default().to_string_lossy() ) } else { @@ -77,7 +79,7 @@ impl SoundpadGui { }; ui.label(RichText::new(target).size(16.0)); ui.add_space(10.0); - ui.label("Press Escape to cancel"); + ui.label(t!("gui.hotkeys.capture.cancel")); }); } @@ -94,7 +96,11 @@ impl SoundpadGui { ui.add_space(ui.available_width() / 2.0 - 40.0); - ui.label(RichText::new("Settings").color(Color32::WHITE).monospace()); + ui.label( + RichText::new(t!("gui.settings.header")) + .color(Color32::WHITE) + .monospace(), + ); }); // -------------------------------- @@ -102,17 +108,19 @@ impl SoundpadGui { ui.add_space(20.0); // --------- Checkboxes ---------- - let save_volume_response = - ui.checkbox(&mut self.config.save_volume, "Always remember volume"); + let save_volume_response = ui.checkbox( + &mut self.config.save_volume, + t!("gui.settings.remember_volume"), + ); let save_input_response = - ui.checkbox(&mut self.config.save_input, "Always remember microphone"); + ui.checkbox(&mut self.config.save_input, t!("gui.settings.remember_mic")); let save_scale_response = ui.checkbox( &mut self.config.save_scale_factor, - "Always remember UI scale factor", + t!("gui.settings.remember_ui_scale"), ); let pause_on_exit_response = ui.checkbox( &mut self.config.pause_on_exit, - "Pause audio playback when the window is closed", + t!("gui.settings.pause_on_window_close"), ); if save_volume_response.changed() @@ -125,7 +133,10 @@ impl SoundpadGui { // -------------------------------- ui.with_layout(Layout::bottom_up(Align::Min), |ui| { - ui.label(format!("GUI version: {}", env!("CARGO_PKG_VERSION"))); + ui.label(t!( + "gui.settings.version", + version = env!("CARGO_PKG_VERSION") + )); }); }); } @@ -157,47 +168,64 @@ impl SoundpadGui { } ui.vertical_centered(|ui| { - ui.label(RichText::new("Hotkeys").color(Color32::WHITE).monospace()); + ui.label( + RichText::new(t!("gui.hotkeys.header")) + .color(Color32::WHITE) + .monospace(), + ); }); }); } fn draw_hotkeys_search(&mut self, ui: &mut Ui) { ui.horizontal(|ui| { - ui.menu_button(format!("{} Add Command", ICON_ADD.codepoint), |ui| { - let mut selected_cmd = None; - if ui.button("Toggle Pause").clicked() { - selected_cmd = Some(("cmd_toggle_pause", Request::toggle_pause(None))); - } - if ui.button("Stop Playback").clicked() { - selected_cmd = Some(("cmd_stop", Request::stop(None))); - } - if ui.button("Pause Playback").clicked() { - selected_cmd = Some(("cmd_pause", Request::pause(None))); - } - if ui.button("Resume Playback").clicked() { - selected_cmd = Some(("cmd_resume", Request::resume(None))); - } - if ui.button("Toggle Loop").clicked() { - selected_cmd = Some(("cmd_toggle_loop", Request::toggle_loop(None))); - } + ui.menu_button( + format!( + "{} {}", + ICON_ADD.codepoint, + t!("gui.hotkeys.add_command_select") + ), + |ui| { + let mut selected_cmd = None; + if ui.button(t!("gui.hotkeys.toggle_pause_command")).clicked() { + selected_cmd = Some(("cmd_toggle_pause", Request::toggle_pause(None))); + } + if ui.button(t!("gui.hotkeys.stop_playback_command")).clicked() { + selected_cmd = Some(("cmd_stop", Request::stop(None))); + } + if ui + .button(t!("gui.hotkeys.pause_playback_command")) + .clicked() + { + selected_cmd = Some(("cmd_pause", Request::pause(None))); + } + if ui + .button(t!("gui.hotkeys.resume_playback_command")) + .clicked() + { + selected_cmd = Some(("cmd_resume", Request::resume(None))); + } + if ui.button(t!("gui.hotkeys.toggle_loop_command")).clicked() { + selected_cmd = Some(("cmd_toggle_loop", Request::toggle_loop(None))); + } - if let Some((slot_name, req)) = selected_cmd { - make_request_async(Request::set_hotkey_action(slot_name, &req)); - self.app_state - .hotkey_config - .set_slot(slot_name.to_string(), req); - self.app_state.assigning_hotkey_slot = Some(slot_name.to_string()); - self.app_state.hotkey_capture_active = true; - ui.close(); - } - }); + if let Some((slot_name, req)) = selected_cmd { + make_request_async(Request::set_hotkey_action(slot_name, &req)); + self.app_state + .hotkey_config + .set_slot(slot_name.to_string(), req); + self.app_state.assigning_hotkey_slot = Some(slot_name.to_string()); + self.app_state.hotkey_capture_active = true; + ui.close(); + } + }, + ); ui.add_space(10.0); ui.add( TextEdit::singleline(&mut self.app_state.hotkey_search_query) - .hint_text("Search hotkeys...") + .hint_text(t!("gui.hotkeys.search_placeholder")) .desired_width(f32::INFINITY), ); }); @@ -242,7 +270,7 @@ impl SoundpadGui { .header(30.0, |mut header| { header.col(|ui| { ui.label( - RichText::new("Slot") + RichText::new(t!("gui.hotkeys.column_slot")) .strong() .monospace() .color(Color32::LIGHT_GRAY), @@ -250,7 +278,7 @@ impl SoundpadGui { }); header.col(|ui| { ui.label( - RichText::new("Sound") + RichText::new(t!("gui.hotkeys.column_sound")) .strong() .monospace() .color(Color32::LIGHT_GRAY), @@ -258,7 +286,7 @@ impl SoundpadGui { }); header.col(|ui| { ui.label( - RichText::new("Key Chord") + RichText::new(t!("gui.hotkeys.column_key_chord")) .strong() .monospace() .color(Color32::LIGHT_GRAY), @@ -266,7 +294,7 @@ impl SoundpadGui { }); header.col(|ui| { ui.label( - RichText::new("Actions") + RichText::new(t!("gui.hotkeys.column_actions")) .strong() .monospace() .color(Color32::LIGHT_GRAY), @@ -279,7 +307,8 @@ impl SoundpadGui { row.col(|_| {}); row.col(|ui| { ui.label( - RichText::new("No hotkey slots configured.").color(Color32::GRAY), + RichText::new(t!("gui.hotkeys.no_hotkeys_configured")) + .color(Color32::GRAY), ); }); row.col(|_| {}); @@ -671,7 +700,11 @@ impl SoundpadGui { // Context menu dir_button_response.context_menu(|ui| { if ui - .button(format!("{} {}", ICON_OPEN_IN_NEW.codepoint, "Show")) + .button(format!( + "{} {}", + ICON_OPEN_IN_NEW.codepoint, + t!("gui.dirs.context.open") + )) .clicked() { self.open_dir(&path); @@ -680,7 +713,8 @@ impl SoundpadGui { if ui .button(format!( "{} {}", - ICON_OPEN_IN_BROWSER.codepoint, "Open in File Manager" + ICON_OPEN_IN_BROWSER.codepoint, + t!("gui.context.dirs.open_in_fm") )) .clicked() && let Err(e) = opener::open(&path) @@ -691,7 +725,11 @@ impl SoundpadGui { ui.separator(); if ui - .button(format!("{} {}", ICON_DELETE.codepoint, "Remove")) + .button(format!( + "{} {}", + ICON_DELETE.codepoint, + t!("gui.context.dirs.remove") + )) .clicked() { self.app_state.dirs_to_remove.insert(path.clone()); @@ -710,7 +748,7 @@ impl SoundpadGui { }); ui.with_layout(Layout::bottom_up(Align::Min), |ui| { - let play_file_button = Button::new("Play file"); + let play_file_button = Button::new(t!("gui.play_file_button")); let play_file_button_response = ui.add(play_file_button); if play_file_button_response.clicked() { self.open_file(); @@ -725,7 +763,8 @@ impl SoundpadGui { ui.horizontal(|ui| { let search_field_response = ui.add_sized( [ui.available_width(), 22.0], - TextEdit::singleline(&mut self.app_state.search_query).hint_text("Search..."), + TextEdit::singleline(&mut self.app_state.search_query) + .hint_text(t!("gui.search_placeholder")), ); if self.app_state.force_focus_search { @@ -793,7 +832,11 @@ impl SoundpadGui { // Context menu file_button_response.context_menu(|ui| { if ui - .button(format!("{} {}", ICON_BOLT.codepoint, "Play Solo")) + .button(format!( + "{} {}", + ICON_BOLT.codepoint, + t!("gui.context.files.play_solo") + )) .clicked() { self.play_file(&entry_path, false); @@ -801,7 +844,11 @@ impl SoundpadGui { } if ui - .button(format!("{} {}", ICON_ADD.codepoint, "Add New")) + .button(format!( + "{} {}", + ICON_ADD.codepoint, + t!("gui.context.files.add_new") + )) .clicked() { self.play_file(&entry_path, true); @@ -811,7 +858,8 @@ impl SoundpadGui { if ui .button(format!( "{} {}", - ICON_SWAP_HORIZ.codepoint, "Replace Last" + ICON_SWAP_HORIZ.codepoint, + t!("gui.context.files.replace_last") )) .clicked() && let Some(last_track) = self.audio_player_state.tracks.last() @@ -826,7 +874,8 @@ impl SoundpadGui { if ui .button(format!( "{} {}", - ICON_OPEN_IN_BROWSER.codepoint, "Show in File Manager" + ICON_OPEN_IN_BROWSER.codepoint, + t!("gui.context.files.show_in_fm") )) .clicked() && let Err(e) = opener::reveal(&entry_path) @@ -839,7 +888,8 @@ impl SoundpadGui { if ui .button(format!( "{} {}", - ICON_KEYBOARD.codepoint, "Assign Hotkey" + ICON_KEYBOARD.codepoint, + t!("gui.context.files.asign_hotkey") )) .clicked() { @@ -880,7 +930,7 @@ impl SoundpadGui { let mut selected_input = self.audio_player_state.current_input.to_owned(); let prev_input = selected_input.to_owned(); - ComboBox::from_label("Choose microphone") + ComboBox::from_label(t!("gui.choose_mic_select")) .height(30.0) .selected_text( self.audio_player_state diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 5187a47..9b9a04f 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -227,8 +227,9 @@ fn load_system_fonts(fonts: &mut FontDefinitions) -> Result<()> { let (_, en_sans) = find_for_locale("en", FontStyle::Sans); let (_, en_serif) = find_for_locale("en", FontStyle::Serif); let (_, ja_sans) = find_for_locale("ja", FontStyle::Sans); + let (_, ar_sans) = find_for_locale("ar", FontStyle::Sans); - let system_fonts = [en_sans, en_serif, ja_sans].concat(); + let system_fonts = [en_sans, en_serif, ja_sans, ar_sans].concat(); for font in system_fonts.iter().rev() { let font_bytes = match &font.source { diff --git a/src/main.rs b/src/main.rs index 37445f6..a2bc891 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,14 @@ mod gui; use anyhow::Result; +use rust_i18n::i18n; + +i18n!("locales", fallback = "en"); #[tokio::main] async fn main() -> Result<()> { - gui::run().await + let locale = sys_locale::get_locale().unwrap_or(String::from("en-US")); + rust_i18n::set_locale(&locale); + + gui::run().await }