master
md 14.6 KB

Creating Localization Tracking Bugs (GCS Azure DevOps)

Community members report localization problems in two ways: by filing a GitHub issue about a bad translation, or by opening a pull request that edits a localized file (the per-locale UI strings in localization/strings/<locale>/Resources.resw, or the per-locale Intune/group-policy templates in intune/<locale>/WSL.adml), or that adds a brand-new locale file. Both are valid signals and you should look for both when triaging.

Either way, the fix is handled by the Microsoft Global Collaboration Service (GCS) localization pipeline, not merged directly from GitHub: every non-en-US localized file is generated by the GCS team and regenerated downstream, so any translation edit merged here would be overwritten. (PRs that touch localized files should be declined with a pointer to CONTRIBUTING.md; only the en-US sources and the language-neutral intune/WSL.admx live in this repo.) To route a report for review, file a tracking Bug in the GCS Azure DevOps project for each issue or PR.

GCS requirement — be specific: list the exact resource IDs to fix. The loc team will not triage abstract reports. A bug that only names the file, language, and a few quoted strings gets rejected (moved to the More Info state) because the team does not have capacity to parse a vague report into the concrete strings that need work — that translation has to be done up front by the filer. Every bug must therefore carry an explicit list of the resource IDs (the name attribute of the <data name="..."> elements in localization/strings/<locale>/Resources.resw) that need fixing. The gold-standard level of detail is Bug 1223866 (.../GlobalCollaborationService/Global%20Collaboration%20Service%20Project/_workitems/edit/1223866): for each resource ID it gives the current (bad) value and the proposed value, e.g.

MessageDistroAlreadySet
  current:  Der Verteilungsname wurde bereits festgelegt.
  proposed: Der Distributionsname wurde bereits festgelegt.

Deriving the resource-ID list

