Add persistent output locale override setting - #6310
Add persistent output locale override setting#6310Kaleb Luedtke (Trenly) wants to merge 17 commits into
Conversation
* Add output.locale setting and schema support * Apply runtime language qualifier override for resource resolution * Include localized resw fallbacks in dev package and update docs/release notes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Flor Chacón (florelis)
left a comment
There was a problem hiding this comment.
LGTM, but I'd want to hold off on merging until we have a plan for what to do with App Installer.
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
This comment was marked as outdated.
This comment was marked as outdated.
…tput-locale-override
There was a problem hiding this comment.
Pull request overview
Adds a new persisted output.locale user setting that lets WinGet override the UI/output language (via a supported BCP47 tag), and wires the setting into startup initialization so localized resources resolve accordingly. It also updates schema/docs/release notes and adjusts packaging to pick up localized winget.resw files during local builds.
Changes:
- Introduces
Setting::OutputLocale(settings mapping + validation/normalization against supported locale tags). - Applies the locale override at CLI startup via
ApplicationLanguages::PrimaryLanguageOverride. - Updates the settings schema + documentation + release notes, and adds packaging fallback to include localized
winget.reswfromLocalization\Resources\<locale>whenShared\Strings\<locale>is absent.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/AppInstallerCommonCore/UserSettings.cpp | Adds supported-locale normalization and validation for the new output.locale setting. |
| src/AppInstallerCommonCore/Public/winget/UserSettings.h | Adds the OutputLocale setting enum value and JSON mapping to .output.locale. |
| src/AppInstallerCLITests/UserSettings.cpp | Adds unit tests covering default/valid/case-insensitive/invalid locale values. |
| src/AppInstallerCLIPackage/AppInstallerCLIPackage.wapproj | Adds build-time fallback PRIResource includes from Localization\\Resources\\<locale> for local builds. |
| src/AppInstallerCLICore/Core.cpp | Applies the persisted output locale override during startup initialization. |
| schemas/JSON/settings/settings.schema.0.2.json | Adds output.locale to the public settings schema with supported enum values. |
| doc/windows/package-manager/winget/settings.md | Documents the new output.locale setting for end users. |
| doc/Settings.md | Documents the new output.locale setting in the repo’s settings documentation. |
| doc/ReleaseNotes.md | Adds a release note entry for the new output locale override feature. |
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
|
Looks like we will need to reset the override in App Installer. Internal PR number for that: 16173490 |
|
Question from internal discussion: |
|
|
||
| bool SetLanguageOverride(std::string_view localeTag) | ||
| { | ||
| return Loader::Instance().SetLanguageOverride(Utility::ConvertToUTF16(localeTag)); |
There was a problem hiding this comment.
Nit: Assuming this is done before any localized strings are fetched, this is going to create a loader with default options, and then immediately overwrite it with a new one that uses the locale. We could make it so that we only needed to create it once, but that's probably too small a gain to care.
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
|
Grrr, pesky build failures |
…tput-locale-override
|
@florelis - I've merged the latest changes from
|
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
ApplyOutputLocaleOverride() unconditionally triggered Loader::Instance()
at startup for every command, including dscv3 --manifest which runs
winget.exe unpackaged during the WinGetGenerateDSCv3Manifests build step.
The Loader() constructor had been refactored to call CreateLoader({}),
which calls ResourceContext::ResetGlobalQualifierValues() before
ResourceLoader(). This broke the safety guard that the original code
relied on: when unpackaged and resource.pri is not found, ResourceLoader()
throws a catchable hresult_error, preventing execution from reaching
ResourceLoader::GetForViewIndependentUse which fast-fails with an
uncatchable crash (0xC0000409 STATUS_STACK_BUFFER_OVERRUN) when not
under a debugger.
Two fixes:
- Restore the original constructor initialization path (without calling
CreateLoader) so the ResourceLoader() probe is not interfered with
- Guard ApplyOutputLocaleOverride to skip loader initialization entirely
when no locale override is configured (the common case)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Root Cause AnalysisNote This comment was authored by GitHub Copilot. Root cause: The original code relied on FixTwo changes applied in commit 25c246a:
|
| return {}; | ||
| } | ||
|
|
||
| if (!AppInstaller::Resource::SetLanguageOverride(localeTag)) |
There was a problem hiding this comment.
This can throw; do we think it important enough to respect the target locale that we should terminate the winget.exe process if we cannot?
There was a problem hiding this comment.
Right now the throw should be caught internally to the function and result in the false return, walking through the warning path here. My thought was that this should be best-effort and not breaking. This would most closely match the behavior today where if the Locale coming from the OS doesn't map to an avaliable resource file it falls back to whatever the resource loader deems is the best fit.
I'm not opposed to making it a hard failure, but without knowing how often it would or could throw, just makes me a bit uneasy. Is this a decision that needs to be made now? Could we do something in the future like adding a telemetry event sampling language overrides as a what-if to better understand the potential impact of making it a terminating failure?
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

📖 Description
Add a persistent
output.localeuser setting that allows overriding winget interface string resolution by BCP47 tag.Current implementation details:
.output.localeat CLI startup and applies the override only when the setting is non-empty.Resource::SetLanguageOverride, which sets the MRTLanguagequalifier for winget resource loading.wil::srwlockin the shared resource loader for synchronized read/write access when resolving strings and updating locale override.This PR also updates settings schema/documentation and local package resource fallback handling for localized
winget.reswfiles.🔗 References
Resolves #422
🤖 Copilot Assistance
This PR includes changes authored with GitHub Copilot assistance.
🔍 Validation
OutputLocalesetting parsing/normalization behavior.output.localechanges.✅ Checklist
📋 Issue Type
Microsoft Reviewers: Open in CodeFlow