Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions src/components/launch/LaunchWindow.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {
AppWindow,
ArrowUpCircle,
ChevronUp,
CheckCircle2,
ChevronUp,
Eye,
EyeOff,
FolderOpen,
Expand Down Expand Up @@ -54,11 +54,12 @@ interface DesktopSource {
windowTitle?: string;
}

const LOCALE_LABELS: Record<string, string> = {
const LOCALE_LABELS: Record<AppLocale, string> = {
en: "EN",
es: "ES",
"zh-CN": "中文",
};
"pt-BR": "Português (Brasil)",
} as const;

const COUNTDOWN_OPTIONS = [0, 3, 5, 10];

Expand Down Expand Up @@ -678,8 +679,8 @@ export function LaunchWindow() {
case "ready":
return updateStatus.availableVersion
? t("recording.update.availableTitle", "Recordly {{version}} is available.", {
version: updateStatus.availableVersion,
})
version: updateStatus.availableVersion,
})
: t("recording.update.availableGenericTitle");
case "downloading":
return updateStatus.detail ?? t("recording.update.downloadingTitle");
Expand Down
16 changes: 16 additions & 0 deletions src/contexts/I18nContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ import zhCNLaunch from '@/i18n/locales/zh-CN/launch.json'
import zhCNSettings from '@/i18n/locales/zh-CN/settings.json'
import zhCNShortcuts from '@/i18n/locales/zh-CN/shortcuts.json'
import zhCNTimeline from '@/i18n/locales/zh-CN/timeline.json'
import ptBRCommon from '@/i18n/locales/pt-BR/common.json'
import ptBRDialogs from '@/i18n/locales/pt-BR/dialogs.json'
import ptBREditor from '@/i18n/locales/pt-BR/editor.json'
import ptBRLaunch from '@/i18n/locales/pt-BR/launch.json'
import ptBRSettings from '@/i18n/locales/pt-BR/settings.json'
import ptBRShortcuts from '@/i18n/locales/pt-BR/shortcuts.json'
import ptBRTimeline from '@/i18n/locales/pt-BR/timeline.json'

const LOCALE_STORAGE_KEY = 'recordly.locale'

Expand Down Expand Up @@ -68,6 +75,15 @@ const messages: Record<AppLocale, LocaleBundle> = {
dialogs: zhCNDialogs,
shortcuts: zhCNShortcuts,
},
'pt-BR': {
common: ptBRCommon,
launch: ptBRLaunch,
editor: ptBREditor,
timeline: ptBRTimeline,
settings: ptBRSettings,
dialogs: ptBRDialogs,
shortcuts: ptBRShortcuts,
},
} as const

