microsoft/store-listing-localizer
Automate Microsoft Store (Partner Center) listing localization for Intelligent Terminal (Store ID 9NMQC2SSJX24). Use when asked to export/import Store listings, localize release notes / descriptions / captions / features into 80+ languages, update listingData CSV, or push Store listing translations without manually clicking through Partner Center. Drives Partner Center export/import via the Playwright MCP and merges per-locale translations into the listingData CSV.
npx skills add https://github.com/microsoft/intelligent-terminal --skill store-listing-localizer
End-to-end automation for localizing the Intelligent Terminal Microsoft Store
listing: export the listingData CSV from Partner Center, localize the
changed fields (release notes, description, captions, features) into all 80+
Store locales using the repo's terminology rules, then import the result —
without manually logging into and clicking through the Partner Center web UI.
9NMQC2SSJX24 ·Overview: https://partner.microsoft.com/en-us/dashboard/products/9NMQC2SSJX24/overview
listing-csv-format.md.
prompt** (handled via en-US overrides — see below).
playwright in ~/.copilot/mcp-config.json(@playwright/mcp, --browser msedge, dedicated --user-data-dir,
--output-dir <repo>\Generated Files\playwright-mcp). Write browser outputs
to a per-run subfolder store-listing-localizer/<YYYY-MM-DD>/… (pass that as
the filename subpath). Restart Copilot CLI after enabling it, then sign
into Partner Center once in the launched Edge window. Full setup + gotchas:
partner-center-mcp-workflow.md.
scripts/ has no npm dependencies).references/intelligent-terminal-translations.md,
and apply.mjs defaults to it. Override with --appnames <path> only if you
maintain a newer copy elsewhere.
Track progress with a TODO list; each step links to its reference.
partner-center-mcp-workflow.md#export.
Copy the downloaded listingData-9NMQC2SSJX24-*.csv into a clean working dir.
source and which locales are stale:
node scripts/extract.mjs --csv <export.csv> [--enus <overrides.json>] --out work-order.json
localization-rules.md (locked tokens,
.resw terminology alignment, RTL handling). Use per-language sub-agents for
breadth + a reviewer pass. Emit translations.json keyed
{ "<locale>": { "<Field>": "<text>" } }.
--appnames defaults to the bundledreferences/intelligent-terminal-translations.md):
node scripts/apply.mjs --csv <export.csv> [--appnames <translations.md>] \
--translations translations.json [--enus overrides.json] \
[--changed-fields ReleaseNotes] --out <stem>-localized.csv
import <stem>-localized.csv —
partner-center-mcp-workflow.md#import.
stages the listing).
When the new en-US text is given in the prompt, write it to an overrides file
and pass it to both scripts:
// enus.json
{ "ReleaseNotes": "Version v0.1.1600\n\n- New: ...\n- Fixed: ..." }
--enus updates the en-US column *and* marks the field as changed, so stale
per-locale values are never preserved (see Gotchas).
| Script | Purpose |
|--------|---------|
| scripts/extract.mjs | Build a translation work order (what to translate, into which locales). |
| scripts/apply.mjs | Merge translations + AppName table into the export → *-localized.csv. |
| scripts/fields.mjs | Field classification (appname / translate / verbatim) + AppName-table parser. |
| scripts/csvlib.mjs | Quote-aware CSV parse/serialize (UTF-8 BOM + CRLF, embedded newlines). |
Run any script with --help for its options.
locale still holds the *previous version's* text. apply.mjs has an
automatic version-drift safety net: for any field whose en-US value
carries a v<x.y.z> token (e.g. ReleaseNotes), a locale whose existing text
has a *different* token is treated as stale and refreshed to the new en-US —
even if you forget --changed-fields. Still pass --enus (or
--changed-fields) for changed fields to be explicit; the guard is a backstop.
Verified: without any flag, a German release note that kept v0.1.1531 while
en-US moved to v0.1.1600 is now auto-refreshed.
profile dir (never the live Edge\User Data, which is locked while Edge runs).
be published separately.
Field/ID/Type columns or split the CSV on rawnewlines — ReleaseNotes/Description contain embedded newlines. Use csvlib.mjs.
zh-cn), mixed-case in .resw(zh-CN). Match case-insensitively when borrowing terminology.
Version v0.1.1600) — copy verbatim per locale;only translate the bullet text. Keep brand/tech tokens (Copilot, CLI,
Agent pane, PowerShell) in English.
apply.mjs replaces "IntelligentTerminal" inside Description/ReleaseNotes/Features with the locale's AppName
(matching the Title), e.g. de-DE "Intelligentes Terminal", zh-CN "智能终端".
This is URL-safe (the github.com/microsoft/intelligent-terminal URL is
untouched). Don't hand-keep the English name in translated bullets.
10000, ShortDescription 1000). Translations expand vs. English by up to
~1.3–1.4×, so a 1280-char en-US ReleaseNotes produced 1680-char translations
that failed the whole import mid-run ("Processing failed" → View errors →
"ReleaseNotes is too long"). Keep en-US ReleaseNotes ≤ ~1100 chars and tell
the translation sub-agents the ≤1400 target explicitly. apply.mjs now
runs the length guard before writing and refuses to emit an over-limit
CSV (exits non-zero, no output file) — so a known-bad file can't be imported.
| Issue | Solution |
|-------|----------|
| Playwright (playwright/*) MCP tools not available | The Playwright MCP didn't load — restart Copilot CLI; confirm the playwright entry in ~/.copilot/mcp-config.json. |
| Export lands on a login page | Corp SSO session expired — complete the interactive Microsoft login + MFA in the Edge window, then retry. |
| Profile-lock / "browser in use" error | --user-data-dir points at the live Edge profile; use the dedicated msstore-playwright-profile dir. |
| Import rejected / mojibake | Output must be UTF-8 BOM + CRLF with unchanged col/row counts — apply.mjs does this; don't re-save the CSV in another editor. |
| A locale shows the old version number | The field wasn't marked changed — re-run apply.mjs with --enus/--changed-fields. |
.resw alignment.Take microsoft/store-listing-localizer from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.