Internationalisation

.


Formatting date and time


In Windows "Control Panel" / "Regional Settings" you can choose a Locale and change several formats for that Locale. However Progress displays dates and times using its own display formats.
You can use GetDateFormatA or GetTimeFormatA to format a date or time according to Windows settings. The resulting character string can be useful for reports or display-only fields. When you call GetDateFormatA or GetTimeFormatA you will probably want it to use the current locale, although it is also possible to use any non-current locale as demonstrated in the above example window.

/* these prototypes are declared in windows.p.
   constants are declared in {i18n.i}.
   i18n.i is available in everything.zip */
 
PROCEDURE GetDateFormatA EXTERNAL "KERNEL32" :
   DEFINE INPUT PARAMETER        Locale      AS LONG.
   DEFINE INPUT PARAMETER        dwFlags     AS LONG.
   DEFINE INPUT PARAMETER        lpTime      AS LONG.
   DEFINE INPUT PARAMETER        lpFormat    AS LONG.
   DEFINE INPUT-OUTPUT PARAMETER lpDateStr   AS CHARACTER.
   DEFINE INPUT PARAMETER        cchDate     AS LONG.
   DEFINE RETURN PARAMETER       cchReturned AS LONG.
END PROCEDURE.
 
PROCEDURE GetTimeFormatA EXTERNAL "KERNEL32" :
   DEFINE INPUT PARAMETER        Locale    AS LONG.
   DEFINE INPUT PARAMETER        dwFlags   AS LONG.
   DEFINE INPUT PARAMETER        lpTime    AS LONG.
   DEFINE INPUT PARAMETER        lpFormat  AS LONG.
   DEFINE INPUT-OUTPUT PARAMETER lpTimeStr AS CHARACTER.
   DEFINE INPUT PARAMETER        cchTime   AS LONG.
   DEFINE RETURN PARAMETER       cchReturned AS LONG.
END PROCEDURE.

Parameter lpTime is a MEMPTR to a SYSTEMTIME structure. lpTime=0 will use the current system date/time.
Parameter lpFormat is a pointer to a format string. lpFormat=0 will use the format as specified in Control Panel. There are numerous possibilities, you best check the help file in Control Panel for examples.
Parameter lpTimeString is the returned character string. The memory for this string must be allocated in your P4GL program as usual. The size of this allocated string must be supplied in cchTime.
The demo window was based on a radio set with a couple of Language ID's:

{i18n.i}
 
DEFINE VARIABLE RD-LANGID AS INTEGER 
     VIEW-AS RADIO-SET VERTICAL
     RADIO-BUTTONS 
          "LOCALE_USER_DEFAULT", {&LOCALE_USER_DEFAULT},
          "LOCALE_SYSTEM_DEFAULT", {&LOCALE_SYSTEM_DEFAULT},
          "Dutch", {&LANGID_DUTCH},
          "French", {&LANGID_FRENCH},
          "German", {&LANGID_GERMAN}, 
          "Spanish", {&LANGID_SPANISH},
          "English", {&LANGID_ENGLISH},
          "Italian", {&LANGID_ITALIAN}
     SIZE 34 BY 5.24 NO-UNDO.
--------------------------------------------------------------------------------
ON VALUE-CHANGED OF RD-LANGID IN FRAME DEFAULT-FRAME
DO:
  ASSIGN rd-langid.
 
  DEFINE VARIABLE chDate AS CHARACTER NO-UNDO.
  DEFINE VARIABLE cchRet AS INTEGER NO-UNDO.
 
  chDate = FILL("x",50).
  RUN GetDateFormatA IN hpApi( RD-LANGID ,
                               2,
                               0,
                               0,
                               INPUT-OUTPUT chDate,
                               LENGTH(chDate),
                               OUTPUT cchRet
                             ).  
  fill-in-longdate:SCREEN-VALUE = chDate.
 
 
  chDate = FILL("x",50).
  RUN GetDateFormatA IN hpApi( RD-LANGID ,
                               1,
                               0,
                               0,
                               INPUT-OUTPUT chDate,
                               LENGTH(chDate),
                               OUTPUT cchRet
                             ).  
  fill-in-shortdate:SCREEN-VALUE = chDate.
 
 
  chDate = FILL("x",50).
  RUN GetTimeFormatA IN hpApi( RD-LANGID ,
                               0,
                               0,
                               0,
                               INPUT-OUTPUT chDate,
                               LENGTH(chDate),
                               OUTPUT cchRet
                             ).  
  fill-in-time:SCREEN-VALUE = chDate.
END.

This example passes 0 for lpTime so it will always format the current system time. To format any other date or time you will have to pass a MEMPTR to an initialized SYSTEMTIME structure, for example:

