[latex3-commits] [git/LaTeX3-latex3-babel] master: Arabic kashida, with user definable rules. 'step' in transforms. (ea7b112)

Javier email at dante.de
Sat May 8 16:35:36 CEST 2021


Repository : https://github.com/latex3/babel
On branch  : master
Link       : https://github.com/latex3/babel/commit/ea7b1122763c1cfc1eabe1dec4f8cef06ac66156

>---------------------------------------------------------------

commit ea7b1122763c1cfc1eabe1dec4f8cef06ac66156
Author: Javier <email at localhost>
Date:   Sat May 8 16:35:36 2021 +0200

    Arabic kashida, with user definable rules. 'step' in transforms.


>---------------------------------------------------------------

ea7b1122763c1cfc1eabe1dec4f8cef06ac66156
 README.md                                   |  20 +-
 babel.dtx                                   | 300 +++++++++++++++++++++++++---
 babel.ins                                   |   2 +-
 babel.pdf                                   | Bin 832617 -> 843054 bytes
 bbcompat.dtx                                |   2 +-
 locale/ar/babel-ar.ini                      |   5 +
 locale/ar/babel-arabic.tex                  |  83 --------
 news-guides/news/whats-new-in-babel-3.59.md |  63 ++++++
 samples/lua-arabic.pdf                      | Bin 117183 -> 85278 bytes
 samples/lua-arabic.tex                      |  11 +
 10 files changed, 364 insertions(+), 122 deletions(-)

diff --git a/README.md b/README.md
index 8a954ea..70766fd 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-## Babel 3.58
+## Babel 3.58.2366
 
 This package manages culturally-determined typographical (and other)
 rules, and hyphenation patterns for a wide range of languages. Many
@@ -8,9 +8,9 @@ is a set of ini files for about 250 languages.
 
 The latest stable version is available on <https://ctan.org/pkg/babel>.
 
-Changes in version 3.58 are described in:
+Changes in version 3.59 are described in:
 
-https://github.com/latex3/babel/blob/master/news-guides/news/whats-new-in-babel-3.58.md
+https://github.com/latex3/babel/blob/master/news-guides/news/whats-new-in-babel-3.59.md
 
 Apart from the manual, you can find information on some aspects of babel at:
 
@@ -46,6 +46,9 @@ respective authors.
 
 ### Summary of Latest changes
 ```
+3.59   2021-05-??
+       * Kashida with user-definable rules (via transforms).
+       
 3.58   2021-04-26
        * More predefined transforms (lua):
          - doubleletter.hyphen: Norsk
@@ -59,17 +62,6 @@ respective authors.
        * Fix: \shorthandoff*{^} was not revertible (#126).
        * Experimental code for Arabic justification (with elongated
          forms: lua).
-         
-3.57   2021-04-07
-       * Predefined transforms (lua):
-         - Arabic:     transliteration.dad
-         - Croatian:   digraphs.ligatures
-         - Greek:      diaeresis.hyphen
-         - Hindi:      transliteration.hk
-         - Hungarian:  digraphs.hyphen
-       * Transforms: {xxxx} syntax also in string=.
-       * Preliminary code for Uyghur hyphenation (lua).
-       * magyar as alternative to hungarian in \babelprovide.
 ```
 
 ### Previous changes
diff --git a/babel.dtx b/babel.dtx
index 745cf11..b6eb2ba 100644
--- a/babel.dtx
+++ b/babel.dtx
@@ -31,7 +31,7 @@
 %
 % \iffalse
 %<*filedriver>
-\ProvidesFile{babel.dtx}[2021/04/26 v3.58 The Babel package]
+\ProvidesFile{babel.dtx}[2021/05/08 v3.58.2366 The Babel package]
 \documentclass{ltxdoc}
 \GetFileInfo{babel.dtx}
 \usepackage{fontspec}
@@ -4958,8 +4958,8 @@ help from Bernd Raichle, for which I am grateful.
 % \section{Tools}
 %
 %    \begin{macrocode}
