The localization framework provides the possibility to separate the language-specific elements from implementation artifacts like templates or Java code.
Therefore, each cartridge, enterprise, channel or application can provide its own translation elements. Each of them contains a mapping from a keyword to the language-specific text.
The translation for a key is looked up by the LocalizationProvider
in different LocalizationSheets
. These sheets are selected by the provider using the LocalizationContext
. The context provides the following information:
If one of them is not set, a fallback is implemented (e.g., if locale is not set, use lead locale and so on).
There are two different types of localization sheets:
a) Cartridge
b) Repository
a) The cartridge localization sheet (provided by a CartridgeLocSheetFactory
) returns a localization sheet which contains all translations "collected" from the cartridges assigned to the given application. That means, this sheet is somehow a file-based localization sheet since it reads the cartridge structure and includes all existing property file entries.
b) The repository reads the values from the database. Each part of an organization structure (enterprise, channel, application) does have its own repository (domain). From these repositories the translations can be requested.
There is a fallback strategy that makes the system search the most suitable translation for you. Starting at the application repository (which is the most specialized data), it goes "down" to the translation provided in an application cartridge (which is the most common data).
green | application-specific repository (since 7.0) |
---|---|
red | application type-specific repositories, available in channel and enterprise application (since 7.0) |
blue | application type-specific sheets, based on cartridges of an application type (since 6.6) |
Each cartridge can provide translations according to the business requirements. Depending on the used application type and the cartridges defined by this application type, the localization files are loaded. The localization keywords can be overwritten by cartridges that appear later in the cartridge list.
The following locations are defined ( development time):
buttons.apply=Apply product.retail_set.part.text=The product {0} is currently part of another retail set {1}. test.choice=There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}.
Additional description files can include descriptions of messages or contexts, which is helpful for translators. These descriptions will have the same key as the translated text. This makes it easier for translation agencies to identify the context of the key. E.g.:
buttons.apply=A button label to apply changes in a form
Depending on the business requirements, translations can also be stored in different repositories. The repositories are linked to one localization table that has nearly the same structure as the properties files, except that there is a description column.
Repository-ID | LocID | LockKey | LocValue |
---|---|---|---|
<an UUID> | en_US | buttons.apply | Apply |
<an UUID> | en_US | product.retail_set.part.text | The product {0} is currently part of another retail set {1}. |
<an UUID> | en_US | test.choice | There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}. |
These values are runtime values as they can be changed using the Commerce Management application. However, they can also be added on development time, but only by using the DBInit functionality.
Usually, you only need to load the localization files once the server is starting. Any changes afterwards should be done in the Commerce Management application. However, it can be useful that the server periodically checks if a localization file has some newer values (e.g., while developing a feature). To enable this, the following settings need to be adjusted using property intershop.localization.CheckContent
in the appserver.properties.
For versions between 7.0 and 7.3.1, you must set the reloading interval:
# reloading interval 5 seconds intershop.localization.CheckContent=5000
For all versions >= 7.3.2.0, you must set the value to true
:
# enables the reloading of localization property files intershop.localization.CheckContent = true
If the translations are available in the localization table, you do not need to enable this feature. The ORM layer guarantees that these values are always up-to-date.
The language-specific texts can contain placeholders to inject dynamic parameters into the sentences. The replacement is driven by java.text.MessageFormat.
<istext ...>
istext
is an ISML expression to easily get a translated text in a template for a certain key.
<
ISTEXT key="" [parameter[0..9]=""] [encoding="" ] [locale="" ]/>
The istext
tag can be configured according to the following parameters:
Keep in mind, that it is also possible to "calculate" the istext
key. For example, the ProductType can be bundle, retail set, variation, or simple product.
Examples:
<istext key="product.retail_set.part.text" parameter0="#Product:SKU#" parameter1="#RetailSet:SKU#" /> <istext key="test.choice" locale="#Locale#" parameter0="#CountOfFiles#" />
<ISMessageBox message="#localizeText('product.delete.ok.cancel', 'en_GB')#" subject="page" type="mdc" okbtnname="#localizeText('button.delete')#" cancelbtnname="#localizeText('button.cancelDelete')#" colspan="1"> <ISMessageBox message="#localizeTextEx('product.removed.info', ParameterList(Product:sku))#" subject="page" type="mdc" okbtnname="#localizeText('button.ok')#" colspan="1">
More about encoding is described in the Cookbook - Encoding.
Refer to ISML Tag - ISTEXT for more information on how to use the ISML tag.
localizeText()
localizeText()
Providing localizable UI text strings for ISML templates means also being able to localize an attribute value of a (possibly custom) ISML tag. For that purpose, the function localizeText
returns the plain text behind a given language-neutral key. Parameters of that function are:
So, you will have the following variations of the localizeText function:
localizeText(key : String) : String
localizeText(key : String, locale : String) : String
localizeText(key : String, locale : String, site : Domain) : String
Refer to ISML Function - localizeText() for more information on how to use the ISML function.
localizeTextEx()
The same applies for the parameter for replacement:
localizeTextEx(key : String, ParameterList(params ... : Object)) : String
localizeTextEx(key : String, locale : String, ParameterList(params ... : Object)) : String
localizeTextEx(key : String, locale : String, site : Domain, ParameterList(params ... : Object)) : String
Refer to ISML Function - localizeTextEx() for more information on how to use the ISML function.
<ISCustomGrid data="#ProductConfigurations#" header="#localizeText("product.configurations.list.header")#">
Providing localization at ISML level is sometimes prevented by legacy code. Therefore, localization features are accessible via the LocalizationProvider.
LocaleInformation enUS = NamingMgr.getManager(LocaleMgr.class).getLocaleBy("en_US"); LocalizationContext localizationContext = LocalizationContext.create(enUS); LocalizationProvider localizationProvider = NamingMgr.getProvider(LocalizationProvider.class); localizationProvider.getText(localizationContext, anyKey, parameter1, parameter2);
The management applications for enterprise and channel provide a module that allows Commerce Management application users to set their own values for the defined localization keys. Actually the set of available keys is searched via the pipelet GetLocalizedTextByLocalizationRepository
. Keys are searched in an application type specific way. This means that there may be found different sets of keys for different types of storefront applications. Generally, keys are defined by their occurrence in a localization property file or in a localization repository (all in the specific context of the application type to be managed).
Since version 7.4.2 it is also possible to prevent that certain keys or key sets do not appear in the Commerce Management application. This is achieved by a named filter object that is registered via the component framework and looked up by the GetLocalizedTextByLocalizationRepository
pipelet. The name is ManagementLocalizationKeyFilter
.
The core cartridge provides three types of filter conditions:
<!-- an operator expression that combines sub expression --> <implementation name="LocalizationKeyFilterExpression" ...> <requires name="operator" contract="String" cardinality="1..1"/> <!-- allowed values are: "and", "or" and "not" --> <requires name="condition" contract="LocalizationKeyCondition" cardinality="0..n"/> </implementation> <!-- a condition on the key name --> <implementation name="LocalizationKeyNameCondition" ...> <requires name="exception" contract="LocalizationKeyCondition" cardinality="0..1"/> <requires name="equals" contract="String" cardinality="0..n"/> <requires name="startsWith" contract="String" cardinality="0..n"/> <requires name="regex" contract="String" cardinality="0..n"/> </implementation> <!-- a condition on the cartridge name that defines the key --> <implementation name="LocalizationKeyCartridgeNameCondition" ...> <requires name="exception" contract="LocalizationKeyCondition" cardinality="0..1"/> <requires name="equals" contract="String" cardinality="0..n"/> <requires name="startsWith" contract="String" cardinality="0..n"/> <requires name="regex" contract="String" cardinality="0..n"/> </implementation>
For the Intershop 7 sales application, the default filter is defined in sld_ch_b2c_app and looks like:
<instance name="ManagementLocalizationKeyFilter" with="LocalizationKeyFilterExpression" scope="app"> <fulfill requirement="operator" value="or"/> <fulfill requirement="condition"> <instance name="LocalizationKeyFilter.DeniedCartridgesCondition" with="LocalizationKeyCartridgeNameCondition"> <fulfill requirement="equals" value="core"/> <fulfill requirement="equals" value="xcs"/> <fulfill requirement="equals" value="bts"/> <fulfill requirement="equals" value="btc"/> <fulfill requirement="startsWith" value="pf_"/> <fulfill requirement="startsWith" value="bc_"/> <fulfill requirement="exception"> <instance name="LocalizationKeyFilter.DeniedCartridges.Exceptions" with="LocalizationKeyFilterExpression"> <fulfill requirement="operator" value="or"/> </instance> </fulfill> </instance> </fulfill> </instance>
With this structure it is easily possible to customize its behavior by fulfilling the requirement of the sub objects LocalizationKeyFilter.DeniedCartridgesCondition
and LocalizationKeyFilter.DeniedCartridges.Exceptions
. Of course it is still possible to replace the whole ManagementLocalizationKeyFilter
object via the component framework.
For example re-enabling all keys from an excluded cartridge:
<fulfill requirement="condition" of="LocalizationKeyFilter.DeniedCartridges.Exceptions"> <instance with="LocalizationKeyCartridgeNameCondition"> <fulfill requirement="equals" value="bc_marketing"/> </instance> </fulfill>
Pattern: <featureGroup>[ENFINITY:.<featureSubGroup].<featureOrStringName>.<stringType>
Type |
Description |
Example Key |
Example String |
---|---|---|---|
text |
Simple informational text |
account.login.contactUs.text |
You can call us 24 hours a day at 1-800-CALLNOW |
label |
Form field label |
product.itemNumber.label |
Item Number: |
message |
Message for the user |
account.login.welcome.message |
Welcome back, Homer! |
error |
Error message |
account.login.invalidPassword.error |
You have entered an invalid password. Please try again. |
heading |
Heading for page or section |
product.reviews.heading |
Product Reviews |
tooltip |
Tool Tip |
product.stockStatus.tooltip |
This item is in stock and will be shipped within 2 days. |
link |
Link text |
product.moreDetails.link |
More Product Details |
The business tools allow to export and import localized strings via XLIFF format. This XML format is defined as follows:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 xliff-core-1.2-transitional.xsd"> <file target-language="en-US" datatype="html" source-language="en-US" original=""> <header/> <body> <trans-unit datatype="html" reformat="" approved="yes" id="checkout.did_you_know.heading"> <source xml:lang="en-US">Did You Know?</source> <target xml:lang="en-US" state="new">DID YOU KNOW?</target> </trans-unit> </body> </file> </xliff>
The import imports only the target
tag and the id of the outer trans
tag to identify the keyword. All other attributes and tags will be ignored.
Four different import modes are available:
INSERT | inserts new entries only |
---|---|
UPDATE | inserts new and updates existing entries |
REPLACE | replaces existing entries only |
DELETE | deletes existing entries |