feat(i18n): translate five more systems, and unify the permission labels
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

- Space settings > Overview — identity, icon, banner, transfer, delete
  - Space settings > Members and Bans
  - Space settings > Roles, including the whole permission table
  - Category settings — rename, privacy, overrides, delete
  - Instance settings > General — name, discovery, GIF search

The permission labels were duplicated: the roles panel carried one English
list and the channel/category override editors carried another. Both now
read a single `perm.*` set, so renaming a permission lands in all three at
once instead of one and a half. This removes the `channel.perm.*` keys added
two commits ago rather than adding a third copy beside them.

Same pattern as before for anything chosen outside the render: the roles
panel's permission groups and the category's override definitions hold keys
and resolve them where they render. The category delete dialog emphasises
the category name, so its sentence is split around the placeholder rather
than interpolated.

Dictionary is at 723 keys, en and pt-BR at exact parity.

Verified: web build (tsc + vite), 490 web tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-02 20:49:25 -03:00
co-authored by Claude Opus 5
parent 4fd6ac890c
commit 94f5da4013
10 changed files with 511 additions and 202 deletions
+153 -14
View File
@@ -254,20 +254,6 @@ export const ptBR: Partial<Dictionary> = {
'channel.delete.irreversible': 'Não dá para desfazer.',
'channel.delete.failed': 'Não foi possível excluir o canal',
// Permissões do canal — rótulos do editor de exceções
'channel.perm.viewChannel': 'Ver canal',
'channel.perm.sendMessages': 'Enviar mensagens',
'channel.perm.manageMessages': 'Gerenciar mensagens',
'channel.perm.attachFiles': 'Anexar arquivos',
'channel.perm.readHistory': 'Ler histórico de mensagens',
'channel.perm.addReactions': 'Adicionar reações',
'channel.perm.connect': 'Conectar',
'channel.perm.speak': 'Falar',
'channel.perm.stream': 'Transmitir',
'channel.perm.muteMembers': 'Silenciar membros',
'channel.perm.deafenMembers': 'Ensurdecer membros',
'channel.perm.moveMembers': 'Mover membros',
'channel.perm.disconnectMembers': 'Desconectar membros',
// Amigos — abas e listas
'friends.title': 'Amigos',
'friends.tab.online': 'Online',
@@ -664,4 +650,157 @@ export const ptBR: Partial<Dictionary> = {
'error.title': 'Alguma coisa deu errado',
'error.tryAgain': 'Tentar de novo',
'error.reload': 'Recarregar a página',
// Rótulos de permissão — usados pelo painel de cargos e pelos editores de
// exceção de canal e categoria, então renomear aqui vale nos três.
'perm.group.general': 'Geral',
'perm.group.text': 'Texto',
'perm.group.voice': 'Voz',
'perm.administrator': 'Administrador',
'perm.viewChannel': 'Ver canal',
'perm.viewChannels': 'Ver canais',
'perm.manageChannels': 'Gerenciar canais',
'perm.manageRoles': 'Gerenciar cargos',
'perm.manageSpace': 'Gerenciar servidor',
'perm.createInvite': 'Criar convite',
'perm.kickMembers': 'Expulsar membros',
'perm.banMembers': 'Banir membros',
'perm.sendMessages': 'Enviar mensagens',
'perm.manageMessages': 'Gerenciar mensagens',
'perm.attachFiles': 'Anexar arquivos',
'perm.readHistory': 'Ler histórico de mensagens',
'perm.addReactions': 'Adicionar reações',
'perm.connect': 'Conectar',
'perm.speak': 'Falar',
'perm.stream': 'Transmitir',
'perm.muteMembers': 'Silenciar membros',
'perm.deafenMembers': 'Ensurdecer membros',
'perm.moveMembers': 'Mover membros',
'perm.disconnectMembers': 'Desconectar membros',
// Configurações do servidor — visão geral
'space.overview.title': 'Visão geral',
'space.overview.identity': 'Identidade do servidor',
'space.overview.icon': 'Ícone do servidor',
'space.overview.iconAlt': 'Ícone do servidor',
'space.overview.iconColor': 'Cor do ícone',
'space.overview.banner': 'Banner do servidor',
'space.overview.bannerAlt': 'Banner do servidor',
'space.overview.bannerUpload': 'Enviar banner (16:9)',
'space.overview.bannerRemove': 'Remover banner',
'space.overview.remove': 'Remover',
'space.overview.name': 'Nome do servidor',
'space.overview.save': 'Salvar',
'space.overview.saving': 'Salvando...',
'space.overview.discard': 'Descartar',
'space.overview.saved': 'Configurações salvas',
'space.overview.saveFailed': 'Não foi possível salvar',
'space.overview.iconFailed': 'Não foi possível enviar o ícone',
'space.overview.bannerFailed': 'Não foi possível enviar o banner',
'space.overview.cropIcon': 'Recortar o ícone do servidor',
'space.overview.cropBanner': 'Recortar o banner do servidor',
'space.overview.danger': 'Zona de perigo',
'space.overview.transfer.description': 'Passe a propriedade para outro membro. Você vira um membro comum.',
'space.overview.transfer.button': 'Transferir propriedade',
'space.overview.transfer.confirm': 'Transferir a propriedade para',
'space.overview.transfer.search': 'Buscar membros...',
'space.overview.transfer.empty': 'Nenhum membro encontrado',
'space.overview.transfer.back': 'Voltar',
'space.overview.transfer.cancel': 'Cancelar',
'space.overview.transfer.submit': 'Transferir',
'space.overview.transfer.transferring': 'Transferindo...',
'space.overview.transfer.failed': 'Não foi possível transferir a propriedade',
'space.overview.delete.description': 'Apaga este servidor e todos os dados dele para sempre. Não dá para desfazer.',
'space.overview.delete': 'Excluir servidor',
'space.overview.delete.confirm': 'Clique de novo para confirmar',
'space.overview.delete.failed': 'Não foi possível excluir o servidor',
// Configurações do servidor — membros e banimentos
'space.members.title': 'Membros',
'space.members.description': 'Gerencie os membros do servidor. Clique num membro para editar os cargos dele.',
'space.members.count': 'Membros ({count})',
'space.members.noRoles': 'Sem cargo',
'space.members.save': 'Salvar',
'space.members.cancel': 'Cancelar',
'space.members.kick': 'Expulsar',
'space.members.ban': 'Banir',
'space.members.kick.title': 'Expulsar {name}',
'space.members.kick.description': 'A pessoa pode voltar com um link de convite.',
'space.members.ban.title': 'Banir {name}',
'space.members.ban.description': 'A pessoa fica banida deste servidor até alguém desfazer o banimento.',
'space.members.rolesFailed': 'Não foi possível atualizar os cargos',
'space.members.kickFailed': 'Não foi possível expulsar o membro',
'space.members.banFailed': 'Não foi possível banir o membro',
'space.bans.title': 'Banimentos',
'space.bans.count': 'Banimentos ({count})',
'space.bans.description': 'Quem está banido não consegue voltar até alguém desfazer o banimento.',
'space.bans.loading': 'Carregando banimentos...',
'space.bans.empty': 'Ninguém banido',
'space.bans.by': 'Banido por {moderator} em {date}',
'space.bans.unban': 'Desfazer banimento',
'space.bans.loadFailed': 'Não foi possível carregar os banimentos',
'space.bans.unbanFailed': 'Não foi possível desfazer o banimento',
// Configurações do servidor — cargos
'space.roles.title': 'Cargos',
'space.roles.description': 'Os cargos definem o que cada membro pode fazer. Cargos mais altos têm prioridade.',
'space.roles.create': 'Criar cargo',
'space.roles.creating': 'Criando...',
'space.roles.createFailed': 'Não foi possível criar o cargo',
'space.roles.created': 'Cargo criado — ajuste abaixo',
'space.roles.back': 'Voltar aos cargos',
'space.roles.identity': 'Identidade',
'space.roles.name': 'Nome do cargo',
'space.roles.name.empty': 'O nome do cargo não pode ficar vazio',
'space.roles.color': 'Cor do cargo',
'space.roles.save': 'Salvar',
'space.roles.saving': 'Salvando...',
'space.roles.saved': 'Cargo salvo',
'space.roles.saveFailed': 'Não foi possível salvar o cargo',
'space.roles.discard': 'Descartar',
'space.roles.copy': 'Duplicar cargo',
'space.roles.copying': 'Duplicando...',
'space.roles.copyFailed': 'Não foi possível duplicar o cargo',
'space.roles.delete': 'Excluir cargo',
'space.roles.deleting': 'Excluindo...',
'space.roles.deleteConfirm': 'Confirma?',
'space.roles.deleteFailed': 'Não foi possível excluir o cargo',
// Configurações da categoria
'category.settings.title': 'Configurações da categoria',
'category.tab.overview': 'Visão geral',
'category.tab.permissions': 'Permissões',
'category.label': 'Categoria',
'category.private.title': 'Categoria privada',
'category.private.description': 'Só os membros e cargos escolhidos vão ver os canais desta categoria.',
'category.private.note': 'Esta categoria fica escondida de quem não tem acesso explícito. Os canais dentro dela herdam essa restrição, a menos que definam a sua própria.',
'category.private.loadFailed': 'Não foi possível carregar as permissões da categoria',
'category.private.updateFailed': 'Não foi possível alterar a privacidade da categoria',
'category.renameFailed': 'Não foi possível renomear a categoria',
'category.danger': 'Zona de perigo',
'category.delete': 'Excluir categoria',
'category.delete.title': 'Excluir "{name}"?',
'category.delete.body': 'Isto apaga a categoria {name} para sempre. Os canais dentro dela vão para o nível de cima. Não dá para desfazer.',
'category.delete.failed': 'Não foi possível excluir a categoria',
// Configurações da instância — geral
'instance.general.title': 'Geral',
'instance.general.description': 'Configure a sua instância do Backspace. Estas opções valem para todo mundo.',
'instance.general.loading': 'Carregando configurações...',
'instance.general.name': 'Nome da instância',
'instance.general.name.description': 'O nome que aparece na tela de login e para as instâncias federadas.',
'instance.general.discovery': 'Descoberta',
'instance.general.discovery.title': 'Descoberta de servidores',
'instance.general.discovery.description': 'Permite que os servidores apareçam na página pública do Explorar',
'instance.general.gif': 'Busca de GIFs',
'instance.general.gif.description': 'Liga a busca de GIFs pelo Klipy. Pegue uma chave de API gratuita no portal de desenvolvedores do Klipy.',
'instance.general.gif.keySaved': 'Chave salva — digite outra para substituir',
'instance.general.gif.keyPlaceholder': 'Chave de API do Klipy',
'instance.general.gif.enabled': 'Ligado',
'instance.general.gif.notConfigured': 'Não configurado',
'instance.general.gif.clearKey': 'Apagar a chave',
'instance.general.save': 'Salvar',
'instance.general.saving': 'Salvando...',
'instance.general.reset': 'Desfazer',
'instance.general.saved': 'Configurações salvas',
'instance.general.saveFailed': 'Não foi possível salvar',
};