HubSpot Forms
The proxy supports translation of HubSpot (or similar) forms via a combination of project linking and JS translation.
Method #1 marshals a combination of advanced proxy features. It is entirely hands-off from the site maintainer’s perspective, no change on the original server is necessary (which is a rather frequent constraint).
Method #2 relies on injected JS and HubSpot to provide separate, localized forms for each target language. Compared to #1, it is a clean and simple approach.
Method #1: Proxy
The proxy approach traces the structure of the main and form domains via linked projects. Affected JS resources/endpoints are overridden and the responses marked as translatable.
Project Creation & Setup
HubSpot uses several external domains to drive a form. You will see https://js.hsforms.net/forms/v2.js referenced in the page source. This file itself references https://forms.hubspot.com, which is where the translatable form contents are coming from.
Domains used by a HubSpot form are related to the main project and each other in the following manner:

Assuming that example.com is already set up, at most two additional projects are required:
js.hsforms.com: creation of this project is optional, though not complicated. At the time of writing, visiting the landing page results in a403 Forbiddenpage (but this is not a problem).forms.hubspot.com: this URL redirects you tohttps://developers.hubspot.com/. To create a project for it, disable Redirect checking in the Add Project dialog. Click on Advanced settings to reveal the option and uncheck the checkbox:

Don’t forget to add every target language of the main project to each project you create.
Link Projects
Open each project in a separate tab and link each project according to the section on Project Linking. The result should be a chain of projects leading from example.com to forms.hubspot.com with js.hsforms.net as an intermediary.
Alternative: Search & Replace
The js.hsforms.net project is not, strictly speaking, necessary. Its true purpose is merely to expose a slightly modified version of the /forms/v2.js script. If its URL is referred to in a way that makes it possible, you can sidestep the domain using a combination of Search & Replace and a page content override. The setup steps for this are as follows (done on the main project):
create a path override for the exact URL where the form is present (the diagram above shows
/contactas an illustration).add a Search & Replace rule: replace
https?://js.hsforms.net(a regex matching both HTTP and HTTPS versions of the same URL) with the empty string. This turns the reference to/forms/v2.jsinto a relative URL, pointing it toward a page content override that is to be created in a moment).
Overriding v2.js
This resource contains a crucial variable called urlRoot, which has to be remappable over the proxy. However, it is set via a computed expression, which is unsupported by the proxy for reasons discussed in the section on JS translation, so an override and a small change is unavoidable (regardless of the presence/absence of the intermediate project). Follow the steps below to create the override:
visit
https://js.hsforms.net/forms/v2.jsand copy & paste the contents of the JS file.use the DevTool or an online pretty printer before pasting the code. Though optional, it is highly recommended that you do this (such minified code is cumbersome to work with as it is).
create a PCO for the
/forms/v2.jspathname in Page modifiers > Content Override. The response code default is 200, and theContent-Typeheader isapplication/javascript; charset=utf-8. We’ll return toCache-ControlandPragmalater, after setup is complete.Add the following line to the top of the PCO:
var HUBSPOT_URL_ROOT = "https://forms.hubspot.com";
Search for
this.urlRoot. It is set in a line similar to the one below:
o ? this.urlRoot = "https://f.hsforms" + e + ".net/fallback" : null != a ? this.urlRoot = "" + a : this.urlRoot = "https://forms.hubspot" + e + ".com";
Add the following line after it to make it use the “accessible” value:
this.urlRoot = HUBSPOT_URL_ROOT
Use the Mark multiple resources as Translatable text field in Advanced settings. Simply add the pathname prefix of the PCO to the list:
/forms/v2.js
URL Translation & HTTP/HTTPS Finally, add the following JS path to the list of translatable paths in Advanced settings:
"HUBSPOT_URL_ROOT" url
Open the PCO link over any one of the proxy preview domains to test it. If all projects are correctly linked and you followed the setup steps correctly, the HUBSPOT_URL_ROOT variable will hold an appropriate proxy-mapped domain (and consequently this.urlRoot will be set to the same value).
Form Contents
Set up the HubSpot content endpoint as translatable on the project for forms.hubspot.com according to the JS translation section. In summary:
locate the form request using the DevTool and add it to the “Mark multiple resources as translatable” list of prefixes. For any given HubSpot form, translatable content will usually be associated with a prefix similar to the one below (it will also have a
callbackquery parameter).
/embed/v3/form/{numericId}/{formId}
use the JSON path tester tool in Advanced settings to process the response. HubSpot forms come in a response format called JSONP or padded JSON (a function call such as
hs_request_0with the form data passed to it as argument). It is not necessary to prefix JS paths with"json"in this case.use the x-proxy to test your JS paths, and use Preview for content extraction.
Publishing & Caching
All projects need to be published together in all target languages. Note that you don’t need to publish on a subdomain of the original server: you are free to proxy the German version of forms.hubspot.com through hs-de.mydomain.com, for example.
Once setup, translation and publishing is complete, you are free to set an appropriate Cache Header on your page content overrides (either on the PCO itself or on a prefix-basis) to reduce page request costs.
Method #2: HubSpot & Injected JS
You can rely on HubSpot to localize the form property names after cloning your form for each target language, and rely on a little JavaScript zo drive the forms on the client-side for each target language. This approach is cleaner than the one described above, as long as you don’t mind having a separate form for each target language.
The proxy sets the lang attribute of the <html> tag to the appropriate locale code on each target language domain, which you can use for branching. The code below demonstrates one example of how such code could look in practice:
var lang = document.querySelector("html").getAttribute("lang");
var HSFormId = {
"en-US": "English9-bb4c-45b4-8e32-21cdeaa3a7f0",
"fr-FR": "Frenche9-bb4c-45b4-8e32-21cdeaa3a7f0",
"de-DE": "Germane9-bb4c-45b4-8e32-21cdeaa3a7f0"
};
// refer to the HubSpot documentation for further customization at
// https://developers.hubspot.com/docs/methods/forms/advanced_form_options
hbspt.forms.create({
portalId: "portalId",
formId: HubSpotFormId[lang]
})