Before thinking about brand globalization, it is very important to first look into content internationalization on your website.
Messages is the VTEX IO app that translates store components, working directly on block code so that the development cycle is not limited by the necessary versioning flow from one language to another.
Once implemented in the app, Messages automatically identifies and interprets passive text messages for translation, reducing obstacles in the evolution process of your code–except in cases where you have already entered a customized translation manually.
Configuring Messages
For Messages to work as expected, we will use the react-intl
library. Serving as a translation engine, this highly versatile library has several advanced internationalization features (i18n) for your front app.
- Open your app's code in the code editor of your choice.
- Access the
react
folder and then run the commandyarn add react-intl@3 && yarn add @types/react-intl@3 --dev
. - Access the
manifest.json
file and add themessages
builder to thebuilders
list, as shown in the following example:
_10{_10 ..._10 "builders": {_10 "react": "3.x",_10 "docs": "0.x",_10+ "messages": "1.x"_10 },_10 ..._10}
- Save your code changes.
All set! Having all the react-intl
dependencies installed and the Messages builder configured, we can proceed to the next steps.
Allowing automatic translations
To understand how VTEX IO translations work in practice, consider the React HelloWorld
component imported in article 3 of this series:
_10import React from 'react'_10 _10const HelloWorld = () => <div>Hello World!</div>_10 _10export default HelloWorld
Note that, regardless of the language used on the store page, the Hello World!
text will be rendered in the component.
In order to have the Hello World!
text automatically translated when the page language changes, we have to use the FormattedMessage
component from the react-intl
package to specify which strings should be translated into other languages.
As a parameter for the FormattedMessage
component, we will have a unique ID (id
) associated with a specific string declared in your app:
- Substitute the
HelloWorld
component code with the code below:
_12import React from 'react'_12import { FormattedMessage } from 'react-intl'_12 _12const HelloWorld = () => {_12 return (_12 <div>_12 <FormattedMessage id="store/my-app.hello"/>_12 </div>_12 )_12}_12 _12export default HelloWorld
Note that in the example above we use the
FormattedMessage
component by associating it to the"store/my-app.hello"
ID, which we created for our example. Since each ID has to be linked to a single string only, it is necessary to define theFormattedMessage
component in this folder as many times as necessary in accordance with the translatable strings.
When creating an
id
, consider using thestore/
oradmin/
prefixes (depending on your app's functionality) followed by the app name (my-app
) and, finally, a short word that can identify this string. For example,store/my-app.hello
.
- In your app's root directory, create a
messages
folder. - In the newly created folder, create a new
.json
file named using the ISO code for the desired language. For example:pt
,en
,fr
. - In the desired language file, such as
messages/en.json
, associate theid
used in theFormattedMessage
component with the desired string:
_10{_10 "store/my-app.hello": "Hello World!"_10}
- Save all your code changes.
When you link your app again and change the page language, you will notice that the text Hello World!
is automatically translated into the UI thanks to the react-intl
library component and Messages.
To test these effects in the store linked to your VTEX account, access
https://{workspaceName}-{accountName}.myvtex.com
and add the query stringcultureInfo
with desired language value. For example, to check your page in Brazilian Portuguese type:https://{workspaceName}-{accountName}.myvtex.com/?cultureInfo=pt-BR
, substituting{workspaceName}
and{accountName}
with the development workspace name and your VTEX account name, respectively.
Overwriting automatic translations
Depending on your business scenario, you may want to change an automatic translation with a customized one.
In this section, we will teach you how to override Messages’ automatic translations using the same example as before:
- In the
Messages
folder, access the file you want for the translation language that will be overwritten (messages/pt.json
, for example). - In this file, define a new translation for the same
id
previously linked to the desired string. For example:
_10{_10 "store/my-app.hello": "Olá, pessoal!"_10}
By linking the same id
to another translation, you are telling VTEX IO to ignore Messages’ automatic translation and consider only the one you defined manually.
Link your app again and change the page language to Portuguese to see how the translation you defined is rendered!
Advanced translations
Internationalizing a component can mean more than translating its strings. For example, it can include changing price and percentage formatting.
Having your app's purpose in mind, you can (and should) make some adjustments to the rendered messages when they contain:
- Price representations;
- Variable values;
- Gender and number agreement dependencies
- Percentage representations;
- Dynamic messages, such as error messages.
Adjusting price representations
Price formatting for describing prices varies from country to country. If the app you are developing includes price variables, it is essential to set it up to handle different internationalization scenarios.
To automate these price changes in the translation flow, you need to add the vtex.format-currency
library to your app's dependencies:
- Access the
manifest.json
file and addvtex.format-currency
to thedependencies
list:
_10 dependencies: {_10+ "vtex.format-currency": "0.x"_10 }
- Access the file created in the
react
folder for the imported React component. - Once you are in it, import the
FormattedCurrency
component fromvtex.format-currency
. - Use the
<FormattedCurrency value={price} />
format to indicate that the variableprice
should be treated as the price notation value. For example:
_14import React from 'react'_14import { FormattedCurrency } from 'vtex.format-currency'_14 _14const PriceComponent = () => {_14 const price = 10.50_14 _14 return (_14 <div>_14 <FormattedCurrency value={price} />_14 </div>_14 )_14}_14 _14export default PriceComponent
- Save your code changes.
Adjusting variable values
It is common to have a variable in the middle of the message that the component is rendering.
Consider our HelloWorld
example. To render a greeting following the format Hello, {userName}!
, we have to use variable interpolation.
Given you have already added the react-intl
package to your app's dependencies, as explained earlier in this article, follow the instructions below:
- Access the file created in the
react
folder for the imported React component. - Once you are in it, import the
FormattedMessage
component fromreact-intl
, setting the variableuser
(sent as a component parameter) using the following standard format:<FormattedNumber id={id} values={{ user: user }}/>
. For example:
_14import React from 'react'_14import { FormattedMessage } from 'react-intl'_14 _14const HelloUser = () => {_14 const user = 'John'_14 _14 return (_14 <div>_14 <FormattedMessage id='store/my-app.hello-user' values={{ user: user }} />_14 </div>_14 )_14}_14 _14export default HelloUser
- Access the file containing Messages’ translations for the desired language (
messages/en.json
for example). - For the
FormattedMessage
id
(in our example,store/my-app.hello-user
), define the string that will be rendered in English using the value passed inuser
:
_10{_10 "store/my-app.hello-user": "Hello {user}!"_10}
- Save your code changes.
If concatenating the string seems complicated, we recommend reading this documentation. It will help your learning process, explaining more details about formatting messages using ICU and variable interpolation.
Adjusting gender and number agreement
A variable's gender and number have a direct impact on string concatenation.
For example, when you do a search, it may return nothing, return one result, or even several results at the same time. That means the answer that we want to render for the user will not remain constant, varying depending on the search itself and the results that are found.
If we analyze this case, it turns out we could render No products found
, One product found
, and X products found
, respectively.
To make the messages in your app agree in gender and number in their given scenario, we will use variable interpolation.
Given you have already added the react-intl
package to your app's dependencies, as explained at the beginning of this article, follow the instructions below:
- Access the file created in the
react
folder for the imported React component. - Import the
FormattedMessage
component fromreact-intl
, setting themyQuantity
variable (sent as a component parameter). Use the following format:<FormattedNumber id={id} values={{ quantity: myQuantity }}/>
. For example:
_14import React from 'react'_14import { FormattedMessage } from 'react-intl'_14 _14const PluralSingularComponent = () => {_14 const myQuantity = 1_14 _14 return (_14 <div>_14 <FormattedMessage id='store/my-app.pluralsingular' values={{ quantity: myQuantity }} />_14 </div>_14 )_14}_14 _14export default PluralSingularComponent
- Access the file containing Messages’ translations for the desired language (
messages/en.json
, for example). - For the
FormattedMessage
id
(store/my-app.pluralsingular
in our example), define the string that will be rendered in English as per the value returned bymyQuantity
:
_10{_10 "store/my-app.pluralsingular": "{quantity, plural, =0 {No product found} one{One product found} other{# products found}}"_10}
- Save your code changes.
If concatenating the string seems complicated, we recommend reading this documentation. It will help your learning process, explaining more details about formatting messages using ICU and variable interpolation.
Adjusting percentage representation
Like prices, percentages are expressed in different ways depending on where you are.
If the app you are developing has variables with percentages, it is essential to set it up to handle different internationalization scenarios.
Given you have already added the react-intl
package to your app's dependencies, as explained at the beginning of this article, follow the instructions below:
- Access the file created in the
react
folder for the imported React component. - Import the
FormattedNumber
component fromreact-intl
, defining thevalue
andstyle
properties with the following format:<FormattedNumber value={variable} style="percent"/>
. For example:
_14import React from 'react'_14import { FormattedNumber } from 'react-intl'_14 _14const PercentageComponent = () => {_14 const percent = 0.1_14 _14 return (_14 <div>_14 <FormattedNumber value={percent} style="percent" />_14 </div>_14 )_14}_14 _14export default PercentageComponent
- Save your code changes.
Adjusting dynamic messages
There are cases where you cannot predefine the message displayed by the block because it depends directly on actions taken by users during navigation. A common case of dynamic messages on the interface is HTTP error messages.
Given you have already added the react-intl
package to your app's dependencies, as explained at the beginning of this article, follow the instructions below:
- Access the file created in the
react
folder for the imported React component. - Import the
FormattedMessage
component fromreact-intl
, defining theerrorCode
variable (sent as a component parameter) to match the HTTP status code returned. For example:
_21import React from 'react'_21import { FormattedMessage, defineMessages } from 'react-intl'_21 _21const messages = defineMessages({_21 404: {_21 id: 'store/my-app.errors.404',_21 },_21 500: {_21 id: 'store/my-app.errors.500',_21 },_21})_21 _21const ErrorMessage = ({ errorCode = 500 }) => {_21 return {_21 <div>_21 <FormattedMessage id={messages[errorCode].id} />_21 </div>_21 }_21}_21 _21export default ErrorMessage
- Save your code changes.
Note that we use a variable to choose the
id
used in theFormattedMessage
component, making the message dynamic. To declare dynamic messages in your block's code, you need to describe all possible exported messages in an object passed in thedefineMessages
function from thereact-intl
package. This function, which returns the same object without changes, is useful for analyzing the code statically, ensuring that Messages delivers only the messages necessary for the browser to render.