i18n Change Workflow

🧩 AGENTS · Agent Skills advanced ⭐ 92

Agent skill that verifies locale completeness, hardcoded text, pluralization, fallbacks, and localization regressions.

Fill in the fields:

The values will be inserted into the prompt below.

---
name: i18n-change-workflow
description: Reusable i18n workflow for coding agents. Verifies locale completeness, hardcoded text, placeholders, pluralization, fallback behavior, formatting, translation consistency, and localization-related UI regressions.
---

# i18n Change Workflow

Act as the i18n/l10n specialist layer for the active task.

This skill adds localization-specific constraints and verification. It does not replace the repository's normal implementation, audit, Git, or approval workflow. Follow the active workflow's mutation boundary: during implementation or remediation, apply the required i18n changes; during a read-only audit or review, use these criteria without modifying repository state.

## 1. Inspect the existing i18n system first

Before changing localized behavior:

- read applicable `AGENTS.md` and project documentation;
- identify the current i18n library or project-native mechanism;
- identify supported locales, source/default locale, locale resource locations, fallback behavior, and locale-selection/persistence logic;
- inspect nearby existing keys and call sites before choosing new key names or structures;
- identify project-specific rules for translations, formatting, generated resources, or validation.

Prefer the existing project architecture. Do not introduce a new i18n library, resource format, or parallel translation mechanism unless the task requires it and the repository has no suitable existing mechanism.

Do not treat one framework convention as universal. Follow the repository's actual conventions.

## 2. Classify text before localizing it

Determine whether each changed string is actually user-facing.

Typical localization candidates include:

- visible UI labels, buttons, headings, menus, dialogs, empty states, validation messages, and user-visible errors;
- accessibility labels and descriptions;
- notifications and user-facing system messages;
- placeholders, helper text, onboarding copy, and tooltips;
- user-visible content generated from application-owned templates.

Do not automatically localize:

- identifiers, translation keys, API names, URLs, paths, commands, SQL, regexes, or protocol values;
- developer-only logs, diagnostics, stack traces, and test fixture text;
- brand names, product names, codes, or terms that project rules intentionally preserve;
- externally supplied runtime content unless the task explicitly covers it.

When classification is ambiguous and affects product meaning, preserve the current behavior and surface the ambiguity rather than guessing.

## 3. Preserve the project's key and resource model

For new or changed user-facing text:

- use the project's translation mechanism instead of introducing hardcoded display text when localization is expected;
- follow the existing key naming and namespacing convention;
- prefer stable semantic keys over keys derived from full display sentences unless the project intentionally uses source-text keys;
- update every supported locale required by project rules or the current task;
- preserve unrelated locale entries and target-only data unless deletion is explicitly intended;
- do not silently rename or delete existing keys merely for stylistic consistency.

Treat the project's declared source/default locale as canonical only if the repository actually uses that model.

Missing translations must follow the project's established fallback policy. Do not invent a new fallback policy silently.

## 4. Preserve interpolation, pluralization, and message structure

Translation structure is part of the contract.

- Preserve the same required placeholders/arguments across locale variants.
- Do not translate placeholder names, format tokens, markup, or control syntax.
- Use the project's plural/select/ICU mechanism when grammar depends on count, gender, case, or other locale-sensitive variation.
- Avoid assembling sentences from separately translated fragments when word order or grammar can vary by language.
- Avoid string concatenation that assumes English word order or spacing.
- Preserve intentional markup, escaping, and line-break semantics.

If a source message changes its arguments or message structure, verify every affected locale rather than updating only the visible source text.

## 5. Keep locale-sensitive values locale-aware

When the changed UI contains locale-sensitive values, use the project's existing locale-aware formatting facilities for relevant:

- dates and times;
- numbers and percentages;
- currencies;
- units;
- relative time;
- list formatting;
- plural categories.

Do not hardcode separators, decimal conventions, date ordering, currency placement, or English-only plural assumptions when locale-aware behavior is expected.

## 6. Protect locale selection and fallback behavior

When the task touches locale switching, initialization, persistence, or fallback:

