From bb6f9cbde3896f5175a85824d1ca9ecf1e9aab16 Mon Sep 17 00:00:00 2001 From: Lucas Rayan Date: Tue, 20 Oct 2026 09:52:41 -0300 Subject: [PATCH 1/2] =?UTF-8?q?Interface:=20completa=20a=20tradu=C3=A7?= =?UTF-8?q?=C3=A3o=20para=20ingl=C3=AAs=20e=20corrige=20"Formato"=20no=20d?= =?UTF-8?q?i=C3=A1logo=20de=20imagem?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Textos que apareciam em português no modo inglês: opções de volumes cifrados e RAID, diálogo de criar imagem, resultados, partições, campos de saúde do disco vindos do núcleo, pré-visualização e erros. O rótulo "Formato" do diálogo de imagem era traduzido como "Form factor" (ficha do disco). Agora é "Formato da imagem" ("Image format"). Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01RRZm8uTVN3WLTwcbrDQAUM --- apps/gui/ui/app.js | 2 +- apps/gui/ui/i18n-en.js | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/apps/gui/ui/app.js b/apps/gui/ui/app.js index 95c3deb..78fcf13 100644 --- a/apps/gui/ui/app.js +++ b/apps/gui/ui/app.js @@ -467,7 +467,7 @@ async function startImage() { const base = (S.defaults.home || '') + (S.defaults.sep || '/'); const f = await askForm({ title: 'Criar imagem do disco', text: 'Onde salvar o arquivo de imagem? Use outro disco com espaço suficiente e um nome que ainda não exista.', ok: 'Criar imagem', fields: [ { name: 'dest', label: 'Arquivo de destino', value: base + 'disco-guara.img' }, - { name: 'format', label: 'Formato', value: 'raw', options: [['raw', 'Bruta (.img)'], ['e01', 'Expert Witness (.E01, com hash e metadados)'], ['aff4', 'AFF4 (.aff4)']] }, + { name: 'format', label: 'Formato da imagem', value: 'raw', options: [['raw', 'Bruta (.img)'], ['e01', 'Expert Witness (.E01, com hash e metadados)'], ['aff4', 'AFF4 (.aff4)']] }, { name: 'case', label: 'Número do caso (E01/AFF4)', value: '' }, { name: 'examiner', label: 'Examinador (E01/AFF4)', value: '' }, ] }); diff --git a/apps/gui/ui/i18n-en.js b/apps/gui/ui/i18n-en.js index e502202..95c52be 100644 --- a/apps/gui/ui/i18n-en.js +++ b/apps/gui/ui/i18n-en.js @@ -406,4 +406,46 @@ export const EN = { 'Origem desconectada': 'Source disconnected', 'Este disco está em uso (montado em': 'This disk is in use (mounted at', '). O Guará só lê, mas evite gravar nele enquanto recupera, porque qualquer escrita pode sobrescrever o que você quer salvar.': '). Guará only reads, but avoid writing to it while recovering, because any write can overwrite what you want to save.', + // formulário de opções de varredura + 'Volumes cifrados, RAID e vídeos': 'Encrypted volumes, RAID and videos', + 'Senha do volume (BitLocker, LUKS, FileVault 2)': 'Volume password (BitLocker, LUKS, FileVault 2)', + 'Chave de recuperação do BitLocker': 'BitLocker recovery key', + 'Arquivo de chave (.BEK ou keyfile)': 'Key file (.BEK or keyfile)', + 'Outros discos do mesmo conjunto (RAID/LVM), um caminho por linha': 'Other disks of the same set (RAID/LVM), one path per line', + 'Estes discos formam um RAID sem metadados': 'These disks form a RAID without metadata', + 'O Guará descobre sozinho o nível, a faixa, o layout e a ordem dos discos.': 'Guará works out the level, stripe size, layout and order of the disks by itself.', + 'Vídeo íntegro da mesma câmera/drone (refaz o índice de MP4 sem moov)': 'Intact video from the same camera/drone (rebuilds the index of an MP4 without moov)', + 'Lembrar as chaves dos volumes abertos na sessão': 'Remember the keys of opened volumes in the session', + 'A senha nunca é gravada; só a chave derivada.': 'The password is never saved; only the derived key.', + // criar imagem do disco + 'Arquivo de destino': 'Destination file', + 'Número do caso (E01/AFF4)': 'Case number (E01/AFF4)', + 'Formato da imagem': 'Image format', + 'Bruta (.img)': 'Raw (.img)', + 'Expert Witness (.E01, com hash e metadados)': 'Expert Witness (.E01, with hash and metadata)', + 'Examinador (E01/AFF4)': 'Examiner (E01/AFF4)', + 'Imagem salva em': 'Image saved to', + 'Hashes do conteúdo inteiro de': 'Hashes of the entire content of', + // resultados e partições + 'arquivo(s) salvos em': 'file(s) saved to', + 'arquivos em {n}': 'files in {n}', + 'Espaço não particionado: {n}': 'Unpartitioned space: {n}', + 'Partição {n}': 'Partition {n}', + 'erro {n}': 'error {n}', + // saúde do disco (campos vindos do núcleo) + 'Autoavaliação SMART': 'SMART self-assessment', + 'Vida útil usada': 'Life used', + 'aprovado': 'passed', + 'REPROVADO: o próprio disco prevê falha': 'FAILED: the disk itself predicts failure', + // pré-visualização + 'Pré-visualização': 'Preview', + 'Pré-visualização de {n}': 'Preview of {n}', + 'vídeo': 'video', + 'áudio': 'audio', + 'Não foi possível reproduzir este {n}.': 'This {n} could not be played.', + 'compressão não suportada': 'compression not supported', + 'diretório do ZIP inconsistente': 'inconsistent ZIP directory', + 'diretório do ZIP não encontrado (arquivo possivelmente incompleto)': 'ZIP directory not found (file possibly incomplete)', + 'visualizador indisponível': 'viewer unavailable', + '© colaboradores do OpenStreetMap': '© OpenStreetMap contributors', }; From 16eced75d9974ce56f7f5a6cf2edf9713508fef1 Mon Sep 17 00:00:00 2001 From: Lucas Rayan Date: Tue, 20 Oct 2026 10:04:10 -0300 Subject: [PATCH 2/2] =?UTF-8?q?Interface:=20traduz=20r=C3=B3tulos=20do=20n?= =?UTF-8?q?=C3=BAcleo=20e=20redesenha=20o=20explorador=20ao=20trocar=20de?= =?UTF-8?q?=20idioma?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Achados ao rodar a interface real em inglês e varrer o DOM: - campos de metadados (EXIF, PDF, MP4), tipos de arquivo e rótulos de saúde do disco que vêm do núcleo em Rust; - textos que a interface divide em nós separados ("1 selecionado", "Sessão: nome", "Imagem · 27 KB", categorias com emoji); - avisos do visualizador de SQLite. Datas e títulos de mês são montados em JS no momento do desenho e ficavam no idioma antigo depois de trocar em Configurações. O explorador ganha relang() e a janela de Configurações o chama. Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01RRZm8uTVN3WLTwcbrDQAUM --- apps/gui/ui/app.js | 1 + apps/gui/ui/explorer.js | 2 ++ apps/gui/ui/i18n-en.js | 57 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/apps/gui/ui/app.js b/apps/gui/ui/app.js index 78fcf13..4841141 100644 --- a/apps/gui/ui/app.js +++ b/apps/gui/ui/app.js @@ -752,6 +752,7 @@ $('#settingsBtn')?.addEventListener('click', () => { const patch = { lang: d.querySelector('[name=lang]').value, notify: d.querySelector('[name=notify]').checked, maps: d.querySelector('[name=maps]').checked }; saveSettings(patch); setLang(patch.lang); + EX?.relang?.(); toast('Salvo'); }; d.showModal(); diff --git a/apps/gui/ui/explorer.js b/apps/gui/ui/explorer.js index 4c1a78d..0b3a147 100644 --- a/apps/gui/ui/explorer.js +++ b/apps/gui/ui/explorer.js @@ -669,6 +669,8 @@ export function createExplorer(deps) { }, query: () => toQuery(), destroy() { E.reloadToken++; stopPv?.(); stopLb?.(); host.innerHTML = ''; }, + /** Idioma trocado em Configurações: refaz o que foi montado em JS (datas, meses, rótulos). */ + relang() { paintCrumb(); paintChips(); paintNav(); paintActions(); paintInspector(); relayout(); }, focus() { scroll.focus({ preventScroll: true }); }, }; } diff --git a/apps/gui/ui/i18n-en.js b/apps/gui/ui/i18n-en.js index 95c52be..2559b06 100644 --- a/apps/gui/ui/i18n-en.js +++ b/apps/gui/ui/i18n-en.js @@ -448,4 +448,61 @@ export const EN = { 'diretório do ZIP não encontrado (arquivo possivelmente incompleto)': 'ZIP directory not found (file possibly incomplete)', 'visualizador indisponível': 'viewer unavailable', '© colaboradores do OpenStreetMap': '© OpenStreetMap contributors', + // explorador: textos que a interface divide em nós separados + 'selecionado': 'selected', + 'selecionados': 'selected', + 'selecionado (todos desta vista)': 'selected (all in this view)', + 'selecionados (todos desta vista)': 'selected (all in this view)', + 'Sessão: {n}': 'Session: {n}', + '🖼 Fotos': '🖼 Photos', + '📄 Documentos': '📄 Documents', + '🎞 Vídeos': '🎞 Videos', + '🎵 Áudio': '🎵 Audio', + '🗜 Compactados': '🗜 Archives', + '🗄 Bancos de dados': '🗄 Databases', + '📦 Outros': '📦 Other', + 'Imagem · {n}': 'Image · {n}', + 'Vídeo · {n}': 'Video · {n}', + 'Áudio · {n}': 'Audio · {n}', + 'Texto · {n}': 'Text · {n}', + 'Documento (texto extraído) · {n}': 'Document (extracted text) · {n}', + 'Conteúdo do arquivo compactado · {n}': 'Archive contents · {n}', + 'Banco de dados SQLite · {n}': 'SQLite database · {n}', + 'Dados brutos (hexadecimal) · {n}': 'Raw data (hexadecimal) · {n}', + // tipos e campos de metadados vindos do núcleo + 'Imagem JPEG': 'JPEG image', + 'Imagem PNG': 'PNG image', + 'Imagem GIF': 'GIF image', + 'Imagem BMP': 'BMP image', + 'Mídia MP4/MOV': 'MP4/MOV media', + 'Fabricante da câmera': 'Camera make', + 'Modelo da câmera': 'Camera model', + 'Data (EXIF)': 'Date (EXIF)', + 'Foto tirada em': 'Photo taken on', + 'Nº de série do corpo': 'Body serial number', + 'Proprietário da câmera': 'Camera owner', + 'Exposição': 'Exposure', + 'Distância focal': 'Focal length', + 'Data do GPS': 'GPS date', + 'Localização (GPS)': 'Location (GPS)', + 'Versão do PDF': 'PDF version', + 'Título': 'Title', + 'Criado com': 'Created with', + 'Páginas (aprox.)': 'Pages (approx.)', + 'Última modificação por': 'Last modified by', + 'Páginas': 'Pages', + 'Duração': 'Duration', + // saúde do disco e confiança vindas do núcleo + 'SSD (sem rotação)': 'SSD (no rotation)', + 'Cache de gravação': 'Write cache', + 'Segurança ATA': 'ATA security', + '{n} (máx. {n})': '{n} (max. {n})', + 'membro de RAID': 'RAID member', + 'sem rodapé/estrutura completa: pode estar truncado': 'no footer/complete structure: may be truncated', + 'vídeo sem índice (moov)': 'video without index (moov)', + // visualizador de SQLite + 'Nenhuma tabela encontrada no esquema. A primeira página pode estar danificada.': 'No table found in the schema. The first page may be damaged.', + 'Tabela virtual: o conteúdo não fica armazenado como linhas comuns.': 'Virtual table: the content is not stored as ordinary rows.', + 'Tabela WITHOUT ROWID: as linhas ficam numa árvore de índice, ainda não exibida.': 'WITHOUT ROWID table: the rows live in an index tree, not shown yet.', + 'Arquivo truncado: o cabeçalho indica {n} páginas, mas só há {n}. Parte dos dados pode estar faltando.': 'Truncated file: the header says {n} pages, but there are only {n}. Part of the data may be missing.', };