Detalles de composición japonesa

Una línea de japonés no lleva espacios entre palabras y, sin embargo, un párrafo japonés compuesto con LaTeX sale justificado a ambos márgenes. El truco es un pegamento llamado \kanjiskip cuya anchura natural es cero pero que se estira: medido en jsarticle a 10pt vale 0.0pt plus 0.92473pt minus 0.0924pt. Casi siempre no está ahí; en cuanto una línea debe apretarse o soltarse, brota un poco entre cada par de caracteres. Lo que la composición occidental confía al espacio entre palabras, el japonés lo reparte finamente por cada junta de caracteres de la línea. Esta página recorre esa maquinaria —el pegamento japonés, las prohibiciones de corte (kinsoku), la escritura vertical y los ruby—, el aparato que TeX tuvo que construir para el japonés y que no tiene equivalente occidental, con cifras medidas en todo momento.

\kanjiskip y \xkanjiskip: el espacio que usted no escribió

La composición japonesa inserta automáticamente dos pegamentos distintos. \kanjiskip va entre dos caracteres japoneses; \xkanjiskip va en la frontera entre japonés y latino. La diferencia decisiva es su anchura natural: en jsarticle a 10pt, \kanjiskip vale 0.0pt plus 0.92473pt minus 0.0924pt y \xkanjiskip, 2.5pt plus 1.49994pt minus 0.59998pt. El primero es cero por defecto y solo se estira cuando hace falta, y por eso la retícula de caracteres se mantiene mientras las líneas siguen justificándose. El segundo mide siempre 2,5pt, y por eso al escribir 日本語 and abc se abre un hueco a ambos lados de la palabra latina aunque nadie haya pulsado la barra espaciadora. Distinguidos ambos, casi todas las discusiones sobre espaciado japonés se reducen a «¿de qué pegamento hablamos?».

latex
% measure it yourself: put this in the body and read the .log
\typeout{kanjiskip  = \the\kanjiskip}
\typeout{xkanjiskip = \the\xkanjiskip}
\sbox0{日本語テキスト}\typeout{plain = \the\wd0}
\sbox0{日本語ABCテキスト}\typeout{mixed = \the\wd0}
\sbox0{ABC}\typeout{latin = \the\wd0}

Al medir, las cifras encajan. En jsarticle a 10pt, 日本語テキスト mide 64,72778pt de ancho y ABC, 21,8056pt. Sumados dan 86,53338pt, pero 日本語ABCテキスト mide 91,53339pt. La diferencia de 5,00001pt son dos veces 2,5pt de \xkanjiskip, insertados entre 語 y A y entre C y テ. Como prueba, declare \noautoxspacing y vuelva a medir la misma caja: regresa a 86,53339pt, exactamente la suma. Y una más: 日本語 mide 27,74048pt, justo el triple de los 9,24683pt de un kanji suelto — \kanjiskip se sitúa entre esos caracteres y no añade anchura alguna, porque su tamaño natural es cero.

