Skip to main content

Translate Purpose-built Apps for Multiple Languages

Summary​

Task: Configure multi-language support for app names, tab names, and UI text

Time estimate: 20-30 minutes

Skill level: Intermediate

Prerequisites​

  • Purpose-built App project initialized
  • Understanding of plugin translation files
  • List of target languages
  • Translations prepared for all user-visible text

Steps​

Step 1: Identify Fields to Translate​

Purpose-built Apps have several user-visible fields that require translation:

FieldLocationTranslation Method
App namePlugin configurationname property in translation file
Tab namesTab configurationnameKey property + translation file
Tab titles (config page)Tab configuration settingstabTitle.key property + translation file
Tab descriptions (config page)Tab configuration settingstabDescription.key property + translation file
Custom Block stringsCustom Block pluginsCustom Block translation files

Step 2: Create Plugin Translation Files​

Create or update your plugin's translation files. The platform only loads translations from the public/translations/ folder in your plugin, and each file is named [language-code].json.

File structure:

your-plugin/
├── config.json
└── public/
└── translations/
├── en.json
├── es.json
├── fr.json
└── de.json

Example en.json:

{
"name": "Customer Support Portal",
"homeTab": "Home",
"ticketsTab": "Support Tickets",
"reportsTab": "Analytics",
"homeTabTitle": "Home Dashboard",
"homeTabDescription": "Overview of support metrics and recent activity",
"ticketsTabTitle": "Support Tickets",
"ticketsTabDescription": "View and manage customer support tickets"
}

Example es.json:

{
"name": "Portal de Atención al Cliente",
"homeTab": "Inicio",
"ticketsTab": "Tickets de Soporte",
"reportsTab": "Analíticas",
"homeTabTitle": "Panel de Inicio",
"homeTabDescription": "Resumen de métricas de soporte y actividad reciente",
"ticketsTabTitle": "Tickets de Soporte",
"ticketsTabDescription": "Ver y administrar tickets de atención al cliente"
}

Step 3: Configure App Name Translation​

The app name uses the name property from your translation files. This is automatically handled by the plugin system - no additional configuration needed in config.json.

In your translation files:

// public/translations/en.json
{
"name": "Customer Support Portal"
}

// public/translations/es.json
{
"name": "Portal de Atención al Cliente"
}

// public/translations/fr.json
{
"name": "Portail de Support Client"
}

Step 4: Configure Tab Name Translation​

Set the nameKey property for each tab to reference a translation key:

{
"metadata": {
"tabs": [
{
"nameKey": "homeTab",
"type": "content",
"href": "/dashboard"
},
{
"nameKey": "ticketsTab",
"type": "content",
"href": "/tickets"
},
{
"nameKey": "reportsTab",
"type": "content",
"href": "/reports"
}
]
}
}

Corresponding translation entries:

{
"homeTab": "Home",
"ticketsTab": "Support Tickets",
"reportsTab": "Analytics"
}

Step 5: Configure Configuration Page Translations​

For the app configuration page, translate tab titles and descriptions using the key property:

{
"metadata": {
"tabs": [
{
"nameKey": "homeTab",
"configurationSettings": {
"configurable": true,
"tabTitle": {
"key": "homeTabTitle"
},
"tabDescription": {
"key": "homeTabDescription"
}
}
},
{
"nameKey": "ticketsTab",
"configurationSettings": {
"configurable": true,
"tabTitle": {
"key": "ticketsTabTitle"
},
"tabDescription": {
"key": "ticketsTabDescription"
}
}
}
]
}
}

tabTitle/tabDescription (and their Key counterparts) live under each tab's configurationSettings object, not on the tab directly.

Corresponding translation entries:

{
"homeTabTitle": "Home Dashboard",
"homeTabDescription": "Overview of support metrics and recent activity",
"ticketsTabTitle": "Support Tickets",
"ticketsTabDescription": "View and manage customer support tickets"
}

Step 6: Translate Custom Block Strings​

