Add a Brazilian Portuguese (pt-BR) interface (#92)

* Add Brazilian Portuguese (pt-BR) UI localization

* Rebase onto German and French: pt-BR last in the registry, new update strings

Document that pt-PT falls back to Brazilian Portuguese; smoother wording for
'Verifying checksum…'.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: AlastorIRL <100581152+AlastorIRL@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ItsAlastor 2026-10-11 03:36:06 -03:00 committed by GitHub
parent 89854ff8f2
commit 2b1b4412e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 456 additions and 8 deletions

View File

@ -84,13 +84,15 @@ The web version shows the same catalog in the browser, with the latest download
## Interface languages ## Interface languages
The interface is in English, French (Français), German (Deutsch), Russian (Русский) or Simplified Chinese The interface is in English, Brazilian Portuguese (Português (Brasil)), French (Français), German
(简体中文). **Auto**, the default, follows the system or browser language; **Settings → Language** (Deutsch), Russian (Русский) or Simplified Chinese (简体中文). **Auto**, the default, follows the
picks one and switches at once, and the choice is kept between runs. German locales (`de-DE`, system or browser language; **Settings → Language** picks one and switches at once, and the choice
`de-AT`, `de-CH`, `de_DE.UTF-8`…) select German, and French ones (`fr-FR`, `fr-CA`…) French. Simplified Chinese locales (`zh-CN`, `zh-SG`, is kept between runs. German locales (`de-DE`, `de-AT`, `de-CH`, `de_DE.UTF-8`…) select German,
`zh-Hans`, and POSIX forms such as `zh_CN.UTF-8`) select Chinese; Traditional Chinese ones don't. French ones (`fr-FR`, `fr-CA`…) French, and Portuguese ones (`pt-BR`, and `pt-PT` too, for now)
To try a language without changing the setting, start the desktop app with Brazilian Portuguese. Simplified Chinese locales (`zh-CN`, `zh-SG`, `zh-Hans`, and POSIX forms such
`ARTCRAFT_LAUNCHER_LOCALE=zh-CN`, or add `?lang=ru` to the web address. 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 Chinese is drawn with the system's own Chinese font (PingFang on macOS, Microsoft YaHei on
Windows, Noto Sans CJK or WenQuanYi on Linux and FreeBSD). Where there is none, and in the web Windows, Noto Sans CJK or WenQuanYi on Linux and FreeBSD). Where there is none, and in the web

View File

