\NeedsTeXFormat{LaTeX2e} \ProvidesPackage{polyglossia}[2022/07/18 v1.57 Modern multilingual typesetting with XeLaTeX and LuaLaTeX] \RequirePackage{etoolbox} \RequirePackage{makecmds} \RequirePackage{xkeyval}[2008/08/13] % Will raise error if used with anything else than XeTeX or LuaTeX \RequirePackage{fontspec}[2010/06/08]% v2.0 \RequirePackage{iftex} \RequirePackage{expl3} \RequirePackage{l3keys2e} \RequirePackage{xparse} % fontspec now uses LaTeX3 packages such as expl3, so we need this: \ExplSyntaxOn % Execute code #3 if package #1 has been loaded already, else % add to package hook #2 \cs_new_nopar:Nn \__xpg_at_package_hook:nnn{ \@ifpackageloaded{#1}{#3}{\AddToHook{#2}{#3}}% } % safe according to expl3 bug #960 \cs_generate_variant:Nn \prop_item:Nn { Ne, Nf, No, Nx } \cs_generate_variant:Nn \clist_set:Nn { Ne, Nf, No, Nx } \cs_generate_variant:Nn \clist_gput_right:Nn {Ne} \cs_generate_variant:Nn \prop_get:NnN {NeN} \cs_generate_variant:Nn \prop_gput:Nnn {Nne, Nee, Nen} \cs_generate_variant:Nn \cs_gset:Npn {Npe} \cs_generate_variant:Nn \cs_new:Nn {Ne} \cs_generate_variant:Nn \cs_new_nopar:Nn {Ne} \cs_generate_variant:Nn \cs_gset_nopar:Npn {Npe} \cs_generate_variant:Nn \cs_gset_nopar:Npn {cpe} \cs_generate_variant:Nn \tl_set:Nn {Ne} \cs_generate_variant:Nn \str_foldcase:n {e} \prg_generate_conditional_variant:Nnn \file_if_exist:n {e} {TF, T, F, p} \prg_generate_conditional_variant:Nnn \tl_if_blank:n {e} {TF, T, F, p} \prg_generate_conditional_variant:Nnn \clist_if_in:Nn {Ne} {TF, T, F, p} \prg_generate_conditional_variant:Nnn \prop_if_in:Nn {Ne} {TF, T, F, p} % correct a bug in tracklang \__xpg_at_package_hook:nnn{tracklang}{file/tracklang.sty/after}{% \@ifpackagelater{tracklang}{2019/08/30}{}{\global\def\AddTrackedLangage{\AddTrackedLanguage}} } %% This is for compatibility with Babel-aware package: \def\languageshorthands#1{\relax} %this is for scrlttr2 class \def\bbl@cs#1{\csname bbl@#1\endcsname}% \AtEndPreamble{\let\bbl@set@language\xpg@set@language@aux} %for biblatex \AtEndPreamble{\let\bbl@main@language\xpg@main@language} %for biblatex \AtEndPreamble{ \providecommand\texorpdfstring[2]{#1}% dummy command if hyperref is not loaded } \sys_if_engine_luatex:T{ \RequirePackage{luatexbase} % already included by fontspec, but needed here \RequireLuaModule{polyglossia} } % Which version of XeTeX do we use? What is the boudary class? 4095 or 255 \@ifundefined{e@alloc@intercharclass@top} {\chardef\xpg@boundaryclass=\@cclv} {\let\xpg@boundaryclass=\e@alloc@intercharclass@top} % Useful for getting list of loaded languages and variants. Like babel's bbl@loaded % all language loaded \seq_new:N \__xpg_langs_loaded % list of loaded languages (polyglossia name) \clist_new:N \xpg@loaded % list of loaded variants \clist_new:N \xpg@vloaded % list of loaded languages (babel name) \clist_new:N \xpg@bloaded % list of loaded languages (bcp-47 id) \clist_new:N \xpg@bcp@loaded % counter in latin \def\latinalph#1{\expandafter\latin@alph\csname c@#1\endcsname} \def\latinAlph#1{\expandafter\latin@Alph\csname c@#1\endcsname} % select language hook \cs_new_nopar:Nn \polyglossia@AtBeginDocument@selectlanguage: {} % \disablehyphenation hook \cs_new_nopar:Nn \polyglossia@AtBeginDocument@hyphenation: {} % hook to be executed at begin of document \cs_new_nopar:Nn \polyglossia@AtBeginDocument: { % save various command \let\latin@alph\@alph % TODO rename when we have the C locale \let\latin@Alph\@Alph % TODO rename when we have the C locale % push to C language gloss \let\polyglossia@Clang@@arabic\@arabic \let\polyglossia@Clang@arabic\arabic \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: } %% custom message macros \providecommand*{\xpg@error}[1]{% \PackageError{polyglossia}{#1}{}% } \providecommand*{\xpg@warning}[1]{% \PackageWarning{polyglossia}{#1}% } \providecommand*{\xpg@info}[1]{% \PackageInfo{polyglossia}% {#1\@gobble}% } %% the \@gobble is to prevent displaying the line nr %TODO change all instances of \xpg@nopatterns in gloss-*.ldf files \providecommand*{\xpg@nopatterns@fallback}[2][nohyphenation]{% \xpg@warning{No~ hyphenation~ patterns~ were~ loaded~ for~ `#2'\MessageBreak I~ will~ use~ \string\language=\string\l@ #1\space instead}% \expandafter\adddialect\csname l@#2\expandafter\endcsname\csname l@#1\endcsname\relax} \providecommand*{\xpg@nopatterns}[1]{% \xpg@warning{No~ hyphenation~ patterns~ were~ loaded~ for~ `#1'\MessageBreak I~ will~ use~ \string\language=\string\l@nohyphenation\space instead}% %%TODO? \expandafter\adddialect\csname l@#1\endcsname\l@nohyphenation\relax } \def\xpg@ill@value#1#2{% \xpg@warning{Illegal~ value~ (#1)~ for~ #2}} % error out if lang is not loaded \cs_new_nopar:Nn \polyglossia@error@iflangnotloaded:n { \seq_if_in:NxF \__xpg_langs_loaded {#1} { \xpg@error{language~ #1~ is~ not~ loaded.~ Please~ load~ it~ before~ using~ it.} } } \msg_new:nnn { polyglossia } { languagenotloaded } { The~ language~ #1~ is~ not~ loaded.~ You~ should~ load~ it. } \msg_redirect_name:nnn { polyglossia } { languagenotloaded } { critical } \cs_new_nopar:Nn \__xpg_msg_if_lang_not_loaded:n { \tl_if_blank:eT {\xpg_alias_base_lang:n{#1}} { \msg_show:nnn { polyglossia } { languagenotloaded } {#1} } } % %% use macro if defined, else warn that it is not \cs_new_nopar:Nn \__xpg_use_or_warn:N { \cs_if_exist_use:NF {#1} { \xpg@warning { \tl_to_str:N {#1} ~ is~ not~ defined } } } \cs_generate_variant:Nn \__xpg_use_or_warn:N {c} %% ensure directionality if bidi is loaded, else ignore \def\@@ensure@dir#1{\ifcsundef{@ensure@dir}{#1}{\@ensure@dir{#1}}} \def\@@ensure@maindir#1{\ifcsundef{@ensure@maindir}{#1}{\@ensure@maindir{#1}}} %% Used by the language definitions files for right-to-left languages \def\RequireBidi{% \str_case_e:nnF{\c_sys_engine_str}{ {luatex}{\ifx\@onlypreamble\@notprerr\else\RequirePackage{luabidi}\fi} {xetex}{\ifx\@onlypreamble\@notprerr\else\RequirePackage{bidi}\fi} } { \xpg@warning{You’re running a TeX engine that is not LuaTeX or XeTeX.\MessageBreak That is almost guaranteed to cause problems.} } } % if #1 is LR run #2 else #3 \prg_set_conditional:Nnn \__xpg_if_LR_str:n {p, T, F, TF} { \str_case_e:nnF{#1}{ {LR}{\prg_return_true:} {RL}{\prg_return_false:} } { \xpg@error{Unknown~ direction~#1} \prg_return_false: } } \prg_generate_conditional_variant:Nnn \__xpg_if_LR_str:n {e} {p, T, F, TF} % (lua)bidi commands to change directionality for paragraphs % and inline text. % overwritten with correct package \cs_new_nopar:Nn{\polyglossia@setpardirection:n}{% \__xpg_if_LR_str:nF {#1} { \xpg@error{right-to-left,~ but~ (lua)bidi~ package~ was~ not~ loaded!} } } \cs_new_nopar:Nn{\polyglossia@settextdirection:n}{% \__xpg_if_LR_str:nF {#1} { \xpg@error{right-to-left,~ but~ (lua)bidi~ package~ was~ not~ loaded!} } } \__xpg_at_package_hook:nnn{bidi}{package/bidi/after}{% \ExplSyntaxOn% \cs_gset_nopar:Nn{\polyglossia@setpardirection:n}{% \__xpg_if_LR_str:nTF{#1}% {% \setLR% }% {% \setRL% }% }% \cs_gset_nopar:Nn{\polyglossia@settextdirection:n}{% \__xpg_if_LR_str:nTF{#1}% {% \LRE% }% {% \RLE% }% }% \ExplSyntaxOff% } \__xpg_at_package_hook:nnn{luabidi}{package/luabidi/after}{% \ExplSyntaxOn% \cs_gset_nopar:Nn{\polyglossia@setpardirection:n}{% \__xpg_if_LR_str:nTF{#1}% {% \setLR% }% {% \setRL% }% }% \cs_gset_nopar:Nn{\polyglossia@settextdirection:n}{% \__xpg_if_LR_str:nTF{#1}% {% \LRE% }% {% \RLE% }% }% \ExplSyntaxOff% } % emulate \RTLmain \cs_new_nopar:Nn \__xpg_setRTLmain: {} \str_case_e:nnF{\c_sys_engine_str}{% {luatex}{\cs_gset:Nn \__xpg_setRTLmain: {\setRTLmain}} {xetex}{\cs_gset:Nn \__xpg_setRTLmain: {\@RTLmaintrue\setnonlatin}} } { \cs_gset:Nn \__xpg_setRTLmain: { \xpg@warning{You’re~ running a~ TeX~ engine~ that~ is~ not~ LuaTeX~ or~ XeTeX.\MessageBreak That~ is~ almost~ guaranteed~ to~ cause~ problems.} } } %% compatibility with babel \let\addto\gappto% gappto is defined in etoolbox %% NEW EXPERIMENTAL SETUP INTERFACE FOR GLOSS FILES %% options currently available: %% language : the name of the language (as understood by fontspec) %% hyphennames : the different hyphenation patterns to try (comma separated list) %%% TODO: if pattern is prefixed by !, then it should be loaded as a fallback, with \xpg@nopatterns@fallback - i.e. with a warning: e.g. sanskrit for hindi, or catalan for asturian. – Also for languages with variants! (English and German, etc.) %% script : the name of the script (as understood by fontspec) – default is Latin %% scripttag : the OpenType tag for the script %% langtag : the OpenType tag for the language %% hyphenmins : the hyphenmins for this language (comma-sep list of two integers) %% frenchspacing : boolean %% indentfirst : boolean %% fontsetup : boolean %% TODO: nouppercase : boolean (for scripts like Arabic, Devanagari, etc which have no concept of uppercase/lowercase) %% TODO: localalph = {,} %% TODO: localnumeral = %% or even better localdigits = {0123456789} for fully automatic setup \newif\if@xpg@language@really@defined@ \newcommand*\PolyglossiaSetup[2]{% \polyglossia@keys_define_lang:n{#1}% \keys_set:nn { polyglossia / #1 } { #2 }% \prop_log:N{\polyglossia@langsetup} \polyglossia_setup_hyphen:n {#1} %define booleans etoolbox style and set defaults %% TODO ? \providetoggle{#1@setup@done}% % we initialize these so that we can use \gappto below \csgdef{init@extras@#1}{}% \csgdef{init@noextras@#1}{}% we don't use this yet: remove? % here we do the fontsetup: \polyglossia@lang@autosetupfont:n{#1} %% TODO? \toggletrue{#1@setup@done}% % reinit \do \def\do##1{\setotherlanguage{##1}}% % register base alias \xpg_language_alias { #1 } { #1 } } % Adjust language key setting after initial setup % This is needed, e.g., for languages with varying script \DeclareDocumentCommand \SetLanguageKeys { m m } { \clist_map_inline:nn { #1 } { \keys_set:nn { polyglossia / ##1 } { #2 } } } % setup hyphennames from a str list of hyphen \cs_new:Nn \polyglossia_setup_hyphen:n { \clist_set:Ne{\l_tmpa_clist}{\prop_item:Nn \polyglossia@langsetup {#1 / hyphennames}} \providebool{havehyphen} \boolfalse{havehyphen} % for each hyphen in the set until we find one that works \clist_map_inline:Nn \l_tmpa_clist { \ifbool{havehyphen}{}{% % check if language hyphenname is defined \__xpg_check_if_exist_l@:NF{#1}{% % if not, first consider nohyphenation \str_if_eq:nnTF{##1}{nohyphenation} {% \cs_gset_eq:cc{l@#1}{l@##1} \global\booltrue{havehyphen} }{% % then test if hyphenation is defined \xpg@ifdefined{##1}{ % test if language hyphenation is nohyphenation \cs_if_eq:cNF{l@#1}{\l@nohyphenation}{\global\booltrue{havehyphen}}{% % if false define language to hyphenation if it is not equal... \str_if_eq:nnF{#1}{##1}{\cs_gset_eq:cc{l@#1}{l@##1}} % ...and load \xpg@set@hyphenation@patterns{##1} \global\booltrue{havehyphen} }% }{}% }% }% }% }% % if l@#1 does not yet exist, % we assign it to nohyphenation % we do this here in case and if the hyphennames key was omitted \ifbool{havehyphen}{}{% \xpg@ifdefined{#1}{}% { \xpg@nopatterns{#1} \expandafter\adddialect\csname l@#1\endcsname\l@nohyphenation\relax }% }% \csdef{#1@language}{% \polyglossia@setup@language@patterns{#1}% }% % setup hyphenmins \clist_set:Ne \l_tmpa_clist { \prop_item:Nn \polyglossia@langsetup {#1 / hyphenmins} } \cs_if_eq:cNF {l@#1} \l@nohyphenation { \use:x { \exp_not:N \setlocalhyphenmins {#1} { \clist_item:Nn \l_tmpa_clist {1} } { \clist_item:Nn \l_tmpa_clist {2} } } } } \newcommand*\polyglossia@setup@language@patterns[1]{% \ifbool{xpg@hyphenation@disabled}{% \xdef\xpg@lastlanguage{\the\csname l@#1\endcsname}% }{% % first, test if \l@#1 exists % without that, \csname l@#1\endcsname will be defined as \relax \cs_if_exist:cTF {l@#1} { \cs_if_eq:cNTF {l@#1} \l@nohyphenation { \language=\l@nohyphenation } { \xpg@set@hyphenation@patterns{#1} } } {% % Since this function is sometimes called from the gloss files % directly, we need to check whether the requested hyphenname exists. \xpg@ifdefined{#1}{}% {% \xpg@nopatterns{#1} \expandafter\adddialect\csname l@#1\endcsname\l@nohyphenation\relax% }% \xpg@set@hyphenation@patterns{#1} } } } \prop_new:N \polyglossia@langsetup \cs_new_protected:Npn \polyglossia@keys_define_lang:n #1 { \keys_define:nn {polyglossia}{ % the script font #1 / script .code:n = { \prop_gput:Nnn{\polyglossia@langsetup}{#1/script}{##1} \prop_gput:Nnx{\polyglossia@langsetup}{#1/lcscript} {\tl_if_empty:nF{##1}{\str_lowercase:n##1}} }, #1 / script .value_required:n = true, #1 / script .initial:n = latin, % the opentype script tag #1 / scripttag .code:n = {\prop_gput:Nnn{\polyglossia@langsetup}{#1/scripttag}{##1}}, #1 / scripttag .default:n = {}, #1 / scripttag .initial:n = {}, % the language full name #1 / language .code:n = {\prop_gput:Nnn{\polyglossia@langsetup}{#1/language}{##1}}, #1 / language .value_required:n = true, #1 / language .initial:x = {\str_upper_case:n#1}, % the language tag #1 / langtag .code:n = {\prop_gput:Nnn{\polyglossia@langsetup}{#1/langtag}{##1}}, #1 / langtag .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 = { \clist_set:Nn{\l_tmpa_clist}{##1} \prop_gput:Nnx{\polyglossia@langsetup}{#1/hyphennames}{\clist_use:Nn \l_tmpa_clist {,}} }, #1 / hyphennames .value_required:n = true, #1 / hyphennames .initial:x = {\c_empty_clist}, % direction #1 / direction . code:n = { \str_case_e:nnTF{##1}{ {LR}{} {RL}{\RequireBidi} } {\prop_gput:Nnn{\polyglossia@langsetup}{#1/direction}{##1}} {\xpg@error{Unknown~ direction~ "##1"~ for~ language~ "#1"}} }, #1 / direction .value_required:n = true, #1 / direction .initial:n = {LR}, % minimal left and right hyphenation minima using #1 / hyphenmins .code:n = { % check syntax \int_compare:nNnF { \clist_count:n {##1} } = {2} {\xpg@error{hypenmins~should~be~a~list~of~two~entries,~got~"##1"}} % set prop \prop_gput:Nnn \polyglossia@langsetup {#1/hyphenmins} {##1} }, #1 / hyphenmins .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 = { \str_case_e:nnTF{##1}{ {true}{} {false}{} } {} {\xpg@error{frenchspacing~should~be~true~or~false. Is~ "##1"~ for~ language~ "#1"}} \prop_gput:Nnn{\polyglossia@langsetup}{#1/frenchspacing}{##1} }, #1 / frenchspacing .default:n = true, #1 / frenchspacing .initial:n = false, % indent first line #1 / indentfirst .code:n = { \str_case_e:nnTF{##1}{ {true}{} {false}{} } {} {\xpg@error{indentfirst~should~be~true~or~false. Is~ "##1"~ for~ language "#1"}} \prop_gput:Nnn{\polyglossia@langsetup}{#1/indentfirst}{##1} }, #1 / indentfirst .default:n = true, #1 / indentfirst .initial:n = false, % fontsetup #1 / fontsetup .code:n = { \str_case_e:nnTF{##1}{ {true}{} {false}{} } {} {\xpg@error{fontsetup~should~be~true~or~false. Is "##1"~ for~ language~ "#1"}} \prop_gput:Nnn{\polyglossia@langsetup}{#1/fontsetup}{##1} }, #1 / fontsetup .default:n = true, #1 / fontsetup .initial:n = false, % environment name #1 / envname .code:n = { \prop_gput:Nnn{\polyglossia@langsetup}{#1/envname}{##1} }, #1/ envname.value_required:n = true, #1/ envname.initial:n = {#1}, % babel name #1 / babelname .code:n = { \prop_gput:Nnn{\polyglossia@langsetup}{#1/babelname}{##1} }, #1/ babelname.value_required:n = true, #1/ babelname.initial:n = {#1}, % default numerals #1 / localnumeral . code:n = { \prop_gput:Nnn{\polyglossia@langsetup}{#1/localnumeral}{##1} \prop_gput:Nnn{\polyglossia@langsetup}{#1/Localnumeral}{##1} }, #1 / localnumeral.value_required:n = true, #1 / localnumeral.initial:n = {polyglossia@C@localnumeral}, % uppercased #1 / Localnumeral . code:n = { \prop_gput:Nnn{\polyglossia@langsetup}{#1/Localnumeral}{##1} }, #1 / Localnumeral.value_required:n = true, #1 / Localnumeral.initial:n = {polyglossia@C@localnumeral}, % environment define command (by default create the environment) #1 / DefineCommandsCmd .code:n = {\prop_gput:Nnn{\polyglossia@langsetup}{#1/DefineCommandsCmd}{##1}}, #1 / DefineCommandsCmd .value_required:n = true, #1 / DefineCommandsCmd .initial:n = {xpg_define_language_commands:e} } } % TODO move to C module \newcommand*{\polyglossia@C@localnumeral}[2]{ \polyglossia@Clang@@arabic{#2} } % print using main language % #2 is the numeral to print % #3 is the mainlanguage (should be expanded) % #4 is the current language (should be expanded) % #1 is the option list (should be expanded) % #5 is the name of the field to use \cs_new:Nn \polyglossia_localnumeral_mainlang:nnnnn { \foreignlanguage{#3}{\use:c {\prop_item:Nn \polyglossia@langsetup {#3/#5}} {#1} {#2}} } % print using local language % #2 is the numeral to print % #3 is the mainlanguage (should be expanded) % #4 is the current language (should be expanded) % #1 is the option list (should be expanded) % #5 is the name of the field to use \cs_new:Nn \polyglossia_localnumeral_locallang:nnnnn { \use:c {\prop_item:Nn \polyglossia@langsetup {#4/#5}} {#1} {#2} } % this function try to resolve some simple parameter about lang % call #2 then branching if found % call parameter #3 if not found % (use curing) \cs_new:Npn \polyglossia_localnumeral_callshortcutorlong:nF #1#2 { \str_case:nnF{#1}{ {lang=local}{\polyglossia_localnumeral_locallang:nnnnn} } {#2} } \cs_new:Npn \polyglossia_iii_map_csv_field_split_kv_iii_localnumeral:w #1 = #2 \q_stop { \str_case:nnF{#2}{ {local} {\clist_map_break:n{\use_i:nn \polyglossia_localnumeral_locallang:nnnnn }} {default}{\clist_map_break:n{\use_i:nn \polyglossia_localnumeral_locallang:nnnnn }} {*} {\clist_map_break:n{\use_i:nn\polyglossia_localnumeral_mainlang:nnnnn }} {main} {\clist_map_break:n{\use_i:nn\polyglossia_localnumeral_mainlang:nnnnn }} }{ \clist_map_break:n{ \use_i_ii:nnn \polyglossia_localnumeral_langlang:nnnnnn {{#2}} } } } % call the language % #3 is the numeral to print % #4 is the mainlanguage (should be expanded) % #5 is the current language (should be expanded) % #2 is the option list (should be expanded) % #6 is the name of the field to use % #1 is the language used \cs_new:Nn \polyglossia_localnumeral_langlang:nnnnnn { \foreignlanguage{#1}{\use:c {\prop_item:Nn \polyglossia@langsetup {#1/#6}} {#2} {#3}} } % check if empty value \cs_new:Npn \polyglossia_iii_map_csv_field_split_kv_ii_localnumeral:w #1 #2 = #3 \q_stop { \quark_if_no_value:NTF {#3} { \clist_map_break:n{\use_i:nn \polyglossia_localnumeral_locallang:nnnnn} } { \polyglossia_iii_map_csv_field_split_kv_iii_localnumeral:w #1 \q_stop } } \cs_new:Npn \polyglossia_iii_map_csv_field_split_kv_i_localnumeral:nw #1 #2 = #3 \q_stop { % parse only lang tag \tl_trim_spaces_apply:nN {#2} \str_if_eq:nnT {lang} { % if empty value \quark_if_nil:nTF{#3} { \clist_map_break:n{\use_i:nn \polyglossia_localnumeral_locallang:nnnn} } { % here we know what we have an equal sign \polyglossia_iii_map_csv_field_split_kv_ii_localnumeral:w {#1} #1 \q_no_value \q_stop } } } % map function \cs_new:Nn \polyglossia_iii_map_csv_localnumeral:n { % fast case is do nothing is empty \tl_if_empty:nF{#1} { \polyglossia_iii_map_csv_field_split_kv_i_localnumeral:nw {#1} #1 = \q_nil \q_stop } } % treat option is empty and option is lang=local % #2 number % #3 mainlanguage % #4 locallanguage % #5 field to call % #1 option % strip space to option \cs_new:Nn \polyglossia_iii_localnumeral:nnnnn { \tl_if_blank:nTF{#1} { \polyglossia_localnumeral_mainlang:nnnnn } { \str_if_eq:nnTF{#1}{lang=local} { \polyglossia_localnumeral_locallang:nnnnn } { % use postscript like trick push to stack {#1} {#2} {#3} {#4} \polyglossia_localnumeral_callshortcutorlong:nF {#1} { % same trick here if found we emit \use_i:nn % thus discarding the default choice that is not lang specified thus local \clist_map_function:nN {#1} {\polyglossia_iii_map_csv_localnumeral:n} \polyglossia_localnumeral_locallang:nnnnn } } {#1} {#2} {#3} {#4} {#5} } } % internal helper useful for oeee and onnn % #1 number % #2 mainlanguage % #3 locallanguage % #4 option % #5 field to call % strip space to option \cs_new:Nn \polyglossia_ii_localnumeral:nnnnn { \tl_trim_spaces_apply:nN {#4} \polyglossia_iii_localnumeral:nnnnn {#1}{#2}{#3}{#5} } \cs_generate_variant:Nn \polyglossia_ii_localnumeral:nnnnn { eeenn, eeeon, eeeen } % convert the counter to value % #1 counter % #2 mainlanguage % #3 locallanguage % #4 option \cs_new:Nn \polyglossia_i_localnumeral:nnnnn { \polyglossia_ii_localnumeral:eeeen {\int_value:w #1} {#2} {#3} {#4} {#5} } % print number usage \localnumeral[option]{numeral} % or \localnumeral*[option]{counter} % \Localnumeral[]{numeral} use main language % \localnumeral{numeral} use local language \NewExpandableDocumentCommand{\localnumeral}{som} { \IfBooleanTF{#1}% {% starred: take counter \exp_args:Nc \polyglossia_i_localnumeral:nnnnn {c@#3} {\mainlanguagename} {\languagename} {\IfNoValueTF {#2}{lang=local}{#2}} {localnumeral} }{% unstarred: take number \polyglossia_ii_localnumeral:eeeen {\int_eval:n{#3}} {\mainlanguagename} {\languagename} {\IfNoValueTF {#2}{lang=local}{#2}} {localnumeral} } } % print number usage \Localnumeral[option]{numeral} % or \Localnumeral*[option]{counter} % \Localnumeral[]{numeral} use main language % \localnumeral{numeral} use local language \NewExpandableDocumentCommand{\Localnumeral}{som} { \IfBooleanTF{#1}% {% starred: take counter \exp_args:Nc \polyglossia_i_localnumeral:nnnnn {c@#3} {\mainlanguagename} {\languagename} {\IfNoValueTF {#2}{lang=local}{#2}} {Localnumeral} }{% unstarred: take number \polyglossia_ii_localnumeral:eeeon {\int_eval:n{#3}} {\mainlanguagename} {\languagename} {\IfNoValueTF {#2}{lang=local}{#2}} {Localnumeral} } } \cs_new_nopar:Nn{\polyglossia@lang@frenchspacing:n}{ \prop_get:NxNTF \polyglossia@langsetup {#1/frenchspacing} \l_tmpa_tl { \str_case_e:nnF{\l_tmpa_tl}{ {true}{\frenchspacing} {false}{\nonfrenchspacing} } {\xpg@error{frenchspacing~should~be~true~or~false. Is~"\l_tmpa_ttl"~ for~ language~ "#1"}} } { \xpg@error{Could~ not~ retrieve~ key~ frenchspacing~ for~ language~ "#1"} \prop_show:N{\polyglossia@langsetup} } } \cs_new_nopar:Nn{\polyglossia@lang@indentfirst:n}{ \prop_get:NxNTF \polyglossia@langsetup {#1/indentfirst} \l_tmpa_tl { \str_case_e:nnF{\l_tmpa_tl}{ {true}{\french@indent} {false}{\nofrench@indent} } {\xpg@error{indentfirst~should~be~true~or~false. Is~"\l_tmpa_ttl"~ for~ language~ "#1"}} } { \xpg@error{Could~ not~ retrieve~ key~ indentfirst~ for~ language~ "#1"} \prop_show:N{\polyglossia@langsetup} } } \cs_new:Nn{\polyglossia@lang@setpardirection:n}{ \prop_get:NxNTF \polyglossia@langsetup {#1/direction} \l_tmpa_tl { \polyglossia@setpardirection:n{\l_tmpa_tl} } { \xpg@error{Could~ not~ retrieve~ key~ direction~ for~ language~ "#1"} \prop_show:N{\polyglossia@langsetup} } } \cs_new:Nn{\polyglossia@lang@settextdirection:nn}{ \prop_get:NxNTF \polyglossia@langsetup {#1/direction} \l_tmpa_tl { \polyglossia@settextdirection:n{\l_tmpa_tl}{#2} } { \xpg@error{Could~ not~ retrieve~ key~ direction~ for~ language~ "#1"} \prop_show:N{\polyglossia@langsetup} } } \AtEndDocument{ \prop_log:N{\polyglossia@langsetup} \prop_log:N{\__xpg_alias} } \def\xpg@lastlanguage{0}% \providebool{xpg@hyphenation@disabled}% \boolfalse{xpg@hyphenation@disabled} \def\xpg@disablehyphenation{% \ifx\@onlypreamble\@notprerr% \xpg@@disablehyphenation% \else% % if this is used in the preamble, we have to postpone % the execution until the main language has been set (#125). \cs_gset_nopar:Nn \polyglossia@AtBeginDocument@hyphenation: { \xpg@@disablehyphenation% }% \fi% } \def\xpg@@disablehyphenation{% \ifbool{xpg@hyphenation@disabled}{}{% \booltrue{xpg@hyphenation@disabled}% \xdef\xpg@lastlanguage{\the\language}% % We do not call \xpg@set@hyphenation@patterns here to avoid a warning message. % "nohyphenation" is not listed in language.dat.lua. \language=\l@nohyphenation% }% } \def\xpg@enablehyphenation{% \ifbool{xpg@hyphenation@disabled}{% \boolfalse{xpg@hyphenation@disabled}% \language=\csname xpg@lastlanguage\endcsname% }{}% } \let\disablehyphenation\xpg@disablehyphenation \let\enablehyphenation\xpg@enablehyphenation %\def\xpg@fontsetup#1{\xpg@csifdef@warn{xpg@fontsetup@#1}} %\def\xpg@fontsetup@none#1{\csgdef{#1@font}{\ifcsdef{#1font}{\csname #1font\endcsname}{}}} %<-- simplistic %\def\xpg@fontsetup@custom#1{\csuse{#1@font}} \cs_new:Nn \polyglossia@lang@autosetupfont:n { \str_if_eq:eeTF{\prop_item:Nn{\polyglossia@langsetup}{#1/fontsetup}}{true} { \str_if_eq:eeTF{\prop_item:Nn{\polyglossia@langsetup}{#1/lcscript}}{latin}% {\xpg@fontsetup@latin{#1}} {\xpg@fontsetup@nonlatin{#1}} } { \xpg@info{Skipping~ automatic~ font~ setup~ for~ language~ #1} } } % add fontfeature Language=#2 to langtag #1 % do nothing if #1 or #2 is empty \cs_new:Nn \polyglossia@addfontfeature@language:nn { \bool_if:nTF{\tl_if_empty_p:n{#1} || \tl_if_empty_p:n{#2}} { % maybe an error ? \xpg@warning{Asking~ to~ add~ empty~ feature~to~ latin~ font~ (Language="#2"~ to~ langtag~ "#1")} } { \str_if_eq:nnTF{#2}{Turkish}{ \fontspec_if_language:nTF {TRK}% { \addfontfeature{Language=Turkish} } { \fontspec_if_language:nTF {TUR}% { \addfontfeature{Language=Turkish} }{} } }{ \fontspec_if_language:nTF{#1} { \addfontfeature{Language=#2} } {} } } } \cs_generate_variant:Nn \polyglossia@addfontfeature@language:nn { on , no, oo , Vn, nV, VV , xn, nx, xx} % add fontfeature Script=#2 to scripttag #1 % do nothing if #1 or #2 is empty \cs_new:Nn \polyglossia@addfontfeature@script:nn { \bool_if:nTF{\tl_if_empty_p:n{#1} || \tl_if_empty_p:n{#2}} { % maybe an error ? \xpg@warning{Asking~ to~ add~ empty~ feature~to~ latin~ font (Script="#2"~ to~ scripttag~ "#1")} } { \fontspec_if_script:nTF{#1} {\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_lowercase:n#2}font\endcsname~ with~ \string\newfontfamily\space command } } } } \cs_generate_variant:Nn \polyglossia@addfontfeature@script:nn { on , no, oo , Vn, nV, VV , xn, nx, xx} \def\xpg@fontsetup@latin#1{% \begingroup \csgdef{#1@font@rm}{% \cs_if_exist_use:cF{#1font}{ \rmfamilylatin \polyglossia@addfontfeature@language:xx{\prop_item:Nn{\polyglossia@langsetup}{#1/langtag}} {\prop_item:Nn{\polyglossia@langsetup}{#1/language}} } } \csgdef{#1@font@sf}{% \cs_if_exist_use:cF{#1fontsf}{ \sffamilylatin \polyglossia@addfontfeature@language:xx{\prop_item:Nn{\polyglossia@langsetup}{#1/langtag}} {\prop_item:Nn{\polyglossia@langsetup}{#1/language}} }% }% \csgdef{#1@font@tt}{% \cs_if_exist_use:cF{#1fonttt}{ \ttfamilylatin \polyglossia@addfontfeature@language:xx{\prop_item:Nn{\polyglossia@langsetup}{#1/langtag}} {\prop_item:Nn{\polyglossia@langsetup}{#1/language}} }% }% \endgroup } \def\xpg@fontsetup@nonlatin#1{% \begingroup \csgdef{#1@font@rm}{% \cs_if_exist_use:cF{#1font} { \providetoggle{#1@use@script@font}% \str_if_eq:nnTF{\prop_item:Nn{\polyglossia@langsetup}{#1/script}}{\prop_item:Nn{\polyglossia@langsetup}{#1/language}} {\rmfamilylatin}% {\cs_if_exist_use:cTF{\prop_item:Nn{\polyglossia@langsetup}{#1/lcscript} font} { \toggletrue{#1@use@script@font}% } { \rmfamilylatin } } \iftoggle{#1@use@script@font}{}{% \polyglossia@addfontfeature@script:xx{\prop_item:Nn{\polyglossia@langsetup}{#1/scripttag}} {\prop_item:Nn{\polyglossia@langsetup}{#1/script}} }% \polyglossia@addfontfeature@language:xx{\prop_item:Nn{\polyglossia@langsetup}{#1/langtag}} {\prop_item:Nn{\polyglossia@langsetup}{#1/language}} }% \def\familytype{rm}% }% \csgdef{#1@font@sf}{% \cs_if_exist_use:cF{#1fontsf}% { \providetoggle{#1@use@script@fontsf}% \str_if_eq:nnTF{\prop_item:Nn{\polyglossia@langsetup}{#1/script}}{\prop_item:Nn{\polyglossia@langsetup}{#1/language}} {\sffamilylatin}% {\cs_if_exist_use:cTF{\prop_item:Nn{\polyglossia@langsetup}{#1/lcscript} fontsf} { \toggletrue{#1@use@script@fontsf}% } { \sffamilylatin } } \iftoggle{#1@use@script@fontsf}{}{% \polyglossia@addfontfeature@script:xx{\prop_item:Nn{\polyglossia@langsetup}{#1/scripttag}} {\prop_item:Nn{\polyglossia@langsetup}{#1/script}} }% \polyglossia@addfontfeature@language:xx{\prop_item:Nn{\polyglossia@langsetup}{#1/langtag}} {\prop_item:Nn{\polyglossia@langsetup}{#1/language}} }% \def\familytype{sf}% }% \csgdef{#1@font@tt}{% \cs_if_exist_use:cF{#1fonttt}% { \providetoggle{#1@use@script@fonttt}% \str_if_eq:nnTF{\prop_item:Nn{\polyglossia@langsetup}{#1/script}}{\prop_item:Nn{\polyglossia@langsetup}{#1/language}} {\ttfamilylatin}% {\cs_if_exist_use:cTF{\prop_item:Nn{\polyglossia@langsetup}{#1/lcscript} fonttt} { \toggletrue{#1@use@script@fonttt}% } { \ttfamilylatin } } \iftoggle{#1@use@script@fonttt}{}{% \polyglossia@addfontfeature@script:xx{\prop_item:Nn{\polyglossia@langsetup}{#1/scripttag}} {\prop_item:Nn{\polyglossia@langsetup}{#1/script}} }% \polyglossia@addfontfeature@language:xx{\prop_item:Nn{\polyglossia@langsetup}{#1/langtag}} {\prop_item:Nn{\polyglossia@langsetup}{#1/language}} }% \def\familytype{tt}% }% \endgroup } %%% END OF PolyglossiaSetup %% ensure localization of \markright and \markboth commands %%% THIS IS NOW DISABLED BY DEFAULT \cs_new_nopar:Nn {\polyglossia@local@marks:n} {} \cs_new_nopar:Nn {\polyglossia@enable@local@marks:} { \xpg@info{Option:~ localmarks}% \cs_gset_nopar:Nn \polyglossia@local@marks:n {% \def\xpg@tmp@lang{##1}% \DeclareRobustCommand\markboth[2]{% \begingroup \let\label\relax \let\index\relax \let\glossary\relax \unrestored@protected@xdef\@themark {% {\lowercase{\foreignlanguage{\xpg@tmp@lang}}{\protect\@@ensure@maindir{####1}}}% {\lowercase{\foreignlanguage{\xpg@tmp@lang}}{\protect\@@ensure@maindir{####2}}}% }% \@temptokena \expandafter{\@themark}% \mark{\the\@temptokena}% \endgroup \if@nobreak\ifvmode\nobreak\fi\fi% }% \DeclareRobustCommand\markright[1]{% \begingroup \let\label\relax \let\index\relax \let\glossary\relax \expandafter\@markright\@themark {\lowercase{\foreignlanguage{\xpg@tmp@lang}}{\protect\@@ensure@maindir{####1}}}% \@temptokena \expandafter{\@themark}% \mark{\the\@temptokena}% \endgroup \if@nobreak\ifvmode\nobreak\fi\fi% }% % This part seems wrong (see #396 for explanation). Remove after a while. % \def\@markright####1####2####3{% % \@temptokena{\protect\@@ensure@maindir{####1}}% % \unrestored@protected@xdef\@themark{% % {\the\@temptokena}% % {\protect\@@ensure@maindir{####3}}% % }% % }% }% } % Easy way out – Arthur, 2012-08-01 \ifcsdef{newXeTeXintercharclass}{% % to reset the intercharclass of a character to "normal" \newXeTeXintercharclass\xpg@normalclass %TODO }{} %% when no patterns are available, we use \l@nohyphenation, assigned to 255 %% (suggestion by Enrico Gregorio) \str_case_e:nn{\c_sys_engine_str}{ {luatex} { \@ifundefined{l@nohyphenation} {\chardef\l@nohyphenation=\directlua{ tex.sprint(polyglossia.newloader_loaded_languages.nohyphenation)}\relax } {} } {xetex} { \@ifundefined{l@nohyphenation}{\chardef\l@nohyphenation=255 }{} } } %we call this macro when a gloss file is not found for a given language \def\xpg@nogloss#1{% \xpg@warning{Neither~ file~ gloss-#1.ldf~ nor file~ gloss-#1.lde~ exists!\MessageBreak I~ will~ nevertheless~ try~ to~ use~ hyphenation~ patterns~ for~ #1.}% \PolyglossiaSetup{#1}{hyphenmins={2,3},hyphennames={#1},fontsetup=true}% % the above amounts to: %\ifcsundef{l@#1}% % {\expandafter\adddialect\csname l@#1\endcsname\l@nohyphenation\relax}% % {\setlocalhyphenmins{#1}{2}{3}}% %\csdef{#1@language}{\language=\csname l@#1\endcsname}% } \newcommand{\xpg@input}[1]{% % Store catcode of @ before making at letter \chardef\xpg@saved@at@catcode\catcode`\@ \makeatletter \input{#1}% % restore former @ catcode \catcode`\@=\xpg@saved@at@catcode% } %% Load a lde file \cs_new_nopar:Nn \__xpg_gloss_ext: {lde} \cs_new_nopar:Ne \__xpg_saved_@pkgextension: {\@pkgextension} \msg_new:nnn { polyglossia } { directloadgloss } { You~ should~ not~ load~ directly~ the~ gloss~ file. ~ You~ must~ use~ `\string\setotherlanguage\{#1\}' or `\string\setmainlanguage\{#1\}'. } \msg_redirect_name:nnn { polyglossia } { directloadgloss } { critical } \NewDocumentCommand{\__xpg_ProvidesLanguageDefinitionExtension_error}{m m m m} { \msg_critical:nn { polyglossia } { directloadgloss } } % ProvideExplPackage but for language file \cs_new_eq:NN \ProvidesLanguageDefinitionExtension \__xpg_ProvidesLanguageDefinitionExtension_error \cs_new_eq:NN \__xpg_saved_ProvidesExplPackage \ProvidesExplPackage \NewDocumentCommand{\__xpg_ProvidesLanguageDefinitionExtension}{m m m m} { \__xpg_saved_ProvidesExplPackage{#1}{#2}{#3}{#4} \cs_gset_eq:NN \@pkgextension \__xpg_saved_@pkgextension: \cs_gset_eq:NN \ProvidesLanguageDefinitionExtension \__xpg_ProvidesLanguageDefinitionExtension_error } % wrapper for loading a gle file \NewDocumentCommand{\RequireLanguageDefinitionExtension}{O{} m} { \cs_gset_eq:NN \__xpg_saved_@pkgextension: \@pkgextension \cs_gset_eq:NN \__xpg_saved_ProvidesExplPackage \ProvidesExplPackage \cs_gset_eq:NN \@pkgextension \__xpg_gloss_ext: \cs_gset_eq:NN \ProvidesLanguageDefinitionExtension \__xpg_ProvidesLanguageDefinitionExtension \RequirePackage[#1]{gloss-#2} % be paranoiac restore \cs_gset_eq:NN \@pkgextension \__xpg_saved_@pkgextension: \cs_gset_eq:NN \__xpg_ProvidesLanguageDefinitionExtension_error \ProvideLanguageDefinitionExtension } % try to load a language file \cs_new:Nn \polyglossia_load_lang_definition:nn { \file_if_exist:eTF{gloss-#2.lde} { \RequireLanguageDefinitionExtension[#1]{#2} \setkeys{#2}{#1} } { \file_if_exist:nTF{gloss-#2.ldf} { % Temporarily force catcode of ~ to 13 since babelsh.def % requires it. This is needed particularly with LaTeX3 % packages which force \ExplSyntaxOn (#425) \protected\edef\xpg@restore@tilde@catcode{\catcode 126 = \the\catcode 126\relax} \catcode 126 = 13 \xpg@input{gloss-#2.ldf} \setkeys{#2}{#1} % restore former ~ catcode \xpg@restore@tilde@catcode } { \xpg@nogloss{#2} } } } \cs_generate_variant:Nn \polyglossia_load_lang_definition:nn { ee, ef, en, eo, ex, fe, ff, fn, fo, fx, ne, nf, no, nx, oe, of, on, oo, ox, xe, xf, xn, xo, xx } % load a master language from an alias file \newcommand*\xpg@load@master@language[1] { \file_if_exist:eTF{gloss-#1.lde} { \RequireLanguageDefinitionExtension{#1} } { \xpg@input{gloss-#1.ldf} } \seq_if_in:NxF \__xpg_langs_loaded {#1} { % define environment and command if not alias \str_if_eq:eeT {\prop_item:Ne \__xpg_alias {#1/target}} {#1} { \use:c{\prop_item:Nn{\polyglossia@langsetup} {#1/DefineCommandsCmd}} {#1} } } \polyglossia@register@language:nn{}{#1}% \seq_gput_right:Nn \__xpg_langs_loaded {#1} } \prop_new:N \__xpg_alias % define environment and command if not alias \cs_new:Nn \xpg_define_language_commands:n { \str_if_eq:eeT {\prop_item:Ne \__xpg_alias {#1/target}} {#1} { \exp_args:Ne \newenvironment {\prop_item:Nn{\polyglossia@langsetup}{#1/envname}} [1] [] { \begin{otherlanguage}[##1]{#1} }% { \end{otherlanguage} }% \exp_args:Nc \newcommand {text#1} [2][] {% \__xpg_textlanguage:een{##1}{#1}{##2}% }% } } \cs_generate_variant:Nn \xpg_define_language_commands:n {e} \AtBeginDocument{ \prop_log:N{\__xpg_alias} } % resolve alias property #1 lang #2 item \cs_new:Nn \xpg_alias_prop_item:nn { \prop_if_in:NeTF \__xpg_alias {#1/#2} { \prop_item:Ne \__xpg_alias {#1/#2} } { \prop_if_in:NeTF \__xpg_alias {#1/target} { % target to self fall back to language table \str_if_eq:eeTF { \prop_item:Ne \__xpg_alias {#1/target} } { #1 } { \prop_item:Nn{\polyglossia@langsetup} {#1/#2} } % load alias by recursion { \xpg_alias_prop_item:ee { \prop_item:Ne \__xpg_alias {#1/target} } {#2} } } { % empty } } } \cs_generate_variant:Nn \xpg_alias_prop_item:nn {en, ne, ee} % add option #2 to list of option of language #1 \cs_new:Nn \xpg_alias_add_to_option_i:nn { \tl_if_blank:eTF {#2} { \xpg_alias_prop_item:nn {#1}{options} } { \tl_if_blank:eTF { \xpg_alias_prop_item:nn {#1}{options} } { #2 } { \xpg_alias_prop_item:nn {#1}{options},#2 } } } % get base language \cs_new:Nn \xpg_alias_base_lang:n { \str_if_eq:eeTF { \prop_item:Ne \__xpg_alias {#1/target} } { #1 } { #1 } { \xpg_alias_base_lang:n { \prop_item:Ne \__xpg_alias {#1/target} } } } \cs_generate_variant:Nn \xpg_alias_base_lang:n {e} \keys_define:nn { polyglossia/alias } { % babelname\l_tmpa_prop babelname .prop_put:N = \__xpg_language_alias_prop, % bcp47 bcp47 .prop_put:N = \__xpg_language_alias_prop, % variant variant .prop_put:N = \__xpg_language_alias_prop, } % provide way to define alias environment and command % #1 () variant % #2 [] option (not yet without variant and bcp47 name) % #3 language % #4 () babel name % #5 [] bcp47 name % #6 alias \DeclareDocumentCommand \xpg_language_alias { D(){} O{} m D(){} O{} m} { \prop_gremove:Nn \__xpg_alias {#6/target} \prop_gremove:Nn \__xpg_alias {#6/options} \prop_gremove:Nn \__xpg_alias {#6/bcp47} \prop_gremove:Nn \__xpg_alias {#6/babelname} \prop_gremove:Nn \__xpg_alias {#6/variant} \prop_gput:Nee \__xpg_alias {#6/target} {#3} \tl_if_blank:eF {#1} { \prop_gput:Nee \__xpg_alias {#6/variant} {#1} } \tl_if_blank:eF {#5} { \prop_gput:Nee \__xpg_alias {#6/bcp47} {#5} } \tl_if_blank:eF {#4} { \prop_gput:Nee \__xpg_alias {#6/babelname} {#1} } \tl_if_blank:eF {#2} { \prop_gput:Nee \__xpg_alias {#6/options} {#2} } } % provide way to define alias environment and command % \setlanguagealias[]{}{} \DeclareDocumentCommand \setlanguagealias {s O{} m m} { % The starred version does not define commands and environments \IfBooleanF {#1} { \exp_args:Nc \providecommand {text#4} [2][] {} \exp_args:Nc \renewcommand {text#4} [2][] { \__xpg_textlanguage:een{##1}{#4}{##2} } \exp_args:Nc \providecommand {#4} {} \exp_args:Ne \renewenvironment {#4} { \begin{otherlanguage}{#4} } { \end{otherlanguage} } }% \tl_clear_new:N \__xpg_alias_option_tl \prop_clear_new:N \__xpg_language_alias_prop \keys_set_known:nnN{polyglossia/alias} {#2} \__xpg_alias_option_tl \xpg_language_alias (\prop_item:Nn \__xpg_language_alias_prop {variant}) % TODO not yet [\__xpg_alias_option_tl] [#2] {#3} (\prop_item:Nn \__xpg_language_alias_prop {babelname}) [\prop_item:Nn \__xpg_language_alias_prop {bcp47}] {#4} } \cs_new:Nn \polyglossia@register@language:nn { \clist_if_in:NeF \xpg@loaded {#2}{ \clist_gput_right:Ne \xpg@loaded {#2} } % Register the language options \polyglossia@set@lang@options:nnn {#2} {#1} {@xpg@set@langvariant} % register babelname \prop_get:NeN \polyglossia@langsetup {#2/babelname} \l_tmpa_tl \clist_if_in:NeF \xpg@bloaded {\l_tmpa_tl}{ \clist_gput_right:Ne \xpg@bloaded {\l_tmpa_tl} } % register BCP-47 ID \prop_get:NeN \polyglossia@langsetup {#2/bcp47} \l_tmpa_tl \clist_if_in:NeF \xpg@bcp@loaded {\l_tmpa_tl}{ \clist_gput_right:Ne \xpg@bcp@loaded {\l_tmpa_tl} } } \DeclareDocumentCommand \setdefaultlanguage { O{} m } { % latex is an internal language, so do not record \str_if_eq:eeF{#2}{latex} { \clist_if_in:NeF \xpg@loaded {\xpg_alias_base_lang:n{##2}}{ \clist_gput_right:Ne \xpg@loaded {\xpg_alias_base_lang:n{##2}} } } \seq_if_in:NxF \__xpg_langs_loaded {#2} { \polyglossia_load_lang_definition:nn{#1}{#2} % define environment and command if not alias \str_if_eq:eeT {\prop_item:Ne \__xpg_alias {#2/target}} {#2} { \use:c{\prop_item:Ne{\polyglossia@langsetup} {#2/DefineCommandsCmd}} {#2} } \exp_args:Nnx \seq_gput_right:Nn \__xpg_langs_loaded {#2} } \polyglossia@set@default@language:ee {\xpg_alias_add_to_option_i:nn{#2}{#1}} {\xpg_alias_base_lang:n{#2}}% } \cs_new:Nn \polyglossia@set@default@language:nn { \gdef\xpg@main@language{#2}% \tl_if_blank:nTF {#1} { \cs_gset_nopar:Npn \mainlanguagevariant {} } {% % Register the language options \polyglossia@set@lang@options:nnn {#2} {#1} {@xpg@main@langvariant}% }% \csgdef{#2@gvar}{\mainlanguagevariant}% %% The following settings are for the default language and script % this tells bidi.sty or luabidi.sty that the document is RTL \__xpg_if_LR_str:eF{\prop_item:Nn{\polyglossia@langsetup}{#2/direction}} { \__xpg_setRTLmain: } \cs_gset_nopar:Nn \polyglossia@AtBeginDocument@selectlanguage: { \selectbackgroundlanguage{#2} \selectlanguage[#1]{#2}% } \xpg@info{Default~ language~ is~ #2}% \polyglossia@set@language@name[#1]{#2}% \cs_gset_nopar:Npn \mainlanguagename {#2} % Store babelname of main language (for external packages such as biblatex) \cs_gset_nopar:Npe \mainbabelname { \prop_item:Nn \polyglossia@langsetup {#2/babelname} } % Store babelname of current language (for external packages such as biblatex) \cs_gset_eq:NN \babelname \mainbabelname \cs_gset_eq:cc{#2@gbabelname}{babelname}% % Store BCP-47 id of main language \cs_gset_nopar:cpe {mainbcp47id} { \prop_item:Nn \polyglossia@langsetup {#2/bcp47} } \cs_gset_eq:cc {bcp47id} {mainbcp47id} \cs_gset_eq:cc{#2@gbcp47id}{bcp47id} \sys_if_engine_luatex:T { \directlua{polyglossia.set_default_language('\luatexluaescapestring{\string#2}')}% } } \cs_generate_variant:Nn\polyglossia@set@default@language:nn { ee, ef, en, eo, ex, fe, ff, fn, fo, fx, ne, nf, no, nx, oe, of, on, oo, ox, xe, xf, xn, xo, xx } \let\setmainlanguage=\setdefaultlanguage % Returns the language ID of the current language % Currently supported: bcp-47 \DeclareDocumentCommand \languageid {m} { \str_case:nnF {#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:nnF {#1} { {bcp-47} { \csuse{mainbcp47id} } {bcp47} { \csuse{mainbcp47id} } } { \xpg@error{Invalid~ \string\mainlanguageid\space argument:~ #1} } } % main babel name \cs_new_nopar:Npn \mainlanguagename {} \cs_new_nopar:Npn \mainbabelname {} \cs_new_nopar:cpn {mainbcp47id} {} \cs_new_nopar:Npn \mainlanguagevariant {}% % Store main language variant for external packages \define@key{xpg@main@langvariant}{variant}{% \cs_gset_nopar:Npn \mainlanguagevariant {#1}% } \cs_new_nopar:Npn \babelname {} \def\languagevariant{}% % Store current language variant for external packages \define@key{xpg@set@langvariant}{variant}{% \def\languagevariant{#1}% } \newcommand*\polyglossia@set@language@name[2][]{ \def\languagename{#2}% \tl_if_blank:nTF {#1}{% \ifcsundef{#2@gvar}{\def\languagevariant{}}{\def\languagevariant{\csuse{#2@gvar}}} }{% % Register the language options \polyglossia@set@lang@options:nnn {#2} {#1} {@xpg@set@langvariant}% \cs_set_eq:cc{#2@gvar}{languagevariant}% }% } \newcommand*{\resetdefaultlanguage}[2][]{% \polyglossia@reset@default@language:nn {\xpg_alias_add_to_option_i:nn{#2}{#1}} {\xpg_alias_base_lang:n{#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} \csuse{noextras@\xpg@main@language}% % This is a hook for external packages which want to access variants % via babelname (such as biblatex) \cs_if_exist_use:c{noextras@bbl@\mainbabelname}% \csuse{init@noextras@\xpg@main@language}% \polyglossia@set@language@name[#1]{#2}% \__xpg_if_LR_str:eF{\prop_item:Ne{\polyglossia@langsetup}{#2/direction}} { \@rlmaintrue\@rl@footnotetrue } \selectlanguage[#1]{#2}% \selectbackgroundlanguage{#2}% % Store babelname of current language (for external packages such as biblatex) \tl_if_blank:nTF {#1}{% \ifcsundef{#2@gbabelname}{% \edef\babelname{\prop_item:Nn{\polyglossia@langsetup}{#2/babelname}}% }{% \edef\babelname{\csuse{#2@gbabelname}}% }% }{% \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}}% }% } \cs_generate_variant:Nn \polyglossia@reset@default@language:nn { ee, ef, en, eo, ex, fe, ff, fn, fo, fx, ne, nf, no, nx, oe, of, on, oo, ox, xe, xf, xn, xo, xx } % This saves the normalfont for the latin script since we may change normalfont in other scripts \let\normalfontlatin=\normalfont% % Provide default fonts (as set with \setmainfont, \setsansfont and \setmonofont) % for Latin scripts and as a fallback for non-Latin scripts. \DeclareRobustCommand\xpg@defaultfont@rm{% \tl_if_empty:NF{\g__fontspec_nfss_enc_tl}{\fontencoding{\g__fontspec_nfss_enc_tl}}% \fontfamily\rmdefault% \ifdefined\UseHook\UseHook{rmfamily}\fi% \selectfont% } \DeclareRobustCommand\xpg@defaultfont@sf{% \tl_if_empty:NF{\g__fontspec_nfss_enc_tl}{\fontencoding{\g__fontspec_nfss_enc_tl}}% \fontfamily\sfdefault% \ifdefined\UseHook\UseHook{sffamily}\fi% \selectfont% } \DeclareRobustCommand\xpg@defaultfont@tt{% \tl_if_empty:NF{\g__fontspec_nfss_enc_tl}{\fontencoding{\g__fontspec_nfss_enc_tl}}% \fontfamily\ttdefault% \ifdefined\UseHook\UseHook{ttfamily}\fi% \selectfont% } \def\xpg@patch@fontfamilies{% % This robustifies the redefinitions of \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) \cs_gset_eq:cc{rmfamilylatin}{xpg@defaultfont@rm}% \cs_gset_eq:cc{sffamilylatin}{xpg@defaultfont@sf}% \cs_gset_eq:cc{ttfamilylatin}{xpg@defaultfont@tt}% \def\xpg@set@familydefault{% % We need the \edef route here in order % to detect both \renewcommand and \let % changes. \edef\tempa{\familydefault}% \edef\tempb{\sfdefault}% \ifcsequal{tempa}{tempb}% {\def\familytype{sf}} {\edef\tempb{\ttdefault}% \ifcsequal{tempa}{tempb}% {\def\familytype{tt}} {\def\familytype{rm}}} \xpg@patch@fontfamilies% % This (re-)saves the normalfont for the latin script since we may % change normalfont in other scripts \let\normalfontlatin=\normalfont% % And for all cases, we also reset \familylatin \cs_gset_eq:cc{rmfamilylatin}{xpg@defaultfont@rm}% \cs_gset_eq:cc{sffamilylatin}{xpg@defaultfont@sf}% \cs_gset_eq:cc{ttfamilylatin}{xpg@defaultfont@tt}% } \def\resetfontlatin{% \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}% \ifx\familytype\tmp@tt% \ttfamilylatin% \else\ifx\familytype\tmp@sf% \sffamilylatin% \else\rmfamilylatin\fi\fi} \def\xpg@select@fontfamily#1{% \def\tmp@tt{tt}\def\tmp@sf{sf}% \ifx\familytype\tmp@tt \__xpg_use_or_warn:c{#1@font@tt}% \else\ifx\familytype\tmp@sf \__xpg_use_or_warn:c{#1@font@sf}% \else\__xpg_use_or_warn:c{#1@font@rm}\fi\fi} \def\xpg@set@normalfont#1{% \letcs{\rmfamily}{#1@font@rm}% \letcs{\sffamily}{#1@font@sf}% \letcs{\ttfamily}{#1@font@tt}% \robustify\rmfamily% \robustify\sffamily% \robustify\ttfamily% \gdef\normalfont{\protect\xpg@select@fontfamily{#1}% \fontseries{\seriesdefault}\selectfont% \fontshape{\shapedefault} \ifdefined\UseHook\UseHook{normalfont}\fi% \selectfont}% \gdef\reset@font{\protect\normalfont}% } \let\@@fterindentfalse\@afterindentfalse \def\french@indent{% \let\@afterindentfalse\@afterindenttrue \@afterindenttrue% } \def\nofrench@indent{% \let\@afterindentfalse\@@fterindentfalse \@afterindentfalse% } \cs_new_nopar:Npn \selectbackgroundlanguage #1 {% \polyglossia@select@background@language:n {\xpg_alias_base_lang: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}% } \cs_generate_variant:Nn \polyglossia@select@background@language:n {e} % Declare secondary language #2 with language options #1 \DeclareDocumentCommand \setotherlanguage { O{} m } { \seq_if_in:NxF \__xpg_langs_loaded {#2} { \polyglossia_load_lang_definition:ee {#1} {#2}% % define environment and command if not alias \str_if_eq:eeT {\prop_item:Ne \__xpg_alias {#2/target}} {#2} { \use:c{\prop_item:Ne{\polyglossia@langsetup} {#2/DefineCommandsCmd}} {#2} } \polyglossia@set@other@language:ee {\xpg_alias_add_to_option_i:nn{#2}{#1}} {\xpg_alias_base_lang:n{#2}}% \exp_args:Nnx \seq_gput_right:Nn \__xpg_langs_loaded {#2} } } \cs_new:Nn \polyglossia@set@other@language:nn { \polyglossia@register@language:nn{#1}{#2}% % If a variant is set, store it. \gdef\otherlanguagevariant{} % Register the language options \polyglossia@set@lang@options:nnn {#2} {#1} {@xpg@other@langvariant}% \csgdef{#2@gvar}{\otherlanguagevariant}% \prop_get:NxNT \polyglossia@langsetup {#2/babelname} \l_tmpa_tl { \xdef\otherlanguagebabelname{\l_tmpa_tl} } \cs_gset_eq:cc{#2@gbabelname}{otherlanguagebabelname}% } \cs_generate_variant:Nn \polyglossia@set@other@language:nn { ee, ef, en, eo, ex, fe, ff, fn, fo, fx, ne, nf, no, nx, oe, of, on, oo, ox, xe, xf, xn, xo, xx } % Store main language variant for external packages \define@key{xpg@other@langvariant}{variant}{% \gdef\otherlanguagevariant{#1}% } \newcommand\setotherlanguages[1]{% \def\do##1{\setotherlanguage{##1}}% \exp_args:Nx\docsvlist{#1}}% \def\common@language{% FIXME is this really needed??? \ifbool{xpg@hyphenation@disabled}{% \xdef\xpg@lastlanguage{\z@}% }{% \language=\z@ }% \lefthyphenmin=\tw@ \righthyphenmin=\thr@@} \def\xpg@initial@setup{% \common@language% } % Alias to \text, but more suitable % for specific (esp. tag-based) aliases % where \text would cause clashes % (e.g., \textit) \newcommand\textlang[3][]{% \__xpg_textlanguage:een {#1} {#2} {#3} }% % Alias to {}, but more suitable % for specific (esp. tag-based) aliases % where {} would cause clashes % (e.g., \fi) \newenvironment{lang}[2][]{% \begin{otherlanguage}[#1]{#2}% }{% \end{otherlanguage} }% \providecommand{\foreignlanguage}{} % wrapper for foreignlanguage and otherlanguage* \newcommand*\polyglossia@setforeignlanguage[2][]{ \select@@language[#1]{#2} \polyglossia@register@language:nn{#1}{#2}% % Store babelname of current language (for external packages such as biblatex) \tl_if_blank:nTF {#1}{% \ifcsundef{#2@gbabelname}{% \edef\babelname{\prop_item:Nn{\polyglossia@langsetup}{#2/babelname}}% }{% \edef\babelname{\csuse{#2@gbabelname}}% }% }{% \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* % and \text % #1 option % #2 language \newcommand{\xpg@otherlanguage}[2][] {% \polyglossia@error@iflangnotloaded:n{#2} \exp_args:Nne \setkeys{#2}{#1}% \polyglossia@setforeignlanguage[#1]{#2} % Hook for external packages such as biblatex \polyglossia@language@switched% % buggy restoration heure \csuse{inlineextras@#2}% % This is a hook for external packages which want to access variants % via babelname (such as biblatex) \cs_if_exist_use:c{inlineextras@bbl@\babelname}% } \renewcommand{\foreignlanguage}[3][] { \__xpg_foreignlanguage:eeen {#1} {#2} {\xpg_alias_base_lang:n{#2}} {#3} } % internal wrapper for foreing language % #1 option % #2 alias % #3 base lang % #4 text \cs_new:Nn \__xpg_foreignlanguage:nnnn { \tl_if_blank:nT {#3} { \msg_show:nnn { polyglossia } { languagenotloaded } {#2} } \group_begin: \xpg@otherlanguage[\xpg_alias_add_to_option_i:nn{#2}{#1}]{#3}% \polyglossia@lang@settextdirection:nn{#3}{#4}% \group_end: } \cs_generate_variant:Nn \__xpg_foreignlanguage:nnnn {eeen} % otherlanguage* is the environment equivalent of \foreignlanguage \expandafter\providecommand\csname otherlanguage*\endcsname{} \renewenvironment{otherlanguage*}[2][] {% \__xpg_otherlanguage:eee {#1} {#2} {\xpg_alias_base_lang:n{#2}} } {\egroup} % internal wrapper % #1 option % #2 alias % #3 base lang \cs_new:Nn \__xpg_otherlanguage:nnn { \tl_if_blank:nT {#3} { \msg_show:nnn { polyglossia } { languagenotloaded } {#2} } \xpg@otherlanguage[\xpg_alias_add_to_option_i:nn{#2}{#1}]{#3}% \polyglossia@lang@settextdirection:nn{#3}% \bgroup } \cs_generate_variant:Nn \__xpg_otherlanguage:nnn { eee } % use by \text and \textlang. Equivalent to \foreignlanguage, % except that dates are localized. % #1: option % #2: alias % #3: text \cs_new:Nn \__xpg_textlanguage:nnn { \__xpg_textlanguage:nnen {#1} {#2} {\xpg_alias_base_lang:n{#2}} {#3} } \cs_generate_variant:Nn \__xpg_textlanguage:nnn {een} % use by \text and \textlang. Equivalent to \foreignlanguage, % except that dates are localized. % #1: option % #2: alias % #3: base language % #4: text \cs_new:Nn \__xpg_textlanguage:nnnn { \tl_if_blank:nT {#3} { \msg_show:nnn { polyglossia } { languagenotloaded } {#2} } \group_begin: \xpg@otherlanguage[#1]{#3}% \csuse{date#3}% % This is a hook for external packages which want to access variants % via babelname (such as biblatex) \cs_if_exist_use:c{date@bbl@\babelname}% \polyglossia@lang@settextdirection:nn{#3}{#4}% \group_end: % Reset the language's/script's font families \str_if_eq:eeTF{\prop_item:Nn{\polyglossia@langsetup}{#3/lcscript}}{latin}{}{\resetfontlatin}% } \cs_generate_variant:Nn \__xpg_textlanguage:nnnn {nnen} % Define language-specific hyphenation exceptions \newcommand\pghyphenation[3][]{ \bgroup \polyglossia@error@iflangnotloaded:n{#2} \setkeys{#2}{#1}% \select@@language[#1]{#2}% \hyphenation{#3}% \egroup } % Hook that other package authors can use % (for instance biblatex): \newcommand*{\xpg@hook@setlanguage}{} \def\xpg@pop@language@i#1#2{% \xpg@set@language@aux[#1]{#2}% \xpg@hook@setlanguage \let\emp@langname\@undefined} \DeclareDocumentCommand \selectlanguage {s O{} m} { \__xpg_msg_if_lang_not_loaded:n {#3} \polyglossia@select@language:nee {#1} {\xpg_alias_add_to_option_i:nn{#3}{#2}} {\xpg_alias_base_lang:n{#3}} } \cs_new:Nn \polyglossia@select@language:nnn { \IfBooleanF {#1} { \cs_set_nopar:Npx \xpg@pop@language { \exp_not:N \xpg@pop@language@i {#2} {#3} } \group_insert_after:N \xpg@pop@language } % Register the language options \polyglossia@set@lang@options:nnn {#3} {#2} {@xpg@set@langvariant}% % The starred variant does not write to the aux \IfBooleanTF#1{% \xpg@set@language@nonaux[#2]{#3}% } {% \xpg@set@language@aux[#2]{#3}% }% \sys_if_engine_luatex:T { \directlua{polyglossia.select_language('\luatexluaescapestring{\string#3}', \the\csname l@#3\endcsname)}% } \polyglossia@register@language:nn{#2}{#3}% } \cs_generate_variant:Nn \polyglossia@select@language:nnn { nee, nne } % set lang option #2 for lang #1 \cs_new:Nn \polyglossia@set@lang@options:nnn { \tl_if_blank:nF {#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=#3:#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:nnn {#1} {#2} {@xpg@set@langvariant}% } % Record synonymous keyvals such as variant=us and variant=american % Syntax: \xpg@set@alias@values{}{}{}{} \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 { \str_if_eq:eeTF{\l_tmpa_tl}{#3} {\prg_return_true:} { \prop_get:cnNTF {xpg@alias@keyvals@#1@#3} {#2} \l_tmpb_tl { \clist_set:Ne{\l_tmpa_clist}{\l_tmpb_tl} \providetoggle{xpgvalfound} \togglefalse{xpgvalfound} \clist_map_inline:Nn \l_tmpa_clist { \str_if_eq:eeT{##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}{% \clist_if_in:NeF \xpg@vloaded {#1}{ \clist_gput_right:Ne \xpg@vloaded {#1} } } % Test if language is loaded \newcommand*\iflanguageloaded[3]{% \AddToHook{begindocument/end}{% \clist_if_in:NeTF \xpg@loaded{#1}{#2}{#3}% }% } % Same for babellanguage is loaded \newcommand*\ifbabellanguageloaded[3]{% \AddToHook{begindocument/end}{% \clist_if_in:NeTF \xpg@bloaded{#1}{#2}{#3}% }% } % Same for languageid \DeclareDocumentCommand \iflanguageidloaded {mmmm} { \AddToHook{begindocument/end}{% \str_case:nnTF {#1} { {bcp-47} { \clist_if_in:NeTF \xpg@bcp@loaded{#2}{#3}{#4} } {bcp47} { \clist_if_in:NeTF \xpg@bcp@loaded{#2}{#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.} \prg_return_false: } } % 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}% } \newcommand*{\xpg@set@language@aux}[2][]{% % Store babelname of current language (for external packages such as biblatex) \tl_if_blank:nTF {#1}{% \ifcsundef{#2@gbabelname}{% \edef\babelname{\prop_item:Nn{\polyglossia@langsetup}{#2/babelname}}% }{% \edef\babelname{\csuse{#2@gbabelname}}% }% }{% \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}}% }% \@select@language[#1]{#2}% % Write to the aux \xpg@set@language@only@aux[#1]{#2}% } \newcommand*{\xpg@set@language@only@aux}[2][]{% % Write to the aux \if@filesw% \ifx#1\\\\% \protected@write\@auxout{}{\protect\selectlanguage*{#2}}% \addtocontents{toc}{\protect\selectlanguage*{#2}}% \addtocontents{lof}{\protect\selectlanguage*{#2}}% \addtocontents{lot}{\protect\selectlanguage*{#2}}% \else \protected@write\@auxout{}{\protect\selectlanguage*[#1]{#2}}% \addtocontents{toc}{\protect\selectlanguage*[#1]{#2}}% \addtocontents{lof}{\protect\selectlanguage*[#1]{#2}}% \addtocontents{lot}{\protect\selectlanguage*[#1]{#2}}% \fi \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!}}% }{}% } % check if language is defined \prg_set_conditional:Npnn \__xpg_check_if_exist_l@:N #1 { p , T , F , TF }{ \cs_if_exist:cTF {l@#1} { \cs_if_eq:cNTF {l@#1} \l@nohyphenation { \prg_return_false: } { % it's possible that sometimes \csname l@#1\endcsname becomes \relax \cs_if_eq:cNTF {l@#1} \relax { \prg_return_false: } { \prg_return_true: } } } { \prg_return_false: } } \def\polyglossia@luatex@load@lang#1{% % if \l@#1 is not properly defined, call lua function newloader(#1), % and assign the returned number to \l@#1 \__xpg_check_if_exist_l@:NF {#1} { \expandafter\chardef\csname l@#1\endcsname= \directlua{ tex.sprint(polyglossia.newloader'#1') }\relax } } % This check is also used by biblatex, so don't % rename silently. \newcommand\xpg@ifdefined[3]{% % With luatex, we first need to define \l@#1. \sys_if_engine_luatex:T { \polyglossia@luatex@load@lang{#1}% } \__xpg_check_if_exist_l@:NTF{#1}{#2}{#3}% }% % Set \bbl@hyphendata@\the\language, which is (lua)babel's % hyphenation pattern hook % FIXME Clarifiy why/when this is needed. \newcommand*\xpg@set@bbl@hyphendata[1]{% \sys_if_engine_luatex:T { \ifcsdef{bbl@hyphendata@#1}{}{% \global\@namedef{bbl@hyphendata@\the\language}{}% }% } } % Set hyphenation patterns for a given language. This does the right % thing both for XeTeX and LuaTeX \newcommand*\xpg@set@hyphenation@patterns[1]{% \str_case_e:nnF{\c_sys_engine_str}{ {luatex} { \polyglossia@luatex@load@lang{#1}% \language=\csname l@#1\endcsname } {xetex} { \language=\csname l@#1\endcsname } } { \xpg@warning{You’re~running~a~TeX~engine~that~is~not~LuaTeX~or~XeTeX.\MessageBreak That~is~almost~guaranteed~to~cause~problems.}% } } \newcommand*\@select@language[2][]{ % hook for compatibility with biblatex \select@language{#2} \xpg@set@bbl@hyphendata{\the\language} \xpg@initial@setup% \select@@language[#1]{#2}% % Hook for external packages such as biblatex \polyglossia@language@switched% \polyglossia@lang@setpardirection:n{#2}% \csuse{captions#2}% \csuse{date#2}% % These are hooks for external packages which want to access variants % via babelname (such as biblatex) \cs_if_exist_use:c{captions@bbl@\babelname}% \cs_if_exist_use:c{date@bbl@\babelname}% \polyglossia@local@marks:n{#2}% \csuse{init@extras@#2}% \polyglossia@lang@indentfirst:n{#2}% \csuse{blockextras@#2}% % This is a hook for external packages which want to access variants % via babelname (such as biblatex) \cs_if_exist_use:c{blockextras@bbl@\babelname}% } % hook for compatibility with biblatex % (probably no longer used due to the % more general hook that follows, but % we keep it for backwards comp.) \def\select@language#1{} % Hook for external packages such as biblatex \def\polyglossia@language@switched{} % remove all custumization for language #1 \cs_new:Npn \noextrascurrent #1 {% \cs_if_exist_use:c{noextras@#1}% % This is a hook for external packages which want to access variants % via babelname (such as biblatex) \cs_if_exist_use:c{noextras@bbl@\babelname} } % Common code for `\select@language' and `\foreignlanguage'. \newcommand{\select@@language}[2][]{% % disable the extras and number settings of the previous language \cs_if_exist:cT{languagename} {% \noextrascurrent{\languagename}% \cs_if_exist_use:c{no\languagename @numbers}% \sys_if_engine_xetex:T{ \__xpg_if_LR_str:eTF{\prop_item:Ne{\polyglossia@langsetup}{\languagename/direction}} { \__xpg_if_LR_str:eF{\prop_item:Nn{\polyglossia@langsetup}{#2/direction}} {\setnonlatin}% LTR -> RTL }% {% \__xpg_if_LR_str:eT{\prop_item:Nn{\polyglossia@langsetup}{#2/direction}} {\setlatin}% RTL -> LTR } } }% \polyglossia@set@language@name[#1]{#2}% % Set the language's/script's font families \str_if_eq:eeTF{\prop_item:Nn{\polyglossia@langsetup}{#2/lcscript}} {latin} { \resetfontlatin } { \xpg@set@normalfont{#2} }% \xpg@select@fontfamily{#2}% \__xpg_use_or_warn:c{#2@language}% \cs_if_exist_use:c{#2@numbers}% \use@localhyphenmins[#1]{#2}% \polyglossia@lang@frenchspacing:n{#2} } \let\xpg@pop@language\relax \provideenvironment{otherlanguage}{}{} % % Keep track of the active (nested) languages and options % \clist_new:N \l_xpg_lang_stack \cs_new:Nn \polyglossia@stack@language:nn { \clist_push:Nn \l_xpg_lang_stack {#1:#2} } \cs_generate_variant:Nn \seq_set_split:Nnn {Nnx} \cs_new:Nn \polyglossia@unstack@language:n { \clist_gpop:NNTF \l_xpg_lang_stack \l_tmpa_tl { % Stored format = options:language => split: \seq_set_split:Nnx \l_tmpa_seq {:} \l_tmpa_tl \seq_get_left:NN \l_tmpa_seq \l_tmpb_tl \seq_get_right:NN \l_tmpa_seq \l_tmpc_tl % Execute passed command with language and maybe options \tl_if_empty:NTF \l_tmpb_tl {\cs_if_exist_use:c{#1}{\l_tmpc_tl}} {\cs_if_exist_use:c{#1}[\l_tmpb_tl]{\l_tmpc_tl}} } {} } \renewenvironment{otherlanguage}[2][] {% % Get real current options (incl. defaults) \clist_clear_new:N \l_xpg_current_options \prop_map_inline:cn {xpg@current@options@#2} { \clist_put_right:Nn \l_xpg_current_options {##1=##2} } % Store current options and language on stack \polyglossia@stack@language:nn{\clist_use:Nn \l_xpg_current_options {,}}{#2}% \selectlanguage[#1]{#2}% } {% % restore previous language in aux file and remove closed one from stack \polyglossia@unstack@language:n{xpg@set@language@only@aux}% } \newcommand{\setlocalhyphenmins}[3]{% \xpg@ifdefined{#1}{% \expandafter\ifx\csname l@#1\endcsname\l@nohyphenation% \xpg@warning{\string\setlocalhyphenmin\space~ useless~ for~ unhyphenated~ language~ #1}% \else \providehyphenmins{#1}{#2#3}% \fi }{% \xpg@warning{\string\setlocalhyphenmin\space~ useless~ for~ unknown~ language~ #1}% }% }% % \setlanghyphenmins[options]{lang}{l}{r} \newcommand*\setlanghyphenmins[4][]{% % Check for real language name and options \edef\xpg@tmp@opts{\xpg_alias_add_to_option_i:nn{#2}{#1}} \edef\xpg@tmp@lang{\xpg_alias_base_lang:n{#2}} \bgroup \polyglossia@error@iflangnotloaded:n{\xpg@tmp@lang} \exp_args:Nne \setkeys{\xpg@tmp@lang}{\xpg@tmp@opts}% % Store BCP-47 id of language \tl_if_blank:nTF {\xpg@tmp@opts}{% \ifcsundef{\csname xpg@tmp@lang\endcsname @gbcp47id}{% \csedef{tmp@bcp47id}{\prop_item:Ne{\polyglossia@langsetup}{\xpg@tmp@lang /bcp47}}% }{% \csedef{tmp@bcp47id}{\csuse{#2@gbcp47id}}% }% }{% \csedef{tmp@bcp47id}{\prop_item:Ne{\polyglossia@langsetup}{\xpg@tmp@lang /bcp47}}% }% \xpg@warning{id: \csuse{tmp@bcp47id}}% \csgdef{\csname tmp@bcp47id\endcsname @hyphenmins}{{#3}{#4}}% \egroup } % \use@localhypenmins[options]{lang} \newcommand*\use@localhyphenmins[2][]{% \bgroup \polyglossia@error@iflangnotloaded:n{#2} \setkeys{#2}{#1}% % Store BCP-47 id of language \tl_if_blank:nTF {#1}{% \ifcsundef{#2@gbcp47id}{% \csxdef{tmp@bcp47id}{\prop_item:Nn{\polyglossia@langsetup}{#2/bcp47}}% }{% \csxdef{tmp@bcp47id}{\csuse{#2@gbcp47id}}% }% }{% \csxdef{tmp@bcp47id}{\prop_item:Nn{\polyglossia@langsetup}{#2/bcp47}}% }% \egroup \ifcsundef{\csname tmp@bcp47id\endcsname @hyphenmins}{% \ifcsundef{#2hyphenmins}{}% {% \expandafter\expandafter\expandafter\set@hyphenmins\csname #2hyphenmins\endcsname\relax% } }{% \edef\tmpa{\csuse{\csname tmp@bcp47id\endcsname @hyphenmins}}% \expandafter\expandafter\expandafter\set@hyphenmins\tmpa\relax% } \sys_if_engine_luatex:T{ % Set \totalhyphenmin if specified \prop_get:NxNTF \polyglossia@langsetup {#2/totalhyphenmin} \l_tmpa_tl { \xpg@info{totalhyphenmin: '\l_tmpa_tl'} \expandafter\hyphenationmin \l_tmpa_tl% }% {}% } } % Babel previously compiled in hyphenrules into the kernel (via hyphen.cfg) % but this is no longer the case. In any case, we roll our own one now % and possibly overwrite babel's. \provideenvironment{hyphenrules}{}{} % As opposed to the one inherited from switch.def/babel, our environment % supports language options and aliases. \renewenvironment{hyphenrules}[2][] {% % Check for real language name and options \edef\xpg@tmp@opts{\xpg_alias_add_to_option_i:nn{#2}{#1}} \edef\xpg@tmp@lang{\xpg_alias_base_lang:n{#2}} % Register the language options \polyglossia@set@lang@options:nnn {\xpg@tmp@lang} {\xpg@tmp@opts} {@xpg@set@langvariant}% % Now switch patterns \__xpg_use_or_warn:c{\use:c{xpg@tmp@lang}@language}% % And activate hyphenmins \use@localhyphenmins[\xpg@tmp@opts]{\xpg@tmp@lang}% } {} \AtEndPreamble{% \@ifpackageloaded{bidi}{% \providecommand*{\aemph}[1]{$\overline{\hboxR{#1}}$}% }{}% \@ifpackageloaded{luabidi}{% \providecommand*{\aemph}[1]{$\overline{\hbox{\RL{#1}}}$}% }{}% } % keys for main package \keys_define:nn { polyglossia } { verbose .bool_set:N = \l_polyglossia_verbose_bool, verbose .default:n = true, % compatibility quiet .meta:n = { verbose = false }, localmarks .bool_set:N = \l_polyglossia_localmarks_bool, localmarks .default:n = true, % compatibility nolocalmarks .meta:n = { localmarks = false }, babelshorthands .bool_set:N = \l_polyglossia_babelshorthands_bool, babelshorthands .default:n = true, luatexrenderer .cs_set:Np = \l_polyglossia_luatex_renderer, luatexrenderer .value_required:n = true, } \keys_set:nn { polyglossia } { localmarks = false, verbose = true, babelshorthands = false, luatexrenderer = Harfbuzz } % load by default latex \setmainlanguage{latex} % then process key in order to overwrite \ProcessKeysOptions{polyglossia} % Set the LuaTeX renderer. As opposed to fontspec, we use Harfbuzz by default. % This can be changed via the luatexrenderer package option. \sys_if_engine_luatex:T{ \str_if_eq:eeF{\l_polyglossia_luatex_renderer}{none} { \xpg@info{Setting~ LuaTeX~ font~ renderer~ to~ \l_polyglossia_luatex_renderer} \exp_args:Ne \defaultfontfeatures{Renderer=\l_polyglossia_luatex_renderer} } } \bool_if:nF \l_polyglossia_verbose_bool { \gdef\@latex@info#1{\relax}% no latex info \gdef\@font@info#1{\relax}% no latex font info \gdef\@font@warning#1{\relax}% no latex font warnings \gdef\zf@PackageInfo#1{\relax}% no fontspec info \gdef\xpg@info#1{\relax}% no polyglossia info } \bool_if:nT \l_polyglossia_localmarks_bool { \polyglossia@enable@local@marks: } % compatibility \newif\ifsystem@babelshorthands \bool_if:nTF \l_polyglossia_babelshorthands_bool { \system@babelshorthandstrue }{ \system@babelshorthandsfalse } % % FIXME these should also be loaded \AtEndOfPackage !!! \def\xpg@option#1#2{% \ifcsundef{xpg@main@language}{\setdefaultlanguage}{\setotherlanguage}% [#1]{#2}} \ExplSyntaxOff \endinput