DEV Community

Cover image for Building a Multilingual Labelling Pipeline That Won't Get Your Product Stuck at Customs
Diogo Heleno
Diogo Heleno

Posted on Originally published at m21global.com

Building a Multilingual Labelling Pipeline That Won't Get Your Product Stuck at Customs

Most i18n content on Dev.to is about UI strings, ICU message formats, and locale-aware date pickers. Nobody talks about the other kind of localization problem: regulatory labelling for physical products. If your company ships hardware, chemicals, or industrial equipment across borders, you eventually run into a translation problem that your normal i18n stack cannot solve.

The source article on industrial packaging and labelling translation covers the compliance side well: CLP/GHS in the EU, UKCA in the UK, ABNT/ANVISA in Brazil, and so on. What it doesn't cover is how to actually build a content pipeline around this. That's the gap I want to fill here, from an engineering perspective.

Why this isn't a normal l10n problem

Standard software localization workflows assume:

  • Source strings live in a repo (JSON, YAML, .po files)
  • Translation happens via a TMS (Lokalise, Crowdin, Phrase) with API-based sync
  • A string can be A/B tested, iterated, and shipped again next sprint

Regulatory labelling breaks all three assumptions:

  • Source content often lives in design files (InDesign, Illustrator, PDF), not structured text
  • "Translation memory" needs to match approved regulatory terminology exactly, not just be fluent
  • Once labelling ships on physical packaging, you can't hotfix it. A bad string means a reprint, a recall, or a customs rejection.

So before reaching for your usual TMS integration, you need a different mental model: treat regulatory labelling like versioned, audited configuration, not like marketing copy.

Structuring the source content

If your labelling content still lives only inside a designer's InDesign file, you have no single source of truth and no way to diff changes. The first engineering win is extracting structured data out of the design layer.

# label_content.en.yaml
product_id: "PMP-2200"
hazard_statements:
  - code: "H314"
    text: "Causes severe skin burns and eye damage."
precautionary_statements:
  - code: "P280"
    text: "Wear protective gloves/eye protection."
transport_classification:
  adr_class: "8"
  un_number: "1760"
manufacturer:
  name: "Acme Industrial"
  address: "..."
Enter fullscreen mode Exit fullscreen mode

Once hazard statements, precautionary codes, and classification data are structured, two things become possible:

  1. You can validate against known GHS/CLP code lists programmatically before anything gets sent for translation.
  2. You can diff label_content.en.yaml against label_content.pt-BR.yaml and immediately see which fields are missing or stale.
import yaml

def missing_translations(source_path, target_path):
    source = yaml.safe_load(open(source_path))
    target = yaml.safe_load(open(target_path))
    missing = []
    for stmt in source.get("hazard_statements", []):
        codes = [s["code"] for s in target.get("hazard_statements", [])]
        if stmt["code"] not in codes:
            missing.append(stmt["code"])
    return missing
Enter fullscreen mode Exit fullscreen mode

This is a trivial script, but it catches the exact failure mode described in the source article: shipping PT-PT content to a PT-BR market, or missing a hazard code entirely, because nobody diffed the files before sending them to print.

Terminology enforcement, not just translation memory

A translation memory (TM) suggests reusing previously translated segments. That's useful but insufficient here. What you actually need is terminology enforcement: a fixed glossary of approved terms for hazard classes, transport codes, and regulatory markings that cannot be substituted with a "close enough" synonym.

Most TMS platforms support this via termbases. If you're rolling your own pipeline, a simple guard is a lint step:

APPROVED_TERMS = {
    "es-ES": {"guantes de protección": True, "guantes protectores": False},
    "es-MX": {"guantes de protección": True, "guantes protectores": True},
}

def lint_terminology(text, locale):
    violations = []
    for term, allowed in APPROVED_TERMS.get(locale, {}).items():
        if not allowed and term in text.lower():
            violations.append(term)
    return violations
Enter fullscreen mode Exit fullscreen mode

Run this as a CI check on every translated file before it goes to a human reviewer. It won't replace a specialist translator (as the source article correctly points out, machine translation fails on regulatory nomenclature), but it catches obvious regressions automatically and cheaply.

Locale variants are not optional fields

A recurring theme in the source article is that es and pt are not real locales for this use case. You need es-ES vs es-MX, pt-PT vs pt-BR, and so on, each with distinct approved terminology.

If your codebase or CMS currently models translations with a flat two-letter language key, that's a bug waiting to cause a compliance incident. Fix the schema first:

{
  "locale": "pt-BR",
  "region_regulatory_body": "ANVISA",
  "content": { "...": "..." }
}
Enter fullscreen mode Exit fullscreen mode

Tie region_regulatory_body to the locale explicitly. It becomes a useful field for routing content to the correct reviewer and for audit trails later.

Building an audit trail

Regulatory documentation may need to survive an audit years after it shipped. That means your pipeline needs:

  • Immutable snapshots of what was actually sent to print, per market, per version
  • A record of who reviewed it and against which glossary/version of the regulation
  • Timestamped diffs when source content changes (a new hazard classification, an updated SDS)

This is a good fit for storing labelling content in a git repo, tagging releases per market (v2.1-de-DE, v2.1-pt-BR), and requiring PR review from a linguist with sector knowledge before merge. Git gives you the audit trail for free; you just have to use it for this instead of only application code.

Where automation should stop

It's tempting to throw an LLM at this and call it solved. Don't. The source article makes a fair point: current MT systems are reasonable for general text and unreliable for regulatory phrasing that must match legally precise wording. Use automation for:

  • Structural validation (missing fields, code mismatches, locale coverage gaps)
  • Terminology linting
  • Diffing and change detection across versions

And keep a human specialist in the loop for anything that ends up on the actual label, especially hazard statements, safety warnings, and regulatory markings. The cost of automating that step incorrectly is not a bad UX string, it's a customs rejection or a product recall.

Takeaway

If your team ships physical products internationally, your labelling content deserves the same engineering rigor as your codebase: structured data, versioning, CI checks, and audit trails. The compliance requirements themselves (which language, which variant, which regulatory body) are covered well in the original article on industrial labelling translation. What's missing from most teams' setup is the pipeline to enforce those requirements automatically, before a translation error becomes a shipping problem.

Top comments (1)

Collapse
 
indiainfranotes profile image
IndiaInfraNotes •

hold up. green uptime tiles are not a usage receipt.

1 cut: when the cloud invoice fight opens, can a buyer GET a signed meter tip of what ran, or only another vendor seal?

receipts > seals. #marker1128-obs