- preserve the project's supported-locale list and normalization rules;
- verify default-locale behavior;
- verify persistence if the project stores the user's language choice;
- verify unsupported or missing locales degrade through the intended fallback path;
- avoid mixed-language UI caused by missing keys or stale cached locale data;
- ensure lazy-loaded locale resources are awaited or synchronized correctly when applicable.

Do not change locale-detection precedence without an explicit requirement.

## 7. Translation quality

When generating or editing translations:

- preserve meaning, intent, tone, and product terminology rather than translating mechanically word-for-word;
- use surrounding UI context to resolve ambiguous short labels;
- preserve approved product names, technical terms, and glossary decisions;
- keep placeholders and markup intact;
- avoid adding claims, meaning, politeness level, or functionality not present in the source;
- flag uncertain, culturally sensitive, legal, safety-critical, or brand-sensitive wording for human confirmation instead of pretending certainty.

If the repository contains a glossary, terminology file, translation memory, or established translations, prefer that evidence over a newly generated alternative.

Read `references/i18n-review-checklist.md` when doing a broad locale addition, translation review, or release-oriented localization change.

## 8. Check UI and layout risk

Localized text can change layout even when the translation is correct.

For affected UI, consider when relevant:

- longer labels and multi-line wrapping;
- narrow mobile widths and responsive layouts;
- CJK line breaking and glyph coverage;
- text truncation and ellipsis;
- buttons, tabs, badges, dialogs, tables, and fixed-width containers;
- font fallback;
- accessibility labels;
- right-to-left direction, mirroring, and logical CSS/layout properties when an RTL locale is in scope.

Do not add RTL-specific work when no RTL locale is supported or requested, but do not ignore it when an RTL locale is part of the task.

Use visual or UI verification when the changed text can plausibly affect layout. A successful locale-file check alone does not prove the UI is correct.

## 9. Verify with project-native checks

Use the repository's existing i18n validators, tests, linters, builds, and UI checks first.

Verify the relevant subset of:

- locale-key completeness/parity;
- missing or blank translations;
- placeholder/argument parity;
- plural/select structure;
- fallback behavior;
- locale switching and persistence;
- locale-aware formatting;
- absence of newly introduced hardcoded user-facing strings in the changed scope;
- build/type/lint/test health;
- layout behavior for affected screens.

For plain JSON locale catalogs, `scripts/check_json_locales.py` may be used as an additional deterministic check. It checks duplicate JSON keys, key parity, value types, blank strings, and common brace-style named placeholder/ICU argument parity. Placeholder detection is intentionally narrow and heuristic; confirm reported mismatches against the project's actual message syntax. It is not a semantic translation review and does not replace project-native tooling.

Do not claim repository-wide i18n completeness from a narrow file or static check.

## 10. Completion criteria

An i18n change is complete only when, for the requested scope:

- the intended user-facing strings use the project's localization mechanism;
- required locale resources are updated;
- placeholders and message structure remain compatible;
- relevant formatting/fallback/switching behavior is preserved;
- project-native verification passes, or limitations are explicitly reported;
- plausible layout regressions have been checked when the UI is affected;
- unresolved translation or product-language ambiguity is reported rather than guessed.

Keep the final report concise. State what locale behavior changed, which locales/resources were touched, what validation actually ran, and any remaining translation or UI limitations.
FILE:references/i18n-review-checklist.md
# i18n Review Checklist

Use this reference for broad locale additions, translation review, or release-oriented localization work. Apply only items relevant to the project and requested scope.

## Coverage

- Inventory the user-visible surfaces in scope.
- Confirm every intended translation candidate is represented by the project i18n mechanism.
- Distinguish deliberate source-language preservation from accidental untranslated text.
- Report dynamic/external/non-text surfaces that cannot be verified from repository resources.

## Resource integrity

- Required keys exist in the locales covered by the task.
- No unrelated locale entries were deleted or rewritten.
- Value types match where the resource format requires them to match.
- Empty translations are intentional or reported.
- Generated locale resources are regenerated only through the project-approved command.

## Message contracts

- Named placeholders and ICU/select arguments are preserved.
- Markup, escapes, formatting tokens, and intentional line breaks remain valid.
- Plural/select branches follow the project's library and locale rules.
- Sentences are not built from fragments that assume source-language word order.

