From d999da47ff375df843c0c9bbfd5911236dd9d40a Mon Sep 17 00:00:00 2001
From: Norbert Preining <norbert@preining.info>
Date: Mon, 17 May 2021 03:02:10 +0000
Subject: CTAN sync 202105170302

---
 macros/latex/required/babel/base/babel.dtx | 393 +++++++++++++++++++++++++----
 1 file changed, 348 insertions(+), 45 deletions(-)

(limited to 'macros/latex/required/babel/base/babel.dtx')

diff --git a/macros/latex/required/babel/base/babel.dtx b/macros/latex/required/babel/base/babel.dtx
index 745cf11406..76bb9a1f93 100644
--- a/macros/latex/required/babel/base/babel.dtx
+++ b/macros/latex/required/babel/base/babel.dtx
@@ -31,7 +31,7 @@
 %
 % \iffalse
 %<*filedriver>
-\ProvidesFile{babel.dtx}[2021/04/26 v3.58 The Babel package]
+\ProvidesFile{babel.dtx}[2021/05/16 v3.59 The Babel package]
 \documentclass{ltxdoc}
 \GetFileInfo{babel.dtx}
 \usepackage{fontspec}
@@ -2579,6 +2579,18 @@ Sets the interword penalty for the writing system of this language.
 Currently used only in Southeast Asian scrips, like Thai. Ignored if 0
 (which is the default value). 
 
+\Describe{justification=}{\texttt{kashida} $\string|$
+\texttt{elongated} $\string|$ \texttt{unhyphenated}}
+\New{3.59} There are currently three options, mainly for the Arabic
+script. It sets the linebreaking and justification method, which can be
+based on the the \textsc{arabic tatweel} character or in the
+‘justification alternatives’ OpenType table (\texttt{jalt}). For an
+explanation see the \href{https://github.com/latex3/babel/blob/master/%
+news-guides/news/whats-new-in-babel-3.59.md}{\babel\ site}.
+
+\Describe{linebreaking=}{}
+\New{3.59} Just a synonymous for \texttt{justification}.
+
 \Describe{mapfont=}{\texttt{direction}}
 Assigns the font for the writing direction of this language (only with
 |bidi=basic|). Whenever possible, instead of this option use |onchar|,
@@ -3080,7 +3092,7 @@ three variants.}
 \trans{Hindi, Sanskrit}{transliteration.hk}{The Harvard-Kyoto system to
 romanize Devanagari.}
 
-\trans{}{punctuation.space}{Inserts a space before the following
+\trans{Hindi, Sanskrit}{punctuation.space}{Inserts a space before the following
 four characters: \textit{!?:;}\,.}
 
 \trans{Hungarian}{digraphs.hyphen}{Hyphenates the long digraphs
@@ -3088,10 +3100,10 @@ four characters: \textit{!?:;}\,.}
 \textit{ssz}, \textit{tty} and \textit{zzs} as \textit{cs-cs},
 \textit{dz-dz}, etc.}
 
