Add localization for app names and descriptions (#769)

* Translate app names and descriptions in Config/Apps.json

* Document Apps section and first-ID translation key for multi-ID apps

* Fix app list breaking when "Only show installed" runs translation in an isolated runspace
This commit is contained in:
Sashank
2026-10-01 21:25:34 +02:00
committed by GitHub
parent 32024662f3
commit 6feebba878
11 changed files with 705 additions and 38 deletions
+9 -1
View File
@@ -16,13 +16,14 @@ Describe 'Resolve-LanguageFolder' {
}
Describe 'Import-LanguageFile' {
It 'loads all three JSON files for the resolved language' {
It 'loads all four JSON files for the resolved language' {
$lang = Import-LanguageFile -LanguageCode 'en-US'
$lang.LanguageCode | Should -Be 'en-US'
$lang.Chrome.TitleBarClose | Should -Be 'Close'
$lang.Features.DisableTelemetry.Label | Should -Be 'Disable telemetry'
$lang.Categories.PrivacySuggestedContent.Label | Should -Be 'Privacy & Suggested Content'
$lang.Apps.'TestApp.One'.FriendlyName | Should -Be 'Test App'
}
It 'attaches an en-US Fallback when a non-en-US language is loaded' {
@@ -124,6 +125,11 @@ Describe 'Get-Translation' {
Get-Translation -Key 'PrivacySuggestedContent' -Field 'Label' -Lang $script:EnLang | Should -Be 'Privacy & Suggested Content'
}
It 'looks up a Field on an Apps entry' {
Get-Translation -Key 'TestApp.One' -Field 'FriendlyName' -Section 'Apps' -Lang $script:EnLang | Should -Be 'Test App'
Get-Translation -Key 'TestApp.One' -Field 'Description' -Section 'Apps' -Lang $script:EnLang | Should -Be 'A test app.'
}
It 'looks up a Field on a UiGroups entry' {
Get-Translation -Key 'SearchIcon' -Field 'Label' -Lang $script:EnLang | Should -Be 'Taskbar search style'
}
@@ -199,6 +205,8 @@ Describe 'Test-LanguageKeyCoverage' {
$coverage.MissingKeys | Should -Contain 'Features.DisableTelemetry.ToolTip'
$coverage.MissingKeys | Should -Contain 'UiGroups.SearchIcon.Label'
$coverage.MissingKeys | Should -Contain 'Categories.PrivacySuggestedContent.Label'
$coverage.MissingKeys | Should -Contain 'Apps.TestApp.One.FriendlyName'
$coverage.MissingKeys | Should -Contain 'Apps.TestApp.One.Description'
$coverage.ExtraKeys | Should -BeNullOrEmpty
}
+26
View File
@@ -1,7 +1,10 @@
BeforeAll {
Add-Type -AssemblyName PresentationFramework
function Invoke-DoEvents {}
. (Join-Path $PSScriptRoot '..\Scripts\FileIO\Import-JsonFile.ps1')
. (Join-Path $PSScriptRoot '..\Scripts\FileIO\Import-LanguageFile.ps1')
. (Join-Path $PSScriptRoot '..\Scripts\FileIO\Import-AppDetailsFromJson.ps1')
. (Join-Path $PSScriptRoot '..\Scripts\Threading\Invoke-NonBlocking.ps1')
. (Join-Path $PSScriptRoot '..\Scripts\GUI\MainWindow-AppSelection.ps1')
. (Join-Path $PSScriptRoot '..\Scripts\GUI\MainWindow-Deployment.ps1')
. (Join-Path $PSScriptRoot '..\Scripts\GUI\MainWindow-Navigation.ps1')
@@ -9,6 +12,10 @@ BeforeAll {
. (Join-Path $PSScriptRoot '..\Scripts\GUI\Set-WindowThemeResources.ps1')
$script:LanguagesPath = Join-Path $PSScriptRoot '..\Config\Languages'
$script:Lang = Import-LanguageFile -LanguageCode 'en-US'
$script:LoadAppsDetailsScriptPath = Join-Path $PSScriptRoot '..\Scripts\FileIO\Import-AppDetailsFromJson.ps1'
$script:TestAppInWingetListScriptPath = Join-Path $PSScriptRoot '..\Scripts\AppRemoval\Test-AppInWingetList.ps1'
$script:ImportLanguageFileScriptPath = Join-Path $PSScriptRoot '..\Scripts\FileIO\Import-LanguageFile.ps1'
$script:AppsListFilePath = Join-Path $PSScriptRoot '..\Config\Apps.json'
function New-TestWindow {
$window = New-Object System.Windows.Window
@@ -19,6 +26,25 @@ BeforeAll {
}
}
Describe 'Invoke-AppDetailsFromJsonAsync' {
BeforeEach { $script:GuiWindow = [PSCustomObject]@{} }
It 'resolves translated FriendlyName and Description inside the background runspace' {
$result = @(Invoke-AppDetailsFromJsonAsync -OnlyInstalled:$false)
$result.Count | Should -Be 141
$clipchamp = $result | Where-Object { $_.AppId -contains 'Clipchamp.Clipchamp' }
$clipchamp.FriendlyName | Should -Be 'Clipchamp'
$clipchamp.Description | Should -Be 'Video editor from Microsoft'
}
It 'does not return null entries when OnlyInstalled filters the runspace results' {
$result = @(Invoke-AppDetailsFromJsonAsync -OnlyInstalled:$true -InstalledList @())
@($result | Where-Object { -not $_ }).Count | Should -Be 0
}
}
Describe 'ConvertTo-NormalizedCheckboxState' {
It 'normalizes indeterminate tri-state checkboxes to checked' {
$checkBox = New-Object System.Windows.Controls.CheckBox
+17 -1
View File
@@ -3,6 +3,7 @@ BeforeAll {
function Test-AppInWingetList { param($appId, $InstalledList) $false }
. (Join-Path $PSScriptRoot '..\Scripts\FileIO\Import-JsonFile.ps1')
. (Join-Path $PSScriptRoot '..\Scripts\FileIO\Import-LanguageFile.ps1')
. (Join-Path $PSScriptRoot '..\Scripts\Helpers\Add-Parameter.ps1')
. (Join-Path $PSScriptRoot '..\Scripts\FileIO\Save-ToFile.ps1')
. (Join-Path $PSScriptRoot '..\Scripts\FileIO\Import-Settings.ps1')
@@ -12,6 +13,8 @@ BeforeAll {
. (Join-Path $PSScriptRoot '..\Scripts\FileIO\Import-AppPresetsFromJson.ps1')
. (Join-Path $PSScriptRoot '..\Scripts\FileIO\Get-ValidatedAppList.ps1')
$script:JsonFixturePath = Join-Path $PSScriptRoot 'TestData\JsonFileLoading'
$script:LanguagesPath = Join-Path $PSScriptRoot '..\Config\Languages'
$script:Lang = Import-LanguageFile -LanguageCode 'en-US'
}
Describe 'Save-ToFile' {
@@ -150,7 +153,8 @@ Describe 'Import-AppDetailsFromJson' {
$apps = @(Import-AppDetailsFromJson -InitialCheckedFromJson)
$apps | Should -HaveCount 2
$apps[0].DisplayName | Should -Be 'One (One.App, Alias.App)'
# 'One.App' has no en-US Apps.json entry, so Get-Translation falls back to the raw key.
$apps[0].DisplayName | Should -Be 'One.App (One.App, Alias.App)'
$apps[0].IsChecked | Should -BeTrue
$apps[0].RemovalMethod | Should -Be 'WinGet'
$apps[1].FriendlyName | Should -Be 'Two.App'
@@ -159,6 +163,18 @@ Describe 'Import-AppDetailsFromJson' {
@($apps[1].AppId) | Should -HaveCount 1
}
It 'resolves FriendlyName and Description from Config/Languages/en-US/Apps.json for a real AppId' {
'{"Apps":[{"AppId":"Clipchamp.Clipchamp","FriendlyName":"stale JSON name, should not appear","Description":"stale JSON description, should not appear"}]}' |
Set-Content -LiteralPath $script:AppsListFilePath -Encoding UTF8
$apps = @(Import-AppDetailsFromJson)
$apps | Should -HaveCount 1
$apps[0].FriendlyName | Should -Be 'Clipchamp'
$apps[0].Description | Should -Be 'Video editor from Microsoft'
$apps[0].DisplayName | Should -Be 'Clipchamp (Clipchamp.Clipchamp)'
}
It 'skips missing, blank, and non-string app IDs without failing the complete catalog' {
'{"Apps":[{"AppId":null},{"FriendlyName":"Missing"},{"AppId":42},{"AppId":[" Valid.App ",null,{},""]}]}' |
Set-Content -LiteralPath $script:AppsListFilePath -Encoding UTF8
@@ -0,0 +1,6 @@
{
"TestApp.One": {
"FriendlyName": "Test App",
"Description": "A test app."
}
}
@@ -0,0 +1 @@
{}