We are in the process of launching a new website. As we were reviewing our old forms, we began looking into how we would handle translations. Having 7 versions of the same form (Contact Us English, Contact Us French, Contact Us German, etc.) sounds aweful to us. I am curious, how have others handled translations of forms in Marketo?
Sanford Whiteman shared this wonderful method for handling translations, https://blog.teknkl.com/smoothing-embedded-marketo-form-loads/. Has anyone tried this approach? Any challenges we should anticipate?
Solved! Go to Solution.
It’s PlaceholderText, not Placeholder.
@SanfordWhiteman is it possible to modify the placeholder value of a field using this method? I've tried adding placeholder as part of the JSON but it does not change the placeholder value of the field I reference. I've added it to the JSON like this:
{
Name: "FirstName",
Placeholder: "Séance B"
}
It’s PlaceholderText, not Placeholder.
Thank you, I didn't know the correct nomenclature
Has anyone tried this approach?
I have.
Good when paired with https://blog.teknkl.com/safely-embedding-json-in-a-rich-text-as-opposed-to-plain-text-my-token/
Where does this translate function get placed? I'm also confused because you've defined a translateMktoDescriptor function in the sample code, but then there's also a translateMktoForm function that doesn't seem to be defined. I'm also curious how to handle translating select list option labels. I'm guessing you'd need an additional conditional loop within the translate function, but I'm not sure where I'd put that in the JSON file.
Additionally, how do you determine which language to translate everything into?
Is there a working example of this approach out there in the wild?
Additionally, how do you determine which language to translate everything into?
The language code could be previously stored in a cookie, put in the path/query string, wherever. How do you usually choose/store the lead's preferred language?
Is there a working example of this approach out there in the wild?
Right here:
MktoForms2 :: Manual descriptor, localize <select>
You're right that there was a mismatch between the function name and the function call in the blog post, changed that.
I've got this working on the initial page load, but I'm not sure how to re-render the form if a user changes their language preference (a dropdown field on the form). I tried attaching an event listener to the field, which runs the function, but the descriptor is undefined and I'm not sure how to access it outside the initial load.
MktoForms2.whenReady(function(form){
var formEl = form.getFormElem()[0];
var langField = "Language_Preference__c";
var langEl = formEl.querySelector("#"+langField);
langEl.onchange = function(e){
//console.log('Running');
session.lang = langEl.value();
translateMktoForm(formEl.descriptor, mktoFormLanguages, session);
}
});
No, that won't work -- the descriptor is only parsed once.
It seems surprising that you would need to keep the person on the same page (including all the other potentially localized information on the page) after they change their language preference. Usually that's grounds for a page reload.
The language preference is a newly-introduced concept for this global company, so everything will default to English until users begin selecting their preferences. I'd like to be able to translate the whole page again if the user selects a new language preference, but I suppose I could force a page reload and re-render everything if it's not possible to do on the fly.
To localize the entire page without a full document refresh requires some major front end engineering. If you look at the world's biggest sites, even those that otherwise operate as single-page apps still refresh the whole doc when you change the language.
Well, I thought I'd be clever and use a hash to override the language preference using this:
var supportedLangs = ["English","Chinese","Japanese","Korean","Spanish","Portuguese","French","German","Polish","Italian"];
var hash = location.hash.substring(1);
var langpref;
if(supportedLangs.includes(hash)){
langpref = hash;
}
else{
langpref = "{{lead.Language_Preference__c:default=English}}";
}
var session = {lang: langpref};
and then adding an event listener to the form to redirect with the new hash like this:
MktoForms2.whenReady(function(form) {
var formEl = form.getFormElem()[0];
var langField = "Language_Preference__c";
var langEl = formEl.querySelector("#" + langField);
langEl.onchange = function(e) {
window.location.assign(window.location.pathname + "#" + langEl.value);
}
});
but that doesn't actually re-load the form from the server. I also tried adding in a window.location.reload(true); somewhere and got stuck in an infinite redirect loop, but I can't remember how I did that exactly. I was thinking I could do something on the page to check if the hash was a supported language, and not equal to a non-blank value of the form field, but the page redirect doesn't trigger another whenReady() event on the form, so I couldn't get that to work right.
Don't use Array#includes, it doesn't work in any version of IE.
Also don't overwrite the single onchange function, add a new listener.
Things like hash = document.location.hash.substring(1) give me the willies (use of the same var name and property name). Try using something semantically accurate, like runtimeLang = document.location.hash.substring(1).
Other than that, the general approach will work, but you must be able to call document.location.reload. I don't know what code you tried that was getting you into a redirect loop.
MktoForms2.whenReady(function(form){
var formEl = form.getFormElem()[0],
langField = "Language_Preference__c",
langEl = formEl.querySelector("[name='"+ langField + "']");
langEl.addEventListener("change", function(e){
document.location.hash = form.getValues()[langField];
document.location.reload();
});
});
Thanks Sandy. Good heads up on the Array.includes. I ended up using Array.prototype.indexOf. While it isn't supported prior to IE9, they decided they didn't need to support older versions.
I also took your advice on the variable name--definitely likely to cause some headaches...
For anyone else looking to do this, I also added a condition to the event listener to make sure the new value of the Language_Preference__c field was different than the current session language. Not including this makes the form unsubmittable as it just reloads every time you change the language preference.
MktoForms2.whenReady(function(form) {
var formEl = form.getFormElem()[0],
langField = "Language_Preference__c",
langEl = formEl.querySelector("[name='" + langField + "']");
langEl.addEventListener("change", function(e) {
if (form.getValues()[langField] && form.getValues()[langField] != session.lang) {
document.location.hash = form.getValues()[langField];
document.location.reload();
}
});
});
If you set the field value to the session language (programmatically using setValues) then it wouldn't be a change event.
Correct, but I'm only changing the value programmatically if it is already stored in a token or present in the hash, and the session language is set prior to the form load (in order to determine what language to load everything in)--in which case it would be equal to the value I'm setting, and I wouldn't want to reload the page because it's already in the correct language.
The only time a reload should occur is if the user changes the form value to a new value that is not blank and is not the current session language.
What other scenarios might I want to set it programmatically and have that trigger a change event? I can't think of a reason I'd need to do this.
I may also get into using sessionStorage to restore previously filled out values if/when the page is reloaded due to changing the language preference (only potential PII is an email address) in order to prevent the user from having to fill them out again, but I haven't thought through all of the potential implications of that yet. I'd be interested in what, if any, thoughts you have on that potential approach.
No, I'm saying you don't need to worry about the change if you set it programmatically. Hence there shouldn't be a situation where the person "changes the dropdown to be the same as the session language" because if the dropdown is already set to Language A, and they drop it down and select Language A, that won't be a change, hence won't reload the page.
@SanfordWhiteman Any ideas on how to scalably translate any rich text included in a form? It doesn't look it's possible to give those a name, and it comes through in the descriptor like this:
[
{
"Id": 29708,
"Name": "HtmlText_2019-09-16T14:03:23.709Z",
"Datatype": "htmltext",
"InputInitialValue": "",
"LabelWidth": 260,
"ProfilingFieldNumber": 0,
"Htmltext": "<p>Here is some text.</p>",
"IsLabelToLeft": true
}
],
If it's just one form, that's fine, but even if the form is cloned, I think the rich text gets a new Id and Name attribute. I suppose you could evaluate the Htmltext, but that seems messy and error-prone as well.
I think you'd have to inject and parse the HTML. It shouldn't be too error-prone as long as you only look for the trimmed textContent.
Thanks for your reply Sanford! In reading through the link, that is for Marketo LPs, but not embedded forms on the main site, correct?
Either one!