-%<<version=3.58>>
-%<<date=2021/04/26>>
+%<<version=3.58.2366>>
+%<<date=2021/05/08>>
 %    \end{macrocode}
 %
 % \textbf{Do not use the following macros in \texttt{ldf} files. They
@@ -7653,14 +7653,19 @@ help from Bernd Raichle, for which I am grateful.
   \else
     \edef\bbl at tempa{\bbl at cl{lnbrk}}%
   \fi
+  % linebreaking - handle u, e, k (v in the future)
   \bbl at xin@{/u}{/\bbl at tempa}%
+  \ifin@\else\bbl at xin@{/e}{/\bbl at tempa}\fi % elongated forms 
+  \ifin@\else\bbl at xin@{/k}{/\bbl at tempa}\fi % only kashida
+  \ifin@\else\bbl at xin@{/v}{/\bbl at tempa}\fi % variable font
   \ifin@
-    % 'unhyphenated' = allow stretching
+    % unhyphenated/kashida/elongated = allow stretching
     \language\l at unhyphenated
     \babel at savevariable\emergencystretch
     \emergencystretch\maxdimen
     \babel at savevariable\hbadness
     \hbadness\@M
+    \hfuzz=10pt
   \else
     % other = select patterns
     \bbl at patterns{#1}%
@@ -10968,6 +10973,10 @@ help from Bernd Raichle, for which I am grateful.
     \bbl at csarg\edef{intsp@#2}{\bbl at KVP@intraspace}%
   \fi
   \bbl at provide@intraspace
+  %
+  \bbl at xin@{/e}{/\bbl at cl{lnbrk}}
+  \ifin@\else\bbl at xin@{/k}{/\bbl at cl{lnbrk}}\fi
+  \ifin@\bbl at arabicjust\fi
   % == Line breaking: hyphenate.other.locale/.script==
   \ifx\bbl at lbkflag\@empty
     \bbl at ifunset{bbl at hyotl@\languagename}{}%
@@ -12126,6 +12135,10 @@ help from Bernd Raichle, for which I am grateful.
   \bbl at adjust@lua{linebreak}{cjk_enabled=true}}
 \@namedef{bbl at ADJ@linebreak.cjk at off}{%
   \bbl at adjust@lua{linebreak}{cjk_enabled=false}}
+\@namedef{bbl at ADJ@justify.arabic at on}{%
+  \bbl at adjust@lua{linebreak}{arabic.justify_enabled=true}}
+\@namedef{bbl at ADJ@justify.arabic at off}{%
+  \bbl at adjust@lua{linebreak}{arabic.justify_enabled=false}}
 %
 \def\bbl at adjust@layout#1{%
   \ifvmode
@@ -13572,6 +13585,22 @@ help from Bernd Raichle, for which I am grateful.
     end
   }^^
   \bbl at 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 at cjkintraspace{%
   \let\bbl at cjkintraspace\relax
@@ -13696,22 +13725,214 @@ help from Bernd Raichle, for which I am grateful.
      \fi}}
 %    \end{macrocode}
 %
-% \subsection{CJK line breaking}
+% \subsection{Arabic justification}
 %
