There are four mechanisms used to support multiple languages in the storefront:
- #properties files
- #localized properties
- #locale dependent fields
Each mechanism has characteristics that make it most appropriate for specific situations.
Properties files are used as the source of language-specific text. The properties files contain simple key value pairs where the key is a description of the String and the value is the corresponding text in a particular language. Multiple properties files with file names that indicate the language are used to support multiple languages. The language-independent keys in the properties files are used to retrieve the corresponding text in Velocity templates using a call to a Velocity macro as shown below.
The Velocity macro is part of Spring's integration with Velocity, and it will look up the value of the key for the currently selected Locale. Properties files are generally created for each Velocity template and stored in the same location. The properties file has the same name as the template but has the extension ".properties" instead of ".vm". For Strings that are frequently used across multiple pages, the properties are stored in "globals.properties".
This multi-language mechanism is suitable only for static page content coded into Velocity templates.
The Localized Properties mechanism is a database-only solution that allows dynamic content such as a store's brands to be displayed in multiple languages. To use this mechanism, a domain object with display values in multiple languages has a reference to a LocalizedProperties object containing the language values retrieved by key and locale. All localized property data for all objects is stored as rows in the TLocalizedProperties table. It is not necessary to change the database schema to add new localized properties. See "How to add Localized Properties to a domain object" below for instructions on adding Localized Property support to a new domain object.
Locale Dependent Fields
Locale Dependent Fields is used programatically in a simlar way to Localized Properties. An object has a reference to a LocaleDependantFields (LDF) object, from which it can retrieve localized Strings. In this mechanism, the localized properties are stored in columns in the database table and the table can be joined directly with the parent entity table. This means that performance is better than Localized Properties and the field values can be accessed using methods instead of a map key. However, the disadvantage of this approach is that a schema change is required for each new kind of localized field and a new table is required to support Locale Dependent Fields for each new object that requires them. For this reason, Locale Dependent Fields is only used for performance-critical domain objects such as products and categories.
The attribute system in Elastic Path also supports multiple languages. Attributes have the advantage that they can be created and maintained by a business user through the Commerce Manager user interface. Attributes are relatively slower than Locale Dependent Fields and are only supported for Products, Categories, and SKUs.
How to add new properties files
Spring framework provides messaging (i18n or internationalization) functionality by using MessageSource. When an ApplicationContext gets loaded, it automatically searches for a MessageSource bean named "messageSource" defined in the context.
In the Storefront, messageSource bean is defined in /WEB-INF/conf/spring/views/velocity/velocity.xml. The MessageSource implementation used in Elastic Path, ResourceBundleMessageSource, supports a hierarchical structure that defines where properties files should be defined. See the anotated XML code below.
<bean id="messageSource" class="org.springframework.context.support. ReloadableResourceBundleMessageSource"> <!-- Define the parent message source bean --> <property name="parentMessageSource"> <ref bean="globalMessageSource"/commerce-legacy/> </property> <property name="basenames"> <list> <!-- Define .properties files here (omitt the extension) --> <value>/WEB-INF/templates/velocity/account/create</value> <value>/WEB-INF/templates/velocity/address/create</value> . . . </list> </property> </bean> <bean id="globalMessageSource" class="org.springframework.context.support. ReloadableResourceBundleMessageSource"> <property name="basenames"> <list> <!-- Global .properties files are defined here --> <value>/WEB-INF/templates/velocity/globals</value> <value>org/acegisecurity/messages</value> </list> </property> </bean>
With this hierarchical structure, the property definition in the files associated with messageSource bean will overwrite the definiton in the files associated with globalMessageSource, if there is any.
To avoid property key duplication among the files in the same hierarchy, property keys are prefixed with the file name. For example, the content of /WEB-INF/templates/velocity/catalog/product/productTemplate.properties will look like the following.
productTemplate.zoom=Zoom In productTemplate.addToWishlist=Add to Wishlist productTemplate.qty=Qty productTemplate.itemno=ITEM NO productTemplate.accessories=Optional Accessories productTemplate.warranties=Protect this item productTemplate.upSells=Upgrade to ...