%D \module %D [ file=mult-ini, %D version=1996.06.01, %D title=\CONTEXT\ Multilingual Macros, %D subtitle=Initialization, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA / Hans Hagen \& Ton Otten}] %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 module implements the multi||lingual interface to %D \CONTEXT. These capabilities concern messages, commands and %D parameters. Currently the following interfaces are %D supported: %D %D \starttabulatie[|l|l|c|c|] %D \NC\bf language\NC\bf translator \NC\bf messages\NC\bf interface\NC\NR %D \NC dutch \NC Hans Hagen \NC yes \NC yes \NC\NR %D \NC english \NC Hans Hagen \NC yes \NC yes \NC\NR %D \NC german \NC Tobias Burnus \NC yes \NC yes \NC\NR %D \NC czech \NC Tom Hudec \NC yes \NC yes \NC\NR %D \NC italian \NC Giuseppe Bilotta \NC yes \NC yes \NC\NR %D \NC norwegian \NC Hans Fredrik Nordhaug\NC yes \NC no \NC\NR %D \stoptabulatie \writestatus{loading}{Context Multilingual Macros / Initialization} \unprotect %D \macros %D [constanten,variabelen,commandos] %D {v!,c!,k!,s!,e!,m!,l!,r!,f!,p!,x!,y!} %D %D In the system modules we introduced some prefixed constants, %D variables (both macros) and registers. Apart from a %D tremendous saving in terms of memory and a gain in speed we %D use from now on prefixes when possible for just another %D reason: consistency and multi||linguality. Systematically %D using prefixed macros enables us to implement a %D multi||lingual user interface. Redefining these next set of %D prefixes therefore can have desastrous results. %D %D \startregelcorrectie %D \starttabel[|c|c|c|] %D \HL %D \NC \bf prefix \NC \bf meaning \NC \bf application \NC\SR %D \HL %D \NC \type{\c!prefix!} \NC c! \NC constant (direct) \NC\FR %D \NC \type{\e!prefix!} \NC e! \NC element \NC\MR %D \NC \type{\f!prefix!} \NC f! \NC file \NC\MR %D \NC \type{\k!prefix!} \NC k! \NC constant (indirect) \NC\MR %D \NC \type{\l!prefix!} \NC l! \NC language \NC\MR %D \NC \type{\m!prefix!} \NC m! \NC message \NC\MR %D \NC \type{\p!prefix!} \NC p! \NC procedure \NC\MR %D \NC \type{\r!prefix!} \NC r! \NC reference \NC\MR %D \NC \type{\s!prefix!} \NC s! \NC system \NC\MR %D \NC \type{\v!prefix!} \NC v! \NC variable \NC\MR %D \NC \type{\x!prefix!} \NC x! \NC setup constant \NC\MR %D \NC \type{\y!prefix!} \NC y! \NC setup variable \NC\LR %D \HL %D \stoptabel %D \stopregelcorrectie %D %D In the single||lingual version we used \type{!}, \type{!!}, %D \type{!!!} and \type{!!!!}. \def\c!prefix!{c!} \def\e!prefix!{e!} \def\f!prefix!{f!} \def\k!prefix!{k!} \def\l!prefix!{l!} \def\m!prefix!{m!} \def\p!prefix!{p!} \def\r!prefix!{r!} \def\s!prefix!{s!} \def\v!prefix!{v!} \def\x!prefix!{x!} \def\y!prefix!{y!} %D \macros %D [constants,variables,commands] %D {@@,??} %D %D Variables generated by the system can be recognized on their %D prefix \type{@@}. They are composed of a command (class) %D specific tag, which can be recognized on \type{??}, and a %D system constant, which has the prefix \type{c!}. We'll se %D some more of this. \def\??prefix {??} \def\@@prefix {@@} %D Just to be complete we repeat some of the already defined %D system constants here. Maybe their prefix \type{\s!} now %D falls into place. \def\s!next {next} \def\s!default {default} \def\s!dummy {dummy} \def\s!unknown {unknown} \def\s!do {do} \def\s!dodo {dodo} \def\s!complex {complex} \def\s!start {start} \def\s!simple {simple} \def\s!stop {stop} \def\!!width {width} \def\!!plus {plus} \def\!!height {height} \def\!!minus {minus} \def\!!depth {depth} \def\!!to {to} %D \macros %D {defineinterfaceconstant, %D defineinterfacevariable, %D defineinterfaceelement, %D definesystemvariable, %D definesystemconstant, %D definemessageconstant, %D definereferenceconstant, %D definefileconstant} %D %D The first part of this module is dedicated to dealing with %D multi||lingual constants and variables. When \CONTEXT\ grew %D bigger and bigger in terms of bytes and used string space, %D we switched to predefined constants. At the cost of more %D hash table entries, the macros not only becase more compact, %D they became much faster too. Maybe an even bigger advantage %D was that mispelling could no longer lead to problems. Even a %D multi||lingual interface became possible. %D %D Constants --- we'll introduce the concept of variables later %D on --- are preceded by a type specific prefix, followed by a %D \type{!}. To force consistency, we provide a few commands %D for defining such constants. %D %D \starttypen %D \defineinterfaceconstant {name} {meaning} %D \defineinterfacevariable {name} {meaning} %D \defineinterfaceelement {name} {meaning} %D \stoptypen %D %D Which is the same as: %D %D \starttypen %D \def\c!name{meaning} %D \def\v!name{meaning} %D \def\e!name{meaning} %D \stoptypen \def\defineinterfaceconstant #1#2{\setvalue{\c!prefix!#1}{#2}} \def\defineinterfacevariable #1#2{\setvalue{\v!prefix!#1}{#2}} \def\defineinterfaceelement #1#2{\setvalue{\e!prefix!#1}{#2}} %D Next come some interface independant constants: %D %D \starttypen %D \definereferenceconstant {name} {meaning} %D \definefileconstant {name} {meaning} %D \stoptypen \def\definereferenceconstant #1#2{\setvalue{\r!prefix!#1}{#2}} \def\definefileconstant #1#2{\setvalue{\f!prefix!#1}{#2}} %D And finaly we have the one argument, space saving constants %D %D \starttypen %D \definesystemconstant {name} %D \definemessageconstant {name} %D \stoptypen \def\definesystemconstant #1{\setvalue{\s!prefix!#1}{#1}} \def\definemessageconstant #1{\setvalue{\m!prefix!#1}{#1}} %D In a parameter driven system, some parameters are shared %D by more system components. In \CONTEXT\ we can distinguish %D parameters by a unique prefix. Such a prefix is defined %D with: %D %D \starttypen %D \definesystemvariable {name} %D \stoptypen \def\definesystemvariable #1{\setevalue{\??prefix#1}{\@@prefix#1}} \definesystemvariable {ms} %D \macros %D {selectinterface, %D defaultinterface, currentinterface, currentresponses} %D %D With \type{\selectinterface} we specify the language we are %D going to use. The system asks for the language wanted, and %D defaults to \type{\currentinterface} when we just give %D \type{enter}. By default the message system uses the %D current interface language, but \type{\currentresponses} %D can specify another language too. %D %D Because we want to generate formats directly too, we do %D not ask for interface specifications when these are already %D defined (like in cont-nl.tex and alike). \ifx\undefined\scratchwrite \newwrite\scratchwrite \fi \ifx\undefined\scratchread \newwrite\scratchread \fi \immediate\openin\scratchread=mult-def.tex % may overload the defaults \ifeof\scratchread % no high level commands yet \immediate\closein\scratchread \else \immediate\closein\scratchread \input mult-def.tex \fi \ifx\defaultinterface\undefined \def\defaultinterface{english} \def\selectinterface% {\def\docommando##1##2% {\bgroup \endlinechar=-1 \global\read16 to ##1 \egroup \doif{\currentinterface}{}{\let##1=##2}% \doifundefined{\s!prefix!##1}{\let##1=##2}}% \docommando\currentinterface\defaultinterface \writestatus{interface}{defining \currentinterface\space interface}% \writeline \docommando\currentresponses\currentinterface \writestatus{interface}{using \currentresponses\space messages}% \writeline \let\selectinterface\relax} \else \def\selectinterface% {\writestatus{interface}{defining \currentinterface\space interface}% \writeline \writestatus{interface}{using \currentresponses\space messages}% \writeline \let\selectinterface\relax} \fi \ifx\currentinterface\undefined \let\currentinterface=\defaultinterface \fi \ifx\currentresponses\undefined \let\currentresponses=\defaultinterface \fi %D \macros %D {startinterface} %D %D Sometimes we want to define things only for specific %D interface languages. This can be done by means of the %D selector: %D %D \starttypen %D \startinterface language %D %D language specific definitions & commands %D %D \stopinterface %D \stoptypen \def\startinterface #1 {\doifinsetelse{\currentinterface}{#1} {\let\next\relax} {\long\def\next##1\stopinterface{}}% \next} \let\stopinterface=\relax %D \macros %D {startmessages, %D getmessage, %D showmessage, %D makemessage} %D %D A package as large as \CONTEXT\ can hardly function without %D a decent message mechanism. Due to its multi||lingual %D interface, the message subsystem has to be multi||lingual %D too. A major drawback of this feature is that we have to %D code messages. As a result, the source becomes less self %D documented. On the other hand, consistency will improve. %D %D Because the overhead in terms of entries in the (already %D exhausted) hash table has to be minimal, messages are packed %D in libraries. We can extract a message from such a library %D in three ways: %D %D \starttypen %D \getmessage {library} {tag} %D \showmessage {library} {tag} {data} %D \makemessage {library} {tag} {data} %D \stoptypen %D %D The first command gets the message \type{tag} from the %D \type{library} specified. The other commands take an extra %D argument: a list of items to be inserted in the message %D text. While \type{\showmessage} shows the message at the %D terminal, the other commands generate the message as text. %D Before we explain the \type{data} argument, we give an %D example of a library. %D %D \starttypen %D \startmessages english library: alfa %D title: something %D 1: first message %D 2: second (--) message -- %D \stopmessages %D \stoptypen %D %D The first message is a simple one and can be shown with: %D %D \starttypen %D \showmessage {alfa} {1} {} %D \stoptypen %D %D The second message on the other hand needs some extra data: %D %D \starttypen %D \showmessage {alfa} {2} {and last,to you} %D \stoptypen %D %D This message is shown as: %D %D \starttypen %D something : second (and last) message to you %D \stoptypen %D %D As we can see, the title entry is shown with the message. %D The data fields are comma separated and are specified in the %D message text by \type{--}. %D %D It is not required to define all messages in a library at %D once. We can add messages to a library in the following way: %D %D \starttypen %D \startmessages english library: alfa %D 10: tenth message %D \stopmessages %D \stoptypen %D %D Because such definitions can take place in different %D modules, the system gives a warning when a tag occurs more %D than once. The first occurrence takes preference over later %D ones, so we had better use a save offset, as shown in the %D example. As we can see, the title field is specified only %D the first time! %D %D Because we want to check for duplicate tags, the macros %D are a bit more complicated than neccessary. The \NEWLINE\ %D token is used as message separator. %D %D For internal purposes one can use \type {\dogetmessage}, %D which puts the message text asked for in \type %D {\currentmessagetext}. \def\findinterfacemessage#1#2% {\let#2\empty \def\dofindinterfacemessage##1 #1: ##2\relax##3\end% {\def#2{##2}}% \edef\!!stringa{\getvalue{\??ms\currentmessagelibrary} #1: \relax}% \expandafter\dofindinterfacemessage\!!stringa\end} \def\composemessagetext#1--#2--#3--#4--#5--#6\\% {\def\docomposemessagetext##1,##2,##3,##4,##5,##6\\% {\edef\currentmessagetext{#1##1#2##2#3##3#4##4#5##5}}% \docomposemessagetext} \def\dogetmessage#1#2% {\def\currentmessagelibrary{#1}% \findinterfacemessage{#2}\currentmessagetext} \unexpanded\def\getmessage#1#2% {\def\currentmessagelibrary{#1}% \findinterfacemessage{#2}\currentmessagetext \currentmessagetext} \unexpanded\def\makemessage#1#2#3% {\def\currentmessagelibrary{#1}% \findinterfacemessage{#2}\currentmessagetext \@EA\composemessagetext\currentmessagetext----------\\#3,,,,,\\% \currentmessagetext} \def\showmessage#1#2#3% {\def\currentmessagelibrary{#1}% \findinterfacemessage{#2}\currentmessagetext \findinterfacemessage{title}\currentmessagetitle \ifx\currentmessagetext\empty \def\currentmessagetext{}% \else \@EA\composemessagetext\currentmessagetext----------\\#3,,,,,\\% \fi \@EA\writestatus\@EA{\currentmessagetitle}{\currentmessagetext}} \def\doaddinterfacemessage#1#2% {\findinterfacemessage{#1}\currentmessagetext \doifelse{\currentmessagetext}{} {\setxvalue{\??ms\currentmessagelibrary}% {\getvalue{\??ms\currentmessagelibrary} #1: #2\relax}} {\debuggerinfotrue % we consider this an important error \debuggerinfo {message} {duplicate tag #1 in library \currentmessagelibrary\space of interface \currentresponses}}% \futurelet\next\getinterfacemessage} \bgroup \obeylines \gdef\addinterfacemessage#1: #2 {\doaddinterfacemessage{#1}{#2}}% \egroup \def\getinterfacemessage% {\ifx\next\stopmessages \def\next##1{\egroup}% \else \let\next\addinterfacemessage \fi \next} \def\startmessages #1 library: #2 {\definemessageconstant{#2}% handy for modules \bgroup \obeylines \doifinsetelse{#1}{\currentresponses,all} {\def\next% {\def\currentmessagelibrary{#2}% \doifundefined{\??ms\currentmessagelibrary} {\setgvalue{\??ms\currentmessagelibrary}{}}% \futurelet\next\getinterfacemessage}} {\long\def\next##1\stopmessages{\egroup}}% \next} %D Here, the messages are stored in a way that saves hash %D entries, i.e. they are packed in one macro per library. %D This was important in the days when we used \TEX's with %D hash tables of about 10.000. The next, less efficient way %D of storing the message, makes \CONTEXT\ run upto 5\% %D faster by storing each message in a macro. In July 2000, %D this costs some 185 additional hash entries, and since %D we run large \TEX's, let do it! \def\startmessages #1 library: #2 {\definemessageconstant{#2}% handy for modules \bgroup \obeylines \doifinsetelse{#1}{\currentresponses,all} {\def\next% {\def\currentmessagelibrary{#2}% \futurelet\next\getinterfacemessage}} {\long\def\next##1\stopmessages{\egroup}}% \next} \def\findinterfacemessage#1#2% {\edef#2{\getvalue{\??ms\currentmessagelibrary#1}}} \def\doaddinterfacemessage#1#2% {\doifdefined{\??ms\currentmessagelibrary#1} {\debuggerinfotrue % we consider this an important error \debuggerinfo {message} {duplicate tag #1 in library \currentmessagelibrary\space of interface \currentresponses}}% \setxvalue{\??ms\currentmessagelibrary#1}{#2}% \futurelet\next\getinterfacemessage} %D \macros %D {ifshowwarnings, ifshowmessages} %D %D Sometimes displaying message can slow down processing %D considerably. We therefore introduce warnings. Users can %D turn of warnings and messages by saying: %D %D \starttypen %D \showwarningstrue %D \showmessagestrue %D \stoptypen %D %D Turning off messages also turns off warnings, which is %D quote logical because they are less important. \newif\ifshowwarnings \showwarningstrue \newif\ifshowmessages \showmessagestrue \let\normalshowmessage=\showmessage \def\showwarning% {\ifshowwarnings \expandafter\showmessage \else \expandafter\gobblethreearguments \fi} \def\showmessage% {\ifshowmessages \expandafter\normalshowmessage \else \expandafter\gobblethreearguments \fi} %D \macros %D {dosetvalue,dosetevalue,dosetgvalue,docopyvalue,doresetvalue} % dogetvalue %D %D We already defined these auxiliary macros in the system %D modules. Starting with this module however, we have to take %D multi||linguality a bit more serious. %D %D First we show a well||defined (simplified) alternative: %D %D \starttypen %D \def\dosetvalue#1#2#3% %D {\doifdefinedelse{\c!prefix!#2} %D {\setvalue{#1\getvalue{\c!prefix!#2}}{#3}} %D {\setvalue{#1#2}{#3}}} %D %D \def\docopyvalue#1#2#3% %D {\doifdefinedelse{\c!prefix!#3} %D {\setvalue{#1\getvalue{\c!prefix!#3}}% %D {\getvalue{#2\getvalue{\c!prefix!#3}}}} %D {\setvalue{#1#3}% %D {\getvalue{#2#3}}}} %D \stoptypen %D %D These macros are called upon quite often and so we optimized %D them a bit. \def\dosetvalue#1#2#3% {\let\c!internal!\c!internal!n \p!doifundefined{\k!prefix!#2}% \let\c!internal!\c!internal!y \let\donottest\doprocesstest \@EA\def\csname#1#2\endcsname{#3}% \else \let\c!internal!\c!internal!y \let\donottest\doprocesstest \@EA\def\csname#1\csname\k!prefix!#2\endcsname\endcsname{#3}% \fi} \def\dosetevalue#1#2#3% {\let\c!internal!\c!internal!n \p!doifundefined{\k!prefix!#2}% \let\c!internal!\c!internal!y \let\donottest\doprocesstest \@EA\edef\csname#1#2\endcsname{#3}% \else \let\c!internal!\c!internal!y \let\donottest\doprocesstest \@EA\edef\csname#1\csname\k!prefix!#2\endcsname\endcsname{#3}% \fi} \def\docopyvalue#1#2#3% {\let\c!internal!\c!internal!n \p!doifundefined{\k!prefix!#3}% \let\c!internal!\c!internal!y \let\donottest\doprocesstest \@EA\def\csname#1#3\endcsname% {\csname#2#3\endcsname}% \else \let\c!internal!\c!internal!y \let\donottest\doprocesstest \@EA\def\csname#1\csname\k!prefix!#3\endcsname\endcsname% {\csname#2\csname\k!prefix!#3\endcsname\endcsname}% \fi} \def\doresetvalue#1#2% {\dosetvalue{#1}{#2}{}} \def\doignorevalue#1#2#3% {\dosetvalue{#1}{#2}{}} %\def\dogetvalue#1#2% % {\csname#1\csname\k!prefix!#2\endcsname\endcsname} %D Although maybe not clearly visible, there is a %D considerable profit in further optimization. By expanding %D the embedded \type {\csname} we can reduce the format file %D by about 5\% (60~KB out of 1.9~MB). \def\docopyvalue#1#2#3% c -> k {\p!doifundefined{\k!prefix!#3}% \let\donottest\doprocesstest \@EA\@EA\@EA\def\@EA \csname\@EA#1\@EA#3\@EA \endcsname\@EA{\csname#2#3\endcsname}% \else \let\donottest\doprocesstest \@EA\@EA\@EA\def\@EA \csname\@EA#1\@EA\csname\@EA\k!prefix!\@EA#3\@EA\endcsname\@EA \endcsname\@EA{\csname#2\csname\k!prefix!#3\endcsname\endcsname}% \fi} %D The next alternatives are slightly faster. \beginTEX % \def\dosetvalue#1#2#3% % {\let\c!internal!\c!internal!n % \@EA\ifx\csname\k!prefix!#2\endcsname\relax % \let\c!internal!\c!internal!y % \@EA\def\csname#1#2\endcsname{#3}% % \else % \let\c!internal!\c!internal!y % \@EA\def\csname#1\csname\k!prefix!#2\endcsname\endcsname{#3}% % \fi} % % \def\dosetevalue#1#2#3% % {\let\c!internal!\c!internal!n % \@EA\ifx\csname\k!prefix!#2\endcsname\relax % \let\c!internal!\c!internal!y % \@EA\edef\csname#1#2\endcsname{#3}% % \else % \let\c!internal!\c!internal!y % \@EA\edef\csname#1\csname\k!prefix!#2\endcsname\endcsname{#3}% % \fi} % % \def\dosetgvalue#1#2#3% % {\let\c!internal!\c!internal!n % \@EA\ifx\csname\k!prefix!#2\endcsname\relax % \let\c!internal!\c!internal!y % \@EA\gdef\csname#1#2\endcsname{#3}% % \else % \let\c!internal!\c!internal!y % \@EA\gdef\csname#1\csname\k!prefix!#2\endcsname\endcsname{#3}% % \fi} % % cleaner (not that much faster) don't pass #3 yet: \def\dosetvalue#1#2% {\let\c!internal!\c!internal!n \@EA\ifx\csname\k!prefix!#2\endcsname\relax \let\c!internal!\c!internal!y \@EA\@EA\@EA\def\@EA\@EA\csname#1#2\endcsname \else \let\c!internal!\c!internal!y \@EA\@EA\@EA\def\@EA\@EA\csname#1\csname\k!prefix!#2\endcsname\endcsname \fi} \def\dosetevalue#1#2% {\let\c!internal!\c!internal!n \@EA\ifx\csname\k!prefix!#2\endcsname\relax \let\c!internal!\c!internal!y \@EA\@EA\@EA\edef\@EA\@EA\csname#1#2\endcsname \else \let\c!internal!\c!internal!y \@EA\@EA\@EA\edef\@EA\@EA\csname#1\csname\k!prefix!#2\endcsname\endcsname \fi} \def\dosetgvalue#1#2% {\let\c!internal!\c!internal!n \@EA\ifx\csname\k!prefix!#2\endcsname\relax \let\c!internal!\c!internal!y \@EA\@EA\@EA\gdef\@EA\@EA\csname#1#2\endcsname \else \let\c!internal!\c!internal!y \@EA\@EA\@EA\gdef\@EA\@EA\csname#1\csname\k!prefix!#2\endcsname\endcsname \fi} % so far \def\docopyvalue#1#2#3% {\let\c!internal!\c!internal!n \@EA\ifx\csname\k!prefix!#3\endcsname\relax \let\c!internal!\c!internal!y \@EA\@EA\@EA\def\@EA \csname\@EA#1\@EA#3\@EA \endcsname\@EA{\csname#2#3\endcsname}% \else \let\c!internal!\c!internal!y \@EA\@EA\@EA\def\@EA \csname\@EA#1\@EA\csname\@EA\k!prefix!\@EA#3\@EA\endcsname\@EA \endcsname\@EA{\csname#2\csname\k!prefix!#3\endcsname\endcsname}% \fi} \endTEX \beginETEX \protected % \def\dosetvalue#1#2#3% % {\let\c!internal!\c!internal!n % \ifcsname\k!prefix!#2\endcsname % \let\c!internal!\c!internal!y % \@EA\def\csname#1\csname\k!prefix!#2\endcsname\endcsname{#3}% % \else % \let\c!internal!\c!internal!y % \@EA\def\csname#1#2\endcsname{#3}% % \fi} % % \def\dosetevalue#1#2#3% % {\let\c!internal!\c!internal!n % \ifcsname\k!prefix!#2\endcsname % \let\c!internal!\c!internal!y % \@EA\edef\csname#1\csname\k!prefix!#2\endcsname\endcsname{#3}% % \else % \let\c!internal!\c!internal!y % \@EA\edef\csname#1#2\endcsname{#3}% % \fi} % % \def\dosetgvalue#1#2#3% % {\let\c!internal!\c!internal!n % \ifcsname\k!prefix!#2\endcsname % \let\c!internal!\c!internal!y % \@EA\gdef\csname#1\csname\k!prefix!#2\endcsname\endcsname{#3}% % \else % \let\c!internal!\c!internal!y % \@EA\gdef\csname#1#2\endcsname{#3}% % \fi} % % cleaner (not that much faster) don't pass #3 yet: \def\dosetvalue#1#2% {\let\c!internal!\c!internal!n \ifcsname\k!prefix!#2\endcsname \let\c!internal!\c!internal!y \@EA\@EA\@EA\def\@EA\@EA\csname#1\csname\k!prefix!#2\endcsname\endcsname \else \let\c!internal!\c!internal!y \@EA\@EA\@EA\def\@EA\@EA\csname#1#2\endcsname \fi} \def\dosetevalue#1#2% {\let\c!internal!\c!internal!n \ifcsname\k!prefix!#2\endcsname \let\c!internal!\c!internal!y \@EA\@EA\@EA\edef\@EA\@EA\csname#1\csname\k!prefix!#2\endcsname\endcsname \else \let\c!internal!\c!internal!y \@EA\@EA\@EA\edef\@EA\@EA\csname#1#2\endcsname \fi} \def\dosetgvalue#1#2% {\let\c!internal!\c!internal!n \ifcsname\k!prefix!#2\endcsname \let\c!internal!\c!internal!y \@EA\@EA\@EA\gdef\@EA\@EA\csname#1\csname\k!prefix!#2\endcsname\endcsname \else \let\c!internal!\c!internal!y \@EA\@EA\@EA\gdef\@EA\@EA\csname#1#2\endcsname \fi} % so far \def\docopyvalue#1#2#3% {\let\c!internal!\c!internal!n \ifcsname\k!prefix!#3\endcsname \let\c!internal!\c!internal!y \@EA\@EA\@EA\def\@EA \csname\@EA#1\@EA\csname\@EA\k!prefix!\@EA#3\@EA\endcsname\@EA \endcsname\@EA{\csname#2\csname\k!prefix!#3\endcsname\endcsname}% \else \let\c!internal!\c!internal!y \@EA\@EA\@EA\def\@EA \csname\@EA#1\@EA#3\@EA \endcsname\@EA{\csname#2#3\endcsname}% \fi} \endETEX %D We can now redefine some messages that will be %D introduced in the multi||lingual system module. \def\showassignerror #1#2{\showmessage{\m!check}{1}{#1,#2}} \def\showargumenterror#1#2{\showmessage{\m!check}{2}{#1,#2}} \def\showdefinederror #1#2{\showmessage{\m!check}{3}{#1,#2}} %D \CONTEXT\ is a parameter driven package. This means that %D users instruct the system by means of variables, values and %D keywords. These instructions take the form: %D %D \starttypen %D \setupsomething[some variable=some value, another one=a keyword] %D \stoptypen %D %D or by keyword only: %D %D \starttypen %D \dosomething[this way, that way, no way] %D \stoptypen %D %D Because the same variables can occur in more than one setup %D command, we have to be able to distinguish them. This is %D achieved by assigning them a unique prefix. %D %D Imagine a setup command for boxed text, that enables us to %D specify the height and width of the box. Behide the scenes %D the command %D %D \starttypen %D \setupbox [width=12cm, height=3cm] %D \stoptypen %D %D results in something like %D %D \starttypen %D \ {12cm} %D \ {3cm} %D \stoptypen %D %D while a similar command for specifying the page dimensions %D of an \kap{A4} page results in: %D %D \starttypen %D \ {21.0cm} %D \ {27.9cm} %D \stoptypen %D %D The prefixes \type{} and \type{} are hidden from %D users and can therefore be language independant. Variables %D on the other hand, differ for each language: %D %D \starttypen %D \ {} %D \ {} %D \ {} %D \stoptypen %D %D In this example we can see that the assigned values or %D keywords are language dependant too. This will be a %D complication when defining multi||lingual setup files. %D %D A third phenomena is that variables and values can have a %D similar meaning. %D %D \starttypen %D \ {} %D \ {12cm} %D \stoptypen %D %D A (minor) complication is that where in english we use %D \type{}, in dutch we find both \type{} and %D \type{}. This means that when we use some sort of %D translation table, we have to distinguish between the %D variables at the left side and the fixed values at the %D right. %D %D The same goes for commands that are composed of different %D user supplied and/or language specific elements. In english %D we can use: %D %D \starttypen %D \
%D \ %D \stoptypen %D %D But in dutch we have the following: %D %D \starttypen %D \ %D \ %D \stoptypen %D %D These subtle differences automatically lead to a solution %D where variables, values, elements and other components have %D a similar logical name (used in macro's) but a different %D meaning (supplied by the user). %D %D Our solution is one in which the whole system is programmed %D in terms of identifiers with language specific meanings. In %D such an implementation, each fixed variable is available as: %D %D \starttypen %D \ %D \stoptypen %D %D This means that for instance: %D %D \starttypen %D \setupbox[width=12cm] %D \stoptypen %D %D expands to something like: %D %D \starttypen %D \def\boxwidth{12cm} %D \stoptypen %D %D because we don't want to recode the source, a setup command %D in another language has to expand to this variable, so: %D %D \starttypen %D \stelblokin[breedte=12cm] %D \stoptypen %D %D has to result in the definition of \type{\boxwidth} too. %D This method enables us to build compact, fast and readable %D code. %D %D An alternative method, which we considered using, uses a %D more indirect way. In this case, both calls generate a %D different variable: %D %D \starttypen %D \def\boxwidth {12cm} %D \def\boxbreedte {12cm} %D \stoptypen %D %D And because we don't want to recode those megabytes of %D already developed code, this variable has to be called with %D something like: %D %D \starttypen %D \valueof\box\width %D \stoptypen %D %D where \type{\valueof} takes care of the translation of %D \type{width} or \type{breedte} to \type{width} and %D combining this with \type{box} to \type{\boxwidth}. %D %D One advantage of this other scheme is that, within certain %D limits, we can implement an interface that can be switched %D to another language at will, while the current approach %D fixes the interface at startup. There are, by the way, %D other reasons too for not choosing this scheme. Switching %D user generated commands is for instance impossible and a %D dual interface would therefore give a strange mix of %D languages. %D %D Now let's work out the first scheme. Although the left hand %D of the assignment is a variable from the users point of %D view, it is a constant in terms of the system. Both %D \type{width} and \type{breedte} expand to \type{width} %D because in the source we only encounter \type{width}. Such %D system constants are presented as %D %D \starttypen %D \c!width %D \stoptypen %D %D This constant is always equivalent to \type{width}. As we %D can see, we use \type{c!} to mark this one as constant. Its %D dutch counterpart is: %D %D \starttypen %D \c!breedte %D \stoptypen %D %D When we interpret a setup command each variable is %D translated to it's \type{c!} counterpart. This means that %D \type{breedte} and \type{width} expand to \type{\c!breedte} %D and \type{\c!width} which both expand to \type{width}. That %D way user variables become system constants. %D %D The interpretation is done by means of a general setup %D command \type{\getparameters} that we introduced in the %D system module. Let us define some simple setup command: %D %D \starttypen %D \def\setupbox[#1]% %D {\getparameters[\??bx][#1]} %D \stoptypen %D %D This command can be used as: %D %D \starttypen %D \setupbox [width=3cm, height=1cm] %D \stoptypen %D %D Afterwards we have two variables \type{\@@bxwidth} and %D \type{\@@bxheight} which have the values \type{3cm} and %D \type{1cm} assigned. These variables are a combinatiom of %D the setup prefix \type{\??bx}, which expands to \type{@@bx} %D and the translated user supplied variables \type{width} and %D \type{height} or \type{breedte} and \type{hoogte}, %D depending on the actual language. In dutch we just say: %D %D \starttypen %D \stelblokin [breedte=3cm, hoogte=1cm] %D \stoptypen %D %D and get ourselves \type{\@@bxwidth} and \type{\@@bxheight} %D too. In the source of \CONTEXT, we can recognize constants %D and variables on their leading \type{c!}, \type{v!} etc., %D prefixes on \type{??} and composed variables on \type{@@}. %D %D We already saw that user supplied keywords need some %D special treatment too. This time we don't translate the %D keyword, but instead use in the source a variable which %D meaning depends on the interface language. %D %D \starttypen %D \v!left %D \stoptypen %D %D Which can be used in macro's like: %D %D \starttypen %D \processaction %D [\@@bxlocation] %D [ \v!left=>\dosomethingontheleft, %D \v!middle=>\dosomthinginthemiddle, %D \v!right=>\dosomethingontheright] %D \stoptypen %D %D Because variables like \type{\@@bxlocation} can have a lot %D of meanings, including tricky expandable tokens, we cannot %D translate this meaning when we compare. This means that %D \type{\@@bxlocation} can be \type{left} of \type{links} of %D whatever meaning suits the language. But because %D \type{\v!left} also has a meaning that suits the language, %D we are able to compare. %D %D Although we know it sounds confusing we want to state two %D important characteristics of the interface as described: %D %D \startsmaller \em %D user variables become system constants %D \stopsmaller %D %D and %D %D \startsmaller \em %D user constants (keywords) become system variables %D \stopsmaller %D %D \macros %D {startconstants,startvariables} %D %D It's time to introduce the macro's that are responsible for %D this translations process, but first we show how constants %D and variables are defined. We only show two languages and %D a few words. %D %D \starttypen %D \startconstants english dutch %D %D width: width breedte %D height: height hoogte %D %D \stopconstants %D \stoptypen %D %D Keep in mind that what users see as variables, are constants %D for the system. %D %D \starttypen %D \startvariables english dutch %D %D location: left links %D text: text tekst %D %D \stopvariables %D \stoptypen %D %D The macro's responsible for interpreting these setups are %D shared. They take care of empty lines and permit a more or %D less free format. All setups accept the keyword \type{all} %D which equals every language. %D The next few macros come into action when we generate %D interface log files: \newif\iflogginginterface \def\flushinterfaceelementline% {\iflogginginterface \immediate\write\scratchwrite{\interfaceelementline}% \let\interfaceelementline\empty \fi} \def\saveinterfaceelementline#1% {\iflogginginterface \edef\interfaceelementline{\interfaceelementline#1\space}% \fi} \def\startlogginginterface #1 % {\logginginterfacetrue \let\interfaceelementline\empty \immediate\openout\scratchwrite=./#1\relax} \def\stoplogginginterface% {\flushinterfaceelementline \immediate\closeout\scratchwrite \logginginterfacefalse} %D By default we don't log at all. \def\startlogginginterface #1 {} \def\stoplogginginterface {} %D These logging commands are used in the next macros. \def\nointerfaceobject{-} \def\startinterfaceobjects#1#2% {\!!counta=1 \let\dogetinterfaceobject\dogetinterfacetemplate \let\dowithinterfaceelement#1% \def\dodogetinterfaceobjects% {\ifx\next#2% \flushinterfaceelementline \flushinterfaceelementline \let\next\gobbleoneargument \else\ifx\next\par \long\def\next####1% {\dogetinterfaceobjects}% \else\ifx\next\empty \def\next####1% {\dogetinterfaceobjects}% \else \def\next####1 % {\dogetinterfaceobject[####1:\relax]% \dogetinterfaceobjects}% \fi\fi\fi \next}% \def\dogetinterfaceobjects% {\futurelet\next\dodogetinterfaceobjects}% \dogetinterfaceobjects} \def\dogetinterfacetemplate[#1:#2]% {\saveinterfaceelementline{#1}% \doifinsetelse{#1}{\currentinterface,all} {\let\dogetinterfaceobject\doskipinterfaceobject} {\advance\!!counta by 1\relax}} \def\doskipinterfaceobject[#1:#2#3]% {\if#2:% \let\dogetinterfaceobject\dogetinterfaceelement \dogetinterfaceobject[#1:#2#3]% \else \saveinterfaceelementline{#1}% \fi} \let\interfaceelementline\empty \def\dogetinterfaceelement[#1:#2#3]% {\ifx#2:% \!!countb=0 \def\!!stringa{#1}% \flushinterfaceelementline \else \advance\!!countb by 1 \saveinterfaceelementline{#1}% \ifnum\!!countb=\!!counta \@EA\dowithinterfaceelement\@EA{\!!stringa}{#1}% \let\dogetinterfaceobject\doskipinterfaceobject \fi \fi} %D The constants and variables are defined as described. When %D \type{\interfacetranslation} is \type{true}, we also %D generate a reverse translation. Because we don't want to put %D too big a burden on \TEX's hash table, this is no default %D behavior. Reverse translation is used in the commands that %D generate the quick reference cards. We are going to define %D the real \CONTEXT\ commands in an abstract way and generate %D those reference cards for each language without further %D interference. \let\c!internal!y \string \def\c!internal!n {-} \let\c!internal! \c!internal!y \def\setinterfaceconstant#1#2% {\setvalue{\c!prefix!#1}{\c!internal!#1}% \doifelse{#2}{\nointerfaceobject} {\debuggerinfo{constant}{#1 defined as #1 by default}% \setvalue{\k!prefix!#2}{#1}} {\debuggerinfo{constant}{#1 defined as #2}% \ifinterfacetranslation \setvalue{\x!prefix!#1}{#2}% \fi \checksetvalue{\k!prefix!#2}{#1}% \setvalue{\k!prefix!#2}{#1}}} \def\setinterfacevariable#1#2% {\doifelse{#2}{\nointerfaceobject} {\debuggerinfo{variable}{#1 defined as #1 by default}% \checksetvalue{\v!prefix!#1}{#1}% \setvalue{\v!prefix!#1}{#1}} {\debuggerinfo{variable}{#1 defined as #2}% \checksetvalue{\v!prefix!#1}{#2}% \setvalue{\v!prefix!#1}{#2}}} \def\checksetvalue#1#2% {\doifdefined{#1}{\doifvaluesomething{#1}{\doifnotvalue{#1}{#2} {\writestatus{problems}{set #1 to #2 overloads \getvalue{#1}}}}}} \def\startvariables% {\startinterfaceobjects\setinterfacevariable\stopvariables} \def\startconstants% {\startinterfaceobjects\setinterfaceconstant\stopconstants} %D \macros %D {defineinterfaceconstant} %D %D Next we redefine a previously defined macro to take care of %D interface translation too. It's a bit redundant, because %D in these situations we could use the c||version, but for %D documentation purposes the x||alternative comes in handy. \def\defineinterfaceconstant#1#2% {\setvalue{\c!prefix!#1}{#2}% \ifinterfacetranslation \setvalue{\x!prefix!#1}{#2}% \fi} %D \macros %D {startinterfacesetupconstant} %D %D The next command, \type{\startinterfacesetupconstant}, which %D behavior also depends on the boolean, is used for constants %D that are only needed in these quick reference macro's. The %D following, more efficient approach does not work here, %D because it sometimes generates spaces. %D %D \starttypen %D \def\setinterfacesetupconstant% %D {\ifinterfacetranslation %D \expandafter\setinterfaceconstant %D \fi} %D \stoptypen %D %D We therefore use the more redundant but robust method: \def\setinterfacesetupvariable#1#2% {\ifinterfacetranslation \doifelse{#2}{\nointerfaceobject} {\setvalue{\y!prefix!#1}{#1}} {\setvalue{\y!prefix!#1}{#2}}% \fi} \def\startsetupvariables% {\startinterfaceobjects\setinterfacesetupvariable\stopsetupvariables} %D \macros %D {startelements} %D %D Due to the object oriented nature of \CONTEXT, we also need %D to define the elements that are used to build commands: %D %D \starttypen %D \startelements english dutch %D %D beginvan: begin beginvan %D eindvan: end eindvan %D start: start start %D stop: stop stop %D %D \stopelements %D \stoptypen %D %D Such elements sometimes are the same in diferent %D languages, but mostly they differ. Things can get even %D confusing when we look at for instance the setup commands. %D In english we say \type{\setup}, but in dutch we %D have: \type{\stelin}. Such split elements are no %D problem, because we just define two elements. When no second %D part is needed, we use a \type{-}: %D %D \starttypen %D \startelements english dutch %D %D setupa: setup stel %D setupb: - in %D %D \stopelements %D \stoptypen %D %D Element translation is realized by means of: \def\setinterfaceelement#1#2% {\doifelse{#2}{\nointerfaceobject} {\debuggerinfo{element}{#1 defined as }% \resetvalue{\e!prefix!#1}} {\doifdefinedelse{\e!prefix!#1} {\doifnot{\getvalue{\e!prefix!#1}}{#2} {\debuggerinfo{element}{#1 redefined as #2}% \setvalue{\e!prefix!#1}{#2}}} {\debuggerinfo{element}{#1 defined as #2}% \setvalue{\e!prefix!#1}{#2}}}} \def\startelements% {\startinterfaceobjects\setinterfaceelement\stopelements} %D \macros %D {startcommands} %D {} %D %D The last setup has to do with the commands themselve. %D Commands are defined as: %D %D \starttypen %D \startcommands english dutch %D %D starttekst: starttext starttekst %D stoptekst: stoptext stoptekst %D omlijnd: framed omlijnd %D margewoord: marginword margewoord %D %D \stopcommands %D \stoptypen %D %D Here we also have to take care of the optional translation %D needed for reference cards. \def\setinterfacecommand#1#2% {\doifelse{#2}{\nointerfaceobject} {\debuggerinfo{command}{no link to #1}% \setinterfacesetupvariable{#1}{#1}} {\doifelse{#1}{#2} {\debuggerinfo{command}{#1 remains #1}} {\doifdefinedelse{#2} {\debuggerinfo{command}{core command #2 redefined as #1}}% {\debuggerinfo{command}{#2 defined as #1}}% \@EA\@EA\@EA\def\@EA\csname\@EA#2\@EA\endcsname \@EA{\csname#1\endcsname}}% \setinterfacesetupvariable{#1}{#2}}} \def\startcommands% {\startinterfaceobjects\setinterfacecommand\stopcommands} %D \macros %D {getinterfaceconstant, getinterfacevariable} %D {} %D %D Generating the interface translation macro's that are used %D in the reference lists, is enabled by setting the boolean: %D %D \starttypen %D \interfacetranslationtrue %D \stoptypen %D %D Keep in mind that enabling interfacetranslation costs a %D bit of hash space. \newif\ifinterfacetranslation \def\getinterfaceconstant#1% {\ifinterfacetranslation \doifdefinedelse{\x!prefix!#1} {\getvalue{\x!prefix!#1}} {#1}% \else #1% \fi} \def\getinterfacevariable#1% {\ifinterfacetranslation \doifdefinedelse{\y!prefix!#1} {\getvalue{\y!prefix!#1}} {#1}% \else #1% \fi} %D When a reference list is generated, one does not need to %D generate a new format. Just reloading the relevant %D definition files suits: %D %D \starttypen %D \interfacetranslationtrue %D \input mult-con %D \input mult-com %D \stoptypen %D \macros %D {interfaced} %D %D The setup commands translate the constants automatically. %D When we want to translate 'by hand' we can use the simple %D but effective command: %D %D \starttypen %D \interfaced {something} %D \stoptypen %D %D Giving \type{\interfaced{breedte}} results in \type{width} %D or, when not defined, in \type{breedte} itself. This %D macro is used in the font switching mechanism. \beginTEX \def\interfaced#1% {\expandafter\ifx\csname\k!prefix!#1\endcsname\relax #1% \else \csname\k!prefix!#1\endcsname \fi} \endTEX \beginETEX \ifcsname \def\interfaced#1% {\ifcsname\k!prefix!#1\endcsname \csname\k!prefix!#1\endcsname \else #1% \fi} \endETEX %D So much for the basic multi||lingual interface commands. The %D macro's can be enhanced with more testing facilities, but %D for the moment they suffice. %D Out of convenience we define the banners here. \edef\contextbanner% {ConTeXt \space ver: \noexpand \contextversion \space \space fmt: \noexpand \formatversion \space \space int: \noexpand \currentinterface \space \space mes: \noexpand \currentresponses} \def\showcontextbanner% {\writeline\writestring{\contextbanner}\writeline} \edef\formatversion% {\ifx\normalyear \undefined\the\year \else\the\normalyear \fi.% \ifx\normalmonth\undefined\the\month\else\the\normalmonth\fi.% \ifx\normalday \undefined\the\day \else\the\normalday \fi} \ifx\contextversion\undefined \def\contextversion{unknown} \fi \ifx\undefined\normaldump \newtoks\everydump \let\normaldump\dump \def\dump{\the\everydump\normaldump} \fi \appendtoks \showcontextbanner \to \everydump \protect \endinput