Skip to main content

Language gates belong in CI, not in code review folklore

· 6 min read
Sai Prudhvi Neelakantam
Senior Consultant, Data Engineering & AI at Evidi

Locale bugs and copy regressions show up in demos, not in polite Slack reminders. White-label shells make it worse: a forbidden customer string in core, a hard-coded English-only prompt overlay, a missing translation key that only fails in one market.

Put language gates in CI. Native linters in the pipeline beat optional pre-commit hooks for shared agent repos. Gates should cover prompt overlays and UI strings. Fail fast on forbidden customer hardcoding in core packages. Keep the gate list short enough that people do not bypass it. Locale and copy regressions are product bugs, not translation tickets filed after the fact.

Azure Pipelines overview

Figure 1. Locale and copy regressions are product bugs. Put the gates in CI where unwilling enforcement actually runs. Source: Microsoft Learn: what is Azure Pipelines.

Azure Pipelines task control options

Figure 2. Native linters and short language tests beat optional hooks that disappear under release pressure. Source: Microsoft Learn: pipeline tasks.

I learned this after watching the same class of defect escape: a tenant name in a shared package, a string key missing for one locale, a prompt overlay that assumed a single language. Reviewers were tired of being human greps. CI greps do not get tired.

The core idea

If a class of string defect is recurring, it is a build gate, not a culture speech.

Pre-commit helps willing developers. Shared repos need unwilling enforcement at merge time. Native linters and small language tests catch forbidden tokens, missing keys, and overlay mistakes before release trains move. Folklore in code review does not scale across time zones.

A model that stays explainable

1. Promote recurring review comments into linters

When reviewers keep asking for the same string hygiene, write a rule. Rules should name the forbidden pattern and the fix. A wiki admonition without a failing check is decoration.

2. Prefer CI-native over optional hooks

Optional pre-commit is skipped under pressure. CI on every PR is the contract. Local hooks can mirror CI for speed, but CI is source of truth. "Works on my laptop" is not a language strategy.

3. Cover UI strings and prompt overlays

Agent products ship language in two places: the shell and the prompts. Gates that only scan React miss the overlay that greets users in the wrong tongue. Include pack files in the same policy.

4. Fail on forbidden customer hardcoding in core

Tenant codes, logo paths, and customer display names in core packages are white-label defects. Maintain a deny list and fail the build. Exceptions need an explicit allow file with owners, not comments that say temporary forever.

5. Keep the gate list short

Five sharp gates beat twenty noisy ones. Noise trains bypass. Each gate should map to a defect you have actually shipped. Retire gates that no longer earn their keep.

6. Treat locale failures as product bugs

Missing keys and broken plurals are release blockers when that locale is in scope. Do not file them as "translation follow-ups" if the feature already claims support. Honesty in scope beats optimistic checkboxes.

Failure modes I design against

Reviewer as linter. Humans miss strings on Fridays.

Hooks only. Pressure skips local tools.

UI-only i18n checks. Prompts drift freely.

Deny list without owners. Exceptions accumulate in silence.

Gate sprawl. Engineers force-merge to survive.

Locale as backlog forever. Markets are "supported" in slides only.

What a minimal gate set looks like

Start with: forbidden tenant tokens in core; required i18n keys for touched features; prompt overlay language metadata present; no raw user-facing English literals in flagged packages when i18n is required. Add screenshot or snapshot tests only where they catch real bugs. Resist Unicode academic perfectionism on day one. Ship the gates that match your last three incidents.

Making failures actionable

A failing language gate should print the file, the rule, and a one-line fix hint. "See docs" without a path is how people disable checks. Link to the overlay slot guide or the i18n README from the error output. On-call and PR authors share the same message. If fixing requires tribal knowledge, the gate is unfinished.

White-label and i18n are the same discipline

Both ask whether core stayed generic. A customer string in core is a branding leak. A hard-coded locale assumption is a market leak. One CI policy can serve both if you organize rules by package boundary: core versus overlay versus sample pack. Samples may contain demo language; core may not. Say that in the rule names.

Trade-offs

Gates slow the first PRs that trip them and speed every PR after. Short gate lists require product judgment; long lists require bypass culture. Scanning prompts adds paths to maintain; not scanning prompts adds demo risk. Deny lists need curation; without them white-label cores rot. Treating locale as product quality may delay a launch date you should not have claimed.

What I would put on an ADR

  1. Language and white-label string hygiene are enforced in CI, not only in review folklore.
  2. CI-native linters are mandatory; local hooks are optional mirrors.
  3. Gates cover UI strings and prompt overlays in scope packages.
  4. Forbidden customer hardcoding in core fails the build with an owned exception process.
  5. The active gate list stays short, documented, and mapped to real defects.
  6. In-scope locale failures are release blockers, not translation tickets alone.

Primary references: your pipeline docs (GitHub Actions or Azure DevOps) and i18n tooling docs for the stack you run. Pair gate names with the white-label overlay ADR so failures point at architecture, not only at strings.

Closing

Demos are a terrible locale test harness.

Lint in CI. Cover prompts and UI. Ban tenant fossils in core. Keep gates few and sharp. Call locale breaks what they are: product bugs. Folklore does not merge-block. Builds do.