lang-spe.mkii / last modification: 2020-01-30 14:15
%D \module
%D   [       file=lang-spe,
%D        version=2002.05.07, % 1996.01.25,
%D          title=\CONTEXT\ Language Macros,
%D       subtitle=Specifics,
%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.

%D This code was originally placed in the language
%D initialization module, but isolating it is clearer. Language
%D specifics evolved out of user demands for special features,
%D like the german active quote. After a while I decided to
%D associate them to languages in a more general way so that we
%D could associate all kind of things with language switching.
%D
%D This is a typical example of functionality that occasionally
%D gets improved based on user input and experience. Much of the
%D code is pretty old and could probabbly be done in better ways.
%D It's probably also the kind of code that has been and will be
%D written over and over again by \TEX\ users around the world,
%D so there are probably better implementations of similar
%D functionality around. Therefore, users are invited to pop in
%D their own handling as long as it does not interfere with
%D existing code. Writing the more obscure macros that deal with
%D this is a good learning experience (catcodes, lccodes, token
%D lists, expansion, \unknown).

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

\unprotect

%D \macros
%D   {everyresetlanguagespecifics,resetlanguagespecifics}
%D
%D Cleanup macros.

\newevery \everyresetlanguagespecifics \relax

\def\resetlanguagespecifics
  {\ifcase\protectionlevel
     \the\everyresetlanguagespecifics
   \else % to be translated
     % \writestatus\m!systems{don't change language in unprotected mode!}%
   \fi}

\appendtoks
  \resetlanguagespecifics
\to \everycleanupfeatures

%D \macros
%D   {startlanguagespecifics,enablelanguagespecifics}
%D
%D Each language has its own typographic pecularities. Some of
%D those can be influenced by parameters, others are handled by
%D the interface, but as soon as specific commands come into
%D view we need another mechanism. In the macro that activates
%D a language, we call \type{\enablelanguagespecifics}. This
%D macro in return calls for the setup of language specific
%D macros. Such specifics are defined as:
%D
%D \starttyping
%D \startlanguagespecifics[de]
%D   \installcompoundcharacter "a {\"a}
%D   \installcompoundcharacter "e {\"e}
%D   \installcompoundcharacter "s {\SS}
%D \stoplanguagespecifics
%D \stoptyping
%D
%D Instead of \type{[du]} we can pass a comma separated
%D list, like \type{[du,nl]}. Next calls to this macro add the
%D specifics to the current list.
%D
%D Before we actually read the specifics, we first take some
%D precautions that will prevent spurious spaces to creep into
%D the list.

% We should use token registers, but alas, we run out of them and
% \ETEX\ has a bug. Well, let's use a token register now (2006).

\def\startlanguagespecifics%                % we use double to
  {\bgroup
   \catcode`\^^I=\@@ignore
   \catcode`\^^M=\@@ignore
   \catcode`\^^L=\@@ignore
   \dodoubleempty\dostartlanguagespecifics} % get rid of spaces

%D The main macro looks quite complicated but actually does
%D nothing special. By embedding \type{\do} we can easily
%D append to the lists and also execute them at will. Just to
%D be sure, we check on spurious spaces. The second dummy
%D argument gobbles spaces.

\def\languageencoding
  {\ifx\characterencoding\nocharacterencoding \else
     \characterencoding-%
   \fi}

\long\def\dostartlanguagespecifics[#1][#2]#3\stoplanguagespecifics
  {\egroup
   \processcommalist[#1]{\dosetlanguagespecifics{#3}}}

% \long\def\dosetlanguagespecifics#1#2%
%   {\ifundefined{\??la\languageencoding#2\??la}\forgetlanguagespecifics[#2]\fi
%    % the next line catches the case that specifics are enabled *before* they are defined
%    \expandafter\ifx\csname\??la\languageencoding#2\??la\endcsname\relax\forgetlanguagespecifics[#2]\fi
%    \appendvalue{\??la\languageencoding#2\??la}{#1}%
%    \bgroup
%    \setbox\scratchbox\hbox{\enablelanguagespecifics[#2]}%
%    \ifdim\wd\scratchbox>\zeropoint
%      \showmessage\m!linguals7{\currentencoding-#2,\the\wd\scratchbox\space}\wait
%    \else
%      \showmessage\m!linguals8{\currentencoding-#2}%
%    \fi
%    \egroup
%    \doif{#2}\currentmainlanguage{\enablelanguagespecifics[#2]}}

\def\languagespectag#1{\??la\languageencoding#1\??la}

\long\def\dosetlanguagespecifics#1#2%
  {\edef\askedlanguagespecificstag{\languagespectag{#2}}%
   \ifcsname\askedlanguagespecificstag\endcsname \else
      \expandafter\newtoks\csname\askedlanguagespecificstag\endcsname
   \fi
   \csname\askedlanguagespecificstag\endcsname\@EA{\the\csname\askedlanguagespecificstag\endcsname#1}%
   \bgroup
   \setbox\scratchbox\hbox{\enablelanguagespecifics[#2]}%
   \ifdim\wd\scratchbox>\zeropoint
     \showmessage\m!linguals7{\currentencoding-#2,\the\wd\scratchbox\space}\wait
   \else
     \showmessage\m!linguals8{\currentencoding-#2}%
   \fi
   \egroup
   \doif{#2}\currentmainlanguage{\enablelanguagespecifics[#2]}}

\def\forgetlanguagespecifics[#1]%
  {\csname\languagespectag{#1}\endcsname\emptytoks}

%D Enabling them is rather straightforward. We only have to
%D define \type{\do} in such a way that \type{{ }} is removed
%D and the language key is gobbled.

% \def\enablelanguagespecifics[#1]%
%   {\the\executeifdefined{\??la
%      \@EA\ifx\csname\??la#1\c!default\endcsname\relax
%        \languageencoding
%      \else
%        \csname\??la#1\c!default\endcsname
%      \fi
%      \??la}\emptytoks
%    \the\executeifdefined{\??la#1\??la}\emptytoks
%    \the\executeifdefined{\??la\languageencoding#1\??la}\emptytoks} % dup ?

\def\enablelanguagespecifics[#1]%
  {\edef\askedlanguagespecificslanguage{\defaultlanguage{#1}}%
   \ifcsname\??la\askedlanguagespecificslanguage\??la\endcsname
     \the\csname\??la\askedlanguagespecificslanguage\??la\endcsname
   \fi
   \ifx\languageencoding\empty\else
     \ifcsname\??la\languageencoding\askedlanguagespecificslanguage\??la\endcsname
       \the\csname\??la\languageencoding\askedlanguagespecificslanguage\??la\endcsname
     \fi
   \fi}

%D \macros
%D   {deactivatelanguagespecific}
%D
%D The next code makes it possible to disable the specifics.

% \def\deactivatelanguagespecific#1%
%   {\ifundefined{l g s \string#1}%
%      \letgvalueempty{l g s \string#1}% signal to prevent dup def
%      \bgroup
%      \catcode`#1=\@@active
%      \uccode`~=`#1
%      \uppercase{\doglobal\appendtoks\dodeactivatetoken{~}\to\everyresetlanguagespecifics}%
%      \egroup
%      \expanded{\doglobal\noexpand\appendtoks{#1}{\the\catcode`#1}}\to\everyresetlanguagespecifics
%    \fi}

% \def\dodeactivatetoken#1#2#3% test needed to avoid clash with \unprotect
%   {\def#1{#2}\ifnum\catcode`#2=\@@active\catcode`#2=#3\relax\fi}

%D We cannot hook this into the installer since language
%D specifics can be anything. So far, we have the following
%D potentially active characters.

%D Beware, this should happen under an unprotected regime;
%D thanks to Giuseppe Oblomov Bilotta, who first noticed
%D that something was wrong.

\protect

% \deactivatelanguagespecific "
% \deactivatelanguagespecific /
% \deactivatelanguagespecific :
% \deactivatelanguagespecific ;
% \deactivatelanguagespecific ?
% \deactivatelanguagespecific !

\unprotect

% yes or no (taco wins: no)

% \startlanguagespecifics[nl,cs,sk,fr]
%   \lccode`\'=`\'
% \stoplanguagespecifics

%D \macros
%D   {ordinaldaynumber, highordinalstr, ordinalstr}
%D
%D Efficient general ordinal number converters are sometimes
%D difficult to implement. Fortunately dates never exceed the
%D number~31.

\ifx\high          \undefined \let\high          \firstofoneargument \fi % todo
\ifx\notsmallcapped\undefined \let\notsmallcapped\firstofoneargument \fi % todo

\def\highordinalstr#1{\high{\notsmallcapped{#1}}}
\def\ordinalstr    #1{\notsmallcapped{#1}}

\def\ordinaldaynumber#1% \strippedcsname\ordinaldaynumber
  {\expanded{\executeifdefined{\currentlanguage ordinaldaynumber}%
     \noexpand\firstofoneargument{\number#1}}}

%D Language specific converters have definitions like:
%D
%D \starttyping
%D \def\enordinaldaynumber#1{...}
%D \stoptyping
%D
%D Examples can be found in the other \type {lang} modules.

% \ifprocessingXML is a nasty dependency

\appendtoks
  \ifprocessingXML \else \resetlanguagespecifics \fi
\to \everylanguage

\protect \endinput