summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/latex/polyglossia/polyglossia.sty
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2020-01-29 22:37:53 +0000
committerKarl Berry <karl@freefriends.org>2020-01-29 22:37:53 +0000
commit015c5f064b14e4a79f151b46a6dd46b150520c81 (patch)
treecc3434d0ae73900950b37bc952816286d4d76d5c /Master/texmf-dist/tex/latex/polyglossia/polyglossia.sty
parente9549ffe43d42fda4e5d3778e1d26fbd95e4ae9f (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.sty522
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}{%