Translation Studio translates a HubSpot campaign — its website pages, landing pages, blog posts and marketing emails — into the languages you choose, as drafts in HubSpot's own editors, with your term list applied every time. It shows, per asset and per language, what is translated, what is missing and what has gone out of date since it was translated.

The problem it answers: brand names and industry terms come out differently from one page to the next, and HubSpot's built-in AI translation gives you no way to fix that. It is powered by DeepL and has no glossary, terminology or do-not-translate setting.

KindHubSpot private app (HubSpot developer platform 2026.09), installed on your own portal
Built forMarketing teams that publish one campaign in several languages on HubSpot, and the partners who run that for them
TranslatesWebsite pages, landing pages, blog posts, marketing emails — including text in custom modules
EnginesDeepL with a synced DeepL glossary, Claude (Anthropic) with your terms as mandatory, or a no-network Test engine
OutputDrafts only. Nothing is ever published by the app
Stores data inYour own portal: 3 HubDB tables and an encrypted settings record. No worksby.design server is involved
How to get itBy invitation — worksby.design/get/translation-studio: enter the invited email address and a download link that lives 24 hours is sent to it; see Requirements and getting it

Important

Maturity, as of 2026-11-10: proof of concept. The whole flow — campaigns, target languages, the asset × language matrix, every status, drafts in all four content types, attaching translations to the campaign, the glossary, settings and storage — has run on a HubSpot portal with the Test engine, which marks text instead of translating it. The DeepL and Claude engines are built and unit-tested against fakes, but have not yet been run against the live DeepL or Anthropic services. It has not been used on a real customer's content. Plan a trial on a copy of one campaign before relying on it.

Why HubSpot's own translation is not enough#

HubSpot's native AI translation is good at sentences and has no way to be told your words.

HubSpot's native AI translationTranslation Studio
EngineDeepLDeepL or Claude, your choice and your account
Glossary / term listNone. Neither help article mentions one (both read 2026-11-10); the only persistent control is brand voice, which governs tone, not termsA HubDB table your marketing team edits in HubSpot, applied on every run
Custom modules"Automatic translation isn't available for custom blog or page modules" (HubSpot knowledge base)Translated — text fields inside custom modules are read and written back
OverviewOne asset at a timeEvery asset in a campaign × every target language, with a status per cell
Knowing what changedNot trackedA translation records the source version it was made from, so an edited source reads Outdated

A request for exactly this feature is open in HubSpot's community (Custom Terminology for AI Website Translations). The glossary claim is the one most likely to change; it was last checked on 2026-11-10.

When it fits#

  • You run multi-language content in HubSpot (Content Hub Professional or Enterprise) and campaigns (Marketing Hub Professional or higher), with an Enterprise subscription on at least one hub.
  • Your translation is machine first, human reviewed: an engine drafts, a language owner corrects and publishes in HubSpot.
  • You have terms that must not drift — product names, brand terms kept in English, industry vocabulary with one correct rendering per language.
  • You are a HubSpot partner running localisation for several clients and want the term list and the status per language in the client's own portal.

It is not a translation-management system. If you work with professional translators, translation memory and per-word vendor workflows, a translation-management product with a HubSpot connector is the better fit; Translation Studio has no translation memory and no translator workspace.

How it works#

Everything starts from a campaign, because that is how a marketer thinks about it: this launch, these languages.

  1. Open a campaign. The Campaigns tab lists every campaign on the portal with its target languages, progress and what needs attention.
  2. Choose the target languages. Every asset in the campaign shows Missing in each new language.
  3. Translate. Everything missing at once, one language, one asset, or one cell. Assets whose source changed since translation show Outdated and get an Update button.
  4. Review in HubSpot. Each translated cell has an Open draft link to HubSpot's own page, blog or email editor, already in the target language.
  5. Publish yourself. The app never publishes. Translations are attached to the same campaign.

The Translation Studio app page on the Campaigns tab. A table lists three campaigns with columns Campaign, Status, Target languages, Progress and Needs attention. Two campaigns have no languages yet and read "Choose languages first". The third, Spring Launch 2026, has target languages de, fr, es and nl, progress "8 / 16 translated as of 2026-11-10 11:22 UTC", and three flags: "2 outdated", "1 blocked" and "4 in template". Further tabs for Website pages, Landing pages, Blog posts and Marketing emails sit beside Campaigns, and a "Read the user guide" link sits above the table.

The Campaigns tab: one row per campaign, with its languages and what needs attention.

