diff --git a/.agents/scripts/audit-translations.allowlist.json b/.agents/scripts/audit-translations.allowlist.json new file mode 100644 index 0000000..49bef57 --- /dev/null +++ b/.agents/scripts/audit-translations.allowlist.json @@ -0,0 +1,112 @@ +{ + "entries": [ + { + "collection": "chapters", + "file": "agents.json", + "field": "sections.1.steps.0.label", + "reason": "Handoff step label (\"Brief\"); kept English by glossary convention." + }, + { + "collection": "chapters", + "file": "landing.json", + "field": "cards.0.label", + "reason": "Numeric card label (\"01\"); identical across locales by design." + }, + { + "collection": "chapters", + "file": "landing.json", + "field": "cards.1.label", + "reason": "Numeric card label (\"02\"); identical across locales by design." + }, + { + "collection": "chapters", + "file": "landing.json", + "field": "cards.2.label", + "reason": "Numeric card label (\"03\"); identical across locales by design." + }, + { + "collection": "chapters", + "file": "landing.json", + "field": "cards.2.title", + "reason": "Product noun (\"Skills\"); kept English by glossary convention." + }, + { + "collection": "chapters", + "file": "landing.json", + "field": "cards.3.label", + "reason": "Numeric card label (\"04\"); identical across locales by design." + }, + { + "collection": "chapters", + "file": "landing.json", + "field": "cards.4.label", + "reason": "Numeric card label (\"05\"); identical across locales by design." + }, + { + "collection": "chapters", + "file": "landing.json", + "field": "cards.5.label", + "reason": "Numeric card label (\"06\"); identical across locales by design." + }, + { + "collection": "chapters", + "file": "summary.json", + "field": "cards.0.label", + "reason": "Numeric card label (\"01\"); identical across locales by design." + }, + { + "collection": "chapters", + "file": "summary.json", + "field": "cards.1.label", + "reason": "Numeric card label (\"02\"); identical across locales by design." + }, + { + "collection": "chapters", + "file": "summary.json", + "field": "cards.2.label", + "reason": "Numeric card label (\"03\"); identical across locales by design." + }, + { + "collection": "chapters", + "file": "summary.json", + "field": "cards.2.title", + "reason": "Product noun (\"Skills\"); kept English by glossary convention." + }, + { + "collection": "chapters", + "file": "summary.json", + "field": "cards.3.label", + "reason": "Numeric card label (\"04\"); identical across locales by design." + }, + { + "collection": "chapters", + "file": "summary.json", + "field": "cards.4.label", + "reason": "Numeric card label (\"05\"); identical across locales by design." + }, + { + "collection": "chapters", + "file": "summary.json", + "field": "cards.5.label", + "reason": "Numeric card label (\"06\"); identical across locales by design." + }, + { + "collection": "providers", + "file": "claude.json", + "field": "title", + "reason": "Model-tier series name (\"Opus · Sonnet · Haiku\"); kept English as product name." + }, + { + "collection": "providers", + "file": "gemini.json", + "field": "title", + "reason": "Model-tier series name (\"Pro · Flash · Flash-Lite\"); kept English as product name." + }, + { + "collection": "providers", + "file": "openai.json", + "field": "title", + "reason": "Model-tier series name (\"Sol · Terra · Luna\"); kept English as product name." + } + ] +} diff --git a/.agents/scripts/audit-translations.mjs b/.agents/scripts/audit-translations.mjs index b663056..bcad668 100644 --- a/.agents/scripts/audit-translations.mjs +++ b/.agents/scripts/audit-translations.mjs @@ -7,16 +7,25 @@ // node .agents/scripts/audit-translations.mjs # walks src/content // node .agents/scripts/audit-translations.mjs src/content/ # explicit root // -// Exits non-zero if any pair is identical. The output is grouped by -// collection, then by file, then by field path, so the report reads like +// Exits non-zero if any unallowed pair is identical. The output is grouped +// by collection, then by file, then by field path, so the report reads like // a translation backlog rather than a wall of strings. // // This is the sibling of extract-strings.mjs: that one proves the // migration moved every string; this one proves every string actually // differs across locales. +// +// Allowlist: a sibling `.agents/scripts/audit-translations.allowlist.json` +// lists (collection, file, field) tuples that are intentionally identical +// across locales (numeric card labels, product nouns, model-tier series +// names, etc.). Entries in the allowlist are listed under "ALLOWED" in the +// output and do not affect the exit code. Adding to the allowlist is a +// deliberate edit + commit; future translators can see it and understand +// which identicals are intentional. -import { readFileSync, readdirSync, statSync } from 'node:fs'; -import { join, relative } from 'node:path'; +import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'; +import { dirname, join, relative } from 'node:path'; +import { fileURLToPath } from 'node:url'; const ROOT = process.argv[2] ?? 'src/content'; @@ -69,9 +78,27 @@ const collectionOf = (file, root) => { return parts.length >= 2 ? parts[0] : '(root)'; }; +// Load the allowlist. The file lives next to this script and lists +// intentional identicals (numeric labels, product nouns, model-tier series +// names, etc.). Missing file is OK — the audit still runs. +const here = dirname(fileURLToPath(import.meta.url)); +const allowlistPath = join(here, 'audit-translations.allowlist.json'); +const allowlist = new Set(); +const allowlistReasons = new Map(); + +if (existsSync(allowlistPath)) { + const { entries } = JSON.parse(readFileSync(allowlistPath, 'utf8')); + for (const { collection, file, field, reason } of entries) { + allowlist.add(`${collection}${file}${field}`); + allowlistReasons.set(`${collection}${file}${field}`, reason); + } +} + const groups = new Map(); +const allowedGroups = new Map(); let totalLocalized = 0; -let totalIdentical = 0; +let totalReal = 0; +let totalAllowed = 0; for (const file of files) { let data; @@ -84,40 +111,78 @@ for (const file of files) { const pairs = collect(data); if (pairs.length === 0) continue; - const offenders = pairs.filter(([, en, pt]) => same(en, pt)); - if (offenders.length === 0) continue; - - totalLocalized += pairs.length; - totalIdentical += offenders.length; - const collection = collectionOf(file, ROOT); const filename = relative(ROOT, file); + // Allowlist entries key on the file's name within its collection + // (e.g. `landing.json`), so strip the collection prefix from + // `filename` when matching. The full relative path is still used + // for the report display. + const collectionFile = filename.startsWith(collection + '/') + ? filename.slice(collection.length + 1) + : filename; - if (!groups.has(collection)) groups.set(collection, []); - groups.get(collection).push({ file: filename, pairs: offenders }); + // Split identical pairs into real offenders (fail the gate) and + // allowlisted ones (listed under ALLOWED, do not affect exit code). + const real = []; + const allowed = []; + for (const [field, en, pt] of pairs) { + if (!same(en, pt)) continue; + const key = `${collection}${collectionFile}${field}`; + if (allowlist.has(key)) { + allowed.push([field, en, allowlistReasons.get(key)]); + } else { + real.push([field, en, null]); + } + } + + totalLocalized += pairs.length; + + if (real.length > 0) { + totalReal += real.length; + if (!groups.has(collection)) groups.set(collection, []); + groups.get(collection).push({ file: filename, pairs: real }); + } + + if (allowed.length > 0) { + totalAllowed += allowed.length; + if (!allowedGroups.has(collection)) allowedGroups.set(collection, []); + allowedGroups.get(collection).push({ file: filename, pairs: allowed }); + } } -if (groups.size === 0) { +const printGroup = (entries, label) => { + for (const [collection, list] of entries) { + console.log(`\n[${collection}]`); + for (const { file, pairs } of list) { + console.log(` ${file}`); + for (const [field, en, reason] of pairs) { + const sample = typeof en === 'string' ? JSON.stringify(en).slice(0, 80) : ''; + const suffix = reason ? ` [${label}: ${reason}]` : ''; + console.log(` - ${field.padEnd(28)} ${sample}${suffix}`); + } + } + } +}; + +// Clean case: no identicals at all. +if (totalReal === 0 && totalAllowed === 0) { console.log('OK: no identical en/pt pairs found under', ROOT); process.exit(0); } -// Print grouped report. -for (const [collection, entries] of groups) { - console.log(`\n[${collection}]`); - for (const { file, pairs } of entries) { - console.log(` ${file}`); - for (const [field, en, pt] of pairs) { - const sample = typeof en === 'string' ? JSON.stringify(en).slice(0, 80) : ''; - console.log(` - ${field.padEnd(28)} ${sample}`); - } - } +// Show allowed entries first, then real offenders (if any). +printGroup(allowedGroups, 'ALLOWED'); + +if (totalReal > 0) { + printGroup(groups, 'REAL'); + console.log( + `\nFAIL: ${totalReal} unallowed identical localized field(s) across ${groups.size} collection(s) of ${ROOT}`, + ); + console.log( + 'A `pt` identical to `en` is how a bilingual site becomes monolingual. Translate, then re-run.', + ); + process.exit(1); } -console.log( - `\nFAIL: ${totalIdentical} identical localized field(s) across ${groups.size} collection(s) of ${ROOT}`, -); -console.log( - 'A `pt` identical to `en` is how a bilingual site becomes monolingual. Translate, then re-run.', -); -process.exit(1); +console.log(`\nOK: ${totalAllowed} identical field(s) found, all on the allowlist.`); +process.exit(0); diff --git a/package.json b/package.json index 73ea234..12ce04f 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "check": "astro check", "lint": "eslint . --max-warnings=0 && stylelint --allow-empty-input 'src/**/*.css' --max-warnings=0", "format": "prettier --write .", - "verify": "node scripts/verify.mjs && node scripts/audit-ui.mjs && node .agents/scripts/check-tokens.mjs", + "verify": "node .agents/scripts/audit-translations.mjs && node scripts/verify.mjs && node scripts/audit-ui.mjs && node .agents/scripts/check-tokens.mjs", "gate": "./.agents/scripts/gate.sh", "snapshot": "node .agents/scripts/snapshot-route.mjs", "prepare": "husky" diff --git a/scripts/verify.mjs b/scripts/verify.mjs index 8cda785..662e66d 100644 --- a/scripts/verify.mjs +++ b/scripts/verify.mjs @@ -271,11 +271,13 @@ if (!allPages.every(([, page]) => page.includes('name="viewport"'))) throw new Error('a built route lacks a viewport declaration'); if (allPages.some(([, page]) => /<(script|link)[^>]+(src|href)="https?:[^\"]+"/i.test(page))) throw new Error('a built route has an external runtime dependency'); -if ( - !read('package.json').includes( - '"verify": "node scripts/verify.mjs && node scripts/audit-ui.mjs && node .agents/scripts/check-tokens.mjs"', - ) -) +// `pnpm run verify` may now prepend `node .agents/scripts/audit-translations.mjs &&` +// for fail-fast translation checks. Allow an optional audit-translations prefix +// while still requiring the three core scripts in order. +const verifyChain = read('package.json'); +const verifyShape = + /\"verify\":\s*\"(?:node \.agents\/scripts\/audit-translations\.mjs && )?node scripts\/verify\.mjs && node scripts\/audit-ui\.mjs && node \.agents\/scripts\/check-tokens\.mjs\"/; +if (!verifyShape.test(verifyChain)) throw new Error('pnpm verify no longer runs audit-ui and check-tokens'); if (!read('.agents/scripts/gate.sh').includes('pnpm run verify')) throw new Error('the gate no longer runs the output contract'); diff --git a/src/content/chapters/agents.json b/src/content/chapters/agents.json index f5093a0..22f1971 100644 --- a/src/content/chapters/agents.json +++ b/src/content/chapters/agents.json @@ -2,57 +2,57 @@ "id": "agents", "eyebrow": { "en": "Subagent workflow", - "pt": "Subagent workflow" + "pt": "Fluxo de subagentes" }, "title": { "en": "One branch
per hand.", - "pt": "One branch
per hand." + "pt": "Uma branch
por mão." }, "lede": { "en": "Agents work when roles, files, and evidence are bounded. A worktree gives each worker its own checkout while the orchestrator protects intent.", - "pt": "Agents work when roles, files, and evidence are bounded. A worktree gives each worker its own checkout while the orchestrator protects intent." + "pt": "Agentes funcionam quando papéis, arquivos e evidências são delimitados. Um worktree dá a cada agente seu próprio checkout enquanto o orquestrador protege a intenção." }, "cards": [ { "label": { "en": "FRAME", - "pt": "FRAME" + "pt": "ENQUADRAR" }, "title": { "en": "Orchestrator", - "pt": "Orchestrator" + "pt": "Orquestrador" }, "copy": { "en": "Owns scope, task graph, boundaries, and integration.", - "pt": "Owns scope, task graph, boundaries, and integration." + "pt": "Dono do escopo, do grafo de tarefas, das fronteiras e da integração." } }, { "label": { "en": "HAND OFF", - "pt": "HAND OFF" + "pt": "PASSAR" }, "title": { "en": "Worker", - "pt": "Worker" + "pt": "Agente" }, "copy": { "en": "Owns one coherent slice and one worktree.", - "pt": "Owns one coherent slice and one worktree." + "pt": "Dono de uma fatia coerente e de um worktree." } }, { "label": { "en": "PROVE", - "pt": "PROVE" + "pt": "COMPROVAR" }, "title": { "en": "Verifier", - "pt": "Verifier" + "pt": "Verificador" }, "copy": { "en": "Re-runs gates and reports remaining gaps.", - "pt": "Re-runs gates and reports remaining gaps." + "pt": "Roda gates novamente e reporta o que ainda falta." } } ], @@ -60,29 +60,29 @@ { "eyebrow": { "en": "The tree", - "pt": "The tree" + "pt": "A árvore" }, "title": { "en": "Split at
the seam.", - "pt": "Split at
the seam." + "pt": "Divida na
costura." }, "panelLabel": { "en": "MAIN / ORCHESTRATOR", - "pt": "MAIN / ORCHESTRATOR" + "pt": "MAIN / ORQUESTRADOR" }, "panelCode": { "en": "├── agent/ui → components + visual states\n├── agent/tests → acceptance + regressions\n└── agent/docs → guide + examples\n\nmerge after each leaf returns a diff and evidence", - "pt": "├── agent/ui → components + visual states\n├── agent/tests → acceptance + regressions\n└── agent/docs → guide + examples\n\nmerge after each leaf returns a diff and evidence" + "pt": "├── agent/ui → componentes + estados visuais\n├── agent/tests → aceitação + regressões\n└── agent/docs → guia + exemplos\n\nfaça merge depois que cada folha devolver um diff e evidências" } }, { "eyebrow": { "en": "Handoff", - "pt": "Handoff" + "pt": "Passagem" }, "title": { "en": "Context that
can travel.", - "pt": "Context that
can travel." + "pt": "Contexto que
pode viajar." }, "steps": [ { @@ -92,27 +92,27 @@ }, "copy": { "en": "Goal, owned files, dependencies, non-goals, acceptance.", - "pt": "Goal, owned files, dependencies, non-goals, acceptance." + "pt": "Objetivo, arquivos sob sua posse, dependências, fora de escopo, aceitação." } }, { "label": { "en": "Isolation", - "pt": "Isolation" + "pt": "Isolamento" }, "copy": { "en": "One branch and worktree per independent change.", - "pt": "One branch and worktree per independent change." + "pt": "Uma branch e um worktree por mudança independente." } }, { "label": { "en": "Evidence", - "pt": "Evidence" + "pt": "Evidência" }, "copy": { "en": "Commands, result, changed files, screenshots, gaps.", - "pt": "Commands, result, changed files, screenshots, gaps." + "pt": "Comandos, resultado, arquivos alterados, capturas de tela, lacunas." } } ] diff --git a/src/content/chapters/landing.json b/src/content/chapters/landing.json index a51dd37..24874a2 100644 --- a/src/content/chapters/landing.json +++ b/src/content/chapters/landing.json @@ -1,83 +1,89 @@ { "id": "landing", - "eyebrow": { "en": "The short route", "pt": "The short route" }, - "title": { "en": "Ship the
system.", "pt": "Ship the
system." }, + "eyebrow": { + "en": "The short route", + "pt": "A rota curta" + }, + "title": { + "en": "Ship the
system.", + "pt": "Entregue o
sistema." + }, "lede": { "en": "Start with the map. Then open the one chapter that matches the decision in front of you: model, agent, worktree, skill, rule, or proof.", - "pt": "Start with the map. Then open the one chapter that matches the decision in front of you: model, agent, worktree, skill, rule, or proof." + "pt": "Comece pelo mapa. Depois abra o capítulo que combina com a decisão à sua frente: modelo, agente, worktree, skill, regra ou prova." }, "threadLabel": { "en": "THE THREAD", - "pt": "THE THREAD" + "pt": "O FIO" }, "threadText": { "en": "Frame uncertainty → isolate execution → preserve judgment → verify the change.", - "pt": "Frame uncertainty → isolate execution → preserve judgment → verify the change." + "pt": "Enquadre a incerteza → isole a execução → preserve o julgamento → verifique a mudança." }, "footer": { "en": "The route map is now the default entry. The full guide remains available whenever you want the whole narrative.", - "pt": "The route map is now the default entry. The full guide remains available whenever you want the whole narrative." + "pt": "O mapa de rotas é agora a entrada padrão. O guia completo segue disponível sempre que você quiser a narrativa inteira." }, "cards": [ { "label": { "en": "01", "pt": "01" }, - "title": { "en": "Models", "pt": "Models" }, + "title": { "en": "Models", "pt": "Modelos" }, "copy": { "en": "Capability and effort are separate knobs.", - "pt": "Capability and effort are separate knobs." + "pt": "Capacidade e esforço são controles separados." }, "href": "models/", - "cta": { "en": "Open chapter →", "pt": "Open chapter →" } + "cta": { "en": "Open chapter →", "pt": "Abrir capítulo →" } }, { "label": { "en": "02", "pt": "02" }, - "title": { "en": "Agents & trees", "pt": "Agents & trees" }, + "title": { "en": "Agents & trees", "pt": "Agentes e árvores" }, "copy": { "en": "Bound roles, handoffs, and worktrees.", - "pt": "Bound roles, handoffs, and worktrees." + "pt": "Limite papéis, handoffs e worktrees." }, "href": "agents/", - "cta": { "en": "Open chapter →", "pt": "Open chapter →" } + "cta": { "en": "Open chapter →", "pt": "Abrir capítulo →" } }, { "label": { "en": "03", "pt": "03" }, "title": { "en": "Skills", "pt": "Skills" }, "copy": { "en": "Capture repeatable decisions in small packages.", - "pt": "Capture repeatable decisions in small packages." + "pt": "Capture decisões repetíveis em pacotes pequenos." }, "href": "skills/", - "cta": { "en": "Open chapter →", "pt": "Open chapter →" } + "cta": { "en": "Open chapter →", "pt": "Abrir capítulo →" } }, { "label": { "en": "04", "pt": "04" }, - "title": { "en": "Rules", "pt": "Rules" }, + "title": { "en": "Rules", "pt": "Regras" }, "copy": { "en": "Connect guidance to enforcement.", - "pt": "Connect guidance to enforcement." + "pt": "Conecte orientação a enforcement." }, "href": "rules/", - "cta": { "en": "Open chapter →", "pt": "Open chapter →" } + "cta": { "en": "Open chapter →", "pt": "Abrir capítulo →" } }, { "label": { "en": "05", "pt": "05" }, - "title": { "en": "Hands-on", "pt": "Hands-on" }, + "title": { "en": "Hands-on", "pt": "Prática" }, "copy": { "en": "Compare a strong prompt with skill-enabled work.", - "pt": "Compare a strong prompt with skill-enabled work." + "pt": "Compare um prompt forte com trabalho assistido por skills." }, "href": "hands-on/starter/", - "cta": { "en": "Open lab →", "pt": "Open lab →" } + "cta": { "en": "Open lab →", "pt": "Abrir lab →" } }, { "label": { "en": "06", "pt": "06" }, - "title": { "en": "Review desk", "pt": "Review desk" }, + "title": { "en": "Review desk", "pt": "Mesa de revisão" }, "copy": { "en": "Browse original packages, references, scripts, and improvements.", - "pt": "Browse original packages, references, scripts, and improvements." + "pt": "Explore pacotes originais, referências, scripts e melhorias." }, "href": "skills-review/", - "cta": { "en": "Open desk →", "pt": "Open desk →" } + "cta": { "en": "Open desk →", "pt": "Abrir mesa →" } } ] } diff --git a/src/content/chapters/models.json b/src/content/chapters/models.json index 48842df..8857d82 100644 --- a/src/content/chapters/models.json +++ b/src/content/chapters/models.json @@ -2,57 +2,57 @@ "id": "models", "eyebrow": { "en": "Model routing", - "pt": "Model routing" + "pt": "Roteamento de modelos" }, "title": { "en": "Choose the
engine.", - "pt": "Choose the
engine." + "pt": "Escolha o
motor." }, "lede": { "en": "A model has a capability ceiling. Effort controls how much room it gets to reason. Route by uncertainty and verification cost.", - "pt": "A model has a capability ceiling. Effort controls how much room it gets to reason. Route by uncertainty and verification cost." + "pt": "Um modelo tem um teto de capacidade. O esforço controla quanto espaço ele ganha para raciocinar. Roteie por incerteza e custo de verificação." }, "cards": [ { "label": { "en": "LOW", - "pt": "LOW" + "pt": "BAIXO" }, "title": { "en": "Bounded rhythm", - "pt": "Bounded rhythm" + "pt": "Ritmo delimitado" }, "copy": { "en": "Lookup, small edits, formatting, and transformations with clear checks.", - "pt": "Lookup, small edits, formatting, and transformations with clear checks." + "pt": "Consultas, edições pequenas, formatação e transformações com checagens claras." } }, { "label": { "en": "MEDIUM", - "pt": "MEDIUM" + "pt": "MÉDIO" }, "title": { "en": "Default work", - "pt": "Default work" + "pt": "Trabalho padrão" }, "copy": { "en": "Normal implementation where the contract is clear but context matters.", - "pt": "Normal implementation where the contract is clear but context matters." + "pt": "Implementação normal em que o contrato é claro, mas o contexto importa." } }, { "label": { "en": "HIGH", - "pt": "HIGH" + "pt": "ALTO" }, "title": { "en": "Ambiguity", - "pt": "Ambiguity" + "pt": "Ambiguidade" }, "copy": { "en": "Planning, architecture, security judgment, and hard failures.", - "pt": "Planning, architecture, security judgment, and hard failures." + "pt": "Planejamento, arquitetura, julgamento de segurança e falhas difíceis." } } ], @@ -60,59 +60,59 @@ { "eyebrow": { "en": "Two knobs", - "pt": "Two knobs" + "pt": "Dois controles" }, "title": { "en": "Capability
× effort", - "pt": "Capability
× effort" + "pt": "Capacidade
× esforço" }, "panelLabel": { "en": "ROUTING RULE", - "pt": "ROUTING RULE" + "pt": "REGRA DE ROTEAMENTO" }, "panelCode": { "en": "strong model + high effort → frame ambiguity\nlight model + low effort → bounded execution\nraise one knob at a time → compare evidence", - "pt": "strong model + high effort → frame ambiguity\nlight model + low effort → bounded execution\nraise one knob at a time → compare evidence" + "pt": "modelo forte + esforço alto → enquadrar ambiguidade\nmodelo leve + esforço baixo → execução delimitada\nsuba um controle por vez → compare evidências" } }, { "eyebrow": { "en": "Sequence", - "pt": "Sequence" + "pt": "Sequência" }, "title": { "en": "Spend judgment
where it compounds.", - "pt": "Spend judgment
where it compounds." + "pt": "Invista julgamento
onde ele compensa." }, "steps": [ { "label": { "en": "Plan", - "pt": "Plan" + "pt": "Planejar" }, "copy": { "en": "Strong model: scope, risks, acceptance, and worktree split.", - "pt": "Strong model: scope, risks, acceptance, and worktree split." + "pt": "Modelo forte: escopo, riscos, aceitação e divisão de worktrees." } }, { "label": { "en": "Build", - "pt": "Build" + "pt": "Construir" }, "copy": { "en": "Focused worker: smallest context and lightest model that can pass.", - "pt": "Focused worker: smallest context and lightest model that can pass." + "pt": "Worker focado: o menor contexto e o modelo mais leve que passa." } }, { "label": { "en": "Review", - "pt": "Review" + "pt": "Revisar" }, "copy": { "en": "Independent pass when missed issues cost more than the call.", - "pt": "Independent pass when missed issues cost more than the call." + "pt": "Revisão independente quando erros perdidos custam mais que a chamada." } } ] diff --git a/src/content/chapters/skills.json b/src/content/chapters/skills.json index 06e11f3..6a54ed6 100644 --- a/src/content/chapters/skills.json +++ b/src/content/chapters/skills.json @@ -1,56 +1,56 @@ { "id": "skills", - "eyebrow": { "en": "Reusable judgment", "pt": "Reusable judgment" }, - "title": { "en": "Teach the
decision.", "pt": "Teach the
decision." }, + "eyebrow": { "en": "Reusable judgment", "pt": "Julgamento reutilizável" }, + "title": { "en": "Teach the
decision.", "pt": "Ensine a
decisão." }, "lede": { "en": "A skill changes behavior. Keep the trigger precise, put the workflow in SKILL.md, and move conditional facts, scripts, and examples into focused files.", - "pt": "A skill changes behavior. Keep the trigger precise, put the workflow in SKILL.md, and move conditional facts, scripts, and examples into focused files." + "pt": "Uma skill muda comportamento. Mantenha o gatilho preciso, coloque o workflow em SKILL.md e mova fatos condicionais, scripts e exemplos para arquivos focados." }, "sections": [ { - "eyebrow": { "en": "Package anatomy", "pt": "Package anatomy" }, + "eyebrow": { "en": "Package anatomy", "pt": "Anatomia do pacote" }, "title": { "en": "One job.
More than
one file.", - "pt": "One job.
More than
one file." + "pt": "Um trabalho.
Mais que
um arquivo." }, "copy": { "en": "Choose a file to see why it belongs in the package.", - "pt": "Choose a file to see why it belongs in the package." + "pt": "Escolha um arquivo para ver por que ele pertence ao pacote." } }, { - "eyebrow": { "en": "Create a skill", "pt": "Create a skill" }, + "eyebrow": { "en": "Create a skill", "pt": "Crie uma skill" }, "title": { "en": "Observe →
trigger →
validate", - "pt": "Observe →
trigger →
validate" + "pt": "Observe →
defina o gatilho →
valide" }, "steps": [ { - "label": { "en": "Observe friction", "pt": "Observe friction" }, + "label": { "en": "Observe friction", "pt": "Observe o atrito" }, "copy": { "en": "Find a repeated decision or failure.", - "pt": "Find a repeated decision or failure." + "pt": "Encontre uma decisão ou falha repetida." } }, { - "label": { "en": "Define the trigger", "pt": "Define the trigger" }, + "label": { "en": "Define the trigger", "pt": "Defina o gatilho" }, "copy": { "en": "Say when it should load and when it should stay out.", - "pt": "Say when it should load and when it should stay out." + "pt": "Diga quando deve carregar e quando deve ficar de fora." } }, { - "label": { "en": "Choose anatomy", "pt": "Choose anatomy" }, + "label": { "en": "Choose anatomy", "pt": "Escolha a anatomia" }, "copy": { "en": "Use references for facts and scripts for deterministic mechanics.", - "pt": "Use references for facts and scripts for deterministic mechanics." + "pt": "Use referências para fatos e scripts para mecânicas determinísticas." } }, { - "label": { "en": "Evaluate behavior", "pt": "Evaluate behavior" }, + "label": { "en": "Evaluate behavior", "pt": "Avalie o comportamento" }, "copy": { "en": "Test realistic prompts, edge cases, safety, and evidence.", - "pt": "Test realistic prompts, edge cases, safety, and evidence." + "pt": "Teste prompts realistas, casos extremos, segurança e evidência." } } ] diff --git a/src/content/chapters/summary.json b/src/content/chapters/summary.json index e003bef..221d54e 100644 --- a/src/content/chapters/summary.json +++ b/src/content/chapters/summary.json @@ -1,75 +1,135 @@ { "id": "summary", - "eyebrow": { "en": "Start here", "pt": "Start here" }, - "title": { "en": "Ship the
system.", "pt": "Ship the
system." }, + "eyebrow": { + "en": "Start here", + "pt": "Comece aqui" + }, + "title": { + "en": "Ship the
system.", + "pt": "Entregue o
sistema." + }, "lede": { "en": "This guide turns AI work into a shape: frame the problem, choose the model and agent, isolate changes, teach repeatable decisions, and verify the result.", - "pt": "This guide turns AI work into a shape: frame the problem, choose the model and agent, isolate changes, teach repeatable decisions, and verify the result." + "pt": "Este guia transforma trabalho com IA em uma forma: enquadre o problema, escolha o modelo e o agente, isole mudanças, ensine decisões repetíveis e verifique o resultado." }, "footer": { "en": "Each chapter stands alone; the order follows a real task becoming a reliable change.", - "pt": "Each chapter stands alone; the order follows a real task becoming a reliable change." + "pt": "Cada capítulo se sustenta sozinho; a ordem segue uma tarefa real se tornando uma mudança confiável." }, "cards": [ { - "label": { "en": "01", "pt": "01" }, - "title": { "en": "Models", "pt": "Models" }, + "label": { + "en": "01", + "pt": "01" + }, + "title": { + "en": "Models", + "pt": "Modelos" + }, "copy": { "en": "Capability and effort are separate knobs.", - "pt": "Capability and effort are separate knobs." + "pt": "Capacidade e esforço são controles separados." }, "href": "../models/", - "cta": { "en": "Open chapter →", "pt": "Open chapter →" } + "cta": { + "en": "Open chapter →", + "pt": "Abrir capítulo →" + } }, { - "label": { "en": "02", "pt": "02" }, - "title": { "en": "Agents & trees", "pt": "Agents & trees" }, + "label": { + "en": "02", + "pt": "02" + }, + "title": { + "en": "Agents & trees", + "pt": "Agentes e árvores" + }, "copy": { "en": "Bound roles, handoffs, and worktrees.", - "pt": "Bound roles, handoffs, and worktrees." + "pt": "Limite papéis, handoffs e worktrees." }, "href": "../agents/", - "cta": { "en": "Open chapter →", "pt": "Open chapter →" } + "cta": { + "en": "Open chapter →", + "pt": "Abrir capítulo →" + } }, { - "label": { "en": "03", "pt": "03" }, - "title": { "en": "Skills", "pt": "Skills" }, + "label": { + "en": "03", + "pt": "03" + }, + "title": { + "en": "Skills", + "pt": "Skills" + }, "copy": { "en": "Capture repeatable decisions.", - "pt": "Capture repeatable decisions." + "pt": "Capture decisões repetíveis." }, "href": "../skills/", - "cta": { "en": "Open chapter →", "pt": "Open chapter →" } + "cta": { + "en": "Open chapter →", + "pt": "Abrir capítulo →" + } }, { - "label": { "en": "04", "pt": "04" }, - "title": { "en": "Rules", "pt": "Rules" }, + "label": { + "en": "04", + "pt": "04" + }, + "title": { + "en": "Rules", + "pt": "Regras" + }, "copy": { "en": "Connect guidance to enforcement.", - "pt": "Connect guidance to enforcement." + "pt": "Conecte orientação a enforcement." }, "href": "../rules/", - "cta": { "en": "Open chapter →", "pt": "Open chapter →" } + "cta": { + "en": "Open chapter →", + "pt": "Abrir capítulo →" + } }, { - "label": { "en": "05", "pt": "05" }, - "title": { "en": "Practice", "pt": "Practice" }, + "label": { + "en": "05", + "pt": "05" + }, + "title": { + "en": "Practice", + "pt": "Prática" + }, "copy": { "en": "Compare prompts and skill-enabled runs.", - "pt": "Compare prompts and skill-enabled runs." + "pt": "Compare prompts e execuções com skills." }, "href": "../hands-on/starter/", - "cta": { "en": "Open lab →", "pt": "Open lab →" } + "cta": { + "en": "Open lab →", + "pt": "Abrir lab →" + } }, { - "label": { "en": "06", "pt": "06" }, - "title": { "en": "Review desk", "pt": "Review desk" }, + "label": { + "en": "06", + "pt": "06" + }, + "title": { + "en": "Review desk", + "pt": "Mesa de revisão" + }, "copy": { "en": "Browse original files and improved drafts.", - "pt": "Browse original files and improved drafts." + "pt": "Explore arquivos originais e rascunhos melhorados." }, "href": "../skills-review/", - "cta": { "en": "Open desk →", "pt": "Open desk →" } + "cta": { + "en": "Open desk →", + "pt": "Abrir mesa →" + } } ] }