Core Gadget - Variable Substitution and Localization
This is a DRAFT. Because of the close relationship between Variable Substitution and Localization, I edited those sections together...
<section title="Variable Substitution" anchor="VariableSubstitution"> <t>The Variable Substitution capability provides the ability for gadget developers to use special "Expression Language" (EL) statements within their gadget specifications that the container will replace with appropriate values when the gadget is rendered.</t> <figure><preamble>For example, given the following partial gadget specification:</preamble><artwork><![CDATA[ <Module> <ModulePrefs> ... </ModulePrefs> <Content type="html"> One plus one is equal to ${1+1}. </Content> </Module> ]]></artwork></figure> <t>When the default view for this gadget is rendered, the expression "${1+1}" will be evaluated and replaced with the value "2", resulting in the output:</t> <figure><artwork> One plus one is equal to 2. </artwork></figure> <t>Expression Language statements can be used to to access values provided by reserved variable keys, variables defined using data pipeline tags as defined by <xref target="DataPipeling"/>, or literal values as in the previous example.</t> <t>The syntax for expressions is based on a subset of the <xref target="JSPEL">Java Server Pages Expression Language (JSPEL)</xref>. All basic operations defined by the JSPEL specification, such as string concatenation and matching, are supported. However, the definition of custom functions, as defined in <xref target="JSPEL" />, Section 1.15, is not supported at this time.</t> <t>Containers are required to support variable substitution using this Expression Language syntax.</t> <section title="Using Literal Statements"> <t>As is defined by the <xref target="JSPEL">JSPEL</xref> specification, literal statements can be used. For instance, the "${1+1}" used in the previous example is a literal statement that outputs the results of adding the two numbers together. All forms of literal statement allowed by JSPEL may be used within OpenSocial.</t> <t>It is also possible to combine the use of literal statements with other variables. For instance, the expression "${1 + count}" will be replaced by the numeric value of the variable "count" plus the number one.</t> </section> <section title="Using Data Pipelining"> <t>For all gadget instances, there is a <spanx style="verb">DataContext</spanx> object that stores and provides access to all of the data associated with the Gadget's use of the <xref target="DataPipelining">Data Pipelining</xref> capability. The information stored within the <spanx style="verb">DataContext</spanx> can be accessed either via expression statements or using the <spanx style="verb">opensocial.data</spanx> API.</t> <figure><preamble>For instance, if we define a simple variable using the data pipelining tags, we can access the value of that variable by naming it within a substitution expression:</preamble><artwork><![CDATA[ <Module xmlns:os="http://ns.opensocial.org/2008/markup"> ... <Data> <os:Var key="myNumber" value="1" /> </Data> <Content type="html"> The value of myNumber is: ${myNumber} </Content> </Module> ]]></artwork></figure> <t>Additional information on the use of the <spanx style="verb">DataContext</spanx> with variable substitution can be found in <xref target="DataPipelining" /> and <xref target="OpenSocial-Templating"/>.</t> </section> <section title="Using Reserved Variable Keys" anchor="ReservedVariableKeys"> <t>Reserved Variable Keys are reserved variables names whose values are provided by the container. The keys take the form "{Prefix}.{Var}" where "{Prefix}" identifies one of the predefined scopes below, and "{Var}" specifies a specific variable within the identified scope. The applicability of each Prefix and Var combination will vary depending on where within the gadget specification the variable substitution is occurring.</t> <texttable align="left"> <ttcol>Prefix</ttcol> <ttcol>Description</ttcol> <ttcol>Applicability</ttcol> <c>Msg</c> <c>References all message bundle variables for the current locale. The values of the {Var} component are selected from the applicable message bundle. For instance, if the bundle includes a key "FOO", then the expression ${Msg.FOO} will be replaced by the localized value associated with "FOO" in the bundle.</c> <c>"Msg.*" variables are available anywhere within gadget, including ModulePrefs and root Module element. Message bundle values may reference other message bundle variables by making use of the ${Msg.*} syntax within the value.</c> <c>Bidi</c> <c>Used to reference information about the currently selected Locale's default text directionality as specified by the text_direction attribute on the <Locale> element. The BIDI variables are discussed in detail in <xref target="Localization"/>.</c> <c>ViewParams</c> <c>References all values passed as "viewParams" with a call to <xref target="gadgets.views.requestNavigateTo">gadgets.views.requestNavigateTo</xref>. The values of the {Var} component correlate to each view parameter. Expression statements using this prefix will resolve to the same values as calls made to the <xref target="gadgets.views.getParams">gadgets.views.getParams</xref> API. For instance, the expression "${ViewParams.FOO}" will be replaced by the same value returned by the API call <spanx style="verb">gadgets.views.getParams()["FOO"]</spanx>.</c> <c>"ViewParam.*" variables are available only within Content blocks, <xref target="DataPipelining">Data Pipeline</xref> tags, and OpenSocial Markup Language (OSML) tags. TODO: Provide Link</c> <c>Prefs</c> <c>References all named values defined by <UserPref> elements contained in the gadget specification. The values of the {Var} component correlate to each defined user preference. Expression statements using this prefix will resolve to the same values as calls to the <xref target="gadgets.Prefs">gadgets.Prefs</xref> API. For instance, the expression "${Prefs.Lang}" will be replaced by the same value returned by the API call <spanx style="verb">gadgets.Prefs.getLang()</spanx>; The expression "${Prefs.FOO}" will be replaced by the same value returned by the API call <spanx style="verb">gadgets.Prefs.getString("FOO")</spanx></c> <c>Available anywhere within gadget the gadget specification.</c> <c>Top</c> <c>Reserved variable used by <xref target="OpenSocial-Templating">OpenSocial Templating</xref> to represent the top level variables registered with the <xref target="DataContext">DataContext</xref>.</c> <c>Available only within Content elements and templates as defined by <xref target="OpenSocial-Templating"/>.</c> <c>My</c> <c>Reserved variable used by <xref target="OpenSocial-Templating">OpenSocial Templating</xref> to represent local variables passed to the template instance.</c> <c>Available only within a template instance as defined by <xref target="OpenSocial-Templating"/>.</c> <c>Cur</c> <c>Reserved variable used by OpenSocial Markup Language (OSML) "repeaters" as defined in the <xref target="OpenSocial-Templating">OpenSocial Templating specification</xref>. Represents the current value or object as a for-each loop would.</c> <c>Available only within a "repeater loop" as defined by <xref target="OpenSocial-Templating"/>.</c> <c>Context</c> <c>Reservied variable used by OSML and templates to hold additional variables generated while processing templates and loops as defined in the <xref target="OpenSocial-Templating">OpenSocial Templating specification</xref>.</c> <c>Available only within a template or "repeater loop" as defined by <xref target="OpenSocial-Templating"/>.</c> <c>Viewer</c> <c>Reserved for future use.</c> <c>N/A</c> <c>Owner</c> <c>Reserved for future use.</c> <c>N/A</c> <c>Gadget</c> <c>Reserved for future use.</c> <c>N/A</c> </texttable> <figure><preamble>The following example illustrates the use of Reserved Variables Names using the "Msg" prefix:</preamble> <artwork><![CDATA[ <Module> <ModulePrefs title="${Msg.TITLE}"> ... <Locale lang="en" country="US"> <msg name="TITLE">My Gadget</msg> <msg name="GREETING">Hello There!</msg> </Locale> ... </ModulePrefs> <Content type="html"><![CDATA[ <div>${Msg.GREETING}</div> ]]></Content> </Module> ]]></artwork></figure> </section> <section title="Deprecated Expression Syntax"> <t>Previous versions of this specification supported a -- now deprecated -- alternative expression syntax. Container implementations are permitted to continue supporting the deprecated syntax to provide backwards compatibility for older, existing gadget specifications, however, gadget developers creating new gadget specifications MUST NOT use the deprecated format.</t> <t>The legacy syntax takes the form "__{Prefix}_{Var}__" where "{Prefix}" identifies one of the predefined scopes below, and "{Var}" specifies a specific variable within the identified scope.</t> <figure><preamble>For instance, in the partial gadget example that follows, the expression "__MSG_FOO__" is replaced for the localized value identified by the key "FOO" within the localized message bundle:</preamble> <artwork><![CDATA[ <Module> <ModulePrefs title="__MSG_FOO__"> ... <Locale language="en" country="US"> <msg name="FOO">Hello World!</msg> </Locale> ... </ModulePrefs> <Content type="html"> ... </Content> </Module> ]]></artwork></figure> <t>The {Prefix} keys supported by the legacy syntax are:</t> <texttable align="left"> <ttcol>Prefix</ttcol> <ttcol>Description</ttcol> <c>MSG</c> <c>References all message bundle variables for the current locale. The values of the {Var} component are selected from the applicable message bundle. For instance, if the bundle includes a key "FOO", then the expression __MSG_FOO__ will be replaced by the localized value associated with "FOO" in the bundle.</c> <c>BIDI</c> <c>References BIDI substitution variables whose values will reflect the default text direction as specified by the selected locale. The BIDI variables are discussed in detail in <xref target="Localization"/>.</c> <c>MODULE</c> <c>Originally intended to provide a context for information about the gadget specification itself. Currently, "ID" is the only variable key supported (e.g. __MODULE_ID__). When used, the container SHOULD replace the "__MODULE_ID__" expression with a unique ID value for each instance of a gadget displayed simultaneously.</c> <c>UP</c> <c>References all named values defined by <UserPref> elements contained in the gadget specification. The values of the {Var} component correlate to each defined user preference. Expression statements using this prefix will resolve to the same values as calls to the <xref target="gadgets.Prefs">gadgets.Prefs</xref> API. For instance, the expression "__UP_Lang__" will be replaced by the same value returned by the API call <spanx style="verb">gadgets.Prefs.getLang()</spanx>; The expression "__UP_FOO__" will be replaced by the same value returned by the API call <spanx style="verb">gadgets.Prefs.getString("FOO")</spanx></c> </texttable> </section> <section title="Processing Requirements"> <t>Containers perform Variable Substitution when instances of a gadget are rendered or when metadata about the gadget is displayed. For instance, if the container includes the gadget specification within a listing of gadgets available to install and use on a page, then the container will perform any substitution necessary on the displayed values.</t> <t>Containers are required to perform substitution on all attributes or elements in the gadget specification document exception of <Locale>, <msg>, <EnumValue> elements, but only when the content of those elements and attributes is currently being rendered. If, for instance, a gadget contains multiple <Content> elements, each of which identify different views, the container will only process substitutions that are included within the content for the view currently being rendered. Further, containers are required to perform all substitutions that use either the Msg reserved variable key (i.e. "${Msg.FOO}") or the MSG legacy syntax format (i.e. "__MSG_FOO__") before applying any other substitutions.</t> <t>Variable substitution MUST NOT be applied recursively and circular dependencies detected within variables MUST be ignored and treated as literal values rather than expressions. For instance, within the following partial gadget specification:</t> <figure><artwork><![CDATA[ <Module xmlns:os="http://ns.opensocial.org/2008/markup"> ... <Data> <os:Var key="key1" value="${key2}" /> <os:Var key="key2" value="${key1}" /> </Data> <Content type="html"> ${key1} ${key2} </Content> </Module> ]]></artwork></figure> <t>The value of "key1" would be resolved as the literal value "${key1}". The value of "key2" would be resolved as the literal value "${key2}". The rendered output generated by the container would be:</t> <figure><artwork><![CDATA[ ${key1} ${key2} ]]></artwork></figure> </section> </section> <!-- END VARIABLE SUBSTITUTION --> <section title="Localization" anchor="Localization"> <t>Localization of a gadget is achieved primarily through <xref target="VariableSubstitution">Variable Substitution</xref>, using the Msg reserved variable key and <Locale> elements.</t> <t>To determine the appropriate keys and values to use for substitution, containers will inspect the gadget specification for a <Locale> element that matches the current view being rendered, as well as the language and country of the viewer.</t> <t>A <Locale> is considered a match if either: <list style="symbols"> <t>The default view is being rendered and the <Locale> elements view attribute is either unspecified or includes "default" as one of it's supported views (e.g. views="default", or views="myview,default", etc), or the specific view being rendered is named explicitly within the view attribute, and </t> <t>The language and country attributes on the <Locale> element exactly match those of the viewer, or</t> <t>The language attribute is an exact match for the viewer and the country attribute specifies "all", or</t> <t>Both the language and country attributes specify "all".</t> </list> </t> <t>How the container determines the current language and country of the viewer is not defined by this specification.</t> <t>If a matching <Locale> is not found within the gadget specification, the container is permitted to provide it's own localization data.</t> <t>Once an appropriate <Locale> has ben selected, containers are required to replace all Msg expressions for which a replacement value can be determined.</t> <t>For example, given the following partial gadget specification:</t> <figure><artwork><![CDATA[ <Module> <ModulePrefs> ... <Locale language="en" country="all"> <msg name="greeting">Hello World!</msg> </Locale> <Locale language="en" country="all" views="other"> <msg name="greeting">Howdy!</msg> </Locale> <Locale language="fr" country="all"> <msg name="greeting">Bonjour tout le monde!</msg> </Locale> ... </ModulePrefs> <Content type="html"> ${Msg.greeting} </Content> </Module> ]]></artwork></figure> <t>When rendering the default view, the container will output "Hello World!" for English-speaking viewers and "Bonjour tout le monde!" for French-speaking viewers.</t> <section title="Considerations for Bidirectional Text"> <t>Gadget developers need to take care when working with languages that require a default Right-to-Left ordering when rendering text. The "Bidi" reserved variable key can be used within Variable Substitution expression statements to access information about the default text directionality as specified by the currently selected locale.</t> <t>The variables supported by the "Bidi" reserved variable key are: <list style="hanging"> <t hangText="START_EDGE">When the selected <Locale> element's text_direction attribute specifies "rtl" (Right-to-Left"), the value of the Bidi.START_EDGE reserved variable key will be "right". When the attribute is either "ltr" (Left-to-Right) or unspecified, the value will be "left".</t> <t hangText="END_EDGE">When the text direction is "rtl", the value of Bidi.END_EDGE will be "left". When the attribute is either "ltr" or unspecified, the value will be "right".</t> <t hangText="DIR">The reserved variable key Bidi.DIR returns the value of the <Locale> element's text_direction attribute or "ltr" if the attribute is unspecified.</t> <t hangText="REVERSE_DIR">The reserved variable key Bidi.REVERSE_DIR returns the opposite of the <Locale> element's text_direction attribute value. If text_direction is "ltr", Bidi.REVERSE_DIR will return "rtl". If text_direction is "rtl", Bidi.REVERSE_DIR will return "ltr".</t> </list> </t> <figure><preamble>The Bidi variables can be used to establish the correct text directionality when rendering. For instance:</preamble><artwork><![CDATA[ <Module> <ModulePrefs> ... <Locale language="en" country="all"> <msg name="greeting">Hello World!</msg> </Locale> <Locale language="ar" country="all" text_direction="rtl"> <msg name="greeting">ʅɷ>D;ɴɳ ɳʄɿɳʄʅ!</msg> </Locale> ... </ModulePrefs> <Content type="html"> <div dir="${Bidi.DIR}">${Msg.greeting}</div> </Content> </Module> ]]></artwork></figure> </section> <section title="Message Bundle Documents" anchor="MessageBundles"> <t>The <Locale> element can either directly contain <msg> elements that define the keys and values used for localization or can reference "Message Bundle Documents" that provide the collection of <msg> elements.</t> <figure><preamble>For instance, the following <Locale> element:</preamble> <artwork><![CDATA[ <Locale language="en" country="US"> <msg name="color">Color</msg> <msg name="red">Red</msg> <msg name="green">Green</msg> <msg name="blue">Blue</msg> </Locale> ]]></artwork></figure> <figure><preamble>Can be replaced with a <Locale> that references an external Message Bundle that includes the same <msg> elements:</preamble> <artwork><![CDATA[ <Locale language="en" country="US" messages="http://example.com/en/messages.xml" /> ]]></artwork> </figure> <figure><preamble>The Message Bundle at http://example.com/en/messages/xml:</preamble> <artwork><![CDATA[ <messagebundle> <msg name="color">Color</msg> <msg name="red">Red</msg> <msg name="green">Green</msg> <msg name="blue">Blue</msg> </messagebundle> ]]></artwork></figure> <t>As illustrated, Message Bundles are XML documents whose root element is a <messagebundle> that contains zero or more <msg> elements that use the same format as the children of the <Locale> element.</t> <figure><artwork> messagebundle = element messagebundle { undefinedAttribute*, element msg { attribute name { text }, text } } </artwork></figure> <t>Variable substitution expressions MAY be used within Message Bundle Documents.</t> <t>Each Message Bundle Document provides <msg> elements for a single locale. By convention, Message Bundle documents are named as {language}_{country}.xml, where {language} is either an ISO-639-1 Language Code or "ALL" and {country} is an ISO-3166-1 Country Code or "ALL". For instance, a Message Bundle providing values for English-language speakers within the United States would be named "en_US.xml", while a Message Bundle providing German-language values for German-language speakers regardless of country would be named "de_ALL.xml". The Message Bundle named "ALL_ALL.xml" would apply to all languages in any country.</t> </section> </section> <!-- END LOCALIZATION -->