\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{polyglossia}[2021/04/12 v1.53
  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
\newcommand\xpg@at@package[3]{%
    \@ifpackageloaded{#1}{#3}{\AddToHook{#2}{#3}}%
}

% correct a bug in tracklang
\xpg@at@package{tracklang}{file/after/tracklang.sty}{%
  \@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
\providecommand\texorpdfstring[2]{#1}% dummy command if hyperref is not loaded

\ifluatex
  \RequirePackage{luatexbase} % already included by fontspec, but needed here
  \RequireLuaModule{polyglossia}
\fi

% 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
\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}
\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
{
  \cs_if_exist:cF{#1@loaded}
  {
    \xpg@error{language~ #1~ is~ not~ loaded.~ Please~ load~ it~ before~ using~ it.}
  }
}


% error do not use directly the gloss file
\msg_new:nnn { polyglossia } { directloadgloss }
{
  You~ should~ not~ load~ directly~ the~ gloss~ file~ using~ `\string\usepackage'.
  You~ must~ use~ `\string\setotherlanguage\{#1\}' or  `\string\setmainlanguage\{#1\}'.
}
\msg_redirect_name:nnn { polyglossia } { directloadgloss } { critical }

%% use macro if defined, else warn that it is not
\def\csuse@warn#1{%
   \ifcsundef{#1}{\xpg@warning{ \expandafter\string\csname #1\endcsname\space is~ not~ defined}}%
   {\csname #1\endcsname}}

%% 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.}
  }
}

% (lua)bidi commands to change directionality for paragraphs
% and inline text.
% overwritten with correct package
\cs_new_nopar:Nn{\polyglossia@setpardirection:n}{%
  \str_case_e:nnTF{#1}{%
       {LR}{\relax}%
       {RL}{\xpg@error{right-to-left,~ but~ (lua)bidi~ package~ was~ not~ loaded!}}%
     }%
     {}%
     {\xpg@error{Unknown~ language~ direction~ #1 ~(base~ wrapper)}}%
}
\cs_new_nopar:Nn{\polyglossia@settextdirection:n}{%
  \str_case_e:nnTF{#1}{%
       {LR}{\relax}%
       {RL}{\xpg@error{right-to-left,~ but~ (lua)bidi~ package~ was~ not~ loaded!}}%
     }%
     {}%
     {\xpg@error{Unknown~ language~ direction~ #1 ~(base~ wrapper)}}%
}
\xpg@at@package{bidi}{package/after/bidi}{%
  \ExplSyntaxOn%
  \cs_gset_nopar:Nn{\polyglossia@setpardirection:n}{%
    \str_case_e:nnTF{#1}{%
        {LR}{\setLR}%
        {RL}{\setRL}%
      }%
      {}%
      {\xpg@error{Unknown~ language~ direction~ #1 ~(bidi~ wrapper)}}%
  }%
  \cs_gset_nopar:Nn{\polyglossia@settextdirection:n}{%
    \str_case_e:nnTF{#1}{%
        {LR}{\LRE}%
        {RL}{\RLE}%
      }%
      {}%
      {\xpg@error{Unknown~ language~ direction~ #1 ~(bidi~ wrapper)}}%
  }%
  \ExplSyntaxOff%
}
\xpg@at@package{luabidi}{package/after/luabidi}{%
  \ExplSyntaxOn%
  \cs_gset_nopar:Nn{\polyglossia@setpardirection:n}{%
    \str_case_e:nnTF{#1}{%
        {LR}{\setLR}%
        {RL}{\setRL}%
      }
      {}%
      {\xpg@error{Unknown~ language~ direction~ #1 ~(luabidi~ wrapper)}}%
  }%
  \cs_gset_nopar:Nn{\polyglossia@settextdirection:n}{%
    \str_case_e:nnTF{#1}{%
        {LR}{\LRE}%
        {RL}{\RLE}%
      }
      {}%
      {\xpg@error{Unknown~ language~ direction~ #1 ~(luabidi~ wrapper)}}%
  }%
  \ExplSyntaxOff%
}

%% 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 = {<alph_csname>,<Alph_csname>}
%% TODO: localnumeral = <csname>
%%       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}}%
}

% 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 {
  \exp_args:Nne \clist_set:Nn{\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
       \polyglossia@check@ifdefined: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
  \exp_args:NNe \clist_set:Nn \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}
  }
}

% 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}}
\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}}
      }}%
  \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}}
      }}%
  \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}}
      }}%
  \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
}{}

