#ifndef LANGUAGE_H
#define LANGUAGE_H
/* To hard code phrases in the executable:

    #define HARDCODE_PHRASES

   in your program before the #include <language.h>

   You should use HARDCODE_PHRASES when your application consists of
   a single executable file in which the phrases will be used.
   If your application consists of several separate programs which
   share many of the same phrases, you should use the load phrases option.

*/

/* language.h

   This C/C++ module will help provide translation of text strings
	to different human languages.  UNIX, AMIGADOS, and Borland C++,
   Both ANSI standard C or K&R function declarations are supported.

   Written by Roger Nelson

		 Biological Systems Engr. Dept.
       Washington State University
       Pullman, WA 99164-6120

       Comments, suggestions, questions and bug reports can be sent to:
       rnelson@wsuaix.csc.wsu.edu

       Phone: (509)335-1100  or 335-1578 (main office)
       Home:  (509)332-8387
       FAX  : (509)335-2722

   An equivelent module for the programming language Pascal is also available.

   -------
	1.00 Jan. 1993
   1.01 Apr. 1993   Added support for Window PChar strings (Use Win_translate)
                   Added remove_tilde function.
   1.02 May. 1993   Just added some additional documentation.
                   Added dialect optimization feature.
                   Added language equivalence feature.
   1.03 Spt.9 1993  Procedure declarations now support non-standard C.
                   Fixed bug in language_load() which sometimes caused
                   Parsing of the phrases file to be confused.
   1.04 Spt.25 1993 Use of ISO standard language codes improves efficiency.
						 New function language_name();
                   New function language_windows2ISO();
   1.05 Oct.19 1993 Phrases can now be hardcoded in the program for
                   faster operations, and simpler UNIX support.
                   In this mode language_set() replaces language_load(),
                   language_init() and language_end().
   1.06 Feb. 1 1994 The C language library now includes the
                   Universal character set conversion utility library.
	1.07 May. 4 1994 Added include sentinel.
   1.08 Oct. 6 1994 A few compiler corrections.
                    Removed list of contries the language is used in because
                    this is seldom used and just takes memory.

   Thanks to:

     Andreas Scherer
     Dipl.-Math., Stud. O.R. an der RWTH Aachen
     Roland-Straße 16
     52070 Aachen, Deutschland (Germany)
     <scherer@genesis.informatik.rwth-aachen.de>
     For several corrections for ANSI C++ and Amiga SAS/C++



	Future plans

   1. When loading the phrases file, I would like to allow the programmer
      to specify the name of the phrases file, so that an application
      could use several phrases files.  This may make the phrases files
      easier to maintain and remove the need for the program list for
      each phrase.

   -------

   OVERVIEW:

   This unit is a facility to provide multiple human language support.
   This unit differs from other similar units in the following ways.

   1. All phrases for all languages are stored in a single file.
      This is advantageous because it is easier to maintain the phrases;
      when you make a change to a phrase you can easily see that you need
      to make the change for the other languages.
      Problems with this approach is that the language name tag becomes
      redundent.  One could leave the tag off, but this could be too
      confusing with many languages. To resolve this problem I am using
      the ISO standard 2 character language code (I will replace this
      with the standard 3 character language codes when I get a hold of them.

      Another approach would be to store the phrases in seperate files
      and or directorys by language. That approach is advantageous in
      that it requires less space, but it is more difficult to maintain.

      Future versions of this language unit will probably offer both
      options.  The latter approach makes it easier to exclude languages
      from the application software distribution

   2. The phrases file itself is loaded into the program at compile time
		for generating the phrases ID enumeration.  This makes it harder
      to inadvertently leave out a phrase from the phrases file and also
      reduces the chances of duplication.

   3. When the program is compiled with HARDCODE_PHRASES #defined.
      The phrases are hardcoded in the executable. When this is not
      defined, the he phrases file may be modified by the end user for
      corrections and or additional localizations.

      This may not be desirable since the user may accidently corrupt
      the phrases file.

   4. The format of the phrases file is very simple, making it easier
      to add localizations or corrections.

   5. This unit is intended for 7/8-bit European like character sets.
      (Right to left or top to bottom orientation).  However this is a simple
      message catalog and should work for any 7/8-bit character set language.

   6. This unit allows multiple programs to share a phrases file, this
      cuts down on duplicatation.

   7. This unit provides optimization features for dialects.


   Phrases are stored in the phrases file.

   When the program is compiled with HARDCODE_PHRASES defined to hard code
   the phrases in the executable, the program hcphrases must be first run
   to generate the file phrases.h. phrases.h must be placed in the same
   directory as your source code.  (You don't need to put it in the
   directory where the language.c file resides, language.h will read phrases.h
   from the current working directory.)

   When the program is compiled to load the phrases file, the phrases file
   must be placed in in the same directory as the application program
   executables. (The phrases file must also be available to the compiler
   when compiling the program.)

   The phrases file entries each have the following format which allows
   for the compiler to double check the existance of a phrase so you
   can't inadvertantly leave out a phrase from your translations!!!!

    phraseID,
    / * programlist
    en English phrase
	 es Spanish phrase
    it Italian phrase
    fr French phrase
       :
       :
    * /
    NextphrasesID,
       :
       :

   Note / * and * / are actually the C comment characters!

   The phraseID must be a unique valid Identifier and must be
   followed by a comma. The phraseID and comma must be on their own line.

   After the first comment (on the same line) is a list of all programs in
   which the phrase is used, only those phrases used by the program will
   be loaded. This is useful if your application consists of several programs,
   but where not all phrases are used in all the programs.

   Each translation must be on its own line, the name of the language
   must be uppercase with consistent spelling and one word.

	There must be only one space or one tab character seperating the
   language name code from the phrase.

   There must not be any blank lines between the * / and the next phrase ID.

   If the phrase is to be a null string, then use
   an underscore character _,  Ie:  EN _



LANGUAGE DIALECTS

   At the top of the file is a dialect equivalences list. For example:

   / * DIALEKTOJ
   es ES_CASTILLIAN ES_MEXICAN ES_COLOMBIAN
   fr FR_CANADIAN FR_MOROCCAN
   * /
   ^- C comment characters.

   This says if the language to load is ES_CASTILLIAN, read and use the
   Spanish phrase unless a Castilian phrases is specifically provided.

	The first label on the line is the base language the remaining labels
   are the dialects of that language.

   The dialects line must not exceed 256 characters a dialect can be
   continued on the next line with the first label repeating the base
   language name.  For the dialect names, I would recommend composing
   the dialect name from the base language code and the ISO standard
   country code or the dialect name itself (as I have done here).
   some dialects already have an ISO standard language code.

   At this time it is not possible to make a hierachical dialect
   dependency.  I.e. the following is NOT valid:

   / * DIALEKTOJ
   es ES_CASTILIAN ES_MEXICIAN
   ES_MEXICIAN ES_YUKATAN
   * /
   ^- C comment characters.

   ES_YUKATAN should be es

   If no dialects are provided, the following should appear at the top
   of the file:

   / * DIALECTOJ
   * /


LANGUAGE EQUIVALENCES

   This optimization feature can be used to handle special cases of
   dialect variations.  For example, one may have several dialects
   of ES (Spanish) where most phrases will be the same for most dialects,
   but there may be a regional variation which is the same as another
   regional variation, but not the same as the base language. I.e.

      L_a_phrase,
      / * MYAPP
      en aaaa bbbb ccc
      ES_COLOMBIAN=ES_MEXICIAN
      ES_MEXICIAN XXXXX wwww zzzz
      es xxxx yyyy zzzz
      * /
      ^- C comment characters so remove the space!

   In this case, Castialian and Peruvian will simply use the SPANISH
	phrase, but Mexican will have a separate phrase which will also
   be used by COLOMBIAN. The equivalence is used to avoid having the
   MEXICIAN phrase duplicated in the COLOMBIAN phrases.

   This may also be useful for similar languages such as Scandinavian
   languages or for phrases or terms which are the same no matter what
   the language is.

THE LINGVO ENTRY

   The very first phrase in PHRASES.LNG must be the translation for the
   name of the language:

      LINGVO,
      / * PROGRAM1 PROGRAM2
      en English
      fr Francais
      es Espanol
      it Italiano
      * /
      ^- C comment characters so remove the space!

   The LINGVOJ entry immediately follows the DIALEKTOJ.

Footnote:

   1. "dialektoj" and "lingvo" are the Esperanto words for
      "dialects" and "language" respectively.

   2. The language name tag can be anything, but it must be uppercase.
      Preferably the programmer will use the ISO language codes.


Tips for restarting a TurboVision application with a new application.

  You may want to allow the user to change the language within the
  application.  The following example shows how to load another language
  when the HARDCODE_PHRASES options is NOT used.

  The easiest thing to do is shutdown and restart TurboVision.

  1. Create a boolean variable that will be used to test for the actual exit
     of the application.

  2. Put a while loop using this variable as the test around the application
     init, run and done procedures.

  3. Call the language_init function near the beginning of the program.
     Call the language_end function near the end of the program.

  4. Usually object registration for TurboVision is done in the
     application.init procedure.
     Move these registrations to a point before the exit_application loop
     otherwise TurboVision will complain about stream registration when
     init gets call more than once.

  5. Provide menu options for changing the language.
     This may be a user preferences dialog box or submenus etc...

  6. Provide an application event handler point for each language:

    I.e.
    case cmLanguageDefault :
         language_load(getenv("LANGUAGE"),argv_0);
         message(this,evCommand,cmQUIT,0);
         break;
    case cmLanguageEnglish :
         language_load("en",argvr_0);
         message(this,evCommand,cmQUIT,0);
			break;
    case cmLanguageFrench  :
         language_load("fr",argv_0);
         message(this,evCommand,cmQUIT,0);
         break;
    case cmLanguageSpanish :
         language_load("es",argv_0);
         message(this,evCommand,cmQUIT,0;
         break;
    case cmLanguageItalian :
         language_load("it",argv_0);
         message(this,evCommand,cmQUIT,0);
         break;

      Where argv_0 is a char * set to argv_0 at the beginning of main.

  7. When you actually want to exit the program with cmQUIT, set
     exit_application to TRUE:

      case cmExit_MyApp :
          exit_application = 1;
          message(this,evCommand,cmQUIT,0);
       break;

  8. To use a phrase translation simply call tranlate() with the phrase_Id
     Ie.
     printf("%s (%s)",translate(L_mouse),translate(L_Not_available));

I.e. The main module of the program MYAPP would look something like this:

main(int argc; char *argv[0]);
{
  argv_0 = argv[0];


  // Get the default language from the DOS environment variable LANGUAGE,
  // set before running the program. If the environment variable doesn't
  // exist, then language_init will use ENGLISH.


  if (!language_init(getenv("LANGUAGE"),program_dir(argv[0])),"MYAPP")
  { printf("Unable to open language translation file: PHRASES.LNG\n"
             "This file should be placed in the same directory as %s\n",argv[0]);
    exit(1);
  };

  RegisterObjects;
  RegisterViews;
  RegisterMenus;
  RegisterDialogs;
  RegisterApp;
  RegisterHelpFile;

  exit_application = 0;                //  <- global variable
  while (!exit_application)
  {
     theapplication.Init;
     theapplication.Run;
     theapplication.Done;
  };

  language_end();
};

*/

