Merge pull request #217 from RicSchonfelder/i18n-pt-br

Ported onto the current language plumbing next to Spanish (catalog codes,
Match System for pt-* locales, native menu Services label, docs, tests);
the language list and settings validation stay the shared LANGUAGES table.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QiAJeFttZp83Fh7YuzAR5f
This commit is contained in:
Claude committed 2026-10-10 12:57:01 +00:00
commit 816fc855d8
4 files changed
+690 -4

No files matched your search

+4
View File
@@ -584,6 +584,10 @@ fn interface_language_is_validated_persisted_and_backward_compatible() {
s.execute("prefs.set", json!({"key": "general.language", "value": "en"})).unwrap();
s.execute("prefs.set", json!({"key": "general.language", "value": "ja"})).unwrap();
assert_eq!(s.execute("prefs.get", json!({"key": "general.language"})).unwrap(), json!("ja"));
// pt-br is registered alongside en and ja, and round-trips through the file like any other.
s.execute("prefs.set", json!({"key": "general.language", "value": "pt-br"})).unwrap();
assert_eq!(s.execute("prefs.get", json!({"key": "general.language"})).unwrap(), json!("pt-br"));
s.execute("prefs.set", json!({"key": "general.language", "value": "ja"})).unwrap();
let saved = store.read(PREFS_FILE).unwrap();
for bad in [json!("fr"), json!(""), json!(17), json!(null)] {
assert!(s.execute("prefs.set", json!({"key": "general.language", "value": bad})).is_err());
+683 -3
View File
@@ -11,7 +11,7 @@ use effectcraft_engine::menus::MenuEntry;
pub(crate) use ui::{set_current, tr, tr_args};
/// Every language with a catalog, in the order Settings ▸ General ▸ Language lists them.
const CATALOG_CODES: [&str; 5] = ["ja", "zh-hans", "zh-hant", "uk", "es"];
const CATALOG_CODES: [&str; 6] = ["ja", "zh-hans", "zh-hant", "uk", "es", "pt-br"];
/// The active interface language: the stored preference when it names a catalog, otherwise `en`
/// (English is the source of every label and needs no lookup).
@@ -52,6 +52,11 @@ pub(crate) fn spanish(app: &EffectcraftApp) -> bool {
language(app) == "es"
}
/// The UI is in Brazilian Portuguese.
pub(crate) fn brazilian_portuguese(app: &EffectcraftApp) -> bool {
language(app) == "pt-br"
}
/// Settings ▸ General ▸ Language ▸ Match System: the operating system's interface language
/// where EffectCraft has it, else English (#229), as After Effects installs in the system's
/// language. The browser build stays in English because it has no system-locale probe.
@@ -67,7 +72,7 @@ fn system_language() -> &'static str {
}
/// The language EffectCraft shows for a BCP 47 locale (`ja-JP` → `ja`, `zh-Hans-CN` → `zh-hans`,
/// `zh-TW` → `zh-hant`, `uk-UA` → `uk`, `es-ES` → `es`).
/// `zh-TW` → `zh-hant`, `uk-UA` → `uk`, `es-ES` → `es`, `pt-BR` → `pt-br`).
fn supported(locale: Option<&str>) -> &'static str {
let Some(locale) = locale else { return "en" };
let mut parts = locale.split(['-', '_']);
@@ -77,6 +82,8 @@ fn supported(locale: Option<&str>) -> &'static str {
"ja" => "ja",
"uk" => "uk",
"es" => "es",
// The only Portuguese catalog: Brazil's, also for Portugal rather than English.
"pt" => "pt-br",
"zh" => {
let traditional = rest.iter().any(|p| p.starts_with("hant") || p.starts_with("tw") || p.starts_with("hk") || p.starts_with("mo"));
if traditional { "zh-hant" } else { "zh-hans" }
@@ -102,6 +109,7 @@ pub(crate) fn label<'a>(app: &EffectcraftApp, command: &str, source: &'a str) ->
"zh-hant" => lookup(TRADITIONAL_CHINESE, command, source),
"uk" => lookup(UKRAINIAN, command, source),
"es" => lookup(SPANISH, command, source),
"pt-br" => lookup(PORTUGUESE, command, source),
_ => source,
}
}
@@ -121,6 +129,7 @@ pub(crate) fn entry(app: &EffectcraftApp, e: &MenuEntry, shown: String) -> Strin
"zh-hant" => ("復原", "沒有可復原的操作", "重做", "沒有可重做的操作"),
"uk" => ("Скасувати", "Немає дій для скасування", "Повторити", "Немає дій для повторення"),
"es" => ("Deshacer", "No se puede deshacer", "Rehacer", "No se puede rehacer"),
"pt-br" => ("Desfazer", "Não há nada para desfazer", "Refazer", "Não há nada para refazer"),
_ => return shown,
};
match e.command.as_str() {
@@ -198,6 +207,17 @@ pub(crate) fn submenu(app: &EffectcraftApp, source: &str, shown: String) -> Stri
return format!("Asignar método abreviado a la vista 3D “{name}”");
}
}
"pt-br" => {
if source == "Assign Shortcut to Workspace" {
if let Some(name) = shown.strip_prefix("Assign Shortcut to “").and_then(|s| s.strip_suffix("” Workspace")) {
return format!("Atribuir atalho à área de trabalho “{name}”");
}
} else if source == "Assign Shortcut to 3D View"
&& let Some(name) = shown.strip_prefix("Assign Shortcut to “").and_then(|s| s.strip_suffix('”'))
{
return format!("Atribuir atalho à visualização 3D “{name}”");
}
}
_ => {}
}
label(app, "", &shown).into()
@@ -3317,6 +3337,628 @@ const SPANISH: &[(&str, &str, &str)] = &[
("file.openDemoProject", "Open Demo Project", "Abrir proyecto de demostración"),
];
/// Brazilian Portuguese: the same (command, English label) keys as `JAPANESE`, one entry
/// per fixed menu row of the engine's menu tree.
const PORTUGUESE: &[(&str, &str, &str)] = &[
("", "EffectCraft", "EffectCraft"),
("app.about", "About EffectCraft...", "Sobre o EffectCraft..."),
("", "Settings...", "Configurações..."),
("app.settings", "General...", "Geral..."),
("app.settings", "Startup & Repair...", "Inicialização e reparo..."),
("app.settings", "Project...", "Projeto..."),
("app.settings", "Composition...", "Composição..."),
("app.settings", "Previews...", "Pré-visualizações..."),
("app.settings", "Appearance...", "Aparência..."),
("app.settings", "Grids & Guides...", "Grade e guias..."),
("app.settings", "Labels...", "Rótulos..."),
("app.settings", "Type...", "Texto..."),
("app.settings", "Import...", "Importação..."),
("app.settings", "Export...", "Exportação..."),
("app.settings", "Audio...", "Áudio..."),
("app.settings", "Disk...", "Disco..."),
("app.settings", "Memory & CPU...", "Memória e CPU..."),
("app.settings", "Video...", "Vídeo..."),
("app.settings", "3D...", "3D..."),
("app.settings", "Scripting & Expressions...", "Scripts e expressões..."),
("app.hide", "Hide EffectCraft", "Ocultar EffectCraft"),
("app.hideOthers", "Hide Others", "Ocultar outros"),
("app.showAll", "Show All", "Mostrar tudo"),
("app.quit", "Quit EffectCraft", "Sair do EffectCraft"),
("", "File", "Arquivo"),
("", "New", "Novo"),
("file.newProject", "New Project", "Novo projeto"),
("file.newFromTemplate", "New Project from Template...", "Novo projeto a partir de modelo..."),
("project.newFolder", "New Folder", "Nova pasta"),
("file.open", "Open Project...", "Abrir projeto..."),
("", "Open Recent", "Abrir recentes"),
("file.clearRecent", "Clear Recent Projects", "Limpar projetos recentes"),
("file.close", "Close", "Fechar"),
("file.closeProject", "Close Project", "Fechar projeto"),
("file.save", "Save", "Salvar"),
("", "Save As", "Salvar como"),
("file.saveAs", "Save As...", "Salvar como..."),
("file.saveCopy", "Save a Copy...", "Salvar uma cópia..."),
("file.saveCopyAsXml", "Save a Copy As XML...", "Salvar uma cópia como XML..."),
("templates.saveAs", "Save as Template...", "Salvar como modelo..."),
("file.incrementAndSave", "Increment and Save", "Incrementar e salvar"),
("file.revert", "Revert", "Reverter"),
("", "Import", "Importar"),
("file.import", "File...", "Arquivo..."),
("file.importMultiple", "Multiple Files...", "Vários arquivos..."),
("file.importTimeline", "Adobe Premiere Pro Project...", "Projeto do Adobe Premiere Pro..."),
("file.importPlaceholder", "Placeholder...", "Espaço reservado..."),
("file.importSolid", "Solid...", "Sólido..."),
("file.importLottie", "Lottie...", "Lottie..."),
("file.importVanishingPoint", "Vanishing Point (.vpe)...", "Vanishing Point (.vpe)..."),
("essential.importTemplate", "Essential Graphics Template...", "Modelo de gráficos essenciais..."),
("", "Import Recent Footage", "Importar mídias recentes"),
("file.clearRecentFootage", "Clear Recent Footage", "Limpar mídias recentes"),
("", "Export", "Exportar"),
("renderQueue.add", "Add to Render Queue", "Adicionar à fila de renderização"),
("file.exportTimeline", "Adobe Premiere Pro Project...", "Projeto do Adobe Premiere Pro..."),
("file.exportLottie", "Lottie JSON...", "Lottie JSON..."),
("essential.exportTemplate", "Essential Graphics Template...", "Modelo de gráficos essenciais..."),
("app.find", "Find", "Localizar"),
("layer.addItem", "Add Footage to Comp", "Adicionar mídia à composição"),
("file.newCompFromSelection", "New Comp from Selection...", "Nova composição a partir da seleção..."),
("", "Dependencies", "Dependências"),
("file.collectFiles", "Collect Files...", "Coletar arquivos..."),
("file.consolidateFootage", "Consolidate All Footage", "Consolidar todas as mídias"),
("file.removeUnusedFootage", "Remove Unused Footage", "Remover mídias não utilizadas"),
("file.reduceProject", "Reduce Project", "Reduzir projeto"),
("file.findMissing", "Find Missing Effects", "Localizar efeitos ausentes"),
("file.findMissing", "Find Missing Fonts", "Localizar fontes ausentes"),
("file.findMissing", "Find Missing Footage", "Localizar mídias ausentes"),
("file.watchFolder", "Watch Folder...", "Pasta monitorada..."),
("", "Scripts", "Scripts"),
("file.installScript", "Install Script File...", "Instalar arquivo de script..."),
("file.installScriptUIPanel", "Install ScriptUI Panel...", "Instalar painel ScriptUI..."),
("file.runScript", "Run Script File...", "Executar arquivo de script..."),
("", "Create Proxy", "Criar proxy"),
("file.createProxy", "Still...", "Imagem fixa..."),
("file.createProxy", "Movie...", "Filme..."),
("", "Set Proxy", "Definir proxy"),
("file.setProxy", "File...", "Arquivo..."),
("file.setProxyNone", "None", "Nenhum"),
("", "Interpret Footage", "Interpretar mídia"),
("file.interpretFootage", "Main...", "Principal..."),
("file.interpretProxy", "Proxy...", "Proxy..."),
("file.rememberInterpretation", "Remember Interpretation", "Lembrar interpretação"),
("file.applyInterpretation", "Apply Interpretation", "Aplicar interpretação"),
("", "Replace Footage", "Substituir mídia"),
("file.replaceFootage", "File...", "Arquivo..."),
("file.replaceWithPlaceholder", "Placeholder...", "Espaço reservado..."),
("file.replaceWithSolid", "Solid...", "Sólido..."),
("file.replaceWithLayeredComp", "With Layered Comp", "Por composição com camadas"),
("file.reloadFootage", "Reload Footage", "Recarregar mídia"),
("file.revealInFinder", "Reveal in Finder", "Mostrar no Finder"),
("file.projectSettings", "Project Settings...", "Configurações do projeto..."),
("app.quit", "Exit", "Sair"),
("", "Edit", "Editar"),
("edit.undo", "Undo", "Desfazer"),
("edit.redo", "Redo", "Refazer"),
("", "History", "Histórico"),
("app.commandPalette", "Quick Apply...", "Aplicação rápida..."),
("edit.cut", "Cut", "Recortar"),
("edit.copy", "Copy", "Copiar"),
("edit.copyWithPropertyLinks", "Copy with Property Links", "Copiar com vínculos de propriedade"),
("edit.copyWithRelativePropertyLinks", "Copy with Relative Property Links", "Copiar com vínculos de propriedade relativos"),
("edit.copyExpressionOnly", "Copy Expression Only", "Copiar apenas a expressão"),
("edit.paste", "Paste", "Colar"),
("edit.pasteReversedKeyframes", "Paste Reversed Keyframes", "Colar quadros-chave em ordem inversa"),
("edit.pasteTextMatchFormatting", "Paste Text and Match Formatting", "Colar texto e manter a formatação"),
("edit.pasteTextFormattingOnly", "Paste Text Formatting Only", "Colar apenas a formatação do texto"),
("edit.clear", "Clear", "Limpar"),
("edit.duplicate", "Duplicate", "Duplicar"),
("edit.splitLayer", "Split Layer", "Dividir camada"),
("edit.liftWorkArea", "Lift Work Area", "Retirar área de trabalho"),
("edit.extractWorkArea", "Extract Work Area", "Extrair área de trabalho"),
("edit.selectAll", "Select All", "Selecionar tudo"),
("edit.deselectAll", "Deselect All", "Desmarcar tudo"),
("", "Label", "Rótulo"),
("edit.selectLabelGroup", "Select Label Group", "Selecionar grupo de rótulos"),
("edit.label", "None", "Nenhum"),
("edit.label", "Red", "Vermelho"),
("edit.label", "Yellow", "Amarelo"),
("edit.label", "Aqua", "Aqua"),
("edit.label", "Pink", "Rosa"),
("edit.label", "Lavender", "Lavanda"),
("edit.label", "Peach", "Pêssego"),
("edit.label", "Sea Foam", "Espuma do mar"),
("edit.label", "Blue", "Azul"),
("edit.label", "Green", "Verde"),
("edit.label", "Purple", "Roxo"),
("edit.label", "Orange", "Laranja"),
("edit.label", "Brown", "Marrom"),
("edit.label", "Fuchsia", "Fúcsia"),
("edit.label", "Cyan", "Ciano"),
("edit.label", "Sandstone", "Arenito"),
("edit.label", "Dark Green", "Verde escuro"),
("app.settings", "Edit Label Colors...", "Editar cores dos rótulos..."),
("", "Select Keyframe Label Group", "Selecionar grupo de rótulos de quadros-chave"),
("keys.selectLabelGroup", "On Selected Layers", "Nas camadas selecionadas"),
("keys.selectLabelGroup", "On All Layers", "Em todas as camadas"),
("keys.selectLabelGroup", "Visible Keyframes on Selected Layers", "Quadros-chave visíveis nas camadas selecionadas"),
("keys.selectLabelGroup", "Visible Keyframes on All Layers", "Quadros-chave visíveis em todas as camadas"),
("", "Purge", "Limpar cache"),
("edit.purge", "All Cache...", "Todo o cache..."),
("edit.purge", "All Memory & Disk Cache...", "Toda a memória e o cache do disco..."),
("edit.purge", "All Memory", "Toda a memória"),
("edit.purge", "All Disk Cache...", "Todo o cache do disco..."),
("edit.purge", "All 3D Cache...", "Todo o cache 3D..."),
("edit.purgeUndo", "Undo", "Desfazer"),
("edit.purge", "Image Cache Memory", "Memória de cache de imagens"),
("edit.purge", "Snapshot", "Instantâneo"),
("edit.editOriginal", "Edit Original...", "Editar original..."),
("", "Templates", "Modelos"),
("app.templates", "Render Settings...", "Configurações de renderização..."),
("app.templates", "Output Module...", "Módulo de saída..."),
("app.keyboardShortcuts", "Keyboard Shortcuts", "Atalhos de teclado"),
("", "Preferences", "Preferências"),
("", "Composition", "Composição"),
("comp.new", "New Composition...", "Nova composição..."),
("comp.settings", "Composition Settings...", "Configurações da composição..."),
("comp.setPosterTime", "Set Poster Time", "Definir tempo do pôster"),
("comp.trimToWorkArea", "Trim Comp to Work Area", "Ajustar composição à área de trabalho"),
("comp.cropToRegionOfInterest", "Crop Comp to Region of Interest", "Recortar composição para a região de interesse"),
("comp.cropToLayerBounds", "Crop Comp to Selected Layer(s) Bounds", "Recortar composição aos limites das camadas selecionada(s)"),
("render.addOutputModule", "Add Output Module", "Adicionar módulo de saída"),
("", "Preview", "Pré-visualização"),
("playback.toggle", "Play Current Preview", "Reproduzir pré-visualização atual"),
("playback.cacheWhenIdle", "Cache Frames When Idle", "Armazenar quadros quando ocioso"),
("playback.audio", "Audio", "Áudio"),
("", "Save Frame As", "Salvar quadro como"),
("comp.saveFrameAs", "File...", "Arquivo..."),
("comp.saveFrameAsPsd", "Photoshop Layers...", "Camadas do Photoshop..."),
("comp.saveFrameAsExr", "ProEXR...", "ProEXR..."),
("render.preRender", "Pre-render...", "Pré-renderização..."),
("render.saveCurrentPreview", "Save Current Preview...", "Salvar pré-visualização atual..."),
("comp.openInEssentialGraphics", "Open in Essential Graphics", "Abrir em Gráficos essenciais"),
("", "Responsive Design — Time", "Design responsivo — Tempo"),
("comp.responsiveTime", "Create Intro", "Criar introdução"),
("comp.responsiveTime", "Create Outro", "Criar encerramento"),
("comp.responsiveTime", "Create Protected Region from Work Area", "Criar região protegida a partir da área de trabalho"),
("comp.flowchart", "Composition Flowchart", "Fluxograma da composição"),
("comp.miniFlowchart", "Composition Mini-Flowchart", "Minifluxograma da composição"),
("", "VR", "VR"),
("comp.vr.createEnvironment", "Create VR Environment...", "Criar ambiente VR..."),
("comp.vr.extractCubemap", "Extract Cubemap...", "Extrair cubemapa..."),
("", "Layer", "Camada"),
("layer.newText", "Text", "Texto"),
("layer.newSolid", "Solid...", "Sólido..."),
("layer.newLight", "Light...", "Luz..."),
("layer.newCamera", "Camera...", "Câmera..."),
("layer.newNull", "Null Object", "Objeto nulo"),
("layer.newShape", "Shape Layer", "Camada de forma"),
("layer.newAdjustment", "Adjustment Layer", "Camada de ajuste"),
("layer.newContentAwareFill", "Content-Aware Fill Layer...", "Camada de preenchimento sensível ao conteúdo..."),
("layer.new3dPrimitive", "Cube", "Cubo"),
("layer.new3dPrimitive", "Sphere", "Esfera"),
("layer.new3dPrimitive", "Plane", "Plano"),
("layer.new3dPrimitive", "Torus", "Toro"),
("layer.new3dPrimitive", "Cone", "Cone"),
("layer.new3dPrimitive", "Cylinder", "Cilindro"),
("layer.settings", "Layer Settings...", "Configurações da camada..."),
("layer.openLayer", "Open Layer", "Abrir camada"),
("layer.openSource", "Open Layer Source", "Abrir a fonte da camada"),
("layer.revealInFinder", "Reveal in Finder", "Mostrar no Finder"),
("", "Mask", "Máscara"),
("layer.addMask", "New Mask", "Nova máscara"),
("layer.mask.shape", "Mask Shape...", "Forma da máscara..."),
("layer.mask.set", "Mask Feather...", "Pena da máscara..."),
("layer.mask.set", "Mask Opacity...", "Opacidade da máscara..."),
("layer.mask.set", "Mask Expansion...", "Expansão da máscara..."),
("layer.mask.reset", "Reset Mask", "Redefinir máscara"),
("layer.mask.remove", "Remove Mask", "Remover máscara"),
("layer.mask.removeAll", "Remove All Masks", "Remover todas as máscaras"),
("track.mask", "Track Mask", "Rastrear máscara"),
("", "Mode", "Modo"),
("layer.mask.mode", "None", "Nenhum"),
("layer.mask.mode", "Add", "Adicionar"),
("layer.mask.mode", "Subtract", "Subtrair"),
("layer.mask.mode", "Intersect", "Interseção"),
("layer.mask.mode", "Lighten", "Clarear"),
("layer.mask.mode", "Darken", "Escurecer"),
("layer.mask.mode", "Difference", "Diferença"),
("layer.mask.invert", "Inverted", "Invertida"),
("layer.mask.lock", "Locked", "Bloqueada"),
("", "Motion Blur", "Borrão de movimento"),
("layer.mask.motionBlur", "Same As Layer", "Igual à camada"),
("layer.mask.motionBlur", "On", "Ativado"),
("layer.mask.motionBlur", "Off", "Desativado"),
("", "Feather Falloff", "Decaimento da pena"),
("layer.mask.featherFalloff", "Smooth", "Suavizar"),
("layer.mask.featherFalloff", "Linear", "Linear"),
("layer.mask.unlockAll", "Unlock All Masks", "Desbloquear todas as máscaras"),
("layer.mask.lockOthers", "Lock Other Masks", "Bloquear outras máscaras"),
("layer.mask.hideLocked", "Hide Locked Masks", "Ocultar máscaras bloqueadas"),
("", "Mask and Shape Path", "Caminho da máscara e da forma"),
("path.rotoBezier", "RotoBezier", "RotoBezier"),
("mask.setClosed", "Closed", "Fechado"),
("path.convertToBezier", "Convert To Bezier Path", "Converter em caminho Bézier"),
("path.setFirstVertex", "Set First Vertex", "Definir primeiro vértice"),
("path.freeTransform", "Free Transform Points", "Pontos de transformação livre"),
("", "Quality", "Qualidade"),
("layer.quality", "Best", "Melhor"),
("layer.quality", "Draft", "Rascunho"),
("layer.quality", "Wireframe", "Wireframe"),
("layer.sampling", "Bilinear", "Bilinear"),
("layer.sampling", "Bicubic", "Bicúbico"),
("", "Switches", "Interruptores"),
("layer.hideOtherVideo", "Hide Other Video", "Ocultar os outros vídeos"),
("layer.showAllVideo", "Show All Video", "Mostrar todos os vídeos"),
("layer.unlockAll", "Unlock All Layers", "Desbloquear todas as camadas"),
("layer.expressions", "Enable Expressions", "Ativar expressões"),
("layer.expressions", "Disable Expressions", "Desativar expressões"),
("layer.setSwitch", "Shy", "Escondida"),
("layer.setSwitch", "Lock", "Bloquear"),
("layer.setSwitch", "Audio", "Áudio"),
("layer.setSwitch", "Video", "Vídeo"),
("layer.setSwitch", "Solo", "Solo"),
("layer.setSwitch", "Effect", "Efeito"),
("layer.setSwitch", "Collapse", "Colapsar"),
("layer.setSwitch", "Motion Blur", "Borrão de movimento"),
("layer.setSwitch", "Adjustment Layer", "Camada de ajuste"),
("", "Transform", "Transformar"),
("layer.transform", "Reset", "Redefinir"),
("layer.setTransform", "Anchor Point...", "Ponto de ancoragem..."),
("layer.setTransform", "Position...", "Posição..."),
("layer.setTransform", "Scale...", "Escala..."),
("layer.setTransform", "Orientation...", "Orientação..."),
("layer.setTransform", "Rotation...", "Rotação..."),
("layer.setTransform", "Opacity...", "Opacidade..."),
("layer.transform", "Flip Horizontal", "Espelhar horizontalmente"),
("layer.transform", "Flip Vertical", "Espelhar verticalmente"),
("layer.transform", "Center In View", "Centralizar na visualização"),
("layer.centerAnchor", "Center Anchor Point in Layer Content", "Centralizar ponto de ancoragem no conteúdo da camada"),
("layer.transform", "Fit to Comp", "Ajustar à composição"),
("layer.transform", "Fit to Comp Width", "Ajustar à largura da composição"),
("layer.transform", "Fit to Comp Height", "Ajustar à altura da composição"),
("layer.autoOrient", "Auto-Orient...", "Auto-orientar..."),
("", "Time", "Tempo"),
("layer.enableTimeRemap", "Enable Time Remapping", "Ativar remapeamento de tempo"),
("layer.timeReverse", "Time-Reverse Layer", "Inverter tempo da camada"),
("layer.timeStretch", "Time Stretch...", "Redefinir duração..."),
("layer.freezeFrame", "Freeze Frame", "Congelar quadro"),
("layer.freezeOnLastFrame", "Freeze On Last Frame", "Congelar no último quadro"),
("layer.alignVideoToData", "Align Video to Data", "Alinhar vídeo aos dados"),
("", "Frame Blending", "Blenda de quadros"),
("layer.frameBlending", "Off", "Desativado"),
("layer.frameBlending", "Frame Mix", "Mistura de quadros"),
("layer.frameBlending", "Pixel Motion", "Movimento de pixels"),
("layer.setSwitch", "3D Layer", "Camada 3D"),
("layer.setSwitch", "Guide Layer", "Camada de guia"),
("layer.environment", "Environment Layer", "Camada de ambiente"),
("", "Markers", "Marcadores"),
("layer.addMarker", "Add Marker", "Adicionar marcador"),
("layer.updateMarkersFromSource", "Update Markers From Source", "Atualizar marcadores da origem"),
("layer.markersLock", "Lock Markers", "Bloquear marcadores"),
("layer.deleteAllMarkers", "Delete All Markers", "Excluir todos os marcadores"),
("layer.setSwitch", "Preserve Transparency", "Preservar transparência"),
("", "Blending Mode", "Modo de mesclagem"),
("layer.setBlendMode", "Normal", "Normal"),
("layer.setBlendMode", "Dissolve", "Dissolver"),
("layer.setBlendMode", "Dancing Dissolve", "Dissolver dinâmico"),
("layer.setBlendMode", "Darken", "Escurecer"),
("layer.setBlendMode", "Multiply", "Multiplicar"),
("layer.setBlendMode", "Color Burn", "Superexposição de cores"),
("layer.setBlendMode", "Classic Color Burn", "Superexposição de cores clássica"),
("layer.setBlendMode", "Linear Burn", "Superexposição linear"),
("layer.setBlendMode", "Darker Color", "Cor mais escura"),
("layer.setBlendMode", "Add", "Adição"),
("layer.setBlendMode", "Lighten", "Clarear"),
("layer.setBlendMode", "Screen", "Divisão"),
("layer.setBlendMode", "Color Dodge", "Subexposição de cores"),
("layer.setBlendMode", "Classic Color Dodge", "Subexposição de cores clássica"),
("layer.setBlendMode", "Linear Dodge", "Subexposição linear"),
("layer.setBlendMode", "Lighter Color", "Cor mais clara"),
("layer.setBlendMode", "Overlay", "Sobrepor"),
("layer.setBlendMode", "Soft Light", "Luz suave"),
("layer.setBlendMode", "Hard Light", "Luz forte"),
("layer.setBlendMode", "Linear Light", "Luz linear"),
("layer.setBlendMode", "Vivid Light", "Luz viva"),
("layer.setBlendMode", "Pin Light", "Luz pontual"),
("layer.setBlendMode", "Hard Mix", "Mistura dura"),
("layer.setBlendMode", "Difference", "Diferença"),
("layer.setBlendMode", "Classic Difference", "Diferença clássica"),
("layer.setBlendMode", "Exclusion", "Exclusão"),
("layer.setBlendMode", "Subtract", "Subtrair"),
("layer.setBlendMode", "Divide", "Dividir"),
("layer.setBlendMode", "Hue", "Matiz"),
("layer.setBlendMode", "Saturation", "Saturação"),
("layer.setBlendMode", "Color", "Cor"),
("layer.setBlendMode", "Luminosity", "Luminosidade"),
("layer.setBlendMode", "Stencil Alpha", "Estêncil alfa"),
("layer.setBlendMode", "Stencil Luma", "Estêncil luminância"),
("layer.setBlendMode", "Silhouette Alpha", "Silhueta alfa"),
("layer.setBlendMode", "Silhouette Luma", "Silhueta luminância"),
("layer.setBlendMode", "Alpha Add", "Adição alfa"),
("layer.setBlendMode", "Luminescent Premul", "Pré-multiplicação luminescente"),
("layer.setBlendMode", "Next Blending Mode", "Modo de mesclagem seguinte"),
("layer.setBlendMode", "Previous Blending Mode", "Modo de mesclagem anterior"),
("", "Track Matte", "Track matte"),
("layer.trackMatte", "No Track Matte", "Sem track matte"),
("layer.trackMatte", "Alpha Matte", "Matte alfa"),
("layer.trackMatte", "Alpha Inverted Matte", "Matte alfa invertida"),
("layer.trackMatte", "Luma Matte", "Matte de luminância"),
("layer.trackMatte", "Luma Inverted Matte", "Matte de luminância invertida"),
("layer.trackMatte", "Matte with Layer Above", "Matte com a camada acima"),
("layer.trackMatte", "Matte with Layer Below", "Matte com a camada abaixo"),
("", "Layer Styles", "Estilos de camada"),
("layer.style.options", "Layer Style Options...", "Opções de estilo de camada..."),
("layer.style.convertToEditable", "Convert to Editable Styles", "Converter em estilos editáveis"),
("layer.style.showAll", "Show All", "Mostrar todos"),
("layer.style.removeAll", "Remove All", "Remover todos"),
("layer.style.dropShadow", "Drop Shadow", "Sombra projetada"),
("layer.style.innerShadow", "Inner Shadow", "Sombra interna"),
("layer.style.outerGlow", "Outer Glow", "Brilho externo"),
("layer.style.innerGlow", "Inner Glow", "Brilho interno"),
("layer.style.bevelEmboss", "Bevel and Emboss", "Chanfro e relevo"),
("layer.style.satin", "Satin", "Satin"),
("layer.style.colorOverlay", "Color Overlay", "Sobreposição de cores"),
("layer.style.gradientOverlay", "Gradient Overlay", "Sobreposição de gradiente"),
("layer.style.stroke", "Stroke", "Traçado"),
("path.groupShapes", "Group Shapes", "Agrupar formas"),
("path.ungroupShapes", "Ungroup Shapes", "Desagrupar formas"),
("", "Arrange", "Organizar"),
("layer.arrange", "Bring Layer to Front", "Trazer camada para o topo"),
("layer.arrange", "Bring Layer Forward", "Trazer camada para a frente"),
("layer.arrange", "Send Layer Backward", "Enviar camada para trás"),
("layer.arrange", "Send Layer to Back", "Enviar camada para o fundo"),
("", "Reveal", "Revelar"),
("layer.revealSource", "Reveal Layer Source in Project", "Revelar origem da camada no projeto"),
("comp.flowchart", "Reveal Layer in Project Flowchart", "Revelar camada no fluxograma do projeto"),
("comp.revealInProject", "Reveal Composition in Project", "Revelar composição no projeto"),
("layer.revealExpressionErrors", "Reveal Expression Errors", "Revelar erros de expressão"),
("", "Create", "Criar"),
("layer.create", "Convert to Editable Text", "Converter em texto editável"),
("layer.create", "Create Shapes from Text", "Criar formas a partir do texto"),
("layer.create", "Create Masks from Text", "Criar máscaras a partir do texto"),
("layer.create", "Create Shapes from Vector Layer", "Criar formas a partir da camada vetorial"),
("layer.create", "Create Keyframes from Data", "Criar quadros-chave a partir de dados"),
("layer.create", "Null Controllers for Positional Points", "Controles null para pontos posicionais"),
("layer.create", "Null Controllers for Path Points", "Controles null para pontos do caminho"),
("layer.create", "Nulls Following Path Points", "Nulls seguindo pontos do caminho"),
("layer.create", "Null Tracing Along Path", "Null traçando ao longo do caminho"),
("layer.create", "Create 3D Layer Instance", "Criar instância de camada 3D"),
("", "Camera", "Câmera"),
("camera.fromView", "Create Camera from 3D View", "Criar câmera a partir da visualização 3D"),
("camera.stereoRig", "Create Stereo 3D Rig", "Criar estrutura 3D estéreo"),
("camera.orbitNull", "Create Orbit Null", "Criar null de órbita"),
("camera.fromModel", "Create Cameras from 3D Model", "Criar câmeras a partir de modelo 3D"),
("camera.linkFocusToPoi", "Link Focus Distance to Point of Interest", "Vincular distância de foco ao ponto de interesse"),
("camera.linkFocusToLayer", "Link Focus Distance to Layer", "Vincular distância de foco à camada"),
("camera.setFocusToLayer", "Set Focus Distance to Layer", "Definir distância de foco para a camada"),
("layer.cameraSettings", "Camera Settings...", "Configurações da câmera..."),
("view.reset3DView", "Reset 3D View", "Redefinir visualização 3D"),
("", "Light", "Luz"),
("light.fromModel", "Create Lights from 3D Model", "Criar luzes a partir de modelo 3D"),
("light.controlWithCamera", "Control Light with Camera", "Controlar luz com a câmera"),
("light.environmentBackground", "Create Environment Light Background Layer", "Criar camada de fundo de luz ambiente"),
("", "Material", "Material"),
("material.revealSource", "Reveal Material Source in Project", "Revelar origem do material no projeto"),
("material.reset", "Reset Material", "Redefinir material"),
("material.duplicateAssign", "Duplicate and Assign Material", "Duplicar e atribuir material"),
("layer.autoTrace", "Auto-trace...", "Traçado automático..."),
("layer.precompose", "Pre-compose...", "Pré-compor..."),
("layer.sceneEditDetection", "Scene Edit Detection...", "Detecção de edição de cena..."),
("", "Effect", "Efeito"),
("window.panel", "Effect Controls", "Controles de efeito"),
("effect.applyLast", "Last Effect", "Último efeito"),
("effect.removeAll", "Remove All", "Remover todos"),
("effect.manage", "Manage Effects...", "Gerenciar efeitos..."),
("effect.plugins.load", "Load Effect Plug-in...", "Carregar plug-in de efeito..."),
("", "Animation", "Animação"),
("anim.savePreset", "Save Animation Preset...", "Salvar predefinição de animação..."),
("anim.applyPreset", "Apply Animation Preset...", "Aplicar predefinição de animação..."),
("", "Recent Animation Presets", "Predefinições de animação recentes"),
("anim.clearRecentPresets", "Clear Recent Presets", "Limpar predefinições recentes"),
("anim.browsePresets", "Browse Presets...", "Procurar predefinições..."),
("", "Text Animation Presets", "Predefinições de animação de texto"),
("layer.applyTextPreset", "Typewriter", "Máquina de escrever"),
("layer.applyTextPreset", "Fade Up Characters", "Aparecer caractere a caractere"),
("layer.applyTextPreset", "Bounce In Words", "Entrar quicando nas palavras"),
("layer.applyTextPreset", "Tracking In", "Entrar com espaçamento"),
("layer.applyTextPreset", "Scramble", "Embaralhar"),
("layer.applyTextPreset", "Blur In", "Entrar desfocado"),
("layer.applyTextPreset", "Jitter", "Tremor"),
("layer.applyTextPreset", "Drop In Lines", "Entrar com queda de linhas"),
("anim.addKeyframe", "Add Keyframe", "Adicionar quadro-chave"),
("keys.toggleHold", "Toggle Hold Keyframe", "Alternar quadro-chave de retenção"),
("keys.interpolation", "Keyframe Interpolation...", "Interpolação de quadro-chave..."),
("keys.velocity", "Keyframe Velocity...", "Velocidade do quadro-chave..."),
("", "Keyframe Assistant", "Assistente de quadro-chave"),
("keys.audioToKeyframes", "Convert Audio to Keyframes", "Converter áudio em quadros-chave"),
("prop.convertExpressionToKeyframes", "Convert Expression to Keyframes", "Converter expressão em quadros-chave"),
("keys.easyEase", "Easy Ease", "Easy Ease"),
("keys.easyEaseIn", "Easy Ease In", "Easy Ease In"),
("keys.easyEaseOut", "Easy Ease Out", "Easy Ease Out"),
("keys.exponentialScale", "Exponential Scale", "Escala exponencial"),
("keys.rpfCameraImport", "RPF Camera Import", "Importação de câmera RPF"),
("layer.sequence", "Sequence Layers...", "Sequenciar camadas..."),
("keys.timeReverse", "Time-Reverse Keyframes", "Inverter ordem dos quadros-chave"),
("", "Animate Text", "Animar texto"),
("layer.enablePerChar3D", "Enable Per-character 3D", "Ativar 3D por caractere"),
("layer.addTextAnimator", "Anchor Point", "Ponto de ancoragem"),
("layer.addTextAnimator", "Position", "Posição"),
("layer.addTextAnimator", "Scale", "Escala"),
("layer.addTextAnimator", "Skew", "Distorção"),
("layer.addTextAnimator", "Rotation", "Rotação"),
("layer.addTextAnimator", "Opacity", "Opacidade"),
("layer.addTextAnimator", "All Transform Properties", "Todas as propriedades de transformação"),
("", "Fill Color", "Cor de preenchimento"),
("layer.addTextAnimator", "RGB", "RGB"),
("layer.addTextAnimator", "Hue", "Matiz"),
("layer.addTextAnimator", "Saturation", "Saturação"),
("layer.addTextAnimator", "Brightness", "Brilho"),
("", "Stroke Color", "Cor do traçado"),
("layer.addTextAnimator", "Stroke Width", "Largura do traçado"),
("layer.addTextAnimator", "Tracking", "Tracking"),
("layer.addTextAnimator", "Line Anchor", "Âncora da linha"),
("layer.addTextAnimator", "Line Spacing", "Espaçamento entre linhas"),
("layer.addTextAnimator", "Character Offset", "Deslocamento de caractere"),
("layer.addTextAnimator", "Character Value", "Valor do caractere"),
("layer.addTextAnimator", "Blur", "Desfoque"),
("text.animatorFontAxes", "Variable Font Axes", "Eixos de fonte variável"),
("", "Add Text Selector", "Adicionar seletor de texto"),
("text.addSelector", "Range", "Intervalo"),
("text.addSelector", "Wiggly", "Oscilante"),
("text.addSelector", "Expression", "Expressão"),
("text.removeAllAnimators", "Remove All Text Animators", "Remover todos os animadores de texto"),
("prop.setExpression", "Add Expression", "Adicionar expressão"),
("essential.addProperty", "Add Property to Essential Graphics", "Adicionar propriedade ao Gráficos essenciais"),
("prop.separateDimensions", "Separate Dimensions", "Dimensões separadas"),
("track.camera", "Track Camera", "Rastrear câmera"),
("track.warpStabilizer", "Warp Stabilizer VFX", "Warp Stabilizer VFX"),
("track.motion", "Track Motion", "Rastrear movimento"),
("track.stabilize", "Stabilize Motion", "Estabilizar movimento"),
("track.property", "Track this Property", "Rastrear esta propriedade"),
("anim.reveal", "Reveal Properties with Keyframes", "Revelar propriedades com quadros-chave"),
("anim.reveal", "Reveal Properties with Animation", "Revelar propriedades com animação"),
("anim.reveal", "Reveal All Modified Properties", "Revelar todas as propriedades modificadas"),
("", "View", "Exibir"),
("view.newViewer", "New Viewer", "Nova visualização"),
("view.splitLockedViewer", "Split with New Locked Viewer", "Dividir com nova visualização bloqueada"),
("view.zoomIn", "Zoom In", "Aproximar"),
("view.zoomOut", "Zoom Out", "Afastar"),
("", "Resolution", "Resolução"),
("view.res.full", "Full", "Total"),
("view.res.half", "Half", "Meio"),
("view.res.third", "Third", "Um terço"),
("view.res.quarter", "Quarter", "Um quarto"),
("view.res.custom", "Custom...", "Personalizado..."),
("view.displayColorManagement", "Use Display Color Management", "Usar gerenciamento de cores do monitor"),
("", "Simulate Output", "Simular saída"),
("view.simulateOutput", "No Output Simulation", "Sem simulação de saída"),
("view.simulateOutput", "HDTV (Rec. 709)", "HDTV (Rec. 709)"),
("view.simulateOutput", "SDTV NTSC", "SDTV NTSC"),
("view.simulateOutput", "SDTV PAL", "SDTV PAL"),
("view.simulateOutput", "Legacy Macintosh RGB (Gamma 1.8)", "RGB legado do Macintosh (Gamma 1.8)"),
("view.simulateOutput", "Internet Standard RGB (sRGB)", "RGB padrão da internet (sRGB)"),
("view.simulateOutput", "UHDTV (Rec. 2020)", "UHDTV (Rec. 2020)"),
("view.simulateOutput", "Display P3", "Display P3"),
("view.simulateOutput", "Linear (1.0 Gamma)", "Linear (Gamma 1.0)"),
("view.customRgb", "My Custom RGB...", "Meu RGB personalizado..."),
("view.simulateOutput", "Custom...", "Personalizado..."),
("view.rulers", "Show Rulers", "Mostrar réguas"),
("", "Panel Background Color", "Cor de fundo do painel"),
("view.panelBackground", "Black", "Preto"),
("view.panelBackground", "Dark Gray", "Cinza escuro"),
("view.panelBackground", "Medium Gray (Default)", "Cinza médio (padrão)"),
("view.panelBackground", "Light Gray", "Cinza claro"),
("view.panelBackground", "White", "Branco"),
("view.panelBackground", "Custom", "Personalizado"),
("view.panelBackground", "Select Custom Background Color...", "Selecionar cor de fundo personalizada..."),
("view.guides", "Show Guides", "Mostrar guias"),
("view.snapToGuides", "Snap to Guides", "Encaixar nas guias"),
("view.lockGuides", "Lock Guides", "Bloquear guias"),
("view.addGuide", "Add Guide...", "Adicionar guia..."),
("view.clearGuides", "Clear Guides", "Limpar guias"),
("view.importGuides", "Import Guides...", "Importar guias..."),
("view.exportGuides", "Export Guides...", "Exportar guias..."),
("view.grid", "Show Grid", "Mostrar grade"),
("view.snapToGrid", "Snap to Grid", "Encaixar na grade"),
("view.snapping", "Snapping", "Encaixe"),
("view.options", "View Options...", "Opções de visualização..."),
("view.layerControls", "Show Layer Controls", "Mostrar controles da camada"),
("", "Switch View Layout", "Alternar layout de visualização"),
("view.layout", "1 View", "1 visualização"),
("view.layout", "2 Views", "2 visualizações"),
("view.layout", "4 Views", "4 visualizações"),
("view.shareViewOptions", "Share View Options", "Compartilhar opções de visualização"),
("", "Switch 3D View", "Alternar visualização 3D"),
("view.3d.activeCamera", "Active Camera", "Câmera ativa"),
("view.3d.default", "Default", "Padrão"),
("view.3d.front", "Front", "Frente"),
("view.3d.left", "Left", "Esquerda"),
("view.3d.top", "Top", "Topo"),
("view.3d.back", "Back", "Atrás"),
("view.3d.right", "Right", "Direita"),
("view.3d.bottom", "Bottom", "Base"),
("view.3d.custom1", "Custom View 1", "Visualização personalizada 1"),
("view.3d.custom2", "Custom View 2", "Visualização personalizada 2"),
("view.3d.custom3", "Custom View 3", "Visualização personalizada 3"),
("", "Assign Shortcut to 3D View", "Atribuir atalho à visualização 3D"),
("view.3d.last", "Switch to Last 3D View", "Alternar para a última visualização 3D"),
("view.lookAtSelected", "Look at Selected Layers", "Olhar para as camadas selecionadas"),
("view.lookAtAll", "Look at All Layers", "Olhar para todas as camadas"),
("time.set", "Go to Time...", "Ir para o tempo..."),
("view.fullScreen", "Enter Full Screen", "Entrar em tela cheia"),
("", "Window", "Janela"),
("", "Workspace", "Área de trabalho"),
("window.workspace", "Default", "Inicial"),
("window.workspace", "Review", "Revisão"),
("window.workspace", "Learn", "Aprender"),
("window.workspace", "Small Screen", "Tela pequena"),
("window.workspace", "Standard", "Padrão"),
("window.workspace", "All Panels", "Todos os painéis"),
("window.workspace", "Animation", "Animação"),
("window.workspace", "Color", "Cores"),
("window.workspace", "Effects", "Efeitos"),
("window.workspace", "Essential Graphics", "Gráficos essenciais"),
("window.workspace", "Minimal", "Mínimo"),
("window.workspace", "Motion Tracking", "Rastreamento de movimento"),
("window.workspace", "Paint", "Pintura"),
("window.workspace", "Text", "Texto"),
("window.workspace", "Undocked Panels", "Painéis desacoplados"),
("window.resetWorkspace", "Reset to Saved Layout", "Redefinir para o layout salvo"),
("window.saveWorkspace", "Save Changes to this Workspace", "Salvar alterações nesta área de trabalho"),
("window.saveWorkspaceAs", "Save as New Workspace...", "Salvar como nova área de trabalho..."),
("window.editWorkspaces", "Edit Workspaces...", "Editar áreas de trabalho..."),
("", "Assign Shortcut to Workspace", "Atribuir atalho à área de trabalho"),
("window.panel", "Align", "Alinhar"),
("window.panel", "Audio", "Áudio"),
("window.panel", "Brushes", "Pincéis"),
("window.panel", "Character", "Caractere"),
("window.panel", "Content-Aware Fill", "Preenchimento sensível ao conteúdo"),
("window.panel", "Effects & Presets", "Efeitos e predefinições"),
("window.panel", "Essential Graphics", "Gráficos essenciais"),
("window.panel", "Info", "Informações"),
("help.inAppTutorials", "Learn", "Aprender"),
("window.panel", "Lumetri Scopes", "Escopos Lumetri"),
("window.panel", "Mask Interpolation", "Interpolação de máscara"),
("window.panel", "Media Browser", "Navegador de mídia"),
("window.panel", "Metadata", "Metadados"),
("window.panel", "Motion Sketch", "Esboço de movimento"),
("window.panel", "Paint", "Pintura"),
("window.panel", "Paragraph", "Parágrafo"),
("window.panel", "Preview", "Pré-visualização"),
("window.panel", "Progress", "Progresso"),
("window.panel", "Properties", "Propriedades"),
("window.panel", "Script Console", "Console de script"),
("window.panel", "Smoother", "Suavizador"),
("window.panel", "Tools", "Ferramentas"),
("window.panel", "Tracker", "Rastreador"),
("window.panel", "Wiggler", "Oscilador"),
("window.panel", "Composition", "Composição"),
("window.panel", "Flowchart", "Fluxograma"),
("window.panel", "Footage", "Mídia"),
("window.panel", "Layer", "Camada"),
("window.panel", "Project", "Projeto"),
("window.panel", "Render Queue", "Fila de renderização"),
("window.panel", "Timeline", "Linha do tempo"),
("window.panel", "Create Nulls From Paths", "Criar nulls a partir de caminhos"),
("window.panel", "VR Comp Editor", "Editor de composição VR"),
("", "Help", "Ajuda"),
("help.docs", "EffectCraft Help...", "Ajuda do EffectCraft..."),
("help.docs", "Scripting Help...", "Ajuda de scripting..."),
("help.docs", "Expression Reference...", "Referência de expressões..."),
("help.docs", "Effect Reference...", "Referência de efeitos..."),
("anim.browsePresets", "Animation Presets...", "Predefinições de animação..."),
("app.keyboardShortcuts", "Keyboard Shortcuts...", "Atalhos de teclado..."),
("help.inAppTutorials", "In-App Tutorials...", "Tutoriais no aplicativo..."),
("help.onlineTutorials", "Online Tutorials...", "Tutoriais online..."),
("help.systemReport", "System Compatibility Report...", "Relatório de compatibilidade do sistema..."),
("help.enableLogging", "Enable Logging", "Ativar registro em log"),
("help.revealLogFile", "Reveal Logging File", "Revelar arquivo de log"),
("help.discord", "Join the ArtCraft Discord...", "Entrar no Discord do ArtCraft..."),
("help.reportIssue", "Provide Feedback...", "Enviar comentários..."),
("help.website", "ArtCraft Website", "Site do ArtCraft"),
("help.appPage", "EffectCraft Home Page", "Página inicial do EffectCraft"),
("help.github", "EffectCraft on GitHub", "EffectCraft no GitHub"),
("file.openDemoProject", "Open Demo Project", "Abrir projeto de demonstração"),
];
#[cfg(test)]
mod tests {
use super::*;
@@ -3350,12 +3992,14 @@ mod tests {
let mut traditional_keys = BTreeSet::new();
let mut ukrainian_keys = BTreeSet::new();
let mut spanish_keys = BTreeSet::new();
let mut portuguese_keys = BTreeSet::new();
for (catalog, unique) in [
(JAPANESE, &mut japanese_keys),
(SIMPLIFIED_CHINESE, &mut chinese_keys),
(TRADITIONAL_CHINESE, &mut traditional_keys),
(UKRAINIAN, &mut ukrainian_keys),
(SPANISH, &mut spanish_keys),
(PORTUGUESE, &mut portuguese_keys),
] {
for (command, en, translated) in catalog {
let key = (command.to_string(), en.to_string());
@@ -3380,6 +4024,7 @@ mod tests {
assert_eq!(japanese_keys, chinese_keys, "the languages must translate the same entries");
assert_eq!(chinese_keys, traditional_keys, "the languages must translate the same entries");
assert_eq!(traditional_keys, spanish_keys, "the languages must translate the same entries");
assert_eq!(spanish_keys, portuguese_keys, "the languages must translate the same entries");
assert_eq!(japanese_keys, ukrainian_keys, "the languages must translate the same entries");
}
@@ -3460,6 +4105,8 @@ mod tests {
(Some("es"), "es"),
(Some("es_MX.UTF-8"), "es"),
(Some("es-419"), "es"),
(Some("pt-BR"), "pt-br"),
(Some("pt_PT.UTF-8"), "pt-br"),
(Some("en-US"), "en"),
(Some("jv-ID"), "en"),
(Some("de-DE"), "en"),
@@ -3492,7 +4139,7 @@ mod tests {
#[test]
fn every_translated_entry_keeps_the_english_shape() {
for (code, catalog) in [("zh-hans", SIMPLIFIED_CHINESE), ("zh-hant", TRADITIONAL_CHINESE), ("uk", UKRAINIAN), ("es", SPANISH)] {
for (code, catalog) in [("zh-hans", SIMPLIFIED_CHINESE), ("zh-hant", TRADITIONAL_CHINESE), ("uk", UKRAINIAN), ("es", SPANISH), ("pt-br", PORTUGUESE)] {
for (command, en, translated) in catalog {
assert_eq!(en.contains("..."), translated.contains("..."), "{code} {command} / {en}: {translated}");
let brackets = |s: &str| s.chars().filter(|c| *c == '(' || *c == ')').count();
@@ -3686,6 +4333,39 @@ mod tests {
assert!(crate::native_menu::build(&app).items().iter().any(|i| i.command == "file.openRecent" && i.label == "File.ecproj"));
}
#[test]
fn pt_br_translates_labels_computed_titles_and_keeps_names_verbatim() {
let mut app = EffectcraftApp::new(effectcraft_engine::Session::default());
app.session.execute("prefs.set", json!({"key":"general.language", "value":"pt-br"})).unwrap();
assert_eq!(language(&app), "pt-br");
assert!(!japanese(&app));
// Fixed menu rows come from the catalog.
assert_eq!(label(&app, "", "Composition"), "Composição");
assert_eq!(label(&app, "", "Effect"), "Efeito");
assert_eq!(label(&app, "comp.new", "New Composition..."), "Nova composição...");
assert_eq!(label(&app, "layer.newText", "Text"), "Texto");
// Untranslated keys and dynamic labels stay verbatim.
assert_eq!(label(&app, "unknown.command", "Text"), "Text");
assert_eq!(
entry(&app, &MenuEntry { label: "Undo".into(), command: "edit.undo".into(), params: json!({}), shortcut: None }, "Undo Comp1".into()),
"Não há nada para desfazer"
);
assert_eq!(
entry(
&app,
&MenuEntry { label: "Layer".into(), command: "window.panel".into(), params: json!({"panel":"layer"}), shortcut: None },
"Layer: File".into()
),
"Camada: File"
);
// The submenu titles that name the current workspace / view.
assert_eq!(
submenu(&app, "Assign Shortcut to Workspace", "Assign Shortcut to “Default” Workspace".into()),
"Atribuir atalho à área de trabalho “Default”"
);
assert_eq!(submenu(&app, "Assign Shortcut to 3D View", "Assign Shortcut to “Top”".into()), "Atribuir atalho à visualização 3D “Top”");
}
#[test]
fn general_settings_exposes_the_language_automation_id() {
let mut app = EffectcraftApp::new(effectcraft_engine::Session::default());
+2
View File
@@ -194,6 +194,8 @@ pub fn build(app: &EffectcraftApp) -> NativeMenu {
"Служби"
} else if crate::i18n::spanish(app) {
"Servicios"
} else if crate::i18n::brazilian_portuguese(app) {
"Serviços"
} else {
"Services"
}
+1 -1
View File
@@ -29,7 +29,7 @@ Commands (CLI, MCP, control channel):
### Settings that change behaviour
- `general.language`: interface language (`system` / `en` / `ja` / `zh-hans` / `zh-hant` / `uk` / `es`), Settings ▸ General ▸ Language; menu labels change immediately. `system` (Match System, the default) follows the operating system's interface language where EffectCraft has a translation and is English otherwise: a Simplified Chinese locale (`zh`, `zh-CN`, `zh_CN.UTF-8`, `zh-Hans-CN`, `zh-SG`) selects `zh-hans`, a Traditional one (`zh-TW`, `zh-HK`, `zh-Hant`, `zh_MO`) selects `zh-hant`, a Ukrainian one (`uk`, `uk-UA`, `uk_UA.UTF-8`) selects `uk`, a Spanish one (`es`, `es-ES`, `es_MX.UTF-8`) selects `es`; the browser build stays in English with it. Choose **Español** for Spanish menus (panels stay in English for now); choose **Українська** for Ukrainian menus and cataloged panel, dialog, button and tooltip text; Ukrainian uses the bundled UI fonts. Native Japanese, Simplified and Traditional Chinese UI uses installed system fonts; the web host must supply a Japanese font. The same setting picks the CJK fallback for the interface *and* the Han preference of the text engine, so the composition's own text is drawn with the same language's glyph forms (the text engine's preference is process-global); swapping the language reinstalls the fonts, so it applies without a restart. Two catalogs back the text: the menus are keyed by `(command, English label)` (`crates/ui-egui/src/i18n.rs`), and the rest of the interface - panels, dialogs, buttons, tooltips - is keyed by its English source string (`crates/ui-egui/src/i18n/ui.rs`, with rows for Japanese, Simplified and Traditional Chinese and Ukrainian), where a panel writes `tr("Rename")`, or `tr_args("Proxy Use: {}", &[&quality])` when the row carries a value. A row that is missing falls back to English, so a new string shows up untranslated rather than empty; the tests in that module fail on an unused row and on a hard-coded string in a converted panel.
- `general.language`: interface language (`system` / `en` / `ja` / `zh-hans` / `zh-hant` / `uk` / `es` / `pt-br`), Settings ▸ General ▸ Language; menu labels change immediately. `system` (Match System, the default) follows the operating system's interface language where EffectCraft has a translation and is English otherwise: a Simplified Chinese locale (`zh`, `zh-CN`, `zh_CN.UTF-8`, `zh-Hans-CN`, `zh-SG`) selects `zh-hans`, a Traditional one (`zh-TW`, `zh-HK`, `zh-Hant`, `zh_MO`) selects `zh-hant`, a Ukrainian one (`uk`, `uk-UA`, `uk_UA.UTF-8`) selects `uk`, a Spanish one (`es`, `es-ES`, `es_MX.UTF-8`) selects `es`, a Portuguese one (`pt`, `pt-BR`, `pt_PT.UTF-8`) selects `pt-br`; the browser build stays in English with it. Choose **Español** or **Português (Brasil)** for Spanish or Brazilian Portuguese menus (panels stay in English for now); choose **Українська** for Ukrainian menus and cataloged panel, dialog, button and tooltip text; Ukrainian uses the bundled UI fonts. Native Japanese, Simplified and Traditional Chinese UI uses installed system fonts; the web host must supply a Japanese font. The same setting picks the CJK fallback for the interface *and* the Han preference of the text engine, so the composition's own text is drawn with the same language's glyph forms (the text engine's preference is process-global); swapping the language reinstalls the fonts, so it applies without a restart. Two catalogs back the text: the menus are keyed by `(command, English label)` (`crates/ui-egui/src/i18n.rs`), and the rest of the interface - panels, dialogs, buttons, tooltips - is keyed by its English source string (`crates/ui-egui/src/i18n/ui.rs`, with rows for Japanese, Simplified and Traditional Chinese and Ukrainian), where a panel writes `tr("Rename")`, or `tr_args("Proxy Use: {}", &[&quality])` when the row carries a value. A row that is missing falls back to English, so a new string shows up untranslated rather than empty; the tests in that module fail on an unused row and on a hard-coded string in a converted panel.
- `general.undoLevels`: Levels of Undo
- `general.pathPointSize`: Path Point and Handle Size
- `general.recentItems`: Recent Projects Shown