## Language quality

- Meaning and user intent match the source.
- Terminology is consistent with existing product language and glossary decisions.
- Short labels are interpreted using screen/action context, not in isolation.
- Tone, formality, capitalization, and punctuation fit the target locale and existing product voice.
- Brand/product names and deliberately preserved terms remain unchanged.
- High-risk ambiguity is surfaced for human confirmation.

## Locale behavior

When applicable, verify:

- default locale;
- explicit locale switching;
- persistence across reload/restart;
- unsupported-locale fallback;
- missing-key fallback;
- lazy-loaded resource behavior;
- date/time/number/currency/unit formatting;
- locale normalization such as `en-US` vs `en` according to project rules.

## UI and accessibility

When affected, check:

- narrow-screen overflow;
- wrapping, truncation, and fixed-height containers;
- buttons/tabs/badges with longer translations;
- CJK line-breaking and font glyphs;
- screen-reader/accessibility labels;
- RTL direction and mirroring only when RTL locales are in scope.

## Evidence and limitations

A passing resource check proves only what it actually checked. It does not by itself prove:

- translation quality;
- runtime locale switching;
- visual correctness;
- complete coverage of inline/dynamic/non-text content;
- correct external/CMS content.

State those limitations explicitly when they matter.
FILE:scripts/check_json_locales.py
#!/usr/bin/env python3
"""Deterministic structural checks for JSON locale catalogs.

Checks:
- duplicate object keys while parsing
- missing/extra leaf paths relative to a source locale
- source/target leaf type mismatches
- blank target strings
- common named placeholder / ICU argument parity

This intentionally does not judge translation quality and is not a general
hardcoded-string scanner.
"""

from __future__ import annotations

import argparse
import json
import re
import sys
from pathlib import Path
from typing import Any, TypeAlias

ARG_RE = re.compile(r"\{\s*([A-Za-z_][A-Za-z0-9_.-]*)\s*(?:[,}])")
PathPart: TypeAlias = str | int
JSONPath: TypeAlias = tuple[PathPart, ...]

class JSONObjectPairs(list):
 """Marker type preserving JSON object pairs so duplicates remain detectable."""

def _object_pairs_hook(pairs: list[tuple[str, Any]]) -> JSONObjectPairs:
 return JSONObjectPairs(pairs)

def path_label(path: JSONPath) -> str:
 """Render an unambiguous JSON-style path without conflating dots in keys."""
 if not path:
 return "$"
 pieces: list${str} = []
 for part in path:
 if isinstance(part, int):
 pieces.append(f"[{part}]")
 else:
 pieces.append(f"[{json.dumps(part, ensure_ascii=False)}]")
 return "$" + "".join(pieces)

def _normalize_json(value: Any, path: JSONPath = ()) -> Any:
 if isinstance(value, JSONObjectPairs):
 out: dict[str, Any] = {}
 seen: set${str} = set()
 for key, child in value:
 if key in seen:
 raise ValueError(f"duplicate key at {path_label(path + (key,))}")
 seen.add(key)
 out[key] = _normalize_json(child, path + (key,))
 return out
 if isinstance(value, list):
 return [
 _normalize_json(child, path + (index,))
 for index, child in enumerate(value)
 ]
 return value

def load_json(path: Path) -> Any:
 try:
 with path.open("r", encoding="utf-8") as f:
 raw = json.load(f, object_pairs_hook=_object_pairs_hook)
 return _normalize_json(raw)
 except (OSError, json.JSONDecodeError, ValueError) as exc:
 raise ValueError(f"{path}: {exc}") from exc

def flatten(value: Any, path: tuple[str, ...] = ()) -> dict[tuple[str, ...], Any]:
 """Flatten JSON objects using tuple paths so literal dots in keys stay distinct."""
 out: dict[tuple[str, ...], Any] = {}
 if isinstance(value, dict):
 for key, child in value.items():
 out.update(flatten(child, path + (key,)))
 else:
 out${path} = value
 return out