#include <stdio.h>

#ifndef char_8bit
#ifdef __BCPLUSPLUS__
#define char_8bit  char
#else
#define char_8bit unsigned char
#endif
#endif

struct ISO2coding
{
  char *code;
  char *language; /* In English */
  /*char *places;  Countries/regions where language is used */
};


#ifdef HARDCODE_PHRASES
#include "phrases.h"
#else
enum phrases {
#include "phrases.lng"
LANGUAGE_END_PHRASES };
#endif


struct language_available
{
  char *name;
  char *desc;
  struct language_available *next;
};

extern  struct language_available *languages_available;  /* List of available languages*/
extern  char *language_current_code;              /* active language */

/* program_name is a fully qualified filename: i.e.  C:\APPDIR\MYAPP.EXE
   Usually just use argv[0].
*/

#if defined(__STDC__) || defined(__cplusplus)
/*
   When using the HARDCODE_PHRASES option the function sets the language
   to translate to and can be called anytime as often as needed to
*/
#ifdef HARDCODE_PHRASES
/* language_set set the current language to translate to.
   It is used in HARDCODE_PHRASES mode in lieu of language_init()
   and language_load().
   language_set may be called as many times as desired any where in the
   program, You will want to use it at the beginning of the program.
   If no language is set, the first language in the LINGVO entry is
	used.  Therefore, if you want the default language to be English,
	English should be the first entry in the LINGVO entry.
*/
extern int language_set(char *language_name);