-% 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}
+\ifnum\bbl at bidimode>100 \ifnum\bbl at bidimode<200
+\def\bblar at 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 at 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 at nofswarn{\gdef\msg_warning:nnx##1##2##3{}}
+\endgroup
+\gdef\bbl at arabicjust{%
+  \let\bbl at arabicjust\relax
+  \newattribute\bblar at kashida
+  \bblar at kashida=\z@
+  \expandafter\bbl at add\csname selectfont \endcsname{{\bbl at 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 at fetchjalt#1#2#3#4{%
+  \bbl at exp{\\\bbl at foreach{#1}}{%
+    \bbl at ifunset{bblar at JE@##1}%
+      {\setbox\z@\hbox{^^^^200d\char"##1#2}}%
+      {\setbox\z@\hbox{^^^^200d\char"\@nameuse{bblar at 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 at parsejalt{%
+  \ifx\addfontfeature\@undefined\else
+    \bbl at xin@{/e}{/\bbl at 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 at parsejalti\endcsname]])
+        end
+      }%
+    \fi
+  \fi}
+\gdef\bbl at parsejalti{%
+  \begingroup
+    \let\bbl at parsejalt\relax     % To avoid infinite loop
+    \edef\bbl at tempb{\fontid\font}%
+    \bblar at nofswarn
+    \bblar at fetchjalt\bblar at elongated{}{from}{}%
+    \bblar at fetchjalt\bblar at chars{^^^^064a}{from}{a}% Alef maksura
+    \bblar at fetchjalt\bblar at chars{^^^^0649}{from}{y}% Yeh
+    \addfontfeature{RawFeature=+jalt}%
+    % \@namedef{bblar at JE@0643}{06AA}% todo: catch medial kaf
+    \bblar at fetchjalt\bblar at elongated{}{dest}{}%
+    \bblar at fetchjalt\bblar at chars{^^^^064a}{dest}{a}%
+    \bblar at fetchjalt\bblar at 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 at 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 at kashida'
+  local LOCALE = luatexbase.registernumber'bbl at attr@locale'
+
+  for line in node.traverse_id(node.id'hlist', head) do
+    % Exclude last line. todo. But-- it discards one-word lines, too!
+    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
+            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 at switchfont}
@@ -14136,6 +14357,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 +14365,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
@@ -14211,6 +14433,10 @@ end
               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
               goto next
@@ -14220,7 +14446,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 at kashida', 
+                 crep.kashida)
+              last_match = utf8.offset(w, sc+1+step)
               goto next
 
             elseif crep and crep.string then
@@ -14256,7 +14489,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
@@ -14325,7 +14558,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 +14628,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 +14726,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{
diff --git a/babel.ins b/babel.ins
index 3a07387..5d94d37 100644
--- a/babel.ins
+++ b/babel.ins
@@ -26,7 +26,7 @@
 %% and covered by LPPL is defined by the unpacking scripts (with
 %% extension .ins) which are part of the distribution.
 %%
-\def\filedate{2021/04/26}
+\def\filedate{2021/05/08}
 \def\batchfile{babel.ins}
 \input docstrip.tex
 
diff --git a/babel.pdf b/babel.pdf
index 4eca976..2c6399c 100644
Binary files a/babel.pdf and b/babel.pdf differ
diff --git a/bbcompat.dtx b/bbcompat.dtx
index a69fa73..46f5169 100644
--- a/bbcompat.dtx
+++ b/bbcompat.dtx
@@ -30,7 +30,7 @@
 %
 % \iffalse
 %<*dtx>
-\ProvidesFile{bbcompat.dtx}[2021/04/26 v3.58]
+\ProvidesFile{bbcompat.dtx}[2021/05/08 v3.58.2366]
 %</dtx>
 %
 %% File 'bbcompat.dtx'
diff --git a/locale/ar/babel-ar.ini b/locale/ar/babel-ar.ini
index ca0c4ff..fd70acd 100644
--- a/locale/ar/babel-ar.ini
+++ b/locale/ar/babel-ar.ini
@@ -207,5 +207,10 @@ transliteration.dad.7.2 =   { string = {1|AauiIbnf|آأؤإئٮںڡ} }
 ; 1-letter
 transliteration.dad.8.0 = { ([{007C}AbtjHxdrzsSDTZ`RfqklmnhUIYaui+opCvgJe]) }
 transliteration.dad.8.1 =   { string = {1|{007C}AbtjHxdrzsSDTZ`RfqklmnhUIYaui+opCvgJe|ءابتجحخدرزسصضطظعغفقكلمنهوىيَُِّْپچڤگژۀ} }
+; 
+kashida.plain.1.0 = { ()[يئهشسقفغعضصنمكلظطخحجثتب]()[يئهشسقفغعضصنمكلظطخحجثتباأإآوؤذدزرة] }
+kashida.plain.1.1 = { kashida = 500 }
+kashida.plain.2.0 = { ()ل()[اأإآ] }
+kashida.plain.2.1 = { kashida = 0 }
 
 
diff --git a/locale/ar/babel-arabic.tex b/locale/ar/babel-arabic.tex
index fbad883..5207dfd 100644
--- a/locale/ar/babel-arabic.tex
+++ b/locale/ar/babel-arabic.tex
@@ -10,87 +10,4 @@
 \BabelBeforeIni{ar}{%
 }
 
-\ifcase\bbl at engine\or
-
-\directlua{
-
-Babel.ar_tolong = {}
-
-function Babel.ar_justify(head)
-  local substlist = Babel.ar_tolong
-  local GLYPH = node.id'glyph'
-  local substs, width, goal
-  local subst_done = true % false
-  math.randomseed(1)
-  for line in node.traverse_id(node.id'hlist', head) do
-    if (line.glue_sign == 1 and line.glue_order == 0) then % exclude last line!
-      substs = {} % we store all “expandable” letters of each line
-      for n in node.traverse_id(GLYPH, line.head) do
-        if (substlist[n.char]) then
-          table.insert(substs, n)
-        end
-      end
-      line.glue_set = 0   % deactivate normal glue expansion
-      width = node.dimensions(line.head)    % check the new width
-      goal = line.width
-      
-      while (width < goal and \string#substs > 0) do
-        x = math.random(\string#substs)     % choose randomly a glyph
-        oldchar = substs[x].char
-        substs[x].char = substlist[substs[x].char]
-        subst_done = true
-        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 substs[x].char = oldchar break end 
-        % if further substitutions have to be done, remove the just
-        % substituted node from the list:
-        table.remove(substs,x)
-      end
-      % Must take into account marks and ins, see luatex manual.
-      % Have to be executed only if there are changes.
-      if subst_done then
-        line.head = node.hpack(line.head, goal, 'exactly')
-      end
-    end
-  end
-  return head
-end
-
-}
-
-\gdef\ArabicSetupJust{%
-  \directlua{
-    Babel.ar_tolong   = {}
-    luatexbase.add_to_callback('post_linebreak_filter',
-      Babel.ar_justify, 'Babel.ar_justify')
-  }% 
-  % It must be done for each font, and stored separately.
-  % Locale must be taken into account too. Brute force.
-  % No rules at all, yet. The ideal: look at jalt table.
-  % And perhaps other tables (falt?, cswh?). What about kaf?
-  \begingroup
-    \bbl at foreach{%   
-        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}{%
-      \setbox\z@\hbox{%  Only final, for the moment
-        ^^^^200d\char"##1=%
-        \addfontfeature{RawFeature=+jalt}%
-        ^^^^200d\char"##1}%
-      \directlua{
-        local chars = {}
-        for item in node.traverse(tex.box[0].head) do
-          if item.id == node.id'glyph' and item.char > 128 and
-              not (item.char == 0x200D) then
-            table.insert(chars, item.char)
-          end
-        end
-        if not (chars[1] == chars[2]) then
-          Babel.ar_tolong[chars[1]] = chars[2]
-        end
-      }}%
-  \endgroup}
-  
-\fi
-
 \endinput
diff --git a/news-guides/news/whats-new-in-babel-3.59.md b/news-guides/news/whats-new-in-babel-3.59.md
new file mode 100644
index 0000000..96f4976
--- /dev/null
+++ b/news-guides/news/whats-new-in-babel-3.59.md
@@ -0,0 +1,63 @@
+# What's new in babel 3.59
+
+(Under development.)
+
+## More experimental Arabic justification
+
+But useable at your own rink, because the interface is unfinished and
+very likely will change. Note also there are still many pending issues –
+for example, lists just doesn't work.
+
+There are two modes: `elongated` and `kashida`. Actually the latter is the
+same as the former, but without real justification alternatives. If you
+only want elongated glyphs with ‘elongated’, just don’t define any
+kashida rule.
+
+For practical reasons, currently `bidi=basic` is required.
+
+The points were kashida have to be inserted if necessary are defined by
+means of ‘transforms’. In other words, they are not hardcoded and you
+can define you own rules with different weights (including rules for
+words matching some patterns). A very simple and basic transform is
+included for ’plain’ Arabic fonts, which attempts to distribute the
+tatwil as evenly as possible, starting at the end of the line. Its
+named `kashida.plain` and no ligature is taken into account (except, of
+course, for the lam-alif).
+
+So:
+```tex
+\usepackage[bidi=basic]{babel}
+
+\babelprovide[import, main,
+  typography/linebreaking = k, % This will change for sure!
+  transforms = kashida.plain
+  ]{arabic}
+  
+\babelfont{rm}{FreeSerif}
+```
+
+An example of how to fine tune these rules is (with Sakkal Majalla):
+```
+\babelprehyphenation{arabic}{ () ب () ر }{ kashida = 0 }
+```
+Of course, these setting must be also font dependent, but for the
+moment this is what it is.
+
+As an example, the following rule is applied to words with at least 3
+letters. A (probably long) kashida is added to the last but one
+char with certain combinations.
+```
+\babelprehyphenation{arabic}{
+  {a}
+  () [ي ئ ه ش س ق ف غ ع ض ص ن م ك ظ ط خ ح ج ث ت ب ] () % ل
+  [ي ئ ه ق ن ك ث ت ب ا أ إ آ و ؤ ذ د ز ر ة]
+  [|،,.){]}] }
+{ kashida = 500 }
+\babelprehyphenation{arabic}{ () ل () [ ا أ إ آ] }{ kashida = 0 }
+```
+
+This feature can be deactivated with:
+```tex
+\babeladjust{ justify.arabic = off }
+```
+Use `on` to reactivate it.
diff --git a/samples/lua-arabic.pdf b/samples/lua-arabic.pdf
index 714831a..6ee50a0 100644
Binary files a/samples/lua-arabic.pdf and b/samples/lua-arabic.pdf differ
diff --git a/samples/lua-arabic.tex b/samples/lua-arabic.tex
index c09428c..b8e6bd8 100644
--- a/samples/lua-arabic.tex
+++ b/samples/lua-arabic.tex
@@ -1,10 +1,21 @@
 %$LuaLaTeX -*- coding: utf-8 ; mode: latex; TeX-engine: luatex; -*-
 \documentclass[a4paper]{book}
 
+% ===================
 \usepackage[english, arabic, provide=*,
             bidi=basic, 
             headfoot=arabic,  % an alternative is layout=sectioning
             layout=counters.tabular]{babel}
+% == Alternative for kashida ==    
+% \usepackage[english,
+%             bidi=basic, 
+%             headfoot=arabic,  % an alternative is layout=sectioning
+%             layout=counters.tabular]{babel}        
+% \babelprovide[import, main,
+%   % typography/linebreaking = k,
+%   % transforms = kashida.plain
+%   ]{arabic}
+% =====================
 
 \babelfont{rm}
           [ItalicFont=FreeSerif, Numbers=Arabic]





More information about the latex3-commits mailing list.