11.7 Multi-lingual applications

XPCE provides some support for building multi-lingual applications without explicitly mapping terms all the time. This section provides an overview of how multi-lingual operation was realised in a simulator for optics.

When writing a multi-lingual application, several different types of information needs to be translated. We will discuss each of them below.

Below is a summary of the file language.pl as using in the optics simulator to reach at an English/Dutch application.


:- module(language,
          [ message/2,                  % Id, Message
            current_language/1,         % -Language
            set_language/1              % +Language
          ]).
:- use_module(pce).
:- use_module(configdb).
:- require([ concat_atom/2
           , is_list/1
           , memberchk/2
           ]).

:- dynamic
        current_language/1.

current_language(english).              % the default
%current_language(dutch).

set_language(Lan) :-
        retractall(current_language(_)),
        assert(current_language(Lan)),
        make_errors.

%       message(+Term, -Translation)
%       The heart of the translator. Map a term
%       (normally an atom, but if can be an arbitrary
%       Prolog term, into an image or atom. If no
%       translation is found, the default case and
%       underscore translation is performed.

message(Term, Translation) :-
        current_language(Lan),
        term(Term, Translations),
        (   is_list(Translations)
        ->  T =.. [Lan, Translation0],
            memberchk(T, Translations),
            (   is_list(Translation0)
            ->  concat_atom(Translation0, Translation)
            ;   Translation = Translation0
            )
        ;   Translation = Translations
        ), !.
message(Term, Translation) :-
        get(Term, label_name, Translation).


                 /*******************************
                 *    MAP DIALOG IDENTIFIERS    *
                 *******************************/

:- pce_extend_class(dialog_item).

label_name(DI, Id:name, Label:'name|image') :<-
        "Multi-lingual label service"::
        message(Id, Label0),
        (   atomic(Label0)
        ->  get(DI, label_suffix, Suffix),
            get(Label0, ensure_suffix, Suffix, Label)
        ;   Label = Label0
        ).

:- pce_end_class.

:- pce_extend_class(dialog_group).

label_name(_DI, Id:name, Label:name) :<-
        "Multi-lingual label service"::
        (   message(Id, Label),
            atomic(Label)
        ->  true
        ;   get(Id, label_name, Label)
        ).

:- pce_end_class.

:- pce_extend_class(menu_item).

default_label(_MI, Id:name, Label:'name|image') :<-
        "Multilingual label service"::
        message(Id, Label).

:- pce_end_class.

                 /*******************************
                 *        GENERIC LABELS        *
                 *******************************/

%       term(+Term, -Translated)
%
%       Term translates a term. There are three examples
%       here. The first only contains the translation
%       for an English label name into a Dutch one. The
%       second replaces all labels named 
%       image. The last is for generating a more
%       elaborate message from an identifier.

term(settings,
     [ dutch('Instellingen')
     ]).
term(label,
     image('label.lbl')).
term(start_named_test(Name),
     [ english(['Click "OK" to start test "', Name, '"']),
       dutch(['Klik op "OK" om aan de toets "', Name,
              '" te beginnen'])
     ]).
     

                 /*******************************
                 *             ERRORS           *
                 *******************************/

%       error(Id, Kind, Translations)
%
%       Specify and create the required error messages.
%       An object that detects there are too many
%       instruments directs this information to the user
%       by
%
%               ...
%               send(MySelf, error, max_instruments, 5),
%               ...

error(max_instruments, error,
      [ dutch('%IU kunt niet meer dan %d van deze \
               instrumenten gebruiken'),
        english('%IYou can not use more than %d of \
                 these instruments')
      ]).

make_errors :-
        current_language(Lan),
        T =.. [Lan, Message],
        error(Id, Kind, Messages),
        (   memberchk(T, Messages)
        ->  true
        ;   Message = Id
        ),
        new(_E, error(Id, Message, Kind, report)),
        fail.
make_errors.

:- initialization make_errors.