interface I18nContextValue {
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const DEFAULT_LOCALE = 'en' as const

export const SUPPORTED_LOCALES = ['en', 'es', 'zh-CN'] as const
export const SUPPORTED_LOCALES = ['en', 'es', 'zh-CN', 'pt-BR'] as const

export const I18N_NAMESPACES = [
'common',
Expand Down
26 changes: 26 additions & 0 deletions src/i18n/locales/pt-BR/common.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"app": {
"name": "Recordly",
"editorTitle": "Editor Recordly",
"subtitle": "Gravação e edição de tela",
"language": "Idioma",
"manageRecordings": "Abrir pasta de gravações"
},
"actions": {
"cancel": "Cancelar",
"close": "Fechar",
"export": "Exportar",
"load": "Carregar",
"redo": "Refazer",
"reset": "Redefinir",
"save": "Salvar",
"undo": "Desfazer",
"delete": "Excluir",
"done": "Concluído"
},
"errors": {
"invalidFileType": "Tipo de arquivo inválido",
"failedToUploadImage": "Falha ao enviar imagem",
"fileReadError": "Ocorreu um erro ao ler o arquivo."
}
}
62 changes: 62 additions & 0 deletions src/i18n/locales/pt-BR/dialogs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"export": {
"pleaseTryAgain": "Por favor, tente novamente",
"compilingGifProgress": "Compilando GIF... {{progress}}%",
"compilingGifWait": "Compilando GIF... Isso pode demorar um pouco",
"takeMoment": "Isso pode demorar um momento...",
"exportFailed": "Exportação Falhou",
"compilingTitle": "Compilando GIF",
"exportingFormat": "Exportando {{format}}",
"exportComplete": "Exportação Concluída",
"formatReady": "Seu {{format}} está pronto",
"showInFolder": "Mostrar na Pasta",
"compiling": "Compilando",
"renderingFrames": "Renderizando Quadros",
"processing": "Processando...",
"status": "Status",
"format": "Formato",
"compilingStatus": "Compilando...",
"frames": "Quadros",
"cancelExport": "Cancelar Exportação",
"reopenSaveDialog": "Abrir Diálogo de Salvamento Novamente",
"savedSuccess": "{{format}} salvo com sucesso!"
},
"addFont": {
"title": "Adicionar Fonte do Google",
"heading": "Adicionar Fonte do Google",
"description": "Adicione uma fonte personalizada do Google Fonts para usar em suas anotações.",
"urlLabel": "URL de Importação do Google Fonts",
"urlPlaceholder": "https://fonts.googleapis.com/css2?family=Roboto&display=swap",
"urlHelp": "Obtenha isso do Google Fonts: Selecione uma fonte -> Clique em \"Obter fonte\" -> Copie a URL de @import",
"nameLabel": "Nome de Exibição",
"namePlaceholder": "Minha Fonte Personalizada",
"nameHelp": "É assim que a fonte aparecerá no seletor de fontes",
"adding": "Adicionando...",
"addFont": "Adicionar Fonte",
"enterUrl": "Por favor, insira uma URL de importação do Google Fonts",
"invalidUrl": "Por favor, insira uma URL válida do Google Fonts",
"enterName": "Por favor, insira um nome de fonte",
"extractFailed": "Não foi possível extrair a família de fontes da URL",
"addSuccess": "Fonte \"{{name}}\" adicionada com sucesso",
"addFailed": "Falha ao adicionar fonte",
"loadTimeout": "A fonte demorou muito para carregar. Por favor, verifique a URL e tente novamente.",
"loadFailed": "A fonte não pode ser carregada. Por favor, verifique se a URL do Google Fonts está correta."
},
"shortcutsConfig": {
"title": "Atalhos de Teclado",
"configurável": "Configurável",
"fixed": "Fixo",
"pressEscToCancel": "Pressione Esc para cancelar",
"clickToChange": "Clique para alterar",
"pressAKey": "Pressione uma tecla...",
"alreadyUsedBy": "Já usado por <strong>{{action}}</strong>",
"swap": "Trocar",
"reserved": "Este atalho está reservado para \"{{label}}\" e não pode ser reatribuído.",
"saved": "Atalhos de teclado salvos",
"resetNotice": "Redefinir para atalhos padrão -- clique em Salvar para aplicar",
"instructions": "Clique em um atalho e pressione a nova combinação de teclas. Pressione Esc para cancelar.",
"resetToDefaults": "Redefinir para padrão",
"cancel": "Cancelar",
"save": "Salvar"
}
}
118 changes: 118 additions & 0 deletions src/i18n/locales/pt-BR/editor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
{
"playback": {
"play": "Reproduzir",
"pause": "Pausar"
},
"annotations": {
"settings": "Configurações de Anotação",
"active": "Ativo",
"text": "Texto",
"image": "Imagem",
"arrow": "Seta",
"textContent": "Conteúdo do Texto",
"textPlaceholder": "Digite seu texto...",
"fontStyle": "Estilo da Fonte",
"selectStyle": "Selecionar estilo",
"size": "Tamanho",
"toggleBold": "Alternar negrito",
"toggleItalic": "Alternar itálico",
"toggleUnderline": "Alternar sublinhado",
"alignLeft": "Alinhar à esquerda",
"alignCenter": "Centralizar",
"alignRight": "Alinhar à direita",
"textColor": "Cor do Texto",
"background": "Plano de Fundo",
"none": "Nenhum",
"clearBackground": "Limpar Plano de Fundo",
"uploadImage": "Enviar Imagem",
"supportedFormats": "Formatos suportados: JPG, PNG, GIF, WebP",
"arrowDirection": "Direção da Seta",
"strokeWidth": "Largura do Traço: {{width}}px",
"arrowColor": "Cor da Seta",
"deleteAnnotation": "Excluir Anotação",
"shortcutsAndTips": "Atalhos e Dicas",
"tipSelectAnnotation": "Mova a cabeça de reprodução para a seção sobreposta da anotação e selecione um item.",
"tipCycleForward": "Use Tab para navegar pelos itens sobrepostos.",
"tipCycleBackward": "Use Shift+Tab para navegar para trás.",
"imageUploadSuccess": "Imagem enviada com sucesso!",
"imageUploadError": "Por favor, envie um arquivo de imagem JPG, PNG, GIF ou WebP."
},
"fontStyles": {
"classic": "Clássico",
"editor": "Editor",
"strong": "Forte",
"typewriter": "Máquina de Escrever",
"deco": "Deco",
"simple": "Simples",
"modern": "Moderno",
"clean": "Limpo"
},
"format": {
"mp4Video": "Vídeo MP4",
"mp4Description": "Arquivo de vídeo de alta qualidade",
"gifAnimation": "Animação GIF",
"gifDescription": "Imagem animada para compartilhar"
},
"gifOptions": {
"frameRate": "Taxa de Quadros",
"outputSize": "Tamanho de Saída",
"outputDimensions": "Saída: {{width}} x {{height}}px",
"loopAnimation": "Animação em Loop",
"loopDescription": "O GIF será reproduzido continuamente"
},
"tutorial": {
"howTrimmingWorks": "Como o corte funciona",
"title": "Como o Corte Funciona",
"understanding": "Entendendo como cortar partes indesejadas do seu vídeo.",
"descriptionP1": "A ferramenta de Corte funciona definindo os segmentos que você deseja",
"descriptionRemove": "remover",
"descriptionP2": "do seu vídeo.",
"descriptionP3": "Qualquer parte da linha do tempo coberta por um segmento de Corte vermelho será removida quando você exportar.",
"visualExample": "Exemplo Visual",
"removed": "REMOVIDO",
"kept": "Mantido",
"finalVideo": "Vídeo Final",
"part": "Parte {{number}}",
"addTrimStep": "1. Adicionar Corte",
"addTrimDesc": "Pressione T ou clique no ícone de tesoura para marcar uma seção para remoção.",
"adjustStep": "2. Ajustar",
"adjustDesc": "Arraste as bordas da região vermelha para cobrir exatamente o que deseja cortar."
},
"feedback": {
"trigger": "Feedback",
"title": "Feedback e contato",
"description": "Entre em contato diretamente ou abra uma issue se algo estiver quebrado ou faltando.",
"emailLabel": "E-mail",
"xLabel": "X",
"reportIssue": "Reportar problema / enviar feedback",
"openFailed": "Falha ao abrir link."
},
"keyboardShortcuts": {
"trigger": "Atalhos",
"title": "Atalhos de Teclado",
"description": "Referência rápida para os controles da linha do tempo e editor.",
"customizeTooltip": "Personalizar atalhos",
"customize": "Personalizar",
"panTimeline": "Mover Linha do Tempo",
"zoomTimeline": "Ampliar Linha do Tempo",
"cycleAnnotations": "Navegar Anotações",
"tab": "Tab"
},
"actions": {
"saveAgain": "Salvar Novamente",
"showInFolder": "Mostrar na Pasta"
},
"project": {
"untitled": "Sem título"
},
"exportStatus": {
"exporting": "Exportando",
"renderingFile": "Renderizando seu arquivo.",
"preparing": "Preparando exportação...",
"completePercent": "{{percent}}% concluído",
"issue": "Problema na exportação",
"complete": "Exportação concluída",
"savedSuccessfully": "Seu arquivo foi salvo com sucesso."
},
"openRecordingsFolder": "Abrir pasta de gravações"
}
72 changes: 72 additions & 0 deletions src/i18n/locales/pt-BR/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"recording": {
"disableSystemAudio": "Desativar áudio do sistema",
"enableSystemAudio": "Ativar áudio do sistema",
"disableMicrophone": "Desativar microfone",
"enableMicrophone": "Ativar microfone",
"disableWebcam": "Desativar sobreposição de webcam",
"enableWebcam": "Ativar sobreposição de webcam",
"countdownDelay": "Atraso de contagem",
"noDelay": "Sem atraso",
"record": "Gravar",
"recordingsFolder": "Pasta de Gravações: {{path}}",
"chooseRecordingsFolder": "Escolher pasta de gravações",
"folderPath": "Caminho: /{{name}}/",
"openVideoFile": "Abrir arquivo de vídeo",
"openProject": "Abrir projeto",
"hideHudFromVideo": "Ocultar HUD da gravação",
"showHudInVideo": "Mostrar HUD na gravação",
"hideHud": "Ocultar HUD",
"closeApp": "Fechar App",
"screens": "Telas",
"windows": "Janelas",
"noSourcesFound": "Nenhuma fonte encontrada",
"microphone": "Microfone",
"turnOffMicrophone": "Desligar Microfone",
"selectMicToEnable": "Selecione um microfone para ativar",
"noMicrophonesFound": "Nenhum microfone encontrado",
"webcam": "Webcam",
"turnOffWebcam": "Desligar Webcam",
"selectWebcamToEnable": "Selecione uma webcam para ativar",
"noWebcamsFound": "Nenhuma webcam encontrada",
"language": "Idioma",
"paused": "PAUSADO",
"rec": "GRAV",
"resume": "Continuar",
"pause": "Pausar",
"stop": "Parar",
"cancel": "Cancelar",
"more": "Mais",
"update": {
"update": "Atualizar",
"updated": "Atualizado",
"idleTitle": "Verificar atualizações.",
"checkingTitle": "Verificando atualizações...",
"downloadingTitle": "Baixando atualização...",
"errorTitle": "Falha ao verificar atualizações. Clique para tentar novamente.",
"upToDateTitle": "Recordly {{version}} está atualizado.",
"availableTitle": "Recordly {{version}} está disponível.",
"availableGenericTitle": "Uma atualização está disponível."
}
},
"sourceSelector": {
"loadingSources": "Carregando fontes...",
"screens": "Telas",
"windows": "Janelas",
"windowsNote": "Apenas janelas visíveis (não minimizadas) podem ser gravadas.",
"windowPlaceholder": "Janela",
"cancel": "Cancelar",
"share": "Compartilhar"
},
"permissions": {
"screenRecordingNeeded": "O Recordly precisa de permissão de Gravação de Tela antes de começar. As Configurações do Sistema foram abertas. Após habilitar, feche e reabra o Recordly.",
"screenRecordingMissing": "A permissão de Gravação de Tela ainda está faltando. As Configurações do Sistema foram abertas novamente. Habilite, depois feche e reabra o Recordly antes de gravar.",
"accessibilityNeeded": "O Recordly também precisa de permissão de Acessibilidade para rastrear o cursor. As Configurações do Sistema foram abertas. Após habilitar, feche e reabra o Recordly.",
"accessibilityMissing": "A permissão de Acessibilidade ainda está faltando. As Configurações do Sistema foram abertas novamente. Habilite, depois feche e reabra o Recordly antes de gravar.",
"selectSource": "Por favor, selecione uma fonte para gravar",
"systemAudioUnavailable": "Áudio do sistema não está disponível para esta fonte. A gravação continuará sem áudio do sistema.",
"microphoneDenied": "Acesso ao microfone foi negado. A gravação continuará sem áudio do microfone.",
"failedToStart": "Falha ao iniciar gravação: {{error}}",
"failedToStartGeneric": "Falha ao iniciar gravação"
}
}
Loading