Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion windows/codenotch/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub struct TraySlot {
pub struct Config {
#[serde(default = "default_port")]
pub port: u16,
/// "auto" | "zh" | "zh-Hant" | "en" | "ja" | "ko" | "ru" | "uk"
/// "auto" | "zh" | "zh-Hant" | "en" | "ja" | "ko" | "ru" | "uk" | "pt"
#[serde(default = "default_lang")]
pub lang: String,
#[serde(default)]
Expand Down
40 changes: 40 additions & 0 deletions windows/codenotch/src/i18n.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ pub fn resolve_auto() -> &'static str {
if let Some(lang) = language_from_windows_locale(&name) {
return lang;
}
if name.starts_with("pt") {
return "pt";
}
}
}
"en"
Expand Down Expand Up @@ -127,6 +130,7 @@ pub fn tr(lang: &str, key: &str) -> &'static str {
("ko", "open_data") => "데이터 폴더 열기 (로그 / 아이콘)",
("ru", "open_data") => "Открыть папку данных (журналы / значки)",
("uk", "open_data") => "Відкрити теку даних (журнали / значки)",
("pt", "open_data") => "Abrir pasta de dados (logs / ícones)",
(_, "open_data") => "Open data folder (logs / icons)",
("ja", "refresh_all") => "すべて更新",
("ko", "refresh_all") => "모두 새로 고침",
Expand Down Expand Up @@ -162,6 +166,16 @@ pub fn tr(lang: &str, key: &str) -> &'static str {
("uk", "autostart") => "Запускати разом із Windows (у фоні)",
("ru", "refresh_all") => "Обновить всё",
("uk", "refresh_all") => "Оновити все",
("pt", "install") => "Instalar hooks do Claude Code",
("pt", "uninstall") => "Remover hooks",
("pt", "language") => "Idioma",
("pt", "lang_auto") => "Seguir o sistema",
("pt", "reset_pos") => "Redefinir posição da barra",
("pt", "quit") => "Sair",
("pt", "hooks_missing") => "Hooks não instalados: clique com o botão direito no ícone da bandeja → Instalar hooks do Claude Code (a versão desktop já tem um substituto automático)",
("pt", "autostart") => "Iniciar com o Windows (em segundo plano)",
("pt", "refresh_all") => "Atualizar tudo",
("pt", "settings") => "Configurações…",
(_, "install") => "Install Claude Code hooks",
(_, "uninstall") => "Uninstall hooks",
(_, "language") => "Language",
Expand Down Expand Up @@ -329,6 +343,32 @@ mod tests {
assert_eq!(language_from_windows_locale("zh"), Some("zh"));
}

const PORTUGUESE_KEYS: &[(&str, &str)] = &[
("settings", "Configurações…"),
("refresh_all", "Atualizar tudo"),
("quit", "Sair"),
("install", "Instalar hooks do Claude Code"),
("uninstall", "Remover hooks"),
("language", "Idioma"),
("lang_auto", "Seguir o sistema"),
("reset_pos", "Redefinir posição da barra"),
("hooks_missing", "Hooks não instalados: clique com o botão direito no ícone da bandeja → Instalar hooks do Claude Code (a versão desktop já tem um substituto automático)"),
("autostart", "Iniciar com o Windows (em segundo plano)"),
("open_data", "Abrir pasta de dados (logs / ícones)"),
];

#[test]
fn portuguese_translates_every_known_key() {
for (key, value) in PORTUGUESE_KEYS {
assert_eq!(
tr("pt", key),
*value,
"missing Portuguese translation for {key}"
);
assert_ne!(tr("pt", key), "?", "unknown Portuguese key {key}");
}
}

