Getting Started

Learn through 101 guides and easy solutions.

The Simple Way to Create Multi-Language Account Engagement Forms

The Simple Way to Create Multi-Language Account Engagement Forms

min. reading

Handling multiple languages with Account Engagement (Pardot) forms has always been complex — especially when it comes to reporting. But there is a way to multi-language Account Engagement forms.

The traditional solution — one form per language — has its drawbacks. But it’s something that’s super important for companies that use Account Engagement on a global scale to do in a logical and user-friendly way. 

Today, we’ll explore a new, more efficient method that improves reporting and streamlines the translation process.

Challenges with traditional solutions for creating multi-language Account Engagement forms

There are a few ripple effects that we have to handle when we use multiple forms to realistically capture one set of data. 

First, we need a way of figuring out which form we want to display. Commonly this is done as a piece of dynamic content driven off a known Prospect field.

Next, we need to handle submissions for a single goal across multiple forms. The approach we take can vary depending on how complex our Automations and Reporting strategies are, and it all can add up.

A new solution for handling multiple languages

We can still work within the constraints of Account Engagement (Pardot) and leverage a common web development pattern of internationalization (or i18n for short). With the power of JavaScript, we can have one Account Engagement form and feel confident that our visitors will be able to have it in their language.

JavaScript and Handlebars.js

Before we dive into the actual code (honestly my favorite), it might be helpful to talk about what we are going to use.  We have a mix of a little bit of custom JavaScript with a common JavaScript library called HandlebarsJS, not to be confused with Account Engagement Handlebars Merge Language (HML).

The custom JavaScript takes the HTML that Account Engagement will render, look for the i18n placeholders and do a real-time replacement with the translations you have set up. This gives you full control over the wording and design in each language for every page.

Both HML and HandlebarsJS (by default) use double curly braces for wrapping placeholders. We’ve chosen to help differentiate between the two easily by specifying square brackets.  

Getting into the details

So as a super simple example, you can use the label [[i18n.firstname]] to have English, French, Spanish (or any other language you want) for the value {{Recipient.first_name}}.

Example of single Account Engagement form supporting 3 languages

Ok, let’s show what this can look like. Here we have a demo form that supports three languages.

Pre-work to do for your multi-language Account Engagement forms

If you’ve previously filled out the form, we will render the form in the language you specified. If you haven’t, we’ll try to use your browser’s language. Form error messages and thank you content are all translated.

Back in Account Engagement, there are a few things that need to be done.

