Revayat Novel — Tradução de livros Inglês → Persa
Execute as nove etapas abaixo em ordem. Cada uma é um comando mais uma regra sobre o que fazer com sua saída. Não improvise uma ordem diferente e não pule uma etapa porque a anterior pareceu boa.
Defina quatro variáveis uma vez e use-as em todos os lugares:
SKILL_DIR— a pasta que contém este arquivo. Em um plugin Claude Code é${CLAUDE_PLUGIN_ROOT}/skills/revayat-novel.WORK— uma pasta de trabalho para este livro, ex.:work/.PY— o interpretador Python. Resolva-o uma vez;python3não existe na maioria das instalações Windows, então uma linha de comando que o codifica funciona em duas plataformas de três:- macOS / Linux:
PY=python3 - Windows:
PY=python— ouPY="py -3"se o lançador é o que está instalado - se nenhum funcionar, o
doctorna etapa 1 não iniciará, e esse é o sinal
- macOS / Linux:
OCR_LANG— o código Tesseract para o idioma impresso no livro que você está traduzindo, não o idioma para o qual está traduzindo. Para o trabalho usual Inglês → Persa, isso éeng. Uma fonte Persa éfas; Alemãodeu, Francêsfra, Árabeara. O mesmo valor deve ser usado em cada etapa de OCR. Reconhecer páginas em inglês com o modelo persa retorna um absurdo de aparência confiante, o que é pior do que uma pontuação baixa porque nada a jusante consegue perceber.
Todo comando é $PY $SKILL_DIR/scripts/revayat-novel.py <estágio> ….
As cinco regras que nunca devem ser quebradas
- Nunca inverta texto persa para fazê-lo ler da direita para a esquerda. A direção é definida pelo construtor. Inverter produz um arquivo que está quebrado em todos os lugares, exceto em um visualizador.
- Nunca invente, descarte, mescle, divida ou reordene um cabeçalho
@@ id. Retorne exatamente aqueles que você recebeu. - Nunca descarte um marcador
[[fn:…]],**negrito**,*itálico*ou`verbatim`. Eles são contados; uma incompatibilidade falha no QA. - Nunca edite manualmente
book.jsonpara corrigir uma tradução. Corrija a planilha e execute a mesclagem novamente. - Nunca encurte o livro. Nada de resumir, pular uma frase difícil ou suavizar. Se uma etapa relatar conteúdo ausente, execute novamente aquele pedaço.
Etapa 1 — Verificar as ferramentas
$PY $SKILL_DIR/scripts/revayat-novel.py doctor
"ready": true→ continue."ready": false→ executepip install -r $SKILL_DIR/requirements.txt, depois executedoctornovamente.optional_toolsmostrandonot foundestá bem por enquanto. A etapa 2 dirá se OCR é realmente necessário.
Etapa 2 — Extrair
$PY $SKILL_DIR/scripts/revayat-novel.py extract "<arquivo de entrada>" --out $WORK --ocr-lang $OCR_LANG
$OCR_LANG é o idioma impresso no livro, definido uma vez acima. Errar aqui não é uma falha visível: OCR ainda retorna texto, é simplesmente o texto errado.
Leia o JSON que ele imprime e siga a tabela:
| O que você vê | O que fazer |
|---|---|
"kind": "digital" | nada; nenhum OCR foi necessário |
"kind": "scanned" ou "mixed" | OCR executou automaticamente; verifique se ocr.probe_after.text_share está acima de 0.7 |
| um erro nomeando OCRmyPDF | instale-o como a mensagem diz, depois execute esta etapa novamente |
clean_scan.cleaned acima de 0 | uma marca d'água colorida foi removida dessas páginas |
ocr.warning não é nulo | leia-o; o arquivo ainda estava utilizável, então continue |
page_scans_dropped acima de 0 | esse número de rasters de página inteira foram reconhecidos como a própria digitalização, não como imagens |
O limpador nunca edita seu arquivo: o original permanece intocado e a cópia limpa é escrita em $WORK/cleaned.pdf, com um registro por página em clean_scan do que foi removido e do que foi deixado em paz. Passe --clean-scan off para pular completamente, ou --clean-scan force quando um carimbo sobreviver.
Se o livro foi digitalizado, faça estas duas passagens extras agora.
Confiança de reconhecimento — sem ela, uma palavra lida incorretamente é indistinguível de uma correta, porque ambas são palavras comuns do idioma de origem, sentadas em uma frase gramatical. Nada mais adiante no pipeline consegue diferenciá-las, e o tradutor renderizará a errada fielmente.
$PY $SKILL_DIR/scripts/revayat-novel.py ocr-sidecar \
--pdf $WORK/ocr.pdf --out $WORK --lang $OCR_LANG --book $WORK/book.json
--lang aqui é o mesmo $OCR_LANG que você deu a extract. Tem que ser: esta passagem reconhece novamente as mesmas páginas para descobrir quão certa a engine estava, então um modelo diferente lê palavras diferentes e pontua algo que o livro não diz.
Isso escreve source.ocr.json — caixa, confiança e ordem de leitura para cada palavra, agregado até linha, bloco e página, mais qual pré-processamento foi executado — e source.ocr.txt, depois carimba cada bloco em book.json com a confiança da região de onde veio. Blocos classificados como low são relatados pelo qa check como ocr-low-confidence, e aceitar um significa olhar a imagem da página. Limiares padrão são 85 e 60 e mudam com --high / --low.
Ilustrações dentro de uma digitalização — uma página digitalizada é uma imagem plana, então uma fotografia nela não é uma imagem separada até que algo a encontre:
mineru -p $WORK/cleaned.pdf -o $WORK/mineru -b pipeline -l en
$PY $SKILL_DIR/scripts/revayat-novel.py extract "<arquivo de entrada>" --out $WORK \
--figures-from-mineru $WORK/mineru
O -l do MinerU usa seus próprios códigos, não os do Tesseract: en para uma fonte em inglês, arabic para escrita persa ou árabe. Combine-o com o livro, da mesma forma que $OCR_LANG é combinado — a detecção de layout usa a escrita para segmentar a página.
Execute o MinerU em cleaned.pdf, não no original, ou ele cortará a marca d'água como se fosse uma figura. Pegue apenas as imagens do MinerU. Medido em uma digitalização persa real, seu próprio texto reconhecido voltou com as palavras e as letras dentro delas invertidas, enquanto o Tesseract leu a mesma página corretamente — então o texto continua vindo da passagem de OCR acima e o MinerU é usado apenas para a única coisa que o OCR não pode fazer, que é encontrar onde uma imagem está em um raster plano. Use --figures-page-offset N quando o MinerU foi executado em um intervalo de páginas.
Depois olhe o resultado antes de prosseguir:
$PY $SKILL_DIR/scripts/revayat-novel.py qa check --book $WORK/book.json --allow-incomplete
Ignore untranslated-block aqui — nada está traduzido ainda. Você está procurando por asset-missing. Se stats.text_blocks estiver abaixo de 20 para um livro real, a extração falhou: veja references/extraction.md.
Etapa 3 — Glossário
$PY $SKILL_DIR/scripts/revayat-novel.py glossary scan \
--book $WORK/book.json --out $WORK/glossary.json
O relatório lista needs_persian, mais frequentes primeiro. Abra $WORK/glossary.json e para cada uma das primeiras 20 entradas preencha quatro campos:
"target": "الیزابت بنت",
"later_form": "الیزابت بنت",
"first_form": "الیزابت بنت (Elizabeth Bennet)",
"locked": true
Quando uma entrada tem aliases — um sobrenome ou nome que o livro usa sozinho — coloque seu persa em alias_targets:
"aliases": ["Ashcroft", "Margaret"],
"alias_targets": ["اشکرافت", "مارگارت"]
Onde a fonte diz apenas «Ashcroft», o persa deve dizer apenas «اشکرافت». Deixar isso vazio faz a verificação de deriva exigir o nome completo toda vez, o que é tanto pior persa quanto um falso alarme.
Deixe first_block_id exatamente como está — o pipeline o usa para decidir qual único pedaço introduz o nome. Não o edite e não decida primeiras menções você mesmo.
Exclua entradas que não são nomes reais. Depois continue.
Etapa 4 — Dividir em planilhas
Um romance inteiro nunca deve alcançar um contexto de modelo, então ele é dividido primeiro. Existem duas maneiras de dividir, e a fonte decide qual — isso não é uma preferência:
| Fonte | Rota |
|---|---|
| PDF, nato-digital ou digitalizado | por página — abaixo |
| EPUB, DOCX, texto simples | por orçamento de caracteres — etapa 4b |
Divida um PDF por página. Uma página é um limite que o livro já tem: estável entre execuções, a unidade que um revisor olha, e a única unidade com a qual uma página renderizada pode ser comparada. Uma planilha dividida por orçamento de caracteres quebra onde o orçamento acaba, que não é lugar nenhum em particular — e uma página que não existe na fonte não pode ser verificada contra a fonte. Os formatos abaixo da linha não têm páginas próprias para dividir, então eles pegam a rota do orçamento e abrem mão dessa verificação.
$PY $SKILL_DIR/scripts/revayat-novel.py pages build \
--book $WORK/book.json --out $WORK/pages --glossary $WORK/glossary.json
Isso escreve uma planilha por página de origem — page0001.md, e sua tradução vai em out_page0001.md ao lado dela. Use esses nomes, não o chunkNNNN.md da etapa 5: o formato é idêntico, apenas os nomes de arquivo diferem, e pages next diz exatamente qual arquivo abrir, então não há nada para adivinhar.
Também escreve $WORK/pages/source/page-0001.pdf — cada página de origem como seu próprio PDF, copiado em vez de re-renderizado para que caixas, rotação e qualidade de imagem sejam as do livro. O manifesto registra cada uma com seu SHA-256 e nomeia o reference_pdf do qual toda a execução foi lida. Leia o PDF de origem do manifesto; é o original para um livro nato-digital e a cópia com OCR para uma digitalização, e codificar um ou outro está errado para o outro.
Cada trabalho de página carrega apenas o que precisa: as linhas do glossário que se aplicam naquela página, as vozes que falam ali, as palavras das quais o OCR não tinha certeza ali, e uma fatia limitada das páginas vizinhas marcadas como não traduzir. Uma página cujo próprio texto excede o orçamento é dividida em partes numeradas em vez de truncada — part e parts no manifesto dizem isso — e as partes se reúnem antes que a página seja julgada.
Um parágrafo que a quebra de página cortou ao meio pertence à página em que começou e é traduzido exatamente uma vez; a página na qual ele continua o vê apenas como contexto. Nunca traduza um bloco que aparece sob o cabeçalho de contexto vizinho — ele já pertence à planilha de outra página.
$PY $SKILL_DIR/scripts/revayat-novel.py pages status --pages $WORK/pages
$PY $SKILL_DIR/scripts/revayat-novel.py pages next --pages $WORK/pages
status relata o estado de cada página; next nomeia a primeira página ainda a fazer, para que uma execução interrompida retome onde parou, em vez de do início.
O loop de páginas
O PDF de origem é qualquer um do qual esta execução foi lida: o próprio livro para um PDF nato-digital, a cópia com OCR para uma digitalização. O manifesto o registrou — pegue-o de lá em vez de nomear um arquivo que pode não existir.
SOURCE_PDF=$($PY -c "import json,sys;print(json.load(open(sys.argv[1]))['reference_pdf'])" $WORK/pages/manifest.json)
Uma página de cada vez, nesta ordem. Cada comando precisa do que o anterior produziu, então uma etapa tomada cedo simplesmente recusa:
P=12 # o que quer que `pages next` tenha nomeado
# 3. dobrar a tradução no livro
$PY $SKILL_DIR/scripts/revayat-novel.py pages merge \
--book $WORK/book.json --pages $WORK/pages --page $P --glossary $WORK/glossary.json
# 4. dispor aquela página sozinha
$PY $SKILL_DIR/scripts/revayat-novel.py pages preview \
--book $WORK/book.json --pages $WORK/pages --page $P
# 5. compará-la com a página de origem
$PY $SKILL_DIR/scripts/revayat-novel.py render-qa \
--book $WORK/book.json --work $WORK --page $P \
--docx $WORK/previews/page-0012.docx --source-pdf $SOURCE_PDF
# 6. olhar para as duas imagens (a etapa 8 diz o que procurar)
$PY $SKILL_DIR/scripts/revayat-novel.py pages review \
--pages $WORK/pages --page $P \
--answer figure-placement=yes --answer script-integrity=yes \
--answer no-source-language=yes --answer hierarchy=yes \
--answer reads-as-a-book=yes --note "o que você viu"
# 7. só agora
$PY $SKILL_DIR/scripts/revayat-novel.py pages accept \
--book $WORK/book.json --pages $WORK/pages --page $P
Depois pages next novamente, até que diga que não há mais nada.
A etapa 4 não é opcional e a etapa 5 fará isso por você se você a pular — deixe --docx de fora e render-qa constrói a pré-visualização sozinha. O comando explícito está lá para quando você quiser abrir a página no Word e olhar você mesmo.
A pré-visualização é uma página de origem, disposta sozinha. Ela não é de forma alguma o livro inteiro: o persa flui novamente, então a página 12 de origem não se torna a página 12 do livro, e no meio de um romance o desvio é de várias páginas. Verificar a décima segunda folha do livro contra as expectativas da página 12 relata uma página correta como faltando todo o seu texto e carregando o de seu vizinho. A pré-visualização é configurada com o construtor de produção — mesmos estilos, fontes, RTL, dimensionamento de imagem, lógica de cabeçalho — então o que você está vendo é a tipografia real do conteúdo real.
Uma página cujo persa é mais longo que seu inglês sai como duas folhas. Isso é comum, ambas são mantidas como renders/target/page-0012.png e page-0012-2.png, e o QA lê todas.
accept recusa a menos que cada porta tenha realmente passado — ele lê a evidência em vez de aceitar sua palavra, então uma página não pode ser marcada como concluída por afirmar que é. Ele quer quatro coisas: persa no livro para cada unidade que a página enviou, uma passagem de render QA no registro de execução, um relatório que ainda diz isso, e uma revisão visual atual.
Reconstruir é seguro e nunca joga uma tradução fora. Uma página cujo texto de origem mudou desde que foi cortada pela última vez é listada sob invalidated — essas, e apenas essas, precisam ser traduzidas novamente. Uma planilha deixada de uma reconstrução com um orçamento diferente é listada sob orphaned: ainda está no disco, mas nada a lê mais, então sua tradução não alcançará o livro.
Etapa 4b — Quando a fonte não tem páginas
Apenas EPUB, DOCX e texto simples. Para um PDF, use a etapa 4.
$PY $SKILL_DIR/scripts/revayat-novel.py chunk build \
--book $WORK/book.json --out $WORK/chunks --glossary $WORK/glossary.json
Observe o número de pedaços. Cada um se torna uma tarefa de tradução.
Se você já traduziu algumas planilhas e uma entrada mudou desde então, isso recusa com "refused": "stale-worksheets" em vez de silenciosamente entregar planilhas que não correspondem mais ao livro. O resto do conteúdo foi truncado para tradução.