A campaign in Translation Studio. At the top, the target languages de, fr, es and nl, each removable, and an "Add a language" picker with the note "Removing a language only hides its column; translations already made are kept." Below, action buttons: "Translate everything missing (9)", "Missing → de (1)", "Missing → fr (2)", "Missing → es (3)", "Missing → nl (3)", "Update outdated (2)" and "Retry blocked (1)". The matrix has one row per asset and one column per language. A website page is Up to date in all four languages, each with an Open draft link. A landing page is Outdated in German and French with Update buttons, and Missing in Spanish and Dutch with Translate buttons; its row ends in "Translate missing (2)".

Choosing languages and acting on a whole language, a whole row, or a single cell.

Further rows of the same matrix. A legacy landing page, "Spring Launch — Webinar sign-up (legacy template)", reads "In template" in all four languages; under its name, once, in italics: "This page's body is coded in its template, so only its title and meta description can be translated here. Translate the template itself, or rebuild the page with drag-and-drop modules." Each cell still offers Translate, for the title and meta description. A blog post is Blocked in German, with the message "This blog has no German (de) version yet. A blog post can only be translated into a language its blog has: add a de language variation of the blog (blog settings → multi-language), then press Retry." and a Retry button; it is Missing in French and Spanish and Up to date in Dutch. A marketing email is Up to date in German, French and Spanish and Missing in Dutch. A footnote reads: "Translations are created as drafts and attached to this campaign; nothing is ever published by this app. A status comes from what Translation Studio recorded when it made a translation, so Outdated means the source changed after that moment. Re-translating replaces the draft's text, including edits made in review."

A page whose body is in its template says so instead of pretending to be translated, a blocked blog post names its own fix, and the footnote states the two rules that matter in review.

Screenshots on this page are from a HubSpot test portal running the Test engine, which prefixes each text with the language — [DE] Welcome… — instead of translating it. That is why the settings screenshots show a Test engine banner.

What each status means#

Every status is judged from what the app recorded when it made the translation — never inferred by comparing dates on two different objects.

StatusWhat it meansWhat to do
Up to dateTranslated, the draft still exists, and the source has not changed sinceReview and publish in HubSpot (Open draft). If the cell says Not yet attached to the campaign, Attach
OutdatedThe source's content changed after it was translatedUpdate — re-translates and replaces the draft's text
MissingNever translated into this language, or the translation was deletedTranslate
Exists, not trackedA language version exists that the app did not make — written by hand, or by HubSpot's own AI translationAdopt it so the app tracks it from now on, or leave it alone
FailedThe last attempt failed; the error is shown in the cellRetry — or Retry failed (n) for all of them
BlockedSomething in HubSpot has to change first; the cell names the fixMake the change, then Retry — or Retry blocked (n) for all of them
In templateA page whose body is coded in its template: only its title and meta description can be translated here. The reason is stated once, under the page's nameTranslate covers the title and meta description; the body needs the template translated, or the page rebuilt with drag-and-drop modules. Never counted as translated, and never holds the campaign's progress below 100 %
Not supported yetAn asset type this version does not translateListed under the matrix, for completeness
Source languageThis language is the asset's ownNothing

A change that touches only the source's metadata — for example, the page gaining a new language version — does not make a fresh translation read Outdated: the app compares a fingerprint of the translatable text as well as the edit time.

Your terms, every time#

The glossary is a HubDB table, Translation Studio — glossary, that your marketing team edits in HubSpot under Content → HubDB. One row per term and target language: the source term, the language code, the term to use, and an optional note.

The HubDB table "Translation Studio — glossary" in HubSpot, with columns Source term, Target language, Target term and Note. Example rows: Big Data → de → Massendaten, "Preferred term in German copy"; Customer Platform → de → Kundenplattform, "Product name — always this form"; Customer Platform → fr → plateforme client, "Lower case in running text"; Smart CRM → de and fr → Smart CRM, "Brand term — never translated"; lead time → de → Lieferzeit, "Industry term, not Vorlaufzeit"; lead time → nl → levertijd, "Industry term".

The glossary is an ordinary HubDB table. Draft rows count; there is no need to publish it.

How the terms reach each engine:

EngineHow the glossary is applied
DeepLThe whole table becomes one DeepL glossary in your DeepL account, with one dictionary per target language. It is rebuilt on the next run after any change to the table, and the old one is deleted. DeepL adjusts glossary entries for case, gender and tense in inflecting languages, rather than pasting them in
ClaudeFor each batch of text, the terms that actually occur in it are sent as mandatory terms, with their notes
Test engineTerms are applied literally, so the flow can be checked without a provider

Three rules to know:

  • Terms are written in the default source language set on the settings page. An asset in a different source language is translated without the glossary, and the run says so.
  • A regional code inherits the base language. A row for nl serves nl-nl and nl-be, unless another row names nl-be exactly.
  • Rows DeepL would refuse are skipped and counted — a duplicate source term, an entry over 1,024 bytes, or an unsupported language. The run's notes report how many.

