{
  "docs": {
    "gettingStarted": {
      "hero": {
        "badge": "Primeiros Passos",
        "title": "Documentação",
        "subtitle": "Tudo que você precisa para construir apps web reativos com No.JS"
      },
      "introduction": {
        "title": "Introdução",
        "text": "No.JS é um framework reativo HTML-first. Construa aplicações web dinâmicas e orientadas a dados usando apenas atributos HTML — sem build, sem virtual DOM, sem JSX.",
        "callout": "Zero dependências · Funciona em todos os navegadores modernos · Sem necessidade de build"
      },
      "installation": {
        "title": "Instalação",
        "cdnSubtitle": "CDN (recomendado)",
        "selfHostedSubtitle": "Auto-hospedado",
        "selfHostedText": "Baixe dist/iife/no.js e inclua com uma tag <script>. É um único arquivo.",
        "npmSubtitle": "npm / ESM",
        "npmText": "Ao usar npm, você deve chamar NoJS.init() manualmente após o DOM estar pronto. O script CDN faz isso automaticamente."
      },
      "quickStart": {
        "title": "Início Rápido",
        "text": "Crie um arquivo index.html: inclua o script, adicione alguns atributos e pronto. Sem app.mount(), sem createApp(), sem NgModule. Simplesmente funciona."
      },
      "howItWorks": {
        "title": "Como Funciona",
        "text": "No DOMContentLoaded, o No.JS percorre o DOM procurando elementos com atributos conhecidos. Cada atributo mapeia para uma diretiva que é executada por prioridade.",
        "card1Title": "1. Analisar",
        "card1Desc": "Percorre o DOM procurando elementos com atributos conhecidos.",
        "card2Title": "2. Resolver",
        "card2Desc": "Cada atributo mapeia para uma diretiva executada por prioridade (data fetching primeiro, depois condicionais, depois renderização).",
        "card3Title": "3. Reagir",
        "card3Desc": "Todos os dados vivem em contextos reativos (baseados em Proxy). Quando os dados mudam, todo elemento vinculado atualiza automaticamente.",
        "card4Title": "4. Escopo",
        "card4Desc": "Contextos herdam dos elementos pais, como escopo léxico. Um bind dentro de um loop each pode acessar tanto o item do loop quanto dados ancestrais."
      },
      "coreConcepts": {
        "title": "Conceitos Fundamentais",
        "reactiveContextSubtitle": "Contexto Reativo",
        "reactiveContextText": "Todo elemento pode ter um contexto — um objeto de dados reativo. Contextos são criados por state, get, store, etc. Elementos filhos herdam automaticamente o contexto do pai.",
        "directivePrioritySubtitle": "Prioridade de Diretivas",
        "tableCol1": "Prioridade",
        "tableCol2": "Diretivas",
        "tableCol3": "Descrição",
        "tableRow1": "Inicializar estado local/global",
        "tableRow4": "Estrutural (adicionar/remover DOM)",
        "tableRow5": "Renderização (atualizar DOM existente)",
        "tableRow7": "Efeitos colaterais",
        "expressionSubtitle": "Sintaxe de Expressões",
        "expressionText": "A maioria dos valores de diretivas aceita expressões JavaScript avaliadas contra o contexto atual:",
        "tableRow1b": "Buscar dados, error boundaries, namespace i18n",
        "tableRow2b": "Valores derivados e watchers de efeitos colaterais",
        "tableRow5b": "Referências a elementos",
        "tableRow15": "Configuração de drag and drop (Agora no NoJS Elements)"
      }
    },
    "cheatsheet": {
      "hero": {
        "badge": "Referência da API",
        "title": "Cheatsheet de Diretivas",
        "subtitle": "Referência completa de todas as diretivas do No.JS"
      },
      "data": {
        "title": "Dados",
        "col1": "Diretiva",
        "col2": "Exemplo",
        "col3": "Descrição",
        "base": "Definir URL base da API para descendentes",
        "get": "Buscar dados (GET)",
        "post": "Enviar dados (POST)",
        "put": "Atualizar dados (PUT)",
        "patch": "Atualização parcial (PATCH)",
        "delete": "Excluir dados (DELETE)",
        "as": "Nome para os dados buscados no contexto",
        "body": "Corpo da requisição",
        "headers": "Cabeçalhos da requisição",
        "params": "Parâmetros de query",
        "cached": "Cachear respostas (memory/local/session)",
        "into": "Escrever resposta em um store global nomeado",
        "debounce": "Debounce para re-fetch de URLs reativas (ms)",
        "retry": "Quantidade de tentativas por elemento",
        "refresh": "Intervalo de polling em ms",
        "success": "ID do template para exibir em caso de sucesso",
        "then": "Expressão para executar em caso de sucesso",
        "redirect": "Caminho para navegar após sucesso",
        "confirm": "Mensagem de confirmação antes da requisição",
        "skeleton": "Mostrar/ocultar um placeholder durante o carregamento",
        "retryDelay": "Atraso entre tentativas em ms"
      },
      "state": {
        "title": "Estado",
        "col1": "Diretiva",
        "col2": "Exemplo",
        "col3": "Descrição",
        "state": "Criar estado reativo local",
        "store": "Definir/acessar store global",
        "computed": "Valor reativo derivado",
        "watch": "Reagir a mudanças de valor",
        "persist": "Atributo da diretiva state — persiste o estado no storage",
        "model": "Two-way binding para inputs",
        "persistKey": "Chave de armazenamento para persistência",
        "persistFields": "Campos separados por vírgula para persistir",
        "persistSchema": "Validar chaves restauradas contra o estado inicial"
      },
      "rendering": {
        "title": "Renderização",
        "col1": "Diretiva",
        "col2": "Exemplo",
        "col3": "Descrição",
        "bind": "Definir conteúdo de texto",
        "bindHtml": "Definir innerHTML (sanitizado)",
        "bindStar": "Vincular qualquer atributo",
        "if": "Renderização condicional",
        "elseIf": "Condicional encadeada",
        "then": "Template para verdadeiro",
        "else": "Template para falso",
        "show": "Alternar visibilidade (CSS)",
        "hide": "Inverso de show",
        "switch": "Renderização switch/case",
        "case": "Correspondência de caso",
        "default": "Caso padrão"
      },
      "loops": {
        "title": "Loops",
        "col1": "Diretiva",
        "col2": "Exemplo",
        "col3": "Descrição",
        "foreach": "Diretiva de loop primária",
        "each": "Alias de foreach",
        "for": "Alias de foreach",
        "from": "Array de origem (DEPRECATED — use a sintaxe \"item in array\")",
        "template": "Template para clonar",
        "index": "Nome da variável de índice",
        "key": "Chave única para diffing",
        "filter": "Expressão de filtro",
        "sort": "Propriedade para ordenação (apenas nome, sem prefixo da variável do item)",
        "limit": "Máximo de itens",
        "offset": "Pular itens"
      },
      "events": {
        "title": "Eventos",
        "col1": "Diretiva",
        "col2": "Exemplo",
        "col3": "Descrição",
        "onClick": "Handler de clique",
        "onSubmit": "Handler de envio",
        "onInput": "Handler de input",
        "onKeydown": "Handler de tecla",
        "onInit": "Dispara imediatamente durante a inicialização",
        "onMounted": "Lifecycle: montado",
        "onUnmounted": "Lifecycle: desmontado",
        "throttle": "Throttle na execução do handler (ms)",
        "self": "Dispara apenas se o alvo do evento for o próprio elemento",
        "backspace": "Modificador de tecla para a tecla Backspace",
        "onUpdated": "Lifecycle: mutação do DOM observada",
        "onError": "Lifecycle: erro na subárvore"
      },
      "styling": {
        "title": "Estilização",
        "col1": "Diretiva",
        "col2": "Exemplo",
        "col3": "Descrição",
        "classStar": "Alternar classe CSS",
        "classMap": "Classe a partir de objeto",
        "styleStar": "Definir estilo inline",
        "styleMap": "Estilo a partir de objeto"
      },
      "forms": {
        "title": "Formulários",
        "col1": "Diretiva",
        "col2": "Exemplo",
        "col3": "Descrição",
        "validate": "Habilitar validação de formulário/campo (Agora no NoJS Elements)",
        "error": "Template de erro para campo",
        "success": "Template de sucesso",
        "loading": "Template de carregamento",
        "confirm": "Diálogo de confirmação",
        "redirect": "Redirecionar em caso de sucesso"
      },
      "routing": {
        "title": "Roteamento",
        "col1": "Diretiva",
        "col2": "Exemplo",
        "col3": "Descrição",
        "route": "Definir rota ou link",
        "routeView": "Outlet de rota",
        "routeViewNamed": "Outlet de rota nomeado",
        "outlet": "Direcionar para um outlet nomeado",
        "routeActive": "Classe de link ativo",
        "guard": "Condição de guard de rota",
        "routeActiveExact": "Classe ativa com correspondência exata para links de rota",
        "redirect": "Caminho de redirecionamento quando o guard falha",
        "lazyPriority": "Carregar template remoto antes de todos os outros (Fase 0)",
        "lazyOnDemand": "Buscar template de rota apenas na primeira visita (somente templates de rota)",
        "routerForward": "Navegar para frente no histórico",
        "routerOn": "Inscrever-se em mudanças de rota",
        "routeWildcard": "Rota wildcard catch-all 404",
        "routerCurrent": "Objeto da rota atual",
        "routeMatched": "<code>true</code> se uma rota explícita correspondeu, <code>false</code> para wildcard/fallback",
        "i18nNs": "Auto-derivar namespace i18n do nome do arquivo de rota",
        "routeViewSrc": "Outlet de roteamento baseado em arquivos",
        "routeIndex": "Nome do arquivo para a raiz <code>/</code> (padrão <code>\"index\"</code>)",
        "routeExt": "Extensão de arquivo (padrão <code>\".tpl\"</code>, fallback <code>\".html\"</code>)",
        "transitionVT": "Preset View Transition API no route-view (slide, fade, scale, none)"
      },
      "animation": {
        "title": "Animação",
        "col1": "Diretiva",
        "col2": "Exemplo",
        "col3": "Descrição",
        "animate": "Animação de entrada",
        "animateEnter": "Animação de entrada",
        "animateLeave": "Animação de saída",
        "animateDuration": "Duração em ms",
        "animateStagger": "Atraso escalonado",
        "transition": "Transição CSS (baseada em classes, para elementos regulares)",
        "transitionVT": "Preset View Transition API no route-view (slide, fade, scale, none)"
      },
      "dnd": {
        "title": "Drag and Drop (Agora no NoJS Elements)",
        "col1": "Diretiva",
        "col2": "Exemplo",
        "col3": "Descrição",
        "drag": "Tornar elemento arrastável",
        "dragType": "Identificador de tipo de dados",
        "dragEffect": "Efeito permitido (move/copy/link/all)",
        "dragHandle": "Restringir arraste ao seletor de handle",
        "dragDisabled": "Desabilitar arraste condicionalmente",
        "dragClass": "Classe adicionada durante o arraste",
        "dragGroup": "Escopo do arraste a um grupo nomeado",
        "drop": "Tornar elemento uma zona de soltura",
        "dropAccept": "Tipo(s) de arraste aceitos",
        "dropEffect": "Efeito de feedback visual",
        "dropClass": "Classe adicionada ao passar arrastando",
        "dropDisabled": "Desabilitar soltura condicionalmente",
        "dropMax": "Máximo de itens na zona de soltura",
        "dropSort": "Habilitar ordenação posicional",
        "dropPlaceholder": "Template placeholder durante o arraste",
        "dropSettleClass": "Classe CSS personalizada para a animação de assentamento",
        "dropEmptyClass": "Classe CSS personalizada para o estado vazio em drag-list",
        "dragList": "Lista ordenável vinculada a array de estado",
        "dragListKey": "Chave única para cada item",
        "dragListItem": "Seletor de template do item",
        "dragListCopy": "Copiar ao invés de mover na transferência",
        "dragListRemove": "Remover itens da origem na transferência",
        "dragMultiple": "Laço / seleção múltipla nos filhos",
        "dragMultipleClass": "Classe adicionada aos itens selecionados",
        "dropRejectClass": "Classe adicionada ao rejeitar o arraste"
      },
      "i18n": {
        "title": "i18n",
        "col1": "Diretiva",
        "col2": "Exemplo",
        "col3": "Descrição",
        "t": "Traduzir chave",
        "tStar": "Parâmetro de tradução",
        "tHtml": "Renderizar tradução como HTML sanitizado"
      },
      "misc": {
        "title": "Diversos",
        "col1": "Diretiva",
        "col2": "Exemplo",
        "col3": "Descrição",
        "ref": "Referência nomeada de elemento",
        "call": "Disparar chamada de API",
        "trigger": "Emitir evento customizado",
        "use": "Instanciar template",
        "src": "Template remoto (veja também: lazy)",
        "loading": "Placeholder exibido enquanto o template remoto carrega; removido na chegada",
        "include": "Clonar sincronamente um template inline na posição atual",
        "errorBoundary": "Limite de erro",
        "var": "Nome da variável do template"
      },
      "headManagement": {
        "title": "Head Management",
        "col1": "Diretiva",
        "col2": "Exemplo",
        "col3": "Descrição",
        "pageTitle": "Definir document.title reativamente",
        "pageDescription": "Definir <meta name=\"description\">",
        "pageCanonical": "Definir <link rel=\"canonical\">",
        "pageJsonld": "Definir <script type=\"application/ld+json\">"
      }
    },
    "stateManagement": {
      "hero": {
        "badge": "Guias",
        "title": "Gerenciamento de Estado",
        "subtitle": "Estado local, stores globais, propriedades computadas e watchers"
      },
      "state": {
        "title": "state — Estado Local",
        "text": "Cria um contexto reativo com escopo no elemento e seus filhos.",
        "preview": "Pré-visualização",
        "helloLabel": "Olá,",
        "countLabel": "Contagem:",
        "resetBtn": "Resetar"
      },
      "store": {
        "title": "store — Store Global",
        "text": "Um store reativo global acessível de qualquer lugar. Ideal para estado de autenticação, tema, dados compartilhados."
      },
      "configStores": {
        "title": "Pré-inicialização de Stores via config()",
        "text": "Você pode pré-criar stores com dados iniciais dentro de NoJS.config(). Cada chave no objeto stores se torna um store global nomeado, acessível imediatamente via $store.nome.",
        "callout": "Se um store já existe (ex: criado via atributo store), config() não o sobrescreverá — o store existente é preservado."
      },
      "into": {
        "title": "into — Escrever Resultados de Fetch em um Store",
        "text": "O atributo into em qualquer diretiva HTTP escreve a resposta diretamente em um store global nomeado.",
        "callout": "O store não precisa ser pré-definido — into irá criá-lo se não existir."
      },
      "computed": {
        "title": "computed — Estado Derivado",
        "text": "Valores que são automaticamente recalculados quando as dependências mudam.",
        "preview": "Pré-visualização",
        "priceLabel": "Preço:",
        "qtyLabel": "Qtd:",
        "subtotalLabel": "Subtotal:",
        "totalLabel": "Total:"
      },
      "watch": {
        "title": "watch — Efeitos Colaterais",
        "text": "Executa uma ação sempre que um valor muda."
      },
      "persistence": {
        "title": "Persistência de Estado",
        "text": "Persista o estado entre recarregamentos de página usando localStorage ou sessionStorage."
      },
      "notify": {
        "title": "NoJS.notify() — Atualizar Store",
        "text": "Quando JavaScript externo muta uma store via NoJS.store, chame NoJS.notify() para atualizar todos os bindings do DOM.",
        "callout": "Só é necessário ao mutar NoJS.store a partir de JavaScript puro — fora de expressões HTML. Mutações dentro de on:click ou bind são tratadas automaticamente."
      },
      "persistSchema": {
        "title": "persist-schema — Validação de Schema",
        "text": "Ao restaurar estado persistido, persist-schema valida que as chaves restauradas correspondem ao formato do estado inicial. Chaves não presentes no estado inicial são descartadas. Isso previne dados obsoletos ou corrompidos de quebrar seu app após mudanças no schema."
      },
      "scoping": {
        "title": "Escopo de Contexto & Shadowing",
        "text": "Contextos herdam de elementos pai como escopo léxico. Um state filho pode sobrescrever uma propriedade do pai — o filho vê seu próprio valor, enquanto irmãos veem o valor do pai.",
        "callout": "O shadowing é intencional e segue as regras de escopo do JavaScript. Se você precisa de estado compartilhado entre irmãos, use um store."
      }
    },
    "dataBinding": {
      "hero": {
        "badge": "Guias",
        "title": "Vinculação de Dados",
        "subtitle": "Data binding unidirecional e bidirecional com bind e model"
      },
      "bind": {
        "title": "bind — Conteúdo de Texto",
        "text": "Substitui o textContent do elemento pela expressão avaliada."
      },
      "bindHtml": {
        "title": "bind-html — HTML Interno",
        "text": "Renderiza a expressão avaliada como HTML. Sanitizado por padrão.",
        "callout": "⚠️ Usa sanitização estrutural integrada baseada em DOMParser: remove tags <script>, bloqueia handlers de evento on* e remove URIs javascript:."
      },
      "bindAttr": {
        "title": "bind-* — Vinculação de Atributos",
        "text": "Vincule qualquer atributo HTML dinamicamente."
      },
      "model": {
        "title": "model — Binding Bidirecional",
        "text": "Para inputs de formulário, model cria data binding bidirecional automático.",
        "preview": "Pré-visualização",
        "nameLabel": "Nome",
        "placeholder": "Digite seu nome...",
        "checkbox": "Eu concordo",
        "agreedLabel": "Concordou:",
        "helloPrefix": "Olá,"
      },
      "radioSelect": {
        "title": "Radio Buttons & Multi-Select",
        "text": "model funciona com todos os tipos de input. Para radio buttons, vincule o mesmo nome de model a um grupo — o valor atualiza para o value do radio selecionado. Para multi-select, o valor do model se torna um array das opções selecionadas."
      },
      "commonMistakes": {
        "title": "Erros Comuns",
        "text": "Evite estas armadilhas comuns de data binding:",
        "mistake1": "Usar bind-html sem entender a sanitização — todo conteúdo é sanitizado por padrão, mas esteja ciente do que é removido.",
        "mistake2": "Esquecer que bind substitui textContent — quaisquer elementos filhos dentro de um alvo bind são removidos.",
        "mistake3": "Usar model em elementos não-formulário — model só funciona em input, textarea e select."
      }
    },
    "events": {
      "hero": {
        "badge": "Guias",
        "title": "Tratamento de Eventos",
        "subtitle": "Vincule eventos DOM diretamente no HTML com a sintaxe on:event"
      },
      "handlers": {
        "title": "on:* — Handlers de Eventos",
        "text": "Vincule qualquer evento DOM diretamente no HTML. Acesse variáveis de estado e contexto diretamente na expressão do handler.",
        "preview": "Pré-visualização",
        "inputPlaceholder": "Digite algo...",
        "youTyped": "Você digitou:",
        "countLabel": "Contagem:"
      },
      "modifiers": {
        "title": "Modificadores de Eventos",
        "text": "Modificadores permitem controlar o comportamento do evento diretamente no atributo:"
      },
      "eventAndEl": {
        "title": "$event & $el",
        "text": "$event é o evento DOM nativo. $el se refere ao elemento atual."
      },
      "lifecycle": {
        "title": "Hooks de Ciclo de Vida",
        "col1": "Hook",
        "col2": "Quando",
        "onInit": "Diretiva processada pela primeira vez",
        "onMounted": "Elemento inserido no DOM visível",
        "onUpdated": "Mutação no DOM observada (via MutationObserver)",
        "onUnmounted": "Elemento removido do DOM",
        "onError": "Erro na subárvore deste elemento"
      },
      "keyModifiers": {
        "title": "Modificadores de Tecla",
        "text": "Use modificadores de tecla em eventos de teclado para filtrar por teclas específicas. Combine com Ctrl, Alt, Shift ou Meta para atalhos.",
        "col1": "Modificador",
        "col2": "Tecla",
        "enter": "Enter / Return",
        "escape": "Escape",
        "space": "Espaço",
        "tab": "Tab",
        "backspace": "Backspace",
        "arrowUp": "Seta para Cima",
        "arrowDown": "Seta para Baixo",
        "arrowLeft": "Seta para Esquerda",
        "arrowRight": "Seta para Direita",
        "ctrl": "Ctrl (Control)",
        "alt": "Alt (Option no Mac)",
        "shift": "Shift",
        "meta": "Meta (Cmd no Mac, Win no Windows)",
        "delete": "Delete"
      }
    },
    "conditionals": {
      "hero": {
        "badge": "Guias",
        "title": "Condicionais",
        "subtitle": "Controle a renderização com if, show, hide e switch"
      },
      "ifThenElse": {
        "title": "if / then / else",
        "text": "Renderize elementos ou templates condicionalmente com base em expressões.",
        "preview": "Pré-visualização",
        "checkbox": "Logado",
        "welcome": "✅ Bem-vindo de volta!",
        "login": "Por favor, faça login."
      },
      "elseIf": {
        "title": "else-if — Condicionais Encadeadas"
      },
      "showHide": {
        "title": "show / hide",
        "text": "Alterna display: none sem adicionar/remover elementos do DOM. Melhor para elementos alternados com frequência.",
        "comparisonTitle": "if vs show",
        "colIf": "if",
        "colShow": "show",
        "mechanism": "Mecanismo",
        "mechanismIf": "Adiciona/remove elementos do DOM",
        "mechanismShow": "Alterna CSS display",
        "bestFor": "Melhor para",
        "bestForIf": "Conteúdo raramente alternado",
        "bestForShow": "Conteúdo frequentemente alternado",
        "preservesState": "Preserva estado",
        "preservesIf": "Não (recria)",
        "preservesShow": "Sim"
      },
      "switchCase": {
        "title": "switch / case",
        "text": "Renderize um dentre vários templates com base em um valor.",
        "inlineSubtitle": "Conteúdo Inline (sem templates)",
        "multiValueSubtitle": "Case com Múltiplos Valores"
      }
    },
    "loops": {
      "hero": {
        "badge": "Guias",
        "title": "Diretivas de Iteração",
        "subtitle": "Itere sobre arrays com foreach, each e for"
      },
      "foreach": {
        "title": "foreach — Iterar Sobre Arrays",
        "text": "A diretiva de iteração primária. Use foreach=\"item in array\" para iterar sobre arrays. each e for são aliases com comportamento idêntico.",
        "col1": "Atributo",
        "col2": "Descrição",
        "foreach": "Expressão: item in array",
        "from": "Array de origem (DEPRECATED — use a sintaxe item in array)",
        "index": "Nome da variável para o índice (padrão: $index)",
        "key": "Expressão de chave única para identificação e rastreamento de elementos",
        "else": "ID do template para renderizar quando o array está vazio",
        "filter": "Expressão para filtrar itens",
        "sort": "Caminho da propriedade para ordenar (prefixo - para descendente)",
        "limit": "Número máximo de itens para renderizar",
        "offset": "Número de itens para pular",
        "preview": "Prévia",
        "template": "ID de template externo (opcional — os filhos se tornam o template se omitido)"
      },
      "fullExample": {
        "title": "Exemplo completo com todos os atributos",
        "text": "Um exemplo completo mostrando foreach com filtragem, ordenação, paginação e um fallback para estado vazio."
      },
      "aliases": {
        "title": "Aliases: each e for",
        "text": "each e for são aliases de foreach — compartilham o mesmo handler e suportam todos os mesmos atributos."
      },
      "inline": {
        "title": "Template Inline de Filhos",
        "text": "Quando nenhum atributo template é especificado, os filhos do elemento se tornam o template de repetição."
      },
      "deprecated": {
        "title": "Deprecated: Atributo from",
        "text": "O atributo from ainda funciona mas está deprecated. Use a sintaxe \"item in array\" em vez disso. Usar from emitirá um aviso no console."
      },
      "contextVars": {
        "title": "Variáveis de Contexto do Loop",
        "col1": "Variável",
        "col2": "Descrição",
        "index": "Índice atual (base 0)",
        "count": "Número total de itens",
        "first": "true se for o primeiro item",
        "last": "true se for o último item",
        "even": "true se o índice for par",
        "odd": "true se o índice for ímpar"
      },
      "nested": {
        "title": "Loops Aninhados",
        "text": "Loops filhos (foreach, each ou for) podem acessar variáveis do escopo pai."
      },
      "reactivity": {
        "title": "Reatividade",
        "text": "Diretivas de loop são totalmente reativas. Quando o array de origem muda (itens adicionados, removidos ou reordenados), o DOM atualiza automaticamente. Use o atributo key para diffing eficiente — sem ele, a lista inteira re-renderiza a cada mudança."
      },
      "objectIteration": {
        "title": "Iteração de Objetos",
        "text": "Para iterar sobre as entradas de um objeto, use o filtro keys ou values para converter em array primeiro.",
        "callout": "Iteração direta de objetos não é suportada — sempre converta para array com keys, values ou Object.entries() em uma expressão computed."
      }
    },
    "templates": {
      "hero": {
        "badge": "Guias",
        "title": "Templates",
        "subtitle": "Fragmentos HTML reutilizáveis com variáveis, slots e carregamento remoto"
      },
      "basic": {
        "title": "Template Básico",
        "text": "Templates são fragmentos HTML reutilizáveis que nunca são renderizados diretamente. Eles são clonados quando referenciados por diretivas como then, else, template, loading, error, etc."
      },
      "var": {
        "title": "Variáveis de Template (var)",
        "text": "Templates podem declarar qual variável esperam do contexto de chamada."
      },
      "slots": {
        "title": "Slots de Template",
        "text": "Permitem que templates aceitem conteúdo projetado."
      },
      "remote": {
        "title": "Templates Remotos (src)",
        "text": "Carregue templates de arquivos HTML externos."
      },
      "recursive": {
        "subtitle": "Carregamento Recursivo",
        "text": "Templates remotos são carregados recursivamente — se um template remoto contém elementos <template src=\"...\"> dentro dele, esses são resolvidos automaticamente também:"
      },
      "remoteRoutes": {
        "subtitle": "Templates Remotos em Rotas",
        "text": "Templates remotos dentro de conteúdo de rota também são resolvidos automaticamente antes da rota renderizar. Veja Roteamento para detalhes."
      },
      "lazy": {
        "title": "Carregamento Lazy (lazy)",
        "text": "Controle quando templates remotos são buscados usando o atributo lazy em elementos <template src=\"...\">. O NoJS carrega templates em fases para otimizar o time-to-first-render.",
        "col1": "Valor",
        "col2": "Comportamento",
        "absent": "(ausente)",
        "absentDesc": "Auto-priorização padrão: templates de content-include e o template da rota atual carregam antes do primeiro render; outros templates de rota são pré-carregados em background após o primeiro render.",
        "priorityDesc": "Forçar carregamento antes de tudo — até antes dos content includes regulares. Útil para templates de layout compartilhados críticos.",
        "ondemandDesc": "Válido apenas em templates de rota. Nunca pré-carregado — buscado de forma lazy na primeira vez que o usuário navega para essa rota. Ideal para páginas pesadas ou raramente visitadas."
      },
      "phases": {
        "subtitle": "Fases de Carregamento",
        "text": "Templates são resolvidos em quatro fases ordenadas: Fase 0 busca templates lazy=\"priority\" primeiro; Fase 1 busca todos os outros templates não-rota mais o template da rota ativa (bloqueando antes do primeiro render); Fase 2 pré-carrega os templates de rota restantes em background após o primeiro render; e sob demanda busca templates lazy=\"ondemand\" de rota apenas quando o usuário navega pela primeira vez."
      },
      "loading": {
        "title": "Placeholder de Carregamento (loading)",
        "text1": "Exiba um template de placeholder enquanto um template remoto está sendo buscado. O placeholder é inserido de forma síncrona — antes de qualquer requisição de rede — e removido automaticamente quando o conteúdo real chega. Funciona tanto para content-includes estáticos quanto para templates aninhados dentro de páginas de rota.",
        "text2": "Tanto IDs simples quanto sintaxe #id são aceitos. O template de placeholder é clonado cada vez, então pode ser reutilizado em múltiplos templates remotos:"
      },
      "include": {
        "title": "Include de Template Inline (include)",
        "text1": "Clone um template inline na posição atual de forma síncrona, antes de qualquer fetch. Útil para injetar markup reutilizável (ex: conjuntos de ícones, fragmentos comuns) sem fazer uma requisição de rede.",
        "text2": "include e loading servem propósitos diferentes: include clona conteúdo inline permanentemente; loading insere um placeholder temporário que desaparece quando um template remoto termina de carregar."
      }
    },
    "dataFetching": {
      "hero": {
        "badge": "Guias",
        "title": "Busca de Dados",
        "subtitle": "Requisições HTTP declarativas — basta adicionar atributos aos elementos HTML"
      },
      "baseUrl": {
        "title": "URL Base",
        "text1": "Defina uma vez em qualquer elemento ancestral. Todos os get, post, etc. descendentes resolvem URLs relativas contra ele.",
        "text2": "Sobrescreva para seções específicas:",
        "text3": "URLs absolutas ignoram a resolução de base:"
      },
      "config": {
        "title": "Configuração Programática"
      },
      "headers": {
        "title": "Headers por Requisição"
      },
      "get": {
        "title": "get — Buscar e Renderizar Dados",
        "attributesTitle": "Atributos",
        "col1": "Atributo",
        "col2": "Tipo",
        "col3": "Descrição",
        "get": "URL para buscar (requisição GET)",
        "as": "Nome para atribuir à resposta no contexto. Padrão: \"data\"",
        "loading": "ID do template para exibir durante o carregamento (ex: \"#skeleton\")",
        "error": "ID do template para exibir em caso de erro no fetch",
        "empty": "ID do template para exibir quando a resposta é array vazio/null",
        "refresh": "Intervalo de atualização automática em ms (polling)",
        "cached": "Cachear respostas. cached = memory, cached=\"local\" = localStorage, cached=\"session\" = sessionStorage",
        "into": "Escrever resposta em um store global nomeado",
        "debounce": "Debounce em ms (útil com URLs reativas)",
        "headers": "String JSON de headers adicionais",
        "params": "Expressão que resolve para um objeto de parâmetros de query"
      },
      "fullExample": {
        "title": "Exemplo Completo"
      },
      "reactiveUrls": {
        "title": "URLs Reativas",
        "text": "URLs que referenciam variáveis de estado re-buscam automaticamente quando esses valores mudam."
      },
      "mutations": {
        "title": "post, put, patch, delete — Requisições de Mutação",
        "text": "Usadas em formulários ou acionadas via call.",
        "formSubmissionTitle": "Envio de Formulário",
        "putPatchDeleteTitle": "PUT / PATCH / DELETE"
      },
      "mutationAttrs": {
        "title": "Atributos de Mutação",
        "col1": "Atributo",
        "col2": "Descrição",
        "method": "URL para a requisição",
        "body": "Corpo da requisição (string JSON com interpolação). Para formulários, serializa campos automaticamente",
        "success": "ID do template para renderizar em caso de sucesso. Recebe a resposta como var",
        "error": "ID do template para renderizar em caso de erro. Recebe o erro como var",
        "loading": "ID do template para exibir durante a requisição",
        "confirm": "Exibir diálogo confirm() do navegador antes de enviar",
        "redirect": "URL para navegar em caso de sucesso (rota SPA)",
        "then": "Expressão para executar em caso de sucesso (ex: \"users.push(result)\")",
        "into": "Escrever resposta em um store global nomeado",
        "cached": "Cachear respostas (memory/local/session). Nota: cache só se aplica a requisições GET."
      },
      "lifecycle": {
        "title": "Ciclo de Vida da Requisição"
      },
      "liveDemo": {
        "title": "Demo ao Vivo — Fetch de API",
        "label": "Resultado"
      }
    },
    "routing": {
      "hero": {
        "badge": "Guias",
        "title": "Roteamento",
        "subtitle": "Navegação SPA client-side completa sem recarregamento de página"
      },
      "definition": {
        "title": "Definição de Rota"
      },
      "params": {
        "title": "Parâmetros de Rota & Query"
      },
      "context": {
        "title": "$route — Contexto da Rota",
        "col1": "Propriedade",
        "col2": "Descrição",
        "path": "Caminho atual (ex: \"/users/42\")",
        "params": "Parâmetros da rota (ex: { id: \"42\" })",
        "query": "Parâmetros de query string (ex: { q: \"hello\" })",
        "hash": "Hash da URL (ex: \"#section\")",
        "matched": "Se uma rota explícita correspondeu (true) ou se um wildcard/fallback está sendo renderizado (false)"
      },
      "activeStyle": {
        "title": "Estilização de Rota Ativa"
      },
      "guards": {
        "title": "Guards de Rota"
      },
      "programmatic": {
        "title": "Navegação Programática",
        "callout": "$router.push() e $router.replace() retornam Promises — a navegação (incluindo carregamento de template remoto) é totalmente assíncrona. Em handlers on:click o valor de retorno é ignorado, mas em scripts você pode usar await:"
      },
      "nested": {
        "title": "Rotas Aninhadas"
      },
      "remoteTemplates": {
        "title": "Templates Remotos em Rotas",
        "text1": "Templates de rota podem incluir <template src=\"...\"> para carregar conteúdo de arquivos externos. Eles são resolvidos automaticamente antes da rota renderizar:",
        "text2": "Templates remotos aninhados (um template remoto que contém mais <template src>) são carregados recursivamente."
      },
      "fileBased": {
        "title": "Roteamento Baseado em Arquivos",
        "text": "Em vez de declarar cada template de rota manualmente, aponte sua saída <code>route-view</code> para uma pasta. O No.JS resolverá automaticamente os caminhos de rota para arquivos de template dentro dessa pasta.",
        "howItWorks": "Como funciona",
        "list1": "Adicione <code>route-view</code> ao seu elemento de saída — o roteamento baseado em arquivos está habilitado por padrão (config <code>router.templates: \"pages\"</code>). Sobrescreva por saída com <code>src=\"folder/\"</code>.",
        "list2": "Quando um usuário navega para <code>/analytics</code>, o No.JS resolve para <code>pages/analytics.tpl</code>",
        "list3": "O template é buscado, armazenado em cache e renderizado — automaticamente",
        "attributesTitle": "Atributos",
        "colAttr": "Atributo",
        "colDefault": "Padrão",
        "colDesc": "Descrição",
        "srcDesc": "Pasta base para resolução de templates (sobrescrita por saída; config: <code>router.templates</code>)",
        "routeIndexDesc": "Nome do arquivo para a rota raiz <code>/</code>",
        "extDesc": "Extensão de arquivo adicionada aos segmentos de rota (fallback: <code>\".html\"</code>)",
        "i18nNsDesc": "Quando presente, auto-deriva o namespace i18n do nome do arquivo",
        "callout": "<strong>Config padrão:</strong> O valor padrão de <code>router.templates</code> é <code>\"pages\"</code>, então o roteamento baseado em arquivos funciona imediatamente — basta adicionar <code>route-view</code> à sua saída. Sobrescreva com <code>NoJS.config({ router: { templates: 'views' } })</code> ou por saída via <code>src=\"./custom/\"</code>.",
        "exampleTitle": "Exemplo — Dashboard SaaS",
        "exampleText": "É isso — <strong>duas linhas</strong> para uma SPA completa com seis rotas.",
        "mixingTitle": "Misturando Rotas Explícitas e Baseadas em Arquivos",
        "mixingText": "Declarações explícitas <code>&lt;template route=\"...\"&gt;</code> <strong>sempre têm prioridade</strong>. Isso permite combinar ambas as abordagens — use roteamento baseado em arquivos para páginas simples e templates explícitos para rotas que precisam de guards, parâmetros ou saídas nomeadas:",
        "autoI18nTitle": "Namespace i18n Automático",
        "autoI18nText": "Quando o elemento <code>route-view</code> tem um atributo <code>i18n-ns</code> (mesmo sem valor), o No.JS carrega automaticamente o namespace i18n correspondente ao nome do arquivo:",
        "autoI18nText2": "Isso substitui a necessidade de adicionar <code>i18n-ns=\"...\"</code> em cada template de rota individualmente."
      },
      "lazyLoading": {
        "title": "Carregamento Lazy de Templates",
        "text": "O atributo lazy em <template src=\"...\"> controla quando um template remoto é buscado em relação ao primeiro render. Use-o para priorizar templates críticos e adiar páginas pesadas ou raramente visitadas.",
        "col1": "Valor",
        "col2": "Fase",
        "col3": "Comportamento",
        "absent": "(ausente)",
        "absentPhase": "1 ou 2",
        "absentDesc": "Auto: templates não-rota e o template da rota ativa carregam antes do primeiro render (Fase 1); outros templates de rota pré-carregam em background após o primeiro render (Fase 2).",
        "priorityPhase": "0",
        "priorityDesc": "Carregar antes de tudo — até antes dos content includes regulares. Use para templates de layout compartilhados críticos.",
        "ondemandPhase": "sob demanda",
        "ondemandDesc": "Válido apenas em templates de rota. Nunca pré-carregado — buscado na primeira vez que o usuário navega para essa rota. Ideal para páginas pesadas ou raramente visitadas."
      },
      "anchor": {
        "title": "Links Âncora",
        "text1": "Ao usar useHash: true, o hash da URL (#) é usado para roteamento (ex: #/docs). Normalmente isso conflita com links âncora padrão como <a href=\"#section\"> — mas o No.JS lida com isso automaticamente em ambos os modos (hash e history).",
        "text2": "Links âncora que apontam para um id de elemento na página são interceptados pelo router: o elemento alvo é rolado até ficar visível suavemente, e o link clicado recebe uma classe active. A rota em si não é afetada.",
        "howItWorks": "Como funciona:",
        "list1": "Clicar em <a href=\"#introduction\"> rola até <div id=\"introduction\"> com comportamento suave",
        "list2": "A classe .active é alternada no link clicado (e removida dos irmãos)",
        "list3": "O caminho da rota atual é preservado — nenhuma navegação ocorre",
        "list4": "Links com atributo route são sempre tratados como navegação de rota, não como âncoras",
        "tip": "Dica: Estilize o link âncora ativo com .active no seu CSS — o router gerencia a classe para você."
      },
      "namedOutlets": {
        "title": "Outlets Nomeados (route-view)",
        "text": "Múltiplos outlets route-view podem coexistir na mesma página. Dê a cada outlet um nome via o valor do atributo e aponte templates de rota para outlets específicos usando o atributo outlet.",
        "callout": "Outlets sem template correspondente para a rota atual são sempre limpos na navegação."
      },
      "catchAll": {
        "title": "404 / Rotas Catch-All",
        "text": "Use <code>route=\"*\"</code> para definir um template <strong>wildcard catch-all</strong> que renderiza quando nenhuma rota explícita corresponde ao caminho atual. O wildcard é sempre avaliado por último, independentemente da ordem no DOM.",
        "text2": "Rotas explícitas <strong>sempre têm prioridade</strong> — o wildcard só é acionado quando <code>matchRoute()</code> não retorna correspondência.",
        "fallbackTitle": "Fallback 404 Automático",
        "fallbackText": "Se você não definir um template <code>route=\"*\"</code>, o No.JS exibe automaticamente uma página 404 mínima integrada quando nenhuma rota corresponde. Isso garante que os usuários sempre vejam algo significativo em vez de um outlet vazio.",
        "fallbackTip": "O fallback integrado é intencionalmente mínimo e sem estilos. Defina seu próprio template <code>route=\"*\"</code> para aplicações em produção.",
        "namedTitle": "Wildcards em Outlets Nomeados",
        "namedText": "Cada outlet nomeado pode ter seu próprio fallback wildcard. Quando nenhuma rota corresponde para um outlet, o framework resolve os fallbacks nesta ordem:",
        "namedList1": "<strong>Wildcard local</strong> — <code>&lt;template route=\"*\" outlet=\"{name}\"&gt;</code> para aquele outlet específico",
        "namedList2": "<strong>Wildcard global</strong> — <code>&lt;template route=\"*\"&gt;</code> (o wildcard do outlet padrão), usado apenas para outlets não padrão",
        "namedList3": "<strong>404 integrado</strong> — a página de fallback mínima do framework",
        "namedText2": "Se a barra lateral não tem wildcard local, recorre ao <code>route=\"*\"</code> global. Se nenhum existir, o 404 integrado é usado.",
        "matchedTitle": "$route.matched",
        "matchedText": "O booleano <code>$route.matched</code> indica se o caminho atual encontrou uma rota explícita (<code>true</code>) ou um wildcard/fallback (<code>false</code>). Use-o para renderização condicional dentro dos seus templates:",
        "matchedText2": "<code>$route.matched</code> é definido <strong>antes</strong> do template renderizar, então está sempre disponível durante o processamento.",
        "remoteTitle": "Template 404 Remoto",
        "remoteText": "Rotas wildcard suportam todos os mesmos atributos que templates de rota regulares, incluindo <code>src</code> para carregamento remoto:",
        "remoteText2": "O template remoto é buscado, armazenado em cache e renderizado como qualquer outro template de rota — e tem acesso completo a <code>$route.path</code>, <code>$route.matched</code> e todas as outras funcionalidades do framework.",
        "fileBasedTitle": "404 no Roteamento Baseado em Arquivos",
        "fileBasedText": "Ao usar roteamento baseado em arquivos, navegar para um caminho cujo arquivo <code>.tpl</code> não existe no servidor (HTTP 404 ou outro erro) aciona automaticamente a cadeia de fallback wildcard.",
        "fileBasedText2": "A resposta HTTP com falha <strong>não</strong> é armazenada em cache — navegações subsequentes para outros caminhos não são afetadas."
      },
      "headAttributes": {
        "title": "Atributos Head em Rotas",
        "text": "Templates de rota podem declarar <code>page-title</code> e <code>page-description</code> diretamente na tag <code>&lt;template&gt;</code>. Quando a rota é ativada, as tags <code>&lt;head&gt;</code> correspondentes são atualizadas automaticamente.",
        "text2": "Strings estáticas e expressões dinâmicas são suportadas:",
        "colAttr": "Atributo",
        "colDesc": "Descrição",
        "pageTitleDesc": "Define <code>document.title</code> quando a rota está ativa",
        "pageDescriptionDesc": "Define o conteúdo de <code>&lt;meta name=\"description\"&gt;</code> quando a rota está ativa",
        "callout": "Para gerenciamento completo do head (URLs canônicas, JSON-LD, Open Graph), veja o guia de <a href=\"/docs/head-management\">Head Management</a>."
      },
      "focusBehavior": {
        "title": "Acessibilidade — Gerenciamento de Foco",
        "text": "Após cada navegação, o No.JS move o foco para um elemento previsível dentro do conteúdo da nova rota. Isso garante que leitores de tela anunciem a mudança de página e usuários de teclado cheguem a um ponto útil.",
        "text2": "Quando focusBehavior é 'auto' (o padrão), o framework percorre uma lista de prioridade:",
        "priority1": "<code>[autofocus]</code> — um elemento com o atributo <code>autofocus</code> dentro do template de rota",
        "priority2": "<code>h1</code> — o primeiro <code>&lt;h1&gt;</code> dentro do conteúdo da rota",
        "priority3": "<code>[tabindex=\"-1\"]</code> — um container focável manualmente",
        "priority4": "O próprio elemento route-view (último recurso)",
        "defaultTitle": "Comportamento Padrão",
        "defaultText": "O gerenciamento de foco está <strong>habilitado por padrão</strong> — você não precisa configurar nada. A estratégia <code>'auto'</code> funciona imediatamente.",
        "timingTitle": "Timing",
        "timingText": "O foco é movido <strong>após</strong> o template de rota estar completamente renderizado e todos os templates remotos dentro dele estarem resolvidos. Isso garante que o elemento alvo exista no DOM.",
        "sideEffectsTitle": "Efeitos Colaterais",
        "sideEffectsText": "O elemento focado recebe <code>tabindex=\"-1\"</code> se ainda não tiver um tabindex, e a página rola para trazê-lo à vista via <code>scrollIntoView({ block: 'nearest' })</code>.",
        "futureTitle": "Valores Futuros",
        "futureText": "Atualmente apenas <code>'auto'</code> é suportado. Versões futuras podem adicionar <code>'none'</code> (desativar) e <code>'target'</code> (focar um seletor específico).",
        "ariaLiveTitle": "Região ARIA Live",
        "ariaLiveText": "Para leitores de tela que não respondem a mudanças de foco, adicione <code>aria-live=\"polite\"</code> ao seu <code>route-view</code>. O browser anunciará o novo conteúdo quando aparecer:"
      },
      "viewTransitions": {
        "title": "View Transitions",
        "text": "O atributo <code>transition</code> no <code>route-view</code> agora usa a <strong>View Transition API</strong> por padrão. Basta escolher um nome de preset e as mudanças de rota são animadas nativamente pelo browser — sem CSS manual.",
        "presetsTitle": "Presets Integrados",
        "presetsText": "O No.JS inclui quatro presets de transição integrados:",
        "colPreset": "Preset",
        "colEffect": "Efeito",
        "presetSlide": "Slide direcional — o conteúdo desliza para esquerda/direita baseado na direção de navegação (forward/backward)",
        "presetFade": "Crossfade — o conteúdo antigo desaparece enquanto o novo aparece",
        "presetScale": "Scale zoom — o conteúdo antigo reduz enquanto o novo amplia",
        "presetNone": "Troca instantânea — sem animação, o conteúdo é substituído imediatamente",
        "configTitle": "Configuração",
        "configText": "A View Transition API está <strong>habilitada por padrão</strong> via <code>router.viewTransition: true</code>. Defina como <code>false</code> para voltar ao sistema legado de transições baseado em classes CSS.",
        "customCssTitle": "CSS Personalizado",
        "customCssText": "Para animações personalizadas, utilize os pseudo-elementos <code>::view-transition-old(route-content)</code> e <code>::view-transition-new(route-content)</code>. O <code>view-transition-name: route-content</code> é definido automaticamente em qualquer outlet com atributo <code>transition</code>.",
        "howItWorksTitle": "Como Funciona",
        "howItWorksText": "Quando ocorre uma mudança de rota com um preset <code>transition</code>:",
        "howStep1": "O router detecta a direção de navegação (<strong>forward</strong> ou <strong>backward</strong>) a partir da pilha de histórico",
        "howStep2": "<code>document.startViewTransition()</code> é chamado, capturando o estado atual do outlet",
        "howStep3": "O novo conteúdo da rota é renderizado dentro do outlet",
        "howStep4": "O browser anima entre os snapshots antigo e novo usando as regras CSS do preset",
        "deprecationTitle": "Migração das Transições Baseadas em Classes",
        "deprecationText": "O sistema antigo de transição baseado em classes (<code>*-enter</code>, <code>*-enter-active</code>, <code>*-leave</code>, etc.) no <code>route-view</code> está <strong>deprecated</strong>. Ainda funciona quando <code>router.viewTransition</code> está definido como <code>false</code>, mas a View Transition API é a abordagem recomendada.",
        "deprecationCallout": "<strong>A migração é praticamente automática.</strong> Se você já usa <code>transition=\"fade\"</code> em um <code>route-view</code>, agora usa a View Transition API por padrão — nenhuma alteração de código necessária. Seu CSS customizado <code>.fade-enter</code> / <code>.fade-leave</code> é simplesmente ignorado (a menos que defina <code>viewTransition: false</code>)."
      }
    },
    "formsValidation": {
      "hero": {
        "badge": "Guias",
        "title": "Formulários & Validação",
        "subtitle": "Envio declarativo de formulários com regras de validação integradas e personalizadas"
      },
      "submission": {
        "title": "Envio Declarativo de Formulário"
      },
      "rules": {
        "title": "Regras de Validação"
      },
      "perRuleErrors": {
        "title": "Mensagens de Erro por Regra",
        "text": "Use atributos error-{regra} para definir uma mensagem personalizada para uma regra específica, ou error como fallback genérico."
      },
      "errorTemplates": {
        "title": "Templates de Erro",
        "text": "Aponte um atributo error para um <template> usando o prefixo # para renderizar UI de erro rica. Dentro do template, $error contém a mensagem e $rule o nome da regra que falhou."
      },
      "errorClass": {
        "title": "Classe CSS de Erro",
        "text": "Use error-class no formulário ou em campos individuais para alternar uma classe CSS quando um campo é inválido e tocado."
      },
      "formContext": {
        "title": "$form — Contexto do Formulário",
        "text": "Dentro de qualquer <form> com o atributo validate, $form fornece:",
        "col1": "Propriedade",
        "col2": "Tipo",
        "col3": "Descrição",
        "valid": "true se todos os campos passam na validação",
        "dirty": "true se algum campo foi modificado",
        "touched": "true se algum campo recebeu foco e perdeu foco",
        "submitting": "true enquanto a requisição está em andamento",
        "pending": "true enquanto validadores assíncronos estão em execução",
        "errors": "Mapa de nomes de campo → mensagens de erro",
        "values": "Valores atuais do formulário",
        "firstError": "Mensagem de erro do primeiro campo inválido (ordem do DOM)",
        "errorCount": "Número de campos que estão falhando na validação",
        "fields": "Objeto de estado por campo (valid, error, dirty, touched)",
        "reset": "Resetar formulário para valores iniciais, limpar erros e classes"
      },
      "formFields": {
        "title": "$form.fields — Estado por Campo",
        "text": "$form.fields expõe o estado individual de cada campo indexado pelo nome.",
        "asTitle": "Aliases de Campo com as",
        "asText": "Use o atributo as para expor o estado de um campo sob um nome personalizado no contexto."
      },
      "validateOn": {
        "title": "Gatilhos de Validação (validate-on)",
        "text": "Por padrão, a validação executa em input e focusout. Use validate-on para controlar quando o feedback visual aparece.",
        "note": "Internamente, os dados do $form são sempre mantidos atualizados independente do validate-on. O gatilho controla apenas quando o feedback visual é exibido."
      },
      "validateIf": {
        "title": "Validação Condicional (validate-if)",
        "text": "Pule a validação de um campo com base em uma condição. Quando validate-if avalia para false, o campo é tratado como válido."
      },
      "autoDisable": {
        "title": "Desabilitar Botões de Envio Automaticamente",
        "text": "Botões de envio são automaticamente desabilitados quando o formulário é inválido. Botões com type=\"button\" não são afetados."
      },
      "customValidators": {
        "title": "Validadores Personalizados"
      },
      "liveDemo": {
        "title": "Demo ao Vivo — Formulário de Registro",
        "label": "Resultado",
        "usernameLabel": "Usuário",
        "usernamePlaceholder": "Escolha um nome de usuário",
        "emailLabel": "Email",
        "emailPlaceholder": "voce@exemplo.com",
        "ageLabel": "Idade",
        "agePlaceholder": "Sua idade",
        "roleLabel": "Função",
        "roleDefault": "Selecione uma função",
        "roleDev": "Desenvolvedor",
        "roleDesign": "Designer",
        "roleMgr": "Gerente",
        "termsLabel": "Concordo com os termos",
        "registerButton": "Registrar",
        "successMessage": "Registro concluído! Bem-vindo."
      }
    },
    "styling": {
      "hero": {
        "badge": "Guias",
        "title": "Estilização Dinâmica",
        "subtitle": "Alterne classes CSS e estilos inline reativamente"
      },
      "classToggle": {
        "title": "class-* — Alternar Classes",
        "text": "Adicione ou remova classes CSS reativamente com base em expressões. Use class-{name} para toggles individuais ou class-map para múltiplas classes.",
        "multiObject": "Múltiplas Classes a partir de Objeto",
        "multiObjectText": "Use class-map com uma expressão de objeto para alternar múltiplas classes. As chaves são nomes de classes, os valores são expressões booleanas.",
        "fromArray": "A partir de Array"
      },
      "inlineStyles": {
        "title": "style-* — Estilos Inline",
        "text": "Defina propriedades CSS inline reativamente usando atributos style-{property}. Os nomes de propriedades usam kebab-case (ex: style-font-size, style-background-color).",
        "fromObject": "A partir de Objeto",
        "fromObjectText": "Use style-map com uma expressão de objeto para definir múltiplos estilos inline de uma vez."
      },
      "liveDemo": {
        "title": "Demo ao Vivo — Estilização Dinâmica",
        "label": "Resultado",
        "toggleButton": "Alternar Ativo"
      },
      "classStatic": {
        "title": "Interação com class Estática",
        "text": "Diretivas class-* funcionam junto com atributos class estáticos. No.JS apenas alterna as classes gerenciadas pela diretiva — classes estáticas nunca são removidas.",
        "callout": "Você pode combinar class=\"card\" com class-active=\"isActive\" com segurança. A classe card está sempre presente; active é alternada."
      },
      "cssCustomProperties": {
        "title": "CSS Custom Properties",
        "text": "Use style-* com CSS custom properties (variáveis) para estilização reativa com temas. Nomes de propriedades seguem a mesma convenção kebab-case.",
        "callout": "CSS custom properties definidas via style-* são escopadas ao elemento e herdadas por seus filhos — assim como CSS custom properties regulares."
      }
    },
    "animations": {
      "hero": {
        "badge": "Guias",
        "title": "Animações & Transições",
        "subtitle": "Animações declarativas de entrada/saída e transições CSS"
      },
      "enterLeave": {
        "title": "animate — Animações de Entrada/Saída",
        "attrsTitle": "Atributos de Animação",
        "col1": "Atributo",
        "col2": "Descrição",
        "row1": "Classe de animação CSS adicionada quando o elemento entra",
        "row2": "Classe de animação CSS adicionada quando o elemento sai",
        "row3": "Duração em milissegundos repassada a animationDuration e usada como timeout de fallback. Quando omitido, o fallback dispara no próximo tick do event-loop (0 ms)",
        "row4": "Atraso em milissegundos entre cada item em um loop (each / foreach)",
        "fallbackCallout": "Timeout de fallback — O No.JS escuta animationend / transitionend para limpar classes e disparar re-renders após animações de saída. Se o evento nunca dispara (ex.: CSS ausente, elemento desconectado) um setTimeout de segurança garante que o pipeline nunca trave permanentemente. Quando animate-duration é omitido, o timeout é 0 ms — dispara no próximo tick do event-loop sem espera artificial. Passar um animate-duration=\"300\" explícito define tanto animation-duration no elemento alvo quanto o timeout de segurança em 300 ms."
      },
      "transition": {
        "title": "transition — Classes de Transição CSS",
        "viewTransitionNote": "<strong>Nota:</strong> Transições de rota no <code>route-view</code> agora usam a <a href=\"/docs/routing#view-transitions\">View Transition API</a> por padrão. O atributo <code>transition</code> baseado em classes descrito abaixo ainda se aplica a <strong>elementos regulares</strong> (ex: <code>if</code>, <code>show</code>).",
        "text1": "Segue uma convenção similar ao sistema de transição do Vue.",
        "text2": "O No.JS adiciona/remove classes durante a transição:",
        "col1": "Classe",
        "col2": "Quando",
        "row1": "Estado inicial da entrada",
        "row2": "Estado ativo da entrada",
        "row3": "Estado final da entrada",
        "row4": "Estado inicial da saída",
        "row5": "Estado ativo da saída",
        "row6": "Estado final da saída"
      },
      "loopAnimations": {
        "title": "Animações em Loops",
        "text": "Todas as diretivas de loop (foreach, each, for) suportam animações de entrada/saída e stagger."
      },
      "builtIn": {
        "title": "Nomes de Animação Integrados",
        "text": "O No.JS inclui estas animações CSS:"
      },
      "liveDemo": {
        "title": "Demo ao Vivo — Animação de Alternância",
        "label": "Resultado",
        "toggleButton": "Alternar",
        "demoText": "Olá, Mundo Animado! ✨"
      },
      "a11y": {
        "title": "Acessibilidade — Movimento Reduzido",
        "text": "No.JS respeita automaticamente a media query prefers-reduced-motion. Quando o usuário prefere movimento reduzido, todas as animações CSS são desabilitadas via uma regra CSS embutida que define animation-duration e transition-duration para 0.01ms.",
        "callout": "Isso se aplica globalmente — nenhuma configuração por elemento é necessária. Usuários que preferem movimento reduzido veem mudanças de estado instantâneas sem animação."
      }
    },
    "dnd": {
      "hero": {
        "badge": "Guias",
        "title": "Drag and Drop",
        "subtitle": "Arrastar, soltar, listas ordenáveis e seleção múltipla declarativos — zero JavaScript"
      },
      "drag": {
        "title": "drag — Tornar um Elemento Arrastável",
        "preview": "Pré-visualização",
        "demoText": "Arraste frutas para a cesta:",
        "fruitsLabel": "Frutas",
        "basketLabel": "Cesta",
        "col1": "Atributo",
        "col2": "Tipo",
        "col3": "Padrão",
        "col4": "Descrição",
        "dragDesc": "O valor sendo arrastado",
        "dragTypeDesc": "Tipo nomeado — apenas zonas <code>drop-accept</code> correspondentes respondem",
        "dragEffectDesc": "Mapeia para <code>dataTransfer.effectAllowed</code>",
        "dragHandleDesc": "Restringe a área de arraste a um elemento filho",
        "dragImageDesc": "Elemento fantasma personalizado para arraste",
        "dragImageOffsetDesc": "Deslocamento em pixels para a imagem de arraste personalizada",
        "dragDisabledDesc": "Quando verdadeiro, desabilita o arraste",
        "dragClassDesc": "Classe adicionada durante o arraste",
        "dragGhostClassDesc": "Classe adicionada ao elemento de imagem de arraste",
        "dragGroupDesc": "Nome do grupo para seleção múltipla"
      },
      "drop": {
        "title": "drop — Definir uma Zona de Soltura",
        "preview": "Pré-visualização",
        "demoText": "Arraste itens entre zonas:",
        "zoneALabel": "Zona A",
        "zoneBLabel": "Zona B",
        "col1": "Atributo",
        "col2": "Tipo",
        "col3": "Padrão",
        "col4": "Descrição",
        "dropDesc": "Expressão executada ao soltar",
        "dropAcceptDesc": "Tipo(s) <code>drag-type</code> aceitos. Use <code>\"*\"</code> para qualquer",
        "dropEffectDesc": "Mapeia para <code>dataTransfer.dropEffect</code>",
        "dropClassDesc": "Classe adicionada quando item válido sobrevoa",
        "dropRejectClassDesc": "Classe adicionada quando o item é rejeitado (tipo errado ou máximo excedido)",
        "dropDisabledDesc": "Quando verdadeiro, desabilita a soltura",
        "dropMaxDesc": "Máximo de itens que a zona aceita",
        "dropSortDesc": "Habilita reordenação posicional",
        "dropPlaceholderDesc": "Exibe placeholder no ponto de inserção",
        "dropPlaceholderClassDesc": "Classe para o placeholder",
        "dropSettleClassDesc": "Classe CSS personalizada para a animação de assentamento",
        "dropEmptyClassDesc": "Classe CSS personalizada para o estado vazio na zona de soltura"
      },
      "dragList": {
        "title": "drag-list — Lista Ordenável",
        "text": "Uma diretiva de nível superior que combina <code>drag</code> e <code>drop</code> em uma lista ordenável vinculada a um array de estado.",
        "preview": "Pré-visualização",
        "todoLabel": "A Fazer",
        "doneLabel": "Feito",
        "col1": "Atributo",
        "col2": "Tipo",
        "col3": "Padrão",
        "col4": "Descrição",
        "dragListDesc": "Caminho para o array no estado",
        "templateDesc": "Template para cada item",
        "dragListKeyDesc": "Chave única por item para identidade estável",
        "dragListItemDesc": "Nome da variável do loop no template",
        "dropSortDesc": "Direção do layout",
        "dropAcceptDesc": "Tipos aceitos (padrão: mesma lista)",
        "dragListCopyDesc": "Copiar itens ao invés de mover",
        "dragListRemoveDesc": "Remover itens ao arrastar para fora",
        "dragDisabledDesc": "Desabilita arraste desta lista",
        "dropDisabledDesc": "Desabilita soltura nesta lista",
        "dropMaxDesc": "Máximo de itens permitidos",
        "dropSettleClassDesc": "Classe CSS personalizada para a animação de assentamento",
        "dropEmptyClassDesc": "Classe CSS personalizada para o estado vazio na drag-list",
        "dropPlaceholderDesc": "Exibe um placeholder onde o item será solto"
      },
      "dragListEvents": {
        "title": "Eventos da Drag-List",
        "col1": "Evento",
        "col3": "Descrição",
        "reorderDesc": "Item reordenado dentro da mesma lista",
        "receiveDesc": "Item recebido de outra lista",
        "removeDesc": "Item removido (arrastado para fora)",
        "preview": "Pré-visualização",
        "inboxLabel": "Caixa de Entrada",
        "archiveLabel": "Arquivo",
        "eventLogLabel": "Log de eventos:"
      },
      "dragMultiple": {
        "title": "drag-multiple — Seleção Múltipla",
        "text": "Habilite clique para selecionar em elementos filhos e arraste todos os itens selecionados de uma vez.",
        "preview": "Pré-visualização",
        "demoText": "Clique nos itens para selecionar, <kbd>Ctrl</kbd>+clique para múltiplos, depois arraste para a zona de soltura:",
        "availableLabel": "Disponíveis",
        "collectedLabel": "Coletados",
        "col1": "Atributo",
        "col2": "Padrão",
        "col3": "Descrição",
        "dragMultipleDesc": "Habilita clique para selecionar",
        "dragMultipleClassDesc": "Classe adicionada aos itens selecionados",
        "dragGroupDesc": "Nome do grupo — todos os itens selecionados se movem juntos",
        "selectionTitle": "Comportamento de seleção:",
        "selCol1": "Ação",
        "selCol2": "Resultado",
        "selClick": "Clique",
        "selClickResult": "Seleciona item único (substitui anterior)",
        "selCtrlClick": "Ctrl/Cmd + Clique",
        "selCtrlClickResult": "Adiciona à seleção",
        "selEscape": "Escape",
        "selEscapeResult": "Limpa todas as seleções",
        "selDrag": "Arrastar um item selecionado",
        "selDragResult": "<code>$drag</code> se torna um array de todos os itens selecionados"
      },
      "implicitVars": {
        "title": "Variáveis Implícitas",
        "text": "Estas variáveis estão disponíveis dentro de expressões <code>drop</code> e handlers <code>on:drop</code>:",
        "col1": "Variável",
        "col2": "Tipo",
        "col3": "Descrição",
        "dragDesc": "O valor arrastado. Array se seleção múltipla",
        "dragTypeDesc": "O <code>drag-type</code> do item",
        "dragEffectDesc": "O <code>drag-effect</code>",
        "dropIndexDesc": "Índice de inserção dentro da zona de soltura",
        "sourceDesc": "<code>{ list, index, el }</code> — informação da origem",
        "targetDesc": "<code>{ list, index, el }</code> — informação do destino",
        "preview": "Pré-visualização",
        "demoText": "Cada item tem um <code>drag-type</code> diferente:",
        "dropHere": "Solte aqui para inspecionar"
      },
      "cssClasses": {
        "title": "Classes CSS",
        "text": "Injetados automaticamente pelo No.JS:",
        "col1": "Classe",
        "col2": "Quando aplicada",
        "draggingDesc": "No elemento de origem durante o arraste",
        "dragOverDesc": "Na zona de soltura enquanto um item válido sobrevoa",
        "dropRejectDesc": "Na zona de soltura quando o item é rejeitado (tipo errado ou máximo excedido)",
        "dropPlaceholderDesc": "No placeholder de inserção",
        "selectedDesc": "Nos itens com seleção múltipla",
        "dropSettleDesc": "Breve animação de assentamento ao soltar",
        "dragListEmptyDesc": "Em uma <code>drag-list</code> quando não tem itens",
        "preview": "Pré-visualização",
        "demoText": "Arraste um item e veja as classes sendo aplicadas:",
        "dropZoneHint": "Zona de soltura (máx 2) — observe <code>.nojs-drag-over</code> / <code>.nojs-drop-reject</code>"
      },
      "a11y": {
        "title": "Acessibilidade",
        "text": "O No.JS adiciona automaticamente atributos ARIA e suporte a teclado:",
        "col1": "Recurso",
        "col2": "Detalhes",
        "draggableDesc": "Definido nas fontes de arraste",
        "ariaGrabbedDesc": "Reflete o estado de arraste (<code>true</code>/<code>false</code>)",
        "ariaDropeffectDesc": "Definido nas zonas de soltura",
        "roleListboxDesc": "Em containers <code>drag-list</code>",
        "roleOptionDesc": "Em itens de <code>drag-list</code>",
        "tabindexDesc": "Para acesso via teclado",
        "keyboardTitle": "Atalhos de teclado:",
        "keyCol1": "Tecla",
        "keyCol2": "Ação",
        "spaceDesc": "Pegar o item em foco",
        "escapeDesc": "Cancelar o arraste",
        "arrowDesc": "Navegar entre itens durante o arraste",
        "enterDesc": "Soltar na posição atual",
        "preview": "Pré-visualização",
        "demoText": "Use <kbd>Tab</kbd> para focar, <kbd>Espaço</kbd> para pegar, <kbd>↑↓</kbd> para mover, <kbd>Enter</kbd> para soltar:"
      }
    },
    "filters": {
      "hero": {
        "badge": "Guias",
        "title": "Filtros & Pipes",
        "subtitle": "Transforme valores em expressões bind usando a sintaxe de pipe |"
      },
      "text": {
        "title": "Filtros de Texto"
      },
      "number": {
        "title": "Filtros de Número"
      },
      "array": {
        "title": "Filtros de Array"
      },
      "date": {
        "title": "Filtros de Data"
      },
      "utility": {
        "title": "Filtros Utilitários"
      },
      "object": {
        "title": "Filtros de Objeto"
      },
      "chaining": {
        "title": "Encadeamento de Filtros"
      },
      "custom": {
        "title": "Filtros Personalizados"
      },
      "liveDemo": {
        "title": "Demo ao Vivo — Filtros",
        "label": "Resultado",
        "uppercaseLabel": "Maiúsculas:",
        "slugifyLabel": "Slugify:"
      },
      "referenceTable": {
        "title": "Referência Completa de Filtros",
        "text": "Todos os 32 filtros embutidos de relance:",
        "col1": "Filtro",
        "col2": "Categoria",
        "col3": "Descrição",
        "uppercase": "Converte texto para MAIÚSCULAS",
        "lowercase": "Converte texto para minúsculas",
        "capitalize": "Capitaliza a primeira letra de cada palavra",
        "truncate": "Trunca texto para N caracteres com reticências",
        "slugify": "Converte para slug compatível com URL",
        "trim": "Remove espaços em branco iniciais/finais",
        "encodeUri": "Codifica um componente URI",
        "currency": "Formata número como moeda",
        "number": "Formata número com agrupamento por localidade",
        "percent": "Formata número como porcentagem",
        "ordinal": "Adiciona sufixo ordinal (1º, 2º, 3º)",
        "filesize": "Formata bytes para tamanho legível",
        "reverse": "Inverte array ou string",
        "unique": "Remove valores duplicados",
        "pluck": "Extrai uma propriedade de cada item",
        "where": "Filtra array por valor de propriedade",
        "sortBy": "Ordena array por propriedade",
        "first": "Retorna o primeiro elemento de um array",
        "last": "Retorna o último elemento de um array",
        "date": "Formata objeto Date",
        "datetime": "Formata Date com horário",
        "relative": "Tempo decorrido desde a data (ex: '5 minutos atrás')",
        "fromNow": "Tempo até uma data futura (ex: 'em 3 horas')",
        "json": "Serializa valor como string JSON",
        "default": "Retorna fallback se valor for null/undefined",
        "keys": "Retorna chaves do objeto como array",
        "values": "Retorna valores do objeto como array",
        "count": "Retorna o comprimento de um array",
        "join": "Junta elementos do array com um separador",
        "stripHtml": "Remove tags HTML de uma string",
        "nl2br": "Converte quebras de linha em tags <br>",
        "debug": "Exibe o valor no console e o retorna"
      }
    },
    "i18n": {
      "hero": {
        "badge": "Guias",
        "title": "Internacionalização (i18n)",
        "subtitle": "Suporte multi-idioma com traduções, pluralização e formatação sensível ao locale"
      },
      "setup": {
        "title": "Configuração"
      },
      "externalFiles": {
        "title": "Arquivos de Locale Externos",
        "text": "Em vez de embutir todas as traduções em JavaScript, você pode carregá-las de arquivos JSON externos. Isso é ideal para apps grandes com muitos locales ou quando traduções são gerenciadas por uma ferramenta separada.",
        "flatSubtitle": "Modo Flat (um arquivo por locale)",
        "flatText": "Estrutura:",
        "nsSubtitle": "Modo Namespace (dividido por funcionalidade)",
        "nsText": "Divida traduções por funcionalidade para code-splitting e carregamento sob demanda:",
        "nsRouteSubtitle": "Namespace por Rota",
        "nsRouteText": "Use i18n-ns em um template de rota para carregar um namespace sob demanda quando a rota é navegada:",
        "nsElementSubtitle": "Namespace em Qualquer Elemento",
        "nsElementText": "Use i18n-ns em qualquer elemento para carregar um namespace antes que seus filhos sejam processados:",
        "cachingSubtitle": "Cache",
        "cachingText": "Arquivos JSON buscados são cacheados em memória por padrão. Defina cache: false durante o desenvolvimento:"
      },
      "usage": {
        "title": "Uso"
      },
      "formatting": {
        "title": "Formatação de Números & Datas"
      },
      "liveDemo": {
        "title": "Demo ao Vivo — Seletor de Locale",
        "label": "Resultado",
        "localeLabel": "Idioma:"
      },
      "fallback": {
        "title": "Comportamento de Fallback",
        "text": "Quando uma chave de tradução está ausente na localidade atual, No.JS faz fallback para a fallbackLocale (padrão: igual a defaultLocale). Se a chave estiver ausente em ambas, o caminho bruto da chave é exibido.",
        "callout": "Defina fallbackLocale explicitamente para garantir que usuários sempre vejam texto significativo, mesmo para localidades parcialmente traduzidas."
      },
      "detection": {
        "title": "Detecção de Localidade do Navegador",
        "text": "Habilite detecção automática de localidade a partir do navigator.language do navegador com detectBrowser: true. A localidade detectada é combinada com suas localidades disponíveis.",
        "callout": "Quando combinado com persist: true, a localidade detectada é salva para que visitas subsequentes usem o mesmo idioma sem re-detecção."
      }
    },
    "actionsRefs": {
      "hero": {
        "badge": "Referência da API",
        "title": "Ações & Refs",
        "subtitle": "Acione chamadas de API, emita eventos customizados e referencie elementos DOM"
      },
      "call": {
        "title": "call — Acionar Requisições de API de Qualquer Elemento"
      },
      "trigger": {
        "title": "trigger — Emitir Eventos Customizados"
      },
      "ref": {
        "title": "ref — Referências Nomeadas",
        "text": "Acesse elementos DOM sem querySelector:"
      },
      "refsMap": {
        "title": "$refs — Mapa de Refs",
        "text": "Todos os elementos com ref são acessíveis via $refs no escopo atual:"
      },
      "triggerAttrs": {
        "title": "Atributos do Trigger",
        "text": "Personalize o comportamento do trigger com atributos adicionais:",
        "col1": "Atributo",
        "col2": "Descrição",
        "triggerData": "Payload de dados anexado à propriedade detail do CustomEvent"
      }
    },
    "customDirectives": {
      "hero": {
        "badge": "Referência da API",
        "title": "Diretivas Personalizadas",
        "subtitle": "Estenda o No.JS com seus próprios comportamentos orientados a atributos"
      },
      "directive": {
        "title": "NoJS.directive()"
      },
      "usage": {
        "title": "Uso"
      },
      "webComponents": {
        "title": "Compatibilidade com Web Components",
        "text": "Diretivas do No.JS funcionam em custom elements:"
      },
      "componentPatterns": {
        "title": "Padrões Semelhantes a Componentes com Templates"
      },
      "priority": {
        "title": "Níveis de Prioridade",
        "text": "A prioridade determina quando sua diretiva executa em relação às diretivas embutidas. Números menores executam primeiro.",
        "col1": "Faixa",
        "col2": "Quando",
        "range0": "Antes de tudo (inicialização de estado)",
        "range1": "Após estado, com busca de dados",
        "range10": "Com diretivas estruturais (if, each)",
        "range20": "Com diretivas de renderização (bind, on:*)",
        "range30": "Após tudo (validação, efeitos colaterais)"
      },
      "disposal": {
        "title": "Disposal & Cleanup",
        "text": "Diretivas customizadas devem limpar após si mesmas. Use o callback _onDispose para remover event listeners, limpar timers e cancelar watchers.",
        "callout": "Diretivas registradas após init (via plugins) não são congeladas — mas não podem sobrescrever diretivas embutidas."
      }
    },
    "errorHandling": {
      "hero": {
        "badge": "Referência da API",
        "title": "Tratamento de Erros",
        "subtitle": "Templates de erro por elemento, lógica de retry e handlers de erro globais"
      },
      "perElement": {
        "title": "Tratamento de Erro por Elemento"
      },
      "globalHandler": {
        "title": "Handler de Erro Global"
      },
      "errorBoundary": {
        "title": "error-boundary — Capturar Erros na Subárvore"
      },
      "retry": {
        "title": "Comportamento de Retry",
        "text": "Requisições HTTP com falha (erros 5xx e falhas de rede) são automaticamente reexecutadas. Configure o número de retries por elemento com o atributo retry, e o atraso entre retries com retry-delay.",
        "callout": "Retries se aplicam apenas a erros de servidor (5xx) e falhas de rede. Erros de cliente (4xx) não são reexecutados."
      },
      "boundaryEvents": {
        "title": "Eventos de Error Boundary",
        "text": "Quando um error boundary captura um erro, ele dispara um CustomEvent nojs:error no elemento boundary. Escute com on:error para registrar erros ou mostrar notificações.",
        "callout": "O objeto $event.detail contém: message (string), source (element) e error (objeto Error original)."
      },
      "expressionErrors": {
        "title": "Erros de Expressão",
        "text": "Quando uma expressão falha ao avaliar (ex: acessar uma propriedade de undefined), No.JS captura o erro, registra um warning via _warn() e retorna undefined. Uma expressão quebrada nunca derruba a página inteira."
      }
    },
    "configuration": {
      "hero": {
        "badge": "Referência da API",
        "title": "Configuração & Segurança",
        "subtitle": "Configurações globais, interceptors de requisição e melhores práticas de segurança"
      },
      "globalSettings": {
        "title": "Configurações Globais"
      },
      "configStores": {
        "title": "Pré-inicialização de Stores",
        "text": "Use a chave stores em NoJS.config() para pré-criar stores globais nomeados com dados iniciais. Cada entrada se torna um store reativo acessível via $store.nome em qualquer parte do seu HTML.",
        "callout": "Stores criados via config() não sobrescreverão stores que já existem — a primeira definição prevalece."
      },
      "configOptions": {
        "title": "Detalhes das Opções de Configuração",
        "sanitizeTitle": "sanitize",
        "sanitizeType": "Tipo: boolean | Padrão: true",
        "sanitizeText": "Controla se o conteúdo HTML renderizado via bind-html é sanitizado através de um sanitizador estrutural baseado em DOMParser. Quando habilitado, todas as tags e atributos potencialmente perigosos (ex: <script>, onerror) são removidos antes da inserção no DOM.",
        "devtoolsTitle": "devtools",
        "devtoolsType": "Tipo: boolean | Padrão: false",
        "devtoolsText": "Habilita o painel de devtools do No.JS, acessível via window.__NOJS_DEVTOOLS__. Quando ativo, expõe estado reativo, diretivas registradas, rotas ativas e árvores de componentes para inspeção no console do navegador.",
        "templatesCacheTitle": "templates.cache",
        "templatesCacheType": "Tipo: boolean | Padrão: true",
        "templatesCacheText1": "Controla se o conteúdo HTML de arquivos .tpl buscados remotamente é armazenado em um Map em memória após a primeira requisição. Em navegações repetidas para a mesma rota, o HTML cacheado é usado diretamente e nenhuma requisição HTTP é feita. O cache dura pela sessão da página (sem TTL — recursos de template são estáticos).",
        "templatesCacheText2": "Defina como false durante o desenvolvimento local se quiser que mudanças em arquivos .tpl sejam refletidas sem um recarregamento forçado da página.",
        "loadPathTitle": "i18n.loadPath",
        "loadPathType": "Tipo: string | null | Padrão: null",
        "loadPathText": "Template de URL para carregar arquivos JSON de locale via fetch. Use {locale} e opcionalmente {ns} como placeholders. Quando null, traduções devem ser fornecidas inline via NoJS.i18n({ locales }).",
        "nsTitle": "i18n.ns",
        "nsType": "Tipo: string[] | Padrão: []",
        "nsText": "Array de identificadores de namespace para pré-carregar no init(). Cada namespace corresponde a um arquivo JSON separado por locale. Namespaces adicionais podem ser carregados sob demanda via a diretiva i18n-ns ou atributo de rota.",
        "cacheTitle": "i18n.cache",
        "cacheType": "Tipo: boolean | Padrão: true",
        "cacheText": "Controla se os arquivos JSON de locale buscados são armazenados em um Map em memória após a primeira requisição. Defina como false durante o desenvolvimento para hot-reload dos arquivos de tradução."
      },
      "apiProperties": {
        "title": "Propriedades da API",
        "baseApiUrlTitle": "NoJS.baseApiUrl",
        "baseApiUrlText": "Getter/setter para a URL base da API usada por todas as diretivas de fetch e chamadas NoJS.http. Pode ser lido ou reatribuído em tempo de execução.",
        "versionTitle": "NoJS.version",
        "versionText": "Propriedade somente leitura que retorna a string da versão atual do framework No.JS."
      },
      "interceptors": {
        "title": "Interceptors de Requisição"
      },
      "security": {
        "title": "Segurança",
        "xssTitle": "Proteção XSS",
        "xssList1": "bind sempre define textContent, nunca innerHTML — seguro por padrão.",
        "xssList2": "bind-html sanitiza conteúdo usando um sanitizador estrutural integrado baseado em DOMParser (remove tags <script>, bloqueia handlers de evento on*, remove URIs javascript:).",
        "xssList3": "Expressões de template são avaliadas por um parser sandboxed personalizado — eval() e Function() não são usados, e propriedades perigosas como __proto__ e constructor são bloqueadas.",
        "csrfTitle": "Proteção CSRF",
        "cspSecTitle": "Content Security Policy",
        "cspSecText1": "O No.JS usa um parser de expressões personalizado totalmente compatível com CSP — eval() e o construtor Function() não são usados. Nenhuma diretiva unsafe-eval é necessária na sua Content Security Policy."
      }
    },
    "plugins": {
      "hero": {
        "badge": "Referência da API",
        "title": "Plugins",
        "subtitle": "Estenda o No.JS com pacotes reutilizáveis — analytics, autenticação, feature flags e mais"
      },
      "use": {
        "title": "NoJS.use()",
        "text": "Registre um plugin antes ou depois de NoJS.init(). Se o app já estiver inicializado, o hook init do plugin executa imediatamente.",
        "objectFormTitle": "Forma de Objeto",
        "objectFormText": "A forma padrão de definir um plugin. Forneça um nome, uma função install e hooks de ciclo de vida opcionais.",
        "functionTitle": "Atalho de Função",
        "functionText": "Para plugins simples, passe uma função nomeada. O nome da função se torna o nome do plugin.",
        "functionCallout": "Funções anônimas e arrow functions são rejeitadas — o plugin deve ter um nome.",
        "optionsTitle": "Opções",
        "optionsText": "O segundo argumento de NoJS.use() é passado para a função install do plugin.",
        "optionsTrustedNote": "A opção trusted é especial — veja Interceptors de Confiança abaixo."
      },
      "interface": {
        "title": "Interface do Plugin",
        "thProperty": "Propriedade",
        "thType": "Tipo",
        "thRequired": "Obrigatório",
        "thDescription": "Descrição",
        "yes": "Sim",
        "no": "Não",
        "nameDesc": "Identificador único. Nomes duplicados são rejeitados.",
        "versionDesc": "String semver para depuração.",
        "capabilitiesDesc": "Capacidades declaradas (registradas em modo debug).",
        "installDesc": "Chamado sincronicamente por NoJS.use().",
        "initDesc": "Chamado após NoJS.init() completar (DOM está pronto).",
        "disposeDesc": "Chamado durante NoJS.dispose() para limpeza.",
        "lifecycleTitle": "Ciclo de Vida",
        "lifecycleInstall": "install executa imediatamente e de forma síncrona. Use para registrar interceptors, globais, diretivas, ouvintes de eventos e stores.",
        "lifecycleInit": "init executa após o DOM ser processado e o router estar ativo. Use para trabalho que dependa de elementos renderizados ou do estado da rota.",
        "lifecycleDispose": "dispose executa durante a destruição do app. Use para fechar conexões WebSocket, limpar intervalos, enviar analytics pendentes, etc.",
        "duplicateTitle": "Detecção de Duplicatas",
        "duplicateText": "Um nome de plugin só pode ser registrado uma vez. Se NoJS.use() for chamado novamente com o mesmo nome mas um objeto diferente, um aviso é registrado e a chamada é ignorada.",
        "freezingTitle": "Congelamento do Registro de Diretivas",
        "freezingText": "Diretivas principais (state, bind, get, on:*, etc.) são congeladas após o framework carregar. Plugins podem registrar novas diretivas mas não podem sobrescrever as integradas."
      },
      "globals": {
        "title": "NoJS.global()",
        "text": "Injeta uma variável reativa acessível como $name em qualquer expressão de template.",
        "namingTitle": "Convenções de Nomes",
        "namingPrefix": "Nomes globais são acessados com um prefixo $ nos templates: NoJS.global('foo', ...) se torna $foo.",
        "namingNamespace": "Use o nome do seu plugin como namespace para evitar colisões: $analytics, $auth, $featureFlags.",
        "reservedTitle": "Nomes Reservados",
        "reservedText": "Os seguintes nomes não podem ser usados com NoJS.global():",
        "reservedProto": "Vetores de prototype pollution (__proto__, constructor, prototype) também são bloqueados.",
        "reactivityTitle": "Reatividade",
        "reactivityText": "Valores de objeto passados para NoJS.global() são automaticamente envolvidos em um contexto reativo. Mutações disparam atualizações do DOM assim como mudanças de store ou state.",
        "ownershipTitle": "Rastreamento de Propriedade",
        "ownershipText": "Quando um plugin registra um global durante sua fase install, ele se torna o proprietário. Se um plugin diferente sobrescrever esse global, um aviso é registrado."
      },
      "sentinels": {
        "title": "Sentinelas de Interceptor",
        "text": "Interceptors de requisição podem retornar objetos especiais com chave de Symbols sentinela para controlar o pipeline de fetch.",
        "cancelTitle": "NoJS.CANCEL — Abortar a Requisição",
        "cancelText": "Retorne um objeto com [NoJS.CANCEL]: true para impedir que a requisição seja enviada. O fetch lança um AbortError.",
        "respondTitle": "NoJS.RESPOND — Servir uma Resposta em Cache",
        "respondText": "Retorne um objeto com [NoJS.RESPOND]: data para curto-circuitar a requisição e retornar data diretamente como resposta. Nenhuma requisição HTTP é feita.",
        "replaceTitle": "NoJS.REPLACE — Substituir Dados da Resposta",
        "replaceText": "Retorne um objeto com [NoJS.REPLACE]: data de um interceptor de resposta para substituir o corpo da resposta parseado com dados personalizados.",
        "summaryTitle": "Resumo",
        "thSentinel": "Sentinela",
        "thUsedIn": "Usado Em",
        "thEffect": "Efeito",
        "cancelUsedIn": "Interceptor de request",
        "respondUsedIn": "Interceptor de request",
        "replaceUsedIn": "Interceptor de response",
        "cancelEffect": "Aborta a requisição (lança AbortError)",
        "respondEffect": "Retorna dados diretamente, pula a chamada HTTP",
        "replaceEffect": "Substitui o corpo da resposta parseado"
      },
      "trusted": {
        "title": "Interceptors de Confiança",
        "text": "Por padrão, interceptors recebem cópias censuradas de requests e responses — headers sensíveis e parâmetros de URL são removidos ou substituídos por [REDACTED].",
        "fullAccess": "Plugins de autenticação que precisam de acesso aos headers reais podem ser instalados com { trusted: true }.",
        "callout": "Um aviso no console é registrado quando um plugin é instalado com acesso de confiança. Só conceda trusted a plugins que você controla ou auditou.",
        "redactedTitle": "Headers Censurados",
        "requestLabel": "Headers de request removidos antes de passar para interceptors não confiáveis:",
        "responseLabel": "Headers de response removidos do proxy de response:"
      },
      "dispose": {
        "title": "NoJS.dispose()",
        "text": "Destrói toda a aplicação: dispõe os plugins, limpa os globais e remove os interceptors.",
        "orderTitle": "Ordem de Destruição",
        "orderStep1": "Plugins são destruídos em ordem reversa de instalação (último instalado, primeiro destruído).",
        "orderStep2": "A função dispose de cada plugin tem um tempo limite de 3 segundos. Se exceder o limite, um erro é registrado e a destruição continua com o próximo plugin.",
        "orderStep3": "Após todos os plugins serem destruídos, globais e interceptors são limpos.",
        "asyncTitle": "Dispose Assíncrono",
        "asyncText": "Funções dispose de plugins podem ser assíncronas. O framework aguarda cada uma (sujeita ao tempo limite de 3 segundos).",
        "callout": "Plugins não podem ser instalados durante a destruição. Chamadas a NoJS.use() enquanto dispose() está executando são ignoradas com um aviso."
      },
      "security": {
        "title": "Diretrizes de Segurança",
        "text": "Ao criar plugins, siga estas práticas para manter sua aplicação segura.",
        "namespaceTitle": "Use Namespace em Tudo",
        "namespaceText": "Prefixe globais, stores e nomes de eventos com o nome do seu plugin para evitar colisões.",
        "evalTitle": "Nunca Use eval ou Function",
        "evalText": "Valores passados para NoJS.global() são verificados em busca de referências perigosas. eval e Function são bloqueados.",
        "cleanupTitle": "Limpe em dispose",
        "cleanupText": "Sempre forneça um hook dispose que limpe intervalos, feche conexões e remova ouvintes de eventos.",
        "overwriteTitle": "Evite Sobrescrever Globais Alheios",
        "overwriteText": "Se seu plugin detectar que um global já pertence a outro plugin, considere usar um nome diferente em vez de sobrescrever silenciosamente.",
        "validateTitle": "Valide as Opções",
        "validateText": "Verifique as opções obrigatórias em install e avise cedo."
      },
      "example": {
        "title": "Exemplo Completo",
        "text": "Um plugin de analytics completo demonstrando o ciclo de vida do plugin, globais, interceptors e destruição."
      }
    },
    "headManagement": {
      "hero": {
        "badge": "Guias",
        "title": "Head Management",
        "subtitle": "Gerencie o título do documento, meta description, URL canônica e JSON-LD de qualquer elemento"
      },
      "intro": {
        "text": "O No.JS permite controlar metadados do <head> de forma declarativa em qualquer parte do seu markup. Use elementos ocultos com atributos page-title, page-description, page-canonical e page-jsonld — eles são avaliados reativamente e atualizam o head do documento automaticamente.",
        "routingTip": "Para gerenciamento do head a nível de rota, você também pode usar <code>page-title</code> e <code>page-description</code> diretamente em tags <code>&lt;template route=\"...\"&gt;</code>. Veja <a href=\"/docs/routing#route-head-attributes\">Atributos Head em Rotas</a>."
      },
      "placement": {
        "title": "Posicionamento",
        "text": "Coloque os elementos de gerenciamento do head dentro de qualquer scope de state. Eles devem ter o atributo hidden — nunca são renderizados visualmente.",
        "reactive": "Todos os valores são reativos — quando o state subjacente muda, o head do documento é atualizado imediatamente."
      },
      "pageTitle": {
        "title": "page-title",
        "text": "Define document.title com o valor da expressão avaliada.",
        "expression": "O valor é uma expressão padrão do No.JS avaliada contra o contexto do elemento."
      },
      "pageDescription": {
        "title": "page-description",
        "text": "Define o atributo content da tag <meta name=\"description\">. Se a tag não existir, ela é criada.",
        "duplicate": "Apenas um page-description deve estar ativo por vez. Se múltiplos estiverem presentes, o último processado vence."
      },
      "pageCanonical": {
        "title": "page-canonical",
        "text": "Define o atributo href da tag <link rel=\"canonical\">. Se a tag não existir, ela é criada.",
        "existing": "Se um link canônico já existir no seu HTML, o valor do atributo é atualizado no local."
      },
      "pageJsonld": {
        "title": "page-jsonld",
        "text": "Injeta um bloco <script type=\"application/ld+json\"> no head do documento. O texto interno do elemento é usado como payload JSON-LD.",
        "scriptNote": "O conteúdo é inserido como está — certifique-se de que seja JSON válido. Use interpolação <code>{variable}</code> para injetar valores dinâmicos.",
        "marker": "A tag script gerada é marcada com <code>data-nojs-jsonld</code> para poder ser identificada e limpa ao desmontar.",
        "fullExampleTitle": "Exemplo Completo de Página de Produto"
      },
      "notes": {
        "title": "Notas e Casos Especiais",
        "competingTitle": "Múltiplas Diretivas Competindo",
        "competingText": "Se múltiplos elementos definirem o mesmo atributo head (ex. dois elementos page-title), o último processado vence. Quando um elemento é desmontado, sua contribuição ao head é revertida para o valor anterior.",
        "cleanupTitle": "Limpeza ao Desmontar",
        "cleanupText": "Quando um elemento com uma diretiva de head é removido do DOM (ex. dentro de um bloco if ou uma mudança de rota), sua contribuição ao head é limpa automaticamente.",
        "captureTitle": "Captura de Template JSON-LD",
        "captureText": "O innerHTML do elemento page-jsonld é capturado no momento do processamento. Se você precisar de JSON-LD reativo, coloque o elemento dentro de um scope de state e use interpolação {expressão}."
      }
    }
  }
}
