User:JHernandez (WMF)/Translating a google form to other languages

The script only supports translating single page forms, so if you are doing a complicated multi-page form it may not work. By default it only does some special things for multiple choice questions, so if you have other types of questions besides multiple choice, inputs, or paragraphs, the script may need to be improved. More details at the end of this page.

Steps edit

First, make your form normally.

Then, note the ID, you can see it in the URL, it is the long string of gibberish characters. For example, in https://docs.google.com/forms/d/1dVFa2AMR9oSfoeCoCp2RO7xqtVSomZGaSDSGedHRswdfghSAF/edit, the ID is 1dVFa2AMR9oSfoeCoCp2RO7xqtVSomZGaSDSGedHRswdfghSAF.

Then, go to https://script.google.com/, make a new project, give it a name, and paste the following code:

function translateForm() {
  let originalFile = DriveApp.getFileById('ORIGINAL FILE ID, IT IS ON THE URL');
  let file = originalFile.makeCopy('Multilingual - ' + originalFile.getName());
  let form = FormApp.openById(file.getId());
  
  // From https://cloud.google.com/translate/docs/languages
  // Choose the ones you want, comment the others.
  let languages = {
    'Afrikaans': 'af',
    'Albanian': 'sq',
    'Amharic': 'am',
    'Arabic': 'ar',
    'Armenian': 'hy',
    'Azerbaijani': 'az',
    'Basque': 'eu',
    'Belarusian': 'be',
    'Bengali': 'bn',
    'Bosnian': 'bs',
    'Bulgarian': 'bg',
    'Catalan': 'ca',
    'Cebuano': 'ceb',
    'Chinese (Simplified)': 'zh-CN',
    'Chinese (Traditional)': 'zh-TW',
    'Corsican': 'co',
    'Croatian': 'hr',
    'Czech': 'cs',
    'Danish': 'da',
    'Dutch': 'nl',
    'English': 'en',
    'Esperanto': 'eo',
    'Estonian': 'et',
    'Finnish': 'fi',
    'French': 'fr',
    'Frisian': 'fy',
    'Galician': 'gl',
    'Georgian': 'ka',
    'German': 'de',
    'Greek': 'el',
    'Gujarati': 'gu',
    'Haitian Creole': 'ht',
    'Hausa': 'ha',
    'Hawaiian': 'haw',
    'Hebrew': 'he',
    'Hindi': 'hi',
    'Hmong': 'hmn',
    'Hungarian': 'hu',
    'Icelandic': 'is',
    'Igbo': 'ig',
    'Indonesian': 'id',
    'Irish': 'ga',
    'Italian': 'it',
    'Japanese': 'ja',
    'Javanese': 'jv',
    'Kannada': 'kn',
    'Kazakh': 'kk',
    'Khmer': 'km',
    'Kinyarwanda': 'rw',
    'Korean': 'ko',
    'Kurdish': 'ku',
    'Kyrgyz': 'ky',
    'Lao': 'lo',
    'Latin': 'la',
    'Latvian': 'lv',
    'Lithuanian': 'lt',
    'Luxembourgish': 'lb',
    'Macedonian': 'mk',
    'Malagasy': 'mg',
    'Malay': 'ms',
    'Malayalam': 'ml',
    'Maltese': 'mt',
    'Maori': 'mi',
    'Marathi': 'mr',
    'Mongolian': 'mn',
    'Myanmar (Burmese)': 'my',
    'Nepali': 'ne',
    'Norwegian': 'no',
    'Nyanja (Chichewa)': 'ny',
    'Odia (Oriya)': 'or',
    'Pashto': 'ps',
    'Persian': 'fa',
    'Polish': 'pl',
    'Portuguese (Portugal, Brazil)': 'pt',
    'Punjabi': 'pa',
    'Romanian': 'ro',
    'Russian': 'ru',
    'Samoan': 'sm',
    'Scots Gaelic': 'gd',
    'Serbian': 'sr',
    'Sesotho': 'st',
    'Shona': 'sn',
    'Sindhi': 'sd',
    'Sinhala (Sinhalese)': 'si',
    'Slovak': 'sk',
    'Slovenian': 'sl',
    'Somali': 'so',
    'Spanish': 'es',
    'Sundanese': 'su',
    'Swahili': 'sw',
    'Swedish': 'sv',
    'Tagalog (Filipino)': 'tl',
    'Tajik': 'tg',
    'Tamil': 'ta',
    'Tatar': 'tt',
    'Telugu': 'te',
    'Thai': 'th',
    'Turkish': 'tr',
    'Turkmen': 'tk',
    'Ukrainian': 'uk',
    'Urdu': 'ur',
    'Uyghur': 'ug',
    'Uzbek': 'uz',
    'Vietnamese': 'vi',
    'Welsh': 'cy',
    'Xhosa': 'xh',
    'Yiddish': 'yi',
    'Yoruba': 'yo',
    'Zulu': 'zu'
  }

  
  let items = form.getItems().slice();
  
  let languagesDropdown = form.addListItem().setTitle("Language");
  let languageChoices = []
  
  for (let [lang, code] of Object.entries(languages)) {
    let t = translate("en", code)
    let page = form.addPageBreakItem().setTitle(t(form.getTitle()))
    page.setGoToPage(FormApp.PageNavigationType.SUBMIT)
    languageChoices.push(languagesDropdown.createChoice(t(lang) + ' - ' + lang, page))

    for (let enItem of items) {
      let item = enItem.duplicate();
      
      try {
      switch (item.getType()) {
//        case FormApp.ItemType.CHECKBOX:
//          if (item['asCheckboxItem']) item = item.asCheckboxItem()
//          break;
//        case FormApp.ItemType.CHECKBOX_GRID:
//          if (item['asCheckboxGridItem']) item = item.asCheckboxGridItem()
//          break;
//        case FormApp.ItemType.DATE:
//          if (item['asDateItem']) item = item.asDateItem()
//          break;
//        case FormApp.ItemType.DATETIME:
//          if (item['asDatetimeItem']) item = item.asDatetimeItem()
//          break;
//        case FormApp.ItemType.DURATION:
//          if (item['asDurationItem']) item = item.asDurationItem()
//          break;
//        case FormApp.ItemType.GRID:
//          if (item['asGridItem']) item = item.asGridItem()
//          break;
//        case FormApp.ItemType.IMAGE:
//          if (item['asImageItem']) item = item.asImageItem()
//          break;
//        case FormApp.ItemType.LIST:
//          if (item['asListItem']) item = item.asListItem()
//          break;
        case FormApp.ItemType.MULTIPLE_CHOICE:
          if (item['asMultipleChoiceItem']) item = item.asMultipleChoiceItem()
          item.setChoiceValues(item.getChoices().map(choice => t(choice.getValue())))
          break;
//        case FormApp.ItemType.PAGE_BREAK:
//          if (item['asPageBreakItem']) item = item.asPageBreakItem()
//          break;
        case FormApp.ItemType.PARAGRAPH_TEXT:
          if (item['asParagraphTextItem']) item = item.asParagraphTextItem()
          break;
//        case FormApp.ItemType.SCALE:
//          if (item['asScaleItem']) item = item.asScaleItem()
//          break;
//        case FormApp.ItemType.SECTION_HEADER:
//          if (item['asSectionHeaderItem']) item = item.asSectionHeaderItem()
//          break;
        case FormApp.ItemType.TEXT:
          if (item['asTextItem']) item = item.asTextItem()
          break;
//        case FormApp.ItemType.TIME:
//          if (item['asTimeItem']) item = item.asTimeItem()
//          break;
//        case FormApp.ItemType.VIDEO:
//          if (item['asVideoItem']) item = item.asVideoItem()
//          break;


        default: 
          log('Ignored ItemType: '+item.getType());
      }
      } catch (e) {
        log(e)
        throw e
      }

      item.setTitle(t(item.getTitle()))
      item.setHelpText(t(item.getHelpText()))
    }
  }
  
  languagesDropdown.setChoices(languageChoices)
  
  for (let item of items) {
    form.deleteItem(item)
  }

  log(form.getEditUrl())
}

function translate(from, to) {
  return function (text) {
    return from === to ? text : LanguageApp.translate(text, from, to);
  }
}

function log(...args) {
  Logger.log(args);
}

Once you have it there, you can put the ID at the beginning of the script on line 2, and you can try it out by selecting the function name translateForm on the toolbar and clicking play.

It may take a bit to run, if there is an error it will show up on the UI, and you can check the logs to see what happened.

If everything went well you will see a new file in the same folder as the original.

Common errors edit

Too many languages, and questions, results in a huge form. You may get an error about the form size.

Also, the script only accounts for text inputs and paragraphs, and multiple choice questions, so if you have other types of questions, like lists, dates, etc., you may have to adapt the switch statement on line 136 to do the right thing.

Here is link to the google documentation that will help you figure out how to get into the question and its data to pass it through translation in the script: https://developers.google.com/apps-script/reference/forms/form