function populatePlaceholder(placeholder, data, defaultSubstitute) {
  // prepare populated string/array
  let populated
  let hasValueForKey = true

  // populate nested placeholders
  if (placeholder.placeholders) {
    // populate and add to array of populated nested placeholders
    populated = placeholder.placeholders.map(nestedPlaceholder => {
      return populatePlaceholder(nestedPlaceholder, data, defaultSubstitute)
    })
  }

  // no nested placeholders, this is the base case
  else {
    // populate with data for keypath
    populated = Utils.accessObjectByString(data, placeholder.keypath)

    //Check to see if 'populated' is a numeric 0
    if( typeof(populated) === 'number' && populated === 0)
    {
      //convert to a string 0 as numeric zero will fail a test like - if (!populated){do something}
      populated = "0";
    } 
    
    // check if substitute is needed
    //NOTE - this check will fail for a numeric zero.
    if (!populated) {
      hasValueForKey = false

      // true signifies to use default substitute
      if (placeholder.substitute === true) {
        populated = defaultSubstitute
      }

      // use specified substitute
      else if (placeholder.substitute && placeholder.substitute.length) {
        if (placeholder.substitute[0] === '?') {
          // iterate over substitute stack in the given order
          // the first substitute key that returns data is used
          let substituteStack = placeholder.substitute.substring(1).split('?')
          for (let i = 0; i < substituteStack.length; ++i) {
            populated = Utils.accessObjectByString(data, substituteStack[i])
            if (populated) break
          }

          // use default if placeholder substitute didn't return any data
          if (!populated) populated = defaultSubstitute
        } else {
          populated = placeholder.substitute
        }
      }

      // return empty string when no substitute should be used
      else {
        populated = ''
      }
    }
  }

  // apply filters
  if (placeholder.filters) {
    placeholder.filters.forEach(filter => {
      populated = Filters.applyFilter(filter, populated)
    })
  }

  // make sure that populated is always a string before returning
  // it could be an array if a filter apply function was not found
  if (populated instanceof Array) {
    populated = populated.join(' ')
  }

  return String(populated)
}
Populates a placeholder with data, returning the populated string.

@param {Object} placeholder
@param {Object} data
@param {String} defaultSubstitute
@returns {String}