-\trans{Norsk}{doubleletter.hyphen}{Hyphenates the doble-letter groups
-\textit{bb}, \textit{dd}, \textit{ff}, \textit{gg}, \textit{ll},
-\textit{mm}, \textit{nn}, \textit{pp}, \textit{rr}, \textit{ss},
-\textit{tt} as \textit{bb-b}, \textit{dd-d}, etc.}
+\trans{Arabic, Persian}{kashida.plain}{Experimental. A very simple and
+basic transform for ‘plain’ Arabic fonts, which attempts to distribute
+the tatwil as evenly as possible (starting at the end of the line). See
+the news for version 3.59.}
 
 \trans{Serbian}{transliteration.gajica}{(Note |serbian| with |ini|
 files refers to the Cyrillic script, which is here the target.) The
@@ -3106,9 +3118,9 @@ standard system devised by Ljudevit Gaj.}
 \New{3.37-3.39} \textit{With \luatex{}} it is now possible to define
 non-standard hyphenation rules, like |f-f| $\to$ |ff-f|, repeated
 hyphens, ranked ruled (or more precisely, ‘penalized’ hyphenation
-points), and so on. No rules are currently provided by default, but
-they can be defined as shown in the following example, where |{1}| is
-the first captured char (between |()| in the pattern):
+points), and so on. Only a few rules are currently provided (see
+below), but they can be defined as shown in the following example,
+where |{1}| is the first captured char (between |()| in the pattern):
 \begin{verbatim}
 \babelposthyphenation{german}{([fmtrp]) | {1}}
 {
@@ -3147,9 +3159,7 @@ transliterations. There are other differences: (1) the first argument
 is the locale instead of the name of the hyphenation patterns; (2) in the
 search patterns |=| has no special meaning, while \verb+|+ stands for
 an ordinary space; (3) in the replacement, discretionaries are not
-accepted.
-
-It handles glyphs and spaces.
+accepted. 
 
 This feature is activated with the first |\babelposthyphenation| or
 |\babelprehyphenation|.
@@ -3188,7 +3198,7 @@ This feature is activated with the first |\babelposthyphenation| or
   \babel{} by default recognizes this setting if the font has been
   declared with |\babelfont|. The \textit{transforms} mechanism
   supplements rather than replaces OTF features.
-  
+
   With \xetex{}, where \textit{transforms} are not available, there is
   still another approach, with font mappings, mainly meant to perform
   encoding conversions and transliterations. Mappings, however, are
@@ -3880,12 +3890,11 @@ empty, removes them. The last argument is the locale name:
 Currently this macro understands the following keys (and only for
 \textsf{luatex}), with values |on| or |off|: |bidi.text|,
 |bidi.mirroring|, |bidi.mapdigits|, |layout.lists|, |layout.tabular|,
-|linebreak.sea|, |linebreak.cjk|. For example, you can set
+|linebreak.sea|, |linebreak.cjk|, |justify.arabic|. For example, you can set
 |\babeladjust{bidi.text=off}| if you are using an alternative algorithm
-or with large sections not requiring it. With \textsf{luahbtex} you may
-need |bidi.mirroring=off|. Use with care, because these options do not
-deactivate other related options (like paragraph direction with
-|bidi.text|).
+or with large sections not requiring it. Use with care, because these
+options do not deactivate other related options (like paragraph
+direction with |bidi.text|).
 
 \subsection{Tips, workarounds, known issues and notes}
 
@@ -4958,8 +4967,8 @@ help from Bernd Raichle, for which I am grateful.
 % \section{Tools}
 %
 %    \begin{macrocode}
-%<<version=3.58>>
-%<<date=2021/04/26>>
+%<<version=3.59>>
+%<<date=2021/05/16>>
 %    \end{macrocode}
 %
 % \textbf{Do not use the following macros in \texttt{ldf} files. They
@@ -7653,9 +7662,13 @@ help from Bernd Raichle, for which I am grateful.
   \else
     \edef\bbl@tempa{\bbl@cl{lnbrk}}%
   \fi
+  % linebreaking - handle u, e, k (v in the future)
   \bbl@xin@{/u}{/\bbl@tempa}%
+  \ifin@\else\bbl@xin@{/e}{/\bbl@tempa}\fi % elongated forms 
+  \ifin@\else\bbl@xin@{/k}{/\bbl@tempa}\fi % only kashida
+  \ifin@\else\bbl@xin@{/v}{/\bbl@tempa}\fi % variable font
   \ifin@
-    % 'unhyphenated' = allow stretching
+    % unhyphenated/kashida/elongated = allow stretching
     \language\l@unhyphenated
     \babel@savevariable\emergencystretch
     \emergencystretch\maxdimen
@@ -8985,7 +8998,7 @@ help from Bernd Raichle, for which I am grateful.
 %    \begin{macrocode}
 \def\babel@texpdf#1#2#3#4{%
   \ifx\texorpdfstring\@undefined
-    \textormath{#1}{#2}%
+    \textormath{#1}{#3}%
   \else
     \texorpdfstring{\textormath{#1}{#3}}{#2}%
     % \texorpdfstring{\textormath{#1}{#3}}{\textormath{#2}{#4}}%
@@ -10788,6 +10801,7 @@ help from Bernd Raichle, for which I am grateful.
   \let\bbl@KVP@language\@nil
   \let\bbl@KVP@hyphenrules\@nil
   \let\bbl@KVP@linebreaking\@nil
+  \let\bbl@KVP@justification\@nil
   \let\bbl@KVP@mapfont\@nil
   \let\bbl@KVP@maparabic\@nil
   \let\bbl@KVP@mapdigits\@nil
@@ -10968,6 +10982,20 @@ help from Bernd Raichle, for which I am grateful.
     \bbl@csarg\edef{intsp@#2}{\bbl@KVP@intraspace}%
   \fi
   \bbl@provide@intraspace
+  %
+  \ifx\bbl@KVP@justification\@nil\else
+     \let\bbl@KVP@linebreaking\bbl@KVP@justification
+  \fi
+  \ifx\bbl@KVP@linebreaking\@nil\else
+    \bbl@xin@{,\bbl@KVP@linebreaking,}{,elongated,kashida,cjk,unhyphenated,}%
+    \ifin@
+      \bbl@csarg\xdef
+        {lnbrk@\languagename}{\expandafter\@car\bbl@KVP@linebreaking\@nil}%
+    \fi
+  \fi
+  \bbl@xin@{/e}{/\bbl@cl{lnbrk}}%
+  \ifin@\else\bbl@xin@{/k}{/\bbl@cl{lnbrk}}\fi
+  \ifin@\bbl@arabicjust\fi
   % == Line breaking: hyphenate.other.locale/.script==
   \ifx\bbl@lbkflag\@empty
     \bbl@ifunset{bbl@hyotl@\languagename}{}%
@@ -12126,6 +12154,10 @@ help from Bernd Raichle, for which I am grateful.
   \bbl@adjust@lua{linebreak}{cjk_enabled=true}}
 \@namedef{bbl@ADJ@linebreak.cjk@off}{%
   \bbl@adjust@lua{linebreak}{cjk_enabled=false}}
+\@namedef{bbl@ADJ@justify.arabic@on}{%
+  \bbl@adjust@lua{linebreak}{arabic.justify_enabled=true}}
+\@namedef{bbl@ADJ@justify.arabic@off}{%
+  \bbl@adjust@lua{linebreak}{arabic.justify_enabled=false}}
 %
 \def\bbl@adjust@layout#1{%
   \ifvmode
@@ -13571,7 +13603,23 @@ help from Bernd Raichle, for which I am grateful.
       end
     end
   }^^
-  \bbl@luahyphenate}
+  \bbl@luahyphenate}  
+%    \end{macrocode}
+%    
+% \subsection{CJK line breaking}
+%
+% Minimal line breaking for CJK scripts, mainly intended for simple
+% documents and short texts as a secundary language. Only line
+% breaking, with a little stretching for justification, without any
+% attempt to adjust the spacing. It is based on (but does not strictly
+% follow) the Unicode algorithm.
+%
+% We first need a little table with the corresponding line breaking
+% properties. A few characters have an additional key for the width
+% (fullwidth \textit{vs.} halfwidth), not yet used. There is a separate
+% file, defined below.
+%
+%    \begin{macrocode}
 \catcode`\%=14
 \gdef\bbl@cjkintraspace{%
   \let\bbl@cjkintraspace\relax
@@ -13696,22 +13744,215 @@ help from Bernd Raichle, for which I am grateful.
      \fi}}
 %    \end{macrocode}
 %
-% \subsection{CJK line breaking}
-%
-% Minimal line breaking for CJK scripts, mainly intended for simple
-% documents and short texts as a secundary language. Only line
-% breaking, with a little stretching for justification, without any
-% attempt to adjust the spacing. It is based on (but does not strictly
-% follow) the Unicode algorithm.
+% \subsection{Arabic justification}
 %
-% We first need a little table with the corresponding line breaking
-% properties. A few characters have an additional key for the width
-% (fullwidth \textit{vs.} halfwidth), not yet used. There is a separate
-% file, defined below.
+%    \begin{macrocode}
+\ifnum\bbl@bidimode>100 \ifnum\bbl@bidimode<200
+\def\bblar@chars{%
+  0628,0629,062A,062B,062C,062D,062E,062F,0630,0631,0632,0633,%
+  0634,0635,0636,0637,0638,0639,063A,063B,063C,063D,063E,063F,%
+  0640,0641,0642,0643,0644,0645,0646,0647,0649}
+\def\bblar@elongated{%
+  0626,0628,062A,062B,0633,0634,0635,0636,063B,%
+  063C,063D,063E,063F,0641,0642,0643,0644,0646,%
+  0649,064A}
+\begingroup
+  \catcode`_=11 \catcode`:=11
+  \gdef\bblar@nofswarn{\gdef\msg_warning:nnx##1##2##3{}}
+\endgroup
+\gdef\bbl@arabicjust{%
+  \let\bbl@arabicjust\relax
+  \newattribute\bblar@kashida
+  \bblar@kashida=\z@
+  \expandafter\bbl@add\csname selectfont \endcsname{{\bbl@parsejalt}}%
+  \directlua{
+    Babel.arabic.elong_map   = Babel.arabic.elong_map or {}
+    Babel.arabic.elong_map[\the\localeid]   = {}
+    luatexbase.add_to_callback('post_linebreak_filter',
+      Babel.arabic.justify, 'Babel.arabic.justify')
+  }}% 
+% Save both node lists to make replacement. TODO. Save also widths to
+% make computations
+\def\bblar@fetchjalt#1#2#3#4{%
+  \bbl@exp{\\\bbl@foreach{#1}}{%
+    \bbl@ifunset{bblar@JE@##1}%
+      {\setbox\z@\hbox{^^^^200d\char"##1#2}}%
+      {\setbox\z@\hbox{^^^^200d\char"\@nameuse{bblar@JE@##1}#2}}%
+    \directlua{%
+      local last = nil
+      for item in node.traverse(tex.box[0].head) do
+        if item.id == node.id'glyph' and item.char > 0x600 and
+            not (item.char == 0x200D) then
+          last = item
+        end
+      end
+      Babel.arabic.#3['##1#4'] = last.char
+    }}}
+% Brute force. No rules at all, yet. The ideal: look at jalt table. And
+% perhaps other tables (falt?, cswh?). What about kaf? And diacritic
+% positioning?
+\gdef\bbl@parsejalt{%
+  \ifx\addfontfeature\@undefined\else
+    \bbl@xin@{/e}{/\bbl@cl{lnbrk}}%
+    \ifin@
+      \directlua{%
+        if Babel.arabic.elong_map[\the\localeid][\fontid\font] == nil then
+          Babel.arabic.elong_map[\the\localeid][\fontid\font] = {}
+          tex.print([[\string\csname\space bbl@parsejalti\endcsname]])
+        end
+      }%
+    \fi
+  \fi}
+\gdef\bbl@parsejalti{%
+  \begingroup
+    \let\bbl@parsejalt\relax     % To avoid infinite loop
+    \edef\bbl@tempb{\fontid\font}%
+    \bblar@nofswarn
+    \bblar@fetchjalt\bblar@elongated{}{from}{}%
+    \bblar@fetchjalt\bblar@chars{^^^^064a}{from}{a}% Alef maksura
+    \bblar@fetchjalt\bblar@chars{^^^^0649}{from}{y}% Yeh
+    \addfontfeature{RawFeature=+jalt}%
+    % \@namedef{bblar@JE@0643}{06AA}% todo: catch medial kaf
+    \bblar@fetchjalt\bblar@elongated{}{dest}{}%
+    \bblar@fetchjalt\bblar@chars{^^^^064a}{dest}{a}%
+    \bblar@fetchjalt\bblar@chars{^^^^0649}{dest}{y}%
+      \directlua{%
+        for k, v in pairs(Babel.arabic.from) do
+          if Babel.arabic.dest[k] and
+              not (Babel.arabic.from[k] == Babel.arabic.dest[k]) then
+            Babel.arabic.elong_map[\the\localeid][\bbl@tempb]
+               [Babel.arabic.from[k]] = Babel.arabic.dest[k]
+          end
+        end
+      }%
+  \endgroup}
 %
-% \textit{Work in progress.} 
+\begingroup
+\catcode`#=11
+\catcode`~=11
+\directlua{
+
+Babel.arabic = Babel.arabic or {}
+Babel.arabic.from = {}
+Babel.arabic.dest = {}
+Babel.arabic.justify_factor = 0.95
+Babel.arabic.justify_enabled = true
+
+function Babel.arabic.justify(head)
+  if not Babel.arabic.justify_enabled then return head end
+  local d, new
+  local k_list, k_item, pos_inline
+  local width, width_new, full, k_curr, wt_pos, goal
+  local subst_done = false
+  local elong_map = Babel.arabic.elong_map
+  local last_line
+  local GLYPH = node.id'glyph'
+  local KASHIDA = luatexbase.registernumber'bblar@kashida'
+  local LOCALE = luatexbase.registernumber'bbl@attr@locale'
+
+  for line in node.traverse_id(node.id'hlist', head) do
+    % Exclude last line. todo. But-- it discards one-word lines, too!
+    % ? Look for glue = 12:15
+    if (line.glue_sign == 1 and line.glue_order == 0) then
+      elongs = {}     % Stores elongated candidates of each line
+      k_list = {}     % And all letters with kashida
+      pos_inline = 0  % Not yet used
+
+      for n in node.traverse_id(GLYPH, line.head) do
+        pos_inline = pos_inline + 1 % To find where it is. Not used.
+
+        % Elongated glyphs
+        if elong_map then
+          local locale = node.get_attribute(n, LOCALE)
+          if elong_map[locale] and elong_map[locale][n.font] and 
+              elong_map[locale][n.font][n.char] then
+            table.insert(elongs, {node = n, locale = locale} )
+            node.set_attribute(n.prev, KASHIDA, 0)
+          end
+        end
+
+        % Tatwil
+        if Babel.kashida_wts then
+          local k_wt = node.get_attribute(n, KASHIDA)
+          if k_wt > 0 then % todo. parameter for multi inserts
+            table.insert(k_list, {node = n, weight = k_wt, pos = pos_inline})
+          end
+        end
+
+      end % of node.traverse_id
+
+      if #elongs == 0 and #k_list == 0 then goto next_line end
+
+      full = line.width
+      goal = full * Babel.arabic.justify_factor % A bit crude
+      width = node.dimensions(line.head)    % The 'natural' width
+
+      % == Elongated ==
+      % Original idea taken from 'chikenize'
+      while (#elongs > 0 and width < goal) do
+        subst_done = true
+        local x = #elongs
+        local curr = elongs[x].node
+        local oldchar = curr.char
+        curr.char = elong_map[elongs[x].locale][curr.font][curr.char]
+        width = node.dimensions(line.head)  % Check if the line is too wide
+        % Substitute back if the line would be too wide and break:
+        if width > goal then
+          curr.char = oldchar
+          break
+        end 
+        % If continue, pop the just substituted node from the list:
+        table.remove(elongs, x)
+      end
+
+      % == Tatwil ==
+      if #k_list == 0 then goto next_line end
+
+      width = node.dimensions(line.head)    % The 'natural' width
+      k_curr = #k_list
+      wt_pos = 1
+
+      while width < goal do
+        subst_done = true
+        k_item = k_list[k_curr].node
+        if k_list[k_curr].weight == Babel.kashida_wts[wt_pos] then       
+          d = node.copy(k_item)
+          d.char = 0x0640
+          line.head, new = node.insert_after(line.head, k_item, d)
+          width_new = node.dimensions(line.head)
+          if width > goal or width == width_new then
+            node.remove(line.head, new) % Better compute before
+            break
+          end
+          width = width_new
+        end
+        if k_curr == 1 then
+          k_curr = #k_list
+          wt_pos = (wt_pos >= table.getn(Babel.kashida_wts)) and 1 or wt_pos+1   
+        else
+          k_curr = k_curr - 1
+        end
+      end
+
+      ::next_line::
+
+      % Must take into account marks and ins, see luatex manual.
+      % Have to be executed only if there are changes. Investigate
+      % what's going on exactly.
+      if subst_done then
+        node.insert_before(head, line, node.hpack(line.head, full, 'exactly'))
+        node.remove(head, line)
+      end
+    end % if process line
+  end % for lines
+  return head
+end
+}
+\endgroup
+\fi\fi % Arabic just block
+%    \end{macrocode}
 %
-% Common stuff.
+% \subsection{Common stuff}
 %
 %    \begin{macrocode}
 \AddBabelHook{babel-fontspec}{afterextras}{\bbl@switchfont}
@@ -13951,11 +14192,11 @@ end
   end
 
   Babel.fetch_subtext = {}
-  
+
   Babel.ignore_pre_char = function(node)
     return (node.lang == \the\l@nohyphenation)
   end
-  
+
   &% Merging both functions doesn't seen feasible, because there are too
   &% many differences.
   Babel.fetch_subtext[0] = function(head)
@@ -14136,6 +14377,7 @@ end
         &% after the match, either as found by u.match (faster) or the
         &% computed position based on sc if w has changed.
         local last_match = 0
+        local step = 0
 
         &% For every match.
         while true do
@@ -14143,9 +14385,9 @@ end
             print('=====')
           end
           local new  &% used when inserting and removing nodes
-          local refetch = false
 
           local matches = { u.match(w, p, last_match) }
+          
           if #matches < 2 then break end
 
           &% Get and remove empty captures (with ()'s, which return a
@@ -14210,6 +14452,10 @@ end
             if crep and crep.data then
               item_base = data_nodes[crep.data]
             end
+            
+            if crep then
+              step = crep.step or 0
+            end
 
             if crep and next(crep) == nil then &% = {}
               last_match = save_last    &% Optimization
@@ -14220,7 +14466,14 @@ end
               table.remove(w_nodes, sc)
               w = u.sub(w, 1, sc-1) .. u.sub(w, sc+1)
               sc = sc - 1  &% Nothing has been inserted.
-              last_match = utf8.offset(w, sc+1)
+              last_match = utf8.offset(w, sc+1+step)
+              goto next
+
+            elseif crep and crep.kashida then &% Experimental
+              node.set_attribute(item,
+                 luatexbase.registernumber'bblar@kashida', 
+                 crep.kashida)
+              last_match = utf8.offset(w, sc+1+step)
               goto next
 
             elseif crep and crep.string then
@@ -14256,7 +14509,7 @@ end
                 end  &% for
                 node.remove(head, item)
               end  &% if ''
-              last_match = utf8.offset(w, sc+1)
+              last_match = utf8.offset(w, sc+1+step)
               goto next
 
             elseif mode == 1 and crep and (crep.pre or crep.no or crep.post) then
@@ -14311,7 +14564,7 @@ end
 
             end  &% ie replacement cases
 
-            &% Shared by disc, space and penalty. 
+            &% Shared by disc, space and penalty.
             if sc == 1 then
               word_head = head
             end
@@ -14325,7 +14578,7 @@ end
               w = u.sub(w, 1, sc-1) .. placeholder .. u.sub(w, sc+1)
             end
 
-            last_match = utf8.offset(w, sc+1)
+            last_match = utf8.offset(w, sc+1+step)
 
             ::next::
 
@@ -14395,6 +14648,26 @@ end
     return "]]..Babel.capt_map(m[" .. capno .. "]," ..
            (mlen) .. ").." .. "[["
   end
+  
+  &% Create/Extend reversed sorted list of kashida weights:
+  function Babel.capture_kashida(key, wt)
+    wt = tonumber(wt)
+    if Babel.kashida_wts then
+      for p, q in ipairs(Babel.kashida_wts) do
+        if wt  == q then
+          break
+        elseif wt > q then
+          table.insert(Babel.kashida_wts, p, wt)
+          break
+        elseif table.getn(Babel.kashida_wts) == p then
+          table.insert(Babel.kashida_wts, wt)
+        end
+      end
+    else
+      Babel.kashida_wts = { wt }
+    end
+    return 'kashida = ' .. wt
+  end
 }
 %    \end{macrocode}
 %
@@ -14473,10 +14746,11 @@ end
            rep = rep:gsub('^%s*(remove)%s*$', 'remove = true')
            rep = rep:gsub('^%s*(insert)%s*,', 'insert = true, ')
            rep = rep:gsub('(string)%s*=%s*([^%s,]*)', Babel.capture_func)
-           rep = rep:gsub( '(space)%s*=%s*([%d%.]+)%s+([%d%.]+)%s+([%d%.]+)',
+           rep = rep:gsub('(space)%s*=%s*([%d%.]+)%s+([%d%.]+)%s+([%d%.]+)',
              'space = {' .. '%2, %3, %4' .. '}')
-           rep = rep:gsub( '(spacefactor)%s*=%s*([%d%.]+)%s+([%d%.]+)%s+([%d%.]+)',
+           rep = rep:gsub('(spacefactor)%s*=%s*([%d%.]+)%s+([%d%.]+)%s+([%d%.]+)',
              'spacefactor = {' .. '%2, %3, %4' .. '}')
+           rep = rep:gsub('(kashida)%s*=%s*([^%s,]*)', Babel.capture_kashida)
            tex.print([[\string\babeltempa{{]] .. rep .. [[}}]])
          }}}&%
     \directlua{
@@ -21562,8 +21836,10 @@ Babel = Babel or {}
 
 Babel.cjk_characters = {
   [0x0021]={c='ex'},
+  [0x0022]={c='qu'},          
   [0x0024]={c='pr'},
   [0x0025]={c='po'},
+  [0x0027]={c='qu'},          
   [0x0028]={c='op'},
   [0x0029]={c='cp'},
   [0x002B]={c='pr'},
@@ -21584,10 +21860,18 @@ Babel.cjk_characters = {
   [0x00A3]={c='pr'},
   [0x00A4]={c='pr'},
   [0x00A5]={c='pr'},
+  [0x00AB]={c='qu'},          
   [0x00B0]={c='po'},
   [0x00B1]={c='pr'},
+  [0x00BB]={c='qu'},          
+  [0x2018]={c='qu'},          
+  [0x2019]={c='qu'},          
   [0x201A]={c='op'},
+  [0x201B]={c='qu'},    
+  [0x201C]={c='qu'},    
+  [0x201D]={c='qu'},          
   [0x201E]={c='op'},
+  [0x201F]={c='qu'},          
   [0x2024]={c='in'},
   [0x2025]={c='in'},
   [0x2026]={c='in'},
@@ -21599,6 +21883,8 @@ Babel.cjk_characters = {
   [0x2035]={c='po'},
   [0x2036]={c='po'},
   [0x2037]={c='po'},
+  [0x2039]={c='qu'},          
+  [0x203A]={c='qu'},            
   [0x203C]={c='ns'},
   [0x203D]={c='ns'},
   [0x2044]={c='is'},
@@ -21657,7 +21943,23 @@ Babel.cjk_characters = {
   [0x29FD]={c='cl'},
   [0x2CF9]={c='ex'},
   [0x2CFE]={c='ex'},
+  [0x2E02]={c='qu'},          
+  [0x2E03]={c='qu'},          
+  [0x2E04]={c='qu'},          
+  [0x2E05]={c='qu'},          
+  [0x2E06]={c='qu'},    
+  [0x2E07]={c='qu'},    
+  [0x2E08]={c='qu'},    
+  [0x2E09]={c='qu'},          
+  [0x2E0A]={c='qu'},          
+  [0x2E0B]={c='qu'},          
+  [0x2E0C]={c='qu'},          
+  [0x2E0D]={c='qu'},          
   [0x2E18]={c='op'},
+  [0x2E1C]={c='qu'},          
+  [0x2E1D]={c='qu'},          
+  [0x2E20]={c='qu'},          
+  [0x2E21]={c='qu'}, 
   [0x2E22]={c='op'},
   [0x2E23]={c='cl'},
   [0x2E24]={c='op'},
@@ -21810,6 +22112,7 @@ Babel.cjk_breaks = {
   ['po'] = { ['op']=1, ['pr']=1, ['po']=1, ['in']=1, ['I']=1 },
   ['in'] = { ['op']=1, ['pr']=1, ['po']=1,           ['I']=1 },
   ['hy'] = { ['op']=1, ['pr']=1, ['po']=1, ['in']=1, ['I']=1 },
+  ['qu'] = { },
   --
   ['I']  = { ['op']=1, ['pr']=1, ['I']=1, ['O']=1 },
   ['O']  = {                     ['I']=1 }
-- 
cgit v1.2.3

