Receber por email
← Voltar para o catálogo

cm-safe-i18n

Use when translating, extracting, or mass-converting hardcoded strings to i18n t() calls. Enforces multi-pass batching, parallel-per-language dispatch, 8 audit gates, and HTML integrity checks. Battle-tested through 21+ batches and 12 bug categories from the March 2026 incidents.

46estrelas
Atualizado há 4 meses

Ver no GitHub ↗

Como adicionar

/plugin marketplace add tody-agent/codymaster

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/cm-safe-i18n-mpsurabn/svg)](https://www.skillteca.com.br/skills/cm-safe-i18n-mpsurabn)

Skills relacionadas

Ver todas de Desenvolvimento →

Alerta por categoria

Receba novas skills de Desenvolvimento toda segunda

1 email curto, só com as skills novas de Desenvolvimento. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Safe i18n Translation v2.0

Overview

Mass i18n conversion is the most dangerous code transformation in a frontend monolith. A single-pass conversion of 600+ strings corrupted app.js beyond repair while 572 backend tests passed green. Additional incidents include HTML tag corruption, variable shadowing, and placeholder translation errors.

Core principle: Every batch of i18n changes MUST pass ALL 8 audit gates before proceeding. No exceptions.

Violating the letter of this rule is violating the spirit of this rule.

The Iron Law

NO BATCH WITHOUT PASSING ALL 8 AUDIT GATES.
NO LANGUAGE FILE WITHOUT KEY PARITY.
NO DEPLOY WITHOUT FULL SYNTAX VALIDATION.
NO HTML TAG MODIFICATION — TEXT CONTENT ONLY.
NO REGEX TO FIX REGEX ERRORS — USE LEXICAL SCANNER.

When to Use

ALWAYS when any of these happen:

  • Extracting hardcoded strings to t() calls
  • Adding new language file (e.g., ph.json)
  • Mass-converting strings across >10 lines
  • Updating translation keys or namespaces
  • Migrating i18n library or pattern

Don't use for:

  • Adding 1-3 translation keys (just add manually + test)
  • Fixing a single typo in a JSON file

The Protocol

digraph i18n_flow {
    rankdir=TB;
    "0. Pre-flight" [shape=box];
    "1. Scan ALL files" [shape=box];
    ">10 strings?" [shape=diamond];
    "Manual add + test" [shape=box];
    "2. Plan passes" [shape=box];
    "3. Extract batch (max 30)" [shape=box];
    "4. 8-Gate Audit" [shape=box, style=filled, fillcolor="#ffffcc"];
    "All 8 pass?" [shape=diamond];
    "FIX or ROLLBACK" [shape=box, style=filled, fillcolor="#ffcccc"];
    "More batches?" [shape=diamond];
    "5. Parallel language sync" [shape=box];
    "6. Final validation" [shape=box];

    "0. Pre-flight" -> "1. Scan ALL files";
    "1. Scan ALL files" -> ">10 strings?";
    ">10 strings?" -> "Manual add + test" [label="no"];
    ">10 strings?" -> "2. Plan passes" [label="yes"];
    "2. Plan passes" -> "3. Extract batch (max 30)";
    "3. Extract batch (max 30)" -> "4. 8-Gate Audit";
    "4. 8-Gate Audit" -> "All 8 pass?";
    "All 8 pass?" -> "FIX or ROLLBACK" [label="no"];
    "FIX or ROLLBACK" -> "4. 8-Gate Audit";
    "All 8 pass?" -> "More batches?" [label="yes"];
    "More batches?" -> "3. Extract batch (max 30)" [label="yes"];
    "More batches?" -> "5. Parallel language sync" [label="no"];
    "5. Parallel language sync" -> "6. Final validation";
}

Phase 0: Pre-Flight Checks (NEW)

Before ANY i18n work:

# NEVER work on main
git checkout -b i18n/$(date +%Y%m%d)-target-description

# Verify baseline is clean
node -c public/static/app.js
npm run test:gate

If either fails, DO NOT PROCEED. Fix the baseline first.

Phase 1: Scan ALL Frontend Files (IMPROVED)

[!CAUTION]
Lesson #11: import-adapters.js and import-engine.js had 60+ hardcoded strings that were initially missed because only app.js was scanned.

Scan EVERY file that produces user-visible UI text:

# Scan ALL .js files for Vietnamese strings
node scripts/i18n-lint.js

# Also check non-app.js files
grep -rnP '[àáạảãâầấậẩẫăằắặẳẵ]' public/static/*.js --include="*.js" | grep -v "\.backup" | grep -v "i18n"

Group strings by functional domain — never by file position:

| Pass | Domain | Example Keys | |------|--------|-------------| | 1 | Core UI | sidebar., common., login. | | 2 | Primary Feature | vio., emp., scores. | | 3 | Config & Settings | config., benconf. | | 4 | Reports & Export | report., export. | | 5 | Secondary Files | import-adapters.js, import-engine.js | | 6 | Edge cases | Tooltips, error messages, dynamic labels |

Output: A numbered list of passes with estimated string count per pass per FILE.

Phase 2: Extract Batch (MAX 30 strings per batch)

[!CAUTION]
MAX 30 strings per batch. Not 31. Not "about 30". Exactly 30 or fewer.
The i18n crash happened because 600+ strings were done in one pass.

For each batch:

  1. Identify up to 30 hardcoded strings in the current pass domain
  2. Generate namespace-compliant keys: domain.descriptive_key
  3. Replace strings with t('domain.key') calls
  4. Add keys to the primary language JSON (usually vi.json)

String Replacement Rules (12 Bug Categories Encoded)

// ✅ CORRECT — backtick template with t() inside
`<div>${t('login.welcome')}</div>`

// ✅ CORRECT — concatenation
'<div>' + t('login.welcome') + '</div>'

// ❌ BUG #1 (FATAL) — single-quote wrapping template expression
'${t("login.welcome")}'     // ← THIS DESTROYED APP.JS

// ❌ BUG #4 — mismatched delimiters
t('login.welcome`)           // ← quote/backtick mismatch
t(`login.welcome')           // ← backtick/quote mismatch

Ternary Inside Template Literals (Bug #5)

// ❌ BROKEN — single-quote ternary result with template expression
${ canDo ? '...${t('key')}...' : '' }

// ✅ CORRECT — backtick ternary result
${ canDo ? `...${t('key')}...` : '' }

Variable Shadowing (Bug #3)

// ❌ BROKEN — shadows global t() translation function
items.map((t, i) => `<div>${t('key')}</div>`)

// ✅ CORRECT — use different variable name
items.map((item, i) => `<div>${t('key')}</div>`)

HTML Tag Protection (Bug #2)

// ❌ NEVER modify content inside HTML tags
`< div class="card" >`    // spaces inside tags = broken rendering
`style = "color: red"`     // space around = breaks attributes
`<!-- text-- >`            // broken comment closers

// ✅ ONLY replace text content between tags
`<div class="card">${t('card.title')}</div>`

Static Keys Only (Bug #8)

// ❌ FORBIDDEN — dynamic keys can't be statically validated
t('nav.' + pageName)
t(`messages.${type}`)

// ✅ REQUIRED — static keys only
t('nav.dashboard')
t('nav.employees')

Phase 3: 8-Gate Audit (MANDATORY after every batch)

[!IMPORTANT]
All 8 gates must pass. Any failure = STOP and FIX before continuing.
# Gate 1: JavaScript syntax (fast, <1s)
node -c public/static/app.js
# Must output: "public/static/app.js: No syntax errors"

# Gate 2: Syntax check on ALL modified .js files
node -c public/static/import-adapters.js 2>/dev/null
node -c public/static/import-engine.js 2>/dev/null

# Gate 3: Corruption pattern check (catches what node -c misses)
grep -nP "=\s*'[^']*\$\{t\(" public/static/app.js
# Must return 0 matches

# Gate 4: Mismatched delimiter check
grep -nP "t\('[^']*\`\)" public/static/app.js
grep -nP "t\(\`[^']*'\)" public/static/app.js
# Must return 0 matches each

# Gate 5: HTML tag integrity (NEW — Bug #2)
grep -nP "<\s+\w" public/static/app.js | head -5
grep -nP "</\s+\w" public/static/app.js | head -5
grep -nP "--\s+>" public/static/app.js | head -5
grep -nP '\w+\s+=\s+"' public/static/app.js | grep -v "==\|!=\|<=\|>=" | head -5
# Must return 0 matches (excluding legitimate JS operators)

# Gate 6: Variable shadowing check
grep -nP "\.\s*(map|filter|forEach|reduce)\s*\(\s*\(\s*t\s*[,)]" public/static/app.js
# Must return 0 matches

# Gate 7: JSON validity
node -e "JSON.parse(require('fs').readFileSync('public/static/i18n/vi.json'))"

# Gate 8: Full test suite
npm run test:gate
# Must output: 0 failures

Audit Summary Table:

| Gate | Check | Command | Pass Criteria | Bug # Prevented | |------|-------|---------|---------------|-----------------| | 1 | JS syntax (main) | node -c app.js | No syntax errors | #1, #4 | | 2 | JS syntax (all files) | node -c *.js | No syntax errors | #11 | | 3 | Corruption pattern | grep = '..${t( | 0 matches | #1 | | 4 | Delimiter mismatch | grep mixed delims | 0 matches | #4 | | 5 | HTML tag integrity | grep < div, </ div | 0 matches | #2 | | 6 | Variable shadowing | grep .map((t, | 0 matches | #3 | | 7 | JSON valid | JSON.parse() | No parse errors | #6 | | 8 | Full test suite | npm run test:gate | 0 failures | #9 |

If ALL 8 gates pass → commit:

git add -A && git commit -
Compartilhar X LinkedIn