diff options
author | Karl Berry <karl@freefriends.org> | 2020-01-29 22:37:53 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2020-01-29 22:37:53 +0000 |
commit | 015c5f064b14e4a79f151b46a6dd46b150520c81 (patch) | |
tree | cc3434d0ae73900950b37bc952816286d4d76d5c /Master/texmf-dist/tex/latex/polyglossia/polyglossia.sty | |
parent | e9549ffe43d42fda4e5d3778e1d26fbd95e4ae9f (diff) |
polyglossia (29jan20)
git-svn-id: svn://tug.org/texlive/trunk@53592 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/polyglossia/polyglossia.sty')
-rw-r--r-- | Master/texmf-dist/tex/latex/polyglossia/polyglossia.sty | 522 |
1 files changed, 423 insertions, 99 deletions
diff --git a/Master/texmf-dist/tex/latex/polyglossia/polyglossia.sty b/Master/texmf-dist/tex/latex/polyglossia/polyglossia.sty index 9cdb503c1ab..118017d1f4f 100644 --- a/Master/texmf-dist/tex/latex/polyglossia/polyglossia.sty +++ b/Master/texmf-dist/tex/latex/polyglossia/polyglossia.sty @@ -1,6 +1,6 @@ \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{polyglossia}[2019/11/15 v1.46 - Alternative to Babel for XeLaTeX and LuaLaTeX] +\ProvidesPackage{polyglossia}[2020/01/29 v1.47 + Modern multilingual typesetting with XeLaTeX and LuaLaTeX] \RequirePackage{etoolbox} \RequirePackage{makecmds} \RequirePackage{xkeyval}[2008/08/13] @@ -46,6 +46,7 @@ \let\xpg@loaded\@empty% list of loaded languages (polyglossia name) \let\xpg@vloaded\@empty% list of loaded variants \let\xpg@bloaded\@empty% list of loaded languages (babel name) +\let\xpg@bcp@loaded\@empty% list of loaded languages (bcp-47 id) % counter in latin \def\latinalph#1{\expandafter\latin@alph\csname c@#1\endcsname} @@ -68,14 +69,20 @@ \xpg@initial@setup % apply \familydefault changes \xpg@set@familydefault +} + +\AtBeginDocument{ + \polyglossia@AtBeginDocument: +} + +% The following needs to go after any \AtBeginDocument (also of packages +% loaded after \set[main|other]language +\AfterEndPreamble{ % now we have the C locale definition: select the language \polyglossia@AtBeginDocument@selectlanguage: % If hyphenation disabling has been requested in preamble, do it now \polyglossia@AtBeginDocument@hyphenation: } -\AtBeginDocument{ - \polyglossia@AtBeginDocument: -} %% custom message macros \providecommand*{\xpg@error}[1]{% @@ -346,7 +353,7 @@ .code:n = { \prop_gput:Nnn{\polyglossia@langsetup}{#1/script}{##1} \prop_gput:Nnx{\polyglossia@langsetup}{#1/lcscript} - {\tl_if_empty:nF{##1}{\str_lower_case:n##1}} + {\tl_if_empty:nF{##1}{\str_lowercase:n##1}} }, #1 / script .value_required:n = true, @@ -373,6 +380,13 @@ .value_required:n = true, #1 / langtag .initial:n = {}, + % the BCP-47 tag + #1 / bcp47 + .code:n = {\prop_gput:Nnn{\polyglossia@langsetup}{#1/bcp47}{##1}}, + #1 / bcp47 + .value_required:n = true, + #1 / bcp47 + .initial:n = {}, % hyphennames #1 / hyphennames .code:n = { @@ -410,6 +424,17 @@ .value_required:n = true, #1 / hyphenmins .initial:n = {2,3}, + % minimal length for hyphenation (LuaTeX only) + #1 / totalhyphenmin + .code:n = { + % check syntax + \int_compare:nNnF { \clist_count:n {##1} } = {1} + {\xpg@error{totalhyphenhypenmin~should~be~a~single~entry,~got~"##1"}} + % set prop + \prop_gput:Nnn \polyglossia@langsetup {#1/totalhyphenmin} {##1} + }, + #1 / totalhyphenmin + .value_required:n = false, % frenchspacing #1 / frenchspacing .code:n = { @@ -828,7 +853,7 @@ {\addfontfeature{Script=#2}} {\xpg@error{ The~ current~ latin ~ font~ \l_fontspec_family_tl\space does~ not~ contain~ the~"#2"~ script!\MessageBreak - Please~ define~\csname\tl_if_empty:nF{#2}{\str_lower_case:n#2}font\endcsname~ + Please~ define~\csname\tl_if_empty:nF{#2}{\str_lowercase:n#2}font\endcsname~ with~ \string\newfontfamily\space command } } @@ -1013,6 +1038,10 @@ % load a master language from an alias file \newcommand*\xpg@load@master@language[1] { \xpg@input{gloss-#1.ldf} + \ifcsundef{#1@loaded}% + { + \exp_args:Nx\polyglossia@define@language@cmd:n{#1}% + }{} \csgdef{#1@loaded}{} \global\edef\xpg@loaded{#1\ifx\xpg@loaded\@empty\else,\xpg@loaded\fi}% } @@ -1040,40 +1069,36 @@ % \setlanguagealias[<options>]{<language>}{<alias>} \DeclareDocumentCommand \setlanguagealias {s O{} m m} { - \ifcsundef{#4@alias@lang}{% - \exp_args:Ne - \newenvironment {#4} - { - \begin{otherlanguage}[#2]{#3} - }% - { - \end{otherlanguage} - }% - % The starred version does not define \text<alias> - \IfBooleanF {#1} - { - \exp_args:Nc \newcommand {text#4} [2][] - {% - \xpg@textlanguage[#2,##1]{#3}{##2}% - }% - }% - }{% - \exp_args:Ne - \renewenvironment {#4} - { - \begin{otherlanguage}[#2]{#3} - }% + % The starred version does not define commands and environments + \IfBooleanF {#1} { - \end{otherlanguage} - }% - % The starred version does not (re)define \text<alias> - \IfBooleanF {#1} - { - \exp_args:Nc \renewcommand {text#4} [2][] - {% - \xpg@textlanguage[#2,##1]{#3}{##2}% - }% - }% + \ifcsundef{#4@alias@lang}{% + \exp_args:Ne + \newenvironment {#4} + { + \begin{otherlanguage}[#2]{#3} + }% + { + \end{otherlanguage} + }% + \exp_args:Nc \newcommand {text#4} [2][] + {% + \xpg@textlanguage[#2,##1]{#3}{##2}% + }% + }{% + \exp_args:Ne + \renewenvironment {#4} + { + \begin{otherlanguage}[#2]{#3} + }% + { + \end{otherlanguage} + }% + \exp_args:Nc \renewcommand {text#4} [2][] + {% + \xpg@textlanguage[#2,##1]{#3}{##2}% + }% + }% }% \csgdef{#4@alias@lang}{#3}% \tl_if_blank:nF {#2} {\csgdef{#4@alias@opts}{#2}}% @@ -1087,6 +1112,8 @@ \global\edef\xpg@loaded{#2\ifx\xpg@loaded\@empty\else,\xpg@loaded\fi}% \global\edef\xpg@bloaded{\prop_item:Nn{\polyglossia@langsetup}{#2/babelname}% \ifx\xpg@bloaded\@empty\else,\xpg@bloaded\fi}% + \global\edef\xpg@bcp@loaded{\prop_item:Nn{\polyglossia@langsetup}{#2/bcp47}% + \ifx\xpg@bcp@loaded\@empty\else,\xpg@bcp@loaded\fi}% }% \polyglossia_load_lang_definition:nn{#1}{#2} % define environment and command (except for internal latex language) @@ -1119,16 +1146,15 @@ \global\edef\xpg@loaded{#2\ifx\xpg@loaded\@empty\else,\xpg@loaded\fi}% \global\edef\xpg@bloaded{\prop_item:Nn{\polyglossia@langsetup}{#2/babelname}% \ifx\xpg@bloaded\@empty\else,\xpg@bloaded\fi}% + \global\edef\xpg@bcp@loaded{\prop_item:Nn{\polyglossia@langsetup}{#2/bcp47}% + \ifx\xpg@bcp@loaded\@empty\else,\xpg@bcp@loaded\fi}% }% \csgdef{#2@loaded}{}% }{} \gdef\xpg@main@language{#2}% \tl_if_blank:nTF {#1}{\gdef\mainlanguagevariant{}}{% - % If the optional argument sets a value for the key “variant”, - % store it in \xpg@main@langvariant - \clist_map_inline:nn { #1 } {% - \xpg@parsevariantkeyvalue##1=@xpg@main@langvariant\relax - }% + % Register the language options + \polyglossia@set@lang@options:nn {#2} {#1}% }% \csgdef{#2@gvar}{\mainlanguagevariant}% %% The following settings are for the default language and script @@ -1152,7 +1178,15 @@ % Store babelname of current language (for external packages such as biblatex) \prop_get:NxNT \polyglossia@langsetup {#2/babelname} \l_tmpa_tl { \edef\babelname{\l_tmpa_tl}% - \csgdef{#2@gbabelname}{\babelname}% + \cs_gset_eq:cc{#2@gbabelname}{babelname}% + } + % Store BCP-47 id of main language + \prop_get:NxNT \polyglossia@langsetup {#2/bcp47} \l_tmpa_tl + { \csedef{mainbcp47id}{\l_tmpa_tl} } + % Store BCP-47 id of current language + \prop_get:NxNT \polyglossia@langsetup {#2/bcp47} \l_tmpa_tl + { \csedef{bcp47id}{\l_tmpa_tl}% + \cs_gset_eq:cc{#2@gbcp47id}{bcp47id}% } \ifluatex % \directlua{polyglossia.set_default_language('\luatexluaescapestring{\string#2}')}% @@ -1161,6 +1195,36 @@ \let\setmainlanguage=\setdefaultlanguage +% Returns the language ID of the current language +% Currently supported: bcp-47 +\DeclareDocumentCommand \languageid {m} +{ + \str_case:nnTF {#1} + { + {bcp-47} { \csuse{bcp47id} } + {bcp47} { \csuse{bcp47id} } + } + {} + { + \xpg@error{Invalid~ \string\languageid\space argument:~ #1} + } +} + +% Returns the language ID of the main language +% Currently supported: bcp-47 +\DeclareDocumentCommand \mainlanguageid {m} +{ + \str_case:nnTF {#1} + { + {bcp-47} { \csuse{mainbcp47id} } + {bcp47} { \csuse{mainbcp47id} } + } + {} + { + \xpg@error{Invalid~ \string\mainlanguageid\space argument:~ #1} + } +} + \def\mainbabelname{}% \def\mainlanguagevariant{}% % Store main language variant for external packages @@ -1180,16 +1244,26 @@ \tl_if_blank:nTF {#1}{% \ifcsundef{#2@gvar}{\def\languagevariant{}}{\def\languagevariant{\csuse{#2@gvar}}} }{% - % If the argument sets a value for the key “variant”, - % store it in \xpg@set@langvariant - \clist_map_inline:nn { #1 } {% - \xpg@parsevariantkeyvalue##1=@xpg@set@langvariant\relax - }% + % Register the language options + \polyglossia@set@lang@options:nn {#2} {#1}% }% } -\newcommand{\resetdefaultlanguage}[2][]{% +\newcommand*{\resetdefaultlanguage}[2][]{% + \ifcsdef{#2@alias@lang}{% + \ifcsdef{#2@alias@opts}{% + \exp_args:Nxx \polyglossia@reset@default@language:nn {\csuse{#2@alias@opts},#1} {\csuse{#2@alias@lang}}% + }{% + polyglossia@reset@default@language:nn {#1} {\csuse{#2@alias@lang}}% + }% + }{% + polyglossia@reset@default@language:nn {#1} {#2}% + }% +} + +\cs_new:Nn \polyglossia@reset@default@language:nn +{ \polyglossia@error@iflangnotloaded:n{#2} % disable globalnumbers of previously defined default language \csuse{no\xpg@main@language @globalnumbers} @@ -1212,6 +1286,16 @@ }{% \edef\babelname{\prop_item:Nn{\polyglossia@langsetup}{#2/babelname}}% }% + % Store BCP-47 id of current language + \tl_if_blank:nTF {#1}{% + \ifcsundef{#2@gbcp47id}{% + \csedef{bcp47id}{\prop_item:Nn{\polyglossia@langsetup}{#2/bcp47}}% + }{% + \csedef{bcp47id}{\csuse{#2@gbcp47id}}% + }% + }{% + \csedef{bcp47id}{\prop_item:Nn{\polyglossia@langsetup}{#2/bcp47}}% + }% } % This saves the normalfont for the latin script since we may change normalfont in other scripts @@ -1235,6 +1319,14 @@ \selectfont% } +\def\xpg@patch@fontfamilies{% + % This robustifies the redefinitions of \<xx>family (suggestion by Enrico Gregorio) + % e.g. to prevent expansion of the \familytype redefinition in auxiliary files + \csgappto{rmfamily~}{\def\familytype{rm}} + \csgappto{sffamily~}{\def\familytype{sf}} + \csgappto{ttfamily~}{\def\familytype{tt}} +} + % These switches activate the default fonts % Note that a simple \let\rmfamilylatin=\rmfamily % does not work reliably (see #24) @@ -1254,11 +1346,7 @@ \ifcsequal{tempa}{tempb}% {\def\familytype{tt}} {\def\familytype{rm}}} - % This robustifies the redefinitions of \<xx>family (suggestion by Enrico Gregorio) - % e.g. to prevent expansion of the \familytype redefinition in auxiliary files - \csgappto{rmfamily~}{\def\familytype{rm}} - \csgappto{sffamily~}{\def\familytype{sf}} - \csgappto{ttfamily~}{\def\familytype{tt}} + \xpg@patch@fontfamilies% % This (re-)saves the normalfont for the latin script since we may % change normalfont in other scripts \let\normalfontlatin=\normalfont% @@ -1269,10 +1357,12 @@ } \def\resetfontlatin{% - \cs_gset_eq:cc{rmfamily}{xpg@defaultfont@rm}% - \cs_gset_eq:cc{sffamily}{xpg@defaultfont@sf}% - \cs_gset_eq:cc{ttfamily}{xpg@defaultfont@tt}% - \global\let\normalfont=\normalfontlatin} + \DeclareRobustCommand\rmfamily{\xpg@defaultfont@rm}% + \DeclareRobustCommand\sffamily{\xpg@defaultfont@sf}% + \DeclareRobustCommand\ttfamily{\xpg@defaultfont@tt}% + \xpg@patch@fontfamilies% + \global\let\normalfont=\normalfontlatin% +} \def\selectfontfamilylatin{% \def\tmp@tt{tt}\def\tmp@sf{sf}% @@ -1301,12 +1391,28 @@ } \let\@@fterindentfalse\@afterindentfalse -\def\french@indent{\let\@afterindentfalse\@afterindenttrue - \@afterindenttrue} -\def\nofrench@indent{\let\@afterindentfalse\@@fterindentfalse - \@afterindentfalse} -\newcommand{\selectbackgroundlanguage}[1]{% - \str_if_eq:eeTF{\prop_item:Nn{\polyglossia@langsetup}{#1/lcscript}}{latin}{}{\xpg@set@normalfont{#1}}% +\def\french@indent{% + \let\@afterindentfalse\@afterindenttrue + \@afterindenttrue% +} +\def\nofrench@indent{% + \let\@afterindentfalse\@@fterindentfalse + \@afterindentfalse% +} + +\newcommand*{\selectbackgroundlanguage}[1]{% + \ifcsdef{#1@alias@lang}{% + \polyglossia@select@background@language:n {\csuse{#1@alias@lang}}% + }{% + \polyglossia@select@background@language:n {#1}% + }% +} + +\cs_new:Nn \polyglossia@select@background@language:n +{ + \str_if_eq:eeTF{\prop_item:Nn{\polyglossia@langsetup}{#1/lcscript}}{latin} + {} + {\xpg@set@normalfont{#1}}% \csuse{#1@globalnumbers}% } @@ -1342,16 +1448,13 @@ % If a variant is set, store it. \gdef\otherlanguagevariant{} \tl_if_blank:nTF {#1}{}{% - % If the optional argument sets a value for the key “variant”, - % store it in \xpg@other@langvariant - \clist_map_inline:nn { #1 } {% - \xpg@parsevariantkeyvalue##1=@xpg@other@langvariant\relax - }% + % Register the language options + \polyglossia@set@lang@options:nn {#2} {#1}% }% \csgdef{#2@gvar}{\otherlanguagevariant}% \prop_get:NxNT \polyglossia@langsetup {#2/babelname} \l_tmpa_tl { \xdef\otherlanguagebabelname{\l_tmpa_tl} } - \csgdef{#2@gbabelname}{\otherlanguagebabelname}% + \cs_gset_eq:cc{#2@gbabelname}{otherlanguagebabelname}% } % Store main language variant for external packages @@ -1384,7 +1487,7 @@ \newcommand\textlang[3][]{% \ifcsdef{#2@alias@lang}{% \ifcsdef{#2@alias@opts}{% - \xpg@textlanguage[\csuse{#2@alias@opts},#1]{\csuse{#2@alias@lang}}{#3}% + \exp_args:Nxx \xpg@textlanguage[\csuse{#2@alias@opts},#1]{\csuse{#2@alias@lang}}{#3}% }{% \xpg@textlanguage[#1]{\csuse{#2@alias@lang}}{#3}% }% @@ -1393,6 +1496,16 @@ }% }% +% Alias to {<lang>}, but more suitable +% for specific (esp. tag-based) aliases +% where {<alias>} would cause clashes +% (e.g., \fi) +\newenvironment{lang}[2][]{% + \begin{otherlanguage}[#1]{#2}% +}{% + \end{otherlanguage} +}% + \providecommand{\foreignlanguage}{} % wrapper for foreignlanguage and otherlanguage* @@ -1408,6 +1521,16 @@ }{% \edef\babelname{\prop_item:Nn{\polyglossia@langsetup}{#2/babelname}}% }% + % Store BCP-47 id of current language + \tl_if_blank:nTF {#1}{% + \ifcsundef{#2@gbcp47id}{% + \csedef{bcp47id}{\prop_item:Nn{\polyglossia@langsetup}{#2/bcp47}}% + }{% + \csedef{bcp47id}{\csuse{#2@gbcp47id}}% + }% + }{% + \csedef{bcp47id}{\prop_item:Nn{\polyglossia@langsetup}{#2/bcp47}}% + }% } % joint code of \foreignlanguage, otherlanguage* @@ -1428,7 +1551,7 @@ {% \ifcsdef{#2@alias@lang}{% \ifcsdef{#2@alias@opts}{% - \polyglossia@foreignlanguage:nnn {\csuse{#2@alias@opts},#1} {\csuse{#2@alias@lang}} {#3}% + \exp_args:Nxx \polyglossia@foreignlanguage:nnn {\csuse{#2@alias@opts},#1} {\csuse{#2@alias@lang}} {#3}% }{% \polyglossia@foreignlanguage:nnn {#1} {\csuse{#2@alias@lang}} {#3}% }% @@ -1453,7 +1576,7 @@ {% \ifcsdef{#2@alias@lang}{% \ifcsdef{#2@alias@opts}{% - \polyglossia@otherlanguage:nn {\csuse{#2@alias@opts},#1} {\csuse{#2@alias@lang}}% + \exp_args:Nxx \polyglossia@otherlanguage:nn {\csuse{#2@alias@opts},#1} {\csuse{#2@alias@lang}}% }{% \polyglossia@otherlanguage:nn {#1} {\csuse{#2@alias@lang}}% }% @@ -1471,7 +1594,7 @@ % use by \text<lang> and \textlang. Equivalent to \foreignlanguage, % except that dates are localized. -\newcommand*\xpg@textlanguage[3][]{% +\newcommand\xpg@textlanguage[3][]{% \polyglossia@error@iflangnotloaded:n{#2} \bgroup \xpg@otherlanguage[#1]{#2}% @@ -1510,7 +1633,7 @@ {% \ifcsdef{#3@alias@lang}{% \ifcsdef{#3@alias@opts}{% - \polyglossia@select@language:nnn {#1} {\csuse{#3@alias@opts},#2} {\csuse{#3@alias@lang}}% + \exp_args:Nxx \polyglossia@select@language:nnn {#1} {\csuse{#3@alias@opts},#2} {\csuse{#3@alias@lang}}% }{% \polyglossia@select@language:nnn {#1} {#2} {\csuse{#3@alias@lang}}% }% @@ -1528,11 +1651,8 @@ \group_insert_after:N \xpg@pop@language } \tl_if_blank:nTF {#2}{}{% - % If the optional argument sets a value for the key “variant”, copy it to xpg@langvariant - \clist_map_inline:nn { #2 } {% - \xpg@parsevariantkeyvalue##1=@xpg@langvariant\relax - }% - \exp_args:Nne \setkeys{#3}{#2}% + % Register the language options + \polyglossia@set@lang@options:nn {#3} {#2}% }% % The starred variant does not write to the aux \IfBooleanTF#1{% @@ -1554,13 +1674,99 @@ }{} } -% Helper to get and register "variant" keyval -\def\xpg@parsevariantkeyvalue#1=#2@#3\relax{% + +\cs_new:Nn \polyglossia@set@lang@options:nn +{ + % If the optional argument sets a value for the key “variant”, copy it to xpg@langvariant + \clist_map_inline:nn { #2 } {% + \xpg@parsevariantkeyvalue##1=@xpg@langvariant:#1\relax + }% + \exp_args:Nne \setkeys{#1}{#2}% +} + +% Initialize default language options, so that +% \iflanguageoption has the info it needs also +% for default settings +\newcommand*\xpg@initialize@gloss@options[2]{% + \polyglossia@set@lang@options:nn {#1} {#2}% +} + +% Record synonymous keyvals such as variant=us and variant=american +% Syntax: \xpg@set@alias@values{<lang>}{<key>}{<val>}{<alias vals, comma-separated>} +\newcommand*\xpg@set@alias@values[4]{% + \prop_if_exist:cF { xpg@alias@keyvals@#1@#3 } + { \prop_new:c {xpg@alias@keyvals@#1@#3} } + \prop_put:cnn { xpg@alias@keyvals@#1@#3 } + {#2}{#4} + \prop_put:cnn { xpg@alias@keyvals@#1@#4 } + {#2}{#3} +} + +% Patch xkeyval to record default values of keys +\pretocmd{\XKV@define@default}{% + \csgdef{xpg@default@opt@\XKV@header #1}{#2}% +}{}{\xpg@warning{Patching xkeyval failed!}} + +% Helper to get and register option keyvals +\def\xpg@parsevariantkeyvalue#1=#2@#3:#4\relax{% \def\@tmpa{#1} \def\@tmpb{variant} + % variant values are stored in specific macros + % (\xpg@main@langvariant, \xpg@other@langvariant + % and \xpg@set@langvariant) \ifx\@tmpa\@tmpb\setkeys{#3}{#1=#2}\fi + \tl_if_empty:nTF{#2} + { + \ifcsdef{xpg@default@opt@KV@#4@#1}% + {\xpg@store@opt@keyval#1:\csuse{xpg@default@opt@KV@#4@#1}=:#4\relax}% + {}% + } + { \xpg@store@opt@keyval#1:#2:#4\relax } }% +% Store option keys and values +% This strips trailing '=' from values. +\def\xpg@store@opt@keyval#1:#2=:#3\relax{% + \prop_if_exist:cF { xpg@current@options@#3 } + { \prop_new:c {xpg@current@options@#3} } + \prop_put:cnn { xpg@current@options@#3 } + {#1}{#2} +} + + +\prg_set_conditional:Npnn \polyglossia@check@option@value:NNN #1#2#3 { p , T , F , TF } +{ + \prop_get:cnNTF {xpg@current@options@#1} {#2} \l_tmpa_tl + { + \exp_args:Nee \str_if_eq:NNTF{\l_tmpa_tl}{#3} + {\prg_return_true:} + { + \prop_get:cnNTF {xpg@alias@keyvals@#1@#3} {#2} \l_tmpb_tl + { + \exp_args:Nne \clist_set:Nn{\l_tmpa_clist}{\l_tmpb_tl} + \providetoggle{xpgvalfound} + \togglefalse{xpgvalfound} + \clist_map_inline:Nn \l_tmpa_clist { + \exp_args:Nee \str_if_eq:NNT{##1}{\l_tmpa_tl} + { \toggletrue{xpgvalfound} } + } + \iftoggle{xpgvalfound}{\prg_return_true:}{\prg_return_false:} + } + { + \prg_return_false: + } + } + } + { + \prg_return_false: + } +} + +% Test if option value is set +\newcommand*\iflanguageoption[5]{% + \polyglossia@check@option@value:NNNTF{#1}{#2}{#3}{#4}{#5}% +} + % Append any variant to csv list of variants \define@key{xpg@langvariant}{variant}{% @@ -1585,6 +1791,51 @@ \polyglossia@check@if@lang@loaded:NTF{#1@bbl@loaded}{#2}{#3}% } +% Same for languageid +\DeclareDocumentCommand \iflanguageidloaded {mmmm} +{ + \str_case:nnTF {#1} + { + {bcp-47} { \polyglossia@check@if@lang@loaded:NTF{#2@bcp@loaded}{#3}{#4} } + {bcp47} { \polyglossia@check@if@lang@loaded:NTF{#2@bcp@loaded}{#3}{#4} } + } + {} + { + \xpg@error{Invalid~ \string\iflanguageidloaded\space argument:~ #1} + } +} + +% Check if the current font has a given glyph +\prg_set_conditional:Npnn \polyglossia@check@if@char@available:N #1 { p , T , F , TF } +{ + \str_case_e:nnF{\c_sys_engine_str}{ + {luatex}{ + \int_compare:nNnTF { \directlua{polyglossia.check_char(0x#1)} } > { 0 } + {\prg_return_true:} + {\prg_return_false:} + } + {xetex}{ + \int_compare:nNnTF { \the\XeTeXcharglyph"#1 } > { 0 } + {\prg_return_true:} + {\prg_return_false:} + } + } + { + \xpg@warning{You’re running a TeX engine that is not LuaTeX or XeTeX.\MessageBreak + That is almost guaranteed to cause problems.} + } +} + +% Test if a char (by char code) is available in the current font +\newcommand*\xpg@if@char@available[3]{% + \polyglossia@check@if@char@available:NTF{#1}{#2}{#3}% +} + +\newcommand*\charifavailable[2]{% + \xpg@if@char@available{#1}{\char"#1}{#2}% +} + + \newcommand*{\xpg@set@language@nonaux}[2][]{% \@select@language[#1]{#2}% } @@ -1601,6 +1852,24 @@ }{% \edef\babelname{\prop_item:Nn{\polyglossia@langsetup}{#2/babelname}}% }% + % Store BCP-47 id of current language + \tl_if_blank:nTF {#1}{% + \ifcsundef{#2@gbcp47id}{% + \csedef{bcp47id}{\prop_item:Nn{\polyglossia@langsetup}{#2/bcp47}}% + }{% + \csedef{bcp47id}{\csuse{#2@gbcp47id}}% + }% + }{% + \csedef{bcp47id}{\prop_item:Nn{\polyglossia@langsetup}{#2/bcp47}}% + }% + % Store bcp47 in \xpg@bcp@loaded csv list + \def\xpg@tmp@bcpname{\csuse{bcp47id}}% + \ifcsundef{\csname xpg@tmp@bcpname\endcsname @bcp@loaded} + { + \global\edef\xpg@bcp@loaded{\xpg@tmp@bcpname% + \ifx\xpg@bcp@loaded\@empty\else,\xpg@bcp@loaded\fi}% + \csgdef{\csname xpg@tmp@bcpname\endcsname @bcp@loaded}{}% + }{} \@select@language[#1]{#2}% % Write to the aux \if@filesw% @@ -1618,24 +1887,57 @@ \fi } +% The bidi package swaps the output stream within RTL tables +% (to get the column order right). This also swaps group +% delimiters inserted to the aux files via otherlanguage (see #354). +% We therefore patch bidi and insert a bool that tells us +% whether we are in such a table. +\newbool{xpg@inbiditable} +\AtBeginDocument{% + \@ifpackageloaded{bidi}{% + \patchcmd{\@tabular}% + {\if@RTLtab}% + {\if@RTLtab\booltrue{xpg@inbiditable}}% + {}% success + {\xpg@warning{Patching bidi table failed!}}% + }{}% +} + % Open a group in the aux file. This is to keep -% nested language options local (see #320) +% nested language options local (see #320). +% In bidi tables, the opening/closing needs to be swapped (see #354) \newcommand*{\xpg@set@group@aux}{% \if@filesw% - \protected@write\@auxout{}{\bgroup}% - \addtocontents{toc}{\bgroup}% - \addtocontents{lof}{\bgroup}% - \addtocontents{lot}{\bgroup}% + \ifbool{xpg@inbiditable}{% + \protected@write\@auxout{}{\egroup}% + \addtocontents{toc}{\egroup}% + \addtocontents{lof}{\egroup}% + \addtocontents{lot}{\egroup}% + }{% + \protected@write\@auxout{}{\bgroup}% + \addtocontents{toc}{\bgroup}% + \addtocontents{lof}{\bgroup}% + \addtocontents{lot}{\bgroup}% + }% \fi } -% Close the group in the aux file +% Close the group in the aux file. +% In bidi RTL tables, the opening/closing needs +% to be swapped (see #354). \newcommand*{\xpg@unset@group@aux}{% \if@filesw% - \protected@write\@auxout{}{\egroup}% - \addtocontents{toc}{\egroup}% - \addtocontents{lof}{\egroup}% - \addtocontents{lot}{\egroup}% + \ifbool{xpg@inbiditable}{% + \protected@write\@auxout{}{\bgroup}% + \addtocontents{toc}{\bgroup}% + \addtocontents{lof}{\bgroup}% + \addtocontents{lot}{\bgroup}% + }{% + \protected@write\@auxout{}{\egroup}% + \addtocontents{toc}{\egroup}% + \addtocontents{lof}{\egroup}% + \addtocontents{lot}{\egroup}% + }% \fi } @@ -1745,7 +2047,7 @@ \noextrascurrent{\languagename}% \csuse{no\languagename @numbers}% \ifxetex - \str_if_eq:eeTF{\prop_item:Nn{\polyglossia@langsetup}{\languagename/direction}}{RL}% + \str_if_eq:eeTF{\exp_args:Nne\prop_item:Nn{\polyglossia@langsetup}{\languagename/direction}}{RL}% {% \str_if_eq:eeTF{\prop_item:Nn{\polyglossia@langsetup}{#2/direction}}{RL}% {}% RTL -> RTL @@ -1772,12 +2074,24 @@ \provideenvironment{otherlanguage}{}{} +\newbool{xpg@noset@groups} \renewenvironment{otherlanguage}[2][] {% - \xpg@set@group@aux% + % We usually embrace the switch in groups to keep the changes local. + % We cannot do this if an LTR environmet starts in an RTL paragraph, + % as bidi interferes here badly with its directionality smartness. + \ifxetex + \str_if_eq:eeT{\exp_args:Nne\prop_item:Nn{\polyglossia@langsetup}{\languagename/direction}}{RL}% + {% + \str_if_eq:eeTF{\prop_item:Nn{\polyglossia@langsetup}{#1/direction}}{RL}% + {}% RTL -> RTL + {\ifvmode\else\booltrue{xpg@noset@groups}\fi}% RTL -> LTR + }% + \fi% + \ifbool{xpg@noset@groups}{}{\xpg@set@group@aux}% \selectlanguage[#1]{#2}% } -{\xpg@unset@group@aux} +{\ifbool{xpg@noset@groups}{}{\xpg@unset@group@aux}} \newcommand{\setlocalhyphenmins}[3]{% \xpg@ifdefined{#1}{% @@ -1792,7 +2106,17 @@ \def\use@localhyphenmins#1{% \ifcsundef{#1hyphenmins}{}% - {\expandafter\expandafter\expandafter\set@hyphenmins\csname #1hyphenmins\endcsname\relax}} + {\expandafter\expandafter\expandafter\set@hyphenmins\csname #1hyphenmins\endcsname\relax} + \ifluatex + % Set \totalhyphenmin if specified + \prop_get:NxNTF \polyglossia@langsetup {#1/totalhyphenmin} \l_tmpa_tl + { + \xpg@warning{totalhyphenmin: '\l_tmpa_tl'} + \expandafter\hyphenationmin \l_tmpa_tl% + }% + {}% + \fi +} \AtEndPreamble{% \@ifpackageloaded{bidi}{% |