{i18n.i}
 
  DEFINE VARIABLE cchRet AS INTEGER NO-UNDO.
  DEFINE VARIABLE lpTime AS MEMPTR  NO-UNDO.
  SET-SIZE (lpTime)    =   16.
  PUT-SHORT(lpTime, 1) = 1998.  /* = year                  */
  PUT-SHORT(lpTime, 3) =    6.  /* = month                 */
  PUT-SHORT(lpTime, 5) =    5.  /* = day of week, ignored  */
  PUT-SHORT(lpTime, 7) =   26.  /* = day                   */
  PUT-SHORT(lpTime, 9) =   21.  /* = hour                  */
  PUT-SHORT(lpTime,11) =   42.  /* = minute                */
  PUT-SHORT(lpTime,13) =   21.  /* = seconds               */
  PUT-SHORT(lpTime,15) =    4.  /* = milliseconds          */
 
  chDate = FILL("x",50).
  RUN GetDateFormatA IN hpApi( RD-LANGID ,
                               0,
                               GET-POINTER-VALUE(lpTime),
                               0,
                               INPUT-OUTPUT chDate,
                               LENGTH(chDate),
                               OUTPUT cchRet
                             ).  
  SET-SIZE(lpTime) = 0.

Local names for dates and months

Procedure GetLocaleInfoA can be used to retrieve all the information entered in "Control Panel / Regional Settings", both for the current locale and for all other locales. This can be useful for lots of things like displaying the actual names for days and months.
The demo window, shown in the picture, allows to choose a locale and fills a couple of selection lists showing the month names, abbreviated month names, day names and abbreviated day names. It uses the following definitions:

/* Procedure GetLocaleInfoA is declared in windows.p.
   Use includefile {i18n.i} to use declared constants.
   i18n.i is part of everything.zip */
 
PROCEDURE GetLocaleInfoA EXTERNAL "kernel32" :
   DEFINE INPUT PARAMETER        Locale      AS LONG.
   DEFINE INPUT PARAMETER        dwFlags     AS LONG.
   DEFINE INPUT-OUTPUT PARAMETER lpLCData    AS CHARACTER.
   DEFINE INPUT PARAMETER        cchData     AS LONG.
   DEFINE RETURN PARAMETER       cchReturned AS LONG.
END PROCEDURE.

The radio set in the window is defined as:

{i18n.i}
 
DEFINE VARIABLE RD-LANGID AS INTEGER 
     VIEW-AS RADIO-SET VERTICAL
     RADIO-BUTTONS 
          "LOCALE_USER_DEFAULT", {&LOCALE_USER_DEFAULT},
          "LOCALE_SYSTEM_DEFAULT", {&LOCALE_SYSTEM_DEFAULT},
          "Dutch", {&LANGID_DUTCH},
          "French", {&LANGID_FRENCH},
          "German", {&LANGID_GERMAN}, 
          "Spanish", {&LANGID_SPANISH},
          "English", {&LANGID_ENGLISH},
          "Italian", {&LANGID_ITALIAN}
     SIZE 34 BY 5.24 NO-UNDO.
 
--------------------------------------------------------------------------------
ON VALUE-CHANGED OF RD-LANGID IN FRAME DEFAULT-FRAME
DO:
  ASSIGN rd-langid.
 
  DEFINE VARIABLE chName AS CHARACTER    NO-UNDO.
  DEFINE VARIABLE i      AS INTEGER NO-UNDO.
  DEFINE VARIABLE cchRet AS INTEGER NO-UNDO.
 
  SELECT-day:LIST-ITEMS="".
  DO i=0 TO 6 :  
    chName = FILL("x",50).
    RUN GetLocaleInfoA IN hpApi ( RD-LANGID ,
                                  {&LOCALE_SDAYNAME1} + i,
                                  INPUT-OUTPUT chName,
                                  LENGTH(chName),
                                  OUTPUT cchRet
                                ).  
    SELECT-day:ADD-LAST(chName).
  END.
 
  SELECT-abbrevday:LIST-ITEMS="".
  DO i=0 TO 6 :  
    chName = FILL("x",50).
    RUN GetLocaleInfoA IN hpApi( RD-LANGID ,
                                 {&LOCALE_SABBREVDAYNAME1} + i,
                                 INPUT-OUTPUT chName,
                                 LENGTH(chName),
                                 OUTPUT cchRet
                               ).  
    SELECT-abbrevday:ADD-LAST(chName).
  END.
 
  SELECT-month:LIST-ITEMS="".
  DO i=0 TO 11 :  
    chName = FILL("x",50).
    RUN GetLocaleInfoA IN hpApi ( RD-LANGID ,
                                  {&LOCALE_SMONTHNAME1} + i,
                                  INPUT-OUTPUT chName,
                                  LENGTH(chName),
                                  OUTPUT cchRet
                                ).  
    SELECT-month:ADD-LAST(chName).
  END.
 
  SELECT-abbrevmonth:LIST-ITEMS="".
  DO i=0 TO 11 :  
    chName = FILL("x",50).
    RUN GetLocaleInfoA IN hpApi ( RD-LANGID ,
                                  {&LOCALE_SABBREVMONTHNAME1} + i,
                                  INPUT-OUTPUT chName,
                                  LENGTH(chName),
                                  OUTPUT cchRet
                                ).  
    SELECT-abbrevmonth:ADD-LAST(chName).
  END.
