Friday, September 21, 2007

Interleaving Text in TEX

I wanted to be able to take an untranslated paragraph and typeset it with an interleaved translation. I wasn't able to find anything after much fruitless searching, so I decided to take a stab at it myself. At first it was sufficient to use

$\stackrel{\mbox{Translated text}}{\mbox{Untranslated text}}$
But, because it uses mboxes, that construction doesn't line break, leading it to run off the edge of the page if either text exceeds one line in length.

After some monkeying around and reading The TEXbook I was able to come up with a solution which interleaves the translated and untranslated text, one line at a time. The final result looks pretty good if I do say so myself.

Presented in the hopes that it'll save someone else some time:

%% Macro used for displaying translated speech. Translation is arg 1, untranslated speech is arg 2.

\newcommand{\translate}[2]{
% Various boxes
\newbox\current     % Temporary storage for boxes split off from translated and untranslated text
\newbox\transrest   % Box holding translated text
\newbox\plainrest   % Box holding untranslated text
% Create a box holding the translated text
\setbox\transrest=\vbox{\vskip\lineskip\small\emph{#1}}
% Create a box holding the untranslated text
\setbox\plainrest=\vbox{\vskip\lineskip#2}
% Add a little space before first line of new paragraph.
\vskip 3pt
% Iterate, stripping single lines off of the top of both boxes, until the untranslated box is empty.
\loop
% Is there still text in \plainrest?
\ifvbox\plainrest
% Split off top line of translated text
\setbox\current=\vsplit\transrest to \baselineskip
% and dump it out.
\unvbox\current
% Split off top line of untranslated text
\setbox\current=\vsplit\plainrest to \baselineskip
% and dump it out.
\unvbox\current
\repeat
}