How you obtain the IDs depends on the report type:

  • PR editing an existing locale file — the changed resource IDs are exactly the <data name> blocks whose <value> differs between the repo's current file and the PR head. Load both and diff by name. The PR "Files changed" view already shows current→proposed for each, so post the compact ID list plus a link to the PR diff rather than re-inlining every value (a 160-row inline table is unwieldy; the PR diff is the source of truth for the old/new text).
  # changed resource IDs between two Resources.resw files (master vs PR head)
  function Get-ChangedIds($baseResw, $headResw) {
    function Load($p) { $x = [xml](Get-Content $p -Raw); $h = @{}; foreach ($d in $x.root.data) { $h[$d.name] = $d.value }; $h }
    $b = Load $baseResw; $h = Load $headResw
    $h.Keys | Where-Object { $b[$_] -ne $h[$_] }
  }
  • Issue citing line numbers (e.g. Resources.resw#L185) — fetch the file at the exact commit the issue links to, then walk upward from each cited line to the nearest data name="..." to get the enclosing resource ID. Line numbers drift between commits, so always pin to the linked SHA.

  • Issue quoting bad strings — grep the locale Resources.resw for each quoted value to find the <data name> that contains it. One displayed term often maps to several IDs (.Header, .Description, ...TextBox.AutomationProperties.Name/.HelpText, shell-nav .Content), so list them all.

  • PR adding a brand-new locale — this is a net-new whole-file contribution, not a correction list, so there is nothing pre-existing to "fix". Give the team the actionable file-level items instead: (1) hard parity failures vs en-US that block tools/devops/validate-localization.py — placeholder/insert-count mismatches and missing {Locked="..."} tokens, listed by resource ID; (2) the coverage gap (which en-US IDs are missing, and how many of N total); (3) any strings present in the file but absent from en-US (obsolete — drop them); and (4) that a new locale needs build registration, not just a file drop.

Coordinates

Org https://dev.azure.com/GlobalCollaborationService
Project Global Collaboration Service Project
Process GCS_Agile
Work item type Bug
Web "create from template" link https://dev.azure.com/GlobalCollaborationService/Global%20Collaboration%20Service%20Project/_workitems/create/Bug?templateId=b97df4d3-4106-4099-a3a9-1782b5891bec

Required fields (and known-good values for a community loc PR)

The Bug type has several required custom picklist fields. Values that work for "community translation PR needs review":

Field (reference name) Value
System.Title WSL: Review community <locale> localization report (GitHub #<issue or PR>)
System.Description / Microsoft.VSTS.TCM.ReproSteps GitHub link + scope + action (see below)
Custom.IssueType Incorrect Translation
Custom.ProductArea Software
Custom.How_Found Community
Custom.Severity_Impact S3 - Medium (field default)
Microsoft.VSTS.Common.ValueArea Business (field default)
Custom.HaveyouattachedEnglishandlocalizedscreenshots No (allowed: Yes/No; no default — must be set)
Custom.Language picklist — see mapping below (the WSL locale code is not accepted)

Other required custom flags (Custom.BugBlocked, Custom.XLanguage, Custom.OverrideMaxStringsThreshold, Custom.SkipSourceAudioFilesValidation, Custom.DidCopilotrespondinthesamelanguage, Custom.Copilotattachallfiles) default to 0 and auto-fill; leave them unset.

Custom.Language mapping (picklist values, not locale codes)

Custom.Language is a 148-value picklist keyed by display name. Map the WSL Resources.resw locale folder to the picklist value:

WSL locale Custom.Language value
es-ES Spanish (Spain, International Sort)
zh-CN Chinese (Simplified) - PRC
el-GR Greek (Greece)
tr-TR Turkish (Turkey)

For other locales, list the allowed values and match by display name:

$org="https://dev.azure.com/GlobalCollaborationService"
$projEnc="Global%20Collaboration%20Service%20Project"
$res="499b84ac-1321-427f-aa17-267ca6975798"   # Azure DevOps AAD resource id
az rest --method get --resource $res `
  --uri "$org/$projEnc/_apis/wit/workitemtypes/Bug/fields/Custom.Language?`$expand=all" `
  --headers "Accept=application/json;api-version=7.1-preview.3" |
  ConvertFrom-Json | Select-Object -ExpandProperty allowedValues

Suggested description body

Community localization report on GitHub microsoft/WSL needs review by the loc pipeline.

GitHub: https://github.com/microsoft/WSL/<issues or pull>/<number>
Language: <locale>
Type: <issue reporting a bad translation | PR editing the localized file>
Scope: localized file (localization/strings/<locale>/Resources.resw or intune/<locale>/WSL.adml).
  For a PR: <edits to existing | brand-new>, +A/-B, 1 file. For an issue: the specific string(s) reported.
Resource IDs to fix: <explicit list of <data name> keys - see the dedicated comment with the full
  list, or paste it here>. This is required; see "Deriving the resource-ID list" above.
Action: validate placeholder/locked-token parity vs en-US (tools/devops/validate-localization.py),
then incorporate or advise. New locales additionally need build registration, not just a file drop.
Note: do not merge the GitHub PR - localized files are regenerated by GCS and edits here are overwritten.

The resource-ID list is the part GCS actually needs. If it is long, post it as a work-item comment (ADO comments accept HTML and can be edited in place via PATCH .../comments/<id>) and reference that comment from the description.

Creating via CLI (az boards)

Requires the azure-devops az extension and an identity with create/edit work item permission in the project (see caveat below).

$org="https://dev.azure.com/GlobalCollaborationService"
$proj="Global Collaboration Service Project"
$area="Global Collaboration Service Project\Global\Windows"   # working area path, see Permissions gotcha
$desc="Community es-ES localization PR. PR: https://github.com/microsoft/WSL/pull/14109 ..."
az boards work-item create --org $org --project $proj --type "Bug" `
  --title "WSL: Review community es-ES localization PR (GitHub #14109)" `
  --area "$area" --description $desc `
  --fields "Microsoft.VSTS.TCM.ReproSteps=$desc" `
           "Custom.Language=Spanish (Spain, International Sort)" `
           "Custom.IssueType=Incorrect Translation" `
           "Custom.ProductArea=Software" `
           "Custom.How_Found=Community" `
           "Custom.Severity_Impact=S3 - Medium" `
           "Microsoft.VSTS.Common.ValueArea=Business" `
           "Custom.HaveyouattachedEnglishandlocalizedscreenshots=No"

Gotchas

  • az.cmd eats & in URLs. When using az rest, never put & (multiple query params) in --uri on Windows — cmd truncates the URL there. Pass api-version via the Accept header instead: --headers "Accept=application/json;api-version=7.1", keeping at most one ?param in the URI.
  • Permissions are area-path-scoped, and the path matters. Creating work items requires explicit rights on the specific area path, not the project as a whole. The correct, durable path for WSL localization bugs is Global Collaboration Service Project\Global\Windows (confirmed against existing manually-filed WSL loc bugs). Always set System.AreaPath (or --area) to that path. A @ntdev.microsoft.com identity is denied at the project root and most other paths (TF237111: ... does not have permissions to save work items under the specified area path). Do NOT file under ...\C and AI\Unspecified: an identity may briefly appear to have access there, but bugs filed there get cleaned up and the access is not stable. To probe a path without creating anything, POST with ?validateOnly=true. If your identity lacks rights everywhere, create the bug through the web template link above.
  • System.Description is required, separately from repro steps. The Bug type rejects a create with TF401320: Rule Error for field Description ... Required, InvalidEmpty unless System.Description is set. Set both System.Description and Microsoft.VSTS.TCM.ReproSteps (the same body is fine). When POSTing a JSON-patch document via az rest, use newline-to-<br> so the HTML-rendered fields keep their line breaks.
  • Picklist discovery. Field allowed-values often don't expand through the plain field endpoint; use ?$expand=all on .../workitemtypes/Bug/fields/<ref> as shown above.
  • "Not found" can mean "no access," not "doesn't exist." WIQL and GET .../workitems/<id> honor ACLs: a CreatedBy=@me query returning zero rows, or TF401232: Work item <id> does not exist, or you do not have permissions to read it, often just means your identity can't read that area path. Don't assume the bug was deleted. A gap in sequential work-item IDs is a tell that items were created but are now invisible to you (e.g. filed under a path whose access got revoked, then reaped) - which is exactly why you should stick to the durable Global\Windows path above.
  • Read the bug back after creating it. Immediately GET each new work item id (or open the URL) to confirm it's actually persisted and readable under your identity. A create that "succeeds" against a flaky area path can vanish later; a read-back catches that while you can still re-file.
  • Non-ASCII gets mangled, and az errors poison ConvertFrom-Json. Locale content (Turkish, Greek, CJK) comes back cp1252-garbled unless you set [Console]::OutputEncoding=[System.Text.Encoding]::UTF8 first. Also, az prints errors to the stream, so piping straight into ConvertFrom-Json throws on any failure; capture with Out-String and parse, or check $LASTEXITCODE. Pass JSON-patch bodies via --body "@file" (content type application/json-patch+json) rather than inline to dodge quoting hell.
  • Don't inline huge diffs into a comment. For a PR that touches many strings, post the resource-ID list and link the PR "Files changed" page for the current→proposed values; a 100+ row HTML table makes the bug unreadable and can bump against comment-size limits. ADO comments can be edited in place (PATCH .../comments/<id>?api-version=7.1-preview.4), so trim/replace rather than re-posting.

After creating

Keep the GitHub link in the ADO Bug's description/repro steps (it's already there from the body above) so the loc team can trace back to the report. Do not paste the internal ADO Bug ID into the public GitHub PR or issue. Then read each new bug back (see gotcha above) to confirm it persisted under Global\Windows.

If GCS moves a bug to More Info, it almost always means the resource-ID detail is missing or too abstract: supply the explicit <data name> list (see "Deriving the resource-ID list"), then move the bug back to Active and reassign it to the requesting GCS reviewer.

What happens after you file (automated pipeline)

Filing the Bug under Global\Windows is usually the end of the manual work. A Fabric Self Service bot (FabricClient-Prod) automatically picks the Bug up and creates a DTT (Direct-To-Translator) job for the locale, posting its progress as Bug discussion comments. So a stream of FabricClient-Prod comments is the expected, healthy path — not something a human has to act on:

  • Bug picked up for processing by the Fabric Self Service process.
  • Successfully created 1 DTT Jobs: ... <locale> ... → the report is now in the translation pipeline; no further action.

Watch for these exceptions, which do need action:

  • New locale not onboarded. If the locale isn't onboarded to TDBuild for the WSL subtenant (WindowsUndocking / LiftedWSL), the DTT job can't be created and a human comments pointing you to file an onboarding request at the Global Services Hub (https://globalservices.powerappsportals.com/global/). This is GCS-side onboarding and is separate from (and in addition to) the WSL-repo build registration a new locale needs. Greek (el-GR, GitHub #40244) hit exactly this.
  • Oversized report. A non-retriable Rqf query exceeded threshold of 1000 words failure means the report's scope is too large; reduce the scope or set Custom.OverrideMaxStringsThreshold and re-file.

If you only see FabricClient-Prod "Successfully created ... DTT Jobs" comments, you're done.