hyperref links break with pdftex + babel + Hebrew (or right-to-left language)

1,985

Solution 1

This is not an answer. I was able to produce the minimal working example as:

\documentclass{article}
\usepackage{hyperref}
\TeXXeTstate=1
\def\neweverypar{{\setbox0\lastbox\beginR\usebox0}}
\let\origeverypar=\everypar
\def\everypar#1{\origeverypar{\neweverypar#1}}
\begin{document}
This is \href{http://google.com}{Google} and ...
\end{document}

after runing pdflatex on this, you get exactly the same error message. I have also forwared this to Heiko Oberdiek and if he answers me, then I post his answer here but I think this actually seems to be a limitation of the pdfTeX engine with TeX--XeT algorithm (the algorithm already have many annoying bugs) and it may turn out that this is not even fixable. XeTeX and PDFTeX both uses TeX--XeT but hyperref with PDFTeX uses PDFTeX primitives for hypertext and in XeTeX, it uses \special.

Edit: This is verbatim response of Heiko Oberdiek:

I don't know. AFAIK there isn't even an easy way to test, whether \beginR or \beginL is active. A workaround could be to put two labels with some distance to find out the writing direction, thus that the order of \pdfstartlink and \pdfendlink could be switched if necessary. But that kind of workaround does not scale, the hash table size in TeX is limited, large document with many links will too easily hit the limit.

In LuaTeX the node lists can be examined and the switches can be done at Lua level.

I also asked him, why this problem happens with PDFTeX and not with XeTeX. Here is his response:

Perhaps the \specials are resorted automatically in xdvipdfmx.

Solution 2

use bidi package with xelatex. You can perhaps apply bidi changes to pdfTeX too (xetex and pdftex both use etex for bidi typesetting so there should not be a problem). I slightly changed your example to use polyglossia (hence using bidi):

\documentclass{article}
\usepackage{hyperref}
\usepackage{polyglossia}
\setmainlanguage{english}
\setotherlanguage{hebrew}
\newfontfamily\hebrewfont[Script=Hebrew]{Ezra SIL} % from SIL
\begin{document}
\section{A section}
\label{mysection}
LTR English reference \autoref{mysection}. And now in RTL Hebrew:

\begin{hebrew}
הוא פשוט טקסט גולמי של תעשיית ההדפסה וההקלדה. Lorem Ipsum היה טקסט סטנדרטי עוד במאה ה-16, כאשר הדפסה לא ידועה לקחה מגש של דפוס ועירבלה אותו כדי ליצור סוג של ספר דגימה. ספר זה שרד לא רק חמש מאות שנים אלא גם את הקפיצה לתוך ההדפסה
\autoref{mysection}
יש המון גרסאות זמינות לפסקאות של . אבל רובם עברו שינויים בצורה זו או אחרת, על ידי השתלת הומור או מילים אקראיות שלא נראות אפילו מעט אמינות. אם אתה הולך להשתמש במקטעים של של Lorem Ipsum אתה צריך להיות בטוח שאין משהו מביך חבוי בתוך 
\end{hebrew}
\end{document}

and the result is shown below:

enter image description here

Solution 3

hyperref provides commands for referencing without creating hyperlinks, such as \ref* and \autoref*.

Your example is compilable if I use \autoref*:

\selectlanguage{hebrew}
\autoref*{mysection}

hebrew autoref example

You even could switch off hyperlinking for parts of the document, such as by

\makeatletter
\newcommand*{\disablehref}{%
  \let\ref\@refstar
  \DeclareRobustCommand*{\autoref}{\HyRef@autoref\@gobbletwo}}
\makeatother

Use it in a group or environment, to limit the effect, or create a similar macro \enablehref.

And here's a macro \disablehyperlinks, which works similar like the draft option of hyperref, disabling hyperlinks. So \autoref, \ref, \cite and \url work with Hebrew. Again, use it in a group or environment to limit the effect. Code and combined example:

\documentclass{article}
\usepackage[hebrew,english]{babel}
\usepackage{hyperref}
\makeatletter
\newcommand*{\disablehyperlinks}{
  % This is is for compatibility for hyperref versions 6.82d and older
  \@ifundefined{Hy@xspace@end}{
    \let\Hy@xspace@end\relax
  }{}
  \let\hyper@@anchor\@gobble
  \def\hyper@link##1##2##3{##3\Hy@xspace@end}%
  \def\hyper@anchorstart##1##2{##2\Hy@xspace@end}%
  \def\hyper@anchorend{\Hy@xspace@end}%
  \let\hyper@linkstart\@gobbletwo
  \def\hyper@linkend{\Hy@xspace@end}%
  \def\hyper@linkurl##1##2{##1\Hy@xspace@end}%
  \def\hyper@linkfile##1##2##3{##1\Hy@xspace@end}%
  \def\hyper@link@[##1]##2##3##4{##4\Hy@xspace@end}%
}
\makeatother
\begin{document}
\section{A section}
\label{mysection}
LTR English cite \cite{MYSRC} in \autoref{mysection} on \url{tex.stackexchange.com}.
And now in RTL Hebrew:

\begingroup
\disablehyperlinks
\selectlanguage{hebrew}
\cite{MYSRC}

\autoref{mysection}

\url{tex.stackexchange.com}

\endgroup
\selectlanguage{english}
Now again LTR English cite \cite{MYSRC} in \autoref{mysection} on
\url{tex.stackexchange.com}.
\begin{thebibliography}{MYSRC}
\bibitem[MYSRC01]{MYSRC}
The bibliography entry for MYSRC.
\end{thebibliography}
\end{document}

Hebrew with disabled hyperlinks

Share:
1,985

Related videos on Youtube

einpoklum
Author by

einpoklum

Updated on February 17, 2020

Comments

  • einpoklum
    einpoklum over 3 years

    Using the babel package to write Hebrew text exposes incompatibilities with all sorts of other packages. This questions is about the incompatibility with hyperref.

    Basically, you can't get links with right-to-left text. It's about the direction rather than the non-Latin language - somehow the link-start command is placed at the end due to some sort of reversal. The problem is described in Guy Rutenberg's blog, here.

    Here's an MWEs for \cite and \ref:

    \documentclass{article}
    \usepackage[hebrew,english]{babel}
    \usepackage{hyperref}
    \begin{document}
    \section{A section}
    \label{mysection}
    LTR English cite \cite{MYSRC}. And now in RTL Hebrew:
    
    \selectlanguage{hebrew}
    \cite{MYSRC}
    \selectlanguage{english}
    
    Let's refer to the current section:
    
    \selectlanguage{hebrew}
    \ref{mysection}
    
    \begin{thebibliography}{MYSRC}
    \bibitem[MYSRC01]{MYSRC}
    The bibliography entry for MYSRC.
    \end{thebibliography}
    \end{document}
    

    For both of these (and for \autoref), you get:

    ! pdfTeX error (ext4): pdf_link_stack empty, \pdfendlink used without \pdfstart
    link?.
    \AtBegShi@Output ...ipout \box \AtBeginShipoutBox 
                                                      \fi \fi 
    

    Notes:

    • Vafa Khaligi's comment below may be useful in isolating the minimum offending code out of everything 'babel' does, although I can't say for sure.
    • The blog entry I linked to has a workaround - which only works with xetex. Can it be adapted somehow?
    • Stefan Kottwitz suggested a workaround which won a bounty on this question. But what I would really like is to make hyperref get such links correctly somehow.
    • Ulrike Fischer
      Ulrike Fischer about 12 years
      I would suggest to write your question in a group where Heiko Oberdiek is reading (e.g. c.t.t).
    • lockstep
      lockstep almost 12 years
      You already got +5 reputation back from me. ;-)
    • doncherry
      doncherry almost 12 years
      @Ulrike: Do you happen to know why Heiko isn't on tex.sx? @ Eyal: The maximum amount of rep any user can offer as a bounty is 500; Stefan and Martin, however, have never offered more than 200.
    • IRAN
      IRAN almost 12 years
      One question, is not it possible that instead running pdflatex on your document, you run xelatex. I am not saying that change your document or use any XeTeX-specific packages but keep your original document (without modifying it) but instead running pdflatex on it, run xelatex on it.
    • einpoklum
      einpoklum almost 12 years
      @VafaKhalighi: Hmm. Interesting. I just tried running xelatex on my thesis, and it actually compiled (!) only problem was that the Hebrew was replaced with gibberish/empty space, and lots of WARNINGs. Maybe I could make xelatex+babel+Hebrew work somehow, then use the xetex workaround.
  • einpoklum
    einpoklum about 12 years
    I can't switch my document, because of all sorts of constraints I can't go into and are more social than technical. I know that there's a workaround when I use bidi+xetex. My question is what can I do with pdftex. Are you saying I can just add the bidi package? I'm kind of assuming it'll create problems either with babel, or with things which conflict/have issues with babel + Hebrew (algorithmicx, other hyperref issues) or with workaround I currently have in place for those things.
  • IRAN
    IRAN about 12 years
    No, I did not mean that you can use bidi package with pdfTeX. I meant that you can use bidi changes to hyperref, maybe it works for you. All the changes are in hyperref-xetex-bidi.def . Copy all the macros from this file (obviously except \providesfile lines) and put them between \makeatletter and \makeatother in the preamble of your document. Also bidi uses \if@RTL conditional but babel uses \if@rl. So you also need to change all \if@RTL to \if@rl.
  • einpoklum
    einpoklum about 12 years
    I'll just report what I've already wrote Vafa... i TRIED LIFTING macros from hyperref-xetex-bidi.def and adapting them as suggested, but it doesn't work. Maybe it's impossible and maybe it requires more involved modification.
  • einpoklum
    einpoklum almost 12 years
    What about \cite? (Editing the question to emphasize its importance). I don't think that there's a \cite*, right?
  • einpoklum
    einpoklum almost 12 years
    (and of course \url would be replaced with \nolinkurl or something, etc.)
  • Stefan Kottwitz
    Stefan Kottwitz almost 12 years
    @EyalRozenberg I added a more complete macro for temporarily disabling hyperlinks.
  • einpoklum
    einpoklum almost 12 years
    I get: ! Undefined control sequence. \hyper@linkurl #1#2->#1\Hy@xspace@end l.30 \url{tex.stackexchange.com}
  • Stefan Kottwitz
    Stefan Kottwitz almost 12 years
    @EyalRozenberg Perhaps you've got a different hyperref version. Adjust \disablehyperlinks to the code you find in hyperref.sty in \Hy@AtBeginDocument or update hyperref.
  • einpoklum
    einpoklum almost 12 years
    I'm using a hyperref version packaged in March for MiKTeX 2.9 , not something really old. And if this code is to go into a document class, it'll need to be robust enough to work with different versions ... but I'll have a look.
  • einpoklum
    einpoklum almost 12 years
    I wonder why he says there isn't an easy way... shouldn't \if@rl work?
  • Stefan Kottwitz
    Stefan Kottwitz almost 12 years
    @EyalRozenberg I used hyperref 2011/04/17 v6.82g. If necessary, we can insert a check for the existence of the macro if it's new.
  • fheshwfq
    fheshwfq about 11 years
    Important to note here that hyperref must be loaded before polyglossia for this solution to work with XeLaTeX.