mirror of
https://github.com/storytold/craft-launcher.git
synced 2026-11-02 18:07:04 +00:00
Add Hungarian localization and fix responsive settings layout (#146)
* Add a Polish interface - pl.tsv: the full catalog (287 rows), written clean-room from the English labels; plurals use the same one|few|many rule as Russian. - Registered as the seventh language: "Polski" in the picker, locales pl, pl-PL and pl_PL.UTF-8, complete_menus = true so the completeness tests cover it. - tests/polish.rs: the Polish UI test, modeled on the French one. - README and AGENTS updated for the new language. * Add Hungarian localization and fix responsive settings layout * i18n: add Czech (cs) interface language Czech catalog with every key of the most complete catalog (287 rows), the cs language entry with locale detection (cs-CZ, cs_CZ.UTF-8, ?lang=cs), a Czech plural rule (1 / 2-4 / other) with a unit test, and the README language list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n(pl): use Polish plural rule, so 21 is "21 aplikacji" plural_east_slavic treats 21, 31 and 101 as "one", which is right for Russian but not Polish, where only 1 itself takes the singular. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n(cs): translate "Installed · latest {latest}" (added by #195) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n(pl): translate "Installed · latest {latest}" (added by #195) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * i18n(hu): translate "Installed · latest {latest}" (added by #195) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * hungarian test: count only the settings body's links, not the cards' Website links behind the modal #198 gave every card a Website link, and Hungarian labels both Webhely. * hungarian test: card links are 14px text, settings icons 24px; filter on that --------- Co-authored-by: DzikStar <82441193+DzikStar@users.noreply.github.com> Co-authored-by: Losminek <301412321+Losminek@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
@@ -76,10 +76,10 @@ colour tokens by name (`theme::Tokens`). Build new UI from `widgets.rs`; never h
|
||||
|
||||
Every user-facing string goes through `crates/ui-egui/src/i18n` (`tl!("…")` for literals, `fmt`
|
||||
for `{placeholders}`, `tn` for counts). English in the code is the lookup key; adding a string
|
||||
means adding its row to every catalog marked `complete_menus` (`ru.tsv`, `zh-CN.tsv`, `de.tsv`,
|
||||
`fr.tsv`, `pt-BR.tsv`, `pl.tsv`), which the i18n tests check. Translate clean-room from the
|
||||
meaning of the English text, never through another catalog. Product and app names (ArtCraft
|
||||
Launcher, Craft App Suite, PhotoCraft…) stay in English.
|
||||
means adding its row to every catalog marked `complete_menus` (the `*.tsv` files in
|
||||
`crates/ui-egui/src/i18n/`), which the i18n tests check. Translate clean-room from the meaning of
|
||||
the English text, never through another catalog. Product and app names (ArtCraft Launcher, Craft
|
||||
App Suite, PhotoCraft…) stay in English.
|
||||
Chinese is drawn with the system's own CJK font (`crates/ui-egui/src/cjk_font.rs`, desktop only;
|
||||
English where there is none): never bundle a CJK font, they are 10 MB and more.
|
||||
|
||||
|
||||
@@ -85,15 +85,16 @@ The web version shows the same catalog in the browser, with the latest download
|
||||
## Interface languages
|
||||
|
||||
The interface is in English, Brazilian Portuguese (Português (Brasil)), Czech (Čeština), French
|
||||
(Français), German (Deutsch), Polish (Polski), Russian (Русский), Simplified Chinese (简体中文) or
|
||||
Spanish (Español). **Auto**, the default, follows the system or browser language; **Settings →
|
||||
Language** picks one and switches at once, and the choice is kept between runs. Czech locales
|
||||
(`cs-CZ`, `cs_CZ.UTF-8`…) select Czech, German ones (`de-DE`, `de-AT`, `de-CH`, `de_DE.UTF-8`…)
|
||||
German, French ones (`fr-FR`, `fr-CA`…) French, Polish ones (`pl`, `pl-PL`, `pl_PL.UTF-8`) Polish,
|
||||
Spanish ones (`es-ES`, `es-MX`, `es-419`…) Spanish, and Portuguese ones (`pt-BR`, and `pt-PT` too,
|
||||
for now) Brazilian Portuguese. Simplified Chinese locales (`zh-CN`, `zh-SG`, `zh-Hans`, and POSIX
|
||||
forms such as `zh_CN.UTF-8`) select Chinese; Traditional Chinese ones don't. To try a language
|
||||
without changing the setting, start the desktop app with `ARTCRAFT_LAUNCHER_LOCALE=pt-BR`, or add
|
||||
(Français), German (Deutsch), Hungarian (Magyar), Polish (Polski), Russian (Русский), Simplified
|
||||
Chinese (简体中文) or Spanish (Español). **Auto**, the default, follows the system or browser
|
||||
language; **Settings → Language** picks one and switches at once, and the choice is kept between
|
||||
runs. Czech locales (`cs-CZ`, `cs_CZ.UTF-8`…) select Czech, German ones (`de-DE`, `de-AT`,
|
||||
`de-CH`, `de_DE.UTF-8`…) German, French ones (`fr-FR`, `fr-CA`…) French, Hungarian ones (`hu`,
|
||||
`hu-HU`, `hu_HU.UTF-8`…) Hungarian, Polish ones (`pl`, `pl-PL`, `pl_PL.UTF-8`) Polish, Spanish ones
|
||||
(`es-ES`, `es-MX`, `es-419`…) Spanish, and Portuguese ones (`pt-BR`, and `pt-PT` too, for now)
|
||||
Brazilian Portuguese. Simplified Chinese locales (`zh-CN`, `zh-SG`, `zh-Hans`, and POSIX forms such
|
||||
as `zh_CN.UTF-8`) select Chinese; Traditional Chinese ones don't. To try a language without
|
||||
changing the setting, start the desktop app with `ARTCRAFT_LAUNCHER_LOCALE=pt-BR`, or add
|
||||
`?lang=ru` to the web address.
|
||||
|
||||
Chinese is drawn with the system's own Chinese font (PingFang on macOS, Microsoft YaHei on
|
||||
|
||||
@@ -178,24 +178,71 @@ impl LauncherUi {
|
||||
}
|
||||
|
||||
fn settings_dialog(&mut self, ui: &mut egui::Ui, host: &mut dyn Host) -> bool {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
// Wide enough for the community buttons and every social icon on one row.
|
||||
ui.set_width(520.0);
|
||||
// Leave room for the frame (48 px) and a 16 px gutter on each side.
|
||||
let viewport = ui.ctx().content_rect();
|
||||
ui.set_width(520.0_f32.min((viewport.width() - 80.0).max(0.0)));
|
||||
// The area remembers its previous size. Reset the available height so the scroll area
|
||||
// measures against the viewport immediately, including on the first frame after a resize.
|
||||
ui.set_max_height((viewport.height() - 80.0).max(0.0));
|
||||
ui.spacing_mut().scroll = egui::style::ScrollStyle { foreground_color: true, ..egui::style::ScrollStyle::solid() };
|
||||
let title_top = ui.cursor().top();
|
||||
Self::title(ui, Some(crate::icons::artcraft_mark()), tl!("Settings"), &format!("ArtCraft Launcher {}", env!("CARGO_PKG_VERSION")));
|
||||
let title_height = ui.cursor().top() - title_top;
|
||||
let quit_width = widgets::button_width(ui, tl!("Quit ArtCraft Launcher"), 0.0);
|
||||
let done_width = widgets::button_width(ui, tl!("Done"), 90.0);
|
||||
let stack_actions = self.caps.manage_apps && quit_width + done_width + ui.spacing().item_spacing.x > ui.available_width();
|
||||
let footer_height = if stack_actions { 2.0 * theme::CONTROL_H + ui.spacing().item_spacing.y } else { theme::CONTROL_H };
|
||||
let body_height = (viewport.height() - 80.0 - title_height - footer_height - 24.0 - ui.spacing().item_spacing.y).max(0.0);
|
||||
egui::ScrollArea::vertical().id_salt("settings-body").max_height(body_height).auto_shrink([false, true]).show(ui, |ui| {
|
||||
self.settings_contents(ui, host);
|
||||
});
|
||||
|
||||
ui.add_space(24.0);
|
||||
let mut close = false;
|
||||
let quit = |ui: &mut egui::Ui, host: &mut dyn Host| {
|
||||
if self.caps.manage_apps && widgets::button(ui, tl!("Quit ArtCraft Launcher"), Kind::Secondary, 0.0).clicked() {
|
||||
host.quit();
|
||||
}
|
||||
};
|
||||
if stack_actions {
|
||||
quit(ui, host);
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
close = widgets::button(ui, tl!("Done"), Kind::Primary, 90.0).clicked();
|
||||
});
|
||||
} else {
|
||||
ui.horizontal(|ui| {
|
||||
quit(ui, host);
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
close = widgets::button(ui, tl!("Done"), Kind::Primary, 90.0).clicked();
|
||||
});
|
||||
});
|
||||
}
|
||||
close
|
||||
}
|
||||
|
||||
fn settings_contents(&mut self, ui: &mut egui::Ui, host: &mut dyn Host) {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
let section = |ui: &mut egui::Ui, s: &str| {
|
||||
ui.add_space(14.0);
|
||||
widgets::hud(ui, s, t.faint);
|
||||
ui.add_space(6.0);
|
||||
};
|
||||
let row = |ui: &mut egui::Ui, label: &str, add: &mut dyn FnMut(&mut egui::Ui)| {
|
||||
ui.horizontal(|ui| {
|
||||
let row = |ui: &mut egui::Ui, label: &str, control_width: f32, add: &mut dyn FnMut(&mut egui::Ui)| {
|
||||
let font = egui::TextStyle::Body.resolve(ui.style());
|
||||
let label_width = ui.painter().layout_no_wrap(label.to_string(), font, t.ink).size().x;
|
||||
if label_width + control_width + ui.spacing().item_spacing.x > ui.available_width() {
|
||||
ui.label(label);
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| add(ui));
|
||||
});
|
||||
add(ui);
|
||||
} else {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(label);
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| add(ui));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let mut lang_code = self.settings.language.clone();
|
||||
row(ui, tl!("Language"), &mut |ui| {
|
||||
row(ui, tl!("Language"), 180.0, &mut |ui| {
|
||||
egui::ComboBox::from_id_salt("language").selected_text(Settings::language_label(&lang_code)).width(180.0).show_ui(ui, |ui| {
|
||||
ui.selectable_value(&mut lang_code, Settings::LANGUAGE_AUTO.to_string(), tl!("Auto"));
|
||||
for lang in crate::i18n::Lang::all() {
|
||||
@@ -216,7 +263,7 @@ impl LauncherUi {
|
||||
|
||||
section(ui, tl!("Updates"));
|
||||
let mut every = self.settings.check_every;
|
||||
row(ui, tl!("Check for updates"), &mut |ui| {
|
||||
row(ui, tl!("Check for updates"), 150.0, &mut |ui| {
|
||||
egui::ComboBox::from_id_salt("every").selected_text(every.label()).width(150.0).show_ui(ui, |ui| {
|
||||
for e in CheckEvery::ALL {
|
||||
ui.selectable_value(&mut every, e, e.label());
|
||||
@@ -245,7 +292,7 @@ impl LauncherUi {
|
||||
None
|
||||
};
|
||||
let mut choice = self.settings.preferred_kinds.first().copied().or(default_kind);
|
||||
row(ui, tl!("Install new apps as"), &mut |ui| {
|
||||
row(ui, tl!("Install new apps as"), 210.0, &mut |ui| {
|
||||
let default_label = match default_kind {
|
||||
Some(k) => crate::i18n::t(k.label()),
|
||||
None => tl!("System package (recommended)"),
|
||||
@@ -290,7 +337,7 @@ impl LauncherUi {
|
||||
section(ui, tl!("Community"));
|
||||
ui.label(RichText::new(tl!("Questions, ideas and news from the ArtCraft team")).color(t.muted));
|
||||
ui.add_space(6.0);
|
||||
ui.horizontal(|ui| {
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
use artcraft_launcher_core::catalog::{DISCORD_URL, GITHUB_URL, WEBSITE_URL};
|
||||
if widgets::button(ui, tl!("Join the Discord"), Kind::Primary, 0.0).on_hover_text(DISCORD_URL).clicked() {
|
||||
ui.ctx().open_url(egui::OpenUrl::new_tab(DISCORD_URL));
|
||||
@@ -301,7 +348,10 @@ impl LauncherUi {
|
||||
if widgets::button(ui, tl!("GitHub"), Kind::Secondary, 0.0).on_hover_text(GITHUB_URL).clicked() {
|
||||
ui.ctx().open_url(egui::OpenUrl::new_tab(GITHUB_URL));
|
||||
}
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
// Wrap the social links as a group so their icons stay together.
|
||||
let count = artcraft_launcher_core::catalog::SOCIAL.len() as f32;
|
||||
let width = count * (16.0 + 8.0) + (count - 1.0).max(0.0) * 4.0;
|
||||
ui.allocate_ui_with_layout(vec2(width, theme::CONTROL_H), egui::Layout::left_to_right(egui::Align::Center), |ui| {
|
||||
ui.spacing_mut().item_spacing.x = 4.0;
|
||||
widgets::social_icons(ui, 16.0);
|
||||
});
|
||||
@@ -313,17 +363,5 @@ impl LauncherUi {
|
||||
widgets::cells(ui, &mut theme_choice, &ThemeChoice::ALL.map(|c| (c, Cell { label: c.label(), tip: c.label(), count: None })));
|
||||
});
|
||||
self.settings.theme = theme_choice;
|
||||
|
||||
ui.add_space(24.0);
|
||||
let mut close = false;
|
||||
ui.horizontal(|ui| {
|
||||
if self.caps.manage_apps && widgets::button(ui, tl!("Quit ArtCraft Launcher"), Kind::Secondary, 0.0).clicked() {
|
||||
host.quit();
|
||||
}
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
close = widgets::button(ui, tl!("Done"), Kind::Primary, 90.0).clicked();
|
||||
});
|
||||
});
|
||||
close
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
# Hungarian (hu) catalog for ArtCraft Launcher.
|
||||
# Format: context<TAB>source<TAB>translation
|
||||
# Empty context = plain UI string (tl!, t).
|
||||
# @id = command-id keyed (tr_id).
|
||||
# @plural = plural forms: one|other (English and Hungarian).
|
||||
# @msg = status/error message template (message, msg).
|
||||
# Other context = disambiguation for tr_ctx.
|
||||
#
|
||||
# Clean-room: written from the meaning of ArtCraft Launcher's English labels in neutral Hungarian,
|
||||
# using the terms Hungarian-speaking users of creative software know. The user is addressed with
|
||||
# the informal "te", as in most current creative and community software.
|
||||
#
|
||||
# Coverage: the whole interface — every menu string and tl! literal (complete_menus = true).
|
||||
# Left in English on purpose: product name "ArtCraft Launcher" (and its "Launcher" tag), suite
|
||||
# name "Craft App Suite",
|
||||
# app names (PhotoCraft, LightCraft, FilmCraft, DesignCraft, VectorCraft, PdfCraft, EffectCraft,
|
||||
# WordCraft, DeckCraft, GridCraft, CADCraft, SoundCraft), "GitHub", "Discord".
|
||||
# Shortcut keys keep their key-cap names (Shift, Alt, Ctrl, Cmd, Esc).
|
||||
# Trailing "…" (U+2026) must be preserved. Placeholders {name}, {n}, {version}, {count}, {v},
|
||||
# {what}, {unit}, {real}, {e} must appear in translation.
|
||||
|
||||
Launcher Launcher
|
||||
Craft App Suite Craft App Suite
|
||||
Open Source Tools for Creatives, Makers, and Builders Nyílt forráskódú eszközök alkotóknak, barkácsolóknak és fejlesztőknek
|
||||
Settings Beállítások
|
||||
Check for updates Frissítések keresése
|
||||
Grid Rács
|
||||
Table Táblázat
|
||||
Show apps as cards Alkalmazások megjelenítése kártyákként
|
||||
Show apps as a table Alkalmazások megjelenítése táblázatként
|
||||
All Összes
|
||||
Updates Frissítések
|
||||
Not installed Nincs telepítve
|
||||
Search apps Alkalmazások keresése
|
||||
Sort Rendezés
|
||||
Suite order Alapértelmezett sorrend
|
||||
Name Név
|
||||
Inspired by Mintául szolgált
|
||||
Status Állapot
|
||||
Installed version Telepített verzió
|
||||
Latest version Legújabb verzió
|
||||
Newest release Legújabb kiadás
|
||||
Discord Discord
|
||||
GitHub GitHub
|
||||
Website Webhely
|
||||
Classic apps Eredeti alkalmazások
|
||||
New apps Új alkalmazások
|
||||
NEW ÚJ
|
||||
Install Telepítés
|
||||
Update to {v} Frissítés: {v}
|
||||
Open Megnyitás
|
||||
Download for {os} Letöltés {os} rendszerre
|
||||
Download Letöltés
|
||||
Coming soon Hamarosan
|
||||
Checking… Ellenőrzés…
|
||||
Not available Nem elérhető
|
||||
Offline Nincs kapcsolat
|
||||
Downloading {done} of {total} Letöltés: {done} / {total}
|
||||
Downloading… Letöltés…
|
||||
Reconnecting… Újracsatlakozás…
|
||||
Verifying… Fájl ellenőrzése…
|
||||
Installing, then restarting… Telepítés, majd újraindítás…
|
||||
Installing… Telepítés…
|
||||
Removing… Eltávolítás…
|
||||
Pause download Letöltés szüneteltetése
|
||||
Cancel download Letöltés megszakítása
|
||||
Resume download Letöltés folytatása
|
||||
Discard download Letöltött fájl törlése
|
||||
Release notes Kiadási információk
|
||||
Show in Finder Megjelenítés a Finderben
|
||||
Show in Explorer Megjelenítés a Fájlkezelőben
|
||||
Show in Files Megjelenítés a fájlkezelőben
|
||||
Reinstall Újratelepítés
|
||||
Uninstall… Eltávolítás…
|
||||
All releases Minden kiadás
|
||||
ArtCraft Launcher {version} is available. Elérhető az ArtCraft Launcher új verziója: {version}.
|
||||
Dismiss Elrejtés
|
||||
Update and restart Frissítés és újraindítás
|
||||
A new version is available. Would you like to relaunch with the updated version? Új verzió érhető el. Újraindítod az alkalmazást a frissítéshez?
|
||||
Later Később
|
||||
What's new Újdonságok
|
||||
No notes were published with this release. Ehhez a kiadáshoz nem tettek közzé kiadási információkat.
|
||||
Released {date} Megjelent: {date}
|
||||
Open on GitHub Megnyitás a GitHubon
|
||||
Close Bezárás
|
||||
ArtCraft Launcher {version} ArtCraft Launcher {version}
|
||||
Only when I ask Csak kézi kereséskor
|
||||
Automatically download and install updates Frissítések automatikus letöltése és telepítése
|
||||
Notify me when an installed app has an update Értesítés a telepített alkalmazásokhoz elérhető frissítésekről
|
||||
Include pre-releases (betas and release candidates) Előzetes kiadások engedélyezése (béta- és kiadásra jelölt verziók)
|
||||
Installing on Linux Telepítés Linuxon
|
||||
Install new apps as Új alkalmazások csomagformátuma
|
||||
System package (recommended) Rendszercsomag (ajánlott)
|
||||
Updates always use the format an app was installed with. A frissítések mindig az eredeti telepítés csomagformátumát használják.
|
||||
Running in the background Futtatás a háttérben
|
||||
Keep running in the tray when the window is closed Az ablak bezárásakor kerüljön a tálcára
|
||||
Show the window on the current desktop Ablak megjelenítése az aktuális asztalon
|
||||
Start ArtCraft Launcher when I log in ArtCraft Launcher indítása bejelentkezéskor
|
||||
Community Közösség
|
||||
Questions, ideas and news from the ArtCraft team Kérdések, ötletek és hírek az ArtCraft csapatától
|
||||
Appearance Megjelenés
|
||||
Quit ArtCraft Launcher Kilépés az ArtCraft Launcherből
|
||||
Done Kész
|
||||
Uninstall {name}? {name} eltávolítása?
|
||||
The app will be moved to the Trash. Your documents and settings stay. Az alkalmazás a Kukába kerül. A dokumentumaid és beállításaid megmaradnak.
|
||||
Windows will remove it like any installed program. Your documents and settings stay. A Windows úgy távolítja el az alkalmazást, mint bármely más telepített programot. A dokumentumaid és beállításaid megmaradnak.
|
||||
Your system's package manager will remove it, and may ask for your password. Your documents and settings stay. Az alkalmazást a rendszer csomagkezelője távolítja el. Ehhez szükség lehet a jelszavadra. A dokumentumaid és beállításaid megmaradnak.
|
||||
The app will be removed. Your documents and settings stay. Eltávolítjuk az alkalmazást. A dokumentumaid és beállításaid megmaradnak.
|
||||
Uninstall Eltávolítás
|
||||
Cancel Mégse
|
||||
Checked {ago} Ellenőrizve: {ago}
|
||||
just now épp most
|
||||
yesterday tegnap
|
||||
{month} {day}, {year} {year}. {month} {day}.
|
||||
|
||||
Automatically Automatikusan
|
||||
Every Craft app Minden Craft-alkalmazás
|
||||
Apps on this computer Alkalmazások ezen a számítógépen
|
||||
Installed apps with a newer version Telepített alkalmazások, amelyekhez frissítés érhető el
|
||||
Apps you can install Telepíthető alkalmazások
|
||||
Checked {ago} · using {sources} Ellenőrizve: {ago} · {sources}
|
||||
{a} and {b} {a} és {b}
|
||||
Join the Discord Csatlakozás a Discordhoz
|
||||
Learn more További információ
|
||||
Minimize Kis méret
|
||||
Maximize Teljes méret
|
||||
Restore Előző méret
|
||||
New Új
|
||||
OK OK
|
||||
Open link Hivatkozás megnyitása
|
||||
Update Frissítés
|
||||
{name} icon {name} ikonja
|
||||
Loading ArtCraft Launcher… ArtCraft Launcher betöltése…
|
||||
Cancel update Frissítés megszakítása
|
||||
Stop waiting; the update can be started again later Megszakítja a várakozást. A frissítést később újra elindíthatod.
|
||||
Download again Újbóli letöltés
|
||||
Install cancelled Telepítés megszakítva
|
||||
Install cancelled. The download is kept for the next try. Telepítés megszakítva. A letöltött fájl megmarad a következő próbálkozáshoz.
|
||||
Update cancelled Frissítés megszakítva
|
||||
Uninstall cancelled Eltávolítás megszakítva
|
||||
Retry install Telepítés újrapróbálása
|
||||
Retry update to {version} Frissítés újrapróbálása: {version}
|
||||
The download is still here. It's checked again, then installed. A letöltött fájl megmaradt. Újra ellenőrizzük, majd telepítjük.
|
||||
Waiting for another app… Várakozás egy másik alkalmazásra…
|
||||
Waiting for other installs… Várakozás a többi telepítésre…
|
||||
|
||||
# Package formats offered for download (PackageKind::label)
|
||||
Installer (.msi) Telepítő (.msi)
|
||||
Portable (.zip) Hordozható (.zip)
|
||||
Disk image (.dmg) Lemezkép (.dmg)
|
||||
Debian package (.deb) Debian-csomag (.deb)
|
||||
RPM package (.rpm) RPM-csomag (.rpm)
|
||||
Flatpak bundle Flatpak-csomag
|
||||
Tarball (.tar.gz) Tömörített archívum (.tar.gz)
|
||||
|
||||
# Contextual: each app's tagline, keyed by app id
|
||||
photocraft Image editing Képszerkesztés
|
||||
vectorcraft Vector illustration Vektoros illusztráció
|
||||
filmcraft Video editing, color and sound Videószerkesztés, színkorrekció és hang
|
||||
lightcraft Photo library and raw development Fotók rendszerezése és RAW-előhívás
|
||||
pdfcraft Reading, organizing and protecting PDFs PDF-ek olvasása, rendezése és védelme
|
||||
effectcraft Motion graphics and visual effects Mozgógrafika és vizuális effektek
|
||||
designcraft Page layout and publishing Oldaltervezés és kiadványszerkesztés
|
||||
wordcraft Writing and document design Írás és dokumentumtervezés
|
||||
deckcraft Presentations and slide shows Prezentációk és diavetítések
|
||||
gridcraft Spreadsheets and data Táblázatok és adatok
|
||||
cadcraft Computer-aided design and drafting Számítógépes tervezés és műszaki rajz
|
||||
soundcraft Recording, editing and mixing audio Hangrögzítés, hangszerkesztés és keverés
|
||||
|
||||
# Contextual: month abbreviations for date rendering
|
||||
month Jan jan.
|
||||
month Feb febr.
|
||||
month Mar márc.
|
||||
month Apr ápr.
|
||||
month May máj.
|
||||
month Jun jún.
|
||||
month Jul júl.
|
||||
month Aug aug.
|
||||
month Sep szept.
|
||||
month Oct okt.
|
||||
month Nov nov.
|
||||
month Dec dec.
|
||||
Not checked yet Még nem történt ellenőrzés
|
||||
GitHub's hourly limit was reached; full details return in {min} min Elértük a GitHub óránkénti lekérdezési korlátját; a részletes adatok {min} perc múlva lesznek újra elérhetők
|
||||
GitHub limit hit; back in {min} min GitHub-korlát elérve; újrapróbálás {min} perc múlva
|
||||
Installing for {platform} Telepítés {platform} rendszerre
|
||||
Downloads for {platform} Letöltések {platform} rendszerre
|
||||
No downloads for this system Nincsenek letöltések ehhez a rendszerhez
|
||||
Join the ArtCraft community on Discord Csatlakozz az ArtCraft közösségéhez a Discordon
|
||||
ArtCraft on {name} ArtCraft – {name}
|
||||
Couldn't open {name}: {e} {name} nem nyitható meg: {e}
|
||||
Download cancelled Letöltés megszakítva
|
||||
Available to install Telepíthető
|
||||
Available Elérhető
|
||||
Installed · up to date Telepítve · naprakész
|
||||
Update available Frissítés elérhető
|
||||
Installed Telepítve
|
||||
installed telepítve
|
||||
Not available here Ezen a rendszeren nem érhető el
|
||||
Updating… Frissítés…
|
||||
Update paused Frissítés szüneteltetve
|
||||
Download paused Letöltés szüneteltetve
|
||||
{version} installed → {latest} released Telepítve: {version} → megjelent: {latest}
|
||||
Version {version} Verzió: {version}
|
||||
{installed} installed · latest {latest} Telepítve: {installed} · legújabb: {latest}
|
||||
Installed · latest {latest} Telepítve · legújabb: {latest}
|
||||
Version {version} installed Telepített verzió: {version}
|
||||
Version {latest} Verzió: {latest}
|
||||
No release published yet Még nem jelent meg kiadás
|
||||
ArtCraft Launcher ArtCraft Launcher
|
||||
App Alkalmazás
|
||||
Latest Legújabb
|
||||
Released Megjelent
|
||||
Auto Automatikus
|
||||
Language Nyelv
|
||||
Ascending Növekvő
|
||||
Descending Csökkenő
|
||||
Click to reverse the order Kattints a sorrend megfordításához
|
||||
Click to sort by this column Kattints az oszlop szerinti rendezéshez
|
||||
Like {name} Mintául szolgált: {name}
|
||||
{done} of {total} {done} / {total}
|
||||
Downloading Letöltés folyamatban
|
||||
Verifying checksum… Ellenőrzőösszeg ellenőrzése…
|
||||
Resume Folytatás
|
||||
{done} of {total} downloaded {done} / {total} letöltve
|
||||
{done} downloaded {done} letöltve
|
||||
Checking for updates… Frissítések keresése…
|
||||
Downloads the new version, replaces this one and opens it again Letölti és telepíti az új verziót, majd újraindítja az alkalmazást
|
||||
Couldn't check for updates: {f} Nem sikerült frissítéseket keresni: {f}
|
||||
Website (coming soon) Webhely (hamarosan)
|
||||
GitHub repository GitHub-tároló
|
||||
ArtCraft ArtCraft
|
||||
Update 1 app 1 alkalmazás frissítése
|
||||
Update all ({count}) Összes frissítése ({count})
|
||||
⊞ Grid ⊞ Rács
|
||||
☰ Table ☰ Táblázat
|
||||
🔍 Search apps 🔍 Alkalmazások keresése
|
||||
{name} {version} {name} {version}
|
||||
Match system Rendszerbeállítás szerint
|
||||
Dark Sötét
|
||||
Light Világos
|
||||
Full changelog Teljes változásnapló
|
||||
link hivatkozás
|
||||
No apps match Nincs találat
|
||||
Open ArtCraft Launcher to update. Nyisd meg az ArtCraft Launchert a frissítéshez.
|
||||
{name} {v} is available Elérhető: {name} {v}
|
||||
{count} updates are available {count} frissítés elérhető
|
||||
These notes weren't fetched (GitHub's request limit was reached). They're on the release page. A kiadási információkat nem sikerült betölteni, mert elértük a GitHub lekérdezési korlátját. A kiadás oldalán megtalálod őket.
|
||||
When on, opening the launcher from the menu bar brings its window to the desktop you're on. When off, macOS switches you to the desktop the window was on. Ha be van kapcsolva, a menüsorból megnyitott ArtCraft Launcher ablaka az aktuális asztalon jelenik meg. Ha ki van kapcsolva, a macOS arra az asztalra vált, ahol az ablak található.
|
||||
Couldn't change the login item: {e} Az automatikus indítás beállítását nem sikerült módosítani: {e}
|
||||
|
||||
# Contextual: table column headers
|
||||
column App Alkalmazás
|
||||
column Installed Telepített
|
||||
column Latest Legújabb
|
||||
column Released Dátum
|
||||
|
||||
# Contextual: the filter tab names a group (the status pill says "Installed")
|
||||
filter Installed Telepítve
|
||||
|
||||
# Plural forms for Hungarian (one|other). After a number the noun stays singular.
|
||||
@plural {n} app|{n} apps {n} alkalmazás|{n} alkalmazás
|
||||
@plural {n} min ago|{n} min ago {n} perce|{n} perce
|
||||
@plural {n} h ago|{n} h ago {n} órája|{n} órája
|
||||
@plural {n} day ago|{n} days ago {n} napja|{n} napja
|
||||
|
||||
# Message templates (@msg): toasts from the backend. {placeholders} match any text.
|
||||
@msg Couldn't open {name}: {e} {name} nem nyitható meg: {e}
|
||||
@msg Download cancelled Letöltés megszakítva
|
||||
@msg {name} updated to {version} {name} frissítve. Verzió: {version}
|
||||
@msg {name} installed: {version} {name} telepítve: {version}
|
||||
@msg {name} updated to {version} (this release publishes no checksum, so only its size was checked) {name} frissítve. Verzió: {version} (ehhez a kiadáshoz nem adtak meg ellenőrzőösszeget, ezért csak a fájl méretét ellenőriztük)
|
||||
@msg {name} installed: {version} (this release publishes no checksum, so only its size was checked) {name} telepítve: {version} (ehhez a kiadáshoz nem adtak meg ellenőrzőösszeget, ezért csak a fájl méretét ellenőriztük)
|
||||
@msg {name} was removed {name} eltávolítva
|
||||
@msg {name} is running. Quit it, then try again. {name} fut. Zárd be, majd próbáld újra.
|
||||
|
||||
# Command IDs for menu items (@id)
|
||||
# Format: @id<TAB>command_id<TAB>translation
|
||||
@id app.install Telepítés
|
||||
@id app.update Frissítés: {v}
|
||||
@id app.open Megnyitás
|
||||
@id app.download Letöltés {os} rendszerre
|
||||
@id app.reveal Megjelenítés a Finderben
|
||||
@id app.reinstall Újratelepítés
|
||||
@id app.uninstall Eltávolítás…
|
||||
@id app.notes Kiadási információk
|
||||
@id app.website Webhely
|
||||
@id app.github GitHub-tároló
|
||||
@id app.releases Minden kiadás
|
||||
@id launcher.update Frissítés és újraindítás
|
||||
@id launcher.download Letöltés
|
||||
@id launcher.notes Újdonságok
|
||||
@id launcher.dismiss Elrejtés
|
||||
@id settings.open Beállítások
|
||||
@id settings.quit Kilépés az ArtCraft Launcherből
|
||||
@id view.grid Rács
|
||||
@id view.table Táblázat
|
||||
@id filter.all Összes
|
||||
@id filter.installed Telepítve
|
||||
@id filter.updates Frissítések
|
||||
@id filter.notinstalled Nincs telepítve
|
||||
@id sort.suite Alapértelmezett sorrend
|
||||
@id sort.name Név
|
||||
@id sort.inspired Mintául szolgált
|
||||
@id sort.status Állapot
|
||||
@id sort.installed Telepített verzió
|
||||
@id sort.latest Legújabb verzió
|
||||
@id sort.released Legújabb kiadás
|
||||
@id help.discord Discord
|
||||
@id help.github GitHub
|
||||
@id help.website Webhely
|
||||
@id update.check Frissítések keresése
|
||||
@id update.check_auto Frissítések automatikus keresése
|
||||
@id update.notify Értesítés a telepített alkalmazásokhoz elérhető frissítésekről
|
||||
@id update.prereleases Előzetes kiadások engedélyezése (béta- és kiadásra jelölt verziók)
|
||||
@id linux.preferred_kind Új alkalmazások csomagformátuma
|
||||
@id tray.close_to_tray Az ablak bezárásakor kerüljön a tálcára
|
||||
@id tray.show_on_current_desktop Ablak megjelenítése az aktuális asztalon
|
||||
@id tray.login_item ArtCraft Launcher indítása bejelentkezéskor
|
||||
@id appearance.theme Megjelenés
|
||||
|
||||
# Tray (menu bar) menu and tooltip
|
||||
Show ArtCraft Launcher ArtCraft Launcher megjelenítése
|
||||
Check for Updates Frissítések keresése
|
||||
Visit getartcraft.com getartcraft.com megnyitása
|
||||
ArtCraft on GitHub ArtCraft a GitHubon
|
||||
Join the ArtCraft Discord Csatlakozás az ArtCraft Discord-közösségéhez
|
||||
@plural ArtCraft Launcher · {n} update available|ArtCraft Launcher · {n} updates available ArtCraft Launcher · {n} frissítés elérhető|ArtCraft Launcher · {n} frissítés elérhető
|
||||
|
Can't render this file because it contains an unexpected character in line 11 and column 16.
|
@@ -7,8 +7,8 @@ use super::detect::system_lang;
|
||||
|
||||
/// One supported UI language.
|
||||
pub struct LangInfo {
|
||||
/// Canonical BCP 47 code (`en`, `ru`, `zh-CN`, `de`, `fr`, `pt-BR`, `es`, `cs`, `pl`). Also the
|
||||
/// `interfaceLanguage` value.
|
||||
/// Canonical BCP 47 code (`en`, `ru`, `zh-CN`, `de`, `fr`, `pt-BR`, `es`, `cs`, `pl`, `hu`). Also
|
||||
/// the `interfaceLanguage` value.
|
||||
pub code: &'static str,
|
||||
/// The language's name in itself, shown in the Preferences dropdown.
|
||||
pub name: &'static str,
|
||||
@@ -19,7 +19,7 @@ pub struct LangInfo {
|
||||
pub cjk: bool,
|
||||
/// Catalog file contents (empty for the built-in English).
|
||||
pub source: &'static str,
|
||||
/// Plural form index for a count (English, German and Spanish: 0 = one, 1 = other; Russian:
|
||||
/// Plural form index for a count (English, German, Spanish and Hungarian: 0 = one, 1 = other; Russian:
|
||||
/// 0 = one, 1 = few, 2 = many; Czech: 0 = one, 1 = few, 2 = other; Polish: 0 = one only for 1,
|
||||
/// 1 = few, 2 = many; French: 0 = one for 0 and 1; Chinese: always 0).
|
||||
pub plural: fn(u64) -> usize,
|
||||
@@ -79,7 +79,7 @@ pub(super) fn plural_polish(n: u64) -> usize {
|
||||
}
|
||||
|
||||
/// The registry. English first: it is the fallback and the source language.
|
||||
pub static LANGUAGES: [LangInfo; 9] = [
|
||||
pub static LANGUAGES: [LangInfo; 10] = [
|
||||
LangInfo {
|
||||
code: "en",
|
||||
name: "English",
|
||||
@@ -179,6 +179,17 @@ pub static LANGUAGES: [LangInfo; 9] = [
|
||||
complete_menus: true,
|
||||
catalog: OnceLock::new(),
|
||||
},
|
||||
LangInfo {
|
||||
code: "hu",
|
||||
name: "Magyar",
|
||||
english_name: "Hungarian",
|
||||
cjk: false,
|
||||
source: include_str!("hu.tsv"),
|
||||
plural: plural_one_other,
|
||||
plural_forms: 2,
|
||||
complete_menus: true,
|
||||
catalog: OnceLock::new(),
|
||||
},
|
||||
];
|
||||
|
||||
impl LangInfo {
|
||||
@@ -215,6 +226,7 @@ impl Lang {
|
||||
pub const ES: Lang = Lang(&LANGUAGES[6]);
|
||||
pub const CS: Lang = Lang(&LANGUAGES[7]);
|
||||
pub const PL: Lang = Lang(&LANGUAGES[8]);
|
||||
pub const HU: Lang = Lang(&LANGUAGES[9]);
|
||||
|
||||
pub fn code(self) -> &'static str {
|
||||
self.0.code
|
||||
|
||||
@@ -289,6 +289,24 @@ fn german_counts_dates_and_messages_work() {
|
||||
assert_eq!(tr(Lang::DE, "Untranslated diagnostic"), "Untranslated diagnostic");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hungarian_locales_and_plurals_work() {
|
||||
for tag in ["hu", "hu-HU", "hu_HU.UTF-8", "HU_hu"] {
|
||||
assert_eq!(lang_from_tag(tag), Some(Lang::HU), "{tag}");
|
||||
}
|
||||
assert_eq!(super::detect::first_supported(["xx-XX", "hu-HU", "en-US"]), Some(Lang::HU));
|
||||
// After a number the noun stays singular; 1 is still the "one" form.
|
||||
assert_eq!(trn(Lang::HU, 0, "{n} app", "{n} apps"), "0 alkalmazás");
|
||||
assert_eq!(trn(Lang::HU, 1, "{n} app", "{n} apps"), "1 alkalmazás");
|
||||
assert_eq!(trn(Lang::HU, 2, "{n} app", "{n} apps"), "2 alkalmazás");
|
||||
assert_eq!(trn(Lang::HU, 21, "{n} day ago", "{n} days ago"), "21 napja");
|
||||
assert_eq!(trn(Lang::HU, 1, "{n} day ago", "{n} days ago"), "1 napja");
|
||||
assert_eq!(super::tr_ctx(Lang::HU, "month", "Mar"), "márc.");
|
||||
assert_eq!(tr(Lang::HU, "{month} {day}, {year}"), "{year}. {month} {day}.");
|
||||
assert_eq!(message(Lang::HU, "PhotoCraft updated to 0.5.0"), "PhotoCraft frissítve. Verzió: 0.5.0");
|
||||
assert_eq!(tr(Lang::HU, "Untranslated diagnostic"), "Untranslated diagnostic");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn french_locales_and_plurals_work() {
|
||||
for tag in ["fr", "fr-FR", "fr_CA.UTF-8", "fr-BE", "FR_ch"] {
|
||||
|
||||
@@ -300,6 +300,12 @@ pub enum Kind {
|
||||
Danger,
|
||||
}
|
||||
|
||||
/// The natural width of a button, including its horizontal padding.
|
||||
pub fn button_width(ui: &Ui, text: &str, minimum: f32) -> f32 {
|
||||
let galley = caps(ui, text, theme::HUD_SIZE, theme::mono_bold(), theme::BUTTON_SPACING, Tokens::get(ui.ctx()).ink);
|
||||
(galley.size().x + 32.0).max(minimum)
|
||||
}
|
||||
|
||||
/// A square button with a mono upper-case label, at least `width` wide.
|
||||
pub fn button(ui: &mut Ui, text: &str, kind: Kind, width: f32) -> Response {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
//! The Hungarian UI, in its own test binary: the UI language is process-wide, so it can't share one
|
||||
//! with the English UI tests. `ARTCRAFT_LAUNCHER_SNAPSHOTS=<dir>` also saves screenshots (run with
|
||||
//! `-- --test-threads=1`, see `ui.rs`).
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use artcraft_launcher_core::protocol::{Backend, Capabilities, Command, Event, JobPhase, LatestRelease, Origin, Source};
|
||||
use artcraft_launcher_core::release::{Asset, Release};
|
||||
use artcraft_launcher_core::status::InstallSource;
|
||||
use artcraft_launcher_core::{Arch, Installed, Os, Platform, SUITE, version};
|
||||
use artcraft_launcher_ui_egui::settings::ViewMode;
|
||||
use artcraft_launcher_ui_egui::{Host, LauncherUi, Settings};
|
||||
use egui_kittest::Harness;
|
||||
use egui_kittest::kittest::Queryable;
|
||||
|
||||
const NOW: i64 = 1_791_500_000;
|
||||
|
||||
struct Fake {
|
||||
events: Vec<Event>,
|
||||
clock: Rc<Cell<i64>>,
|
||||
os: Os,
|
||||
}
|
||||
|
||||
impl Backend for Fake {
|
||||
fn send(&mut self, _command: Command) {}
|
||||
fn poll(&mut self) -> Vec<Event> {
|
||||
std::mem::take(&mut self.events)
|
||||
}
|
||||
fn capabilities(&self) -> Capabilities {
|
||||
Capabilities { manage_apps: true, reveal_label: "Show in Finder", self_update: true }
|
||||
}
|
||||
fn platform(&self) -> Option<Platform> {
|
||||
Some(Platform { os: self.os, arch: Arch::Arm64 })
|
||||
}
|
||||
fn now(&self) -> i64 {
|
||||
self.clock.get()
|
||||
}
|
||||
}
|
||||
|
||||
struct DesktopHost;
|
||||
impl Host for DesktopHost {
|
||||
fn has_tray(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn login_item(&self) -> Option<bool> {
|
||||
Some(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn release(id: &str, v: &str, at: i64) -> Release {
|
||||
let name = format!("{id}-{v}-macos-universal.dmg");
|
||||
Release {
|
||||
tag: format!("v{v}"),
|
||||
version: version::parse(v),
|
||||
name: format!("v{v}"),
|
||||
published_at: Some(at),
|
||||
html_url: format!("https://github.com/storytold/{id}/releases/tag/v{v}"),
|
||||
notes: String::new(),
|
||||
prerelease: false,
|
||||
assets: vec![Asset {
|
||||
name: name.clone(),
|
||||
size: 150 << 20,
|
||||
url: format!("https://github.com/storytold/{id}/releases/download/v{v}/{name}"),
|
||||
sha256: None,
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
fn events() -> Vec<Event> {
|
||||
let mut ev = Vec::new();
|
||||
for (i, app) in SUITE.iter().enumerate() {
|
||||
let latest = LatestRelease::Found(release(app.id, "0.5.0", NOW - 40 * 86_400 - i as i64 * 600));
|
||||
ev.push(Event::Latest { app: app.id.into(), latest, from: Origin::ArtCraftApi });
|
||||
let installed = matches!(app.id, "photocraft" | "lightcraft").then(|| Installed {
|
||||
version: version::parse(if app.id == "photocraft" { "0.4.1" } else { "0.5.0" }),
|
||||
source: InstallSource::MacApp,
|
||||
location: format!("/Applications/{}.app", app.name),
|
||||
package: None,
|
||||
});
|
||||
ev.push(Event::Detected { app: app.id.into(), installed });
|
||||
}
|
||||
ev.push(Event::Progress { app: "filmcraft".into(), phase: JobPhase::Verifying });
|
||||
ev.push(Event::CheckFinished { at: NOW - 180, source: Source::Feed, rate_limited_until: None });
|
||||
// A backend message, translated through its `@msg` template where it's shown.
|
||||
ev.push(Event::JobFinished { app: "lightcraft".into(), result: Ok("LightCraft updated to 0.5.0".into()) });
|
||||
ev
|
||||
}
|
||||
|
||||
fn harness(view: ViewMode) -> Harness<'static, Option<LauncherUi>> {
|
||||
harness_on(view, Os::MacOs)
|
||||
}
|
||||
|
||||
fn harness_on(view: ViewMode, os: Os) -> Harness<'static, Option<LauncherUi>> {
|
||||
artcraft_launcher_ui_egui::i18n::set_test_lang(artcraft_launcher_ui_egui::i18n::Lang::EN);
|
||||
let mut backend = Some(Fake { events: events(), clock: Rc::new(Cell::new(NOW)), os });
|
||||
let settings =
|
||||
Settings { view, notify: false, language: "hu".into(), theme: artcraft_launcher_ui_egui::theme::ThemeChoice::Dark, ..Settings::default() };
|
||||
Harness::builder().with_size(egui::vec2(1180.0, 900.0)).with_theme(egui::Theme::Dark).build_ui_state(
|
||||
move |ui, state: &mut Option<LauncherUi>| {
|
||||
if state.is_none()
|
||||
&& let Some(b) = backend.take()
|
||||
{
|
||||
*state = Some(LauncherUi::new(ui.ctx(), Box::new(b), settings.clone()));
|
||||
}
|
||||
if let Some(l) = state.as_mut() {
|
||||
l.logic(&ui.ctx().clone(), &mut DesktopHost);
|
||||
l.ui(ui, &mut DesktopHost);
|
||||
}
|
||||
},
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
fn snapshot(h: &mut Harness<'_, Option<LauncherUi>>, name: &str) {
|
||||
let Some(dir) = std::env::var_os("ARTCRAFT_LAUNCHER_SNAPSHOTS") else { return };
|
||||
let img = h.render().unwrap();
|
||||
img.save(std::path::Path::new(&dir).join(format!("{name}.png"))).unwrap();
|
||||
}
|
||||
|
||||
// One test: the UI language is process-wide.
|
||||
#[test]
|
||||
fn hungarian_ui_translates_labels_dates_and_messages() {
|
||||
let mut h = harness(ViewMode::Grid);
|
||||
h.run_steps(8);
|
||||
snapshot(&mut h, "grid-hu-dark");
|
||||
// Product names stay in English.
|
||||
h.get_by_label("Launcher");
|
||||
h.get_by_label("Craft App Suite");
|
||||
h.get_by_label("Képszerkesztés");
|
||||
h.get_by_label("Frissítés: 0.5.0");
|
||||
h.get_by_label_contains("Ellenőrzőösszeg ellenőrzése…");
|
||||
h.get_by_label_contains("Ellenőrizve: 3 perce · ArtCraft API");
|
||||
h.get_by_label("LightCraft frissítve. Verzió: 0.5.0");
|
||||
|
||||
let mut table = harness(ViewMode::Table);
|
||||
table.run_steps(8);
|
||||
snapshot(&mut table, "table-hu-dark");
|
||||
table.get_by_label("Telepített");
|
||||
assert!(table.query_all_by_label_contains("2026. aug.").count() >= 1);
|
||||
check_settings_layout();
|
||||
}
|
||||
|
||||
/// Checks the actual modal after resizing it while open, including Linux's extra controls.
|
||||
fn check_settings_layout() {
|
||||
let mut h = harness_on(ViewMode::Grid, Os::Linux);
|
||||
h.run_steps(8);
|
||||
h.get_by_label("Beállítások").click();
|
||||
h.run_steps(8);
|
||||
for (width, height) in [(1180.0, 900.0), (720.0, 500.0), (480.0, 500.0), (1180.0, 900.0)] {
|
||||
h.set_size(egui::vec2(width, height));
|
||||
h.run_steps(8);
|
||||
let screen = egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(width, height));
|
||||
let done = h.get_by_label("Kész").rect();
|
||||
let quit = h.get_by_label("Kilépés az ArtCraft Launcherből").rect();
|
||||
assert!(screen.contains_rect(done), "{width}x{height}: Done is clipped: {done:?}");
|
||||
assert!(screen.contains_rect(quit), "{width}x{height}: Quit is clipped: {quit:?}");
|
||||
assert!(!done.intersects(quit));
|
||||
let title = h.get_all_by_label("Beállítások").last().unwrap().rect();
|
||||
assert!(screen.contains_rect(title), "{width}x{height}: title is clipped: {title:?}");
|
||||
h.get_by_label("Rendszerbeállítás szerint").scroll_to_me();
|
||||
h.run_steps(8);
|
||||
// The footer has the same services, and the cards behind the modal have Webhely and GitHub
|
||||
// links as one 14px line of text; keep only the settings body's buttons (34px) and icons (24px).
|
||||
let discord = h.get_by_label("Csatlakozás a Discordhoz").rect();
|
||||
let theme = h.get_by_label("Rendszerbeállítás szerint").rect();
|
||||
assert!(screen.contains_rect(discord), "community links must be reachable by scrolling");
|
||||
assert!(theme.bottom() < done.top(), "appearance controls must scroll above the fixed actions");
|
||||
let mut links = vec![discord];
|
||||
for label in ["Webhely", "GitHub", "X", "Instagram", "LinkedIn", "YouTube", "TikTok"] {
|
||||
let candidates: Vec<_> = h
|
||||
.query_all_by_label(label)
|
||||
.map(|n| n.rect())
|
||||
.filter(|r| r.top() >= discord.top() - 1.0 && r.bottom() < theme.top() && r.height() > 20.0)
|
||||
.collect();
|
||||
assert_eq!(candidates.len(), 1, "{width}x{height}: settings link {label}: {candidates:?}");
|
||||
links.extend(candidates);
|
||||
}
|
||||
for (i, r) in links.iter().enumerate() {
|
||||
assert!(screen.contains_rect(*r), "{width}x{height}: link is clipped: {r:?}");
|
||||
for other in links.iter().skip(i + 1) {
|
||||
assert!(!r.intersects(*other), "{width}x{height}: links overlap: {r:?}, {other:?}");
|
||||
}
|
||||
}
|
||||
snapshot(&mut h, &format!("settings-hu-{width}x{height}-bottom"));
|
||||
h.get_by_label("Nyelv").scroll_to_me();
|
||||
h.run_steps(8);
|
||||
let language = h.get_by_label("Nyelv").rect();
|
||||
assert!(screen.contains_rect(language), "the top of settings must remain reachable");
|
||||
snapshot(&mut h, &format!("settings-hu-{width}x{height}-top"));
|
||||
}
|
||||
h.get_by_label("Kész").click();
|
||||
h.run_steps(4);
|
||||
assert!(h.query_by_label("Kész").is_none(), "Done must still close the resized dialog");
|
||||
}
|
||||
Reference in New Issue
Block a user