@ -56,7 +56,7 @@ pub(super) fn plural_east_slavic(n: u64) -> usize {
} }
/// The registry. English first: it is the fallback and the source language. /// The registry. English first: it is the fallback and the source language.
pub static LANGUAGES: [LangInfo; 5] = [ pub static LANGUAGES: [LangInfo; 6] = [
LangInfo { LangInfo {
code: "en", code: "en",
name: "English", name: "English",
@ -112,6 +112,17 @@ pub static LANGUAGES: [LangInfo; 5] = [
complete_menus: true, complete_menus: true,
catalog: OnceLock::new(), catalog: OnceLock::new(),
}, },
LangInfo {
code: "pt-BR",
name: "Português (Brasil)",
english_name: "Portuguese (Brazil)",
cjk: false,
source: include_str!("pt-BR.tsv"),
plural: plural_one_other,
plural_forms: 2,
complete_menus: true,
catalog: OnceLock::new(),
},
]; ];
impl LangInfo { impl LangInfo {
@ -144,6 +155,7 @@ impl Lang {
pub const ZH_CN: Lang = Lang(&LANGUAGES[2]); pub const ZH_CN: Lang = Lang(&LANGUAGES[2]);
pub const DE: Lang = Lang(&LANGUAGES[3]); pub const DE: Lang = Lang(&LANGUAGES[3]);
pub const FR: Lang = Lang(&LANGUAGES[4]); pub const FR: Lang = Lang(&LANGUAGES[4]);
pub const PT_BR: Lang = Lang(&LANGUAGES[5]);
pub fn code(self) -> &'static str { pub fn code(self) -> &'static str {
self.0.code self.0.code
@ -209,6 +221,7 @@ pub fn lang_from_tag(tag: &str) -> Option<Lang> {
match cands.last().map(String::as_str) { match cands.last().map(String::as_str) {
Some("c" | "posix") => Some(Lang::EN), Some("c" | "posix") => Some(Lang::EN),
Some("zh") => chinese(cands.first().map_or("zh", String::as_str)), Some("zh") => chinese(cands.first().map_or("zh", String::as_str)),
Some("pt") => Some(Lang::PT_BR),
_ => cands.iter().find_map(|c| Lang::from_code(c)), _ => cands.iter().find_map(|c| Lang::from_code(c)),
} }
} }

View File

@ -0,0 +1,314 @@
# Brazilian Portuguese (pt-BR) 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.
# @msg = status/error message template (message, msg).
# Other context = disambiguation for tr_ctx.
Launcher Launcher
Craft App Suite Craft App Suite
Open Source Tools for Creatives, Makers, and Builders Ferramentas de código aberto para criadores, artistas e desenvolvedores
Settings Configurações
Check for updates Verificar atualizações
Grid Grade
Table Tabela
Show apps as cards Mostrar aplicativos como cartões
Show apps as a table Mostrar aplicativos como tabela
All Todos
Updates Atualizações
Not installed Não instalados
Search apps Buscar aplicativos
Sort Ordenar
Suite order Ordem da suíte
Name Nome
Inspired by Inspirado em
Status Status
Installed version Versão instalada
Latest version Última versão
Newest release Lançamento mais recente
Discord Discord
GitHub GitHub
Website Site
Classic apps Aplicativos clássicos
New apps Novos aplicativos
Classic Clássico
NEW NOVO
Install Instalar
Update to {v} Atualizar para {v}
Open Abrir
Download for {os} Baixar para {os}
Download Baixar
Coming soon Em breve
Checking… Verificando…
Not available Indisponível
Offline Offline
Downloading {done} of {total} Baixando {done} de {total}
Downloading… Baixando…
Reconnecting… Reconectando…
Verifying… Verificando…
Installing, then restarting… Instalando e reiniciando…
Installing… Instalando…
Removing… Removendo…
Pause download Pausar download
Cancel download Cancelar download
Resume download Retomar download
Discard download Descartar download
Release notes Notas de lançamento
Show in Finder Mostrar no Finder
Show in Explorer Mostrar no Explorer
Show in Files Mostrar no gerenciador de arquivos
Reinstall Reinstalar
Uninstall… Desinstalar…
All releases Todos os lançamentos
ArtCraft Launcher {version} is available. ArtCraft Launcher {version} está disponível.
Dismiss Dispensar
Update and restart Atualizar e reiniciar
A new version is available. Would you like to relaunch with the updated version? Uma nova versão está disponível. Reiniciar com a nova versão?
Later Mais tarde
What's new Novidades
No notes were published with this release. Nenhuma nota foi publicada com este lançamento.
Released {date} Lançado em {date}
Open on GitHub Abrir no GitHub
Close Fechar
ArtCraft Launcher {version} ArtCraft Launcher {version}
Only when I ask Apenas quando eu pedir
Automatically download and install updates Baixar e instalar atualizações automaticamente
Notify me when an installed app has an update Notificar quando um aplicativo instalado tiver atualização
Include pre-releases (betas and release candidates) Incluir versões de pré-lançamento (betas e RC)
Installing on Linux Instalação no Linux
Install new apps as Instalar novos aplicativos como
System package (recommended) Pacote do sistema (recomendado)
Updates always use the format an app was installed with. As atualizações sempre usam o formato com o qual o aplicativo foi instalado.
Running in the background Execução em segundo plano
Keep running in the tray when the window is closed Continuar na bandeja do sistema ao fechar a janela
Show the window on the current desktop Mostrar a janela na área de trabalho atual
Start ArtCraft Launcher when I log in Iniciar o ArtCraft Launcher ao fazer login
Community Comunidade
Questions, ideas and news from the ArtCraft team Dúvidas, ideias e novidades da equipe ArtCraft
Appearance Aparência
Quit ArtCraft Launcher Sair do ArtCraft Launcher
Done Concluído
Uninstall {name}? Desinstalar {name}?
The app will be moved to the Trash. Your documents and settings stay. O aplicativo será movido para a Lixeira. Seus documentos e configurações serão mantidos.
Windows will remove it like any installed program. Your documents and settings stay. O Windows o removerá como qualquer programa instalado. Seus documentos e configurações serão mantidos.
Your system's package manager will remove it, and may ask for your password. Your documents and settings stay. O gerenciador de pacotes do sistema o removerá e poderá pedir sua senha. Seus documentos e configurações serão mantidos.
The app will be removed. Your documents and settings stay. O aplicativo será removido. Seus documentos e configurações serão mantidos.
Uninstall Desinstalar
Cancel Cancelar
Checked {ago} Verificado {ago}
just now agora mesmo
yesterday ontem
{month} {day}, {year} {day} de {month} de {year}
Automatically Automaticamente
Every Craft app Todos os aplicativos Craft
Apps on this computer Aplicativos neste computador
Installed apps with a newer version Aplicativos instalados com nova versão
Apps you can install Aplicativos que você pode instalar
Checked {ago} · using {sources} Verificado {ago} · via {sources}
{a} and {b} {a} e {b}
Join the Discord Entrar no Discord
Learn more Saiba mais
Minimize Minimizar
Maximize Maximizar
Restore Restaurar
New Novo
OK OK
Open link Abrir link
Update Atualizar
{name} icon Ícone do {name}
Loading ArtCraft Launcher… Carregando ArtCraft Launcher…
Cancel update Cancelar atualização
Stop waiting; the update can be started again later Parar de aguardar; a atualização pode ser iniciada novamente depois
Download again Baixar novamente
Install cancelled Instalação cancelada
Install cancelled. The download is kept for the next try. Instalação cancelada. O download foi mantido para a próxima tentativa.
Update cancelled Atualização cancelada
Uninstall cancelled Desinstalação cancelada
Retry install Tentar instalar novamente
Retry update to {version} Tentar atualizar novamente para {version}
The download is still here. It's checked again, then installed. O arquivo baixado ainda está aqui. Ele será verificado novamente e instalado.
Waiting for another app… Aguardando outro aplicativo…
Waiting for other installs… Aguardando outras instalações…
# Package formats offered for download (PackageKind::label)
Installer (.msi) Instalador (.msi)
Portable (.zip) Portátil (.zip)
Disk image (.dmg) Imagem de disco (.dmg)
Debian package (.deb) Pacote Debian (.deb)
RPM package (.rpm) Pacote RPM (.rpm)
Flatpak bundle Pacote Flatpak
Tarball (.tar.gz) Arquivo (.tar.gz)
# Contextual: each app's tagline, keyed by app id
photocraft Image editing Edição de imagens
vectorcraft Vector illustration Ilustração vetorial
filmcraft Video editing, color and sound Edição de vídeo, cor e som
lightcraft Photo library and raw development Biblioteca de fotos e revelação RAW
pdfcraft Reading, organizing and protecting PDFs Leitura, organização e proteção de PDFs
effectcraft Motion graphics and visual effects Motion graphics e efeitos visuais
designcraft Page layout and publishing Diagramação de páginas e publicação
wordcraft Writing and document design Escrita e design de documentos
deckcraft Presentations and slide shows Apresentações e slides
gridcraft Spreadsheets and data Planilhas e dados
cadcraft Computer-aided design and drafting Desenho técnico e projeto assistido por computador (CAD)
soundcraft Recording, editing and mixing audio Gravação, edição e mixagem de áudio
# Contextual: month abbreviations for date rendering
month Jan jan.
month Feb fev.
month Mar mar.
month Apr abr.
month May mai.
month Jun jun.
month Jul jul.
month Aug ago.
month Sep set.
month Oct out.
month Nov nov.
month Dec dez.
Not checked yet Ainda não verificado
GitHub's hourly limit was reached; full details return in {min} min O limite por hora do GitHub foi atingido; detalhes completos voltam em {min} min
Installing for {platform} Instalando para {platform}
Downloads for {platform} Downloads para {platform}
No downloads for this system Nenhum download disponível para este sistema
Join the ArtCraft community on Discord Entre na comunidade ArtCraft no Discord
ArtCraft on {name} ArtCraft no {name}
Couldn't open {name}: {e} Não foi possível abrir {name}: {e}
Download cancelled Download cancelado
Available to install Disponível para instalar
Available Disponível
Installed · up to date Instalado · atualizado
Update available Atualização disponível
Installed Instalado
installed instalado
Not available here Indisponível neste sistema
Updating… Atualizando…
Update paused Atualização pausada
Download paused Download pausado
{version} installed → {latest} released {version} instalado → {latest} lançado
Version {version} Versão {version}
{installed} installed · latest {latest} {installed} instalado · última {latest}
Version {version} installed Versão {version} instalada
Version {latest} Versão {latest}
No release published yet Nenhum lançamento publicado ainda
ArtCraft Launcher ArtCraft Launcher
App Aplicativo
Latest Última
Released Lançado
Auto Automático
Language Idioma
Ascending Crescente
Descending Decrescente
Click to reverse the order Clique para inverter a ordem
Click to sort by this column Clique para ordenar por esta coluna
Like {name} Similar ao {name}
{done} of {total} {done} de {total}
Downloading Baixando
Verifying checksum… Conferindo a soma de verificação…
Resume Retomar
{done} of {total} downloaded {done} de {total} baixado
{done} downloaded {done} baixado
Checking for updates… Verificando atualizações…
Downloads the new version, replaces this one and opens it again Baixa a nova versão, substitui a atual e abre novamente
Couldn't check for updates: {f} Não foi possível verificar atualizações: {f}
Website (coming soon) Site (em breve)
GitHub repository Repositório no GitHub
ArtCraft ArtCraft
Update 1 app Atualizar 1 aplicativo
Update all ({count}) Atualizar todos ({count})
⊞ Grid ⊞ Grade
☰ Table ☰ Tabela
🔍 Search apps 🔍 Buscar aplicativos
{name} {version} {name} {version}
Match system Igual ao sistema
Dark Escuro
Light Claro
Full changelog Histórico completo de alterações
link link
No apps match Nenhum aplicativo encontrado
Open ArtCraft Launcher to update. Abra o ArtCraft Launcher para atualizar.
{name} {v} is available {name} {v} está disponível
{count} updates are available {count} atualizações estão disponíveis
These notes weren't fetched (GitHub's request limit was reached). They're on the release page. Estas notas não foram carregadas (o limite de requisições do GitHub foi atingido). Elas estão na página de lançamentos.
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. Quando ativado, abrir o launcher pela barra de menus traz a janela para a área de trabalho atual. Quando desativado, o macOS alterna para a área de trabalho onde a janela estava.
Couldn't change the login item: {e} Não foi possível alterar o item de inicialização no login: {e}
# Contextual: table column headers
column App Aplicativo
column Installed Instalada
column Latest Última
column Released Lançamento
# Contextual: the filter tab names a group (the status pill says "Installed")
filter Installed Instalados
# Plural forms for Brazilian Portuguese (one|other)
@plural {n} app|{n} apps {n} aplicativo|{n} aplicativos
@plural {n} min ago|{n} min ago há {n} min|há {n} min
@plural {n} h ago|{n} h ago há {n} h|há {n} h
@plural {n} day ago|{n} days ago há {n} dia|há {n} dias
# Message templates (@msg): toasts from the backend. {placeholders} match any text.
@msg Couldn't open {name}: {e} Não foi possível abrir {name}: {e}
@msg Download cancelled Download cancelado
@msg {name} updated to {version} {name} atualizado para {version}
@msg {name} installed: {version} {name} instalado: {version}
@msg {name} updated to {version} (this release publishes no checksum, so only its size was checked) {name} atualizado para {version} (este lançamento não publica soma de verificação, então apenas o tamanho foi verificado)
@msg {name} installed: {version} (this release publishes no checksum, so only its size was checked) {name} instalado: {version} (este lançamento não publica soma de verificação, então apenas o tamanho foi verificado)
@msg {name} was removed {name} foi removido
@msg {name} is running. Quit it, then try again. {name} está em execução. Feche-o e tente novamente.
# Command IDs for menu items (@id)
# Format: @id<TAB>command_id<TAB>translation
@id app.install Instalar
@id app.update Atualizar para {v}
@id app.open Abrir
@id app.download Baixar para {os}
@id app.reveal Mostrar no Explorer
@id app.reinstall Reinstalar
@id app.uninstall Desinstalar…
@id app.notes Notas de lançamento
@id app.website Site
@id app.github Repositório no GitHub
@id app.releases Todos os lançamentos
@id launcher.update Atualizar e reiniciar
@id launcher.download Baixar
@id launcher.notes Novidades
@id launcher.dismiss Dispensar
@id settings.open Configurações
@id settings.quit Sair do ArtCraft Launcher
@id view.grid Grade
@id view.table Tabela
@id filter.all Todos
@id filter.installed Instalados
@id filter.updates Atualizações
@id filter.notinstalled Não instalados
@id sort.suite Ordem da suíte
@id sort.name Nome
@id sort.inspired Inspirado em
@id sort.status Status
@id sort.installed Versão instalada
@id sort.latest Última versão
@id sort.released Lançamento mais recente
@id help.discord Discord
@id help.github GitHub
@id help.website Site
@id update.check Verificar atualizações
@id update.check_auto Verificar atualizações automaticamente
@id update.notify Notificar quando um aplicativo instalado tiver atualização
@id update.prereleases Incluir versões de pré-lançamento (betas e RC)
@id linux.preferred_kind Instalar novos aplicativos como
@id tray.close_to_tray Continuar na bandeja do sistema ao fechar a janela
@id tray.show_on_current_desktop Mostrar a janela na área de trabalho atual
@id tray.login_item Iniciar o ArtCraft Launcher ao fazer login
@id appearance.theme Aparência
# Tray (menu bar) menu and tooltip
Show ArtCraft Launcher Mostrar ArtCraft Launcher
Check for Updates Verificar atualizações
Visit getartcraft.com Visitar getartcraft.com
ArtCraft on GitHub ArtCraft no GitHub
Join the ArtCraft Discord Entrar no Discord da ArtCraft
@plural ArtCraft Launcher · {n} update available|ArtCraft Launcher · {n} updates available ArtCraft Launcher · {n} atualização disponível|ArtCraft Launcher · {n} atualizações disponíveis
Can't render this file because it has a wrong number of fields in line 9.

View File

@ -218,6 +218,9 @@ fn untranslated_plurals_fall_back_to_english_by_count() {
#[test] #[test]
fn locale_tags_resolve() { fn locale_tags_resolve() {
assert_eq!(lang_from_tag("pt_BR.UTF-8"), Some(Lang::PT_BR));
assert_eq!(lang_from_tag("pt-BR"), Some(Lang::PT_BR));
assert_eq!(lang_from_tag("pt"), Some(Lang::PT_BR));
assert_eq!(lang_from_tag("ru_RU.UTF-8"), Some(Lang::RU)); assert_eq!(lang_from_tag("ru_RU.UTF-8"), Some(Lang::RU));
assert_eq!(lang_from_tag("ru-RU"), Some(Lang::RU)); assert_eq!(lang_from_tag("ru-RU"), Some(Lang::RU));
assert_eq!(lang_from_tag("en-US"), Some(Lang::EN)); assert_eq!(lang_from_tag("en-US"), Some(Lang::EN));

View File

@ -0,0 +1,116 @@
//! The Brazilian Portuguese (pt-BR) UI test and snapshot generator.
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>>,
}
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 Explorer", self_update: true }
}
fn platform(&self) -> Option<Platform> {
Some(Platform { os: Os::Windows, arch: Arch::X64 })
}
fn now(&self) -> i64 {
self.clock.get()
}
}
struct NoHost;
impl Host for NoHost {}
fn release(id: &str, v: &str, at: i64) -> Release {
let name = format!("{id}-{v}-windows-x64.msi");
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::Msi,
location: format!("C:\\Program Files\\{}\\{}.exe", app.name, app.id),
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 });
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>> {
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)) });
let settings =
Settings { view, notify: false, language: "pt-BR".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 NoHost);
l.ui(ui, &mut NoHost);
}
},
None,
)
}
#[test]
fn portuguese_ui_translates_labels_dates_and_messages() {
let mut h = harness(ViewMode::Grid);
h.run_steps(8);
h.get_by_label("Launcher");
h.get_by_label("Craft App Suite");
h.get_by_label("Edição de imagens");
h.get_by_label("Atualizar para 0.5.0");
h.get_by_label_contains("Conferindo a soma de verificação…");
h.get_by_label_contains("Verificado há 3 min · via ArtCraft API");
h.get_by_label("LightCraft atualizado para 0.5.0");
let mut table = harness(ViewMode::Table);
table.run_steps(8);
table.get_by_label("Instalada");
assert!(table.query_all_by_label_contains("de ago. de 2026").count() >= 1);
}