mirror of
https://github.com/Raphire/Win11Debloat.git
synced 2026-10-08 06:26:45 +00:00
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:
@@ -70,8 +70,8 @@ function Import-AppDetailsFromJson {
|
||||
# Use first AppId for fallback names, join all for display
|
||||
$primaryAppId = $appIdArray[0]
|
||||
$appIdDisplay = $appIdArray -join ', '
|
||||
$friendlyName = if ($appData.FriendlyName) { $appData.FriendlyName } else { $primaryAppId }
|
||||
$displayName = if ($appData.FriendlyName) { "$($appData.FriendlyName) ($appIdDisplay)" } else { $appIdDisplay }
|
||||
$friendlyName = Get-Translation -Key $primaryAppId -Field 'FriendlyName' -Section 'Apps'
|
||||
$displayName = "$friendlyName ($appIdDisplay)"
|
||||
$isChecked = if ($InitialCheckedFromJson) { $appData.SelectedByDefault } else { $false }
|
||||
|
||||
$apps += [PSCustomObject]@{
|
||||
@@ -80,7 +80,7 @@ function Import-AppDetailsFromJson {
|
||||
FriendlyName = $friendlyName
|
||||
DisplayName = $displayName
|
||||
IsChecked = $isChecked
|
||||
Description = $appData.Description
|
||||
Description = Get-Translation -Key $primaryAppId -Field 'Description' -Section 'Apps'
|
||||
SelectedByDefault = $appData.SelectedByDefault
|
||||
Recommendation = $appData.Recommendation
|
||||
RemovalMethod = if ($appData.RemovalMethod -and $appData.RemovalMethod -eq 'WinGet') { 'WinGet' } else { 'Appx' }
|
||||
@@ -89,3 +89,51 @@ function Import-AppDetailsFromJson {
|
||||
|
||||
return $apps
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Runs Import-AppDetailsFromJson in a background runspace via Invoke-NonBlocking.
|
||||
|
||||
.DESCRIPTION
|
||||
The runspace inherits neither dot-sourced functions nor script-scoped variables, so
|
||||
this dot-sources the app loader, its winget helper, and the language loader inside the
|
||||
scriptblock, and passes $Lang through to be reassigned to $script:Lang there.
|
||||
|
||||
.PARAMETER OnlyInstalled
|
||||
Filters the results to applications detected through Appx or the supplied
|
||||
winget installation list.
|
||||
|
||||
.PARAMETER InstalledList
|
||||
A pre-fetched winget installation list used when filtering installed apps.
|
||||
|
||||
.PARAMETER InitialCheckedFromJson
|
||||
Sets each returned app's IsChecked value from its SelectedByDefault setting.
|
||||
|
||||
.PARAMETER Lang
|
||||
The loaded language object ($script:Lang) to make available inside the runspace.
|
||||
#>
|
||||
function Invoke-AppDetailsFromJsonAsync {
|
||||
param (
|
||||
[string]$LoaderScriptPath = $script:LoadAppsDetailsScriptPath,
|
||||
[string]$HelperScriptPath = $script:TestAppInWingetListScriptPath,
|
||||
[string]$LanguageFileScriptPath = $script:ImportLanguageFileScriptPath,
|
||||
[string]$AppsFilePath = $script:AppsListFilePath,
|
||||
[object[]]$InstalledList = $null,
|
||||
[switch]$OnlyInstalled,
|
||||
[switch]$InitialCheckedFromJson,
|
||||
[object]$Lang = $script:Lang
|
||||
)
|
||||
|
||||
$onlyInstalledValue = [bool]$OnlyInstalled
|
||||
$initialCheckedFromJsonValue = [bool]$InitialCheckedFromJson
|
||||
|
||||
return Invoke-NonBlocking -ScriptBlock {
|
||||
param($loaderScript, $helperScript, $languageFileScript, $appsListFilePath, $installedList, $onlyInstalled, $initialCheckedFromJson, $Lang)
|
||||
$script:AppsListFilePath = $appsListFilePath
|
||||
$script:Lang = $Lang
|
||||
. $helperScript
|
||||
. $languageFileScript
|
||||
. $loaderScript
|
||||
Import-AppDetailsFromJson -OnlyInstalled:$onlyInstalled -InstalledList $installedList -InitialCheckedFromJson:$initialCheckedFromJson
|
||||
} -ArgumentList $LoaderScriptPath, $HelperScriptPath, $LanguageFileScriptPath, $AppsFilePath, $InstalledList, $onlyInstalledValue, $initialCheckedFromJsonValue, $Lang
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ function Resolve-LanguageFolder {
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Loads Chrome/Features/Categories JSON for a language folder, or returns $null on failure.
|
||||
Loads Chrome/Features/Categories/Apps JSON for a language folder, or returns $null on failure.
|
||||
#>
|
||||
function Import-LanguageContent {
|
||||
param(
|
||||
@@ -38,8 +38,9 @@ function Import-LanguageContent {
|
||||
$chrome = Import-JsonFile -filePath (Join-Path $folderPath 'Chrome.json')
|
||||
$features = Import-JsonFile -filePath (Join-Path $folderPath 'Features.json')
|
||||
$categories = Import-JsonFile -filePath (Join-Path $folderPath 'Categories.json')
|
||||
$apps = Import-JsonFile -filePath (Join-Path $folderPath 'Apps.json')
|
||||
|
||||
if (-not $chrome -or -not $features -or -not $categories) {
|
||||
if (-not $chrome -or -not $features -or -not $categories -or -not $apps) {
|
||||
return $null
|
||||
}
|
||||
|
||||
@@ -49,6 +50,7 @@ function Import-LanguageContent {
|
||||
Features = $features.Features
|
||||
UiGroups = $features.UiGroups
|
||||
Categories = $categories
|
||||
Apps = $apps
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +130,7 @@ function Get-LanguageFallbackChain {
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Finds the named section object (Chrome, Features, UiGroups, or Categories) that owns a key.
|
||||
Finds the named section object (Chrome, Features, UiGroups, Categories, or Apps) that owns a key.
|
||||
|
||||
.DESCRIPTION
|
||||
A FeatureId, GroupId, and CategoryId aren't guaranteed to be disjoint (Config/Features.json
|
||||
@@ -142,7 +144,7 @@ function Find-TranslationSection {
|
||||
[object]$Lang,
|
||||
[Parameter(Mandatory)]
|
||||
[string]$Key,
|
||||
[ValidateSet('', 'Chrome', 'Features', 'UiGroups', 'Categories')]
|
||||
[ValidateSet('', 'Chrome', 'Features', 'UiGroups', 'Categories', 'Apps')]
|
||||
[string]$Section = ''
|
||||
)
|
||||
|
||||
@@ -154,7 +156,7 @@ function Find-TranslationSection {
|
||||
return $null
|
||||
}
|
||||
|
||||
foreach ($sectionName in 'Chrome', 'Features', 'UiGroups', 'Categories') {
|
||||
foreach ($sectionName in 'Chrome', 'Features', 'UiGroups', 'Categories', 'Apps') {
|
||||
$sectionObject = $Lang.$sectionName
|
||||
if ($sectionObject -and $sectionObject.PSObject.Properties[$Key]) {
|
||||
return $sectionObject
|
||||
@@ -169,14 +171,15 @@ function Find-TranslationSection {
|
||||
Looks up a translated value from the active language, falling back to en-US, then to the key itself.
|
||||
|
||||
.DESCRIPTION
|
||||
Chrome.json keys are flat strings, so -Field is omitted for those. Features/UiGroups/Categories
|
||||
keys (FeatureId/GroupId/CategoryId) resolve to an object, so -Field picks the property on it
|
||||
(Label, ToolTip, ApplyText, UndoLabel, ApplyUndoText). One generic lookup covers every section
|
||||
instead of a separate function per section.
|
||||
Chrome.json keys are flat strings, so -Field is omitted for those. Features/UiGroups/Categories/Apps
|
||||
keys (FeatureId/GroupId/CategoryId/AppId) resolve to an object, so -Field picks the property on it
|
||||
(Label, ToolTip, ApplyText, UndoLabel, ApplyUndoText for Features/UiGroups/Categories;
|
||||
FriendlyName, Description for Apps). One generic lookup covers every section instead of a
|
||||
separate function per section.
|
||||
|
||||
A FeatureId and a GroupId aren't guaranteed to be distinct strings, so pass -Section
|
||||
('Features', 'UiGroups', or 'Categories') whenever the caller knows which one it means,
|
||||
rather than relying on Find-TranslationSection's search order to guess correctly.
|
||||
('Features', 'UiGroups', 'Categories', or 'Apps') whenever the caller knows which one it
|
||||
means, rather than relying on Find-TranslationSection's search order to guess correctly.
|
||||
|
||||
When -Count is supplied, tries the plural-suffixed key ("$Key`_$category") before the bare key,
|
||||
so callers don't need to add a plural variant for every string, only the ones that need one.
|
||||
@@ -191,7 +194,7 @@ function Get-Translation {
|
||||
[object]$Lang = $script:Lang,
|
||||
[Nullable[int]]$Count = $null,
|
||||
[object[]]$FormatArgs = $null,
|
||||
[ValidateSet('', 'Chrome', 'Features', 'UiGroups', 'Categories')]
|
||||
[ValidateSet('', 'Chrome', 'Features', 'UiGroups', 'Categories', 'Apps')]
|
||||
[string]$Section = ''
|
||||
)
|
||||
|
||||
@@ -282,7 +285,7 @@ function Get-GroupValueTranslation {
|
||||
Flattens a loaded language object into a sorted set of dotted key paths.
|
||||
|
||||
.DESCRIPTION
|
||||
Chrome.json keys are already flat and are used as-is. Features/UiGroups/Categories
|
||||
Chrome.json keys are already flat and are used as-is. Features/UiGroups/Categories/Apps
|
||||
keys are one level deeper (EntryId -> {Field: value}), so each field becomes its own
|
||||
"Section.EntryId.Field" path (e.g. "Features.DisableTelemetry.Label"). UiGroups' nested
|
||||
Values map becomes "UiGroups.GroupId.Values.FeatureId". Used by Test-LanguageKeyCoverage
|
||||
@@ -301,7 +304,7 @@ function Get-LanguageKeyPaths {
|
||||
$paths.Add($chromeKey)
|
||||
}
|
||||
|
||||
foreach ($sectionName in 'Features', 'Categories') {
|
||||
foreach ($sectionName in 'Features', 'Categories', 'Apps') {
|
||||
$section = $Lang.$sectionName
|
||||
if (-not $section) { continue }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user