Subtítulos en chino para video — traducir y grabar
Toma un video en inglés que ya existe en disco y produce una versión con subtítulos duros (quemados) en chino simplificado, además de un archivo SRT correspondiente.
La descarga queda deliberadamente fuera del alcance. Se asume que el MP4 de origen ya está presente.
El pipeline es independiente del tema: se construyó a partir de un video de 22 minutos sobre movimiento en Apex, pero nada en los scripts sabe ni le importa qué contenido es el video. Lo que cambia por video es el glosario y la posición de la banda de subtítulos.
Cómo se ve un buen resultado
La persona que usa esto se preocupa por una apariencia específica y ya definida. No son valores predeterminados que se deban reconsiderar cada vez: se llegó a ellos iterando sobre resultados reales, y cambiarlos sin aviso se tratará como una regresión.
- Solo chino simplificado. Nunca chino tradicional. Verificar antes de entregar.
- Una línea por subtítulo, siempre. Los subtítulos de dos líneas son la queja más común. Si una línea es demasiado larga, divídela en dos subtítulos secuenciales en lugar de envolverla.
build_srt.pylo exige. - Subtítulos cortos. "Una línea" no es licencia para una línea muy ancha. Apunta a un ancho renderizado de aproximadamente 1100 px como máximo (aproximadamente el 57 % del cuadro a 1080p).
- Sin caja de fondo. Texto blanco, trazo duro oscuro, sombra suave oscura.
- Source Han Sans Bold / 思源黑体 (incluida en
assets/NotoSansSC-Bold.ttf). Recta y pesada, con caracteres latinos fuertes; este estilo de video está lleno de jerga en inglés dentro de oraciones en chino, y una fuente decorativa maneja eso mal. - La jerga que la comunidad realmente dice en inglés se mantiene en inglés. Qué términos son esos es una cuestión por tema, y es lo que responden los glosarios.
- Las tarjetas de capítulos grabadas obtienen una línea en chino debajo, no encima.
Flujo de trabajo
1. Analizar el origen y elegir un glosario
ffprobe -v error -show_entries format=duration -show_entries stream=codec_type,codec_name,width,height,r_frame_rate -of default=nw=1 source.mp4
Anotar duración y FPS exactamente: cada paso posterior depende de ellos.
Luego determinar de qué trata el video y leer references/glossaries/README.md, que dirige al archivo correcto y dice qué secciones leer. Leer la sección 字幕使用原则 del glosario emparejado en su totalidad antes de traducir: es breve y es donde residen las convenciones para ese juego.
Incluidos: Apex Legends, Warframe, osu!, Minecraft 速通/MCSR, StarCraft 星际争霸, Counter-Strike 反恐精英, ARC Raiders.
Si no hay glosario para este video, ese es el caso normal. Traducir contra nombres oficiales simplificados verificables, mantener una lista de los términos que se tuvieron que decidir y entregar esa lista al final. Si un término no tiene nombre chino oficial, usar una traducción descriptiva y decir que no es oficial; no presentar una suposición como definitiva. Nunca inventar un nombre para algo que ya tiene uno.
2. Obtener una transcripción en inglés con marcas de tiempo
Si el video proviene de YouTube, sus subtítulos automáticos son una base utilizable: yt-dlp --write-auto-subs --sub-langs "en.*" --skip-download. Son subtítulos continuos con etiquetas de tiempo a nivel de palabra, así que deduplicarlos en segmentos de oraciones.
Los subtítulos automáticos distorsionan la jerga gravemente y debes repararla mientras traduces. El ASR transcribe fonéticamente contra un modelo de inglés general, por lo que cada término del dominio que no sea una palabra común vuelve como una palabra incorrecta plausible. Ejemplos reales de imágenes de movimiento en Apex: "forward rez/raft/raz" → RAS, "Neor strafe" → Neo strafe, "pedo strafe" → Pito strafe, "mantel boost" → mantle boost, "alerts" → lurches, "my VO was so high" → my velo (velocity), "I couldn't attach out of that" → couldn't tap-strafe out of that. Esperar la misma clase de daño en cualquier video con mucha jerga: el glosario es lo que permite reconocerlo.
Cuando el habla es genuinamente irrecuperable (puntas musicales, gritos superpuestos), dejar zh vacío para ese segmento para que se elimine, e informar al usuario qué marcas de tiempo se eliminaron. Inventar una línea plausible es peor que no tener ninguna línea.
3. Traducir a un JSON de segmentos
[{"i": 1, "start": 0.24, "end": 4.90,
"en": "Seeing movement players pull off tricks like these is super cool and all, but",
"zh": "看身法玩家秀出这种操作确实很酷,但真正的问题是"}]
Mantener en; no es decorativo. build_srt.py lo usa para distinguir una continuación de oración de una emisión separada al decidir si dos subtítulos pueden fusionarse, lo que evita continuaciones como 算了好 o 是,长官你好啊.
4. Construir el SRT
python scripts/build_srt.py segments.json sub.srt --font assets/NotoSansSC-Bold.ttf
Imprime un informe. Tratar los valores distintos de cero en overlaps, multiline, latin_cjk_runons o term_split_across_cues como errores que corregir antes de codificar. Unos pocos subtítulos under_0.35s están bien cuando son interjecciones de 1 a 3 caracteres; verificarlos, no asumir.
5. Encontrar y traducir tarjetas de capítulos grabadas
python scripts/find_chapters.py source.mp4
Los creadores a menudo graban tarjetas de capítulos en el video en lugar de usar los capítulos de YouTube, por lo que los metadatos no muestran ninguno. Esto informa ventanas candidatas; extraer un fotograma de cada una y leer el texto real de la tarjeta antes de escribir la traducción. Generar chapters.json: [{"start":42,"end":46,"zh":"第 1 章:定义 lurch 组合"}].
6. Verificar lugares donde los subtítulos chocarían con texto en pantalla
Las tarjetas de cierre son el infractor habitual: los subtítulos en la posición normal caen sobre las redes sociales del creador. Extraer un fotograma, encontrar el hueco y declararlo:
[{"from": 1334.0, "to": 100000, "bottom": 820}]
La banda de subtítulos predeterminada se sitúa sobre el HUD típico de un FPS. Un juego diferente, o imágenes no relacionadas con juegos, pueden colocar sus propios elementos allí: un minimapa de MOBA, la línea de juicio de un juego rítmico, el tercio inferior de una charla. Extraer un fotograma y mirar antes de aceptar el valor predeterminado.
7. Construir la superposición y codificar
python scripts/build_overlay.py sub.srt ov --font assets/NotoSansSC-Bold.ttf \
--duration 1354.351 --chapters chapters.json --avoid avoid.json
python scripts/burn_in.py source.mp4 ov/concat.txt out.mp4
Verificar que la desviación reportada de la superposición sea de unos milisegundos, no cientos.
Antes de comprometerse con una codificación de ~20 minutos, componer un PNG de superposición sobre un fotograma real en PIL y mirarlo. Cuesta segundos y detecta errores de posición y fuente que de otro modo aparecerían 20 minutos después.
8. Verificar
python scripts/verify.py out.mp4 --expect-frames <frames> \
--contact-sheet sheet.jpg --at 75 300 660 945 1340
Mirar la hoja. Confirmar: líneas individuales, legibles sobre fotogramas brillantes, líneas de capítulos debajo de sus tarjetas, nada chocando con HUD o texto de cierre.
9. Correcciones posteriores: empalmar, no recodificar
Cuando el usuario pida cambiar algunas líneas (lo hará), reconstruir el SRT, compararlo con el anterior para encontrar qué subtítulos cambiaron, luego:
python scripts/splice.py out.mp4 source.mp4 sub.srt out_fixed.mp4 \
--font assets/NotoSansSC-Bold.ttf --change-from 310 --change-to 316 \
--duration 1354.351 --chapters chapters.json --avoid avoid.json
python scripts/verify.py out_fixed.mp4 --expect-frames <frames> --seams 310 316
15 segundos en lugar de 20 minutos. El recuento de fotogramas debe salir idéntico.
Entregables
Junto con out.mp4, entregar el SRT (diálogo más líneas de capítulos, fusionados y renumerados) para que los subtítulos puedan editarse más tarde sin rehacer el trabajo. Ofrecer también un título y descripción en chino; si el video es una republicación, mencionar que la descripción en primera persona original implica autoría, y que los bloques de atribución musical deben permanecer en su inglés original porque la licencia requiere esa forma exacta.
Si se tuvieron que resolver términos que no estaban en un glosario, listarlos. Un término decidido una vez y escrito vale más que la misma decisión tomada de manera diferente la próxima vez; references/glossaries/README.md dice cómo convertir una lista así en un archivo de glosario.
Material de referencia
references/glossaries/README.md: qué glosario leer, qué secciones del mismo y qué hacer cuando el video no tiene ninguno. Comenzar aquí.references/glossaries/*.md: los glosarios en sí. Grandes. Leer la sección de principios y las secciones relevantes; buscar términos individuales con grep.references/pipeline.md: notas técnicas y las trampas específicas de este pipeline. Leerlo antes de depurar cualquier cosa que parezca un problema de sincronización, empalme o renderizado; la mayoría ya se han diagnosticado una vez.