feat(i18n): translate five more systems, and check for updates more often
CI / Build & test (Node 20) (push) Canceled after 0s
CI / Build & test (Node 24) (push) Canceled after 0s
CI / Build & test (push) Canceled after 0s
CodeQL / Analyze (javascript-typescript) (push) Canceled after 0s
Security / Secret scan (gitleaks) (push) Canceled after 0s
Security / Dependency scan (OSV-Scanner) (push) Canceled after 0s
Security / IaC/config scan (Trivy) (push) Canceled after 0s
Security / License compliance scan (Trivy) (push) Canceled after 0s
OpenSSF Scorecard / Scorecard analysis (push) Canceled after 0s
CI / Build & test (Node 20) (push) Canceled after 0s
CI / Build & test (Node 24) (push) Canceled after 0s
CI / Build & test (push) Canceled after 0s
CodeQL / Analyze (javascript-typescript) (push) Canceled after 0s
Security / Secret scan (gitleaks) (push) Canceled after 0s
Security / Dependency scan (OSV-Scanner) (push) Canceled after 0s
Security / IaC/config scan (Trivy) (push) Canceled after 0s
Security / License compliance scan (Trivy) (push) Canceled after 0s
OpenSSF Scorecard / Scorecard analysis (push) Canceled after 0s
Update cadence: the desktop app checked once ten seconds after launch and
then every four hours. A release published while the app sits open went
unnoticed until the next poll — which is exactly what happened with 1.4.0.
It now polls every 30 minutes and also checks when the window regains focus,
throttled to one check per five minutes so alt-tabbing does not hammer the
feed. `lastCheckAt` is stamped from the `checking-for-update` event rather
than by the callers, so a manual check from the settings panel counts too.
The focus listener is on `app`, not on mainWindow, because the window is
destroyed and recreated when closed to tray.
Translations, five whole systems:
- Settings > Desktop (autostart, updates, instance)
- Settings > Voice: output device, which completes that tab
- Settings > Keybinds, including the action names and conflict prompt
- Settings > Account, the largest — profile, password, detached-instance
notice, danger zone
- Explore spaces
Two sentences wrap a literal that must not be translated (the `input` group
name, the `user@instance` example). Those are split around a placeholder
rather than interpolated as text, so a translation keeps control of the word
order on both sides of it. Keybind action labels gained a `labelKey`
alongside the English `label`, which stays for non-React callers.
Verified: web build (tsc + vite), desktop typecheck, 490 web tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -362,4 +362,133 @@ export const ptBR: Partial<Dictionary> = {
|
||||
'invite.fail.invalid_target': 'Destino inválido',
|
||||
'invite.fail.network': 'Não deu para falar com a sua instância',
|
||||
'invite.fail.generic': 'Não deu para enviar (erro no servidor)',
|
||||
// Configurações — área de trabalho
|
||||
'settings.desktop.title': 'Área de trabalho',
|
||||
'settings.desktop.startAtBoot': 'Abrir junto com o sistema',
|
||||
'settings.desktop.startAtBoot.description': 'Inicia o Backspace sozinho quando você faz login',
|
||||
'settings.desktop.startMinimized': 'Abrir minimizado',
|
||||
'settings.desktop.startMinimized.description': 'Começa escondido na bandeja em vez de abrir a janela',
|
||||
'settings.desktop.version': 'Versão {version}',
|
||||
'settings.desktop.appName': 'Backspace Desktop',
|
||||
'settings.desktop.update.description': 'Procurar versões novas do aplicativo',
|
||||
'settings.desktop.update.check': 'Procurar atualizações',
|
||||
'settings.desktop.update.checking': 'Procurando...',
|
||||
'settings.desktop.instance.current': 'Instância conectada agora',
|
||||
'settings.desktop.instance.change': 'Trocar de instância',
|
||||
|
||||
// Configurações — voz: saída
|
||||
'settings.output.title': 'Dispositivo de saída',
|
||||
'settings.output.checking': 'Verificando o acesso ao áudio…',
|
||||
'settings.output.systemDefault': 'Padrão do sistema',
|
||||
'settings.output.unsupported': 'Este navegador não deixa escolher o dispositivo de saída. O áudio toca no padrão do sistema.',
|
||||
'settings.output.needPermission': 'Dê permissão de microfone para listar os dispositivos de saída (os navegadores escondem os nomes de saída atrás do acesso ao microfone).',
|
||||
'settings.output.enableAccess': 'Liberar acesso ao áudio',
|
||||
'settings.output.volume': 'Volume de saída',
|
||||
'settings.output.testSound': 'Tocar som de teste',
|
||||
|
||||
// Configurações — atalhos
|
||||
'settings.keybinds.title': 'Atalhos',
|
||||
'settings.keybinds.section.voice': 'Atalhos de voz',
|
||||
'settings.keybinds.pressCombo': 'Aperte a combinação...',
|
||||
'settings.keybinds.notBound': 'Sem atalho',
|
||||
'settings.keybinds.edit': 'Editar',
|
||||
'settings.keybinds.record': 'Gravar',
|
||||
'settings.keybinds.delete': 'Excluir',
|
||||
'settings.keybinds.escToCancel': 'ESC para cancelar',
|
||||
'settings.keybinds.accessibility.title': 'Precisa da permissão de Acessibilidade',
|
||||
'settings.keybinds.accessibility.description': 'O Backspace precisa da permissão de Acessibilidade para os atalhos funcionarem fora do aplicativo.',
|
||||
'settings.keybinds.accessibility.grant': 'Conceder permissão',
|
||||
'settings.keybinds.hookError.title': 'Atalhos globais indisponíveis',
|
||||
'settings.keybinds.hookError.description': 'Não foi possível iniciar o leitor de entrada. No Linux, talvez o seu usuário precise estar no grupo {group}.',
|
||||
'settings.keybinds.webNote': 'Os atalhos funcionam enquanto esta aba estiver em foco. Para atalhos que funcionam em outros programas, use o aplicativo.',
|
||||
'settings.keybinds.conflict.suffix': '. Substituir?',
|
||||
'settings.keybinds.conflict.boundTo': 'já está ligado a',
|
||||
'settings.keybinds.conflict.overwrite': 'Substituir',
|
||||
'settings.keybinds.conflict.cancel': 'Cancelar',
|
||||
'settings.keybinds.action.toggleMute': 'Ligar/desligar microfone',
|
||||
'settings.keybinds.action.toggleDeafen': 'Ligar/desligar som',
|
||||
'settings.keybinds.action.pushToTalk': 'Apertar para falar',
|
||||
'settings.keybinds.action.toggleCamera': 'Ligar/desligar câmera',
|
||||
'settings.keybinds.action.toggleScreenShare': 'Ligar/desligar transmissão',
|
||||
'settings.keybinds.action.disconnect': 'Desconectar',
|
||||
|
||||
// Configurações — conta
|
||||
'settings.account.title': 'Minha conta',
|
||||
'settings.account.detached.lead': 'Esta conta está desligada da instância de origem.',
|
||||
'settings.account.detached.body': 'A {instance} foi reiniciada ou não existe mais, então esta conta agora funciona localmente nesta instância — o perfil e a senha são gerenciados aqui.',
|
||||
'settings.account.detached.relink': 'Como {username} em {instance}, dá para religar esta conta — o perfil e a presença voltam a sincronizar de lá.',
|
||||
'settings.account.detached.reattaching': 'Religando…',
|
||||
'settings.account.detached.confirm': 'Confirmar religação como {username}',
|
||||
'settings.account.detached.reattach': 'Religar a {instance}',
|
||||
'settings.account.detached.failed': 'Não foi possível religar',
|
||||
'settings.account.section.profile': 'Personalização do perfil',
|
||||
'settings.account.section.account': 'Conta',
|
||||
'settings.account.section.password': 'Senha',
|
||||
'settings.account.section.danger': 'Zona de perigo',
|
||||
'settings.account.avatar': 'Foto de perfil',
|
||||
'settings.account.avatar.change': 'Trocar foto',
|
||||
'settings.account.banner': 'Banner',
|
||||
'settings.account.banner.change': 'Trocar banner',
|
||||
'settings.account.banner.chooseGif': 'Escolher GIF',
|
||||
'settings.account.remove': 'Remover',
|
||||
'settings.account.clear': 'Limpar',
|
||||
'settings.account.avatarColor': 'Cor da foto',
|
||||
'settings.account.bannerColor': 'Cor do banner',
|
||||
'settings.account.aboutMe': 'Sobre mim',
|
||||
'settings.account.aboutMe.placeholder': 'Conte alguma coisa sobre você...',
|
||||
'settings.account.status': 'Status',
|
||||
'settings.account.status.online': 'Online',
|
||||
'settings.account.status.idle': 'Ausente',
|
||||
'settings.account.status.dnd': 'Não perturbe',
|
||||
'settings.account.displayName': 'Nome de exibição',
|
||||
'settings.account.customStatus': 'Status personalizado',
|
||||
'settings.account.customStatus.placeholder': 'O que você está fazendo?',
|
||||
'settings.account.password.current': 'Senha atual',
|
||||
'settings.account.password.current.placeholder': 'Digite a senha atual',
|
||||
'settings.account.password.new': 'Senha nova',
|
||||
'settings.account.password.new.placeholder': 'Mínimo de 6 caracteres',
|
||||
'settings.account.password.confirm': 'Confirmar a senha nova',
|
||||
'settings.account.password.confirm.placeholder': 'Confirme a senha nova',
|
||||
'settings.account.password.change': 'Trocar senha',
|
||||
'settings.account.password.changing': 'Trocando...',
|
||||
'settings.account.password.changed': 'Senha trocada',
|
||||
'settings.account.password.tooShort': 'A senha nova precisa ter pelo menos 8 caracteres',
|
||||
'settings.account.password.mismatch': 'As senhas não batem',
|
||||
'settings.account.password.failed': 'Não foi possível trocar a senha',
|
||||
'settings.account.sync.synced': 'Sincronizado',
|
||||
'settings.account.sync.failed': 'Falhou — sincroniza quando reconectar',
|
||||
'settings.account.delete.warning': 'Depois de excluir a conta não tem volta. Suas mensagens continuam lá, mas passam a aparecer como "Usuário excluído".',
|
||||
'settings.account.delete': 'Excluir conta',
|
||||
'settings.account.reset': 'Desfazer',
|
||||
'settings.account.save': 'Salvar',
|
||||
'settings.account.saving': 'Salvando...',
|
||||
'settings.account.saved': 'Perfil atualizado',
|
||||
'settings.account.saveFailed': 'Não foi possível atualizar o perfil',
|
||||
'settings.account.avatar.uploadFailed': 'Não foi possível enviar a foto',
|
||||
'settings.account.banner.uploadFailed': 'Não foi possível enviar o banner',
|
||||
'settings.account.crop.avatar': 'Recortar a foto',
|
||||
'settings.account.crop.banner': 'Recortar o banner',
|
||||
|
||||
// Explorar servidores
|
||||
'explore.title': 'Explorar',
|
||||
'explore.searchPlaceholder': 'Buscar servidores...',
|
||||
'explore.disabled': 'A descoberta de servidores está desativada pelo administrador da instância.',
|
||||
'explore.empty.search': 'Nenhum servidor encontrado.',
|
||||
'explore.empty.none': 'Nenhum servidor para descobrir ainda.',
|
||||
'explore.allJoined': 'Você já está em todos os servidores visíveis',
|
||||
'explore.joined': 'Você participa',
|
||||
'explore.badge.public': 'Público',
|
||||
'explore.badge.request': 'Por pedido',
|
||||
'explore.noDescription': 'Sem descrição',
|
||||
'explore.member': 'membro',
|
||||
'explore.members': 'membros',
|
||||
'explore.view': 'Ver servidor',
|
||||
'explore.join': 'Entrar no servidor',
|
||||
'explore.joining': 'Entrando...',
|
||||
'explore.requestPending': 'Pedido pendente',
|
||||
'explore.requestToJoin': 'Pedir para entrar',
|
||||
'explore.request.placeholder': 'Por que você quer entrar? (opcional)',
|
||||
'explore.request.send': 'Enviar pedido',
|
||||
'explore.request.sending': 'Enviando...',
|
||||
'explore.request.cancel': 'Cancelar',
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user