ParámetroEn el lado pTeXEn el lado LuaTeX-jaValor por defecto en jsarticle a 10pt
kanjiskip\kanjiskip=...\ltjsetparameter{kanjiskip=...}0.0pt plus 0.92473pt minus 0.0924pt
xkanjiskip\xkanjiskip=...\ltjsetparameter{xkanjiskip=...}2.5pt plus 1.49994pt minus 0.59998pt
prebreakpenalty\prebreakpenalty seguido de un carácter\ltjsetparameter{prebreakpenalty={...}}10000 para puntuación y cierres
postbreakpenalty\postbreakpenalty seguido de un carácter\ltjsetparameter{postbreakpenalty={...}}10000 para aperturas
jcharwidowpenalty\jcharwidowpenalty=...\ltjsetparameter{jcharwidowpenalty=...}500
inhibitxspcode\inhibitxspcode seguido de un carácter japonés\ltjsetparameter{jaxspmode={...}}2 en el paréntesis de apertura de ancho completo, 1 en los cierres y 。, 3 en los kanji
xspcode\xspcode seguido de un carácter latino\ltjsetparameter{alxspmode={...}}3 para A, 2 para ., 1 para (

Esos valores por defecto cambian con la clase, y eso es lo que da carácter a una página. La misma medición en jlreq da 0.0pt plus 2.5pt para \kanjiskip y 2.5pt plus 2.5pt minus 1.25pt para \xkanjiskip. Como un kanji en jlreq a 10pt mide exactamente 10pt, el estiramiento equivale a un cuarto de cuadratín: dos veces y media el décimo que permiten las jsclasses. jlreq está diseñada, pues, para justificar abriendo bastante más el espaciado entre caracteres, y el comportamiento al final de línea cambia de forma visible. Si un documento «se ve distinto» tras cambiar de clase, imprima antes esos dos valores con \typeout y compárelos.

Por qué los paréntesis de ancho completo no llevan hueco: anchos e \inhibitxspcode

Porque el propio paréntesis declara «por este lado, ningún hueco». \inhibitxspcode asigna a cada carácter japonés un valor de 0 a 3 que regula cómo puede engancharse \xkanjiskip; en jsarticle, el paréntesis de apertura de ancho completo ( lleva 2, el de cierre ) y el punto 。 llevan 1, y un kanji corriente lleva 3. La medición lo zanja: 日本語(ABC)テキスト da 105,02704pt, es decir nueve caracteres de ancho completo (9 × 9,24683pt) más los 21,8056pt de ABC: ni un solo \xkanjiskip. Los paréntesis de ancho completo ya llevan blanco dentro de su propio cuadratín; otros 2,5pt se notarían, así que el paréntesis los prohíbe. Respetar la convención de escritura —letras latinas y cifras en medio ancho, puntuación y paréntesis japoneses en ancho completo— no es solo cuestión de aspecto: es lo que permite que esta lógica de espaciado funcione. Cuele un ( de medio ancho en texto japonés y mandarán en su lugar las reglas de \xspcode (( lleva 1), con un espaciado muy distinto.

latex
% (u)pLaTeX: inspect and change how xkanjiskip attaches to one character
\typeout{open  paren = \the\inhibitxspcode`(}   % 2 in jsarticle
\typeout{close paren = \the\inhibitxspcode`)}   % 1 in jsarticle
\inhibitxspcode`(=3   % allow the gap on both sides after all

% LuaLaTeX: same idea, other name -- and NO space after the comma
\ltjsetparameter{jaxspmode={`(,preonly}}

Aquí está la trampa al trasladar ajustes entre pLaTeX y LuaLaTeX: los valores 1 y 2 de \inhibitxspcode están numerados al revés en el jaxspmode de LuaTeX-ja. La medición lo demuestra. En el lado pTeX, ponga a 1 el \inhibitxspcode del kanji 語 y el hueco desaparece de A語 (de 19,24684pt a 16,74684pt) mientras sobrevive en 語A. En LuaTeX-ja, ponga a 1 el jaxspmode del mismo carácter y ocurre lo contrario: el hueco se va de 語A (de 19,24713pt a 16,74713pt) y sobrevive en A語. El código fuente de LuaTeX-ja nombra sus modos: 1 es preonly y 2 es postonly, esto es, «permitir el hueco solo antes / solo después de este carácter japonés». El 1 de pTeX significa «solo después». Los dos sistemas coinciden en las palabras y se contradicen en los números. Copiar los ajustes mecánicamente coloca el hueco en el lado equivocado. Al portar, escriba los nombres preonly y postonly en lugar de las cifras. Una advertencia en el lado LuaTeX-ja: no ponga un espacio tras la coma. Con espacio, TeX Live 2024 avisa ! Missing number, treated as zero. y aplica 0 de todos modos: el hueco se suprime a ambos lados en vez de a uno.

Kinsoku: prohibir el corte con \prebreakpenalty y \postbreakpenalty

El kinsoku es la regla que mantiene ciertos caracteres fuera del inicio o el final de línea. La puntuación 。、, los cierres )」』 y los kana pequeños ゃ ぁ no pueden iniciar una línea; las aperturas (「『 no pueden terminarla. Qué carácter rehúye qué lado lo aportan las métricas de fuente japonesas (JFM) junto con la clase, y TeX lo implementa no como prohibición sino como penalización. Corte justo antes del punto 。 o del paréntesis de cierre ) y ese carácter cae al comienzo de la línea siguiente; por eso jsarticle fija tanto \prebreakpenalty。 como \prebreakpenalty) en 10000. Corte justo después del paréntesis de apertura ( y este queda huérfano al final de línea, así que \postbreakpenalty( vale también 10000. Por convención de TeX, 10000 es una penalización infinita, es decir, una prohibición absoluta. La virtud de construirlo así es que la prohibición admite grados: se escribe 10000 para «nunca» o 200 para «mejor no», y el algoritmo de corte lo sopesa con todo lo demás. La composición occidental no conoce siquiera la noción de kinsoku; es maquinaria que pTeX añadió a TeX.

latex
% read the shipped values, then relax one of them
\typeout{full stop  = \the\prebreakpenalty`。}   % 10000
\typeout{open paren = \the\postbreakpenalty`(}  % 10000
\prebreakpenalty`〜=200        % discourage, do not forbid
\jcharwidowpenalty=1000        % dislike a lone character on the last line

% the LuaTeX-ja spelling of the same three settings
\ltjsetparameter{prebreakpenalty={`〜, 200}}
\ltjsetparameter{jcharwidowpenalty=1000}

Al estar expresado como penalización, la composición japonesa pudo desarrollar un parámetro sin equivalente occidental alguno: \jcharwidowpenalty, cuyo valor por defecto es 500 tanto en jsarticle como en ltjsarticle. Pondera el caso de dejar un único carácter japonés varado en la última línea de un párrafo: la viuda, en versión japonesa. Lo importante es la moderación del valor: no es una prohibición absoluta, sino «vale la pena apretar un poco las demás líneas para evitarlo, pero no destrozar la página por ello». En la práctica, ante un párrafo que se empeña en terminar con un carácter solitario, pruebe \jcharwidowpenalty=1000 antes de reescribir nada. Si aun así no se resuelve, añadir o quitar un carácter de prosa suele ser la solución más rápida.

Cómo activar la escritura vertical: la opción tate y plext

Hoy se activa con una opción de clase. \documentclass[tate]{jlreq} funciona tanto con uplatex como con lualatex, y \documentclass[tate]{ltjsarticle} con LuaLaTeX. La familia pLaTeX incluye además clases verticales dedicadas, utarticle y utbook, que compilan tal cual con uplatex. La escritura vertical es especial para TeX no solo porque se intercambian la dirección de la línea y la del apilado, sino porque el mismo carácter exige otro glifo. La puntuación y los paréntesis deben recolocarse y girarse en composición vertical. Por eso pTeX lleva desde el principio dos familias de codificación de fuentes —JY para horizontal y JT para vertical— y, dentro de una caja declarada \tate, se elige automáticamente el lado JT. Nada de esto tiene equivalente en la composición occidental.

latex
% vertical writing, three ways that all compile on TeX Live 2024
\documentclass[tate,uplatex]{jlreq}     % uplatex; also works under lualatex
\documentclass[tate]{ltjsarticle}       % lualatex
\documentclass[uplatex]{utarticle}      % uplatex, dedicated vertical class

% tate-chu-yoko: a short horizontal run inside vertical text
平成\tatechuyoko{31}% jlreq only -- under uplatex or lualatex
平成\rensuji{31}% plext (pLaTeX) and lltjext (LuaTeX-ja)

% zw is the width of one full-width character, zh its height;
% \begin{minipage}<t>{10zw} sets a vertical box ten characters wide

Componer números de dos cifras o unidades erguidos y uno junto a otro dentro de texto vertical se llama tate-chu-yoko. La forma depende de la ruta. \tatechuyoko{31} lo define solo jlreq y funciona tanto con uplatex como con lualatex mientras se use jlreq; ltjsarticle no lo tiene, y allí \tatechuyoko produce ! Undefined control sequence. En LuaTeX-ja la forma es \rensuji{31}, que aporta lltjext (o las clases verticales ltjtarticle y ltjtbook); pLaTeX dispone del mismo \rensuji{31} en el paquete plext. plext fue la extensión de ASCII para la composición vertical; además de \rensuji se ocupa de tablas, cajas y su dirección de escritura: su rasgo distintivo es el argumento entre paréntesis angulares, como en \begin{minipage}<t>{10zw}, que declara explícitamente la dirección y es lo que hace falta para insertar una tabla horizontal en un documento vertical. lltjext es su contraparte en LuaTeX-ja, casi una transcripción tanto en nombres como en convenciones de argumentos. Si la vertical se resiste, compruebe primero si la clase acepta una opción tate y después si plext o lltjext está cargado.

Ruby (furigana) y puntos de énfasis: qué paquete elegir

La respuesta actual es: pxrubrica en (u)pLaTeX y luatexja-ruby en LuaLaTeX. Ambos se escriben \ruby{...}{...}, pero pxrubrica distingue las dos clases de ruby que definen JIS X 4051 y JLReq, y obliga a elegir. Una barra vertical divide la lectura carácter a carácter: \ruby{漢字}{かん|じ} es mono ruby, una lectura sobre cada kanji. El ruby de grupo, una sola tira de kana sobre todo el compuesto, hay que pedirlo expresamente: \ruby[g]{漢字}{かんじ}. Dele a una palabra de dos caracteres una lectura sin dividir, sin barra ni opción, y obtendrá ! Package pxrubrica Error: Group count mismatch between the ruby and the body (2 <> 1). Los puntos de énfasis salen del mismo paquete: \kenten{重要}. Para algo ligero basta el \ruby de okumacro, que acompaña a las jsclasses: siempre compone ruby de grupo, así que \ruby{漢字}{かんじ} funciona sin más. Conviene saber que CTAN aloja además un paquete llamado simplemente ruby —el de Werner Lemberg, procedente del paquete CJK, versión 4.8.5 en TeX Live 2024—, un linaje del todo distinto.

PaqueteRutaQué ofrece
pxrubricapLaTeX / upLaTeX / LuaLaTeX / XeLaTeXmono ruby frente a ruby de grupo, control del voladizo y puntos de énfasis con \kenten
luatexja-rubysolo LuaLaTeXruby integrado en LuaTeX-ja, que interfiere menos con el corte de líneas
okumacropLaTeX / upLaTeXviene con las jsclasses; \ruby y \kenten rápidos, sin sintaxis de división
rubyla familia del paquete CJK (pdfLaTeX y afines)el linaje aparte de Werner Lemberg; ajeno a la pila TeX japonesa, no lo mezcle
latex
\usepackage{pxrubrica}
...
\ruby{漢字}{かん|じ}     % mono ruby: the bar splits the reading per character
\ruby[g]{漢字}{かんじ}   % group ruby: one run over the word -- [g] is required
\kenten{重要}            % emphasis dots beside each character

He aquí un accidente que rompe sin producir ningún error. Tanto pxrubrica como okumacro definen \ruby, y cargar ambos no genera ni un aviso: el que llega segundo gana en silencio. Cargue okumacro después de pxrubrica y componga \ruby{漢字}{かん|じ}: la barra de かん|じ deja de leerse como separador de mono ruby y se imprime como una línea vertical de ancho completo (con pxrubrica solo, la lectura se reparte correctamente entre los dos kanji). En el registro no aparece nada, así que no se descubre hasta mirar el PDF. Cargue exactamente un paquete que defina \ruby. Si trabaja con jsclasses y ya carga okumacro, borre esa línea al pasar a pxrubrica.

Qué es JLReq: los «Requirements for Japanese Text Layout» del W3C y la clase jlreq

JLReq es el documento del W3C titulado «Requirements for Japanese Text Layout», una exposición sistemática y legible para quien implementa sobre el diseño de página japonés, la composición de líneas, las prohibiciones de corte, los ruby y el tratamiento de la puntuación. Hasta su aparición, ese conocimiento vivía como oficio acumulado de las imprentas, así que publicarlo importó: navegadores web y lectores de libros electrónicos se remiten hoy al mismo texto. La clase jlreq es ese documento implementado en LaTeX, escrita por Noriyuki Abe. El archivo de clase que acompaña a TeX Live 2024 indica en sus comentarios iniciales la edición que sigue: (based on JLReq 20200811). Elegir jlreq no es, por tanto, «tomar una clase más nueva»: es apoyar el diseño de la página en un documento público.

La consecuencia práctica es que uno deja de escribir los ajustes finos. La escritura vertical cabe en una opción tate, \jlreqsetup permite fijar por su nombre los parámetros de composición de línea, y los valores por defecto de kinsoku y ruby ya siguen JLReq. A la inversa, cambiar sin más un documento jsarticle existente a jlreq amplía el estiramiento de \kanjiskip, altera la densidad de las líneas y puede mover la paginación. Una frontera sensata: jlreq para un documento que empieza ahora, jsclasses cuando haya que preservar el aspecto de un manuscrito existente. En cualquier caso, \kanjiskip, \xkanjiskip, \prebreakpenalty y \jcharwidowpenalty existen con los mismos nombres, así que el último ajuste siempre queda en sus manos.