END.

Right to Left in FILL-INs and EDITORs etc

Found in an e-mail to Peg, sent by Torben Jensby Christensen

We have been experimenting with mixing Arabic and standard Western Eropean
fields on the same screen.

For this to work as seamlessly as possible for the users we are changing
keyboard and writing direction on every field entry.

Following code is working with Progress 9.1

DEFINE VARIABLE we-keyboard AS CHARACTER INIT "00000409":U  NO-UNDO.
DEFINE VARIABLE arabic-keyboard AS CHARACTER INIT "00000429":U  NO-UNDO.

/* Used for change input keyboard behaviour (Arabic) */
PROCEDURE LoadKeyboardLayoutA EXTERNAL "user32.dll":
   /*
   Input paramets
      klid : keyboard layout id
             00000401: Arabic (Saudi Arabia, Iraq, Egypt, Libya, Algeria,
Jordan ....)
             00000402: Bulgaria
             00000405: Czech
             00000406: Danish
             00000407: German Standard
             00000409: English US
             0000040a: Spanish
             0000040b: Finnish
             0000040c: French_Standard
             0000040d: Hebrew
             00000410: Italian
             00000413: Dutch_Standard
             00000414: Norwegian
             00000415: Polish
             0000041a: Croatian
             0000041d: Swedish
             00000429: Farsi

             00000807: German_Swiss
             00000809: English United Kingdom
             0000080a: Spanish Latin
             0000080c: French_Belgian
             00000813: Dutch_Belgian
             00000816: Portuguese
      flags: specifies how the keyboard layout is to be loaded
             KLF_ACTIVATE    &1H
             KLF_NOTELLSHEL
             KLF_REORDER
             KLF_REPLACELANG
             KLF_SUBSTITUTE_OK
             KLF_UNLOADPREVIOUS

   See keyboard layout id at:
http://www.microsoft.com/globaldev/winxp/xp-lcid.asp
   */
   DEFINE INPUT PARAMETER klid  AS CHARACTER.
   DEFINE INPUT PARAMETER flags AS LONG.
END.

FUNCTION set-keyboard RETURNS LOGICAL (INPUT lng AS CHAR ).
   DEFINE VARIABLE klid AS CHARACTER INIT "00000409":U NO-UNDO.
   IF lng <> "ARABIC":U AND lng <> "NORMAL":U THEN DO:
      MESSAGE "set-keyboard":U SKIP
         "Must be called with Arabic or normal":U SKIP
         lng
         VIEW-AS ALERT-BOX ERROR BUTTONS OK.
      RETURN FALSE.
   END.
   IF lng = "ARABIC":U THEN DO:
      /* klid = "00000429":U. arabic farsi keyboard */
      klid = arabic-keyboard.
   END.
   ELSE DO:
      /* klid = "00000409":U. English US keyboard */
      klid = we-keyboard.
   END.
   ASSIGN klid = "00000409":U WHEN klid = "".
   RUN LoadKeyboardLayoutA IN THIS-PROCEDURE (INPUT klid,INPUT 1). /* arabic farsi keyboard */
   RETURN TRUE.
END FUNCTION.

FUNCTION set-field-direction RETURNS LOGICAL (INPUT fillin-or-editor AS
HANDLE,INPUT direction AS CHAR).
   DEFINE VARIABLE styles AS INTEGER    NO-UNDO.
   IF direction <> "R2L":U AND direction <> "L2R":U THEN DO:
      MESSAGE "set-field-direction":U SKIP
         "Must be called with R2L or L2R":U SKIP
         direction
         VIEW-AS ALERT-BOX ERROR BUTTONS OK.
      RETURN FALSE.
   END.
   IF direction = "R2L":U THEN DO:
      /*
      styles = 4608. /* R2L arabic field */
      */
      styles = 29184. /* R2L + Scrollbar left Arabic field */
   END.
   ELSE DO:
      styles = 512. /* L2R Normal WE field */
   END.
   RUN SetWindowLongA IN THIS-PROCEDURE (INPUT fillin-or-editor:HWND ,INPUT -20,INPUT styles).
   RETURN TRUE.
END FUNCTION.

/* Used for fill-in and not large editor behaviour (Arabic) */
PROCEDURE SetWindowLongA EXTERNAL "user32.dll":
   /*
   Input parameters
      hdwnd   HWND handle of fill-in or editor
      offs    -20 for Extended windows styles
      newlong  4608 for arabic
              29184 for arabic with vertical scrollbar
                512 for WE

   */
   DEFINE INPUT PARAMETER hdwnd   AS LONG.
   DEFINE INPUT PARAMETER offs    As LONG.
   DEFINE INPUT PARAMETER newlong AS LONG.
END.