Custom Blocks use a separate, generic Extension SDK translation mechanism (the Plugin Client's getText), not the PBA-specific nameKey/tabTitleKey system used in the rest of this guide. Their translation files still live under public/translations/, but are named with an uppercase language code (EN.json, ES.json) and use a { meta, strings } shape instead of flat key-value pairs.

Custom Block translation structure:

custom-block-plugin/
├── config.json
├── public/
│ └── translations/
│ ├── EN.json
│ └── ES.json
└── src/
└── App.tsx

Example public/translations/EN.json:

{
"meta": {
"summary": "Custom Block Language Strings - EN"
},
"strings": {
"welcomeMessage": {
"text": "Welcome",
"context": "Heading shown at the top of the custom block"
},
"instructions": {
"text": "Follow the steps below",
"context": "Instructional text below the heading"
}
}
}

In Custom Block code:

// `client` is passed into your component via props
function MyCustomBlock({ client }) {
return (
<div>
<h1>{client.getText('welcomeMessage')}</h1>
<p>{client.getText('instructions')}</p>
</div>
);
}

See getText in the Plugin Client reference for the full API, and the Custom Block documentation for complete translation guidance.

Step 7: Test Translations​

  1. Save all translation files and config.json
  2. Rebuild and deploy your Purpose-built App
  3. Log in to Qualtrics with different language settings
  4. Verify app name appears in correct language
  5. Check that tab names translate properly
  6. Review configuration page translations
  7. Test Custom Block translations (if applicable)

Checkpoint: Your Purpose-built App should display in the user's preferred language across all components.

Common Issues and Solutions​

Issue: Translations Not Appearing​

Symptoms: Text shows as translation keys (e.g., homeTab instead of "Home")

Causes:

  • Missing translation file for user's language
  • Typo in translation key
  • Translation key not defined in translation file

Solution:

Verify translation key exists in all language files:

// ❌ Missing in public/translations/es.json
{
"homeTab": "Home"
}

// ✅ Present in all files
// public/translations/en.json
{"homeTab": "Home"}
// public/translations/es.json
{"homeTab": "Inicio"}

Ensure key names match exactly between config.json and translation files:

// config.json
"nameKey": "homeTab"

// public/translations/en.json
"homeTab": "Home" // ✅ Matches
"home_tab": "Home" // ❌ Doesn't match

Issue: Some Languages Work, Others Don't​

Symptoms: English works but Spanish shows keys

Causes:

  • Missing translation file for specific language
  • Incomplete translations in language file

Solution:

Ensure all language files exist and have complete translations:

public/translations/en.json ✅
public/translations/es.json ✅
public/translations/fr.json ✅
public/translations/de.json ❌ Missing

Verify each language file has all keys:

// public/translations/en.json
{
"homeTab": "Home",
"ticketsTab": "Tickets",
"reportsTab": "Reports"
}

// public/translations/es.json - ❌ Missing reportsTab
{
"homeTab": "Inicio",
"ticketsTab": "Tickets"
}

Issue: Fallback Language Not Working​

Symptoms: Missing translations show keys instead of English fallback

Causes:

  • No fallback language configured
  • Primary translation file missing

Solution:

Always provide public/translations/en.json as the fallback:

public/translations/en.json   ✅ Required - base language
public/translations/es.json Optional
public/translations/fr.json Optional

Alternative Approaches​

Using Value Instead of Key​

For simple apps or testing, you can use direct values instead of translation keys:

{
"tabTitle": {
"value": "Home Dashboard" // Direct value, not translated
}
}

Appropriate for:

  • Single-language deployments
  • Rapid prototyping
  • Non-translated content (proper nouns, brand names)

Hybrid Approach​

Mix translated and non-translated content:

{
"tabs": [
{
"nameKey": "homeTab", // Translated
"tabTitle": {
"value": "Acme Corp Portal" // Not translated (brand name)
}
}
]
}

Best Practices​

Translation Management​

  • Use descriptive translation keys (homeTabTitle not t1)
  • Keep translation files in version control
  • Document what each key is used for
  • Review translations with native speakers
  • Test all supported languages before release

Content Guidelines​

  • Keep text concise (tab names especially)
  • Avoid idioms that don't translate well
  • Consider text expansion in some languages (German is often longer)
  • Test UI layout with longest translations
  • Use consistent terminology across translations

Maintenance​

  • Update all language files when adding new text
  • Archive obsolete translation keys
  • Use translation management tools for large projects
  • Document which languages are officially supported
  • Plan for adding new languages in the future

Recap​

You've successfully configured multi-language support for your Purpose-built App. Your app now:

  • Displays in users' preferred languages
  • Translates app names and tab names
  • Supports configuration page translations
  • Provides consistent multilingual experience
  • Scales to additional languages as needed

This makes your Purpose-built App accessible to global users and enhances the user experience across different regions.