DEV Community

Cover image for Treating Multilingual BCPs Like Code: Version Control, Glossaries and CI for Incident Documentation
Diogo Heleno
Diogo Heleno

Posted on Originally published at m21global.com

Treating Multilingual BCPs Like Code: Version Control, Glossaries and CI for Incident Documentation

If your company runs infrastructure across multiple regions, you already know the drill: config drift between environments is a silent killer. Nobody notices until there's an incident and staging behaves differently from prod.

The same failure mode exists in business continuity plans (BCPs) that get translated for different country subsidiaries. A recent article from M21Global makes a good case for why BCP translation needs more rigor than standard corporate docs: ambiguous terminology, mismatched institutional references, and inconsistent clauses across language versions can make a plan useless exactly when it's needed.

That article covers the linguistic and legal angle well. What it doesn't cover is the tooling problem: how do you actually keep N language versions of a living document in sync over time, with reviewable changes and no silent drift? That's a problem developers are well equipped to solve, because it's structurally identical to managing config across environments.

Why this is a documentation infrastructure problem, not just a translation problem

A BCP isn't static. It gets updated when:

  • A subsidiary changes its local emergency contact or regulatory body
  • Decision authority changes (new VP, new escalation chain)
  • A DRP dependency changes (new hosting provider, new backup region)
  • An audit finds a gap

Every one of these updates needs to propagate to every language version, consistently, with a record of who approved what and when. If your current process is "send the Word doc to a translation agency and wait for an email back," you have no diffing, no audit trail, and no way to catch terminology drift between versions.

This is solvable with the same primitives you already use for code.

Structure: treat each BCP version as a build artifact from a single source

Don't maintain five Word documents (EN, PT, PT-AO, ES, FR) as independent files. Maintain:

  1. A single structured source document (Markdown, AsciiDoc, or XML) with the canonical English (or source-language) content, split into addressable sections.
  2. A terminology glossary as structured data, not a PDF.
  3. A translation memory (TM) that's versioned alongside the source.
  4. Generated outputs per locale, built from source + glossary + TM, the same way you'd generate environment-specific configs from a template plus variables.

A minimal directory structure:

bcp/
  source/
    en/
      01-activation-criteria.md
      02-decision-authority.md
      03-escalation-matrix.md
  glossary/
    terms.yaml
  locales/
    pt-PT/
    pt-AO/
    es-ES/
  build/
    pt-PT/
    pt-AO/
    es-ES/
Enter fullscreen mode Exit fullscreen mode

The glossary file is the part most teams skip, and it's the part that matters most. Something like:

- term: "immediate"
  context: "activation deadlines"
  pt-PT: "imediato"
  pt-AO: "imediato"
  es-ES: "inmediato"
  notes: "Never translate as 'assim que possível' / 'as soon as possible'. Changes binding obligation."

- term: "Civil Contingencies Secretariat"
  context: "UK regulatory reference"
  pt-AO: "Serviço Nacional de Protecção Civil e Bombeiros"
  notes: "Not a literal translation — functional equivalent per jurisdiction."
Enter fullscreen mode Exit fullscreen mode

This file should be reviewed and version-controlled like any other config. Every PR that touches it should require sign-off from whoever owns legal/compliance review, the same way infra changes require a second approver.

Using translation memory tools programmatically

You don't need to build this from scratch. Tools like OmegaT, Weblate, or commercial TMS platforms expose APIs or CLI interfaces that let you integrate translation memory into a pipeline instead of a manual handoff.

A rough CI flow:

# .github/workflows/bcp-build.yml
name: Build BCP translations
on:
  push:
    paths:
      - 'bcp/source/**'
      - 'bcp/glossary/**'

jobs:
  check-glossary-consistency:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Validate glossary coverage
        run: python scripts/check_glossary_coverage.py bcp/source/en bcp/glossary/terms.yaml
      - name: Flag untranslated or stale segments
        run: python scripts/tm_diff.py bcp/source/en bcp/locales/
Enter fullscreen mode Exit fullscreen mode

check_glossary_coverage.py is something you can write in an afternoon: parse the source docs, extract terms that match glossary entries, and fail the build if a term appears in source but has no approved translation for a required locale. tm_diff.py compares segment hashes against the last translated version and flags anything that changed upstream but wasn't re-translated, which is exactly the terminology drift problem the source article describes when "the same concept is rendered three different ways" because documents were translated at different times by different providers.

Catching the dangerous class of bugs: modal verb drift

The single highest-risk failure mode in a translated BCP, per the source article, is a clause like "must notify within 1 hour" getting softened into "should notify when possible." This is a linguistic bug class that's actually greppable.

A simple lint rule:

# scripts/modal_lint.py
BINDING_TERMS = {
    "en": ["must", "shall", "immediately", "within"]}
SOFTENERS = {
    "pt-PT": ["poderá", "quando possível", "recomenda-se"],
    "es-ES": ["podrá", "cuando sea posible", "se recomienda"]}

def check_segment(source_text, translated_text, locale):
    if any(term in source_text.lower() for term in BINDING_TERMS["en"]):
        if any(soft in translated_text.lower() for soft in SOFTENERS.get(locale, [])):
            raise ValueError(f"Possible obligation softening detected: {translated_text}")
Enter fullscreen mode Exit fullscreen mode

This won't replace a human legal reviewer, but it catches the obvious cases before a document ever reaches review, the same way a linter catches an obvious null-pointer risk before a human reviewer even opens the PR.

Review gates based on document risk, not uniform process

The source article recommends a two-tier approach: a stricter review workflow (second linguist, ISO 17100-style process) for documents with legal or regulatory exposure, and a lighter process for internal operational manuals. That maps directly onto a branch protection strategy:

  • High-risk documents (anything referenced in contracts, insurance, or audits): require two approvals, one from a linguist/reviewer and one from legal/compliance, before merge.
  • Internal/operational documents: single reviewer, faster merge, still versioned and glossary-checked.
# CODEOWNERS
bcp/source/en/02-decision-authority.md   @legal-team @translation-lead
bcp/source/en/03-escalation-matrix.md    @legal-team @translation-lead
bcp/locales/pt-AO/operational-manual.md  @ops-team
Enter fullscreen mode Exit fullscreen mode

The takeaway

Translation agencies solve the linguistic and legal accuracy problem. They don't solve the versioning, drift-detection, and review-gate problem, and most companies don't either, because they treat the BCP as a one-off document instead of a build artifact with dependencies.

If you're running a multi-country operation, the fix isn't just hiring a better translation provider (though the source article makes a solid case for why that matters for legal fidelity). It's putting the same engineering discipline around your BCP that you'd put around any other piece of infrastructure that multiple teams depend on in an emergency: version control, automated checks, and risk-based review gates.

Source article: Business Continuity Plan Translation for Multi-Country Operations

Top comments (0)