version 1.7, 2006/08/16 13:45:04
|
version 1.8, 2006/08/16 19:34:35
|
|
|
different language. Please refer to PEP58 for details on these | different language. Please refer to PEP58 for details on these |
provider scenarios. <br> | provider scenarios. <br> |
</p> | </p> |
<p>Pegasus 2.3 has added classes for the localization support. |
<p> |
There are new classes called AcceptLanguages and ContentLanguages that |
The Accept-Language and Content-Language headers are encapsulated |
encapsulate the Accept-Language and Content-Language headers, |
in AcceptLanguageList and ContentLanguageList classes, respectively. |
respectively. These classes are basically containers of |
These classes contain LanguageTag objects. The AcceptLanguageList class |
AcceptLanguageElement and ContentLanguageElement, where a language |
keeps its LanguageTags prioritized based on quality, |
element represents one language tag. The AcceptLanguages class |
|
will keep the AcceptLanguageElement's prioritized based on quality, |
|
according to RFC 2616. <br> | according to RFC 2616. <br> |
</p> | </p> |
<p>AcceptLanguages and ContentLanguages are the objects used by code |
<p>AcceptLanguageList and ContentLanguageList are the objects used by code |
throughout the request/response processing, from the client to the | throughout the request/response processing, from the client to the |
server to the providers and back. The server handles the creation | server to the providers and back. The server handles the creation |
of these objects from the HTTP headers. Code at each point in the | of these objects from the HTTP headers. Code at each point in the |
process will have access to these objects. <br> | process will have access to these objects. <br> |
</p> | </p> |
<p>Please refer to the following files for details on the new Pegasus |
<p>Please refer to the following files for details on the Pegasus |
classes. <br> |
language interfaces.<br> |
</p> | </p> |
<ul> | <ul> |
<li> pegasus/src/Pegasus/Common/AcceptLanguages.h</li> |
<li> pegasus/src/Pegasus/Common/AcceptLanguageList.h</li> |
<li> pegasus/src/Pegasus/Common/AcceptLanguageElement.h</li> |
<li> pegasus/src/Pegasus/Common/ContentLanguageList.h</li> |
<li> pegasus/src/Pegasus/Common/ContentLanguages.h</li> |
<li> pegasus/src/Pegasus/Common/LanguageTag.h</li> |
<li> pegasus/src/Pegasus/Common/ContentLanguageElement.h</li> |
|
<li> pegasus/src/Pegasus/Common/LanguageElementContainer.h</li> |
|
<li> pegasus/src/Pegasus/Common/LanguageElement.h</li> |
|
</ul> | </ul> |
<p><br> | <p><br> |
See the sections below for details on how to write clients and | See the sections below for details on how to write clients and |
|
|
</p> | </p> |
<p>The MessageLoader is the place where the Accept-Language header, | <p>The MessageLoader is the place where the Accept-Language header, |
Content-Language header, and the ICU resource bundles, join up. | Content-Language header, and the ICU resource bundles, join up. |
The MessageLoader class is designed to receive an AcceptLanguages |
The MessageLoader class is designed to receive an AcceptLanguageList |
object, and a set of parameters indicating the bundle base-name and | object, and a set of parameters indicating the bundle base-name and |
message ID to use. The AcceptLanguages object contains the list of |
message ID to use. The AcceptLanguageList object contains the list of |
requested languages sent by the client. The MessageLoader | requested languages sent by the client. The MessageLoader |
searches for the message in the set of bundles named with the base-name, | searches for the message in the set of bundles named with the base-name, |
using the AcceptLanguages for the list of specific translated bundles |
using the AcceptLanguageList for the list of specific translated bundles |
to search. The MessageLoader returns the message that it found, | to search. The MessageLoader returns the message that it found, |
along with a ContentLanguages object indicating the language of the |
along with a ContentLanguageList object indicating the language of the |
message. The ContentLanguages object should be used to indicate |
message. The ContentLanguageList object should be used to indicate |
the language of the response sent back to the client. <br> | the language of the response sent back to the client. <br> |
</p> | </p> |
<p>The MessageLoaderParms object contains the parameters to load the | <p>The MessageLoaderParms object contains the parameters to load the |
|
|
Note: defaults to the bundle containing the Pegasus server messages.</td> | Note: defaults to the bundle containing the Pegasus server messages.</td> |
</tr> | </tr> |
<tr> | <tr> |
<td>AcceptLanguages acceptlanguages;</td> |
<td>AcceptLanguageList acceptlanguages;</td> |
<td>Input. <br> | <td>Input. <br> |
Optional <br> | Optional <br> |
Default: AcceptLanguages::EMPTY</td> |
Default: AcceptLanguageList()</td> |
<td>Contains the list of preferred languages, in priority | <td>Contains the list of preferred languages, in priority |
order. This is combined with msg_src_path to determine which | order. This is combined with msg_src_path to determine which |
resource bundles to search for for the msg_id. If not empty, | resource bundles to search for for the msg_id. If not empty, |
overrides useThreadLocale and useProcessLocale.</td> | overrides useThreadLocale and useProcessLocale.</td> |
</tr> | </tr> |
<tr> | <tr> |
<td>ContentLanguages contentlanguages;</td> |
<td>ContentLanguageList contentlanguages;</td> |
<td>Output</td> | <td>Output</td> |
<td>Contains the language that MessageLoader found for the | <td>Contains the language that MessageLoader found for the |
msg_id. </td> | msg_id. </td> |
|
|
<td>Input <br> | <td>Input <br> |
Optional <br> | Optional <br> |
Default = <font color="#ff0000">true</font></td> | Default = <font color="#ff0000">true</font></td> |
<td>If true, MessageLoader will use the AcceptLanguages set by |
<td>If true, MessageLoader will use the AcceptLanguageList set by |
Pegasus into the caller's Thread. See the Note below for | Pegasus into the caller's Thread. See the Note below for |
details. </td> | details. </td> |
</tr> | </tr> |
|
|
Default = false</td> | Default = false</td> |
<td>If true, use ICU's fallback mechnism to search more general | <td>If true, use ICU's fallback mechnism to search more general |
resource bundles if the msg_id cannot be found. Note: the | resource bundles if the msg_id cannot be found. Note: the |
recommended setting is false if you are using an AcceptLanguages from a |
recommended setting is false if you are using an AcceptLanguageList from a |
CIM client. The Accept-Languages HTTP header from the client | CIM client. The Accept-Languages HTTP header from the client |
contains the fallback specifications. Using ICU's fallback in this | contains the fallback specifications. Using ICU's fallback in this |
case may lead to returning a language that the client didn't ask for.</td> | case may lead to returning a language that the client didn't ask for.</td> |
|
|
<p>Notes: <br> | <p>Notes: <br> |
</p> | </p> |
<p>The "useThreadLocale" parameter defaults to true. This flag | <p>The "useThreadLocale" parameter defaults to true. This flag |
indicates to use the AcceptLanguages object set by Pegasus into the |
indicates to use the AcceptLanguageList object set by Pegasus into the |
Pegasus Thread in which the caller's code is running. This | Pegasus Thread in which the caller's code is running. This |
AcceptLanguages object reflects the languages requested by the |
AcceptLanguageList object reflects the languages requested by the |
client. This is useful for code that may not have access to the | client. This is useful for code that may not have access to the |
AcceptLanguages from the client. Pegasus sets this AcceptLanguages |
AcceptLanguageList from the client. Pegasus sets this AcceptLanguageList |
object into the Thread of providers and internal Pegasus code. | object into the Thread of providers and internal Pegasus code. |
For this reason, it is recommended that provider and internal Pegasus | For this reason, it is recommended that provider and internal Pegasus |
code use the "useThreadLocale" flag instead of explicity passing in an | code use the "useThreadLocale" flag instead of explicity passing in an |
AcceptLanguages object. See the Provider Developer and Pegasus |
AcceptLanguageList object. See the Provider Developer and Pegasus |
Developer sections for details. <br> | Developer sections for details. <br> |
</p> | </p> |
<p>The "useProcessLocale" flag can be used to tell MessageLoader to use | <p>The "useProcessLocale" flag can be used to tell MessageLoader to use |
|
|
</p> | </p> |
<p>"Master switch" <br> | <p>"Master switch" <br> |
The MessageLoader class has a public static Boolean variable called | The MessageLoader class has a public static Boolean variable called |
_useProcessLocale that may be used to override all the AcceptLanguages |
_useProcessLocale that may be used to override all the AcceptLanguageList |
and useThreadLocale settings in the MessageLoaderParms objects passed | and useThreadLocale settings in the MessageLoaderParms objects passed |
in. This is useful for CLI code (eg cimconfig) that needs to | in. This is useful for CLI code (eg cimconfig) that needs to |
localize its messages based on the locale of its process, which refects | localize its messages based on the locale of its process, which refects |
the locale set by the user running the CLI (eg. $LANG on Unix). | the locale set by the user running the CLI (eg. $LANG on Unix). |
The CLI code may call Pegasus APIs that are coded to use the Thread's | The CLI code may call Pegasus APIs that are coded to use the Thread's |
AcceptLanguages, which will not be set in this case. The |
AcceptLanguageList, which will not be set in this case. The |
_useProcessLocale static variable tells the MessageLoader to ignore the | _useProcessLocale static variable tells the MessageLoader to ignore the |
AcceptLanguages, useThreadLocale, and useProcessLocale settings in |
AcceptLanguageList, useThreadLocale, and useProcessLocale settings in |
MessageLoaderParms that it gets. The MessageLoader will use the | MessageLoaderParms that it gets. The MessageLoader will use the |
default process locale, as determined by ICU, in this case. <br> | default process locale, as determined by ICU, in this case. <br> |
</p> | </p> |
|
|
section. This is because the Accept-Language header itself | section. This is because the Accept-Language header itself |
describes the fallback that the client wants. However, the | describes the fallback that the client wants. However, the |
MessageLoader does "fallback" to the root resource bundle if none of the | MessageLoader does "fallback" to the root resource bundle if none of the |
languages in AcceptLanguages can be found. If the root resource |
languages in AcceptLanguageList can be found. If the root resource |
bundle cannot be found, then the default_msg is returned. The | bundle cannot be found, then the default_msg is returned. The |
"useICUFallback" flag can be set to have MessageLoader use ICU fallback | "useICUFallback" flag can be set to have MessageLoader use ICU fallback |
on all message load attempts. However, usage of this flag for | on all message load attempts. However, usage of this flag for |
|
|
classes described above. Note: this a generic example. Each | classes described above. Note: this a generic example. Each |
of the developer sections below have 'real-life' examples that are | of the developer sections below have 'real-life' examples that are |
better suited to each type of code. </p> | better suited to each type of code. </p> |
<p>// Build an AcceptLanguages with some language elements <br> |
<p>// Build an AcceptLanguageList with some language elements <br> |
AcceptLanguages acceptLangs; <br> |
AcceptLanguageList acceptLangs; <br> |
acceptLangs.add(AcceptLanguageElement("fr", 0.5)); <br> |
acceptLangs.insert(LanguageTag("fr"), 0.5); <br> |
acceptLangs.add(AcceptLanguageElement("de", 0.8)); <br> |
acceptLangs.insert(LanguageTag("de"), 0.8); <br> |
acceptLangs.add(AcceptLanguageElement("es", 0.4)); </p> |
acceptLangs.insert(LanguageTag("es"), 0.4); </p> |
<p>// Construct a MessageLoaderParms <br> | <p>// Construct a MessageLoaderParms <br> |
MessageLoaderParms parms("msgID", "default message"); <br> | MessageLoaderParms parms("msgID", "default message"); <br> |
parms. msg_src_path = "/my_msg_dir/my_bundle"; <br> | parms. msg_src_path = "/my_msg_dir/my_bundle"; <br> |
|
|
MessageLoaderParms object. These constructors will use the | MessageLoaderParms object. These constructors will use the |
MessageLoaderParms object to call the MessageLoader to load the | MessageLoaderParms object to call the MessageLoader to load the |
localized exception message. The localized message is saved in the | localized exception message. The localized message is saved in the |
Exception. The ContentLanguages object returned by MessageLoader |
Exception. The ContentLanguageList object returned by MessageLoader |
is also saved in the Exception. This indicates the language of | is also saved in the Exception. This indicates the language of |
the message. The ContentLanguages object is used later to set the |
the message. The ContentLanguageList object is used later to set the |
Content-Language header in the HTTP message to the client. <br> | Content-Language header in the HTTP message to the client. <br> |
</p> | </p> |
<p>The old Exception constructors that take a String will remain. | <p>The old Exception constructors that take a String will remain. |
|
|
provider does not need to know what the Accept-Language is. This | provider does not need to know what the Accept-Language is. This |
is the recommended method to load messages based on the client's request.</li> | is the recommended method to load messages based on the client's request.</li> |
<br> | <br> |
<li> The OperationContext will contain an AcceptLanguages object |
<li> The OperationContext will contain an AcceptLanguageList object |
that has the Accept-Language requested by the client. The provider | that has the Accept-Language requested by the client. The provider |
can use this AcceptLanguages object to load strings with MessageLoader.</li> |
can use this AcceptLanguageList object to load strings with MessageLoader.</li> |
</ul> | </ul> |
<p><br> | <p><br> |
The OperationContext will also contain a ContentLanguages object that |
The OperationContext will also contain a ContentLanguageList object that |
is set from the Content-Language in the client request. This is | is set from the Content-Language in the client request. This is |
the language of the CIM objects being passed to the provider on that | the language of the CIM objects being passed to the provider on that |
request. A localized provider should store the content language | request. A localized provider should store the content language |
|
|
| |
// We are going to let the message loader parameters default to use the <br> | // We are going to let the message loader parameters default to use the <br> |
| |
// AcceptLanguages that Pegasus set into our thread. <br> |
// AcceptLanguageList that Pegasus set into our thread. <br> |
| |
// (this equals the AcceptLanguages requested by the client) <br> |
// (this equals the AcceptLanguageList requested by the client) <br> |
| |
// Note: This parms object could be constructed once and <br> | // Note: This parms object could be constructed once and <br> |
| |
|
|
| |
// of parms to the language that it found for the message. <br> | // of parms to the language that it found for the message. <br> |
| |
ContentLanguages rtnLangs = parms.contentlanguages; </p> |
ContentLanguageList rtnLangs = parms.contentlanguages; </p> |
<p> | <p> |
// We need to tag the instance we are returning with the <br> | // We need to tag the instance we are returning with the <br> |
// the | // the |
|
|
| |
// We are going to let the message loader parameters default to use the <br> | // We are going to let the message loader parameters default to use the <br> |
| |
// AcceptLanguages that Pegasus set into our thread. <br> |
// AcceptLanguageList that Pegasus set into our thread. <br> |
| |
// (this equals the AcceptLanguages requested by the client) <br> |
// (this equals the AcceptLanguageList requested by the client) <br> |
| |
// Note: This parms object could be constructed once and <br> | // Note: This parms object could be constructed once and <br> |
| |
|
|
<p> // Language priority is martian, pig-latin, and | <p> // Language priority is martian, pig-latin, and |
french. We should <br> | french. We should <br> |
// get french back, even though its the lowest priority <br> | // get french back, even though its the lowest priority <br> |
AcceptLanguages acceptLangs; <br> |
AcceptLanguageList acceptLangs; <br> |
acceptLangs.add(AcceptLanguageElement("x-martian")); <br> |
acceptLangs.insert(LanguageTag("x-martian"), 1.0); <br> |
acceptLangs.add(AcceptLanguageElement("fr", 0.1)); <br> |
acceptLangs.insert(LanguageTag("fr"), 0.1); <br> |
acceptLangs.add(AcceptLanguageElement("x-pig-latin", 0.4)); </p> |
acceptLangs.insert(LanguageTag("x-pig-latin"), 0.4); </p> |
<p> // Set the requested languages into the CIMClient <br> | <p> // Set the requested languages into the CIMClient <br> |
client.setRequestAcceptLanguages(acceptLangs); </p> | client.setRequestAcceptLanguages(acceptLangs); </p> |
<p> // Get the instance <br> | <p> // Get the instance <br> |
|
|
| |
get(returnedString); </p> | get(returnedString); </p> |
<p> // Check that we got back french <br> | <p> // Check that we got back french <br> |
ContentLanguages CL_FR("fr"); <br> |
ContentLanguageList CL_FR(); <br> |
|
CL_FR.append(LanguageTag("fr")); <br> |
String expectedFRString = "oui"; <br> | String expectedFRString = "oui"; <br> |
PEGASUS_ASSERT(CL_FR == client.getResponseContentLanguages()); <br> | PEGASUS_ASSERT(CL_FR == client.getResponseContentLanguages()); <br> |
PEGASUS_ASSERT(expectedFRString == returnedString); </p> | PEGASUS_ASSERT(expectedFRString == returnedString); </p> |
|
|
ICU. If ICU is installed on the client system then CIMClient will | ICU. If ICU is installed on the client system then CIMClient will |
set the Accept-Language from the default ICU process locale. If | set the Accept-Language from the default ICU process locale. If |
ICU is not installed then the caller is required to set an | ICU is not installed then the caller is required to set an |
AcceptLanguages into CIMClient that meets the ISO-639 and IS0-3166 |
AcceptLanguageList into CIMClient that meets the ISO-639 and IS0-3166 |
standards. Note: this is useful for local clients, such as | standards. Note: this is useful for local clients, such as |
the Pegasus CLIs, where ICU would be installed on both the client and | the Pegasus CLIs, where ICU would be installed on both the client and |
server sides. <br> | server sides. <br> |
|
|
<p><b>Server Design Points:</b> <br> | <p><b>Server Design Points:</b> <br> |
</p> | </p> |
<p>The CIMMessage object has been expanded to include an | <p>The CIMMessage object has been expanded to include an |
AcceptLanguages object and a ContentLanguages object. For |
AcceptLanguageList object and a ContentLanguageList object in its |
|
OperationContext member. For |
CIMRequestMessage, these objects contain the Accept-Language and | CIMRequestMessage, these objects contain the Accept-Language and |
Content-Language headers that were built from the client request. | Content-Language headers that were built from the client request. |
For CIMResponseMessage, the ContentLanguages object is used to build the |
For CIMResponseMessage, the ContentLanguageList object is used to build the |
Content-Language header associated with the CIM <i>objects </i>in the | Content-Language header associated with the CIM <i>objects </i>in the |
response message. The AcceptLanguages object in the |
response message. The AcceptLanguageList object in the |
CIMResponseMessage is ignored. <br> | CIMResponseMessage is ignored. <br> |
</p> | </p> |
<p>The localization of the cimException object in the | <p>The localization of the cimException object in the |
|
|
localized by the time it is built into the XML. For this reason, | localized by the time it is built into the XML. For this reason, |
the localization of the exception is the responsibility of the code | the localization of the exception is the responsibility of the code |
throwing the exception. (The goal of the design is to make that | throwing the exception. (The goal of the design is to make that |
easy - see below). The ContentLanguages object in the |
easy - see below). The ContentLanguageList object in the |
CIMResponseMessage has NO relation to this exception. The | CIMResponseMessage has NO relation to this exception. The |
cimException object keeps its own localization information once it is | cimException object keeps its own localization information once it is |
created. <br> | created. <br> |
|
|
<p>To enable exceptions to be localized, the ability was added to set a | <p>To enable exceptions to be localized, the ability was added to set a |
global language for all the code running from a Pegasus Thread | global language for all the code running from a Pegasus Thread |
object. The top level code for a Thread can set a global | object. The top level code for a Thread can set a global |
AcceptLanguages object that can be accessed by all the low-level |
AcceptLanguageList object that can be accessed by all the low-level |
functions that it calls. This will allow an exception thrown by | functions that it calls. This will allow an exception thrown by |
the low-level function to be localized based on this global | the low-level function to be localized based on this global |
AcceptLanguages object. Note: This applies only to Threads |
AcceptLanguageList object. Note: This applies only to Threads |
that are managed by a ThreadPool. <br> | that are managed by a ThreadPool. <br> |
</p> | </p> |
<p>Each service in the request path of the Pegasus server sets the | <p>Each service in the request path of the Pegasus server sets the |
AcceptLanguages into its Thread from the AcceptLanguages in the |
AcceptLanguageList into its Thread from the AcceptLanguageList in the |
CIMRequestMessage object that it dequeues. This sets the global | CIMRequestMessage object that it dequeues. This sets the global |
langauge for all the functions in the same thread that are called below | langauge for all the functions in the same thread that are called below |
handleEnqueue. <i>If you are writing a new service that processes | handleEnqueue. <i>If you are writing a new service that processes |
|
|
<p>With all that background, here is how code running in a Pegasus | <p>With all that background, here is how code running in a Pegasus |
service can throw a localized exception: <br> | service can throw a localized exception: <br> |
This example assumes that the top-level code in the service had set the | This example assumes that the top-level code in the service had set the |
global thread AcceptLanguages beforehand. As described above, |
global thread AcceptLanguageList beforehand. As described above, |
every service in Pegasus should do that. The code here may be | every service in Pegasus should do that. The code here may be |
buried several layers deep in the call chain, but does not need to know | buried several layers deep in the call chain, but does not need to know |
the AcceptLanguage of the current client request. </p> |
the AcceptLanguagList of the current client request. </p> |
<p>// First, construct a MessageLoaderParms <br> | <p>// First, construct a MessageLoaderParms <br> |
// <br> | // <br> |
// Notes: <br> | // Notes: <br> |
|
|
// 3) The MessageLoaderParms will default to use the Pegasus | // 3) The MessageLoaderParms will default to use the Pegasus |
server resource bundle <br> | server resource bundle <br> |
// 4) The MessageLoaderParms will default to use the | // 4) The MessageLoaderParms will default to use the |
AcceptLanguages set into the current Thread. Don't change this! <br> |
AcceptLanguageList set into the current Thread. Don't change this! <br> |
// 5) You might need to set the arguments for the message into | // 5) You might need to set the arguments for the message into |
the MessageLoaderParms <br> | the MessageLoaderParms <br> |
MessageLoaderParms parms("errorMessageID", "default message"); </p> | MessageLoaderParms parms("errorMessageID", "default message"); </p> |
|
|
e.getMessage()); <br> | e.getMessage()); <br> |
} <br> | } <br> |
</p> | </p> |
<p>This type of code would have lost the ContentLanguages saved in "e", |
<p>This type of code would have lost the ContentLanguageList saved in "e", |
so that the Content-Language would not be set in HTTP response to the | so that the Content-Language would not be set in HTTP response to the |
client. <br> | client. <br> |
</p> | </p> |
<p>For Pegasus 2.3, these types of macro calls can stay. The | <p>For Pegasus 2.3, these types of macro calls can stay. The |
TraceableCIMException constructed by the macro will "re-localize". | TraceableCIMException constructed by the macro will "re-localize". |
That is, the "CIM" part of the message (the part based on the error | That is, the "CIM" part of the message (the part based on the error |
code) will be localized at throw time, and the ContentLanguages |
code) will be localized at throw time, and the ContentLanguageList |
re-established. A key is to avoid a "language mismatch" problem | re-established. A key is to avoid a "language mismatch" problem |
between the CIM part of the message and the extra part of the | between the CIM part of the message and the extra part of the |
message. The design point here is that all internal exceptions | message. The design point here is that all internal exceptions |
thrown by Pegasus code are localized using the global AcceptLanguages |
thrown by Pegasus code are localized using the global AcceptLanguageList |
of the Thread...see above. <br> | of the Thread...see above. <br> |
</p> | </p> |
<p>In the future, it will be safer and more maintainable to use of | <p>In the future, it will be safer and more maintainable to use of |
|
|
e.getMessage( )); <br> | e.getMessage( )); <br> |
} <br> | } <br> |
</p> | </p> |
<p>This guarantees that the ContentLanguages in "e" is copied to the |
<p>This guarantees that the ContentLanguageList in "e" is copied to the |
newly created TraceableCIMException. <br> | newly created TraceableCIMException. <br> |
</p> | </p> |
<p>In the case where the extra message for the CIMException is | <p>In the case where the extra message for the CIMException is |