Summary
PowerShellBuild.psm1 carries a hand-maintained second copy of the localized strings in an inline
data LocalizedData { ConvertFrom-StringData @'...'@ } block, introduced with the comment
# Load here in case Import-LocalizedData is not available. It has drifted from
PowerShellBuild/en-US/Messages.psd1, and on Windows PowerShell 5.1 with a non-English UI culture
it is the copy consumers actually get.
Evidence
Import-LocalizedData is called with -ErrorAction SilentlyContinue, so a lookup that resolves
nothing leaves the stale inline table bound and says nothing about it. The two supported hosts do
not agree on when that lookup misses.
Probe module with en-US/Messages.psd1 (Source=en-US-file) and de-DE/Messages.psd1
(Source=de-DE-file) next to a script that seeds $LocalizedData with Source=inline-fallback
and then runs the same splat the module uses:
pwsh 7 (PowerShell 7.5) powershell.exe (5.1.26100.9168)
en-US -> en-US-file en-US -> en-US-file
de-DE -> de-DE-file de-DE -> de-DE-file
de-AT -> en-US-file de-AT -> inline-fallback
fr-FR -> en-US-file fr-FR -> inline-fallback
ja-JP -> en-US-file ja-JP -> inline-fallback
PowerShell 7 has a final en-US fallback (confirmed by hiding the en-US directory, after which
fr-FR also lands on inline-fallback). Windows PowerShell 5.1 has no such fallback: it walks the
culture's own parent chain and stops.
Against the real module on Windows PowerShell 5.1:
en-US: Keys=41 HasModuleLandingPageNotFound=True requires Pester 6.0.0 or newer.
fr-FR: Keys=25 HasModuleLandingPageNotFound=False requires Pester 5.0.0 or newer.
ja-JP: Keys=25 HasModuleLandingPageNotFound=False requires Pester 5.0.0 or newer.
Sixteen of the forty-one shipped strings are missing, and PesterVersionNotSupported still names
the pre-#182 floor of 5.0.0.
Impact
Missing keys do not throw -- $null -f $arguments returns an empty string rather than raising --
so the failure is silent and worse to diagnose:
Write-Warning ($LocalizedData.ModuleLandingPageNotFound -f $path, $locale) in
Build-PSBuildUpdatableHelp emits a blank WARNING: line.
Write-Warning ($LocalizedData.HelpInfoUriRequired -f $Module) does the same.
throw $LocalizedData.NoCertificateFound in IB.tasks.ps1 raises ScriptHalted with no
explanation of what went wrong.
Assert ($null -ne $certificate) $LocalizedData.NoCertificateFound in psakeFile.ps1 asserts
with no message.
Test-PSBuildPester reports a floor of 5.0.0 when the real requirement is 6.0.0.
Windows PowerShell 5.1 is a supported host (PowerShellVersion = '5.1',
CompatiblePSEditions = @('Desktop', 'Core')), and non-English Windows installations are common,
so this is reachable rather than theoretical.
en-US/Messages.psd1 itself is shipped correctly -- the root Build task copies the whole source
tree -- so the file is always present; only the lookup misses.
Fix direction
The duplication is the defect. Delete the inline copy and make the lookup deterministic by asking
for en-US by name when the culture-based lookup binds nothing, with -ErrorAction Stop on that
fallback so genuinely missing strings fail at import instead of blanking every message. Add tests
that pin both halves: one source of truth, and a complete string table under a non-English UI
culture on every supported host.
Summary
PowerShellBuild.psm1carries a hand-maintained second copy of the localized strings in an inlinedata LocalizedData { ConvertFrom-StringData @'...'@ }block, introduced with the comment# Load here in case Import-LocalizedData is not available. It has drifted fromPowerShellBuild/en-US/Messages.psd1, and on Windows PowerShell 5.1 with a non-English UI cultureit is the copy consumers actually get.
Evidence
Import-LocalizedDatais called with-ErrorAction SilentlyContinue, so a lookup that resolvesnothing leaves the stale inline table bound and says nothing about it. The two supported hosts do
not agree on when that lookup misses.
Probe module with
en-US/Messages.psd1(Source=en-US-file) andde-DE/Messages.psd1(
Source=de-DE-file) next to a script that seeds$LocalizedDatawithSource=inline-fallbackand then runs the same splat the module uses:
PowerShell 7 has a final
en-USfallback (confirmed by hiding theen-USdirectory, after whichfr-FRalso lands oninline-fallback). Windows PowerShell 5.1 has no such fallback: it walks theculture's own parent chain and stops.
Against the real module on Windows PowerShell 5.1:
Sixteen of the forty-one shipped strings are missing, and
PesterVersionNotSupportedstill namesthe pre-#182 floor of 5.0.0.
Impact
Missing keys do not throw --
$null -f $argumentsreturns an empty string rather than raising --so the failure is silent and worse to diagnose:
Write-Warning ($LocalizedData.ModuleLandingPageNotFound -f $path, $locale)inBuild-PSBuildUpdatableHelpemits a blankWARNING:line.Write-Warning ($LocalizedData.HelpInfoUriRequired -f $Module)does the same.throw $LocalizedData.NoCertificateFoundinIB.tasks.ps1raisesScriptHaltedwith noexplanation of what went wrong.
Assert ($null -ne $certificate) $LocalizedData.NoCertificateFoundinpsakeFile.ps1assertswith no message.
Test-PSBuildPesterreports a floor of 5.0.0 when the real requirement is 6.0.0.Windows PowerShell 5.1 is a supported host (
PowerShellVersion = '5.1',CompatiblePSEditions = @('Desktop', 'Core')), and non-English Windows installations are common,so this is reachable rather than theoretical.
en-US/Messages.psd1itself is shipped correctly -- the rootBuildtask copies the whole sourcetree -- so the file is always present; only the lookup misses.
Fix direction
The duplication is the defect. Delete the inline copy and make the lookup deterministic by asking
for
en-USby name when the culture-based lookup binds nothing, with-ErrorAction Stopon thatfallback so genuinely missing strings fail at import instead of blanking every message. Add tests
that pin both halves: one source of truth, and a complete string table under a non-English UI
culture on every supported host.