home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Misc / CBMDevKit1.dms / CBMDevKit1.adf / tutorials.lha / tutorials / Locale < prev    next >
Encoding:
Text File  |  1993-11-04  |  35.4 KB  |  918 lines

  1.                   Locale Library
  2.  
  3. This document has two parts:
  4.  
  5.     - Introduction To Locale
  6.     - Writing Localized Applications
  7.  
  8.  
  9. NOTE - See also the locale examples which include code you can link
  10. with to self-load your catalogs on V37 machines.
  11.  
  12.  
  13.  
  14.             Introduction to Locale
  15.                         ======================
  16.    (c) Copyright 1991-93 Commodore-Amiga, Inc. All Rights Reserved
  17.  
  18. Localization is the process by which software dynamically adapts to
  19. different locales.  A locale is made up of a set of attributes
  20. describing a language, a set of cultural and lingual conventions, a
  21. physical location, etc.
  22.  
  23. Without standardized system support to help deal with localization
  24. issues, the task of localizing applications is significant.  There
  25. needs to be several different versions of every application, each
  26. specially adapted to run in a particular language and country.
  27.  
  28. Given the importance of the international market to the Amiga, it is
  29. imperative that the operating system provide services to facilitate,
  30. and thus encourage, application software localization.  This is where
  31. locale.library comes in.
  32.  
  33. The locale.library is an Amiga shared library offering services to let
  34. applications transparently adapt to any locale the user has chosen.
  35. Functions are provided for formatted information display, text catalog
  36. management, character attribute acquisition, string sorting, and more.
  37.  
  38.  
  39. Compatibility-Now and in the Future
  40.  
  41. In a world where inter-platform compatibility is increasingly
  42. important, it is a significant advantage to adhere as closely as
  43. possible to adopted standards.  This makes developing and porting
  44. applications to the Amiga easier, thus encouraging it.
  45.  
  46. The locale.library offers the necessary services to implement fully
  47. compatible X/Open - ANSI/C localization support.  Simple wrapper
  48. functions need to be provided by compiler writers to adhere to these
  49. standards, but the nuts and bolts of localization is in the library.
  50.  
  51. The locale.library provides for easy and virtually unlimited expansion.
  52. All character manipulation routines are defined as accepting 32-bit
  53. characters, allowing future support for multi-byte character sets such
  54. as UniCode.  Provisions are also made to allow the use of different
  55. character sets such as Cyrillic.
  56.  
  57. Since all language-specific text manipulation is implemented within
  58. language drivers, the library does not impose any artificial limitation
  59. on the simplicity or complexity of the algorithms used within the
  60. drivers.  This enables the creation of very specialized sorting
  61. algorithms that adhere closely to a language's grammatical rules.
  62. Workbench Disk
  63.  
  64. System localization is accomplished by an update to the Workbench disk.
  65. The changes needed include:
  66.  
  67. locale.library - This is the central element to localization and
  68. contains routines to allow management of locales, catalogs, and strings.
  69.  
  70. Language drivers - Much of locale.library's functionality is
  71. implemented through language drivers.  There is one such driver for
  72. every language supported.  All the language drivers are stored in the
  73. LOCALE:Languages directory.
  74.  
  75. Country database - A set of files describing various attributes of
  76. every country supported, including the country's currency symbol,
  77. number format, measuring system, etc.  Country files are stored in the
  78. LOCALE:Countries directory.
  79.  
  80. Locale preferences editor - A preferences editor found in the Prefs
  81. drawer that lets the user select which languages he speaks, the country
  82. in which he lives, and his time zone.
  83.  
  84. Revised system programs - Most programs found on the Workbench and
  85. Extras disks need to be updated in order to use locale.library.
  86.  
  87. System catalogs - A set of system text catalogs stored in the
  88. LOCALE:Catalogs directory.  These provide all the strings needed to
  89. operate the system in different languages.
  90.  
  91. Application catalogs - A set of application text catalogs stored in
  92. either the PROGDIR:Catalogs or LOCALE:Catalogs directories.  These are
  93. provided by applications and let them run in different languages.
  94.  
  95.  
  96. Patching the ROM
  97.  
  98. When an updated version of IPrefs is run, it instructs locale.library
  99. to patch several ROM routines to transparently provide them with
  100. localized behavior.
  101.  
  102. The ROM routines patched by locale.library are:
  103.  
  104. exec.library/RawDoFmt()
  105.     Adds argument ordering support using nn$ specifications (see below
  106. for more information on this).  Adds %U and %D formatting commands for
  107. localized number output.
  108.  
  109. dos.library/DosGetString() (internal routine)
  110.     Adds the ability to make use of disk-based text catalogs instead of
  111. always returning ROM-based strings.
  112.  
  113. dos.library/DateToStr() & dos.library/StrToDate()
  114.     Process and output localized dates
  115.  
  116. utility.library/ToLower() & utility.library/ToUpper()
  117.     Use the current language driver to adapt their behavior based on
  118. the user's current locale
  119.  
  120. utility.library/Strnicmp() & utility.library/Stricmp()
  121.     Use the current language driver to adapt their behavior based on
  122. the user's current locale
  123.  
  124. In addition, a new version of the LoadWB command patches a routine in
  125. workbench.library which enables the Workbench to run in the user's
  126. preferred language.
  127.  
  128.  
  129. Disk Files
  130.  
  131. The locale.library loads three types of files from disk to provide its
  132. functionality:
  133.  
  134.    o  Preferences files
  135. The user's locale preferences are stored as a standard prefs file named
  136. ENV:Sys/locale.prefs.  The Locale prefs editor is provided to let the
  137. user control the contents of this file. An in-memory Locale structure
  138. is built directly based on a locale preferences file.
  139.  
  140.    o  Language drivers
  141. Each locale has a single language driver bound to it.  When a locale is
  142. loaded in memory, a language driver is also loaded and automatically
  143. bound to the locale.  The language drivers are located in
  144. LOCALE:Languages.  For example:
  145.  
  146.                 LOCALE:Languages/dansk.language
  147.                 LOCALE:Languages/francais.language
  148.                 LOCALE:Languages/italiano.language
  149.  
  150.         A language driver is an Amiga shared library providing around a
  151. dozen functions for string and character-oriented operations that need
  152. to be adapted depending on the language being used.  The way each
  153. function is implemented is hidden to locale.library, allowing maximum
  154. flexibility for the driver when dealing with complex languages.
  155.  
  156.     o  Message catalogs
  157. Catalogs contain a series of translated strings for use by an
  158. application.  They are stored on disk in an IFF file that is processed
  159. and managed by calls in the library.  A utility called CatComp is
  160. provided that lets catalog files be generated easily.
  161.  
  162.         Each locale contains a list of preferred languages.  When a
  163. message catalog is accessed via the OpenCatalog() function,
  164. locale.library attempts to find a catalog in one of the locale's
  165. preferred languages.  OpenCatalog() looks in two different places for
  166. message catalogs:
  167.  
  168.                 PROGDIR:Catalogs/languageName/catalogName
  169.                 LOCALE:Catalogs/languageName/catalogName
  170.  
  171.         languageName is one of the locale's preferred languages.
  172. catalogName is the name of the catalog the application wishes to open.
  173. Typically, catalogName is the name of the application suffixed with
  174. ``.catalog''.
  175.  
  176. Looking in the LOCALE: directory for catalogs lets the user put message
  177. catalogs for small applications (system tools for example) into a
  178. single directory, or even simpler on a single disk called LOCALE.  In
  179. addition, using LOCALE: gives applications loaded as resident the
  180. ability to load in catalogs.  Since resident applications do not get
  181. the benefit of PROGDIR:, LOCALE: becomes the automatic fall-back.
  182.  
  183. Of course, language drivers and catalogs are transparently cached by
  184. locale.library and get flushed whenever a memory panic occurs and when
  185. their respective use count is 0.
  186.  
  187.  
  188. Functions
  189.  
  190. locale.library implements the actual localization facilities for
  191. application use.  Around two dozen functions are available to access
  192. and manipulate locales, catalogs, and strings.  Language drivers
  193. implement much of the functionality found in locale.library.  The
  194. drivers offer services needed by the higher-level functions in the
  195. library.  Each locale is bound automatically to a single language
  196. driver.
  197.  
  198.  
  199. Locales
  200.  
  201. The two most basic routines in the library are OpenLocale() and
  202. CloseLocale().  OpenLocale() returns a pointer to a Locale structure,
  203. which can then be used with most of the other functions in the library.
  204. A Locale structure describes all the attributes necessary to localize
  205. an application and is built from the values found in a locale
  206. preferences file.
  207.  
  208. During the OpenLocale() call, a language driver is automatically bound
  209. to a locale.  The language driver bound to the locale depends on the
  210. list of preferred languages specified by the user.  There is one driver
  211. per supported language.  Drivers are easy to write and new ones can be
  212. added by C= or third parties to support new languages as demand arises.
  213.  
  214. The language drivers offer specific services needed by the library to
  215. implement its functionality.  This currently involves only text
  216. manipulation functions specifically adapted to the language at hand.
  217. For example, sorting text behaves differently from language to language
  218. and needs to be taken care of by specialized code.
  219.  
  220.  
  221. Catalogs
  222.  
  223. Message catalogs are a simple means for an application to separate the
  224. strings of a program from the actual executable.  By adding new message
  225. catalogs, the application can be made to support new languages and to
  226. display all of its output in the desired language.
  227.  
  228. Message catalogs are loaded in memory via the OpenCatalog() function.
  229. Two of the parameters required by this function are a locale and a
  230. catalog name.  The locale is provided since it contains the list of the
  231. user's preferred languages.  Based on these languages, OpenCatalog()
  232. attempts to find the best catalog possible from the series of catalogs
  233. provided by the application.
  234.  
  235. Once a message catalog is in memory, any string it contains can be
  236. retrieved using the GetCatalogStr() routine.  The routine expects a
  237. number specifying which string of the catalog is to be returned.
  238. Sparse numbering of the strings is supported providing the most
  239. convenience possible to the application writer.
  240.  
  241. Date And Time
  242.  
  243. A Locale structure specifies special date and time formatting strings.
  244. These strings describe exactly how the date and time are to be
  245. displayed and interpreted.  The FormatDate() routine is provided to
  246. convert an AmigaDOS DateStamp structure into a localized date string,
  247. while the ParseDate() routine converts a string to a DateStamp
  248. structure.
  249.  
  250.  
  251. Argument Positioning
  252.  
  253. The grammar of most languages requires that subjects, objects, adverbs
  254. and complements be written out in a specific order.  This order varies
  255. from language to language.  For example:
  256.  
  257.         ``Please insert volume Workbench in drive DF0:''
  258.  
  259. might be said as:
  260.  
  261.         ``Insert in drive DF0: volume Workbench please''
  262.  
  263. To address this problem, an extension to the standard C-language
  264. printf() conventions used by FormatString() is argument position
  265. specification.  Specifying the argument position lets the order of the
  266. % commands change while the arguments provided remain the same.  Using
  267. the C printf() call as an example:
  268.  
  269. eyes = 2;
  270. feet = 3;
  271. ears = 4;
  272. printf("%d eyes, %d feet and %d ears",eyes,feet,ears);
  273. printf("%3$d ears, %1$d eyes and %2$d feet",eyes,feet,ears);
  274.  
  275. These two statements would produce the following output:
  276.  
  277.         ``2 eyes, 3 feet and 4 ears''   for the first
  278.         ``4 ears, 2 eyes and 3 feet''   for the second
  279.  
  280. The argument positioning feature lets you change the format string
  281. being processed while keeping the data stream the same.  This is an
  282. invaluable tool when translating strings to different languages.
  283.  
  284. So, in practical terms, you can change the order in which things
  285. appear.  As an example, the following string from the workbench catalog:
  286.  
  287.         ``Amiga Workbench  %lD graphics mem  %lD other mem''
  288.  
  289. can be changed to:
  290.  
  291.         ``Amiga Workbench  %2$lD other mem  %1$lD graphics mem''
  292.  
  293. and the string produced and displayed in the title bar of the Workbench
  294. would be correct.
  295.  
  296. The locale.library patches exec.library/RawDoFmt() to give it support
  297. for argument ordering.  In addition, locale's own FormatString()
  298. routine supports argument ordering as well.
  299.  
  300.  
  301. Sorting
  302.  
  303. Sorting follows different rules based on the language of the strings
  304. being sorted.  Thus, locale.library provides two routines to deal with
  305. sorting: StrnCmp() and StrConvert().
  306.  
  307. StrnCmp() is similar to the C function of the same name, except that it
  308. takes an argument specifying which type of sort to perform.  There are
  309. currently three supported sorts, each having its own role.  Refer to
  310. the autodoc entry for the StrnCmp() function for more information.
  311.  
  312. StrConvert() is a routine to enhance performance.  Its purpose in life
  313. is to convert a string into a special format that can be compared
  314. efficiently.  That is, the more advanced comparison types offered by
  315. StrnCmp() can be several times slower than a standard ASCII-based
  316. strncmp() call in C because StrnCmp() takes into account many more
  317. factors when sorting.
  318.  
  319. In programs, it is often necessary to compare a single string with many
  320. different strings.  Think for example of how alphabetical insertion
  321. into a list is done.  In these cases, the slower operation of StrnCmp()
  322. vs strncmp() can impact performance.  To alleviate this, StrConvert()
  323. allows you to perform most of the work performed by StrnCmp() only
  324. once.  Once a string has been converted by StrConvert(), it can be used
  325. with regular C strncmp() calls.
  326.  
  327. To clarify, given two strings A and B, the following will produce
  328. equivalent results:
  329.  
  330. StrnCmp(A,B)  ==  StrConvert(A,a)
  331. StrConvert(B,b)
  332. strncmp(a,b)
  333.  
  334.  
  335. Example
  336.  
  337. Here is a sample localized C program.  This program requires a message
  338. catalog called sample.catalog to get its strings from.
  339.  
  340. /* localetest.c */
  341. #include <exec/types.h>
  342. #include <exec/libraries.h>
  343. #include <libraries/locale.h>
  344.  
  345. #include <clib/exec_protos.h>
  346. #include <clib/dos_protos.h>
  347. #include <clib/locale_protos.h>
  348.  
  349.  
  350. /*****************************************************************************/
  351.  
  352.  
  353. extern struct Library *DOSBase;
  354. extern struct Library *SysBase;
  355.        struct Library *LocaleBase;
  356.        struct Catalog *catalog = NULL;
  357.  
  358.  
  359. /*****************************************************************************/
  360.  
  361.  
  362. enum AppStringsID
  363. {
  364.     MSG_HELLO,
  365.     MSG_BYE
  366. };
  367.  
  368.  
  369.  
  370. /*****************************************************************************/
  371.  
  372.  
  373. STRPTR AppStrings[] =
  374. {
  375.     "Hello World!\n",
  376.     "Bye, I'm leaving...\n"
  377. };
  378.  
  379.  
  380. /*****************************************************************************/
  381.  
  382.  
  383. STRPTR GetString(enum AppStringsID id)
  384. {
  385.     if (LocaleBase)
  386.         return(GetCatalogStr(catalog,id,AppStrings[id]));
  387.  
  388.     return(AppStrings[id]);
  389. }
  390.  
  391.  
  392. /*****************************************************************************/
  393.  
  394.  
  395. VOID main(VOID)
  396. {
  397.     if (LocaleBase = OpenLibrary("locale.library",38))
  398.         catalog = OpenCatalogA(NULL,"sample.catalog",NULL);
  399.  
  400.     PutStr(GetString(MSG_HELLO));
  401.     PutStr(GetString(MSG_BYE));
  402.  
  403.     if (LocaleBase)
  404.     {
  405.         CloseCatalog(catalog);
  406.         CloseLibrary(LocaleBase);
  407.     }
  408. }
  409.  
  410.  
  411. Structures
  412.  
  413. The Locale structure is the main public structure provided by
  414. locale.library.  The structure is defined in <libraries/locale.h> and
  415. consists of the following fields:
  416.  
  417. STRPTR loc_LocaleName
  418.     Locale's name.
  419. STRPTR loc_LanguageName
  420.     The language of the driver bound to this locale.
  421. STRPTR loc_PrefLanguages[10]
  422.     The ordered list of preferred languages for this locale.
  423. ULONG loc_Flags
  424.     Locale flags.  The single current flag specifies whether daylight
  425.     savings time should be used in the system.
  426. ULONG loc_CodeSet
  427.     Specifies the code set required by this locale. Currently, this
  428. value is always 0.
  429. ULONG loc_CountryCode
  430.     The international country code.
  431. ULONG loc_TelephoneCode
  432.     The international telephone code for the country.
  433. LONG loc_GMTOffset
  434.     The offset in minutes of the current location from GMT.
  435. UBYTE loc_MeasuringSystem
  436.     The measuring system being used.
  437. UBYTE loc_CalendarType
  438.     The type of calendar being used.
  439. STRPTR loc_DateTimeFormat
  440.     The date and time format string, ready to pass to FormatDate().
  441. STRPTR loc_DateFormat
  442.     The date format string.
  443. STRPTR loc_TimeFormat
  444.     The time format string.
  445. STRPTR loc_ShortDateTimeFormat
  446.     The short date and time format string, ready to pass to
  447.     FormatDate().
  448. STRPTR loc_ShortDateFormat
  449.     The short date format string.
  450. STRPTR loc_ShortTimeFormat
  451.     The short time format string.
  452. STRPTR loc_DecimalPoint
  453.     The decimal point character used to format non-monetary quantities.
  454. STRPTR loc_GroupSeparator
  455.     The characters used to separate groups of digits before the
  456.     decimal-point character in formatted non-monetary quantities.
  457. STRPTR loc_FracGroupSeparator
  458.     The characters used to separate groups of digits after the
  459.     decimal-point character in formatted non-monetary quantities.
  460. STRPTR loc_Grouping
  461.     A string whose elements indicate the size of each group of digits
  462.     before the decimal-point character in formatted non-monetary
  463.     quantities.
  464. STRPTR loc_FracGrouping
  465.     A string whose elements indicate the size of each group of digits
  466.     after the decimal-point character in formatted non-monetary
  467.     quantities.
  468. STRPTR loc_MonDecimalPoint
  469.     The decimal point used to format monetary quantities.
  470. STRPTR loc_MonGroupSeparator
  471.     The separator for groups of digits before the decimal point in
  472.     monetary quantities.
  473. STRPTR loc_MonFracGroupSeparator
  474.     The separator for groups of digits after the decimal point in
  475.     monetary quantities.
  476. STRPTR loc_MonGrouping
  477.     A string whose elements indicate the size of each group of digits
  478.     before the decimal-point character in monetary quantities.
  479. STRPTR loc_MonFracGrouping
  480.     A string whose elements indicate the size of each group of digits
  481.     after the decimal-point character in monetary quantities.
  482. UBYTE loc_MonFracDigits
  483.     The number of fractional digits (those after the decimal-point) to
  484.     be displayed in a formatted monetary quantity.
  485. UBYTE loc_MonIntFracDigits
  486.     The number of fractional digits (those after the decimal-point) to
  487.     be displayed in an internationally formatted monetary quantity.
  488. STRPTR loc_MonCS
  489.     The local currency symbol applicable to the current locale.
  490. STRPTR loc_MonSmallCS
  491.     The currency symbol for small amounts.
  492. STRPTR loc_MonIntCS
  493.     The international currency symbol applicable to the current locale.
  494.     The first three characters contain the alphabetic international
  495.     currency symbol in accordance with those specified in ISO 4217
  496.     Codes for the Representation of Currency and Funds.  The fourth
  497.     character (immediately preceding the NULL) is the character used to
  498.     separate the international currency symbol from the monetary
  499.     quantity.
  500. STRPTR loc_MonPositiveSign
  501.     The string used to indicate a nonnegative-valued formatted monetary
  502.     quantity.
  503. UBYTE loc_MonPositiveSpaceSep
  504.     Specifies the number of spaces separating the currency symbol from
  505.     the non-negative monetary quantity.
  506. UBYTE loc_MonPositiveSignPos
  507.     Set to a value indicating the positioning of loc_MonPositiveSign
  508.     for a non-negative monetary quantity.
  509. UBYTE loc_MonPositiveCSPos
  510.     Set to 1 or 0 if loc_MonCS respectively precedes or succeeds the
  511.     value for a non-negative monetary quantity.
  512. STRPTR loc_MonNegativeSign
  513.     The string used to indicate a negative-valued monetary quantity.
  514. UBYTE loc_MonNegativeSpaceSep
  515.     Specifies the number of spaces separating the currency symbol from
  516.     the negative monetary quantity.
  517. UBYTE loc_MonNegativeSignPos
  518.     Set to a value indicating the positioning of loc_MonNegativeSign
  519.     for a negative formatted monetary quantity.
  520. UBYTE loc_MonNegativeCSPos
  521.     Set to 1 or 0 if loc_MonCS respectively precedes or succeeds the
  522.     value for a negative formatted monetary quantity.
  523.     The grouping tables pointed to by loc_Grouping, loc_FracGrounping,
  524.     loc_MonGrouping, and loc_MonFracGrouping contain a stream of bytes
  525.     with the following values:
  526.  
  527. 255     No further grouping is to be performed.
  528.  
  529. 0       The previous element is to be repeatedly used for the remainder
  530. of the digits.
  531.  
  532. 1..254  The integer value is the number of digits that comprise the
  533. current group.  The next element is examined to determine the size of
  534. the next group of digits before the current group.
  535.  
  536. The values of loc_MonPositiveSignPos and loc_MonNegativeSignPos are
  537. interpreted according to the following:
  538.  
  539. 0       Parentheses surround the quantity and currency symbol
  540. 1       The sign string precedes the quantity and currency symbol
  541. 2       The sign string succeeds the quantity and currency symbol
  542. 3       The sign string immediately precedes the currency symbol
  543. 4       The sign string immediately succeeds the currency symbol.
  544.  
  545.  
  546. Using Locale.library from ARexx
  547.  
  548. locale.library provides an ARexx function host interface enabling ARexx
  549. programs to take advantage of system localization.  The functions
  550. provided by the interface are directly analogous to the functions
  551. available to C and assembly programmers, with the differences mostly
  552. being in the way they are called.
  553.  
  554. The function host library vector is located at offset -30 from the
  555. library.  This is the value you provide to ARexx in the AddLib()
  556. function call.  Here is a sample ARexx script to add locale.library to
  557. ARexx's function host list:
  558.  
  559.     /* Make sure the library is loaded as a function host */
  560.     IF ~SHOW(L,'locale.library') THEN DO
  561.       CALL ADDLIB('locale.library',0,-30)
  562.     END;
  563.  
  564. As mentioned, the functions available through the function host are
  565. very similar to the ones available from C and assembly.  Here is a list
  566. of the commands supported through the function host.  Each command has
  567. an AmigaDOS-style template that describes the arguments it accepts,
  568. along with a short description of what the command does.  Refer to the
  569. autodoc entries with the same names for more complete explanations of
  570. what each command is intended for.
  571.  
  572. CloseCatalog (CATALOG/N/A)
  573.     Closes a previously opened message catalog.  Pass it the return
  574.     value from OpenCatalog().
  575. ConvToLower (CHARACTER/A)
  576.     Pass it the character to convert and it returns the converted
  577.     character.
  578. ConvToUpper (CHARACTER/A)
  579.     Pass it the character to convert and it returns the converted
  580.     character.
  581. GetCatalogStr (CATALOG/A,STRING/N/A,DEFAULT/A)
  582.     Extract a string from a catalog.  Pass it the catalog obtained from
  583.     OpenCatalog(), the number of the string to extract from the
  584.     catalog, and a default string to return in case the requested
  585.     string is not in the catalog. IsAlNum (CHARACTER/A) - Pass it a
  586.     character and it returns 1 if the character is alphanumeric, or
  587.     returns 0 otherwise
  588. IsAlpha (CHARACTER/A)
  589.     Pass it a character and it returns 1 if the character is
  590.     alphabetic, or returns 0 otherwise
  591. IsCntrl (CHARACTER/A)
  592.     Pass it a character and it returns 1 if the character is a control
  593.     character, or returns 0 otherwise
  594. IsDigit (CHARACTER/A)
  595.     Pass it a character and it returns 1 if the character is a digit,
  596.     or returns 0 otherwise
  597. IsGraph (CHARACTER/A)
  598.     Pass it a character and it returns 1 if the character can be
  599.     represented graphically, or returns 0 otherwise
  600. IsLower (CHARACTER/A)
  601.     Pass it a character and it returns 1 if the character is lower
  602.     case, or returns 0 otherwise
  603. IsPrint (CHARACTER/A)
  604.     Pass it a character and it returns 1 if the character is a space,
  605.     or returns 0 otherwise
  606. IsPunct (CHARACTER/A)
  607.     Pass it a character and it returns 1 if the character is a
  608.     punctuation mark, or returns 0 otherwise
  609. IsSpace (CHARACTER/A)
  610.     Pass it a character and it returns 1 if the character is a white
  611.     space, or returns 0 otherwise
  612. IsUpper (CHARACTER/A)
  613.     Pass it a character and it returns 1 if the character is upper
  614.     case, or returns 0 otherwise
  615. IsXDigit (CHARACTER/A)
  616.     Pass it a character and it returns 1 if the character is a
  617.     hexadecimal digit (0..9, a..f, A..F), or returns 0 otherwise
  618. OpenCatalog (NAME/A,BUILTIN/A,VERSION/N/A)
  619.     Opens a message catalog and returns a value to be used for
  620.     GetCatalogStr() and CloseCatalog(). The first parameter specifies
  621.     the name of the catalog to load, the second parameter specifies the
  622.     language used for the default strings in the script, and the final
  623.     parameter specifies the version number of the catalog to open.  A
  624.     version of 0 means any version is fine.
  625. StrnCmp(STRING1/A,STRING2/A,TYPE/N/A)
  626.     Compares two strings and returns -1 if STRING1 comes before
  627.     STRING2, returns 0 if both strings are equal, and returns 1 if
  628.     STRING1 comes after STRING2.  The TYPE parameter is either 0 to do
  629.     an ASCII comparison, 1 to do a single pass collation, or 2 to do a
  630.     two pass collation (this corresponds to the C SC_ASCII, SC_COLLATE1
  631.     and SC_COLLATE2 constants explained in the autodoc entry for
  632.     StrnCmp() ). Here is a sample ARexx script that exercises some of
  633.     locale's function host commands:
  634.  
  635.         /* localetest.rexx */
  636.  
  637.         /* Make sure locale is loaded as a function host */
  638.         IF ~SHOW(L,'locale.library') THEN DO
  639.           CALL ADDLIB('locale.library',0,-30);
  640.         END;
  641.  
  642.         say ConvToLower("A");
  643.         say ConvToUpper("b");
  644.         say IsAlpha("1");
  645.  
  646.         catalog = OpenCatalog("workbench.catalog","english",0);
  647.         say GetCatalogStr(catalog,34,"default");
  648.         say CloseCatalog(catalog);
  649.         say StrnCmp("abc","def",2);
  650.  
  651.  
  652.  
  653.  
  654.             Writing Localized Applications
  655.                     ==============================
  656.  
  657.    (c) Copyright 1991-93 Commodore-Amiga, Inc. All Rights Reserved
  658.  
  659. One of the important goals while developing locale.library was to keep
  660. it simple in order to encourage its use.  The result is that
  661. applications can be localized with little effort on the programmer's
  662. part.  Of course, there are some issues to consider in order to do a
  663. better localization job.
  664.  
  665. The central part of localizing an application is getting all of the
  666. user-interface running in different languages.  locale.library provides
  667. text catalog management routines to solve this problem.  To make use of
  668. these catalogs, an application must group all of its strings in one
  669. location within the source code, and only refer to them using symbolic
  670. names from within the rest of the program.  See the sample program at
  671. the end of this document for an example of how this can be done easily.
  672.  
  673. Translated strings vary in length from their originals.  This can cause
  674. headaches when trying to perform screen layout, or otherwise formatting
  675. tables, etc...  On the average, it is safe to assume any given English
  676. string will double in length when translated to a variety of languages.
  677. This fact must always be considered when planning the visuals of a
  678. program.
  679.  
  680. Remember to take into account the time it takes to translate the
  681. strings of your application when you plan development schedules.  Be
  682. flexible, and prepare to maintain a dialog with the translators.  It
  683. may be necessary to extend the size of some of your gadgets to
  684. accommodate special cases.  Take this into account from the start, and
  685. design your application so these kinds of modifications remain easy.
  686.  
  687. Localization also involves number output.  From country to country,
  688. numbers are represented in different ways.  As such, it is not correct
  689. to assume anything about the length and format of numeric values.
  690.  
  691. Date format is another localized item.  Whenever displaying a date or
  692. requesting a date from the user, the FormatDate() and ParseDate()
  693. routines from locale.library should be used.  These routines handle all
  694. the details of the variations in date format.  Again, it is not safe to
  695. assume the length or format of a date string.
  696.  
  697. A localized application will potentially be viewed by audiences with
  698. radically different cultural backgrounds.  This is an important point
  699. to note when designing icons for an application.  Icons designed in the
  700. US for example, may seem perfectly obvious to an American, but may be
  701. totally meaningless to a Swedish user.  Be flexible with your icon
  702. designs.  Make sure to show them to users of your target countries
  703. before releasing your applications.
  704.  
  705. Something else which is important is naming.  When naming programs or
  706. features of programs, you should verify that the chosen name is
  707. suitable for all of your target markets.  Some words may have totally
  708. different meanings, or even be insulting, when viewed in different
  709. languages.
  710.  
  711.  
  712. Screen Layout
  713.  
  714. Screen layout is a problem when localizing applications.  Strings vary
  715. in length from language to language and it becomes difficult to create
  716. effective displays that will work well when translated. When creating a
  717. user-interface display on the Amiga, there are two main areas of
  718. concern: menus and gadgets.
  719.  
  720. Menus are easily localized thanks to gadtools.library.  Its dynamic
  721. menu layout code makes adapting to different strings virtually
  722. automatic.
  723.  
  724. Gadgets are not so easily handled.  As the text they contain can
  725. change, so can their size.  And when their size change, it can affect
  726. their positioning, which can then start to affect the positioning of
  727. surrounding gadgets, which ultimately affect the dimensions of the
  728. window.
  729.  
  730. There are two main ways to handle localization of gadgets:
  731.  
  732.    o  make all gadgets large enough to hold any string
  733.    o  dynamic screen layout
  734.  
  735. The first approach is simplest and involves making all gadgets large
  736. enough to accommodate the largest translated string for that gadget.
  737. For example, a gadget containing the string "Use" in an English
  738. program should not be made just large enough to hold three characters,
  739. but instead should be large enough to contain the longest translation
  740. of the word "Use."  The 2.1 system Preferences editors make use of
  741. this approach to localize their gadgetry.
  742.  
  743. The second approach to handle gadgets is by doing font sensitive
  744. layout.  This involves determining exactly the size of all strings used
  745. to create a display, then to scale and position every component so it
  746. can deal with the largest strings out there.  Font sensitive layout is
  747. normally thought of as a way of accomodating different fonts, but it
  748. also serves to accommodate different strings.  The 2.1 system
  749. Calculator is an example of a font sensitive application.
  750.  
  751.  
  752. Adapting GadTools
  753.  
  754. GadTools' NewMenu and NewGadget structures both have Label fields
  755. requiring a pointer to a string.  The string is used to build the
  756. user-interface component.  Many programs currently declare a static
  757. array of these structures to pass them to either CreateMenus() or
  758. CreateGadget().  Static initialization will not work however within a
  759. localized application due to the fact the label strings are not known
  760. at compile-time, and are instead obtained at run-time from disk-based
  761. catalogs.
  762.  
  763.  
  764. Localizing GadTools Gadgets
  765.  
  766. Here is a routine that lets you easily localize GadTools gadgets.
  767. Instead of calling the GadTools CreateGadget() routine, simply call
  768. CreateLocGadget().
  769.  
  770. extern struct Catalog *catalog;
  771.  
  772. struct Gadget *CreateLocGadget(ULONG kind, struct Gadget *previous,
  773.                               struct NewGadget *newGad, ULONG tag, ...)
  774. {
  775. struct NewGadget ng;
  776.  
  777.     ng = *newGad;
  778.     ng.ng_Label = GetCatalogStr(catalog,
  779.                                 (LONG)ng.ng_Label,
  780.                                 GetAppStr((LONG)ng.ng_Label));
  781.  
  782.     return (CreateGadgetA(kind,previous,&ng,&tag));
  783. }
  784.  
  785. This function assumes you have an opened message catalog called
  786. "catalog," and that your application has a function called GetAppStr()
  787. that returns the built-in string of the application given a string ID
  788. number.
  789.  
  790. Now the trick with this function is that when you declare your
  791. NewGadget structure, you initialize the ng_Label field to contain the
  792. string ID of the desired string, instead of a pointer to the string
  793. itself.  CreateLocGadget() will then replace the string ID by an actual
  794. string pointer and will call the real GadTools routine to create the
  795. gadget.
  796.  
  797.  
  798. Localizing GadTools Menus
  799.  
  800. Localizing menus is a bit trickier than gadgets because the
  801. CreateMenus() call accepts an array of NewMenu structures as a
  802. parameter instead of a single structure at a time like CreateGadget().
  803. Still, the solution remains relatively simple:
  804.  
  805. struct Menu *CreateLocMenus(struct NewMenu *newMenus, ULONG tag, ...)
  806. {
  807. UWORD           i;
  808. struct NewMenu *nm;
  809. struct Menu    *menus;
  810.  
  811.  i = 0;
  812.  while (nm[i++].nm_Type != NM_END) {}
  813.  
  814.  if (!(nm = AllocVec(sizeof(struct NewMenu)*i,MEMF_CLEAR|MEMF_PUBLIC)))
  815.      return(NULL);
  816.  
  817.  while (i--)
  818.  {
  819.      nm[i] = newMenus[i];
  820.  
  821.      if (nm[i].nm_Label != NM_BARLABEL)
  822.      {
  823.          nm[i].nm_CommKey = GetCatalogStr(catalog,
  824.                                      (LONG)nm[i].nm_Label,
  825.                                      GetAppStr((LONG)nm[i].nm_Label));
  826.  
  827.     nm[i].nm_Label = nm[i].nm_CommKey+2;
  828.  
  829.          if (nm[i].nm_CommKey[0] == ' ')
  830.              nm[i].nm_CommKey = NULL;
  831.      }
  832.  }
  833.  
  834.  
  835.  
  836.  if (menus = CreateMenusA(nm,&tag))
  837.  {
  838.      if (!(LayoutMenus(menus,visualInfo,GTMN_NewLookMenus,TRUE,
  839.                                         TAG_DONE)))
  840.      {
  841.          FreeMenus(menus);
  842.                 menus = NULL;
  843.             }
  844.  }
  845.  
  846.  FreeVec(nm);
  847.  
  848.  return(menus);
  849. }
  850.  
  851. Like the gadget example above, this function expects to have both an
  852. open catalog and a GetAppStr() function available.  In addition, this
  853. function expects to find the menu strings in a specific format.  That
  854. is, all strings must be preceded by their keyboard shortcuts and a NULL
  855. byte.  For example:
  856.  
  857.         "X\0Cut"
  858.         "C\0Copy"
  859.         "V\0Paste"
  860.  
  861. This is compact, and lets the keyboard shortcuts be easily localized
  862. and associated with the menu item.  If a menu item has no keyboard
  863. shortcut, it needs to be specified using a leading space such as:
  864.  
  865.         " \0Erase"
  866.  
  867. As with gadgets, the trick with this function is to initialize all the
  868. nm_Label fields to be string IDs instead of direct string pointers.
  869. CreateLocMenus() then allocates a new array, replacing the string IDs
  870. with string pointers, and passes the result to GadTools for the actual
  871. menu strip creation and layout.
  872.  
  873.  
  874. Character Sets
  875.  
  876. A character set defines the meaning and graphical representation
  877. associated with a sequence of numbers.  From the beginning, the Amiga
  878. has used the ECMA-Latin 1 character set which is a superset of regular
  879. ASCII designed by the European Computer Manufacturer's Association.
  880. This character set is sufficient to represent alphabets used by
  881. languages spoken in Western Europe.
  882.  
  883. Commodore has never endorsed character sets other than ECMA-Latin 1,
  884. which means that alphabets used in Eastern Europe, in the Middle-East,
  885. or in Asia, cannot be represented in a standard way on an Amiga.
  886. Designing fonts with the needed characters in them is not sufficient,
  887. because without a formal standard, there is no way to guarantee that a
  888. given character will be used in every variation of a font for a given
  889. alphabet.  To clarify, without a standard, it is not possible to assume
  890. that the Greek Omega letter will be represented by the same character
  891. value from one Greek font to the next.
  892.  
  893. The locale.library assumes nothing about the character set being used.
  894. The character set is dependant on the current language driver and
  895. catalog.  At this time, the only character set formally recognized is
  896. ECMA-Latin 1.  New character sets can be specified easily.
  897.  
  898. It is possible that new character sets may require more than one byte
  899. of storage per character.  This would be the case for the Unicode
  900. character set.  Applications written now only need to deal with the
  901. current 1-byte character set.  In the future, applications may want to
  902. support new extended character sets as they are standardized upon by
  903. Commodore.
  904.  
  905.  
  906. CatComp: the Catalog Compiler
  907.  
  908. CatComp is a program to handle the creation and maintenance of the
  909. message catalogs used by locale.library. Message catalogs are IFF files
  910. read by locale.library that contain all the text strings used by an
  911. application. By providing several of these catalog files, an
  912. application can use locale.library and transparently adapt itself to
  913. the user's preferred language.
  914.  
  915. For more information on CatComp, consult catcomp.doc that comes with the
  916. CatComp program.
  917.  
  918.