\ifxetex
%% when no patterns are available, we use \l@nohyphenation, assigned to 255
%%  (suggestion by Enrico Gregorio)
  \@ifundefined{l@nohyphenation}{\chardef\l@nohyphenation=255 }{}
\else\ifluatex
  \@ifundefined{l@nohyphenation}{\chardef\l@nohyphenation=\directlua{
    tex.sprint(polyglossia.newloader_loaded_languages.nohyphenation)}\relax
  }{}
\fi\fi

%we call this macro when a gloss file is not found for a given language
\def\xpg@nogloss#1{%
   \xpg@warning{File~ gloss-#1.ldf~ does~ not~ exist!\MessageBreak
   I~ will~ nevertheless~ try~ to~ use~ hyphenation~ patterns~ for~ #1.}%
  \PolyglossiaSetup{#1}{hyphenmins,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%
}

% try to load a language file
\cs_new:Nn \polyglossia_load_lang_definition:nn {
  \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}
  }
}

% 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}%
   }{}
   \polyglossia@register@language:nn{}{#1}%
   \csgdef{#1@loaded}{}%
}


% define environment and command
\cs_new:Nn \polyglossia@define@language@cmd:n {
  \ifcsundef{#1@alias@lang}{%
    \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[##1]{#1}{##2}%
    }%
  }{}
}

% provide way to define alias environment and command
% \setlanguagealias[<options>]{<language>}{<alias>}
\DeclareDocumentCommand \setlanguagealias {s O{} m m}
{
  % The starred version does not define commands and environments
  \IfBooleanF {#1}
    {
     \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}}%
}

\cs_new:Nn \polyglossia@register@language:nn {
   % register polyglossia language name
   \ifcsundef{#2@registered}{%
       \global\edef\xpg@loaded{%
           \ifx\xpg@loaded\@empty\else\xpg@loaded,\fi #2%
        }%
   }{}
   \csgdef{#2@registered}{}%
   \tl_if_blank:nF {#1}{%
      % Register the language options
      \polyglossia@set@lang@options:nn {#2} {#1}%
   }%
   % register babelname
   \def\xpg@tmp@babelname{\prop_item:Nn{\polyglossia@langsetup}{#2/babelname}}%
   \ifcsundef{\csname xpg@tmp@babelname\endcsname @bbl@registered}{%
       \global\edef\xpg@bloaded{%
           \ifx\xpg@bloaded\@empty\else\xpg@bloaded,\fi\xpg@tmp@babelname}%
   }{}%
   \csgdef{\csname xpg@tmp@babelname\endcsname @bbl@registered}{}%
   % register BCP-47 ID
   \def\xpg@tmp@bcpname{\prop_item:Nn{\polyglossia@langsetup}{#2/bcp47}}%
   \ifcsundef{\csname xpg@tmp@bcpname\endcsname @bcp@registered}{%
       \global\edef\xpg@bcp@loaded{%
           \ifx\xpg@bcp@loaded\@empty\else\xpg@bcp@loaded,\fi\xpg@tmp@bcpname}%
   }{}%
   \csgdef{\csname xpg@tmp@bcpname\endcsname @bcp@registered}{}%
}


\newcommand{\setdefaultlanguage}[2][]{%
  % latex is an internal language, so do not record
  \ifstrequal{#2}{latex}{}{%
     % register polyglossia language name
     \ifcsundef{#2@registered}{%
       \global\edef\xpg@loaded{%
           \ifx\xpg@loaded\@empty\else\xpg@loaded,\fi #2%
        }%
     }{}%
     \csgdef{#2@registered}{}%
  }%
  \ifcsundef{#2@loaded}%
  {
    \polyglossia_load_lang_definition:nn{#1}{#2}
    % define environment and command (except for internal latex language)
    \ifstrequal{#2}{latex}{}{%
      \exp_args:Nx\polyglossia@define@language@cmd:n{#2}
    }%
    \csgdef{#2@loaded}{}%
  }
  {
    \relax
  }
  \ifcsdef{#2@alias@lang}{%
     \ifcsdef{#2@alias@opts}{%
       \exp_args:Nxx \polyglossia_load_lang_definition:nn {\csuse{#2@alias@opts},#1} {\csuse{#2@alias@lang}}%
       \exp_args:Nxx \polyglossia@set@default@language:nn {\csuse{#2@alias@opts},#1} {\csuse{#2@alias@lang}}%
     }{%
       \polyglossia@set@default@language:nn {#1} {\csuse{#2@alias@lang}}%
     }%
  }{%
    \polyglossia@set@default@language:nn {#1} {#2}%
  }%
}

\cs_new:Nn \polyglossia@set@default@language:nn
{
  \gdef\xpg@main@language{#2}%
  \tl_if_blank:nTF {#1}{\gdef\mainlanguagevariant{}}{%
     % 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
  % this tells bidi.sty or luabidi.sty that the document is RTL
  \str_if_eq:eeTF{\prop_item:Nn{\polyglossia@langsetup}{#2/direction}}{RL}{%
    \str_case_e:nnF{\c_sys_engine_str}{%
      {luatex}{\setRTLmain}
      {xetex}{\@RTLmaintrue\setnonlatin}
    }{}%
  }{}%
  \cs_gset_nopar:Nn \polyglossia@AtBeginDocument@selectlanguage: {
    \selectbackgroundlanguage{#2}
    \selectlanguage[#1]{#2}%
  }
  \xpg@info{Default~ language~ is~ #2}%
  \polyglossia@set@language@name[#1]{#2}%
  \def\mainlanguagename{#2}
  % Store babelname of main language (for external packages such as biblatex)
  \prop_get:NxNT \polyglossia@langsetup {#2/babelname} \l_tmpa_tl
      { \edef\mainbabelname{\l_tmpa_tl} }
  % 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}% 
        \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}')}%
  \fi %
}

\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
\define@key{xpg@main@langvariant}{variant}{%
  \gdef\mainlanguagevariant{#1}%
}

\def\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:nn {#2} {#1}%
  }%
}


\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}
  \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}%
  \str_if_eq:eeTF{\prop_item:Nn{\polyglossia@langsetup}{#2/direction}}{RL}{\@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}}%
  }%
}

% 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 \<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)
\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 \<xx>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
    \csuse@warn{#1@font@tt}%
  \else\ifx\familytype\tmp@sf
    \csuse@warn{#1@font@sf}%
      \else\csuse@warn{#1@font@rm}\fi\fi}

\def\xpg@set@normalfont#1{%
  \DeclareRobustCommand\rmfamily{\csuse{#1@font@rm}}%
  \DeclareRobustCommand\sffamily{\csuse{#1@font@sf}}%
  \DeclareRobustCommand\ttfamily{\csuse{#1@font@tt}}%
  \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%
}

\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}%
}

\newcommand{\setotherlanguage}[2][]{%
  \ifcsundef{#2@loaded}
  {
    \polyglossia_load_lang_definition:nn{#1}{#2}
    % define environment and command
    \exp_args:Nx\polyglossia@define@language@cmd:n{#2}
    \ifcsdef{#2@alias@lang}{%
       \ifcsdef{#2@alias@opts}{%
         \exp_args:Nxx \polyglossia_load_lang_definition:nn {\csuse{#2@alias@opts},#1} {\csuse{#2@alias@lang}}%
         \exp_args:Nxx \polyglossia@set@other@language:nn {\csuse{#2@alias@opts},#1} {\csuse{#2@alias@lang}}%
       }{%
         \polyglossia@set@other@language:nn {#1} {\csuse{#2@alias@lang}}%
       }%
    }{%
      \polyglossia@set@other@language:nn {#1} {#2}%
    }%
    \csgdef{#2@loaded}{}%
  }
  {}
}

\cs_new:Nn \polyglossia@set@other@language:nn
{
  \polyglossia@register@language:nn{#1}{#2}%
  % If a variant is set, store it.
  \gdef\otherlanguagevariant{}
  \tl_if_blank:nTF {#1}{}{%
    % 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} }
  \cs_gset_eq:cc{#2@gbabelname}{otherlanguagebabelname}%
}

% 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<lang>, but more suitable
% for specific (esp. tag-based) aliases
% where \text<alias> would cause clashes
% (e.g., \textit)
\newcommand\textlang[3][]{%
  \ifcsdef{#2@alias@lang}{%
     \ifcsdef{#2@alias@opts}{%
       \exp_args:Nxx \xpg@textlanguage[\csuse{#2@alias@opts},#1]{\csuse{#2@alias@lang}}{#3}%
     }{%
       \xpg@textlanguage[#1]{\csuse{#2@alias@lang}}{#3}%
     }%
  }{%
    \xpg@textlanguage[#1]{#2}{#3}%
  }%
}%

% 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*
\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<lang>
\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][]
{%
  \ifcsdef{#2@alias@lang}{%
     \ifcsdef{#2@alias@opts}{%
       \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}%
     }%
  }{%
    \polyglossia@foreignlanguage:nnn {#1} {#2} {#3}%
  }%
}

\cs_new:Nn \polyglossia@foreignlanguage:nnn
{
   \polyglossia@error@iflangnotloaded:n{#2}
   \bgroup
   \xpg@otherlanguage[#1]{#2}%
   \polyglossia@lang@settextdirection:nn{#2}{#3}%
   \egroup
}

% otherlanguage* is the environment equivalent of \foreignlanguage
\expandafter\providecommand\csname otherlanguage*\endcsname{}

\renewenvironment{otherlanguage*}[2][]
{%
  \ifcsdef{#2@alias@lang}{%
     \ifcsdef{#2@alias@opts}{%
       \exp_args:Nxx \polyglossia@otherlanguage:nn {\csuse{#2@alias@opts},#1} {\csuse{#2@alias@lang}}%
     }{%
       \polyglossia@otherlanguage:nn {#1} {\csuse{#2@alias@lang}}%
     }%
  }{%
    \polyglossia@otherlanguage:nn {#1} {#2}%
  }%
}
{\egroup}

\cs_new:Nn \polyglossia@otherlanguage:nn
{
  \xpg@otherlanguage[#1]{#2}%
  \polyglossia@lang@settextdirection:nn{#2}\bgroup%
}

% use by \text<lang> and \textlang. Equivalent to \foreignlanguage,
% except that dates are localized.
\newcommand\xpg@textlanguage[3][]{%
  \polyglossia@error@iflangnotloaded:n{#2}
   \bgroup
   \xpg@otherlanguage[#1]{#2}%
   \csuse{date#2}%
   % 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{#2}{#3}%
   \egroup
  % Reset the language's/script's font families
  \str_if_eq:eeTF{\prop_item:Nn{\polyglossia@langsetup}{#2/lcscript}}{latin}{}{\resetfontlatin}%
}


% 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}
{%
  \ifcsdef{#3@alias@lang}{%
     \ifcsdef{#3@alias@opts}{%
       \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}}%
     }%
  }{%
     \polyglossia@error@iflangnotloaded:n{#3}%
     \polyglossia@select@language:nnn {#1} {#2} {#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
    }
  \tl_if_blank:nTF {#2}{}{%
    % Register the language options
    \polyglossia@set@lang@options:nn {#3} {#2}%
   }%
   % The starred variant does not write to the aux
   \IfBooleanTF#1{%
     \xpg@set@language@nonaux[#2]{#3}%
   }{%
     \xpg@set@language@aux[#2]{#3}%
   }%
   \ifluatex%
     \directlua{polyglossia.select_language('\luatexluaescapestring{\string#3}',
                     \the\csname l@#3\endcsname)}%
   \fi%
  \polyglossia@register@language:nn{#2}{#3}%
}


\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}{%
  \edef\xpg@vloaded{#1\ifx\xpg@vloaded\@empty\else,\xpg@vloaded\fi}%
}

\prg_set_conditional:Npnn \polyglossia@check@if@lang@loaded:N #1 { p , T , F , TF }{
  \cs_if_exist:cTF{#1}{
     \prg_return_true:
  }{
    \prg_return_false:
  }
}

% Test if language is loaded
\newcommand*\iflanguageloaded[3]{%
  \polyglossia@check@if@lang@loaded:NTF{#1@loaded}{#2}{#3}%
}

% Same for babellanguage is loaded
\newcommand*\ifbabellanguageloaded[3]{%
  \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}%
}


\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
   \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!}}%
  }{}%
}

% Open a group in the aux file. This is to keep
% 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%
      \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.
% In bidi RTL tables, the opening/closing needs
% to be swapped (see #354).
\newcommand*{\xpg@unset@group@aux}{%
   \if@filesw%
      \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
}

\prg_set_conditional:Npnn \polyglossia@check@ifdefined: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
  \polyglossia@check@ifdefined: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.
    \ifluatex
      \polyglossia@luatex@load@lang{#1}%
    \fi
    \polyglossia@check@ifdefined: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]{%
    \ifluatex%
        \ifcsdef{bbl@hyphendata@#1}{}{%
            \global\@namedef{bbl@hyphendata@\the\language}{}%
        }%
    \fi% 
}

% Set hyphenation patterns for a given language. This does the right
% thing both for XeTeX and LuaTeX
\newcommand*\xpg@set@hyphenation@patterns[1]{%
  \ifluatex
    \polyglossia@luatex@load@lang{#1}%
    \language=\csname l@#1\endcsname
  \else
    \ifxetex
      \language=\csname l@#1\endcsname
    \else
      \xpg@warning{You’re~running~a~TeX~engine~that~is~not~LuaTeX~or~XeTeX.\MessageBreak
        That~is~almost~guaranteed~to~cause~problems.}%
    \fi
  \fi
}


\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{}

\def\noextrascurrent#1{%
   \csuse{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
  \ifcsundef{languagename}{}{%
     \noextrascurrent{\languagename}%
     \csuse{no\languagename @numbers}%
     \ifxetex
        \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
                  {\setlatin}% RTL -> LTR
            }{%
               \str_if_eq:eeTF{\prop_item:Nn{\polyglossia@langsetup}{#2/direction}}{RL}%
                  {\setnonlatin}% LTR -> RTL
                  {}% LTR -> LTR
           }%
     \fi
  }%
  \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}%
  \csuse@warn{#2@language}%
  \csuse{#2@numbers}%
  \use@localhyphenmins[#1]{#2}%
  \polyglossia@lang@frenchspacing:n{#2}
}


\let\xpg@pop@language\relax

\provideenvironment{otherlanguage}{}{}

\newbool{xpg@noset@groups}
\renewenvironment{otherlanguage}[2][]
{%
  % 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}%
}
{\ifbool{xpg@noset@groups}{}{\xpg@unset@group@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@lang{#2}%
  \edef\xpg@tmp@opts{#1}%
  \ifcsdef{#2@alias@lang}{%
     \edef\xpg@tmp@lang{\csuse{#2@alias@lang}}%
     \ifcsdef{#2@alias@opts}{%
       \edef\xpg@tmp@opts{\csuse{#2@alias@opts},#1}%
     }{}%
  }{}%
  \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}{\exp_args:Nne\prop_item:Nn{\polyglossia@langsetup}{\xpg@tmp@lang /bcp47}}%
    }{%
       \csedef{tmp@bcp47id}{\csuse{#2@gbcp47id}}%
    }%
  }{%
    \csedef{tmp@bcp47id}{\exp_args:Nne \prop_item:Nn{\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%
   }
   \ifluatex
     % Set \totalhyphenmin if specified
     \prop_get:NxNTF \polyglossia@langsetup {#2/totalhyphenmin} \l_tmpa_tl
     {
        \xpg@warning{totalhyphenmin: '\l_tmpa_tl'}
        \expandafter\hyphenationmin \l_tmpa_tl%
     }%
     {}%
   \fi
}

% 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][]
{%
  % 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}%
  % Check for real language name and options
  \edef\xpg@tmp@lang{#2}%
  \edef\xpg@tmp@opts{#1}%
  \ifcsdef{#2@alias@lang}{%
     \edef\xpg@tmp@lang{\csuse{#2@alias@lang}}%
     \ifcsdef{#2@alias@opts}{%
       \edef\xpg@tmp@opts{\csuse{#2@alias@opts},#1}%
     }{}%
  }{}%
  \tl_if_blank:nF {\xpg@tmp@opts}{%
     % Register the language options
     \polyglossia@set@lang@options:nn {\xpg@tmp@lang} {\xpg@tmp@opts}%
  }%
  % Now switch patterns
  \csuse@warn{\csuse{xpg@tmp@lang}@language}%
  % And activate hyphenmins
  \use@localhyphenmins[\xpg@tmp@opts]{\xpg@tmp@lang}%
}
{\ifbool{xpg@noset@groups}{}{\xpg@unset@group@aux}}

\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.
\ifluatex
  \exp_args:Nee \str_if_eq:nnF{\l_polyglossia_luatex_renderer}{none}
     {
         \xpg@info{Setting~ LuaTeX~ font~ renderer~ to~ \l_polyglossia_luatex_renderer}
         \exp_args:Nee \defaultfontfeatures{Renderer=\l_polyglossia_luatex_renderer}
     }
\fi

\bool_if:nTF \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:nTF \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