#else
/* language_init should be called near the beginning of the program.
   None of the other functions must be called before this function.
   This function must only be called once.
*/
extern int language_init
(char *language_name,
 char *program_name,
 char *program_dir,
 char *phrases_filename);

/* language_load is usually used internally by language_init(),
	but may be used by the programmer to allow the user to change the
   language on the fly.

   language_load returns 1 if the translations loaded successfully
   0 if the file is not found or corrupt.
*/
extern int language_load
(char *language_name,
 char *program_name,
 char *program_dir,
 char *phrases_filename);

/* language_end should be called near the end of the program.
   It deallocates the memory used by the translation list.
   This function must only be called once.
*/
extern void language_end(void);

#endif

/* translate() is used in place of literal strings.
   The programmer should not modify the returned string; if the string
   must be modified, strcpy the string into a seperate buffer.
*/
extern char *translate(long phrase_ID);

/*Remove_tilde removes tilde characters from the phrase string.
  and places the result in newphrase.
  A pointer to newphrase is returned.
  The program must provide a sufficiently sized buffer to store newphrase.
  Tilde characters are used in TurboVision to highlight text in gadgets.
*/
extern char *remove_tilde(char *phrase, char *newphrase);

/* language_list_available lists the codes/names for the languages
   and dialects available in the file to the provided output file.

   Normally this function can be called on stdout or stderr to display
	the languages to choose from, and the program may then prompt the
   user to enter the code for the language to use.

   When using HARDCODE_PHRASES, the language_init must be called first!
*/
void language_list_available(FILE *dest);

/* Given an ISO standard 2 letter language code, return the
	English name of the language
*/
extern char *language_name(char *language_name_code);

#ifdef _Windows
/* Given an MS Window language code, return the two digit ISO language code.
*/
extern char *language_MSWindows2ISO2(unsigned int windowscode);
#endif

#else

extern int language_init();
#ifndef HARDCODE_PHRASES
extern int language_load();
extern void language_end();
#endif
extern char *translate();
extern char *remove_tilde();
extern char *language_name();
extern void language_list_available();

#ifdef _Windows
/* Given an MS Window language code, return the two digit ISO language code.*/
extern char *language_MSWindows2ISO2();
#endif

#endif

#endif
