---
title: "The 22 language codes behind one site setting and a widget that rewrites everything"
canonical: https://dxdev.com/blog/translate-widget-scope-boundary/
datePublished: 2026-09-05
---
We shipped an optional language switch for customer sites with a fixed list of 22 language codes. It is Google's Translate widget behind one site setting, and the hard part was deciding where the widget was allowed to run.

## What the widget does to a page

The feature was small on paper. A site owner turns on a "Visitor language selector" and picks which languages to offer. A visitor gets a small dropdown that swaps the page into their language on the fly. The widget rewrites the rendered text in place, so it translates whatever it can see, including the account names and event descriptions the owner typed themselves.

That is the point of the feature, and it is also the risk. The widget has no idea which text is public content and which control belongs to the owner. So the boundary had to be ours.

## Where the boundary went

Three decisions did most of the work:

- The setting is off by default and lives under Advanced Settings, International. Nothing changes on a site until its owner flips it.
- The selector renders on visitor pages only. Admin pages run under a different zone in the code, and the check returns early for anything that is not the visitor zone, so the owner's own dashboard never loads the widget.
- The language list is a fixed set. The save handler filters against it on write, and the page filters against it again at render time, because the list ends up inside an inline script and a stored value is not something to trust there.

Saving any of those settings also clears the page cache in the same request, so a toggle takes effect on the next visitor view instead of racing a cached page.

## The layout guess that did not survive the demo

The first version pinned the dropdown to the top right with absolute positioning. In the demo it came out as a full-width bar under the nav. The container around it had no positioned ancestor, so the browser measured against the whole page.

The obvious fix was to make that container relative. That would have touched a template used on every visitor page, ads included, for the sake of one dropdown. So the selector stayed a normal-flow row under the nav, right-aligned and small. It is the lowest-risk spot in the template for a control that has to be on every page.

## What happened before it shipped

The design went through Manus and Codex as two independent reviewers. A separate verification pass then checked the finished behavior against the design instead of against the code. After that we ran the widget end to end on a look-alike copy of a real site, not a real customer's.

The hotfix landed on a review branch with dev notes and a summary on the ticket. It stopped there for a human to sign off before anything reached production.

A translation widget rewrites every piece of text it can see, so where it runs is a decision we have to make before the widget gets a say. Here that meant off by default, visitor pages only, and a language list checked on save and again on render.
