screentinker/frontend/js/i18n/pt.js
ScreenTinker 9face2fdd4 Show a panel's IPv6, and size the pairing code to the screen it is on
Two field-reported gaps, unrelated except that both are about being able to
read something off a screen.

A PANEL'S IPv6 WAS NEVER COLLECTED, LET ALONE SHOWN.

DeviceInfo.getLocalIp() filters to Inet4Address, so a v6-only panel reported no
address at all and the dashboard rendered a dash for a screen that was perfectly
reachable. It now reports both stacks in their own fields: a dual-stack panel
genuinely has two addresses and either may be the one you need, so collapsing
them into one column would make it mean "whichever interface enumerated first".

Link-local (fe80::/10) is deliberately excluded. Every interface has one, they
tend to enumerate first, and none can be dialled without also knowing the zone
index — so admitting them would fill the field with a string nobody can paste
anywhere and hide the address that works. Any %iface suffix is trimmed for the
same reason. The 45-char cap the writer already applied is exactly the longest
legitimate IPv6 text form, so it needed no change.

The dashboard card renders only when a panel actually has a v6 address, rather
than showing an empty row to the overwhelmingly v4 fleet.

THE PAIRING CODE DID NOT SCALE, WHICH IS WORST WHERE IT MATTERS MOST.

Every size on the pre-playback screens was a hard-coded pixel value. A CSS pixel
covers a quarter of the screen area on a 4K panel that it does on 1080p, and a
sixteenth on 8K — so the 72px code that fills a 1080p screen is a smudge on the
4K wall it was installed on, which is where signage actually goes.

What has to stay constant is ANGULAR size, so the root font size is now
viewport-proportional and everything on those screens is a rem against it. The
code holds 6.67% of screen height at every resolution: 72px at 1080p — bit for
bit what it renders today, so nothing changes for the existing fleet — 144px at
4K, 288px at 8K. Verified in a browser rather than by arithmetic: at a 1409px
viewport the root computes to 13.0473px, which is 0.926vmin to four decimals.

vmin, not vw, because portrait-mounted panels are common here and vw would
render a 1080x1920 screen at half size. Clamped at both ends so the dashboard's
preview iframe stays legible instead of microscopic and an ultrawide does not
get silly. Applied to the web player (which BrightSign also runs) and to Tizen,
where a 1920x1080 logical viewport makes it arithmetically identical to the
values it replaces — the point being the panels where it is not.

A test asserts the scaling cannot reach playback content: the whole safety
argument is that only the chrome uses rem, and a stage or zone rule adopting it
would start resizing CONTENT, which is a worse bug than the one being fixed.
Android is untouched — its pairing code already autosizes within a dp-scaled
layout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014skWYXJUWhF73EvNPgB2AS
2026-08-07 08:06:45 -05:00

