From 45491db9ecb6686384257f5f3c0b3927716f7393 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Wed, 24 Mar 2021 21:27:50 +0000 Subject: babel (24mar21) git-svn-id: svn://tug.org/texlive/trunk@58684 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/latex/babel/README.md | 23 +- Master/texmf-dist/doc/latex/babel/babel.pdf | Bin 818518 -> 824234 bytes Master/texmf-dist/source/latex/babel/babel.dtx | 419 ++++++++++++++------- Master/texmf-dist/source/latex/babel/babel.ins | 2 +- Master/texmf-dist/source/latex/babel/bbcompat.dtx | 2 +- Master/texmf-dist/source/latex/babel/locale.zip | Bin 778243 -> 778354 bytes Master/texmf-dist/tex/generic/babel/babel.def | 42 ++- Master/texmf-dist/tex/generic/babel/babel.sty | 2 +- Master/texmf-dist/tex/generic/babel/hyphen.cfg | 6 +- .../tex/generic/babel/locale/es/babel-es.ini | 7 + .../tex/generic/babel/locale/mr/babel-mr.ini | 6 +- Master/texmf-dist/tex/generic/babel/luababel.def | 292 +++++++++----- Master/texmf-dist/tex/generic/babel/nil.ldf | 2 +- 13 files changed, 540 insertions(+), 263 deletions(-) diff --git a/Master/texmf-dist/doc/latex/babel/README.md b/Master/texmf-dist/doc/latex/babel/README.md index 1ec95e18268..723cf41d822 100644 --- a/Master/texmf-dist/doc/latex/babel/README.md +++ b/Master/texmf-dist/doc/latex/babel/README.md @@ -1,4 +1,4 @@ -## Babel 3.55 +## Babel 3.56 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 . -Changes in version 3.55 are described in: +Changes in version 3.56 are described in: -https://github.com/latex3/babel/blob/master/news-guides/news/whats-new-in-babel-3.55.md +https://github.com/latex3/babel/blob/master/news-guides/news/whats-new-in-babel-3.56.md Apart from the manual, you can find information on some aspects of babel at: @@ -46,16 +46,19 @@ respective authors. ### Summary of Latest changes ``` -3.55 2021-03-03?? - * Captions for Uyghur. +3.56 2021-03-24 + * Transforms (\babelprehyphenation, \babelposthyphenation) + - Key 'space', in em units. + - Key 'spacefactor', based on the current word separation. + - Multiple 'insert's allowed. + - Definable in 'ini' files. + - Arbitrary characters in pattern. * Fixes: - - Wrong caption in Romanian for Index (#117). - - Missing lines in ngermanb.sty (#118). - * There is also some tentative code to improve pgfpicture with - RTL texts. + - 'insert' and 'data' didn't always set/get the expected node. + - Hyphen was not shown in Marathi (#123) ``` ### Previous changes -See https://github.com/latex3/babel/blob/master/news-guides/news/ +See https://github.com/latex3/babel/blob/master/news-guides/README.md#whats-new diff --git a/Master/texmf-dist/doc/latex/babel/babel.pdf b/Master/texmf-dist/doc/latex/babel/babel.pdf index 89135c5cb23..588c656f93e 100644 Binary files a/Master/texmf-dist/doc/latex/babel/babel.pdf and b/Master/texmf-dist/doc/latex/babel/babel.pdf differ diff --git a/Master/texmf-dist/source/latex/babel/babel.dtx b/Master/texmf-dist/source/latex/babel/babel.dtx index e91394c7bfb..9c8ff775c03 100644 --- a/Master/texmf-dist/source/latex/babel/babel.dtx +++ b/Master/texmf-dist/source/latex/babel/babel.dtx @@ -31,7 +31,7 @@ % % \iffalse %<*filedriver> -\ProvidesFile{babel.dtx}[2021/03/03 v3.55 The Babel package] +\ProvidesFile{babel.dtx}[2021/03/24 v3.56 The Babel package] \documentclass{ltxdoc} \GetFileInfo{babel.dtx} \usepackage{fontspec} @@ -750,22 +750,6 @@ environment of |\foreignlanguage|, except when the option |bidi| is set -- in this case, |\foreignlanguage| emits a |\leavevmode|, while |otherlanguage*| does not. -\Describe{\begin\menv{hyphenrules}}{\marg{language}\Eenv{hyphenrules}} - -The environment \Lenv{hyphenrules} can be used to select \emph{only} the -hyphenation rules to be used (it can be used as command, too). This can -for instance be used to select `nohyphenation', provided that in -\file{language.dat} the `language' \textsf{nohyphenation} is defined by -loading \file{zerohyph.tex}. It deactivates language shorthands, too -(but not user shorthands). - -Except for these simple uses, |hyphenrules| is deprecated and -|otherlanguage*| (the starred version) is preferred, because the former -does not take into account possible changes in encodings of characters -like, say, |'| done by some languages (eg, \textsf{italian}, -\textsf{french}, \textsf{ukraineb}). To set hyphenation exceptions, use -|\babelhyphenation| (see below). - \subsection{More on selection} \Describe{\babeltags}{\char`\{\m{tag1} \texttt{=} \m{language1}, \m{tag2} @@ -2967,6 +2951,28 @@ font encodings are the same, like in Unicode based engines. language, you can add at least some typical cases. \end{note} +\begin{note} + To set hyphenation exceptions in the preamble before any language is + explicitly set with a selector, use |\babelhyphenation| instead of + |\hyphenation|. In the preamble the hyphenation rules are not always + fully set up and an error can be raised. +\end{note} + +\Describe{\begin\menv{hyphenrules}}{\marg{language}\Eenv{hyphenrules}} + +The environment \Lenv{hyphenrules} can be used to select \emph{only} the +hyphenation rules to be used (it can be used as command, too). This can +for instance be used to select `nohyphenation', provided that in +\file{language.dat} the `language' \textsf{nohyphenation} is defined by +loading \file{zerohyph.tex}. It deactivates language shorthands, too +(but not user shorthands). + +Except for these simple uses, |hyphenrules| is deprecated and +|otherlanguage*| (the starred version) is preferred, because the former +does not take into account possible changes in encodings of characters +like, say, |'| done by some languages (eg, \textsf{italian}, +\textsf{french}, \textsf{ukraineb}). + \Describe{\babelpatterns}{\texttt{[}\langlist\texttt{]}% \marg{patterns}} @@ -3002,6 +3008,18 @@ Unicode engines, spacing is based on the ``current'' em unit (the size of the previous char in \luatex, and the font size set by the last |\selectfont| in \xetex). +\subsection{Transforms} + +Transforms (only \luatex) provide a way to process the text on the +typesetting level in several language-dependent ways, like non-standard +hyphenation, special line breaking rules, script to script conversion, +spacing conventions and so on.\footnote{They are similar in concept, +but not the same, as those in Unicode.} + +It currently embraces |\babelprehyphenation| and +|\babelposthyphenation|, which have been available for several months. +\New{3.56} In this version they can be defined in |ini| files, too. + \Describe{\babelposthyphenation}{\marg{hyphenrules-name}% \marg{lua-pattern}\marg{replacement}} @@ -3042,20 +3060,15 @@ future implementation may alternatively accept \textsf{lpeg}. \Describe{\babelprehyphenation}{\marg{locale-name}% \marg{lua-pattern}\marg{replacement}} - -\New{3.44-3-52} This command is not strictly about hyphenation, but -it is included here because it is a clear counterpart of -|\babelposthyphenation|. It is similar to the latter, but (as its name -implies) applied before hyphenation. There are other differences: (1) -the first argument is the locale instead the name of 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 (but you can not insert spaces). +\New{3.44-3-52} It is similar to the latter, but (as its name implies) +applied before hyphenation. There are other differences: (1) the first +argument is the locale instead the name of 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. -Performance is still somewhat poor in some cases, but it is fast in the -typical ones. +It handles glyphs and spaces. This feature is activated with the first |\babelposthyphenation| or |\babelprehyphenation|. @@ -4849,8 +4862,8 @@ help from Bernd Raichle, for which I am grateful. % \section{Tools} % % \begin{macrocode} -%<> -%<> +%<> +%<> % \end{macrocode} % % \textbf{Do not use the following macros in \texttt{ldf} files. They @@ -10657,6 +10670,7 @@ help from Bernd Raichle, for which I am grateful. \let\bbl@KVP@intraspace\@nil \let\bbl@KVP@intrapenalty\@nil \let\bbl@KVP@onchar\@nil + \let\bbl@KVP@transforms\@nil \let\bbl@KVP@alph\@nil \let\bbl@KVP@Alph\@nil \let\bbl@KVP@labels\@nil @@ -10699,6 +10713,10 @@ help from Bernd Raichle, for which I am grateful. \ifx\bbl@KVP@captions\@nil \let\bbl@KVP@captions\bbl@KVP@import \fi + % == + \ifx\bbl@KVP@transforms\@nil\else + \bbl@replace\bbl@KVP@transforms{ }{,}% + \fi % Load ini \bbl@ifunset{date#2}% {\bbl@provide@new{#2}}% @@ -11294,6 +11312,8 @@ help from Bernd Raichle, for which I am grateful. \bbl@cs{@kv@identification.warning#1}\\% Reported }}} % +\let\bbl@release@transforms\@empty +% \def\bbl@ini@exports#1{% % Identification always exported \bbl@iniwarning{}% @@ -11319,6 +11339,8 @@ help from Bernd Raichle, for which I am grateful. \ifbbl@bcptoname \bbl@csarg\xdef{bcp@map@\bbl@cl{tbcp}}{\languagename}% \fi + % Finish here transforms, too + \bbl@release@transforms\relax % \relax closes the last item. % Conditional \ifnum#1>\z@ % 0 = only info, 1, 2 = basic, (re)new \bbl@exportkey{lnbrk}{typography.linebreaking}{h}% @@ -11676,6 +11698,39 @@ help from Bernd Raichle, for which I am grateful. \def\bbl@xdatecntr[#1|#2]{\localenumeral{#2}{#1}} % \end{macrocode} % +% \textbf{Transforms.} +% +% \begin{macrocode} +\let\bbl@release@transforms\@empty +\@namedef{bbl@inikv@transforms.prehyphenation}{% + \bbl@transforms\babelprehyphenation} +\@namedef{bbl@inikv@transforms.posthyphenation}{% + \bbl@transforms\babelposthyphenation} +\def\bbl@transforms@aux#1#2#3,#4\relax{#1{#2}{#3}{#4}} +\begingroup + \catcode`\%=12 + \catcode`\&=14 + \gdef\bbl@transforms#1#2#3{&% + \ifx\bbl@KVP@transforms\@nil\else + \directlua{ + str = [==[#2]==] + str = str:gsub('%.%d+%.%d+$', '') + tex.print([[\def\string\babeltempa{]] .. str .. [[}]]) + }&% + \bbl@xin@{,\babeltempa,}{,\bbl@KVP@transforms,}&% + \ifin@ + \in@{.0$}{#2$}&% + \ifin@ + \bbl@add\bbl@release@transforms{&% + \relax\bbl@transforms@aux#1{\languagename}{#3}}&% + \else + \bbl@add\bbl@release@transforms{, {#3}}&% + \fi + \fi + \fi} +\endgroup +% \end{macrocode} +% % Language and Script values to be used when defining a font or % setting the direction are set with the following macros. % @@ -13881,6 +13936,31 @@ end Babel.hyphenate_replace(head, 1) end + function Babel.debug_hyph(w, wn, sc, first, last, last_match) + local ss = '' + for pp = 1, 40 do + if wn[pp] then + if wn[pp].id == 29 then + ss = ss .. unicode.utf8.char(wn[pp].char) + else + ss = ss .. '{' .. wn[pp].id .. '}' + end + end + end + print('nod', ss) + print('lst_m', + string.rep(' ', unicode.utf8.len( + string.sub(w, 1, last_match))-1) .. '>') + print('str', w) + print('sc', string.rep(' ', sc-1) .. '^') + if first == last then + print('f=l', string.rep(' ', first-1) .. '!') + else + print('f/l', string.rep(' ', first-1) .. '[' .. + string.rep(' ', last-first-1) .. ']') + end + end + Babel.us_char = string.char(31) function Babel.hyphenate_replace(head, mode) @@ -13891,11 +13971,11 @@ end while true do &% for each subtext block - local w, wn, nw, lang = Babel.fetch_subtext[mode](word_head) + local w, w_nodes, nw, lang = Babel.fetch_subtext[mode](word_head) if Babel.debug then print() - print('@@@@@', w, nw) + print((mode == 0) and '@@@@<' or '@@@@>', w) end if nw == nil and w == '' then break end @@ -13906,11 +13986,11 @@ end &% For each saved (pre|post)hyphenation. TODO. Reconsider how &% loops are nested. for k=1, #lbkr[lang] do - local p = lbkr[lang][k].pattern + local p = lbkr[lang][k].pattern local r = lbkr[lang][k].replace if Babel.debug then - print('=====', p, mode) + print('*****', p, mode) end &% This variable is set in some cases below to the first *byte* @@ -13918,10 +13998,10 @@ end &% computed position based on sc if w has changed. local last_match = 0 - &% For every match. + &% For every match. while true do if Babel.debug then - print('-----') + print('=====') end local new &% used when inserting and removing nodes local refetch = false @@ -13933,7 +14013,7 @@ end &% number with the position), and keep actual captures &% (from (...)), if any, in matches. local first = table.remove(matches, 1) - local last = table.remove(matches, #matches) + local last = table.remove(matches, #matches) &% Non re-fetched substrings may contain \31, which separates &% subsubstrings. if string.find(w:sub(first, last-1), Babel.us_char) then break end @@ -13944,126 +14024,171 @@ end first = u.len(w:sub(1, first-1)) + 1 last = u.len(w:sub(1, last-1)) &% now last points to C - if Babel.debug then - print(p) - print('', 'sc', 'first', 'last', 'last_m', 'w') + &% This loop stores in n small table the nodes + &% corresponding to the pattern. Used by 'data' to provide a + &% predictable behavior with 'insert' (now w_nodes is modified on + &% the fly), and also access to 'remove'd nodes. + local sc = first-1 &% Used below, too + local data_nodes = {} + + for q = 1, last-first+1 do + data_nodes[q] = w_nodes[sc+q] end &% This loop traverses the matched substring and takes the &% corresponding action stored in the replacement list. &% sc = the position in substr nodes / string &% rc = the replacement table index - local sc = first-1 local rc = 0 + while rc < last-first+1 do &% for each replacement if Babel.debug then - print('.....') + print('.....', rc + 1) end sc = sc + 1 rc = rc + 1 - local crep = r[rc] - local char_node = wn[sc] - local char_base = char_node - local end_replacement = false - if crep and crep.data then - char_base = wn[crep.data+first-1] + if Babel.debug then + Babel.debug_hyph(w, w_nodes, sc, first, last, last_match) end - if Babel.debug then - print('*', sc, first, last, last_match, w) + local crep = r[rc] + local item = w_nodes[sc] + local item_base = item + local placeholder = Babel.us_char + local d + + if crep and crep.data then + item_base = data_nodes[crep.data] end - if crep and next(crep) == nil then &% {} - last_match = save_last + if crep and next(crep) == nil then &% = {} + last_match = save_last &% Optimization + goto next - elseif crep == nil then &% remove - node.remove(head, char_node) - table.remove(wn, sc) + elseif crep == nil or crep.remove then + node.remove(head, item) + table.remove(w_nodes, sc) w = u.sub(w, 1, sc-1) .. u.sub(w, sc+1) - last_match = utf8.offset(w, sc) - sc = sc - 1 &% Nothing has been inserted + sc = sc - 1 &% Nothing has been inserted. + last_match = utf8.offset(w, sc+1) + goto next + + elseif crep and crep.string then + local str = crep.string(matches) + if str == '' then &% Gather with nil + node.remove(head, item) + table.remove(w_nodes, sc) + w = u.sub(w, 1, sc-1) .. u.sub(w, sc+1) + sc = sc - 1 &% Nothing has been inserted. + else + local loop_first = true + for s in string.utfvalues(str) do + d = node.copy(item_base) + d.char = s + if loop_first then + loop_first = false + head, new = node.insert_before(head, item, d) + if sc == 1 then + word_head = head + end + w_nodes[sc] = d + w = u.sub(w, 1, sc-1) .. u.char(s) .. u.sub(w, sc+1) + else + sc = sc + 1 + head, new = node.insert_before(head, item, d) + table.insert(w_nodes, sc, new) + w = u.sub(w, 1, sc-1) .. u.char(s) .. u.sub(w, sc) + end + if Babel.debug then + print('.....', 'str') + Babel.debug_hyph(w, w_nodes, sc, first, last, last_match) + end + end &% for + node.remove(head, item) + end &% if '' + last_match = utf8.offset(w, sc+1) + goto next elseif mode == 1 and crep and (crep.pre or crep.no or crep.post) then - local d = node.new(7, 0) &% (disc, discretionary) - d.pre = Babel.str_to_nodes(crep.pre, matches, char_base) - d.post = Babel.str_to_nodes(crep.post, matches, char_base) - d.replace = Babel.str_to_nodes(crep.no, matches, char_base) - d.attr = char_base.attr + d = node.new(7, 0) &% (disc, discretionary) + d.pre = Babel.str_to_nodes(crep.pre, matches, item_base) + d.post = Babel.str_to_nodes(crep.post, matches, item_base) + d.replace = Babel.str_to_nodes(crep.no, matches, item_base) + d.attr = item_base.attr if crep.pre == nil then &% TeXbook p96 d.penalty = crep.penalty or tex.hyphenpenalty else d.penalty = crep.penalty or tex.exhyphenpenalty end - head, new = node.insert_before(head, char_node, d) - end_replacement = true + placeholder = '|' + head, new = node.insert_before(head, item, d) + + elseif mode == 0 and crep and (crep.pre or crep.no or crep.post) then + &% ERROR elseif crep and crep.penalty then - local d = node.new(14, 0) &% (penalty, userpenalty) - d.attr = char_base.attr + d = node.new(14, 0) &% (penalty, userpenalty) + d.attr = item_base.attr d.penalty = crep.penalty - head, new = node.insert_before(head, char_node, d) - end_replacement = true - - elseif crep and crep.string then - local str = crep.string(matches) - if str == '' then &% Gather with nil - refetch = true - if sc == 1 then - word_head = char_node.next - end - head, new = node.remove(head, char_node) - elseif char_node.id == 29 and u.len(str) == 1 then - char_node.char = string.utfvalue(str) - w = u.sub(w, 1, sc-1) .. str .. u.sub(w, sc+1) - last_match = utf8.offset(w, sc+1) - else - refetch = true - local n - for s in string.utfvalues(str) do - if char_node.id == 7 then - &% TODO. Remove this limitation. - texio.write_nl('Automatic hyphens cannot be replaced, just removed.') - else - n = node.copy(char_base) - end - n.char = s - if sc == 1 then - head, new = node.insert_before(head, char_node, n) - word_head = new - else - node.insert_before(head, char_node, n) - end - end - node.remove(head, char_node) - end &% string length - end &% if char and char.string (ie replacement cases) - - &% Shared by disc and penalty. - if end_replacement then - if sc == 1 then - word_head = new + head, new = node.insert_before(head, item, d) + + elseif crep and crep.space then + &% 655360 = 10 pt = 10 * 65536 sp + d = node.new(12, 13) &% (glue, spaceskip) + local quad = font.getfont(item_base.font).size or 655360 + node.setglue(d, crep.space[1] * quad, + crep.space[2] * quad, + crep.space[3] * quad) + if mode == 0 then + placeholder = '|' end - if crep.insert then - last_match = save_last - else - node.remove(head, char_node) - w = u.sub(w, 1, sc-1) .. Babel.us_char .. u.sub(w, sc+1) - last_match = utf8.offset(w, sc) + head, new = node.insert_before(head, item, d) + + elseif crep and crep.spacefactor then + d = node.new(12, 13) &% (glue, spaceskip) + local base_font = font.getfont(item_base.font) + node.setglue(d, + crep.spacefactor[1] * base_font.parameters['space'], + crep.spacefactor[2] * base_font.parameters['space_stretch'], + crep.spacefactor[3] * base_font.parameters['space_shrink']) + if mode == 0 then + placeholder = '|' end + head, new = node.insert_before(head, item, d) + + elseif mode == 0 and crep and crep.space then + &% ERROR + + end &% ie replacement cases + + &% Shared by disc, space and penalty. + if sc == 1 then + word_head = head end + if crep.insert then + w = u.sub(w, 1, sc-1) .. placeholder .. u.sub(w, sc) + table.insert(w_nodes, sc, new) + last = last + 1 + else + w_nodes[sc] = d + node.remove(head, item) + w = u.sub(w, 1, sc-1) .. placeholder .. u.sub(w, sc+1) + end + + last_match = utf8.offset(w, sc+1) + + ::next:: + end &% for each replacement if Babel.debug then - print('/', sc, first, last, last_match, w) + print('.....', '/') + Babel.debug_hyph(w, w_nodes, sc, first, last, last_match) end - &% TODO. refetch will be eventually unnecesary. - if refetch then - w, wn, nw, lang = Babel.fetch_subtext[mode](word_head) - end - end &% for match + end &% for patterns ::next:: @@ -14128,11 +14253,14 @@ end \begingroup \def\babeltempa{\bbl@add@list\babeltempb}&% \let\babeltempb\@empty - \bbl@foreach{#3}{&% + \def\bbl@tempa{#3}&% TODO. Ugly trick to preserve {}: + \bbl@replace\bbl@tempa{,}{ ,}&% + \expandafter\bbl@foreach\expandafter{\bbl@tempa}{&% \bbl@ifsamestring{##1}{remove}&% {\bbl@add@list\babeltempb{nil}}&% {\directlua{ - local rep = [[##1]] + local rep = [=[##1]=] + rep = rep:gsub('^%s*(remove)%s*$', 'remove = true') rep = rep:gsub('^%s*(insert)%s*,', 'insert = true, ') rep = rep:gsub( '(no)%s*=%s*([^%s,]*)', Babel.capture_func) rep = rep:gsub( '(pre)%s*=%s*([^%s,]*)', Babel.capture_func) @@ -14143,6 +14271,7 @@ end \directlua{ local lbkr = Babel.linebreaking.replacements[1] local u = unicode.utf8 + local id = \the\csname l@#1\endcsname &% Convert pattern: local patt = string.gsub([==[#2]==], '%s', '') if not u.find(patt, '()', nil, true) then @@ -14151,12 +14280,15 @@ end patt = string.gsub(patt, '%(%)%^', '^()') patt = string.gsub(patt, '%$%(%)', '()$') patt = u.gsub(patt, '{(.)}', - function (n) - return '%' .. (tonumber(n) and (tonumber(n)+1) or n) - end) - lbkr[\the\csname l@#1\endcsname] = lbkr[\the\csname l@#1\endcsname] or {} - table.insert(lbkr[\the\csname l@#1\endcsname], - { pattern = patt, replace = { \babeltempb } }) + function (n) + return '%' .. (tonumber(n) and (tonumber(n)+1) or n) + end) + patt = u.gsub(patt, '{(%x%x%x%x+)}', + function (n) + return u.gsub(u.char(tonumber(n, 16)), '(%p)', '%%%1') + end) + lbkr[id] = lbkr[id] or {} + table.insert(lbkr[id], { pattern = patt, replace = { \babeltempb } }) }&% \endgroup} % TODO. Copypaste pattern. @@ -14165,18 +14297,26 @@ end \begingroup \def\babeltempa{\bbl@add@list\babeltempb}&% \let\babeltempb\@empty - \bbl@foreach{#3}{&% + \def\bbl@tempa{#3}&% TODO. Ugly trick to preserve {}: + \bbl@replace\bbl@tempa{,}{ ,}&% + \expandafter\bbl@foreach\expandafter{\bbl@tempa}{&% \bbl@ifsamestring{##1}{remove}&% {\bbl@add@list\babeltempb{nil}}&% {\directlua{ - local rep = [[##1]] + local rep = [=[##1]=] + 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%.]+)', + 'space = {' .. '%2, %3, %4' .. '}') + rep = rep:gsub( '(spacefactor)%s*=%s*([%d%.]+)%s+([%d%.]+)%s+([%d%.]+)', + 'spacefactor = {' .. '%2, %3, %4' .. '}') tex.print([[\string\babeltempa{{]] .. rep .. [[}}]]) }}}&% \directlua{ local lbkr = Babel.linebreaking.replacements[0] local u = unicode.utf8 + local id = \the\csname bbl@id@@#1\endcsname &% Convert pattern: local patt = string.gsub([==[#2]==], '%s', '') if not u.find(patt, '()', nil, true) then @@ -14185,12 +14325,15 @@ end &% patt = string.gsub(patt, '%(%)%^', '^()') &% patt = string.gsub(patt, '([^%%])%$%(%)', '%1()$') patt = u.gsub(patt, '{(.)}', - function (n) - return '%' .. (tonumber(n) and (tonumber(n)+1) or n) - end) - lbkr[\the\csname bbl@id@@#1\endcsname] = lbkr[\the\csname bbl@id@@#1\endcsname] or {} - table.insert(lbkr[\the\csname bbl@id@@#1\endcsname], - { pattern = patt, replace = { \babeltempb } }) + function (n) + return '%' .. (tonumber(n) and (tonumber(n)+1) or n) + end) + patt = u.gsub(patt, '{(%x%x%x%x+)}', + function (n) + return u.gsub(u.char(tonumber(n, 16)), '(%p)', '%%%1') + end) + lbkr[id] = lbkr[id] or {} + table.insert(lbkr[id], { pattern = patt, replace = { \babeltempb } }) }&% \endgroup} \endgroup @@ -21080,13 +21223,13 @@ function Babel.bidi(head, ispar, hdir) first_et = nil has_en = false end - + -- Force mathdir in math if ON (currently works as expected only -- with 'l') if inmath and d == 'on' then d = ('TRT' == tex.mathdir) and 'r' or 'l' end - + if d then if d == 'al' then d = 'r' diff --git a/Master/texmf-dist/source/latex/babel/babel.ins b/Master/texmf-dist/source/latex/babel/babel.ins index 29d689b4b86..bb675249c6f 100644 --- a/Master/texmf-dist/source/latex/babel/babel.ins +++ b/Master/texmf-dist/source/latex/babel/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/03/03} +\def\filedate{2021/03/24} \def\batchfile{babel.ins} \input docstrip.tex diff --git a/Master/texmf-dist/source/latex/babel/bbcompat.dtx b/Master/texmf-dist/source/latex/babel/bbcompat.dtx index 91092197f2a..efd3eb77dbf 100644 --- a/Master/texmf-dist/source/latex/babel/bbcompat.dtx +++ b/Master/texmf-dist/source/latex/babel/bbcompat.dtx @@ -30,7 +30,7 @@ % % \iffalse %<*dtx> -\ProvidesFile{bbcompat.dtx}[2021/03/03 v3.55] +\ProvidesFile{bbcompat.dtx}[2021/03/24 v3.56] % % %% File 'bbcompat.dtx' diff --git a/Master/texmf-dist/source/latex/babel/locale.zip b/Master/texmf-dist/source/latex/babel/locale.zip index 34b8e0b0e11..0f9331de0cd 100644 Binary files a/Master/texmf-dist/source/latex/babel/locale.zip and b/Master/texmf-dist/source/latex/babel/locale.zip differ diff --git a/Master/texmf-dist/tex/generic/babel/babel.def b/Master/texmf-dist/tex/generic/babel/babel.def index 60c7c172e36..98495230347 100644 --- a/Master/texmf-dist/tex/generic/babel/babel.def +++ b/Master/texmf-dist/tex/generic/babel/babel.def @@ -39,7 +39,7 @@ \wlog{File: #1 #4 #3 <#2>}% \let\ProvidesFile\@undefined} \fi -\ProvidesFile{babel.def}[2021/03/03 3.55 Babel common definitions] +\ProvidesFile{babel.def}[2021/03/24 3.56 Babel common definitions] \ifx\AtBeginDocument\@undefined % TODO. change test. % == Code for plain == \def\@empty{} @@ -397,8 +397,8 @@ \fi \countdef\last@language=19 % TODO. why? remove? \def\addlanguage{\csname newlanguage\endcsname} -\def\bbl@version{3.55} -\def\bbl@date{2021/03/03} +\def\bbl@version{3.56} +\def\bbl@date{2021/03/24} \def\adddialect#1#2{% \global\chardef#1#2\relax \bbl@usehooks{adddialect}{{#1}{#2}}% @@ -2335,6 +2335,7 @@ \let\bbl@KVP@intraspace\@nil \let\bbl@KVP@intrapenalty\@nil \let\bbl@KVP@onchar\@nil + \let\bbl@KVP@transforms\@nil \let\bbl@KVP@alph\@nil \let\bbl@KVP@Alph\@nil \let\bbl@KVP@labels\@nil @@ -2377,6 +2378,10 @@ \ifx\bbl@KVP@captions\@nil \let\bbl@KVP@captions\bbl@KVP@import \fi + % == + \ifx\bbl@KVP@transforms\@nil\else + \bbl@replace\bbl@KVP@transforms{ }{,}% + \fi % Load ini \bbl@ifunset{date#2}% {\bbl@provide@new{#2}}% @@ -2893,6 +2898,7 @@ From babel-\bbl@cs{lini@\languagename}.ini:\\% \bbl@cs{@kv@identification.warning#1}\\% Reported }}} +\let\bbl@release@transforms\@empty \def\bbl@ini@exports#1{% % Identification always exported \bbl@iniwarning{}% @@ -2918,6 +2924,8 @@ \ifbbl@bcptoname \bbl@csarg\xdef{bcp@map@\bbl@cl{tbcp}}{\languagename}% \fi + % Finish here transforms, too + \bbl@release@transforms\relax % \relax closes the last item. % Conditional \ifnum#1>\z@ % 0 = only info, 1, 2 = basic, (re)new \bbl@exportkey{lnbrk}{typography.linebreaking}{h}% @@ -3208,6 +3216,34 @@ \bbl@replace@finish@iii\bbl@toreplace} \def\bbl@datecntr{\expandafter\bbl@xdatecntr\expandafter} \def\bbl@xdatecntr[#1|#2]{\localenumeral{#2}{#1}} +\let\bbl@release@transforms\@empty +\@namedef{bbl@inikv@transforms.prehyphenation}{% + \bbl@transforms\babelprehyphenation} +\@namedef{bbl@inikv@transforms.posthyphenation}{% + \bbl@transforms\babelposthyphenation} +\def\bbl@transforms@aux#1#2#3,#4\relax{#1{#2}{#3}{#4}} +\begingroup + \catcode`\%=12 + \catcode`\&=14 + \gdef\bbl@transforms#1#2#3{&% + \ifx\bbl@KVP@transforms\@nil\else + \directlua{ + str = [==[#2]==] + str = str:gsub('%.%d+%.%d+$', '') + tex.print([[\def\string\babeltempa{]] .. str .. [[}]]) + }&% + \bbl@xin@{,\babeltempa,}{,\bbl@KVP@transforms,}&% + \ifin@ + \in@{.0$}{#2$}&% + \ifin@ + \bbl@add\bbl@release@transforms{&% + \relax\bbl@transforms@aux#1{\languagename}{#3}}&% + \else + \bbl@add\bbl@release@transforms{, {#3}}&% + \fi + \fi + \fi} +\endgroup \def\bbl@provide@lsys#1{% \bbl@ifunset{bbl@lname@#1}% {\bbl@load@info{#1}}% diff --git a/Master/texmf-dist/tex/generic/babel/babel.sty b/Master/texmf-dist/tex/generic/babel/babel.sty index f0c953c9951..ca2c203a858 100644 --- a/Master/texmf-dist/tex/generic/babel/babel.sty +++ b/Master/texmf-dist/tex/generic/babel/babel.sty @@ -33,7 +33,7 @@ %% \NeedsTeXFormat{LaTeX2e}[2005/12/01] -\ProvidesPackage{babel}[2021/03/03 3.55 The Babel package] +\ProvidesPackage{babel}[2021/03/24 3.56 The Babel package] \@ifpackagewith{babel}{debug} {\providecommand\bbl@trace[1]{\message{^^J[ #1 ]}}% \let\bbl@debug\@firstofone diff --git a/Master/texmf-dist/tex/generic/babel/hyphen.cfg b/Master/texmf-dist/tex/generic/babel/hyphen.cfg index 2c8ef5ce321..df8e10deb11 100644 --- a/Master/texmf-dist/tex/generic/babel/hyphen.cfg +++ b/Master/texmf-dist/tex/generic/babel/hyphen.cfg @@ -37,10 +37,10 @@ \wlog{File: #1 #4 #3 <#2>}% \let\ProvidesFile\@undefined} \fi -\ProvidesFile{hyphen.cfg}[2021/03/03 3.55 Babel hyphens] +\ProvidesFile{hyphen.cfg}[2021/03/24 3.56 Babel hyphens] \xdef\bbl@format{\jobname} -\def\bbl@version{3.55} -\def\bbl@date{2021/03/03} +\def\bbl@version{3.56} +\def\bbl@date{2021/03/24} \ifx\AtBeginDocument\@undefined \def\@empty{} \let\orig@dump\dump diff --git a/Master/texmf-dist/tex/generic/babel/locale/es/babel-es.ini b/Master/texmf-dist/tex/generic/babel/locale/es/babel-es.ini index 5ed832dd28d..733293f938f 100644 --- a/Master/texmf-dist/tex/generic/babel/locale/es/babel-es.ini +++ b/Master/texmf-dist/tex/generic/babel/locale/es/babel-es.ini @@ -183,3 +183,10 @@ plusSign = + superscriptingExponent = × [counters] + +[transforms.prehyphenation] +; Experimental. Don't use in production +percent.space.1.0 = { {d}{0025} } +percent.space.1.1 = {} +percent.space.1.2 = { insert, spacefactor = .5 .3 .5, data = 1 } +percent.space.1.3 = {} diff --git a/Master/texmf-dist/tex/generic/babel/locale/mr/babel-mr.ini b/Master/texmf-dist/tex/generic/babel/locale/mr/babel-mr.ini index 8935a54b2ad..1178e561099 100644 --- a/Master/texmf-dist/tex/generic/babel/locale/mr/babel-mr.ini +++ b/Master/texmf-dist/tex/generic/babel/locale/mr/babel-mr.ini @@ -13,8 +13,8 @@ [identification] charset = utf8 -version = 1.8 -date = 2020-10-11 +version = 1.9 +date = 2021-03-16 name.local = मराठी name.english = Marathi name.babel = marathi @@ -118,7 +118,7 @@ hyphenrules = marathi lefthyphenmin = 2 righthyphenmin = 2 hyphenchar = -prehyphenchar = 0 +prehyphenchar = posthyphenchar = exhyphenchar = preexhyphenchar = diff --git a/Master/texmf-dist/tex/generic/babel/luababel.def b/Master/texmf-dist/tex/generic/babel/luababel.def index a032fbe7631..0d00d5b238d 100644 --- a/Master/texmf-dist/tex/generic/babel/luababel.def +++ b/Master/texmf-dist/tex/generic/babel/luababel.def @@ -1046,6 +1046,31 @@ end Babel.hyphenate_replace(head, 1) end + function Babel.debug_hyph(w, wn, sc, first, last, last_match) + local ss = '' + for pp = 1, 40 do + if wn[pp] then + if wn[pp].id == 29 then + ss = ss .. unicode.utf8.char(wn[pp].char) + else + ss = ss .. '{' .. wn[pp].id .. '}' + end + end + end + print('nod', ss) + print('lst_m', + string.rep(' ', unicode.utf8.len( + string.sub(w, 1, last_match))-1) .. '>') + print('str', w) + print('sc', string.rep(' ', sc-1) .. '^') + if first == last then + print('f=l', string.rep(' ', first-1) .. '!') + else + print('f/l', string.rep(' ', first-1) .. '[' .. + string.rep(' ', last-first-1) .. ']') + end + end + Babel.us_char = string.char(31) function Babel.hyphenate_replace(head, mode) @@ -1056,11 +1081,11 @@ end while true do &% for each subtext block - local w, wn, nw, lang = Babel.fetch_subtext[mode](word_head) + local w, w_nodes, nw, lang = Babel.fetch_subtext[mode](word_head) if Babel.debug then print() - print('@@@@@', w, nw) + print((mode == 0) and '@@@@<' or '@@@@>', w) end if nw == nil and w == '' then break end @@ -1075,7 +1100,7 @@ end local r = lbkr[lang][k].replace if Babel.debug then - print('=====', p, mode) + print('*****', p, mode) end &% This variable is set in some cases below to the first *byte* @@ -1086,7 +1111,7 @@ end &% For every match. while true do if Babel.debug then - print('-----') + print('=====') end local new &% used when inserting and removing nodes local refetch = false @@ -1109,126 +1134,171 @@ end first = u.len(w:sub(1, first-1)) + 1 last = u.len(w:sub(1, last-1)) &% now last points to C - if Babel.debug then - print(p) - print('', 'sc', 'first', 'last', 'last_m', 'w') + &% This loop stores in n small table the nodes + &% corresponding to the pattern. Used by 'data' to provide a + &% predictable behavior with 'insert' (now w_nodes is modified on + &% the fly), and also access to 'remove'd nodes. + local sc = first-1 &% Used below, too + local data_nodes = {} + + for q = 1, last-first+1 do + data_nodes[q] = w_nodes[sc+q] end &% This loop traverses the matched substring and takes the &% corresponding action stored in the replacement list. &% sc = the position in substr nodes / string &% rc = the replacement table index - local sc = first-1 local rc = 0 + while rc < last-first+1 do &% for each replacement if Babel.debug then - print('.....') + print('.....', rc + 1) end sc = sc + 1 rc = rc + 1 - local crep = r[rc] - local char_node = wn[sc] - local char_base = char_node - local end_replacement = false - if crep and crep.data then - char_base = wn[crep.data+first-1] + if Babel.debug then + Babel.debug_hyph(w, w_nodes, sc, first, last, last_match) end - if Babel.debug then - print('*', sc, first, last, last_match, w) + local crep = r[rc] + local item = w_nodes[sc] + local item_base = item + local placeholder = Babel.us_char + local d + + if crep and crep.data then + item_base = data_nodes[crep.data] end - if crep and next(crep) == nil then &% {} - last_match = save_last + if crep and next(crep) == nil then &% = {} + last_match = save_last &% Optimization + goto next - elseif crep == nil then &% remove - node.remove(head, char_node) - table.remove(wn, sc) + elseif crep == nil or crep.remove then + node.remove(head, item) + table.remove(w_nodes, sc) w = u.sub(w, 1, sc-1) .. u.sub(w, sc+1) - last_match = utf8.offset(w, sc) - sc = sc - 1 &% Nothing has been inserted + sc = sc - 1 &% Nothing has been inserted. + last_match = utf8.offset(w, sc+1) + goto next + + elseif crep and crep.string then + local str = crep.string(matches) + if str == '' then &% Gather with nil + node.remove(head, item) + table.remove(w_nodes, sc) + w = u.sub(w, 1, sc-1) .. u.sub(w, sc+1) + sc = sc - 1 &% Nothing has been inserted. + else + local loop_first = true + for s in string.utfvalues(str) do + d = node.copy(item_base) + d.char = s + if loop_first then + loop_first = false + head, new = node.insert_before(head, item, d) + if sc == 1 then + word_head = head + end + w_nodes[sc] = d + w = u.sub(w, 1, sc-1) .. u.char(s) .. u.sub(w, sc+1) + else + sc = sc + 1 + head, new = node.insert_before(head, item, d) + table.insert(w_nodes, sc, new) + w = u.sub(w, 1, sc-1) .. u.char(s) .. u.sub(w, sc) + end + if Babel.debug then + print('.....', 'str') + Babel.debug_hyph(w, w_nodes, sc, first, last, last_match) + end + end &% for + node.remove(head, item) + end &% if '' + last_match = utf8.offset(w, sc+1) + goto next elseif mode == 1 and crep and (crep.pre or crep.no or crep.post) then - local d = node.new(7, 0) &% (disc, discretionary) - d.pre = Babel.str_to_nodes(crep.pre, matches, char_base) - d.post = Babel.str_to_nodes(crep.post, matches, char_base) - d.replace = Babel.str_to_nodes(crep.no, matches, char_base) - d.attr = char_base.attr + d = node.new(7, 0) &% (disc, discretionary) + d.pre = Babel.str_to_nodes(crep.pre, matches, item_base) + d.post = Babel.str_to_nodes(crep.post, matches, item_base) + d.replace = Babel.str_to_nodes(crep.no, matches, item_base) + d.attr = item_base.attr if crep.pre == nil then &% TeXbook p96 d.penalty = crep.penalty or tex.hyphenpenalty else d.penalty = crep.penalty or tex.exhyphenpenalty end - head, new = node.insert_before(head, char_node, d) - end_replacement = true + placeholder = '|' + head, new = node.insert_before(head, item, d) + + elseif mode == 0 and crep and (crep.pre or crep.no or crep.post) then + &% ERROR elseif crep and crep.penalty then - local d = node.new(14, 0) &% (penalty, userpenalty) - d.attr = char_base.attr + d = node.new(14, 0) &% (penalty, userpenalty) + d.attr = item_base.attr d.penalty = crep.penalty - head, new = node.insert_before(head, char_node, d) - end_replacement = true - - elseif crep and crep.string then - local str = crep.string(matches) - if str == '' then &% Gather with nil - refetch = true - if sc == 1 then - word_head = char_node.next - end - head, new = node.remove(head, char_node) - elseif char_node.id == 29 and u.len(str) == 1 then - char_node.char = string.utfvalue(str) - w = u.sub(w, 1, sc-1) .. str .. u.sub(w, sc+1) - last_match = utf8.offset(w, sc+1) - else - refetch = true - local n - for s in string.utfvalues(str) do - if char_node.id == 7 then - &% TODO. Remove this limitation. - texio.write_nl('Automatic hyphens cannot be replaced, just removed.') - else - n = node.copy(char_base) - end - n.char = s - if sc == 1 then - head, new = node.insert_before(head, char_node, n) - word_head = new - else - node.insert_before(head, char_node, n) - end - end - node.remove(head, char_node) - end &% string length - end &% if char and char.string (ie replacement cases) - - &% Shared by disc and penalty. - if end_replacement then - if sc == 1 then - word_head = new + head, new = node.insert_before(head, item, d) + + elseif crep and crep.space then + &% 655360 = 10 pt = 10 * 65536 sp + d = node.new(12, 13) &% (glue, spaceskip) + local quad = font.getfont(item_base.font).size or 655360 + node.setglue(d, crep.space[1] * quad, + crep.space[2] * quad, + crep.space[3] * quad) + if mode == 0 then + placeholder = '|' end - if crep.insert then - last_match = save_last - else - node.remove(head, char_node) - w = u.sub(w, 1, sc-1) .. Babel.us_char .. u.sub(w, sc+1) - last_match = utf8.offset(w, sc) + head, new = node.insert_before(head, item, d) + + elseif crep and crep.spacefactor then + d = node.new(12, 13) &% (glue, spaceskip) + local base_font = font.getfont(item_base.font) + node.setglue(d, + crep.spacefactor[1] * base_font.parameters['space'], + crep.spacefactor[2] * base_font.parameters['space_stretch'], + crep.spacefactor[3] * base_font.parameters['space_shrink']) + if mode == 0 then + placeholder = '|' end + head, new = node.insert_before(head, item, d) + + elseif mode == 0 and crep and crep.space then + &% ERROR + + end &% ie replacement cases + + &% Shared by disc, space and penalty. + if sc == 1 then + word_head = head + end + if crep.insert then + w = u.sub(w, 1, sc-1) .. placeholder .. u.sub(w, sc) + table.insert(w_nodes, sc, new) + last = last + 1 + else + w_nodes[sc] = d + node.remove(head, item) + w = u.sub(w, 1, sc-1) .. placeholder .. u.sub(w, sc+1) end + + last_match = utf8.offset(w, sc+1) + + ::next:: + end &% for each replacement if Babel.debug then - print('/', sc, first, last, last_match, w) - end - - &% TODO. refetch will be eventually unnecesary. - if refetch then - w, wn, nw, lang = Babel.fetch_subtext[mode](word_head) + print('.....', '/') + Babel.debug_hyph(w, w_nodes, sc, first, last, last_match) end end &% for match + end &% for patterns ::next:: @@ -1276,11 +1346,14 @@ end \begingroup \def\babeltempa{\bbl@add@list\babeltempb}&% \let\babeltempb\@empty - \bbl@foreach{#3}{&% + \def\bbl@tempa{#3}&% TODO. Ugly trick to preserve {}: + \bbl@replace\bbl@tempa{,}{ ,}&% + \expandafter\bbl@foreach\expandafter{\bbl@tempa}{&% \bbl@ifsamestring{##1}{remove}&% {\bbl@add@list\babeltempb{nil}}&% {\directlua{ - local rep = [[##1]] + local rep = [=[##1]=] + rep = rep:gsub('^%s*(remove)%s*$', 'remove = true') rep = rep:gsub('^%s*(insert)%s*,', 'insert = true, ') rep = rep:gsub( '(no)%s*=%s*([^%s,]*)', Babel.capture_func) rep = rep:gsub( '(pre)%s*=%s*([^%s,]*)', Babel.capture_func) @@ -1291,6 +1364,7 @@ end \directlua{ local lbkr = Babel.linebreaking.replacements[1] local u = unicode.utf8 + local id = \the\csname l@#1\endcsname &% Convert pattern: local patt = string.gsub([==[#2]==], '%s', '') if not u.find(patt, '()', nil, true) then @@ -1299,12 +1373,15 @@ end patt = string.gsub(patt, '%(%)%^', '^()') patt = string.gsub(patt, '%$%(%)', '()$') patt = u.gsub(patt, '{(.)}', - function (n) - return '%' .. (tonumber(n) and (tonumber(n)+1) or n) - end) - lbkr[\the\csname l@#1\endcsname] = lbkr[\the\csname l@#1\endcsname] or {} - table.insert(lbkr[\the\csname l@#1\endcsname], - { pattern = patt, replace = { \babeltempb } }) + function (n) + return '%' .. (tonumber(n) and (tonumber(n)+1) or n) + end) + patt = u.gsub(patt, '{(%x%x%x%x+)}', + function (n) + return u.gsub(u.char(tonumber(n, 16)), '(%p)', '%%%1') + end) + lbkr[id] = lbkr[id] or {} + table.insert(lbkr[id], { pattern = patt, replace = { \babeltempb } }) }&% \endgroup} \gdef\babelprehyphenation#1#2#3{&% @@ -1312,18 +1389,26 @@ end \begingroup \def\babeltempa{\bbl@add@list\babeltempb}&% \let\babeltempb\@empty - \bbl@foreach{#3}{&% + \def\bbl@tempa{#3}&% TODO. Ugly trick to preserve {}: + \bbl@replace\bbl@tempa{,}{ ,}&% + \expandafter\bbl@foreach\expandafter{\bbl@tempa}{&% \bbl@ifsamestring{##1}{remove}&% {\bbl@add@list\babeltempb{nil}}&% {\directlua{ - local rep = [[##1]] + local rep = [=[##1]=] + 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%.]+)', + 'space = {' .. '%2, %3, %4' .. '}') + rep = rep:gsub( '(spacefactor)%s*=%s*([%d%.]+)%s+([%d%.]+)%s+([%d%.]+)', + 'spacefactor = {' .. '%2, %3, %4' .. '}') tex.print([[\string\babeltempa{{]] .. rep .. [[}}]]) }}}&% \directlua{ local lbkr = Babel.linebreaking.replacements[0] local u = unicode.utf8 + local id = \the\csname bbl@id@@#1\endcsname &% Convert pattern: local patt = string.gsub([==[#2]==], '%s', '') if not u.find(patt, '()', nil, true) then @@ -1332,12 +1417,15 @@ end &% patt = string.gsub(patt, '%(%)%^', '^()') &% patt = string.gsub(patt, '([^%%])%$%(%)', '%1()$') patt = u.gsub(patt, '{(.)}', - function (n) - return '%' .. (tonumber(n) and (tonumber(n)+1) or n) - end) - lbkr[\the\csname bbl@id@@#1\endcsname] = lbkr[\the\csname bbl@id@@#1\endcsname] or {} - table.insert(lbkr[\the\csname bbl@id@@#1\endcsname], - { pattern = patt, replace = { \babeltempb } }) + function (n) + return '%' .. (tonumber(n) and (tonumber(n)+1) or n) + end) + patt = u.gsub(patt, '{(%x%x%x%x+)}', + function (n) + return u.gsub(u.char(tonumber(n, 16)), '(%p)', '%%%1') + end) + lbkr[id] = lbkr[id] or {} + table.insert(lbkr[id], { pattern = patt, replace = { \babeltempb } }) }&% \endgroup} \endgroup diff --git a/Master/texmf-dist/tex/generic/babel/nil.ldf b/Master/texmf-dist/tex/generic/babel/nil.ldf index d7733c017a6..4d4b1e326a5 100644 --- a/Master/texmf-dist/tex/generic/babel/nil.ldf +++ b/Master/texmf-dist/tex/generic/babel/nil.ldf @@ -32,7 +32,7 @@ %% extension |.ins|) which are part of the distribution. %% -\ProvidesLanguage{nil}[2021/03/03 3.55 Nil language] +\ProvidesLanguage{nil}[2021/03/24 3.56 Nil language] \LdfInit{nil}{datenil} \ifx\l@nil\@undefined \newlanguage\l@nil -- cgit v1.2.3