diff --git a/apps/gui/ui/app.js b/apps/gui/ui/app.js index 95c3deb..4841141 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: '' }, ] }); @@ -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 e502202..2559b06 100644 --- a/apps/gui/ui/i18n-en.js +++ b/apps/gui/ui/i18n-en.js @@ -406,4 +406,103 @@ 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', + // 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.', };