Localizing a Support app
In this tutorial, you'll localize the user interface of a Zendesk Support app. The app displays "Hello, World!" in different languages based on the user's locale and available translations. You can use the app's code as a starting point for localizing your own apps.
Tip: The app in this tutorial uses basic app starter files. If your app uses React, we recommend using the i18n module in the React app scaffold instead. For details, see Using the i18n module on GitHub.
Disclaimer: Zendesk provides this article for instructional purposes only. Zendesk doesn't provide support for the app or the example code in this tutorial.
What you'll need
To complete this tutorial, you'll need the following:
-
A Zendesk account with the Zendesk Suite Growth plan or above, or the Support Professional plan or above. To get a free eligible account for testing, see Getting a trial or sponsored account for development.
-
The Zendesk Command Line Interface (ZCLI). To install or upgrade ZCLI, refer to Installing and updating ZCLI. ZCLI replaces the Zendesk Apps Tools (ZAT), which are in maintenance mode. To use ZAT instead, refer to Installing and using ZAT.
-
Familiarity with the Zendesk Apps framework (ZAF). Before you start, complete the Building your first Support app tutorial.
Creating the app files
First, create basic starter files for an app named i18n.
-
In your shell, navigate to the folder where you want to store the app. Example:
cd projects
-
In the folder, run:
zcli apps:new
-
At the prompts, enter the following values:
- Directory name: i18n
- Author's name: Your name
- Author's email: Your email address
- Author's website: Leave blank and press Enter.
- App name: i18n
ZCLI creates app starter files in the i18n folder.
Adding translation strings
The starter files include an en.json file in the app's translations folder. You can add translation strings to JSON files in this folder.
-
In the app's translations folder, open en.json in your text editor.
-
Add the following
default
property:{
"app": {
...
},
"default": {
"hello_world": "Hello, World!"
}
}
Note: Don't add translation strings to the
app
object. Theapp
object contains content for the app listing on the Zendesk Marketplace. -
In the translations folder, create a fr.json file. Paste the following into the file:
{
"default": {
"hello_world": "Bonjour le Monde!"
}
}
-
Save en.json and fr.json.
Loading translation strings
A Zendesk app's iframe can only access local files in the assets folder. Create a script to output the translation strings to a JavaScript file in this folder.
-
In the app's root folder, create a load-translations.js file. Paste the following into the file:
const fs = require("fs");
const path = require("path");
const translations = getTranslationsFromDir("./translations");
writeTranslationsToFile(translations);
function getTranslationsFromDir(translationsDir) {
const jsonFiles = fs
.readdirSync(translationsDir)
.filter((file) => path.extname(file) === ".json");
let translations = {};
jsonFiles.forEach((file) => {
const fileData = fs.readFileSync(path.join(translationsDir, file));
const filename = file.replace(".json", "").toLowerCase();
const json = JSON.parse(fileData.toString());
translations[filename] = json;
});
return translations;
}
function writeTranslationsToFile(translations) {
const translationsString = JSON.stringify(translations);
const translationsObj = `const translations = ${translationsString};`;
const translationsFile = "./assets/translation-strings.js";
fs.writeFileSync(translationsFile, translationsObj);
console.log(`🚀 Translations written to ${translationsFile}`);
}
The code fetches translation strings from JSON files in the translations folder. The code adds the strings to a
translations
object. It then writes the object to a translation-strings.js file in the assets folder. -
In your shell, navigate the app's root folder. Example:
cd project/i18n
-
Use the following command to run the script:
node load-translations.js
The script creates a translation-strings.js file in the app's assets folder. To update the file, rerun the command.
Important: If you add or edit any translation strings in the translations folder, you need to rerun the script before using the strings in your app.
Localizing the app interface
Next, add code to insert a translation string into the app's user interface based on the current user's locale in Zendesk.
-
In the app's assets folder, open iframe.html. Replace the file's contents with the following:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/combine/npm/@zendeskgarden/[email protected],npm/@zendeskgarden/[email protected]"
/>
</head>
<body>
<h2 data-i18n-key="hello_world"></h2>
<script src="https://static.zdassets.com/zendesk_app_framework_sdk/2.0/zaf_sdk.min.js"></script>
<script src="translation-strings.js"></script>
<script src="i18n.js"></script>
</body>
</html>
The HTML contains an empty H2 heading. The heading has a
data-i18n-key
attribute of "hello_world". Later, you'll uses this attribute to insert a translation string.The HTML also loads the translation-strings.js and i18n.js scripts. You'll create i18n.js in the next step.
-
In the assets folder, create an i18n.js file. Paste the following into the file:
(function () {
const client = ZAFClient.init();
client.get("currentUser.locale").then((data) => {
let userLocale = data["currentUser.locale"].toLowerCase();
const locale = getSupportedLocale(userLocale);
document.querySelectorAll("[data-i18n-key]").forEach((element) => {
translateElement(element, locale);
});
});
})();
function getSupportedLocale(userLocale) {
// Check if translations exist for locale
// If not, return a locale of "en"
let supportedLocales = Object.keys(translations).map((item) => {
return item.toLowerCase();
});
if (supportedLocales.includes(userLocale)) {
return userLocale;
} else {
return "en";
}
}
function translateElement(element, locale) {
const key = element.getAttribute("data-i18n-key");
const translation = translations[locale]["default"][key];
element.innerText = translation;
}
The code uses the ZAF client's
get()
method to get the current user's locale in Zendesk. It then checks whether the locale exists in the translation-strings.js file'stranslations
object. If not, the code uses theen
locale instead.The code replaces the text of HTML elements with a
data-i18n-key
attribute with a corresponding string from thetranslations
object. For example, for a user with an "fr" (French) locale, an element with adata-i18n-key
of "hello_world" uses thetranslations.fr.default.hello_world
string.
Testing the app
Change your locale in Zendesk to verify the app works as intended.
-
Use the following Show Self request to get your user id and locale.
curl https://{subdomain}.zendesk.com/api/v2/users/me.json \
-u {email_address}/token:{api_token}
Save the
user.id
anduser.locale
from the response. You'll use these later in the tutorial.{
"user": {
"id": 1905826600027,
...
"locale": "en-US",
...
}
}
-
Use the following Update User request to change your locale to
en
. Replace{user_id}
with your user id from step 1.curl -X PUT https://{subdomain}.zendesk.com/api/v2/users/{user_id}.json \
-u {email_address}/token:{api_token} \
-H "Content-Type: application/json" \
-d '{
"user": {
"locale": "en"
}
}'
-
In your shell, navigate to the i18n folder. Example:
cd projects/i18n
-
Start a local ZCLI web server by running the following command:
zcli apps:server
After a moment, a status message appears informing you that the server has started.
Note: To stop the server, press Ctrl+C.
-
In your browser's private or incognito window, sign in to Zendesk Support and go to the Agent Workspace. From the workspace, open a new or existing ticket.
The URL should look like this:
https://{subdomain}.zendesk.com/agent/tickets/{ticket_id}
-
Append
?zcli_apps=true
to the URL and press Enter. The URL should now look like this:https://{subdomain}.zendesk.com/agent/tickets/{ticket_id}?zcli_apps=true
-
Click the Apps icon.
The app displays a "Hello, World!" heading.
-
In your shell, use the following Update User request to update your locale to
fr
. Replace{user_id}
with your user id from step 1.curl -X PUT https://{subdomain}.zendesk.com/api/v2/users/{user_id}.json \
-u {email_address}/token:{api_token} \
-H "Content-Type: application/json" \
-d '{
"user": {
"locale": "fr"
}
}'
-
In your browser, reload the Agent Workspace page. The app now displays a localized French heading.
-
Use the following Update User request to reset your locale to
en
. Replace{user_id}
and "LOCALE" with your user id and locale from step 1.curl -X PUT https://{subdomain}.zendesk.com/api/v2/users/{user_id}.json \
-u {email_address}/token:{api_token} \
-H "Content-Type: application/json" \
-d '{
"user": {
"locale": "LOCALE"
}
}'
Adding a new locale
To add a new locale to the app, add a corresponding JSON file to the translations folder. The file name must be a BCP-47 compliant tag for a language. For a list of supported language tags, see the supported language for Zendesk Support in Zendesk help.
Use the following steps to add the "it" (Italian) locale.
-
In the translations folder, create an it.json file. Paste the following into the file:
{
"default": {
"hello_world": "Ciao mondo!"
}
}
-
Save it.json.
-
In your shell, navigate the app's root folder. Example:
cd project/i18n
-
To update the translation strings in the app, rerun the load-translations.js script:
node load-translations.js
-
Repeat the steps in Testing the app using the "it" locale instead of the "fr" locale.
The app displays a localized Italian heading for the "it" locale.
Adding a new translation string
To add a new translation string, add a new element with the data-i18n-key
attribute to iframe.html. Then add a corresponding translation string to the
default
object of each JSON file in the translations folder. The
property's key must be the data-i18n-key
attribute's value.
-
In iframe.html, add the following button:
...
<body>
<h2 data-i18n-key="hello_world"></h2>
<button data-i18n-key="submit"></button>
<script src="https://static.zdassets.com/zendesk_app_framework_sdk/2.0/zaf_sdk.min.js"></script>
...
</body>
</html>
The button has a
data-i18n-key
value of "submit". -
In the translations folder, add a
submit
property to thedefault
object of each JSON file.en.json:
{
"default": {
"hello_world": "Hello, World!",
"submit": "Submit"
}
}
fr.json:
{
"default": {
"hello_world": "Bonjour le Monde!",
"submit": "Envoyer"
}
}
it.json:
{
"default": {
"hello_world": "Ciao mondo!",
"submit": "Invia"
}
}
-
Save iframe.html, en.json, fr.json, and it.json.
-
In your shell, navigate the app's root folder. Example:
cd project/i18n
-
To update the translation strings in the app, rerun the load-translations.js script:
node load-translations.js
-
To test the translation string, repeat the steps in Testing the app with the "en", "fr", and "it" locales.
"en" locale:
"fr" locale:
"it" locale:
Congratulations! You've localized a Zendesk app. If wanted, you can extend the app by adding more locales and translation strings.