Engines, keys and what is sent where#

The Translation tab of the Translation Studio settings page. A yellow banner reads "The Test engine is selected — Runs produce marked copies of the source ("[DE] …"), not translations. Choose DeepL or Claude once a key is saved." Below are three choices that save as soon as they change: Translation engine (set to "Test engine (no network — marks text, for proving the flow)"), Claude model (set to "Claude Sonnet 5.5 (default)") and Default source language (English). A "Test the engine" button has run and shows "Test engine works — en → de in 1 ms" with two sample sentences prefixed [DE], one of them HTML with its tags and link left intact.

Choosing the engine, the Claude model and the default source language, then checking the engine on two samples.

EngineWhat it doesWhat leaves your portal
DeepLTranslates through DeepL's API with your glossary attached. A free-plan key (ending in :fx) is sent to DeepL's free endpoint automatically. HubSpot's template markup (HubL) is marked as not-to-translateThe extracted text and the glossary, to DeepL
ClaudeTranslates through Anthropic's API, in batches of up to 2,500 characters, with the glossary terms found in each batch as mandatory terms. Choose Sonnet 5.5 (default), Opus 5.5 or Haiku 5.5The extracted text and the matching glossary entries, to Anthropic
Test enginePrefixes each text with the target language and makes no network call. The default, so the flow can be proven before any key existsNothing

Only text is sent. The app reads the text fields of each module — headings, body text, button labels, image alt text — plus the page title and meta description, a blog post's title, body and summary, and an email's subject and text. Keys, ids, URLs, colours, fonts and other style values are never sent. The app's functions run inside HubSpot, and the only outside hosts it is configured to call are DeepL's two API hosts and Anthropic's.

