%D \module
%D   [       file=lang-ini,
%D        version=1996.01.25,
%D          title=\CONTEXT\ Language Macros,
%D       subtitle=Initialization,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

% \cldcontext{languages.numbers[tex.count.mainlanguagenumber]}

%D This module implements multi||language support of \CONTEXT, which should not be
%D confused with the multi||lingual interface. This support will be extended when
%D needed. Properties of languages are defined in \TEX\ files as well as \LUA\
%D files.

\writestatus{loading}{ConTeXt Language Macros / Initialization}

\registerctxluafile{lang-ini}{autosuffix}
\registerctxluafile{lang-def}{}
\registerctxluafile{lang-cnt}{}

\unprotect

\ifdefined\nonfrenchspacing\else \let\nonfrenchspacing\relax \fi
\ifdefined\frenchspacing   \else \let\frenchspacing   \relax \fi

%D When loading hyphenation patterns, \TEX\ assign a number to each loaded table,
%D starting with~0. Switching to a specific table is done by assigning the relevant
%D number to the predefined \COUNTER\ \type {\language}. However, in \MKIV\ a lot
%D of management is delegated to \LUA.

%D We keep track of the last loaded patterns by means of a pseudo \COUNTER. This
%D just one of those situations in which we don't want to spent a real one. Language
%D zero has no patterns, first of all because I like to start numbering at one. It
%D may come in handy for special purposes as well.

\normallanguage\zerocount

%D \macros
%D   {currentlanguage, setupcurrentlanguage}
%D
%D Instead of numbers,we are going to use symbolic names for the languages. The
%D current langage is saved in the macro \type {\currentlanguage}. The setup macro
%D is mainly used for cosmetic purposes.
%D
%D \starttyping
%D \dorecurse{3}
%D   {\language[nl]
%D    \startmode[*en] english \stopmode
%D    \startmode[*nl] dutch   \stopmode
%D    \language[en]
%D    \startmode[*en] english \stopmode
%D    \startmode[*nl] dutch   \stopmode}
%D \stoptyping

\mutable\lettonothing\askedlanguage
\mutable\lettonothing\currentlanguage
\mutable\lettonothing\currentmainlanguage

%D \macros
%D   {defaultlanguage,languageparameter,specificlanguageparameter}
%D
%D We don't use the commandhandler here (yet) because we have a rather special
%D fallback mechanism so quite some compatibility testing is needed.

\installcorenamespace{language}
\installcorenamespace{languagelinked}

\mutable\def\currentusedlanguage{\currentlanguage} % no \cdef

\permanent\def\defaultlanguage#1%
  {\ifcsname\??language#1\s!default\endcsname
     \expandafter\defaultlanguage\lastnamedcs
   \else
     #1%
   \fi}

\permanent\def\languageparameter#1%
  {\ifcsname\??language\currentlanguage#1\endcsname
     \lastnamedcs
   \orelse\ifcsname\??language\currentlanguage\s!default\endcsname
     \expandafter\specificlanguageparameter\lastnamedcs{#1}%
   \orelse\ifcsname\??language\s!default#1\endcsname
     \lastnamedcs
   \fi}

\permanent\def\specificlanguageparameter#1#2%
  {\ifcsname\??language#1#2\endcsname
     \lastnamedcs
   \orelse\ifcsname\??language#1\s!default\endcsname
     \expandafter\specificlanguageparameter\lastnamedcs{#2}%
   \orelse\ifcsname\??language\s!default#2\endcsname
     \lastnamedcs
   \fi}

\permanent\def\mainlanguageparameter#1%
  {\ifcsname\??language\currentmainlanguage#1\endcsname
     \lastnamedcs
   \orelse\ifcsname\??language\currentmainlanguage\s!default\endcsname
     \expandafter\specificlanguageparameter\lastnamedcs{#1}%
   \orelse\ifcsname\??language\s!default#1\endcsname
     \lastnamedcs
   \fi}

\aliased\let\usedlanguageparameter\languageparameter

\permanent\def\askedlanguageparameter#1% assumes \currentusedlanguage being set
  {\ifcsname\??language\currentusedlanguage#1\endcsname
     \lastnamedcs
   \orelse\ifcsname\??language\currentusedlanguage\s!default\endcsname
     \expandafter\specificlanguageparameter\lastnamedcs{#1}%
   \orelse\ifcsname\??language\s!default#1\endcsname
     \lastnamedcs
   \fi}

\permanent\protected\def\setusedlanguage#1%
  {\cdef\currentusedlanguage{\reallanguagetag{#1}}%
   \ifempty\currentusedlanguage
     \let\currentusedlanguage  \currentlanguage
     \enforced\let\usedlanguageparameter\languageparameter
   \orelse\ifx\currentusedlanguage\v!global
     \let\currentusedlanguage  \currentmainlanguage
     \enforced\let\usedlanguageparameter\mainlanguageparameter
   \orelse\ifx\currentusedlanguage\v!local
     \let\currentusedlanguage  \currentlanguage
     \enforced\let\usedlanguageparameter\languageparameter
   \else
     \enforced\let\usedlanguageparameter\askedlanguageparameter
   \fi}

\permanent\protected\def\setupcurrentlanguage[#1]%
  {\setcurrentlanguage\currentmainlanguage{#1}}

\permanent\protected\def\setcurrentlanguage#1#2% sets modes: **id (currentmain) *id (current)
  {\edef\p_askedlanguage{#1}% otherwise clash with \askedlanguage
   \ifempty\p_askedlanguage \else
     \ifempty\currentmainlanguage\else\resetsystemmode{\systemmodeprefix\currentmainlanguage}\fi
     \let\currentmainlanguage\p_askedlanguage
     \setsystemmode{\systemmodeprefix\currentmainlanguage}%
   \fi
   \edef\p_askedlanguage{#2}%
   \ifempty\p_askedlanguage \else
     \ifempty\currentlanguage\else\resetsystemmode\currentlanguage\fi
     \let\currentlanguage\p_askedlanguage
     \setsystemmode\currentlanguage
   \fi}

%D The internal macros will be defined later.

%D \macros
%D   {installlanguage}
%D
%D Hyphenation patterns can only be loaded when the format file is prepared. The
%D next macro takes care of this loading. A language is specified with
%D
%D \showsetup{installlanguage}
%D
%D When \type {state} equals \type {start}, both patterns and additional hyphenation
%D specifications are loaded. These files are seached for in the patterns path
%D have names like \type {lang-nl.lua}.
%D
%D The \type {spacing} variable specifies how the spaces after punctuation has to be
%D handled. English is by tradition more tolerant to inter||sentence spacing than
%D other languages.
%D
%D This macro also defines \type {\identifier} as a shortcut switch to the language.
%D Furthermore the command defined as being language specific, are executed. With
%D \type {default} we can default to another language (patterns) at format
%D generation time. Patterns are loaded at runtime.

\newtoks \everysetuplanguage

\aliased\let\installedlanguages\clf_installedlanguages % no need for \clf_

\permanent\protected\def\doifelselanguage#1%
  {\ifcsname\??language#1\c!state\endcsname
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\aliased\let\doiflanguageelse\doifelselanguage

\permanent\def\reallanguagetag#1%
  {\ifcsname\??languagelinked#1\endcsname\lastnamedcs\else#1\fi}

% \language[#1] gave unwanted side effect of loading language specifics

\mutable\lettonothing\currentsetuplanguage

\permanent\tolerant\protected\def\installlanguage[#1]#*[#S#2]%
  {\ifhastok={#2}%
     \doifelselanguage{#1}
       {\getparameters[\??language#1][#2]}
       {\defcsname\??languagelinked#1\endcsname{#1}%
        \getparameters[\??language#1][\c!state=\v!start,#2]%
        \lang_basics_install_indeed{#1}{#1}}%
     \cdef\currentsetuplanguage{#1}%
     \clf_definelanguage{#1}{\specificlanguageparameter{#1}\s!default}%
     \expand\everysetuplanguage
   \else
     \defcsname\??languagelinked#1\endcsname{#2}%
     \clf_setlanguagesynonym{#1}{#2}%
     \lang_basics_install_indeed{#1}{#2}%
  \fi}

\def\lang_basics_install_indeed#1#2%
  {\ifcstok{\specificlanguageparameter{#1}\c!define}\v!no\orelse\ifcsname#1\endcsname\else
     \protected\frozen\instance\defcsname#1\endcsname{\lang_basics_set_current[#2]}%
   \fi}

%D When the second argument is a language identifier, a synonym is created. This
%D feature is present because we used dutch mnemonics in the dutch version, but
%D nowadays conform a standard.

\permanent\protected\def\doifelsepatterns#1%
  {\begingroup % will change
   \lang_basics_set_current[#1]%
   \ifnum\normallanguage>\zerocount
     \endgroup\expandafter\firstoftwoarguments
   \else
     \endgroup\expandafter\secondoftwoarguments
   \fi}

\aliased\let\doifpatternselse\doifelsepatterns

%D \macros
%D   {setuplanguage}
%D
%D Quick and dirty, but useful:
%D
%D \showsetup{setuplanguage}
%D
%D Beware, this command can only be used when a language is installed.

\ifdefined\lang_basics_synchronize \else
    \let\lang_basics_synchronize\relax % be nice for setups till we have one
\fi

\installmacrostack\currentlanguage

\permanent\tolerant\protected\def\setuplanguage[#S#1]#*[#S#2]%
  {\ifarguments
     % only synchronize
   \or
     \let\currentsetuplanguage\currentlanguage
     \getparameters[\??language\currentsetuplanguage][#1]%
     \expand\everysetuplanguage
   \or
     \push_macro_currentlanguage % can be default
     \cdef\currentsetuplanguage{\reallanguagetag{#1}}%
     \getparameters[\??language\currentsetuplanguage][#2]%
     \expand\everysetuplanguage
     \pop_macro_currentlanguage
   \fi
   \lang_basics_synchronize}

\appendtoks
    \clf_unloadlanguage{\currentsetuplanguage}%
\to \everysetuplanguage

\setuplanguage
  [\s!default]
  [\s!patterns=,
   \s!goodies=,
   \s!lefthyphenmin=2,
   \s!righthyphenmin=2,
   \s!lefthyphenchar=-1,
   \s!righthyphenchar=45,
   \s!explicitlefthyphenchar=\languageparameter\s!lefthyphenchar,
   \s!explicitrighthyphenchar=\languageparameter\s!righthyphenchar,
   % used in compound i.e. interfaced with c! and can be anything so no numbers
   \c!lefthyphen=,
   \c!righthyphen=-,
   \c!hyphen=-,
   \s!apostrophe=\v!yes, % Per 2025-11-01 this is enabled by default
   \c!spacing=\v!packed,
   \c!compoundhyphen=\compoundhyphen,
   \c!rightcompoundhyphen=\compoundhyphen,
   \c!leftcompoundhyphen=,
   \c!midsentence=---,
   \c!leftsentence=---,
   \c!rightsentence=---,
   \c!leftsubsentence=---,
   \c!rightsubsentence=---,
   \c!leftquote=\upperleftsinglesixquote,
   \c!rightquote=\upperrightsingleninequote,
   \c!leftquotation=\upperleftdoublesixquote,
   \c!rightquotation=\upperrightdoubleninequote,
   \c!leftspeech=\languageparameter\c!leftquotation,
   \c!middlespeech=,
   \c!rightspeech=\languageparameter\c!rightquotation,
   \c!limittext=\unknown,
   \c!time={h,:,m},
   \c!date={\v!year,\ ,\v!month,\ ,\v!day},
   \c!text=Ag,
   \c!font=] % \v!auto : experimental !

% to be tested:
%
% \setuplanguage
%   [\s!default]
%   [\c!righthyphenchar="AD]

%D The values \type {leftsentence} and \type {rightsentence} can be (and are) used
%D to implement automatic subsentence boundary glyphs, like in {\fr |<|french
%D guillemots|>|} or {\de |<|german guillemots|>|} or {\nl |<|dutch dashes|>|} like
%D situations. Furthermore \type {leftquotation} and \type {leftquote} come into
%D view \quotation {when we quote} or \quote {quote} something.

%D \macros
%D  {currentdatespecification, currenttimespecification}
%D
%D Just to make things easy we can ask for the current date specification by saying:

\permanent\def\currentdatespecification{\languageparameter\c!date}
\permanent\def\currenttimespecification{\languageparameter\c!time}

%D Carefull reading of these macros shows that it's legal to say
%D
%D \starttyping
%D \installlanguage [du] [de]
%D \stoptyping

%D \macros
%D   {language,mainlanguage}
%D
%D Switching to another language (actually another hyphenation pattern) is done
%D with:
%D
%D \starttyping
%D \language[identifier]
%D \stoptyping
%D
%D or with \type {\identifier}. Just to be compatible with \PLAIN\ \TEX, we still
%D support the original meaning, so
%D
%D \starttyping
%D \language=1
%D \stoptyping
%D
%D is a valid operation, where the relation between number and language depends on
%D the order in installing languages.
%D
%D \showsetup{language}
%D \showsetup{mainlanguage}
%D
%D Both commands take a predefined language identifier as argument. We can use \type
%D {\mainlanguage[identifier]} for setting the (indeed) main language. This is the
%D language used for translating labels like {\em figure} and {\em table}. The main
%D language defaults to the current language.

\newtoks \everylanguage

\installcorenamespace{languagenumbers}

\appendtoks
    % we need to reassign the number because new patterns can be defined later on
    % so let's hope not that many \setups happen during a run
    \gletcsname\??languagenumbers\currentlanguage\endcsname\undefined
\to \everysetuplanguage

\def\lang_basics_synchronize_yes
  {\zerocount % see below
   \global\expandafter\chardef\csname\??languagenumbers\currentlanguage\endcsname
      \clf_languagenumber
        {\currentlanguage}%
        {\defaultlanguage\currentlanguage}%
        {\languageparameter\s!patterns}%
        {\languageparameter\s!goodies}%
        {\languageparameter\c!factor}%
      \relax
   \normallanguage\csname\??languagenumbers\currentlanguage\endcsname}

\let\lang_basics_synchronize_nop\zerocount % not loaded anyway

\letcsname\??languagenumbers\endcsname\lang_basics_synchronize_nop % initime

\appendtoks
    \letcsname\??languagenumbers\endcsname\lang_basics_synchronize_yes % runtime
\to \everydump

\def\lang_basics_synchronize
  {\normallanguage\csname\??languagenumbers
     \ifcsname\??languagenumbers\currentlanguage\endcsname
       \currentlanguage
     \fi
   \endcsname
   \relax
   \expand\everylanguage
   \relax}

\newinteger\hyphenstate
\newinteger\hyphenminoffset

% This is the old implementation: a hack that sets the min values, because we want
% to keep the language set:
%
% \protected\def\nohyphens % nicer for url's
%   {\ifrelax\dohyphens
%      \protected\edef\dohyphens
%        {\hyphenminoffset\the\hyphenminoffset\relax
%         \lang_basics_synchronize_min_max}%
%    \fi
%    \hyphenminoffset\plusthousand
%    \lang_basics_synchronize_min_max}
%
% \let\dohyphens\relax

% But this one is nicer because we do keep the language set as well as don't mess
% with the min values (it's more efficient too). We might get some more bits in
% this mode (engine specific).

\exhyphenchar 45 % to permit breaking at explicit hyphens

% \uchyph\plusone :

% \chardef \completehyphenationcode \numexpr
\permanent \integerdef \completehyphenationcode \numexpr
    \normalhyphenationcode            % \discretionary
  + \automatichyphenationcode         % -
  + \explicithyphenationcode          % \-
  + \syllablehyphenationcode          % pattern driven
  + \uppercasehyphenationcode         % replaces \uchyph
  + \compoundhyphenationcode          % replaces \compoundhyphenmode
  % \strictstarthyphenationcode       % replaces \hyphenationbounds (strict = original tex)
  % \strictendhyphenationcode         % replaces \hyphenationbounds (strict = original tex)
  + \automaticpenaltyhyphenationcode  % replaces \hyphenpenaltymode (otherwise use \exhyphenpenalty)
  + \explicitpenaltyhyphenationcode   % replaces \hyphenpenaltymode (otherwise use \exhyphenpenalty)
  + \permitgluehyphenationcode        % turn glue into kern in \discretionary
  + \permitallhyphenationcode         % okay, let's be even more tolerant
  + \permitmathreplacehyphenationcode % and again we're more permissive
  + \forcehandlerhyphenationcode      % kick in the handler (could be an option)
  + \feedbackcompoundhyphenationcode  % feedback compound snippets
  + \ignoreboundshyphenationcode      % just in case we have hyphens at the edges
  + \collapsehyphenationcode          % collapse -- and ---
  + \replaceapostrophehyphenationcode % replace ' by 0x2019
\relax

\permanent \integerdef \partialhyphenationcode \numexpr
    \ignoreboundshyphenationcode      % just in case we have hyphens at the edges
% + \explicithyphenationcode          % \-
  + \collapsehyphenationcode          % collapse -- and ---
  + \replaceapostrophehyphenationcode % replace ' by 0x2019
  + \permitgluehyphenationcode        % turn glue into kern in \discretionary
  + \permitallhyphenationcode         % okay, let's be even more tolerant
\relax

\hccode"002D "002D % hyphen
\hccode"00B7 "00B7 % centered text period (used in some languages)

\permanent\protected\def\keephyphensequences
  {\hccode"2010 \zerocount
   \hccode"2013 \zerocount
   \hccode"2014 \zerocount}

\permanent\protected\def\collapsehyphensequences
  {\hccode"2010 "2010\relax
   \hccode"2013 "2013\relax
   \hccode"2014 "2014\relax}

\collapsehyphensequences

% maybe a (un)setter for handlers

\permanent\protected\def\dohyphens{\hyphenationmode\completehyphenationcode}
\permanent\protected\def\nohyphens{\hyphenationmode\partialhyphenationcode}

\permanent\protected\def\doapostrophes{\hyphenationmode\bitwiseflip\hyphenationmode \replaceapostrophehyphenationcode}
\permanent\protected\def\noapostrophes{\hyphenationmode\bitwiseflip\hyphenationmode-\replaceapostrophehyphenationcode}

% \permanent\protected\def\dohyphens
%   {\ifbitwiseand\hyphenationmode\collapsehyphenationcode
%      \hyphenationmode\completehyphenationcode
%    \else
%      \hyphenationmode\numexpr\completehyphenationcode-\collapsehyphenationcode\relax
%    \fi}

% \permanent\protected\def\nohyphens
%   {\ifbitwiseand\hyphenationmode\collapsehyphenationcode
%      \hyphenationmode\partialhyphenationcode
%    \else
%      \hyphenationmode\numexpr\partialhyphenationcode-\collapsehyphenationcode\relax
%    \fi}

\permanent\protected\def\dohyphencollapsing{\hyphenationmode\bitwiseflip\hyphenationmode \collapsehyphenationcode}
\permanent\protected\def\nohyphencollapsing{\hyphenationmode\bitwiseflip\hyphenationmode-\collapsehyphenationcode}

\permanent\protected\def\doexplicithyphens{\hyphenationmode\bitwiseflip\hyphenationmode \explicithyphenationcode}
\permanent\protected\def\noexplicithyphens{\hyphenationmode\bitwiseflip\hyphenationmode-\explicithyphenationcode}

\permanent\protected\def\usehyphensparameter#1%
  {\ifcstok{#1\c!hyphens}\v!no
     \ifbitwiseand\hyphenationmode\collapsehyphenationcode
       \nohyphens
     \else
       \nohyphens
       \nohyphencollapsing
     \fi
   \fi}

\dohyphens

%D The rest stays the same as in mkiv:

\permanent\protected\def\lesshyphens
  {\advanceby\hyphenminoffset\plusone
   \lang_basics_synchronize_min_max}

\permanent\protected\def\morehyphens
  {\ifcase\hyphenminoffset \else
     \advanceby\hyphenminoffset\minusone
   \fi
   \lang_basics_synchronize_min_max}

% \protected\def\lang_basics_synchronize_min_max % maybe store this at the lua end
%   {% these values are stored along with glyph nodes
%    \lefthyphenmin \numexpr0\languageparameter\s!lefthyphenmin +\hyphenminoffset\relax
%    \righthyphenmin\numexpr0\languageparameter\s!righthyphenmin+\hyphenminoffset\relax
%    \hyphenationmin\numexpr0\languageparameter\s!hyphenmin\relax
%    % these values are stored with the language (global!)
%    \prehyphenchar \languageparameter\s!righthyphenchar\relax
%    \posthyphenchar\languageparameter\s!lefthyphenchar \relax}

\protected\def\lang_basics_synchronize_min_max % maybe store this at the lua end
  {% these values are stored along with glyph nodes
  %\lefthyphenmin \numexpr0\languageparameter\s!lefthyphenmin +\hyphenminoffset\relax
  %\righthyphenmin\numexpr0\languageparameter\s!righthyphenmin+\hyphenminoffset\relax
  %\hyphenationmin\numexpr0\languageparameter\s!hyphenmin\relax
   \lefthyphenmin {\ifchknumexpr\languageparameter\s!lefthyphenmin \or\lastchknumber+\fi\hyphenminoffset}%
   \righthyphenmin{\ifchknumexpr\languageparameter\s!righthyphenmin\or\lastchknumber+\fi\hyphenminoffset}%
   \hyphenationmin{\ifchknumexpr\languageparameter\s!hyphenmin     \or\lastchknumber\else\zeropoint\fi}%
   % these values are stored with the language (global!)
   \prehyphenchar   \languageparameter\s!righthyphenchar\relax
   \posthyphenchar  \languageparameter\s!lefthyphenchar \relax
   \preexhyphenchar \languageparameter\s!explicitrighthyphenchar\relax
   \postexhyphenchar\languageparameter\s!explicitlefthyphenchar \relax}

\appendtoks
    \lang_basics_synchronize_min_max % todo: also sync when already in language
\to \everylanguage

\appendtoks
    \ifcstok{\languageparameter\s!apostrophe}\v!yes
      \doapostrophes
    \else
      \noapostrophes
    \fi
\to \everylanguage

\doapostrophes % enabled by default

\exapostrophechar\singlequoteasciicode

\permanent\protected\def\unhyphenated
  {\groupedcommand{\lefthyphenmin\maxdimen}\donothing}

% \appendtoks
%     \setups[\languageparameter\c!setups]%
% \to \everylanguage

%D You can setup the default language to reset settings.

\mutable\lettonothing\currentlanguagesetups

\appendtoks
    \edef\currentlanguagesetups{\languageparameter\c!setups}%
    \ifempty\currentlanguagesetups \else
        \setups[\currentlanguagesetups]%
    \fi
\to \everylanguage

% this will move to core-spa !

\appendtoks
    \ifcstok{\languageparameter\c!spacing}\v!broad
      \nonfrenchspacing
    \else
      \frenchspacing
    \fi
\to \everylanguage

% \mainlanguage[nl] \setuplanguage[nl][lefthyphen=,righthyphen=?]
%
% \dorecurse{100}{dit is toch wel een heel\normalhyphendiscretionary lang\normalhyphendiscretionary woord \recurselevel\ }
% \dorecurse{100}{dit is toch wel een heellangwoord \recurselevel\ }

% new experimental feature

\permanent\protected\def\setuplanguages
  {\setuplanguage[\s!default]}

% \setuplanguages[\c!font=\v!auto]
% \setuplanguage[\s!default][\c!font=\v!auto]
% \setuplanguage[nl][\c!font=\v!auto]

\lettonothing\p_language_font

\appendtoks
    \edef\p_language_font{\languageparameter\c!font}%
    \ifempty\p_language_font
    \orelse\ifx\p_language_font\v!auto
      \doaddfeature\currentlanguage
    \else
      \doaddfeature\p_language_font
    \fi
\to \everylanguage

%D Fast switcher

\permanent\protected\def\uselanguageparameter#1%
  {\cdef\currentlanguageparameter{#1\c!language}%
   \ifempty\currentlanguageparameter\else\dousecurrentlanguageparameter\fi}

\permanent\protected\def\douselanguageparameter#1% fast setter
  {\cdef\currentlanguageparameter{#1}%
   \ifempty\currentlanguageparameter\else\dousecurrentlanguageparameter\fi}

\permanent\protected\def\dousecurrentlanguageparameter% fast setter
  {\ifcsname\??languagelinked\currentlanguageparameter\endcsname
     \edef\currentlanguageparameter{\lastnamedcs}%
     \ifx\currentlanguage\currentlanguageparameter \else
       \setcurrentlanguage\currentmainlanguage\currentlanguageparameter
       \lang_basics_synchronize
     \fi
   \fi}

\def\lang_basics_one_time_warning
  {\ifconditional\c_strc_tags_enabled
     \writestatus\m!languages{}% todo: move to mult-mes.lua
     \writestatus\m!languages{use a language parameter or define an environment}%
     \writestatus\m!languages{}%
   \fi
   \glettonothing\lang_basics_one_time_warning}

\def\lang_basics_switch_asked
  {\ifcsname\??languagelinked\askedlanguage\endcsname
     \cdef\askedlanguage{\lastnamedcs}%
     \ifx\currentlanguage\askedlanguage \else
       \lang_basics_one_time_warning
       \setcurrentlanguage\currentmainlanguage\askedlanguage
       \lang_basics_synchronize
     \fi
   \fi}

\protected\def\lang_basics_set_current[#1]%
  {\cdef\askedlanguage{#1}%
   \ifempty\askedlanguage\else\lang_basics_switch_asked\fi}

\pushoverloadmode

    \permanent\protected\def\language
      {\doifelsenextoptionalcs\lang_basics_set_current\normallanguage}

    \aliased\let\setlanguage\language % we make these synonyms

    \aliased\let\patterns\gobbleoneargument

\popoverloadmode

\newinteger\mainlanguagenumber

%D Beware: you might need to use \type {\dontleavehmode} outside and|/|or \type {\par}
%D inside the group!

\permanent\protected\def\startlanguage
  {\begingroup\language}

\permanent\let\stoplanguage\endgroup

\permanent\protected\def\mainlanguage[#1]%
  {\cdef\askedlanguage{#1}%
   \ifempty\askedlanguage
   \orelse\ifcsname\??languagelinked\askedlanguage\endcsname
    %\edef\askedlanguage{\csname\??languagelinked\askedlanguage\endcsname}%
     \cdef\askedlanguage{\lastnamedcs}%
     \ifx\currentlanguage\askedlanguage
       \ifx\currentmainlanguage\askedlanguage \else
         \setcurrentlanguage\askedlanguage\askedlanguage
         \lang_basics_synchronize
       \fi
     \else
       \setcurrentlanguage\askedlanguage\askedlanguage
       \lang_basics_synchronize
     \fi
   \fi
   \mainlanguagenumber\normallanguage}

\appendtoks
    \normallanguage\mainlanguagenumber
\to \everybeforepagebody

%D Used at all?

\permanent\def\splitsequence#1#2% append periods etc
  {\ifcstok{#1}\v!no
     #2%
   \orelse\ifcstok{#1}\v!yes
      \languageparameter\c!limittext
   \else
     #1%
   \fi}

\permanent\def\splitsymbol#1%
  {\splitsequence{#1}{\languageparameter\c!limittext}}

%D Just like with subsentence boundary symbols, quotes placement depends on the
%D current language, therefore we show the defaults here.
%D
%D \def\ShowLanguageValues [#1] [#2] #3 #4
%D   {\blank
%D    \startlinecorrection
%D    \vbox\bgroup
%D    \language[#1]
%D    \midaligned{\bf#2 subsentence symbol and quotes}
%D    \framed[width=\hsize,frame=off,topframe=on,bottomframe=on,offset=.5ex]
%D      {\hfil\quotation{#3 #4}\hfil\quote{#2}\hfil
%D       \startsubsentence\startsubsentence#3\stopsubsentence#4\stopsubsentence\hfil}
%D    \egroup
%D    \stoplinecorrection
%D    \blank}
%D
%D \ShowLanguageValues [af] [afrikaans]  afrikaanse ...
%D \ShowLanguageValues [ca] [catalan]    catalan ...
%D \ShowLanguageValues [cs] [czech]      tjechisch tex
%D \ShowLanguageValues [cs] [slovak]     slowaakse ...
%D \ShowLanguageValues [da] [danish]     deense ...
%D \ShowLanguageValues [de] [german]     duitse degelijkheid
%D \ShowLanguageValues [en] [english]    engelse humor
%D \ShowLanguageValues [et] [estonian]   ...
%D \ShowLanguageValues [fi] [finnish]    finse ...
%D \ShowLanguageValues [fr] [french]     franse slag
%D \ShowLanguageValues [it] [italian]    italiaanse ...
%D \ShowLanguageValues [la] [latin]      latijnse missen
%D \ShowLanguageValues [nl] [dutch]      nederlandse zuinigheid
%D \ShowLanguageValues [nb] [bokmal]     noorse zalm
%D \ShowLanguageValues [nn] [nnynorsk]   noorse zalm
%D \ShowLanguageValues [pl] [polish]     poolse vlag
%D \ShowLanguageValues [pt] [portuguese] portugese ...
%D \ShowLanguageValues [es] [spanish]    spaans benauwd
%D \ShowLanguageValues [sv] [swedish]    zweedse ...
%D \ShowLanguageValues [tr] [turkish]    turks fruit

%D We support a lot of languages. These are specified and loaded in separate files,
%D according to their roots. Here we only take care of (postponed) setting of the
%D current language.
%D
%D \unprotect
%D \placetable{The germanic languages (\type{lang-ger})}
%D \starttable[||||]
%D \HL
%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
%D \HL
%D \NC \s!nl        \NC dutch        \NC germanic  \NC\FR
%D \NC \s!en        \NC english      \NC germanic  \NC\MR
%D \NC \s!de        \NC german       \NC germanic  \NC\MR
%D \NC \s!da        \NC danish       \NC germanic  \NC\MR
%D \NC \s!sv        \NC swedish      \NC germanic  \NC\MR
%D \NC \s!af        \NC afrikaans    \NC germanic  \NC\MR
%D \NC \s!nb        \NC bokmal       \NC germanic  \NC\LR
%D \NC \s!nn        \NC nynorsk      \NC germanic  \NC\LR
%D \HL
%D \stoptable
%D \protect
%D
%D \unprotect
%D \placetable{The italic languages (\type{lang-ita})}
%D \starttable[||||]
%D \HL
%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
%D \HL
%D \NC \s!fr        \NC french       \NC italic    \NC\FR
%D \NC \s!ca        \NC catalan      \NC italic    \NC\MR
%D \NC \s!es        \NC spanish      \NC italic    \NC\MR
%D \NC \s!it        \NC italian      \NC italic    \NC\MR
%D \NC \s!la        \NC latin        \NC italic    \NC\MR
%D \NC \s!pt        \NC portuguese   \NC italic    \NC\LR
%D \HL
%D \stoptable
%D \protect
%D
%D \unprotect
%D \placetable{The slavic languages (\type{lang-sla})}
%D \starttable[||||]
%D \HL
%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
%D \HL
%D \NC \s!pl        \NC polish       \NC slavic    \NC\FR
%D \NC \s!cs        \NC czech        \NC slavic    \NC\MR
%D \NC \s!sk        \NC slavik       \NC slavic    \NC\LR
%D \HL
%D \stoptable
%D \protect
%D \unprotect
%D
%D \placetable{The altaic languages (\type{lang-alt})}
%D \starttable[||||]
%D \HL
%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
%D \HL
%D \NC \s!tr        \NC turkish      \NC altaic    \NC\SR
%D \HL
%D \stoptable
%D
%D \placetable{The uralic languages (\type{lang-ura})}
%D \starttable[||||]
%D \HL
%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
%D \HL
%D \NC \s!fi        \NC finnish      \NC uralic    \NC\SR
%D \HL
%D \stoptable
%D \protect

\permanent\protected\def\nopatterns{\normallanguage\minusone}

%D We default to the language belonging to the interface. This is one of the few
%D places outside the interface modules where \type {\startinterface} is used.

\setupcurrentlanguage[\s!en]

\permanent\protected\def\initializemainlanguage
  {\mainlanguage[\currentlanguage]%
   \showmessage\m!languages9\currentlanguage}

%D New:

\permanent\let\stopexceptions\relax

\tolerant\permanent\protected\def\startexceptions[#1]#:#2\stopexceptions
  {\begingroup
   \cdef\askedlanguage{\reallanguagetag{#1}}%
   \ifempty\askedlanguage
     \let\askedlanguage\currentlanguage
   \fi
   \clf_setlanguageexceptions{\askedlanguage}{#2}%
   \endgroup}

\permanent\let\stoppatterns\relax

\tolerant\permanent\protected\def\startpatterns[#1]#:#2\stoppatterns
  {\begingroup
   \cdef\askedlanguage{\reallanguagetag{#1}}%
   \ifempty\askedlanguage
     \let\askedlanguage\currentlanguage
   \fi
   \clf_setlanguagepatterns{\askedlanguage}{#2}%
   \endgroup}


\pushoverloadmode

\permanent\protected\def\hyphenation{\clf_setlanguageexceptions{\currentlanguage}}
\permanent\protected\def\patterns   {\clf_setlanguagepatterns  {\currentlanguage}}

\popoverloadmode

%D New:

\permanent\protected\def\traceddiscretionary#1#%
  {\dontleavehmode\lang_basics_traced_discretionary{#1}}

\protected\def\lang_basics_traced_discretionary#1#2#3#4%
  {\normaldiscretionary#1{\darkred#2}{\darkgreen#3}{\darkblue#4}}

\def\lang_basics_trace_discretionary_yes{\enforced\let\discretionary\traceddiscretionary} % indirect because of overload
\def\lang_basics_trace_discretionary_nop{\enforced\let\discretionary\normaldiscretionary} % indirect because of overload


\installtextracker
  {discretionaries}
  {\lang_basics_trace_discretionary_yes}
  {\lang_basics_trace_discretionary_nop}

\permanent\protected\def\samplediscretionary
  {\traceddiscretionary
     {pre\clf_currentprehyphenchar}%
     {\clf_currentposthyphenchar post}%
     {replace}}

%D A typical \LMTX\ feature:
%D
%D \starttyping
%D whatever\par
%D {\nokerning whatever}\par
%D efficient ff fi\par
%D {\noligaturing efficient ff fi}\par
%D {\nokerning\noligaturing efficient ff fi}\par
%D {e{\noligaturing ffi}cient}\par
%D {ef{\noleftligaturing f}icient ff fi}\par
%D {ef{\norightligaturing f}icient ff fi}\par
%D \stoptyping

\permanent\immutable\integerdef\nokerningcode   \numexpr\noleftkernglyphoptioncode        +\norightkernglyphoptioncode           \relax
\permanent\immutable\integerdef\noligaturingcode\numexpr\noleftligatureglyphoptioncode    +\norightligatureglyphoptioncode       \relax
\permanent\immutable\integerdef\noitalicscode   \numexpr\noitaliccorrectionglyphoptioncode+\nozeroitaliccorrectionglyphoptioncode\relax

\permanent\protected\def\nokerning         {\bitwiseflip\glyphoptions\nokerningcode}
\permanent\protected\def\noligaturing      {\bitwiseflip\glyphoptions\noligaturingcode}
\permanent\protected\def\noitaliccorrection{\bitwiseflip\glyphoptions\noitalicscode}

\permanent\protected\def\noleftkerning     {\bitwiseflip\glyphoptions\noleftkernglyphoptioncode}
\permanent\protected\def\noleftligaturing  {\bitwiseflip\glyphoptions\noleftligatureglyphoptioncode}
\permanent\protected\def\norightkerning    {\bitwiseflip\glyphoptions\norightkernglyphoptioncode}
\permanent\protected\def\norightligaturing {\bitwiseflip\glyphoptions\norightligatureglyphoptioncode}

\bitwiseflip\glyphoptions\nozeroitaliccorrectionglyphoptioncode % for the moment default avoid the side effect

%D Also \LMTX:

% \startlanguageoptions[de]
%     Zapf|innovation
% \stoplanguageoptions

\permanent\let\stoplanguageoptions\relax

\permanent\protected\def\startlanguageoptions
  {\begingroup
   \catcode`|\othercatcode
   \lang_startlanguageoptions}

\tolerant\def\lang_startlanguageoptions[#1]#:#2\stoplanguageoptions
  {\cdef\askedlanguage{\reallanguagetag{#1}}%
   \ifempty\askedlanguage
     \let\askedlanguage\currentlanguage
   \fi
   \clf_setlanguageoptions{\askedlanguage}{#2}%
   \endgroup}

% \startluacode
%     table.save("oeps-fixes.llg", {
%         name    = "demo",
%         options = {
%             { patterns = { fio  = "f|io" }, words = [[ fioot fiots ]] },
%             { patterns = { fio  = "t|h"  }, words = [[ this that ]]   },
%         },
%     })
% \stopluacode
%
% \setuplanguage[en][goodies={oeps-fixes.llg}] \setupbodyfont[ebgaramond]
%
% \starttext
%     fiets fiots fiats fioot this that
% \stoptext

% new

\protect \endinput