def value_kind(value: Any) -> str:
 if isinstance(value, bool):
 return "boolean"
 if value is None:
 return "null"
 if isinstance(value, str):
 return "string"
 if isinstance(value, (int, float)):
 return "number"
 if isinstance(value, list):
 return "array"
 return type(value).__name__

def arguments(value: Any) -> set${str}:
 if not isinstance(value, str):
 return set()
 return set(ARG_RE.findall(value))

def check_pair(source_path: Path, target_path: Path, allow_extra: bool) -> int:
 source = flatten(load_json(source_path))
 target = flatten(load_json(target_path))

 findings: list[tuple[str, str]] = []

 source_keys = set(source)
 target_keys = set(target)

 for key in sorted(source_keys - target_keys):
 findings.append(("ERROR", f"missing key: {path_label(key)}"))

 if not allow_extra:
 for key in sorted(target_keys - source_keys):
 findings.append(("WARN", f"extra key: {path_label(key)}"))

 for key in sorted(source_keys & target_keys):
 src = source[key]
 dst = target[key]
 label = path_label(key)
 src_kind = value_kind(src)
 dst_kind = value_kind(dst)

 if src_kind != dst_kind:
 findings.append(
 ("ERROR", f"type mismatch at {label}: source={src_kind}, target={dst_kind}")
 )
 continue

 if isinstance(dst, str) and dst.strip() == "":
 findings.append(("WARN", f"blank target string: {label}"))

 src_args = arguments(src)
 dst_args = arguments(dst)
 if src_args != dst_args:
 missing = sorted(src_args - dst_args)
 extra = sorted(dst_args - src_args)
 details: list${str} = []
 if missing:
 details.append(f"missing={missing}")
 if extra:
 details.append(f"extra={extra}")
 findings.append(("ERROR", f"argument mismatch at {label}: {', '.join(details)}"))

 print(f"SOURCE: {source_path}")
 print(f"TARGET: {target_path}")
 if not findings:
 print("PASS: no structural findings")
 return 0

 for severity, message in findings:
 print(f"{severity}: {message}")

 errors = sum(1 for severity, _ in findings if severity == "ERROR")
 warnings = sum(1 for severity, _ in findings if severity == "WARN")
 print(f"SUMMARY: {errors} error(s), {warnings} warning(s)")
 return 1 if errors else 0

def main() -> int:
 parser = argparse.ArgumentParser(
 description="Check JSON locale catalogs for structural parity."
 )
 parser.add_argument("source", type=Path, help="source/default locale JSON")
 parser.add_argument("targets", nargs="+", type=Path, help="target locale JSON file(s)")
 parser.add_argument(
 "--allow-extra",
 action="store_true",
 help="do not warn about target-only keys",
 )
 args = parser.parse_args()

 try:
 statuses = [check_pair(args.source, target, args.allow_extra) for target in args.targets]
 except ValueError as exc:
 print(f"ERROR: {exc}", file=sys.stderr)
 return 2

 return 1 if any(status != 0 for status in statuses) else 0

if __name__ == "__main__":
 raise SystemExit(main())
FILE:README.md
# i18n-change-workflow

Repository-local Agent Skill for safe i18n/l10n changes.

Suggested location:

`.agents/skills/i18n-change-workflow/`

The optional JSON checker is intentionally narrow and deterministic. It detects duplicate JSON keys and structural mismatches, plus heuristic common brace-style placeholder mismatches; it does not translate text or claim semantic/visual completeness.
#i18n#localization#workflow#verification#skill

Кураторская подборка fizoni.com · структура, примеры использования и рабочие сценарии

Similar prompts

💡 Liked this prompt?

📦 AI Agent Skills Pack — 217 промптов

Вместо одного промпта — целый набор по теме. Готовые процессы, структура, быстрый старт. Системные промпты, скиллы агентов, воркфлоу и автоматизация.…

Забрать набор — $4.99 🎁 6 free prompts

Всего $4.99 · мгновенный доступ · оплата картой

🎁 Get the 6 best prompts for free

Liked this prompt? We've put together 6 more hand-picked ones — for business, code, and productivity. Plus access to the full library of 2000+ prompts.