Cost sits with your provider account. DeepL bills on source characters, and each target language counts separately; HTML tags do not count when tag handling is on (DeepL's documentation, read 2026-11-10). Whether DeepL glossaries are available on DeepL's free API plan was not confirmed — check your DeepL contract.

The API keys tab of the settings page, under the same Test engine banner. Text reads "Keys are encrypted before they are stored and are write-only: they can be replaced or removed here, never shown again. Each key saves on its own." Two fields follow, each marked "Not set" with its own Save button: the DeepL API key ("From your DeepL account → API keys. A free-plan key ends in ":fx" and is sent to api-free.deepl.com automatically.") and the Anthropic API key ("From the Claude Console → API keys. It starts with "sk-ant-".").

Keys are write-only: once saved they can be replaced or removed, never read back.

Your keys stay on your portal. A key is checked for the right shape, encrypted (AES-256-GCM) and stored in a settings record on your portal. It is never returned to the page — not even masked. It is read only where the app calls the provider.

The Storage and glossary tab of the settings page. A table lists three HubDB tables, each with state Ready: Translation records (translation_studio_records), Campaign languages (translation_studio_campaigns) and Glossary (translation_studio_glossary). A "Set up storage" button is disabled because the tables exist, beside a "Check again" button. Below, a section headed "The glossary" explains where to edit it in HubDB, that terms are written in the default source language, that DeepL receives the whole table as one DeepL glossary rebuilt when the table changes, that Claude receives the terms occurring in the text as mandatory, that the Test engine applies them literally, and that the table is read as a draft.

Storage is set up once from the settings page; repeating it leaves existing tables untouched.

What it translates today, and what it does not#

ContentToday
Website pages and landing pages built from drag-and-drop areas and modules, including custom modulesTranslated into a native HubSpot language variation, as a draft
Blog postsTranslated into a native language variation, as a draft — provided the blog already has that language. HubSpot refuses otherwise, and the cell shows Blocked with the fix: add the language to the blog once, in its multi-language settings
Marketing emailsTranslated into a copy of the email with its language set, as a draft. HubSpot's API has no language-variation route for emails, so the copy is not linked to the original as a variation; the app keeps the link in its own records
Pages whose body lives in the template (older, template-coded pages)Not translatable per page. The body text is not in the page's content at all, so only the title and meta description can be translated. The matrix marks such a page In template and says why, under its name, instead of calling it translated
Any other campaign asset — forms, CTAs and the likeNot translated; listed under the matrix as Not supported yet

What it deliberately does not do:

  • Publish. Every translation is a draft. A person reviews and publishes in HubSpot.
  • Change your blog's settings. Adding a language to a blog is an admin decision, so the app reports Blocked with the fix rather than doing it.
  • Translate anything that is not recognisably text. A module field the app cannot identify as text is left untranslated — an untranslated field is the safe failure; a translated style value is not.

Limits of this version, stated once:

  • Update replaces the draft's text, including edits made in review. Review last, or re-apply edits after an update.
  • Runs happen in your browser tab. Keep the app page open while a run is going; closing it stops after the asset in flight, and a rerun picks up from what was recorded. With the Test engine, one asset into one language took about 4–5 seconds; DeepL and Claude timings have not been measured yet.
  • A field is recognised as text by its name and content. A custom module that names a text field unusually is skipped.
  • Blocked is only known after an attempt. A blog post whose blog lacks the language shows Missing until someone tries.
  • Storage is HubDB, with HubSpot's limit of 10,000 rows per table — one row per asset and language translated.
  • Languages: 15 — English (British by default, or American), German, French, Spanish, Italian, Dutch, Polish, Portuguese (European or Brazilian), Swedish, Danish, Finnish, Czech, Japanese and Chinese (simplified), with regional codes such as de-at, fr-be and nl-be. A code outside this list is refused with the list, never guessed.

Where your data lives#

Everything stays on your portal.

StoreHolds
HubDB translation_studio_recordsOne row per asset and language: the source version the translation was made from (edit time and text fingerprint), the engine, the outcome (ok, failed or blocked), any error, and whether it is attached to the campaign. Statuses are read from here
HubDB translation_studio_campaignsEach campaign's target languages, and the progress summary shown on the Campaigns tab
HubDB translation_studio_glossaryYour terms
Custom object app_settingThe engine, Claude model and default source language; the encrypted keys; the id of the DeepL glossary the app maintains

Records are kept per asset, not per campaign: an asset in two campaigns shares its translations. The app creates no association labels; translated drafts are attached to the campaign as campaign assets. It has no public web address — its functions answer only to a signed-in user of the portal it is installed on, from its own app page and settings page.

Requirements and getting it#

Your portal needs:

  • Content Hub Professional or Enterprise — multi-language pages and blog posts.
  • Marketing Hub Professional or higher — campaigns and marketing emails.
  • An Enterprise subscription on at least one hub — the app keeps its settings in a small custom object, and custom objects need Enterprise. It has only been run on an Enterprise portal.
  • HubDB — the records and the glossary.
  • For real translations, a DeepL API key, an Anthropic API key, or both. Neither is needed to try the flow with the Test engine.

Permissions it asks for at install, in plain words:

PermissionWhy
Custom objects and their schemas, read and writeThe settings record
ContentRead pages, landing pages and blog posts; create language variations; write drafts
Marketing email (shown at install as Marketing Single Send API access)Read, copy and update marketing emails
Campaigns, read and writeList campaigns, read their assets, attach translations
Data-integration file data sources, read and writeHubSpot requires these to read a campaign's assets; without them each asset read was refused with a 403 on the portal where this was tested
HubDB tables and rows, read and writeThe three tables

Getting it. Translation Studio is distributed as a HubSpot project you upload to your own portal with HubSpot's CLI and install there as a private app. It is shared by invitation: go to worksby.design/get/translation-studio, enter the email address that was invited, and a download link arrives within a minute. The link works for 24 hours; when it has expired, ask for a new one on the same page. Not on the list? Say which package you are after through worksby.design/contact — access is arranged per organisation. The zip (Apache 2.0) carries INSTALL.md — build, upload, install, first visit to the settings page, storage, keys and the glossary — and DOCUMENTATION.md for anyone extending it.

On first open the settings page prepares its settings record; Set up storage creates the HubDB tables; the API keys tab takes your keys; Test the engine translates two samples into German without storing anything.

What comes next#

In the order planned:

  1. Runs against DeepL and Claude, with timings per page size.
  2. Glossary import — load an existing term list from a spreadsheet file, or use a glossary you already keep in DeepL.
  3. Runs that continue on the server, so closing the page no longer stops a run and long pages are not bound by a browser session.
  4. Text found from each module's own field definitions, instead of by field name — and an Update that keeps reviewer edits, re-translating only the text whose source changed.
  5. Translation outside campaigns — tabs per content type (website pages, landing pages, blog posts, marketing emails), and a Translate action in HubSpot's own content lists if HubSpot opens its bulk actions to content.
  6. Storage beyond HubDB, and availability as a public app installed from a link rather than uploaded.

Smaller items on the list: more engines, a check that reports any glossary term an engine did not respect, a review task for the language owner when a draft is ready, an explicit "publish reviewed translations" action (never automatic), and more languages as HubSpot and the engines support them.

Try it#

The fastest evaluation is one of your own campaigns, copied, with your term list in the glossary and your own DeepL or Anthropic key — the drafts land in HubSpot's editors where your language owners already work. To set that up, or to see it running first, contact worksby.design →

HubSpot, DeepL, Anthropic and Claude are trademarks of their respective owners. worksby.design is an independent publisher, not affiliated with HubSpot, DeepL or Anthropic.