1207 lines
64 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Portuguese translations (Brazilian-leaning vocab; pt-BR is the larger market).
// Reviewed for UI register (informal você). Native review recommended before
// publicizing as fully supported.
export default {
'nav.members': 'Membros',
'common.close': 'Fechar',
'switcher.manage_members': 'Gerir membros',
'switcher.rename': 'Mudar o nome da área de trabalho',
'wall.rename': 'Mudar o nome do mural',
'wall.remove_from_wall': 'Remover do mural',
'dashboard.select_for_wall': 'Selecionar para o mural de vídeo',
'team.unavailable_desc': 'Esta funcionalidade está indisponível enquanto é reformulada para funcionar com as Áreas de trabalho. Os dados das equipas existentes são preservados.',
'team.unavailable_title': 'As equipas estão a ser reformuladas',
'settings.help_tip': 'O seu perfil, palavra-passe e autenticação de dois fatores, além de tokens de API para integrações e ferramentas para exportar ou importar os seus dados.',
'activity.help_tip': 'Registo do que mudou e de quem o mudou: inícios de sessão, carregamentos de conteúdo, comandos a dispositivos e alertas. Útil para perceber por que razão um ecrã mudou o que estava a mostrar.',
'playlist.help_tip': 'Uma playlist é a ordem de reprodução que um ecrã repete em ciclo. Adicione conteúdos, defina quanto tempo cada um aparece e atribua a playlist a um ecrã ou a um grupo. Um ecrã reproduz uma playlist de cada vez, a não ser que um agendamento a substitua.',
// #zone-orphan dashboard warnings
'device.pl_item.orphan_zone': 'Zona de outro layout — reatribuir',
'device.pl_item.orphan_zone_tip': 'A zona deste item não faz parte do layout atual do dispositivo. Ele continua sendo reproduzido (recuperado na maior zona), mas reatribua-o a uma zona deste layout.',
'dashboard.device_orphan_tip_one': '{n} item atribuído a uma zona que não está no layout deste dispositivo — abra o dispositivo para reatribuir',
'dashboard.device_orphan_tip_other': '{n} itens atribuídos a uma zona que não está no layout deste dispositivo — abra o dispositivo para reatribuir',
// Nav
'nav.displays': 'Telas',
'nav.content': 'Conteúdo',
'nav.playlists': 'Playlists',
'nav.layouts': 'Layouts',
'nav.widgets': 'Widgets',
'nav.schedule': 'Agenda',
'nav.walls': 'Paredes de vídeo',
'nav.reports': 'Relatórios',
'nav.kiosk': 'Quiosque',
'nav.designer': 'Designer',
'nav.activity': 'Atividade',
'nav.teams': 'Equipes',
'nav.help': 'Ajuda',
'nav.settings': 'Configurações',
'nav.subscription': 'Assinatura',
'nav.admin': 'Admin',
// Common
'common.save': 'Salvar',
'common.cancel': 'Cancelar',
'common.delete': 'Excluir',
'common.edit': 'Editar',
'common.done': 'Concluído',
'common.loading': 'Carregando...',
'common.connected': 'Conectado',
'common.disconnected': 'Desconectado',
'common.never': 'Nunca',
'common.just_now': 'Agora mesmo',
'common.minutes_ago': 'há {n}m',
'common.hours_ago': 'há {n}h',
'common.days_ago': 'há {n}d',
'common.unknown': 'Desconhecido',
// Auth
'auth.sign_in': 'Entrar',
'auth.sign_out': 'Sair',
'auth.create_account': 'Criar conta',
'auth.create_admin_account': 'Criar conta de administrador',
'auth.email': 'E-mail',
'auth.password': 'Senha',
'auth.name': 'Nome',
'auth.placeholder_email': 'voce@exemplo.com',
'auth.placeholder_password': '••••••••',
'auth.placeholder_name': 'Seu nome',
'auth.placeholder_register_password': 'No mínimo 6 caracteres',
'auth.subtitle_setup': 'Crie sua conta de administrador para começar',
'auth.subtitle_signin': 'Entre para gerenciar suas telas',
'auth.trial_notice': 'Contas novas ganham 14 dias de avaliação Pro grátis',
'auth.divider_or': 'OU',
'auth.signin_google': 'Entrar com o Google',
'auth.signin_microsoft': 'Entrar com a Microsoft',
'auth.back_to_signin': 'Voltar ao login',
'auth.support_access': 'Acesso de suporte',
'auth.support_token_placeholder': 'Cole o token de suporte',
'auth.support_authenticate': 'Autenticar com token de suporte',
'auth.terms': 'Termos de Serviço',
'auth.privacy': 'Política de Privacidade',
'auth.error_email_password_required': 'E-mail e senha obrigatórios',
'auth.error_password_min_6': 'A senha deve ter no mínimo 6 caracteres',
'auth.error_login_failed': 'Falha no login',
'auth.error_registration_failed': 'Falha no cadastro',
'auth.error_paste_support_token': 'Cole um token de suporte',
'auth.error_support_failed': 'Falha no login de suporte',
'auth.error_google_failed': 'Falha no login com Google',
'auth.error_microsoft_failed': 'Falha no login com Microsoft',
// Dashboard
'dashboard.title': 'Telas',
'dashboard.subtitle': 'Gerencie suas telas remotas',
'dashboard.help_tip': 'Seus dispositivos pareados. Verde = online, vermelho = offline. Clique em um para gerenciar a playlist, ver telemetria ou usar o controle remoto.',
'dashboard.add': 'Adicionar tela',
'dashboard.create_group': '+ Grupo',
'dashboard.search': 'Buscar telas...',
'dashboard.all_status': 'Todos os status',
'dashboard.online': 'Online',
'dashboard.offline': 'Offline',
'dashboard.awaiting_pairing': 'Aguardando pareamento',
'dashboard.no_preview': 'Pré-visualização indisponível',
'dashboard.total_displays': 'Total de telas',
'dashboard.ungrouped': 'Sem grupo',
'dashboard.no_displays': 'Nenhuma tela ainda',
'dashboard.no_displays_desc': 'Instale o aplicativo ScreenTinker na sua TV e pareie com o botão acima.',
'dashboard.failed_to_load': 'Falha ao carregar as telas',
'dashboard.unknown_playlist': 'Playlist desconhecida',
'dashboard.mixed_playlists': 'Playlists variadas',
'dashboard.playlist_label': 'Playlist: {name}',
'dashboard.devices_count_one': '{n} dispositivo',
'dashboard.devices_count_other': '{n} dispositivos',
'dashboard.online_count': '{n} online',
'dashboard.set_playlist_placeholder': 'Definir playlist...',
'dashboard.send_command_placeholder': 'Enviar comando...',
'dashboard.manage': 'Gerenciar',
'dashboard.manage_tooltip': 'Adicionar/remover dispositivos',
'dashboard.delete_group_tooltip': 'Excluir grupo',
'dashboard.no_devices_in_group': 'Nenhum dispositivo neste grupo. Clique em Gerenciar para adicionar.',
'dashboard.manage_group_subtitle': 'Marque os dispositivos para adicioná-los a este grupo',
'dashboard.draft_suffix': '(rascunho)',
'dashboard.cmd.screen_on': 'Ligar tela',
'dashboard.cmd.screen_off': 'Desligar tela',
'dashboard.cmd.restart_app': 'Reiniciar app',
'dashboard.cmd.check_update': 'Verificar atualização',
'dashboard.cmd.reboot': 'Reiniciar',
'dashboard.cmd.shutdown': 'Desligar',
'dashboard.prompt_group_name': 'Nome do grupo:',
'dashboard.error_pairing_code': 'Digite um código de pareamento válido de 6 dígitos',
'dashboard.confirm_add_to_group': '{name} já está em: {groups}\n\nAdicionar também a "{target}"?',
'dashboard.confirm_move_to_group': '{name} está atualmente em: {groups}\n\nMover para "{target}"?',
'dashboard.toast.move_partial': 'Não foi possível remover de {group} — continua em ambos',
'dashboard.confirm_assign_playlist': 'Atribuir a playlist "{playlist}" a todos os dispositivos de "{group}"?',
'dashboard.confirm_destructive_command': '{cmd} todos os {n} dispositivos de "{group}"?\n\nIsso não pode ser desfeito.',
'dashboard.confirm_delete_group': 'Excluir este grupo? Os dispositivos não serão afetados.',
'dashboard.toast.display_paired': 'Tela pareada com sucesso!',
'dashboard.toast.group_created': 'Grupo criado',
'dashboard.toast.group_deleted': 'Grupo excluído',
'dashboard.toast.already_in_group': '{name} já está em {group}',
'dashboard.toast.moved_device': '{name} movido para {group}',
'dashboard.toast.removed_device_one': '{name} removido de 1 grupo',
'dashboard.toast.removed_device_other': '{name} removido de {n} grupos',
'dashboard.toast.playlist_assigned_one': 'Playlist atribuída a 1 dispositivo',
'dashboard.toast.playlist_assigned_other': 'Playlist atribuída a {n} dispositivos',
'dashboard.toast.command_sent': '{cmd} enviado para {sent}/{total} dispositivos',
'dashboard.toast.command_sent_with_offline': '{cmd} enviado para {sent}/{total} dispositivos ({offline} offline)',
// Content library
'content.title': 'Biblioteca de conteúdo',
'content.subtitle': 'Envie e gerencie seus arquivos de mídia',
'content.help_tip': 'Envie vídeos e imagens aqui. Selecione vários arquivos para envio em lote. Use URL remota para transmitir de fontes externas. Clique em uma miniatura para pré-visualizar.',
'content.drop': 'Solte os arquivos aqui ou clique para enviar',
'content.upload_hint': 'Suporta MP4, WebM, AVI, MKV, JPEG, PNG, GIF, WebP',
'content.upload_progress': 'Enviando...',
'content.upload_progress_named': 'Enviando {name}...',
'content.upload_progress_named_pct': 'Enviando {name}... {pct}%',
'content.remote_url': 'URL remota',
'content.remote_desc': 'Transmita direto de uma URL. Economiza largura de banda local.',
'content.remote_url_placeholder': 'https://exemplo.com/video.mp4',
'content.remote_name_placeholder': 'Nome de exibição (opcional)',
'content.remote_add_btn': 'Adicionar URL remota',
'content.youtube': 'YouTube',
'content.youtube_desc': 'Incorpore um vídeo do YouTube nas suas telas.',
'content.youtube_url_placeholder': 'https://youtube.com/watch?v=...',
'content.youtube_name_placeholder': 'Nome de exibição (opcional)',
'content.youtube_add_btn': 'Adicionar vídeo do YouTube',
'content.search_placeholder': 'Buscar conteúdo...',
'content.new_folder_btn': '+ Nova pasta',
'content.breadcrumb_root': 'Todo o conteúdo',
'content.rename_btn': 'Renomear',
'content.delete_folder_btn': 'Excluir pasta',
'content.prompt_folder_name': 'Nome da pasta:',
'content.prompt_rename_folder': 'Renomear pasta:',
'content.confirm_delete_folder': 'Excluir esta pasta? O conteúdo voltará para o nível raiz. Subpastas também serão excluídas.',
'content.empty_folder_title': 'Esta pasta está vazia',
'content.empty_folder_desc': 'Arraste o conteúdo para cá ou use a ação Mover.',
'content.no_content': 'Nenhum conteúdo ainda',
'content.no_content_desc': 'Envie vídeos e imagens para começar.',
'content.failed_to_load': 'Falha ao carregar o conteúdo',
'content.type_youtube': 'YouTube',
'content.type_remote': 'URL remota',
'content.type_remote_short': 'Remoto',
'content.type_video': 'Vídeo',
'content.type_image': 'Imagem',
'content.btn_edit': 'Editar',
'content.btn_delete': 'Excluir',
'content.btn_confirm_delete': 'Confirmar exclusão?',
'content.btn_deleting': 'Excluindo...',
'content.edit_modal_title': 'Editar conteúdo',
'content.label_filename': 'Nome do arquivo / Exibição',
'content.label_remote_url_field': 'URL remota',
'content.label_mime_type': 'Tipo MIME',
'content.label_folder': 'Pasta',
'content.label_replace_file': 'Substituir arquivo',
'content.replace_file_hint': 'Deixe vazio para manter o arquivo atual',
'content.folder_root_option': '— Raiz —',
'content.save_changes': 'Salvar alterações',
'content.mime.video_mp4': 'Vídeo (MP4)',
'content.mime.video_webm': 'Vídeo (WebM)',
'content.mime.image_jpeg': 'Imagem (JPEG)',
'content.mime.image_png': 'Imagem (PNG)',
'content.mime.image_gif': 'Imagem (GIF)',
'content.mime.image_webp': 'Imagem (WebP)',
'content.error_enter_url': 'Digite uma URL',
'content.error_enter_youtube_url': 'Digite uma URL do YouTube',
'content.error_update_failed': 'Falha ao atualizar',
'content.toast.remote_added': 'Conteúdo remoto adicionado',
'content.toast.youtube_added': 'Vídeo do YouTube adicionado',
'content.toast.deleted': 'Conteúdo excluído',
'content.toast.updated': 'Conteúdo atualizado',
'content.toast.uploaded_named': '{name} enviado com sucesso',
'content.toast.upload_failed_named': 'Falha ao enviar {name}: {error}',
'content.toast.folder_created_named': 'Pasta "{name}" criada',
'content.toast.folder_renamed': 'Pasta renomeada',
'content.toast.folder_deleted': 'Pasta excluída',
'content.toast.moved': 'Movido',
'content.toast.moved_to_root': 'Movido para a raiz',
// Device detail
'device.back': 'Voltar para Telas',
'device.owner_label': 'Proprietário: {owner}',
'device.rename': 'Renomear',
'device.preview_btn': 'Pré-visualização',
'device.screenshot_btn': 'Captura',
'device.remove': 'Remover',
'device.click_to_confirm': 'Clique novamente para confirmar',
'device.prompt_new_name': 'Digite o novo nome:',
'device.confirm_discard_draft': 'Descartar todas as alterações não publicadas e voltar à última versão publicada?',
'device.failed_load': 'Falha ao carregar o dispositivo',
'device.no_screenshot': 'Sem captura disponível. Clique em "Captura" para tirar uma.',
'device.no_content_assigned': 'Sem conteúdo atribuído',
'device.now_playing_id': 'Reproduzindo: {id}',
'device.playlist_count_one': '1 item na playlist',
'device.playlist_count_other': '{n} itens na playlist',
'device.tab.now_playing': 'Reproduzindo agora',
'device.tab.now_playing_tip': 'Captura ao vivo do que está sendo exibido neste dispositivo.',
'device.tab.playlist': 'Playlist',
'device.tab.playlist_tip': 'Conteúdo atribuído a este dispositivo. Arraste para reordenar. Adicione mídia, widgets ou páginas de quiosque.',
'device.tab.info': 'Informações do dispositivo',
'device.tab.info_tip': 'Telemetria de hardware, orientação, notas e controles do dispositivo.',
'device.tab.remote': 'Controle remoto',
'device.tab.remote_tip': 'Visualize a tela em tempo real e envie pressionamentos de tecla. Funciona no APK do Android e no player web.',
'device.draft.banner_title': 'Alterações não publicadas',
'device.draft.devices_showing_published': 'Os dispositivos ainda exibem a última versão publicada.',
'device.draft.never_published': 'Esta playlist nunca foi publicada. Os dispositivos não exibirão nada até você publicar.',
'device.draft.discard': 'Descartar',
'device.draft.publish': 'Publicar',
'device.draft.publishing': 'Publicando...',
'device.layout.label': 'Layout da tela',
'device.layout.fullscreen_default': 'Tela cheia (padrão)',
'device.layout.zones_count': '{name} ({n} zonas)',
'device.layout.template_zones_count': '[Modelo] {name} ({n} zonas)',
'device.layout.apply': 'Aplicar',
'device.playlist.label': 'Playlist',
'device.playlist.no_playlist': 'Sem playlist',
'device.playlist.copy_to_btn': 'Copiar para...',
'device.playlist.add_content_btn': 'Adicionar conteúdo',
'device.playlist.empty_title': 'Sem conteúdo atribuído',
'device.playlist.empty_desc': 'Adicione conteúdo da sua biblioteca à playlist desta tela.',
'device.playlist_picker.with_count': '{name} — {n} itens',
'device.playlist_picker.with_auto': '{name} (auto) — {n} itens',
'device.info.status': 'Status',
'device.info.ip_address': 'Endereço IP',
'device.info.local_ip': 'IP local',
'device.info.local_ip6': 'IPv6 local',
'device.info.wifi_needs_location': 'Requer permissão de localização',
'device.info.battery': 'Bateria',
'device.info.storage': 'Armazenamento',
'device.info.size_free': '{size} livres',
'device.info.player_type': 'Tipo de player',
'device.info.web_player': 'Player web',
'device.info.wifi': 'Wi-Fi',
'device.info.uptime': 'Tempo ativo',
'device.info.android_version': 'Versão do Android',
'device.info.app_version': 'Versão do app',
'device.info.settings_pin': 'PIN de configurações',
'device.info.settings_pin_hint': 'Menu de configurações no dispositivo (2× Voltar)',
'device.info.screen_resolution': 'Resolução',
'device.info.ram': 'RAM',
'device.info.cpu_usage': 'Uso de CPU',
'device.timeline.title': 'Linha do tempo (últimas 24 horas)',
'device.timeline.h24_ago': 'há 24h',
'device.timeline.now': 'Agora',
'device.timeline.online': 'Online',
'device.timeline.offline': 'Offline',
'device.timeline.no_data': 'Sem dados',
'device.timeline.uptime_pct_tracked': '{pct}% ativo ({n}min monitorados)',
'device.timeline.uptime_pct_no_data': '{pct}% ativo (sem dados)',
'device.form.orientation_label': 'Orientação / Rotação',
'device.form.orientation.landscape': 'Paisagem (0°)',
'device.form.orientation.portrait': 'Retrato (90° SH)',
'device.form.orientation.landscape_flipped': 'Paisagem invertida (180°)',
'device.form.orientation.portrait_flipped': 'Retrato invertido (270° SH)',
'device.form.default_content_label': 'Conteúdo padrão',
'device.form.default_content_none': 'Nenhum (mostrar "Aguardando...")',
'device.form.notes_label': 'Notas',
'device.form.notes_placeholder': 'Localização, detalhes de instalação, etc.',
'device.form.save_settings': 'Salvar configurações',
'device.ctl.reboot_device': 'Reiniciar dispositivo',
'device.ctl.screen_off': 'Desligar tela',
'device.ctl.screen_on': 'Ligar tela',
'device.ctl.launch_player': 'Iniciar player',
'device.ctl.force_update': 'Forçar atualização',
'device.ctl.shutdown': 'Desligar',
'device.remote.start_prompt': 'Clique em "Iniciar controle remoto" para começar',
'device.remote.start': 'Iniciar controle remoto',
'device.remote.stop': 'Parar controle remoto',
'device.remote.vol_up': 'Vol +',
'device.remote.vol_down': 'Vol -',
'device.remote.home': 'Início',
'device.remote.back': 'Voltar',
'device.remote.recents': 'Recentes',
'device.remote.power': 'Energia',
'device.remote.ok': 'OK',
'device.remote.settings': 'Configurações',
'device.remote.scrn_off': 'Tela off',
'device.remote.scrn_on': 'Tela on',
'device.remote.enable_system_view': 'Ativar visão do sistema',
'device.remote.system_view_tooltip': 'Solicita ao usuário do dispositivo permitir captura de tela cheia - habilita visualização remota da tela inicial, configurações e outros apps',
'device.remote.system_view_hint': 'Aprovação única necessária no dispositivo',
'device.remote.waiting_for_approval': 'Aguardando aprovação do dispositivo...',
'device.remote.system_view_enabled': 'Visão do sistema ativada',
'device.remote.unlocked_hint': 'Navegação e controles do sistema desbloqueados',
'device.pl_item.widget_with_type': 'Widget ({type})',
'device.pl_item.youtube': 'YouTube',
'device.pl_item.video': 'Vídeo',
'device.pl_item.image': 'Imagem',
'device.pl_item.zone_label': 'Zona: {id}',
'device.pl_item.no_zone': 'Sem zona',
'device.pl_item.mute': 'Silenciar',
'device.pl_item.unmute': 'Ativar áudio',
'device.pl_item.remove': 'Remover',
'device.copy.no_other_devices': 'Não há outros dispositivos para copiar',
'device.copy.prompt': 'Copiar playlist para qual dispositivo?\n\n{list}\n\nDigite o número:',
'device.copy.invalid_selection': 'Seleção inválida',
'device.copy.toast': '{n} itens copiados para {device}',
'device.assign.empty_all': 'Ainda não há conteúdo, widgets ou páginas de quiosque. Crie algo primeiro!',
'device.assign.modal_title': 'Adicionar à playlist',
'device.assign.zone_label': 'Zona',
'device.assign.zone_default': 'Padrão (tela cheia)',
'device.assign.duration_label': 'Duração (segundos, para imagens/widgets)',
'device.assign.tab.media': 'Mídia ({n})',
'device.assign.tab.widgets': 'Widgets ({n})',
'device.assign.tab.kiosk': 'Quiosque ({n})',
'device.assign.no_media': 'Nenhuma mídia enviada ainda',
'device.assign.no_widgets': 'Nenhum widget criado ainda.',
'device.assign.no_kiosk': 'Nenhuma página de quiosque ainda.',
'device.assign.create_one': 'Crie um',
'device.assign.add_selected': 'Adicionar selecionados',
'device.assign.select_first': 'Selecione algo primeiro',
'device.assign.kiosk_widget_name': 'Quiosque: {name}',
'device.toast.screenshot_requested': 'Captura solicitada',
'device.toast.renamed': 'Tela renomeada',
'device.toast.removing': 'Removendo...',
'device.toast.removed': 'Tela removida',
'device.toast.settings_saved': 'Configurações salvas',
'device.toast.published': 'Playlist publicada — dispositivos atualizados',
'device.toast.draft_discarded': 'Alterações do rascunho descartadas',
'device.toast.playlist_changed': 'Playlist alterada',
'device.toast.layout_applied': 'Layout aplicado',
'device.toast.switched_to_fullscreen': 'Alterado para tela cheia',
'device.toast.added_to_playlist': 'Adicionado à playlist',
'device.toast.unmuted': 'Áudio ativado',
'device.toast.muted': 'Silenciado',
'device.toast.zone_updated': 'Zona atualizada',
'device.toast.removed_from_playlist': 'Conteúdo removido da playlist',
'device.toast.playlist_reordered': 'Playlist reordenada',
'device.toast.reboot_sent': 'Comando de reinício enviado',
'device.toast.shutdown_sent': 'Comando de desligamento enviado',
'device.toast.screen_off_sent': 'Comando para desligar tela enviado',
'device.toast.screen_on_sent': 'Comando para ligar tela enviado',
'device.toast.launch_sent': 'Comando de início enviado',
'device.toast.update_triggered': 'Verificação de atualização disparada',
'device.toast.remote_started': 'Sessão de controle remoto iniciada',
// Settings
'settings.title': 'Configurações',
'settings.subtitle': 'Configuração do servidor e informações de instalação',
'settings.account': 'Conta',
// Tokens de API
'apitoken.title': 'Tokens de API',
'apitoken.desc': 'Tokens de acesso pessoal para a API pública, restritos a este espaço de trabalho. Trate-os como senhas — qualquer pessoa com o token pode agir como você aqui.',
'apitoken.docs_link': 'Novo na API? Veja a documentação completa →',
'apitoken.portal_url_label': 'URL do portal da agência',
'apitoken.invite_label': 'Convite para copiar — envie para a agência:',
'apitoken.invite_text': 'Acesse {url} e cole esta chave de acesso: {key}',
'apitoken.copy_invite': 'Copiar convite',
'apitoken.name_placeholder': 'ex.: Integração da agência',
'apitoken.scope_read': 'Somente leitura',
'apitoken.scope_write': 'Leitura e escrita',
'apitoken.scope_full': 'Completo (incl. comandos de dispositivo)',
'apitoken.scope_agency': 'Agência (enviar apenas para listas escolhidas)',
'apitoken.agency_playlists_label': 'Listas às quais este token de agência pode publicar',
'apitoken.agency_playlists_hint': 'O token só pode enviar e adicionar itens com datas a estas listas. As adições ficam como rascunho para você publicar.',
'apitoken.agency_needs_playlists': 'Selecione pelo menos uma lista para um token de agência.',
'apitoken.agency_no_playlists': 'Crie uma lista primeiro: um token de agência deve apontar para uma.',
'apitoken.targets_label': 'Designadas:',
'apitoken.edit_targets': 'Editar listas',
'apitoken.zoned_playlist_reason': 'Atribuída a uma zona — agências precisam de uma lista de tela cheia',
'apitoken.targets_updated': 'Designações atualizadas',
'apitoken.auto_publish_label': 'Publicação automática (ignorar minha aprovação)',
'apitoken.auto_publish_hint': 'Desativado (padrão): as adições aguardam como rascunho para você publicar. Ativado: vão ao ar imediatamente, apenas para agências de total confiança.',
'apitoken.auto_publish_on': 'publicação automática ativada',
'apitoken.agency_folder_label': 'Pasta de upload',
'apitoken.agency_folder_hint': 'Onde os uploads desta agência ficam. Deixe em automático para criar uma pasta com o nome do token; a agência pode usar subpastas dela, mas nada além disso.',
'apitoken.agency_folder_auto': 'Criar uma automaticamente (Agency — <nome>)',
'apitoken.folder_label': 'Pasta:',
'apitoken.folder_root': 'Raiz da biblioteca',
'apitoken.edit_folder': 'Pasta',
'apitoken.folder_updated': 'Pasta de upload atualizada',
'apitoken.create': 'Criar token',
'apitoken.none': 'Ainda não há tokens.',
'apitoken.col_token': 'Token',
'apitoken.col_name': 'Nome',
'apitoken.col_scope': 'Escopo',
'apitoken.col_created': 'Criado',
'apitoken.col_last_used': 'Último uso',
'apitoken.never': 'Nunca',
'apitoken.revoke': 'Revogar',
'apitoken.revoked': 'Revogado',
'apitoken.secret_title': 'Copie seu token agora',
'apitoken.secret_warning': 'Esta é a única vez que o token completo é exibido. Guarde-o em um lugar seguro — você não poderá vê-lo novamente.',
'apitoken.copy': 'Copiar',
'apitoken.copied': 'Copiado para a área de transferência',
'apitoken.created_toast': 'Token criado',
'apitoken.revoked_toast': 'Token revogado',
'apitoken.revoke_confirm': 'Revogar este token? Qualquer integração que o utilize para de funcionar imediatamente.',
'settings.save_profile': 'Salvar perfil',
'settings.change_password': 'Alterar senha',
'settings.password_min_8': 'Deve ter no mínimo 8 caracteres.',
'settings.current_password': 'Senha atual',
'settings.new_password': 'Nova senha',
'settings.confirm_new_password': 'Confirmar nova senha',
'settings.sso_note': 'Você entra via {provider}. Gerencie sua senha lá.',
'settings.license': 'Licença',
'settings.license_mit': 'Licença MIT - todos os recursos incluídos.',
'settings.platform_admin_link': 'As ferramentas de admin da plataforma estão na página',
'settings.platform_admin_page_suffix': '.',
'settings.user_management': 'Gestão de usuários',
'settings.loading_users': 'Carregando usuários...',
'settings.white_label': 'Marca branca / Branding',
'settings.white_label_desc': 'Personalize a aparência do painel e do player para seus clientes.',
'settings.brand_name': 'Nome da marca',
'settings.logo_url': 'URL do logotipo',
'settings.primary_color': 'Cor primária',
'settings.bg_color': 'Cor de fundo',
'settings.custom_domain': 'Domínio personalizado',
'settings.favicon_url': 'URL do favicon',
'settings.custom_css': 'CSS personalizado (opcional)',
'settings.hide_branding': 'Ocultar marca "ScreenTinker"',
'settings.save_branding': 'Salvar branding',
'settings.preview': 'Pré-visualizar',
'settings.white_label_enterprise_only': 'Branding personalizado disponível no plano Enterprise',
'settings.view_plans': 'Ver planos',
'settings.server_info': 'Informações do servidor',
'settings.server_url': 'URL do servidor',
'settings.api_endpoint': 'Endpoint da API',
'settings.server_url_hint': 'Use esta URL ao configurar o app Android',
'settings.setup_guide': 'Guia de instalação',
'settings.setup_step_1': 'Instale o APK do ScreenTinker na sua TV via sideloading',
'settings.setup_step_2_prefix': 'Abra o app e digite esta URL do servidor:',
'settings.setup_step_3': 'O app exibirá um código de pareamento de 6 dígitos',
'settings.setup_step_4': 'Clique em "Adicionar tela" no painel e digite o código',
'settings.setup_step_5': 'Envie conteúdo na Biblioteca de conteúdo',
'settings.setup_step_6': 'Atribua conteúdo à playlist da tela',
'settings.your_data': 'Seus dados',
'settings.your_data_desc': 'Exporte ou importe seus dispositivos, conteúdo, layouts, agendas e todas as configurações. Use para migrar entre nuvem e auto-hospedado.',
'settings.export_my_data': 'Exportar meus dados',
'settings.include_media_zip': 'Incluir arquivos de mídia (ZIP)',
'settings.import_data': 'Importar dados',
'settings.language': 'Idioma',
'settings.about': 'Sobre',
'settings.about_tagline': 'Sistema de gerenciamento de sinalização digital.',
'settings.third_party_licenses': 'Licenças de terceiros',
'settings.import.reading_file': 'Lendo arquivo...',
'settings.import.zip_detected': 'Exportação ZIP detectada: <strong>{name}</strong> ({size} MB)<br>Contém dados + arquivos de mídia.',
'settings.import.confirm': 'Confirmar importação',
'settings.import.invalid_file': 'Arquivo inválido. Deve ser JSON ou ZIP de exportação do ScreenTinker.',
'settings.import.summary_devices': '{n} dispositivos',
'settings.import.summary_content': '{n} itens de conteúdo',
'settings.import.summary_widgets': '{n} widgets',
'settings.import.summary_layouts': '{n} layouts',
'settings.import.summary_schedules': '{n} agendas',
'settings.import.summary_walls': '{n} paredes de vídeo',
'settings.import.summary_kiosk': '{n} páginas de quiosque',
'settings.import.found_summary': 'Encontrado: {summary}.<br>De: {email} (exportado {date})',
'settings.import.empty_export': 'exportação vazia',
'settings.import.uploading_zip': 'Enviando e importando... Pode demorar para arquivos grandes.',
'settings.import.importing': 'Importando...',
'settings.import.complete': 'Importação concluída: {imported}.',
'settings.import.pairing_codes_title': 'Códigos de pareamento:',
'settings.import.pairing_codes_hint': 'Digite estes códigos em cada dispositivo para revinculá-los. Atribuições e agendas serão preservadas.',
'settings.import.failed': 'Falha na importação',
'settings.import.failed_with_error': 'Falha na importação: {error}',
'settings.import.read_failed': 'Falha ao ler o arquivo: {error}',
'settings.toast.support_token_generated': 'Token de suporte gerado (válido {hours}h)',
'settings.toast.import_success': 'Dados importados com sucesso',
'settings.toast.name_required': 'O nome não pode ficar em branco',
'settings.toast.profile_saved': 'Perfil salvo',
'settings.toast.current_password_required': 'Digite sua senha atual',
'settings.toast.new_password_min_8': 'A nova senha deve ter no mínimo 8 caracteres',
'settings.toast.passwords_dont_match': 'As novas senhas não conferem',
'settings.toast.password_changed': 'Senha alterada',
'settings.toast.branding_saved': 'Branding salvo',
'settings.toast.preview_applied': 'Pré-visualização aplicada (recarregue para redefinir)',
'settings.toast.plan_updated': 'Plano atualizado',
'settings.toast.user_removed': 'Usuário removido',
'settings.user.col_user': 'Usuário',
'settings.user.col_auth': 'Auth',
'settings.user.col_role': 'Função',
'settings.user.col_plan': 'Plano',
'settings.user.col_actions': 'Ações',
'settings.user.remove': 'Remover',
'settings.user.you': 'Você',
'settings.user.confirm': 'Confirmar?',
'settings.user.count_one': '1 usuário registrado',
'settings.user.count_other': '{n} usuários registrados',
'settings.user.reset_password': 'Redefinir senha',
'settings.user.prompt_reset_password': 'Digite uma nova senha para {email} (mínimo 8 caracteres):',
'settings.toast.password_reset_for_user': 'Senha redefinida',
// Widgets
'widget.title': 'Widgets',
'widget.subtitle': 'Adicione conteúdo dinâmico aos seus layouts',
'widget.help_tip': 'Elementos de conteúdo dinâmico: relógios ao vivo, clima, tickers RSS, texto, páginas web e feeds sociais. Crie um widget e atribua à playlist de um dispositivo.',
'widget.new_widget': 'Novo widget',
'widget.configure': 'Configurar widget',
'widget.preview': 'Pré-visualizar',
'widget.preview_title': 'Pré-visualização',
'widget.webpage_blocked_note': 'Se esta área estiver em branco, o site bloqueia a incorporação e também não será exibido no dispositivo. Tente uma página que a permita.',
'widget.close': 'Fechar',
'widget.edit_x': 'Editar {type}',
'widget.new_x': 'Novo {type}',
'widget.empty_title': 'Nenhum widget ainda',
'widget.empty_desc': 'Crie um widget para adicionar conteúdo dinâmico aos seus layouts.',
'widget.this_widget': 'este widget',
'widget.confirm_delete': 'Excluir "{name}"? Isso não pode ser desfeito.',
'widget.toast.saved': 'Widget salvo',
'widget.toast.deleted': 'Widget excluído',
'widget.toast.preview_failed': 'Falha na pré-visualização',
'widget.type.clock.name': 'Relógio',
'widget.type.clock.desc': 'Relógio digital com data',
'widget.type.weather.name': 'Clima',
'widget.type.weather.desc': 'Condições climáticas atuais',
'widget.type.rss.name': 'Ticker de notícias',
'widget.type.rss.desc': 'Feed RSS com rolagem',
'widget.type.text.name': 'Texto/HTML',
'widget.type.text.desc': 'Texto ou conteúdo HTML personalizado',
'widget.type.webpage.name': 'Página web',
'widget.type.webpage.desc': 'Incorporar uma página web',
'widget.type.social.name': 'Feed social',
'widget.type.social.desc': 'Feed de redes sociais',
'widget.type.directory_board.name': 'Diretório',
'widget.type.directory_board.desc': 'Diretório rolante de inquilinos/salas para lobbies',
'widget.type.directory_search.name': 'Pesquisa de diretório',
'widget.type.directory_search.desc': 'Pesquisa interativa de um painel de diretório',
// directory-search widget
'widget.dirsearch.source_label': 'Painel de diretório',
'widget.dirsearch.source_hint': 'Lê as entradas ao vivo do painel selecionado; nada é copiado.',
'widget.dirsearch.source_empty': 'Crie primeiro um painel de diretório: este widget pesquisa em um painel existente.',
'widget.dirsearch.title_label': 'Título',
'widget.dirsearch.title_placeholder': 'Encontrar um inquilino',
'widget.dirsearch.logo_label': 'Logotipo (opcional)',
'widget.dirsearch.placeholder_label': 'Texto do campo de pesquisa',
'widget.dirsearch.placeholder_hint': 'Digite um nome, sala ou departamento…',
'widget.dirsearch.theme': 'Tema',
'widget.dirsearch.keyboard_label': 'Mostrar teclado na tela',
'widget.dirsearch.no_matches': 'Sem correspondências',
'widget.dirsearch.hint': 'Comece a digitar para pesquisar no diretório…',
'widget.field.name': 'Nome do widget',
'widget.field.format': 'Formato',
'widget.field.format_12h': '12 horas',
'widget.field.format_24h': '24 horas',
'widget.field.timezone': 'Fuso horário',
'widget.field.font_size': 'Tamanho da fonte',
'widget.field.font_size_px': 'Tamanho da fonte (px)',
'widget.field.color': 'Cor',
'widget.field.background': 'Fundo',
'widget.field.location': 'Local',
'widget.field.location_placeholder': 'Cidade, Estado',
'widget.field.units': 'Unidades',
'widget.field.units_imperial': 'Imperial (°F)',
'widget.field.units_metric': 'Métrico (°C)',
'widget.field.feed_url': 'URL do feed',
'widget.field.scroll_speed_seconds': 'Velocidade de rolagem (segundos)',
'widget.field.max_items': 'Máx. itens',
'widget.field.html_content': 'Conteúdo HTML',
'widget.field.css_optional': 'CSS (opcional)',
'widget.field.url': 'URL',
'widget.field.zoom_pct': 'Zoom (%)',
'widget.field.refresh_interval': 'Intervalo de atualização (segundos, 0 = nunca)',
'widget.field.platform': 'Plataforma',
'widget.field.platform_twitter': 'Twitter/X',
'widget.field.platform_instagram': 'Instagram',
'widget.field.query': 'Consulta',
'widget.field.query_placeholder': '@usuario ou #hashtag',
'widget.picker.default_title': 'Selecionar imagem',
'widget.picker.select_logo': 'Selecionar logotipo',
'widget.picker.select_bg_images': 'Selecionar imagens de fundo',
'widget.picker.search': 'Buscar imagens...',
'widget.picker.no_matches': 'Sem correspondências.',
'widget.picker.no_images': 'Sem imagens na biblioteca. Envie imagens primeiro pela Biblioteca de conteúdo.',
'widget.picker.selected_count': '{n} selecionadas',
'widget.dir.title_label': 'Título',
'widget.dir.title_placeholder': 'Armazém Lincoln',
'widget.dir.logo_label': 'Logotipo (opcional)',
'widget.dir.footer_text_label': 'Texto do rodapé',
'widget.dir.footer_placeholder': 'Consultas de locação: Contato...',
'widget.dir.bg_images_label': 'Imagens de fundo (opcional)',
'widget.dir.bg_images_hint': 'As imagens alternam a cada 15 segundos com 30% de opacidade. Adicione várias para rotação.',
'widget.dir.add_bg_image': '+ Adicionar imagem de fundo',
'widget.dir.theme': 'Tema',
'widget.dir.theme_dark': 'Escuro',
'widget.dir.theme_light': 'Claro',
'widget.dir.scroll_speed': 'Velocidade de rolagem',
'widget.dir.speed_slow': 'Lenta',
'widget.dir.speed_medium': 'Média',
'widget.dir.speed_fast': 'Rápida',
'widget.dir.columns': 'Colunas',
'widget.dir.columns_auto': 'Auto',
'widget.dir.categories': 'Categorias',
'widget.dir.add_category': '+ Adicionar categoria',
'widget.dir.add_entry': '+ Adicionar entrada',
'widget.dir.empty_categories': 'Adicione seu primeiro andar ou departamento para começar',
'widget.dir.no_entries': 'Sem entradas ainda',
'widget.dir.entry': 'entrada',
'widget.dir.entries': 'entradas',
'widget.dir.collapse': 'Recolher',
'widget.dir.expand': 'Expandir',
'widget.dir.move_up': 'Mover para cima',
'widget.dir.move_down': 'Mover para baixo',
'widget.dir.delete_category': 'Excluir categoria',
'widget.dir.delete_entry': 'Excluir entrada',
'widget.dir.unnamed': '(sem nome)',
'widget.dir.confirm_delete_category': 'Excluir a categoria "{name}" e todas as entradas?',
'widget.dir.category_name_placeholder': 'ex. Primeiro andar',
'widget.dir.entry_id_placeholder': '101',
'widget.dir.entry_name_placeholder': 'Nome do inquilino',
'widget.dir.entry_subtitle_placeholder': 'Detalhes (opcional)',
'widget.dir.available': 'Disponível',
'widget.dir.change': 'Alterar',
'widget.dir.choose_logo': 'Escolher logotipo',
'widget.dir.remove_logo': 'Remover',
'widget.dir.no_bg_images': 'Nenhuma imagem de fundo selecionada',
'widget.dir.remove_bg': 'Remover',
// Designer
'designer.title': 'Designer de conteúdo',
'designer.subtitle': 'Crie conteúdo dinâmico de sinalização',
'designer.help_tip': 'Crie sinalização personalizada com elementos ao vivo: relógios, clima, tickers RSS, contagens regressivas, códigos QR. Publique como widget ou exporte como PNG.',
'designer.load_design': 'Carregar design',
'designer.export_png': 'Exportar PNG',
'designer.publish': 'Publicar na biblioteca',
'designer.preview_hint': 'Clique em elementos para selecionar. Arraste para reposicionar. Pré-visualização atualiza em tempo real.',
'designer.add_element': 'Adicionar elemento',
'designer.background': 'Fundo',
'designer.bg_image': 'Imagem',
'designer.properties': 'Propriedades',
'designer.layers': 'Camadas',
'designer.no_elements': 'Sem elementos ainda',
'designer.save_design_file': 'Salvar arquivo de design',
'designer.qr_label': 'CÓDIGO QR',
'designer.loading_news': 'Carregando notícias...',
'designer.no_items': 'Sem itens',
'designer.feed_unavailable': 'Feed indisponível',
'designer.countdown_now': 'AGORA!',
'designer.widget_name': 'Design {date}',
'designer.el.text': 'Texto',
'designer.el.heading': 'Título',
'designer.el.image': 'Imagem',
'designer.el.video': 'Vídeo',
'designer.el.clock': 'Relógio',
'designer.el.date': 'Data',
'designer.el.weather': 'Clima',
'designer.el.ticker': 'Ticker',
'designer.el.shape': 'Forma',
'designer.el.qr': 'Código QR',
'designer.el.countdown': 'Contagem regressiva',
'designer.el.webpage': 'Página web',
'designer.bg.black': 'Preto',
'designer.bg.dark_blue': 'Azul escuro',
'designer.bg.dark_gradient': 'Gradiente escuro',
'designer.bg.blue_gradient': 'Gradiente azul',
'designer.bg.sunset': 'Pôr do sol',
'designer.bg.ocean': 'Oceano',
'designer.bg.forest': 'Floresta',
'designer.bg.dark_red': 'Vermelho escuro',
'designer.bg.white': 'Branco',
'designer.default.text': 'Seu texto aqui',
'designer.default.heading': 'TÍTULO',
'designer.default.coming_soon': 'Em breve',
'designer.prompt.video_url': 'URL do vídeo (MP4):',
'designer.prompt.weather_location': 'Cidade, Estado:',
'designer.prompt.rss_url': 'URL do feed RSS:',
'designer.prompt.qr_url': 'URL do código QR:',
'designer.prompt.countdown_date': 'Data alvo (AAAA-MM-DD):',
'designer.prompt.webpage_url': 'URL da página web:',
'designer.prop.text': 'Texto',
'designer.prop.size': 'Tamanho',
'designer.prop.font': 'Fonte',
'designer.prop.color': 'Cor',
'designer.prop.bold': 'Negrito',
'designer.prop.shadow': 'Sombra',
'designer.prop.format': 'Formato',
'designer.prop.show_seconds': 'Mostrar segundos',
'designer.prop.muted': 'Mudo',
'designer.prop.loop': 'Loop',
'designer.prop.opacity': 'Opacidade',
'designer.prop.shape': 'Forma',
'designer.prop.location': 'Local',
'designer.prop.feed_url': 'URL do feed',
'designer.prop.speed': 'Velocidade (segundos)',
'designer.prop.text_color': 'Cor do texto',
'designer.prop.bg_color': 'Cor de fundo',
'designer.prop.target_date': 'Data alvo',
'designer.prop.label': 'Rótulo',
'designer.toast.published': 'Publicado como widget! Atribua a uma zona de layout.',
'designer.toast.publish_failed': 'Falha ao publicar',
'designer.toast.export_failed': 'Falha ao exportar: {error}',
'designer.toast.loaded': 'Design carregado',
'designer.toast.invalid_file': 'Arquivo de design inválido',
// Playlists
'playlist.title': 'Playlists',
'playlist.subtitle': 'Crie e gerencie playlists de conteúdo',
'playlist.show_auto_generated': 'Mostrar autogeradas',
'playlist.new_playlist_btn': '+ Nova playlist',
'playlist.new_playlist': 'Nova playlist',
'playlist.empty_title': 'Sem playlists ainda',
'playlist.empty_desc': 'Crie sua primeira playlist para organizar conteúdo para suas telas.',
'playlist.all_auto_generated': 'Todas as playlists são autogeradas. Ative "Mostrar autogeradas" para vê-las.',
'playlist.tag_auto': 'auto',
'playlist.tag_draft': 'rascunho',
'playlist.item_count_one': '1 item',
'playlist.item_count_other': '{n} itens',
'playlist.created_at': 'Criada {date}',
'playlist.display_count_one': '1 tela',
'playlist.display_count_other': '{n} telas',
'playlist.assigned_to_one': 'Atribuída a 1 tela',
'playlist.assigned_to_other': 'Atribuída a {n} telas',
'playlist.load_failed': 'Falha ao carregar playlists: {error}',
'playlist.back_to_playlists': 'Voltar para playlists',
'playlist.name_placeholder': 'Nome da playlist',
'playlist.desc_placeholder': 'Descrição (opcional)',
'playlist.create_btn': 'Criar',
'playlist.add_desc_placeholder': 'Adicionar uma descrição...',
'playlist.click_to_rename': 'Clique para renomear',
'playlist.click_to_edit_desc': 'Clique para editar a descrição',
'playlist.add_content': '+ Adicionar conteúdo',
'playlist.delete_playlist': 'Excluir playlist',
'playlist.back': 'Voltar',
'playlist.items_empty': 'Esta playlist está vazia',
'playlist.items_empty_hint': 'Clique em "Adicionar conteúdo" para adicionar itens.',
'playlist.duration': 'Duração',
'playlist.sec': 'seg',
'playlist.move_up': 'Mover para cima',
'playlist.move_down': 'Mover para baixo',
'playlist.remove_item': 'Remover item',
'playlist.item_widget': 'Widget',
'playlist.unknown_type': 'Tipo desconhecido',
'playlist.confirm_delete': 'Excluir "{name}"? Isso não pode ser desfeito.',
'playlist.confirm_discard_draft': 'Descartar todas as alterações não publicadas e voltar à última versão publicada?',
'playlist.draft.banner_title': 'Alterações não publicadas',
'playlist.draft.devices_showing_published': 'Os dispositivos ainda exibem a última versão publicada.',
'playlist.draft.never_published': 'Esta playlist nunca foi publicada. Os dispositivos não exibirão nada até você publicar.',
'playlist.draft.discard_changes': 'Descartar alterações',
'playlist.draft.publish': 'Publicar',
'playlist.draft.publishing': 'Publicando...',
'playlist.preview_prev': 'Anterior',
'playlist.preview_next': 'Próximo',
'playlist.preview_position': '{current} de {total}',
'playlist.preview_zoned': 'As zonas tocam juntas',
'playlist.toast.created': 'Playlist criada',
'playlist.toast.deleted': 'Playlist excluída',
'playlist.toast.published': 'Playlist publicada — dispositivos atualizados',
'playlist.toast.draft_discarded': 'Alterações do rascunho descartadas',
'playlist.toast.item_removed': 'Item removido',
'playlist.add_modal_title': 'Adicionar conteúdo à playlist',
'playlist.tab_content': 'Conteúdo',
'playlist.tab_widgets': 'Widgets',
'playlist.search_placeholder': 'Buscar...',
'playlist.close': 'Fechar',
'playlist.no_content_found': 'Nenhum conteúdo encontrado',
'playlist.no_widgets_found': 'Nenhum widget encontrado',
'playlist.add_btn': 'Adicionar',
'playlist.replace_item': 'Substituir conteúdo',
'playlist.duplicate_item': 'Duplicar item',
'playlist.replace_modal_title': 'Substituir conteúdo',
'playlist.replace_btn': 'Substituir',
'playlist.replacing': 'Substituindo…',
'playlist.toast.item_duplicated': 'Item duplicado',
'playlist.toast.item_replaced': 'Conteúdo substituído',
'playlist.adding': 'Adicionando...',
'playlist.added': 'Adicionado',
// Per-item schedule editor (#74/#75)
'itemsched.title': 'Programação',
'itemsched.hint': 'Itens sem programação sempre são reproduzidos. Adicione blocos para limitar quando este item aparece — avaliado no horário local de cada tela.',
'itemsched.none': 'Sem programação — este item sempre é reproduzido.',
'itemsched.block': 'Bloco {n}',
'itemsched.remove_block': 'Remover bloco',
'itemsched.from': 'De',
'itemsched.to': 'Até',
'itemsched.end_of_day': 'fim do dia',
'itemsched.starts': 'Início',
'itemsched.ends': 'Fim',
'itemsched.dates_hint': '(datas opcionais, inclusivas)',
'itemsched.add_block': '+ Adicionar bloco de programação',
'itemsched.cancel': 'Cancelar',
'itemsched.save': 'Salvar programação',
'itemsched.toast.saved': 'Programação salva — publique a playlist para enviá-la aos dispositivos',
'itemsched.toast.cleared': 'Programação limpa — publique para atualizar os dispositivos',
'itemsched.every_day': 'Todos os dias',
'itemsched.mon_fri': 'Seg-Sex',
'itemsched.sat_sun': 'Sáb-Dom',
'itemsched.dow_short': 'Dom,Seg,Ter,Qua,Qui,Sex,Sáb',
'itemsched.err.days': 'Cada bloco de programação precisa de pelo menos um dia ativo',
'itemsched.err.start': 'A hora de início deve ser HH:MM',
'itemsched.err.end': 'A hora de fim deve ser HH:MM (ou fim do dia)',
'itemsched.err.start_date': 'A data de início deve ser AAAA-MM-DD',
'itemsched.err.end_date': 'A data de fim deve ser AAAA-MM-DD',
'device.clock.label': 'Relógio do dispositivo',
'device.clock.reported': '{time} reportado',
'device.clock.skew': '⚠ relógio defasado em {amount} — as programações podem disparar no horário local errado',
// Onboarding
'onboarding.back': 'Voltar',
'onboarding.next': 'Próximo',
'onboarding.skip': 'Pular assistente',
'onboarding.go_to_dashboard': 'Ir para o painel',
'onboarding.pair_display': 'Parear tela',
'onboarding.step.welcome.title': 'Bem-vindo ao ScreenTinker!',
'onboarding.step.welcome.intro': 'Vamos configurar tudo em menos de 5 minutos.',
'onboarding.step.welcome.guide_through': 'Este assistente irá guiá-lo através de:',
'onboarding.step.welcome.bullet_download': 'Baixar o app do player',
'onboarding.step.welcome.bullet_pair': 'Parear sua primeira tela',
'onboarding.step.welcome.bullet_upload': 'Enviar e atribuir conteúdo',
'onboarding.step.player.title': 'Passo 1: Obtenha o app do player',
'onboarding.step.player.intro': 'Instale o player no seu dispositivo de exibição.',
'onboarding.step.player.android_label': 'APK Android',
'onboarding.step.player.android_desc': 'TV boxes, tablets, Fire TV',
'onboarding.step.player.web_label': 'Player web',
'onboarding.step.player.web_desc': 'Qualquer navegador, Pi, ChromeOS',
'onboarding.step.player.url_hint': 'Abra o app na sua tela e digite esta URL do servidor:',
'onboarding.step.pair.title': 'Passo 2: Pareie sua tela',
'onboarding.step.pair.intro': 'Digite o código de 6 dígitos exibido na sua tela.',
'onboarding.step.pair.name_placeholder': 'Nome (ex. TV do lobby)',
'onboarding.step.upload.title': 'Passo 3: Envie conteúdo',
'onboarding.step.upload.intro': 'Envie um vídeo ou imagem para exibir.',
'onboarding.step.upload.click_to_select': 'Clique para selecionar um arquivo',
'onboarding.step.upload.formats': 'MP4, WebM, JPEG, PNG, GIF',
'onboarding.step.upload.uploading': 'Enviando...',
'onboarding.step.done.title': 'Tudo pronto!',
'onboarding.step.done.intro': 'Sua tela está pareada e o conteúdo está sendo exibido!',
'onboarding.step.done.whats_next': 'O que vem a seguir?',
'onboarding.step.done.next_content': 'Adicione mais conteúdo na <strong>Biblioteca de conteúdo</strong>',
'onboarding.step.done.next_layouts': 'Crie layouts multi-zona em <strong>Layouts</strong>',
'onboarding.step.done.next_schedule': 'Configure uma agenda no calendário <strong>Agenda</strong>',
'onboarding.step.done.next_widgets': 'Adicione widgets ao vivo (relógio, clima, ticker) em <strong>Widgets</strong>',
'onboarding.step.done.next_kiosk': 'Crie telas interativas em <strong>Quiosque</strong>',
'onboarding.step.done.next_designer': 'Crie conteúdo personalizado no <strong>Designer</strong>',
'onboarding.toast.invalid_code': 'Digite um código válido de 6 dígitos',
'onboarding.toast.pairing': 'Pareando...',
'onboarding.toast.pair_failed': 'Falha no pareamento',
'onboarding.toast.pair_failed_with_error': 'Falha no pareamento: {error}',
'onboarding.toast.paired': 'Tela pareada!',
'onboarding.toast.uploaded_assigning': 'Enviado! Atribuindo à tela...',
'onboarding.toast.content_assigned': 'Conteúdo enviado e atribuído!',
'onboarding.toast.upload_failed': 'Falha no envio',
'onboarding.toast.error_with_error': 'Erro: {error}',
// Admin
'admin.title': 'Administração da plataforma',
'admin.subtitle': 'Controles de superadmin - apenas você pode ver isso',
'admin.access_denied': 'Acesso negado',
'admin.access_denied_desc': 'Acesso de admin da plataforma necessário.',
'admin.all_users': 'Todos os usuários',
'admin.plans': 'Planos de assinatura',
'admin.col.accounts': 'Contas',
'admin.col.screens': 'Ecrãs',
'admin.plan_hidden': 'oculto',
'admin.plan_orphaned': 'Contas num plano que já não existe',
'admin.system': 'Sistema',
'admin.col.user': 'Usuário',
'admin.col.auth': 'Auth',
'admin.col.last_login': 'Último login',
'admin.col.role': 'Função',
'admin.col.plan': 'Plano',
'admin.col.actions': 'Ações',
'admin.col.devices': 'Dispositivos',
'admin.col.storage': 'Armazenamento',
'admin.col.monthly': 'Mensal',
'admin.col.yearly': 'Anual',
'admin.role.user': 'Usuário',
'admin.role.admin': 'Admin',
'admin.role.superadmin': 'Superadmin',
'admin.remove': 'Remover',
'admin.owner': 'Proprietário',
'admin.confirm': 'Confirmar?',
'admin.total_users': '{n} usuários no total',
'admin.unlimited': 'Ilimitado',
'admin.free': 'Grátis',
'admin.version': 'Versão',
'admin.frontend_hash': 'Hash do frontend',
'admin.download_db_backup': 'Baixar backup do BD',
'admin.server_status': 'Status do servidor',
'admin.toast.role_updated': 'Função atualizada',
'admin.toast.plan_updated': 'Plano atualizado',
'admin.toast.user_removed': 'Usuário removido',
'admin.reset_password': 'Redefinir senha',
'admin.prompt_reset_password': 'Digite uma nova senha para {email} (mínimo 8 caracteres):',
'admin.toast.password_min_8': 'A senha deve ter no mínimo 8 caracteres',
'admin.toast.password_reset': 'Senha redefinida',
// Schedule
'schedule.title': 'Agenda',
'schedule.subtitle': 'Calendário de programação de conteúdo',
'schedule.help_tip': 'Calendário semanal. Arraste sobre um intervalo para criar um agendamento, arraste um bloco para o mover, arraste a margem inferior para alterar quando termina, ou clique com o botão direito para mais opções. A prioridade mais alta prevalece, e o agendamento do próprio ecrã substitui o do seu grupo.',
'schedule.prev_week': '< Anterior',
'schedule.next_week': 'Próxima >',
'schedule.add_schedule': 'Adicionar agenda',
'schedule.edit_schedule': 'Editar agenda',
'schedule.apply_to': 'Aplicar a',
'schedule.target_device': 'Dispositivo',
'schedule.target_group': 'Grupo',
'schedule.group_devices_count': '{n} dispositivos',
'schedule.no_groups_msg': 'Sem grupos criados ainda. Crie na página Telas.',
'schedule.zone_note': 'Nota: Agendas por zona dependem do layout. Garanta que todos dispositivos do grupo usem o mesmo layout.',
'schedule.playlist_override': 'Sobrepor playlist',
'schedule.no_playlist_override': '— Sem sobreposição —',
'schedule.draft_suffix': '(rascunho)',
'schedule.layout_override': 'Sobrepor layout',
'schedule.no_layout_override': '— Sem sobreposição —',
'schedule.content_label': 'Conteúdo',
'schedule.content_hint': '(item único, opcional)',
'schedule.content_none': '— Nenhum —',
'schedule.title_label': 'Título (opcional)',
'schedule.title_placeholder': 'ex. Playlist matinal',
'schedule.start_time': 'Início',
'schedule.end_time': 'Fim',
'schedule.repeat': 'Repetir',
'schedule.repeat_none': 'Sem repetição',
'schedule.repeat_daily': 'Diário',
'schedule.repeat_weekdays': 'Dias úteis',
'schedule.repeat_weekends': 'Fins de semana',
'schedule.repeat_weekly': 'Semanal',
'schedule.priority': 'Prioridade',
'schedule.color': 'Cor',
'schedule.scheduled_label': 'Agendado',
'schedule.tooltip_group_prefix': 'Grupo: ',
'schedule.tooltip_priority': 'Prioridade: {n}',
'schedule.day.sun': 'Dom',
'schedule.day.mon': 'Seg',
'schedule.day.tue': 'Ter',
'schedule.day.wed': 'Qua',
'schedule.day.thu': 'Qui',
'schedule.day.fri': 'Sex',
'schedule.day.sat': 'Sáb',
'schedule.hour_12am': '00h',
'schedule.hour_am': 'h',
'schedule.hour_12pm': '12h',
'schedule.hour_pm': 'h',
'schedule.toast.no_groups': 'Nenhum grupo disponível. Crie um primeiro.',
'schedule.toast.saved': 'Agenda salva',
// Reports
'report.title': 'Relatórios',
'report.subtitle': 'Análise de exibição e disponibilidade dos dispositivos',
'report.help_tip': 'Análise de exibição. Veja o que foi exibido, quando e em qual dispositivo. Filtre por período e dispositivo. Exporte CSV para verificação.',
'report.export_csv': 'Exportar CSV',
'report.device': 'Dispositivo',
'report.all_devices': 'Todos os dispositivos',
'report.start_date': 'Data de início',
'report.end_date': 'Data de fim',
'report.load_report': 'Carregar relatório',
'report.select_range': 'Selecione um período e clique em Carregar relatório',
'report.error': 'Erro',
'report.total_plays': 'Exibições totais',
'report.total_hours': 'Horas totais',
'report.unique_content': 'Conteúdo único',
'report.active_devices': 'Dispositivos ativos',
'report.avg_duration': 'Duração média',
'report.plays_per_day': 'Exibições por dia',
'report.plays_by_hour': 'Exibições por hora',
'report.top_content': 'Conteúdo mais exibido',
'report.by_device': 'Por dispositivo',
'report.no_data': 'Sem dados',
'report.col.content': 'Conteúdo',
'report.col.device': 'Dispositivo',
'report.col.plays': 'Exibições',
'report.col.total_hours': 'Horas totais',
'report.col.completion': 'Conclusão',
// Kiosk
'kiosk.title': 'Páginas de quiosque',
'kiosk.subtitle': 'Crie interfaces de toque interativas',
'kiosk.help_tip': 'Crie interfaces de toque interativas. Adicione botões com ícones e ações. Inclui tela ociosa após inatividade. Atribua a dispositivos como widget.',
'kiosk.new_page': 'Nova página de quiosque',
'kiosk.prompt_name': 'Nome da página:',
'kiosk.empty_title': 'Sem páginas ainda',
'kiosk.empty_desc': 'Crie uma interface interativa para suas telas.',
'kiosk.label': 'Página de quiosque',
'kiosk.preview': 'Pré-visualizar',
'kiosk.confirm_delete': 'Excluir a página "{name}"? Isso não pode ser desfeito.',
'kiosk.toast.deleted': 'Página excluída',
'kiosk.toast.delete_failed': 'Falha ao excluir',
'kiosk.toast.saved': 'Página salva',
'kiosk.not_found': 'Página não encontrada',
'kiosk.back': 'Voltar para páginas',
'kiosk.page_settings': 'Configurações da página',
'kiosk.title_label': 'Título',
'kiosk.subtitle_label': 'Subtítulo',
'kiosk.logo_url': 'URL do logotipo',
'kiosk.footer_text': 'Texto do rodapé',
'kiosk.idle_title': 'Título da tela ociosa',
'kiosk.idle_default': 'Toque para começar',
'kiosk.idle_timeout': 'Tempo de inatividade (segundos)',
'kiosk.style': 'Estilo',
'kiosk.background': 'Fundo',
'kiosk.text_color': 'Cor do texto',
'kiosk.columns': 'Colunas',
'kiosk.button_color': 'Cor do botão',
'kiosk.button_hover': 'Cor do hover',
'kiosk.buttons': 'Botões',
'kiosk.add_btn': '+ Adicionar',
'kiosk.icon_placeholder': 'Emoji',
'kiosk.label_placeholder': 'Rótulo',
'kiosk.sublabel_placeholder': 'Sub-rótulo',
'kiosk.action_none': 'Sem ação',
'kiosk.action_url': 'Abrir URL',
'kiosk.action_page': 'Ir para página',
'kiosk.url_placeholder': 'URL ou página',
'kiosk.no_buttons': 'Sem botões ainda',
'kiosk.new_button': 'Novo botão',
// Layout editor
'layout.title': 'Layouts',
'layout.subtitle': 'Layouts e modelos de tela',
'layout.help_tip': 'Crie layouts de tela multi-zona. Use modelos ou crie os seus. Arraste zonas para posicionar, redimensione pelo canto. Atribua layouts a dispositivos na aba Playlist.',
'layout.new_layout': 'Novo layout',
'layout.templates': 'Modelos',
'layout.my_layouts': 'Meus layouts',
'layout.empty_custom': 'Sem layouts personalizados ainda',
'layout.prompt_name': 'Nome do layout:',
'layout.default_zone_name': 'Principal',
'layout.template_label': 'Modelo',
'layout.use_template': 'Usar modelo',
'layout.zone_count_one': '1 zona',
'layout.zone_count_other': '{n} zonas',
'layout.confirm_delete': 'Excluir o layout "{name}"? Isso não pode ser desfeito.',
'layout.toast.deleted': 'Layout excluído',
'layout.toast.delete_failed': 'Falha ao excluir o layout',
'layout.toast.saved': 'Layout salvo',
'layout.not_found': 'Layout não encontrado',
'layout.back': 'Voltar para layouts',
'layout.add_zone': 'Adicionar zona',
'layout.zones': 'Zonas',
'layout.properties': 'Propriedades',
'layout.delete_zone': 'Excluir zona',
'layout.zone_n': 'Zona {n}',
'layout.prop.name': 'Nome',
'layout.prop.x': 'X (%)',
'layout.prop.y': 'Y (%)',
'layout.prop.width': 'Largura (%)',
'layout.prop.height': 'Altura (%)',
'layout.prop.type': 'Tipo',
'layout.type_content': 'Conteúdo',
'layout.type_widget': 'Widget',
// Video walls
'wall.title': 'Paredes de vídeo',
'wall.subtitle': 'Combine várias telas em uma grande',
'wall.help_tip': 'Combine várias telas em uma grande. Defina o tamanho da grade, arraste dispositivos para posições, ajuste compensação de moldura. Atribua conteúdo para reproduzir em todos os dispositivos.',
'wall.new_wall': 'Nova parede de vídeo',
'wall.prompt_name': 'Nome da parede de vídeo:',
'wall.empty_title': 'Nenhuma parede de vídeo ainda',
'wall.empty_desc': 'Crie uma parede de vídeo para combinar várias telas.',
'wall.grid_summary': 'Grade {cols}x{rows} • {n} dispositivos',
'wall.not_found': 'Parede não encontrada',
'wall.back': 'Voltar para paredes',
'wall.delete_wall': 'Excluir parede',
'wall.grid_config': 'Configuração da grade',
'wall.columns': 'Colunas',
'wall.rows': 'Linhas',
'wall.h_bezel': 'Moldura H (px)',
'wall.v_bezel': 'Moldura V (px)',
'wall.update': 'Atualizar',
'wall.content': 'Conteúdo',
'wall.no_content': 'Sem conteúdo',
'wall.set_content': 'Definir conteúdo',
'wall.available_displays': 'Telas disponíveis',
'wall.all_assigned': 'Todos os dispositivos atribuídos',
'wall.drop_here': 'Solte aqui',
'wall.toast.placed': '{name} posicionado em [{col},{row}]',
'wall.toast.grid_updated': 'Grade atualizada',
'wall.toast.content_updated': 'Conteúdo atualizado',
'wall.toast.deleted': 'Parede excluída',
// Billing
'billing.title': 'Assinatura',
'billing.subtitle': 'Gerencie seu plano e cobrança',
'billing.current_plan': 'Plano atual',
'billing.self_hosted': 'Auto-hospedado',
'billing.trial_days_left': 'Avaliação - {n} dias restantes',
'billing.trial_ends': 'Sua avaliação {plan} termina em {n} dias',
'billing.trial_after': 'Após a avaliação, você passará para o plano Gratuito (1 dispositivo). Atualize agora para manter seus dispositivos e recursos.',
'billing.devices': 'Dispositivos',
'billing.devices_lc': 'dispositivos',
'billing.storage': 'Armazenamento',
'billing.storage_lc': 'armazenamento',
'billing.features': 'Recursos',
'billing.feat.remote_control': 'Controle remoto',
'billing.feat.remote_urls': 'URLs remotas',
'billing.feat.priority_support': 'Suporte prioritário',
'billing.available_plans': 'Planos disponíveis',
'billing.current': 'Atual',
'billing.unlimited': 'Ilimitado',
'billing.free': 'Grátis',
'billing.per_month': '/mês',
'billing.yearly_save': 'ou ${price}/ano (economize {pct}%)',
'billing.monthly': 'Mensal',
'billing.yearly': 'Anual',
'billing.manage_subscription': 'Gerenciar assinatura',
'billing.self_hosted_note': 'Modo auto-hospedado: planos podem ser atribuídos por administradores sem cobrança.',
'billing.failed_to_load': 'Falha ao carregar',
'billing.toast.checkout_failed': 'Falha ao iniciar pagamento: {error}',
'billing.toast.portal_failed': 'Falha ao abrir portal de cobrança: {error}',
'billing.toast.payment_success': 'Pagamento bem-sucedido! Seu plano foi atualizado.',
// Teams
'team.title': 'Equipes',
'team.subtitle': 'Gerencie equipes e acesso compartilhado',
'team.help_tip': 'Crie equipes para compartilhar dispositivos com outros usuários. Proprietários gerenciam a equipe, editores podem alterar conteúdo/playlists, visualizadores apenas monitoram.',
'team.new_team': 'Nova equipe',
'team.prompt_name': 'Nome da equipe:',
'team.empty_title': 'Sem equipes ainda',
'team.empty_desc': 'Crie uma equipe para compartilhar dispositivos com outros usuários.',
'team.your_role': 'Sua função: {role}',
'team.member_count_one': '1 membro',
'team.member_count_other': '{n} membros',
'team.not_found': 'Equipe não encontrada',
'team.back': 'Voltar para equipes',
'team.delete_team': 'Excluir equipe',
'team.members_count': 'Membros ({n})',
'team.invite': '+ Convidar',
'team.role_viewer': 'Visualizador',
'team.role_editor': 'Editor',
'team.role_owner': 'Proprietário',
'team.remove': 'Remover',
'team.remove_from_team': 'Remover da equipe',
'team.no_members': 'Sem membros',
'team.shared_devices': 'Dispositivos compartilhados ({n})',
'team.add_device': '+ Adicionar dispositivo...',
'team.no_devices': 'Sem dispositivos compartilhados com esta equipe',
'team.prompt_email': 'E-mail para convidar:',
'team.prompt_role': 'Função (viewer, editor ou owner):',
'team.toast.invalid_role': 'Função inválida',
'team.toast.invitation_sent': 'Convite enviado',
'team.toast.role_updated': 'Função atualizada',
'team.toast.member_removed': 'Membro removido',
'team.toast.device_added': 'Dispositivo adicionado à equipe',
'team.toast.device_removed': 'Dispositivo removido da equipe',
'team.toast.deleted': 'Equipe excluída',
// Activity
'activity.title': 'Registro de atividades',
'activity.subtitle': 'Trilha de auditoria de todas as ações',
'activity.load_more': 'Carregar mais',
'activity.empty_title': 'Sem atividade ainda',
'activity.empty_desc': 'As ações aparecerão aqui conforme você usa o sistema.',
'activity.system': 'Sistema',
'activity.verb_created': 'criou',
'activity.verb_updated': 'atualizou',
'activity.verb_deleted': 'excluiu',
'activity.action_paired_device': 'pareou um dispositivo',
'activity.action_added_remote_content': 'adicionou conteúdo remoto',
'activity.noun_content': 'conteúdo',
'activity.noun_device': 'dispositivo',
'activity.noun_playlist_assignment': 'atribuição de playlist',
'activity.noun_assignment': 'atribuição',
'activity.noun_layout': 'layout',
'activity.noun_widget': 'widget',
'activity.noun_schedule': 'agenda',
'activity.noun_video_wall': 'parede de vídeo',
'activity.alert_device_offline': 'alerta: dispositivo offline',
// Help
'help.title': 'Central de ajuda',
'help.subtitle': 'Guias rápidos e perguntas frequentes',
'help.faq': 'Perguntas frequentes',
'help.shortcuts': 'Atalhos de teclado',
'help.shortcut_esc': 'Reiniciar player web (na página do player)',
'help.shortcut_f': 'Alternar tela cheia (player web)',
// Add Display modal
'add_display.title': 'Adicionar tela',
'add_display.intro': 'Digite o código de pareamento de 6 dígitos exibido na tela.',
'add_display.pairing_code': 'Código de pareamento',
'add_display.display_name': 'Nome (opcional)',
'add_display.name_placeholder': 'ex. TV do lobby',
'add_display.need_player': 'Precisa de um app player? Instale um para obter um código:',
'add_display.android_apk': 'APK Android',
'add_display.web_player': 'Player web',
'add_display.raspberry_pi': 'Raspberry Pi',
'add_display.windows': 'Windows',
'add_display.smart_tv_note': 'Smart TVs (LG/Samsung): abra o navegador integrado e vá para <code style="background:var(--bg-input,#0f172a);padding:1px 4px;border-radius:3px">/player</code>',
'add_display.pair_btn': 'Parear tela',
};