#[test]
fn unknown_language_keeps_the_english_fallback() {
assert_eq!(tr("xx", "settings"), "Settings…");
Expand Down
82 changes: 82 additions & 0 deletions windows/codenotch/ui/notch.html
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,46 @@
'needs your input':'等待你的輸入',
'Working in':'工作於',
},
pt:{
'Included usage':'Uso incluído',
'API usage':'Uso da API',
'On demand':'Sob demanda',
'Usage':'Uso',
'Current session':'Sessão atual',
'Weekly (all models)':'Semanal (todos os modelos)',
'Weekly (Opus)':'Semanal (Opus)',
'Weekly (model-scoped)':'Semanal (por modelo)',
'Weekly limit':'Limite semanal',
'Weekly Limit':'Limite semanal',
'5-Hour Limit':'Limite de 5 horas',
'5-hour Limit':'Limite de 5 horas',
'Gemini Models':'Modelos Gemini',
'Claude and GPT models':'Modelos Claude e GPT',
'Monthly limit':'Limite mensal',
'Monthly Limit':'Limite mensal',
'Longer window':'Janela mais longa',
'Requests today · no limit published':'Solicitações hoje · sem limite publicado',
'Updated':'Atualizado',
'Resetting…':'Reiniciando…',
'Resets at':'Reinicia às',
'Resets':'Reinicia',
'Working':'Trabalhando',
'Waiting':'Aguardando',
'Streaming (network)':'Transmitindo (rede)',
'Rate limited, retrying in':'Limite atingido, tentando novamente em',
'Rate limited — retrying in':'Limite atingido — tentando novamente em',
'request today':'solicitação hoje',
'requests today':'solicitações hoje',
'no requests today':'nenhuma solicitação hoje',
'Waiting for first reading…':'Aguardando a primeira leitura…',
'Sign in to Claude Code to see usage.':'Faça login no Claude Code para ver o uso.',
'Sign in to Cursor to see usage.':'Faça login no Cursor para ver o uso.',
'Sign in to Codex to see usage.':'Faça login no Codex para ver o uso.',
'Sign in to Antigravity to see usage.':'Faça login no Antigravity para ver o uso.',
'Run grok login to see usage.':'Execute grok login para ver o uso.',
'needs your input':'precisa da sua resposta',
'Working in':'Trabalhando em',
},
};
// Kept as patterns rather than exact keys: each one carries a number, a plan name or an error
// the provider wrote, so the whole string can never be a dictionary key.
Expand Down Expand Up @@ -654,6 +694,44 @@
[/Sign in to Cursor \(the editor\) to see usage\./g,'請登入 Cursor(編輯器)以查看用量。'],
[/Cursor session was rejected — sign in again in the editor/g,'Cursor 工作階段被拒絕 — 請在編輯器中重新登入'],
],
pt:[
[/^(\d+)m limit$/,'Limite de $1 min'],
[/^(\d+)h limit$/,'Limite de $1 h'],
[/^(\d+)d limit$/,'Limite de $1 d'],
[/^Rate limited, retrying in (\d+)s$/,'Limite atingido, tentando novamente em $1 s'],
[/^Rate limited — retrying in (\d+)s$/,'Limite atingido — tentando novamente em $1 s'],
[/^Unlimited on the (.+) plan — nothing to meter$/,'Ilimitado no plano $1 — nada para medir'],
[/^The (.+) plan has nothing for Cursor to meter yet$/,'O plano $1 ainda não tem nada para o Cursor medir'],
[/^(.+) · Google publishes no quota for this account$/,'$1 · o Google não publica cota para esta conta'],
[/^Live read failed \((.+)\)$/,'Falha na leitura ao vivo ($1)'],
[/Weekly \(all models\)/g,'Semanal (todos os modelos)'],
[/Weekly \(Opus\)/g,'Semanal (Opus)'],
[/Weekly \(model-scoped\)/g,'Semanal (por modelo)'],
[/Weekly limit/g,'Limite semanal'],
[/Monthly limit/g,'Limite mensal'],
[/\bWeekly\b/g,'Semanal'],
[/\bMonthly\b/g,'Mensal'],
[/ · via /g,' · via '],
[/needs your input/g,'precisa da sua resposta'],
[/^Working in /,'Trabalhando em '],
[/via Antigravity CLI/g,'via CLI do Antigravity'],
[/via Antigravity/g,'via Antigravity'],
[/via Google/g,'via Google'],
[/No Claude Code credential found/g,'Nenhuma credencial do Claude Code encontrada'],
[/Credential expired — run claude once in a terminal to renew it/g,'Credencial expirada — rode claude uma vez no terminal para renová-la'],
[/Credential rejected \(switched accounts\?\)/g,'Credencial rejeitada (trocou de conta?)'],
[/Codex sign-in expired — open Codex once to refresh it/g,'Login do Codex expirado — abra o Codex uma vez para renová-lo'],
[/Codex rejected its sign-in — sign in to Codex again/g,'O Codex rejeitou o login — faça login no Codex novamente'],
[/Codex reported no usage windows/g,'O Codex não reportou nenhuma janela de uso'],
[/Codex has not recorded a usage snapshot yet/g,'O Codex ainda não registrou um snapshot de uso'],
[/from last Codex run/g,'da última execução do Codex'],
[/Waiting for Antigravity CLI quota/g,'Aguardando a cota da CLI do Antigravity'],
[/Open Antigravity to read its quota/g,'Abra o Antigravity para ler sua cota'],
[/Antigravity's Google session was rejected — sign in again in Antigravity/g,'A sessão do Google no Antigravity foi rejeitada — faça login novamente no Antigravity'],
[/Antigravity is closed — last reading kept/g,'Antigravity está fechado — mantendo a última leitura'],
[/Sign in to Cursor \(the editor\) to see usage\./g,'Faça login no Cursor (o editor) para ver o uso.'],
[/Cursor session was rejected — sign in again in the editor/g,'A sessão do Cursor foi rejeitada — faça login novamente no editor'],
],
};
// Grammar differs enough that a format string would not carry it — Russian puts the verb last,
// Chinese puts it after the time — so each language writes its own short functions.
Expand All @@ -678,6 +756,10 @@
resetsAt:t=>`${t} 重置`,resetsOn:(d,t)=>`${d} ${t} 重置`,resetsDate:d=>`${d} 重置`,
ago:m=>m<60?`${m} 分鐘前`:`${Math.round(m/60)} 小時前`,
usedLeft:(used,left)=>`已用 ${used}% · 剩餘 ${left}%`,andMore:n=>`另有 ${n} 個`},
pt:{locale:'pt-BR',title:n=>'Uso de '+n,resetting:'Reiniciando…',resetsIn:m=>`Reinicia em ${m} min`,
resetsAt:t=>`Reinicia às ${t}`,resetsOn:(d,t)=>`Reinicia ${d} ${t}`,resetsDate:d=>`Reinicia ${d}`,
ago:m=>m<60?`há ${m} min`:`há ${Math.round(m/60)} h`,
usedLeft:(used,left)=>`${used}% usado · ${left}% restante`,andMore:n=>`e mais ${n}`},
};
function ui(){return UI[uiLang]||UI.en;}
function textCopy(value){
Expand Down
Loading