feat: FTPS, AppError, Site Manager, tests, multi-window, auto-clear, CI/CD, virtual scroll

- FTPS: реализован FtpsClient через suppaftp + async-native-tls
- AppError: кастомный enum с Serialize вместо Result<T, String>
- Site Manager UI: создание/редактирование/удаление сайтов
- Тесты: 53 тестов (domain, storage, transfer, fs, remote)
- Multi-window: новое окно + сохранение геометрии
- Auto-clear: воркер чистит завершённые задачи по таймеру
- CI/CD: 3-ступенчатый пайплайн (lint→build→test) с кэшированием
- Virtual scroll: fileTable с рендером только видимых строк
- UI: исправлены close-кнопки, color-scheme для select, скриншоты в README
This commit is contained in:
loki5512344 2026-07-11 00:04:13 +02:00
parent 545dd4ed0b
commit e188fbef36
Signed by: boba
GPG key ID: 253067914055423B
52 changed files with 5188 additions and 523 deletions

View file

@ -7,8 +7,18 @@ pub const ENTRIES: &[Entry] = &[
(
"common.cancel",
[
"Cancel", "Отмена", "Cancelar", "Annuler", "Abbrechen", "Annulla", "Cancelar",
"Anuluj", "取消", "キャンセル", "취소", "İptal",
"Cancel",
"Отмена",
"Cancelar",
"Annuler",
"Abbrechen",
"Annulla",
"Cancelar",
"Anuluj",
"取消",
"キャンセル",
"취소",
"İptal",
],
),
(
@ -20,8 +30,18 @@ pub const ENTRIES: &[Entry] = &[
(
"common.delete",
[
"Delete", "Удалить", "Eliminar", "Supprimer", "Löschen", "Elimina", "Excluir",
"Usuń", "删除", "削除", "삭제", "Sil",
"Delete",
"Удалить",
"Eliminar",
"Supprimer",
"Löschen",
"Elimina",
"Excluir",
"Usuń",
"删除",
"削除",
"삭제",
"Sil",
],
),
(
@ -44,29 +64,69 @@ pub const ENTRIES: &[Entry] = &[
(
"common.edit",
[
"Edit", "Изменить", "Editar", "Modifier", "Bearbeiten", "Modifica", "Editar",
"Edytuj", "编辑", "編集", "편집", "Düzenle",
"Edit",
"Изменить",
"Editar",
"Modifier",
"Bearbeiten",
"Modifica",
"Editar",
"Edytuj",
"编辑",
"編集",
"편집",
"Düzenle",
],
),
(
"common.save",
[
"Save", "Сохранить", "Guardar", "Enregistrer", "Speichern", "Salva", "Salvar",
"Zapisz", "保存", "保存", "저장", "Kaydet",
"Save",
"Сохранить",
"Guardar",
"Enregistrer",
"Speichern",
"Salva",
"Salvar",
"Zapisz",
"保存",
"保存",
"저장",
"Kaydet",
],
),
(
"common.open",
[
"Open", "Открыть", "Abrir", "Ouvrir", "Öffnen", "Apri", "Abrir", "Otwórz", "打开",
"開く", "열기", "Aç",
"Open",
"Открыть",
"Abrir",
"Ouvrir",
"Öffnen",
"Apri",
"Abrir",
"Otwórz",
"打开",
"開く",
"열기",
"Aç",
],
),
(
"common.close",
[
"Close", "Закрыть", "Cerrar", "Fermer", "Schließen", "Chiudi", "Fechar", "Zamknij",
"关闭", "閉じる", "닫기", "Kapat",
"Close",
"Закрыть",
"Cerrar",
"Fermer",
"Schließen",
"Chiudi",
"Fechar",
"Zamknij",
"关闭",
"閉じる",
"닫기",
"Kapat",
],
),
(
@ -106,8 +166,18 @@ pub const ENTRIES: &[Entry] = &[
(
"common.connect",
[
"Connect", "Подключить", "Conectar", "Connecter", "Verbinden", "Connetti",
"Conectar", "Połącz", "连接", "接続", "연결", "Bağlan",
"Connect",
"Подключить",
"Conectar",
"Connecter",
"Verbinden",
"Connetti",
"Conectar",
"Połącz",
"连接",
"接続",
"연결",
"Bağlan",
],
),
(
@ -130,8 +200,18 @@ pub const ENTRIES: &[Entry] = &[
(
"common.host",
[
"Host", "Хост", "Host", "Hôte", "Host", "Host", "Host", "Host", "主机", "ホスト",
"호스트", "Sunucu",
"Host",
"Хост",
"Host",
"Hôte",
"Host",
"Host",
"Host",
"Host",
"主机",
"ホスト",
"호스트",
"Sunucu",
],
),
(
@ -154,43 +234,103 @@ pub const ENTRIES: &[Entry] = &[
(
"common.password",
[
"Password", "Пароль", "Contraseña", "Mot de passe", "Passwort", "Password", "Senha",
"Hasło", "密码", "パスワード", "비밀번호", "Parola",
"Password",
"Пароль",
"Contraseña",
"Mot de passe",
"Passwort",
"Password",
"Senha",
"Hasło",
"密码",
"パスワード",
"비밀번호",
"Parola",
],
),
(
"common.port",
[
"Port", "Порт", "Puerto", "Port", "Port", "Porta", "Porta", "Port", "端口", "ポート",
"포트", "Port",
"Port",
"Порт",
"Puerto",
"Port",
"Port",
"Porta",
"Porta",
"Port",
"端口",
"ポート",
"포트",
"Port",
],
),
(
"common.label",
[
"Label", "Метка", "Etiqueta", "Étiquette", "Bezeichnung", "Etichetta", "Rótulo",
"Etykieta", "标签", "ラベル", "라벨", "Etiket",
"Label",
"Метка",
"Etiqueta",
"Étiquette",
"Bezeichnung",
"Etichetta",
"Rótulo",
"Etykieta",
"标签",
"ラベル",
"라벨",
"Etiket",
],
),
(
"common.refresh",
[
"Refresh", "Обновить", "Actualizar", "Actualiser", "Aktualisieren", "Aggiorna",
"Atualizar", "Odśwież", "刷新", "更新", "새로고침", "Yenile",
"Refresh",
"Обновить",
"Actualizar",
"Actualiser",
"Aktualisieren",
"Aggiorna",
"Atualizar",
"Odśwież",
"刷新",
"更新",
"새로고침",
"Yenile",
],
),
(
"common.upload",
[
"Upload", "Загрузить", "Subir", "Envoyer", "Hochladen", "Carica", "Enviar",
"Prześlij", "上传", "アップロード", "업로드", "Yükle",
"Upload",
"Загрузить",
"Subir",
"Envoyer",
"Hochladen",
"Carica",
"Enviar",
"Prześlij",
"上传",
"アップロード",
"업로드",
"Yükle",
],
),
(
"common.download",
[
"Download", "Скачать", "Descargar", "Télécharger", "Herunterladen", "Scarica",
"Baixar", "Pobierz", "下载", "ダウンロード", "다운로드", "İndir",
"Download",
"Скачать",
"Descargar",
"Télécharger",
"Herunterladen",
"Scarica",
"Baixar",
"Pobierz",
"下载",
"ダウンロード",
"다운로드",
"İndir",
],
),
(
@ -213,15 +353,35 @@ pub const ENTRIES: &[Entry] = &[
(
"common.history",
[
"History", "История", "Historial", "Historique", "Verlauf", "Cronologia",
"Histórico", "Historia", "历史记录", "履歴", "기록", "Geçmiş",
"History",
"История",
"Historial",
"Historique",
"Verlauf",
"Cronologia",
"Histórico",
"Historia",
"历史记录",
"履歴",
"기록",
"Geçmiş",
],
),
(
"common.search",
[
"Search", "Поиск", "Buscar", "Rechercher", "Suchen", "Cerca", "Pesquisar", "Szukaj",
"搜索", "検索", "검색", "Ara",
"Search",
"Поиск",
"Buscar",
"Rechercher",
"Suchen",
"Cerca",
"Pesquisar",
"Szukaj",
"搜索",
"検索",
"검색",
"Ara",
],
),
(
@ -233,7 +393,17 @@ pub const ENTRIES: &[Entry] = &[
(
"common.no",
[
"No", "Нет", "No", "Non", "Nein", "No", "Não", "Nie", "否", "いいえ", "아니요",
"No",
"Нет",
"No",
"Non",
"Nein",
"No",
"Não",
"Nie",
"否",
"いいえ",
"아니요",
"Hayır",
],
),

View file

@ -39,8 +39,18 @@ pub const ENTRIES: &[Entry] = &[
(
"dialogs.browse",
[
"Browse…", "Обзор…", "Examinar…", "Parcourir…", "Durchsuchen…", "Sfoglia…",
"Procurar…", "Przeglądaj…", "浏览…", "参照…", "찾아보기…", "Gözat…",
"Browse…",
"Обзор…",
"Examinar…",
"Parcourir…",
"Durchsuchen…",
"Sfoglia…",
"Procurar…",
"Przeglądaj…",
"浏览…",
"参照…",
"찾아보기…",
"Gözat…",
],
),
(

View file

@ -5,8 +5,18 @@ pub const ENTRIES: &[Entry] = &[
(
"panels.local_label",
[
"LOCAL", "ЛОКАЛЬНО", "LOCAL", "LOCAL", "LOKAL", "LOCALE", "LOCAL", "LOKALNE", "本地",
"ローカル", "로컬", "YEREL",
"LOCAL",
"ЛОКАЛЬНО",
"LOCAL",
"LOCAL",
"LOKAL",
"LOCALE",
"LOCAL",
"LOKALNE",
"本地",
"ローカル",
"로컬",
"YEREL",
],
),
(
@ -94,29 +104,69 @@ pub const ENTRIES: &[Entry] = &[
(
"panels.col_size",
[
"Size", "Размер", "Tamaño", "Taille", "Größe", "Dimensione", "Tamanho", "Rozmiar",
"大小", "サイズ", "크기", "Boyut",
"Size",
"Размер",
"Tamaño",
"Taille",
"Größe",
"Dimensione",
"Tamanho",
"Rozmiar",
"大小",
"サイズ",
"크기",
"Boyut",
],
),
(
"panels.type_dir",
[
"Dir", "Папка", "Carpeta", "Dossier", "Ordner", "Cartella", "Pasta", "Folder",
"文件夹", "フォルダ", "폴더", "Klasör",
"Dir",
"Папка",
"Carpeta",
"Dossier",
"Ordner",
"Cartella",
"Pasta",
"Folder",
"文件夹",
"フォルダ",
"폴더",
"Klasör",
],
),
(
"panels.type_file",
[
"File", "Файл", "Archivo", "Fichier", "Datei", "File", "Arquivo", "Plik", "文件",
"ファイル", "파일", "Dosya",
"File",
"Файл",
"Archivo",
"Fichier",
"Datei",
"File",
"Arquivo",
"Plik",
"文件",
"ファイル",
"파일",
"Dosya",
],
),
(
"panels.type_link",
[
"Link", "Ссылка", "Enlace", "Lien", "Link", "Collegamento", "Link", "Link", "链接",
"リンク", "링크", "Bağlantı",
"Link",
"Ссылка",
"Enlace",
"Lien",
"Link",
"Collegamento",
"Link",
"Link",
"链接",
"リンク",
"링크",
"Bağlantı",
],
),
(
@ -139,8 +189,18 @@ pub const ENTRIES: &[Entry] = &[
(
"panels.sidebar.drives",
[
"DRIVES", "ДИСКИ", "UNIDADES", "DISQUES", "LAUFWERKE", "UNITÀ", "UNIDADES", "DYSKI",
"磁盘", "ドライブ", "드라이브", "SÜRÜCÜLER",
"DRIVES",
"ДИСКИ",
"UNIDADES",
"DISQUES",
"LAUFWERKE",
"UNITÀ",
"UNIDADES",
"DYSKI",
"磁盘",
"ドライブ",
"드라이브",
"SÜRÜCÜLER",
],
),
(
@ -197,8 +257,18 @@ pub const ENTRIES: &[Entry] = &[
(
"panels.sidebar.qa_home",
[
"Home", "Домой", "Inicio", "Accueil", "Start", "Home", "Início", "Dom", "主目录",
"ホーム", "홈", "Ana Sayfa",
"Home",
"Домой",
"Inicio",
"Accueil",
"Start",
"Home",
"Início",
"Dom",
"主目录",
"ホーム",
"홈",
"Ana Sayfa",
],
),
(
@ -221,8 +291,18 @@ pub const ENTRIES: &[Entry] = &[
(
"panels.sidebar.qa_documents",
[
"Documents", "Документы", "Documentos", "Documents", "Dokumente", "Documenti",
"Documentos", "Dokumenty", "文稿", "書類", "문서", "Belgeler",
"Documents",
"Документы",
"Documentos",
"Documents",
"Dokumente",
"Documenti",
"Documentos",
"Dokumenty",
"文稿",
"書類",
"문서",
"Belgeler",
],
),
(
@ -245,22 +325,52 @@ pub const ENTRIES: &[Entry] = &[
(
"panels.sidebar.qa_pictures",
[
"Pictures", "Изображения", "Imágenes", "Images", "Bilder", "Immagini", "Imagens",
"Obrazy", "图片", "ピクチャ", "사진", "Resimler",
"Pictures",
"Изображения",
"Imágenes",
"Images",
"Bilder",
"Immagini",
"Imagens",
"Obrazy",
"图片",
"ピクチャ",
"사진",
"Resimler",
],
),
(
"panels.sidebar.qa_music",
[
"Music", "Музыка", "Música", "Musique", "Musik", "Musica", "Música", "Muzyka",
"音乐", "ミュージック", "음악", "Müzik",
"Music",
"Музыка",
"Música",
"Musique",
"Musik",
"Musica",
"Música",
"Muzyka",
"音乐",
"ミュージック",
"음악",
"Müzik",
],
),
(
"panels.sidebar.qa_videos",
[
"Videos", "Видео", "Vídeos", "Vidéos", "Videos", "Video", "Vídeos", "Filmy", "影片",
"ムービー", "동영상", "Videolar",
"Videos",
"Видео",
"Vídeos",
"Vidéos",
"Videos",
"Video",
"Vídeos",
"Filmy",
"影片",
"ムービー",
"동영상",
"Videolar",
],
),
(

View file

@ -24,8 +24,18 @@ pub const ENTRIES: &[Entry] = &[
(
"settings.nav.group_general",
[
"GENERAL", "ОБЩЕЕ", "GENERAL", "GÉNÉRAL", "ALLGEMEIN", "GENERALE", "GERAL", "OGÓLNE",
"通用", "一般", "일반", "GENEL",
"GENERAL",
"ОБЩЕЕ",
"GENERAL",
"GÉNÉRAL",
"ALLGEMEIN",
"GENERALE",
"GERAL",
"OGÓLNE",
"通用",
"一般",
"일반",
"GENEL",
],
),
(
@ -65,15 +75,35 @@ pub const ENTRIES: &[Entry] = &[
(
"settings.nav.group_about",
[
"ABOUT", "О ПРОГРАММЕ", "ACERCA DE", "À PROPOS", "ÜBER", "INFORMAZIONI", "SOBRE",
"O PROGRAMIE", "关于", "情報", "정보", "HAKKINDA",
"ABOUT",
"О ПРОГРАММЕ",
"ACERCA DE",
"À PROPOS",
"ÜBER",
"INFORMAZIONI",
"SOBRE",
"O PROGRAMIE",
"关于",
"情報",
"정보",
"HAKKINDA",
],
),
(
"settings.nav.general",
[
"General", "Общие", "General", "Général", "Allgemein", "Generale", "Geral", "Ogólne",
"通用", "一般", "일반", "Genel",
"General",
"Общие",
"General",
"Général",
"Allgemein",
"Generale",
"Geral",
"Ogólne",
"通用",
"一般",
"일반",
"Genel",
],
),
(
@ -113,8 +143,18 @@ pub const ENTRIES: &[Entry] = &[
(
"settings.nav.history",
[
"History", "История", "Historial", "Historique", "Verlauf", "Cronologia",
"Histórico", "Historia", "历史记录", "履歴", "기록", "Geçmiş",
"History",
"История",
"Historial",
"Historique",
"Verlauf",
"Cronologia",
"Histórico",
"Historia",
"历史记录",
"履歴",
"기록",
"Geçmiş",
],
),
(
@ -154,8 +194,18 @@ pub const ENTRIES: &[Entry] = &[
(
"settings.nav.about",
[
"About", "О программе", "Acerca de", "À propos", "Über", "Informazioni", "Sobre",
"O programie", "关于", "情報", "정보", "Hakkında",
"About",
"О программе",
"Acerca de",
"À propos",
"Über",
"Informazioni",
"Sobre",
"O programie",
"关于",
"情報",
"정보",
"Hakkında",
],
),
// ── General ──────────────────────────────────────────────────────────
@ -340,8 +390,17 @@ pub const ENTRIES: &[Entry] = &[
(
"settings.appearance.sidebar",
[
"Sidebar", "Боковая панель", "Barra lateral", "Barre latérale", "Seitenleiste",
"Barra laterale", "Barra lateral", "Pasek boczny", "侧边栏", "サイドバー", "사이드바",
"Sidebar",
"Боковая панель",
"Barra lateral",
"Barre latérale",
"Seitenleiste",
"Barra laterale",
"Barra lateral",
"Pasek boczny",
"侧边栏",
"サイドバー",
"사이드바",
"Kenar Çubuğu",
],
),
@ -383,8 +442,18 @@ pub const ENTRIES: &[Entry] = &[
(
"settings.connections.sites",
[
"Sites", "Сайты", "Sitios", "Sites", "Seiten", "Siti", "Sites", "Serwery", "站点",
"サイト", "사이트", "Siteler",
"Sites",
"Сайты",
"Sitios",
"Sites",
"Seiten",
"Siti",
"Sites",
"Serwery",
"站点",
"サイト",
"사이트",
"Siteler",
],
),
(
@ -441,8 +510,18 @@ pub const ENTRIES: &[Entry] = &[
(
"settings.connections.bookmarks_title",
[
"Bookmarks", "Закладки", "Marcadores", "Favoris", "Lesezeichen", "Preferiti",
"Favoritos", "Zakładki", "书签", "ブックマーク", "북마크", "Yer İmleri",
"Bookmarks",
"Закладки",
"Marcadores",
"Favoris",
"Lesezeichen",
"Preferiti",
"Favoritos",
"Zakładki",
"书签",
"ブックマーク",
"북마크",
"Yer İmleri",
],
),
(
@ -534,9 +613,18 @@ pub const ENTRIES: &[Entry] = &[
(
"settings.history.delete_all",
[
"Delete All", "Удалить всё", "Eliminar todo", "Tout supprimer", "Alles löschen",
"Elimina tutto", "Excluir tudo", "Usuń wszystko", "全部删除", "すべて削除",
"모두 삭제", "Tümünü Sil",
"Delete All",
"Удалить всё",
"Eliminar todo",
"Tout supprimer",
"Alles löschen",
"Elimina tutto",
"Excluir tudo",
"Usuń wszystko",
"全部删除",
"すべて削除",
"모두 삭제",
"Tümünü Sil",
],
),
(
@ -748,8 +836,18 @@ pub const ENTRIES: &[Entry] = &[
(
"settings.transfers.never",
[
"Never", "Никогда", "Nunca", "Jamais", "Nie", "Mai", "Nunca", "Nigdy", "从不", "しない",
"안 함", "Asla",
"Never",
"Никогда",
"Nunca",
"Jamais",
"Nie",
"Mai",
"Nunca",
"Nigdy",
"从不",
"しない",
"안 함",
"Asla",
],
),
(
@ -792,22 +890,51 @@ pub const ENTRIES: &[Entry] = &[
(
"settings.about.version",
[
"Version", "Версия", "Versión", "Version", "Version", "Versione", "Versão", "Wersja",
"版本", "バージョン", "버전", "Sürüm",
"Version",
"Версия",
"Versión",
"Version",
"Version",
"Versione",
"Versão",
"Wersja",
"版本",
"バージョン",
"버전",
"Sürüm",
],
),
(
"settings.about.license",
[
"License", "Лицензия", "Licencia", "Licence", "Lizenz", "Licenza", "Licença",
"Licencja", "许可证", "ライセンス", "라이선스", "Lisans",
"License",
"Лицензия",
"Licencia",
"Licence",
"Lizenz",
"Licenza",
"Licença",
"Licencja",
"许可证",
"ライセンス",
"라이선스",
"Lisans",
],
),
(
"settings.about.database",
[
"Database", "База данных", "Base de datos", "Base de données", "Datenbank",
"Database", "Banco de dados", "Baza danych", "数据库", "データベース", "데이터베이스",
"Database",
"База данных",
"Base de datos",
"Base de données",
"Datenbank",
"Database",
"Banco de dados",
"Baza danych",
"数据库",
"データベース",
"데이터베이스",
"Veritabanı",
],
),

View file

@ -22,8 +22,18 @@ pub const ENTRIES: &[Entry] = &[
(
"toolbar.queue_label",
[
"Queue", "Очередь", "Cola", "File d'attente", "Warteschlange", "Coda", "Fila",
"Kolejka", "队列", "キュー", "대기열", "Kuyruk",
"Queue",
"Очередь",
"Cola",
"File d'attente",
"Warteschlange",
"Coda",
"Fila",
"Kolejka",
"队列",
"キュー",
"대기열",
"Kuyruk",
],
),
(
@ -165,8 +175,18 @@ pub const ENTRIES: &[Entry] = &[
(
"queue.state_queued",
[
"Queued", "В очереди", "En cola", "En attente", "Wartend", "In coda", "Na fila",
"W kolejce", "排队中", "待機中", "대기 중", "Sırada",
"Queued",
"В очереди",
"En cola",
"En attente",
"Wartend",
"In coda",
"Na fila",
"W kolejce",
"排队中",
"待機中",
"대기 중",
"Sırada",
],
),
(
@ -206,29 +226,69 @@ pub const ENTRIES: &[Entry] = &[
(
"queue.state_complete",
[
"Complete", "Готово", "Completado", "Terminé", "Fertig", "Completato", "Concluído",
"Gotowe", "已完成", "完了", "완료", "Tamamlandı",
"Complete",
"Готово",
"Completado",
"Terminé",
"Fertig",
"Completato",
"Concluído",
"Gotowe",
"已完成",
"完了",
"완료",
"Tamamlandı",
],
),
(
"queue.state_failed",
[
"Failed", "Ошибка", "Fallido", "Échec", "Fehlgeschlagen", "Non riuscito", "Falhou",
"Niepowodzenie", "失败", "失敗", "실패", "Başarısız",
"Failed",
"Ошибка",
"Fallido",
"Échec",
"Fehlgeschlagen",
"Non riuscito",
"Falhou",
"Niepowodzenie",
"失败",
"失敗",
"실패",
"Başarısız",
],
),
(
"queue.state_paused",
[
"Paused", "Приостановлено", "Pausado", "En pause", "Pausiert", "In pausa", "Pausado",
"Wstrzymane", "已暂停", "一時停止", "일시 중지", "Duraklatıldı",
"Paused",
"Приостановлено",
"Pausado",
"En pause",
"Pausiert",
"In pausa",
"Pausado",
"Wstrzymane",
"已暂停",
"一時停止",
"일시 중지",
"Duraklatıldı",
],
),
(
"queue.state_cancelled",
[
"Cancelled", "Отменено", "Cancelado", "Annulé", "Abgebrochen", "Annullato",
"Cancelado", "Anulowane", "已取消", "キャンセル済み", "취소됨", "İptal edildi",
"Cancelled",
"Отменено",
"Cancelado",
"Annulé",
"Abgebrochen",
"Annullato",
"Cancelado",
"Anulowane",
"已取消",
"キャンセル済み",
"취소됨",
"İptal edildi",
],
),
(