Here’s what to do:

  1. Edit form fields – Each Form Field needs to be edited to use a label in the format [[i18n.TOKEN]] (where the TOKEN can be a field name or anything you like
  2. Edit dropdown field values – Each Dropdown field value needs to be edited to use a label in a similar format
  3. Ensure dropdown fields store language code – The Form should have a Language dropdown field that stores the language code. Language choice labels should use a label in a slightly different format. It should use [[lang.CODE]].
  4. Check submit button text – Submit button text should be edited to use a label in a similar format.
  5. Check thank you content – Thank you content should be edited to use labels in a similar format.

Add JavaScript to the form

Once you have all your labels set up, we need to actually add the JavaScript to the form.  There are a few ways you can do this and the approach will depend on just how reusable (and large) you want your JavaScript to be.

In our example, we’ve placed the JavaScript in the Layout Template, which provides a balance of re-usability (can be used by multiple forms) and maintenance (common, but not all translations for the entire site).

Ok, time for the code. I’ve split this JavaScript into three sections, but it can all be copy and pasted into a single <script> block in your Layout Template.

Define languages the form will support

First, we have a JavaScript object that defines the languages that we will be supporting, as well as the label of that language. Feel free to adjust this as necessary, just keep the structure intact.

// the supported languages by this script
const languages = {
  lang: {
    en: 'English',
    fr: 'Français',
    es: 'Español'

Add the translations

Next we have all of the translations

// the translations for each language
const translations = {
  'en': {
    i18n: {
      firstname: "First Name",
      lastname: "Last Name",
      company: "Company",
      email: "Email",
      industry: "Industry",
      hospitality: "Hospitality",
      tech: "Tech",
      submit: "Save now",
      language: "Language",
      formErrors: "Please correct the errors below:",
      fieldError: "This field is required",
      thankyou: "Thanks for submitting!"
  'fr': {
    i18n: {
      firstname: "Prénom",
      lastname: "Nom de famille",
      company: "Société",
      email: "Email",
      industry: "Secteur d'activité",
      hospitality: "Hospitality",
      tech: "Technologie",
      submit: "Enregistrer",
      language: "Langue",
      formErrors: "Corrigez les erreurs ci-dessous:",
      fieldError: "Ce champ est obligatoire",
      thankyou: "Merci d'avoir soumis"
  'es': {
    i18n: {
      firstname: "Primer nombre",
      lastname: "Apellido",
      company: "Compañía",
      email: "Correo electrónico",
      industry: "Industria",
      hospitality: "Hospitalidad",
      tech: "Tecnología",
      submit: "Guardar ahora",
      language: "Idioma",
      formErrors: "Por favor corrija los siguientes errores:",
      fieldError: "Este campo es obligatorio",
      thankyou: "Gracias por enviar"

For each token you want to be translated, you will need to add a translation for each language. Like how languages are set up, you can make any adjustments/additions you want… just keep the structure intact.

Add the main functionality to apply translations you defined

Next, we have the main functionality. This handles the actual work of applying the translations we have defined already.

function i18nForm(prospectLang) {
  document.addEventListener("DOMContentLoaded", function(event) {
    //used to convert into handlebars. Not entirely necessary if this JS is in Layout Template, but needed if JS is in Form
    const brO = '{', brC = '}';
    let formErrors = document.querySelector('#pardot-form p.errors');
    if (formErrors != null) {
      // look for error messages in the original HTML. Pardot won't let us translate that, so we will hack it a bit here
      document.querySelector('#pardot-form p.errors').innerHTML = `[[i18n.formErrors]]`;
      [...document.querySelectorAll('#pardot-form')].forEach(node => { // loops through each field error
        node.innerHTML = `[[i18n.fieldError]]`;
    // stores the original HTML, or what was rendered from Pardot initially (with our placeholders)
    // also converts from using square braces (to make Pardot happy) to using Curly Braces (to make handlebarsjs happy)
    const originalHtml = document.querySelector('body').innerHTML
      .replace(/\[\[/g, `${brO+brO}`).replace(/\]\]/g, `${brC+brC}`);
    // creates the Template that Handlebars can use to generate processed (translated) HTML later on
    const processTemplate = Handlebars.compile(originalHtml);

    // get the language the Browser is using
    const browserLang = window.navigator.language.substr(0, 2);
    // console.log(`browserLang=${browserLang} and prospectLang=${prospectLang}`);
    // figure out which language we are going to go with
    let currentLangCode = prospectLang || browserLang;
    let currentLangVal = '';

    // retrieves the allowed languages, as Pardot doesn't actually use the language values we need to use, they change it to numbers (blegh)
    const pardotLanguages = new Array();
    const langNodes = document.querySelectorAll('.langChoice select option');
    [...langNodes].forEach(option => { // loops through the values in the Language Dropdown, storing lang code and numeric value for use
      let lang = option.text.replace(/\[|\]|lang./g, '');
      //console.log(`lang=${lang} and option value=${option.value}`);
      pardotLanguages[option.value] = lang;
    [...langNodes].forEach(option => { // loops through the values in the Language Dropdown, checking to see if one was selected
      let lang = option.text.replace(/\[|\]|lang./g, '');
      if(option.selected) {
        currentLangVal = option.value;
        currentLangCode = lang;
    console.log(`initially translating form to ${currentLangCode}`);

    function applyTranslations() {
      let translatedHtml = processTemplate({
      //replaces the visible HTML with the translations in place
      document.querySelector("#pardot-form").innerHTML = translatedHtml;
      document.querySelector('.langChoice select').value = currentLangVal;

      //handle when the language dropdown value is changed, translating on the fly
      document.querySelector('.langChoice select').onchange = function() { // we only want to translate to a valid language
        let selectedLang = pardotLanguages[this.value];
        if (selectedLang in languages.lang) {
          currentLangCode = selectedLang;
          currentLangVal = this.value;
          // console.log(`new language is ${currentLangVal} which is ${currentLangCode}`);
        applyTranslations(); // re-apply the translations when the value in this dropdown changes
    applyTranslations(); // apply the translations for the first time

Enable the form to detect language for known prospects

The last thing we need to do is tie this all together. Because we want to try to leverage the Prospect Language (if a known Prospect and we have a value in their Language Custom Field), we need to add just a little bit of JavaScript to each Form, in the Form’s Look & Feel as well as the Thank You content.

  // get the language the Prospect has saved
  const prospectLang = "{{{Recipient.Language}}}"; //Pardot HML  
  // kick off translations

Test and revise

All that’s left to do is test it out, and then mold this example into what you need.


Like any JavaScript examples you might find online, they are opinionated in approach. Making minor changes can sometimes break the code due to assumptions that might not be well documented/understood. I’ve left a bunch of console.log statements commented throughout the code to hopefully help you troubleshoot when things go wrong.

One of those opinions is using the “i18n” and “lang” prefixes. We think this makes the placeholders easier to read, even if it slightly complicates the JavaScript object itself. Feel free to remove this if you want, just know to make the various adjustments.

One Account Engagement form can handle all the languages you need

If your company works with audiences who speak a variety of languages, then this is the perfect solution for you to simplify the way you build forms in Account Engagement. Our new approach simplifies translating Pardot Forms, improves reporting, and offers a better user experience for a multilingual audience.

Still not sure how to approach your global marketing strategy? Then reach out to the team at Sercante for guidance along the way.

Subscribe to The Spot

This field is for validation purposes and should be left unchanged.

Community Events


Top 10 Recent Post

  • Adam Erstelle is a Developer with Sercante. He loves learning about and solving really interesting challenges with Pardot and Salesforce often by building some cool tools.

Leave Your Comment

Related Articles

Bot Single Post