Автоматизировал локальное обновление перевода
This commit is contained in:
186
scripts/apply-translation-edits.ps1
Normal file
186
scripts/apply-translation-edits.ps1
Normal file
@@ -0,0 +1,186 @@
|
||||
param(
|
||||
[string]$RussianPath = "Mods/DnD 5.5e AIO Russian/Localization/Russian/russian.xml",
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$EditsPath
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Read-XmlDocument {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Path
|
||||
)
|
||||
|
||||
$resolvedPath = [System.IO.Path]::GetFullPath($Path)
|
||||
if (-not (Test-Path -LiteralPath $resolvedPath)) {
|
||||
throw "XML file was not found: '$resolvedPath'."
|
||||
}
|
||||
|
||||
[xml]$xml = Get-Content -LiteralPath $resolvedPath -Raw
|
||||
if ($null -eq $xml.SelectSingleNode('/contentList')) {
|
||||
throw "XML file does not contain '/contentList': '$resolvedPath'."
|
||||
}
|
||||
|
||||
return @{
|
||||
Path = $resolvedPath
|
||||
Xml = $xml
|
||||
}
|
||||
}
|
||||
|
||||
function Get-ContentNodeMap {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[xml]$Xml
|
||||
)
|
||||
|
||||
$map = @{}
|
||||
foreach ($node in $Xml.SelectNodes('/contentList/content')) {
|
||||
$contentUid = [string]$node.GetAttribute("contentuid")
|
||||
if ([string]::IsNullOrWhiteSpace($contentUid)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if ($map.ContainsKey($contentUid)) {
|
||||
throw "Duplicate contentuid found in target XML: '$contentUid'."
|
||||
}
|
||||
|
||||
$map[$contentUid] = $node
|
||||
}
|
||||
|
||||
return $map
|
||||
}
|
||||
|
||||
$russianDocument = Read-XmlDocument -Path $RussianPath
|
||||
$temporaryRussianPath = "$($russianDocument.Path).tmp"
|
||||
$validateScriptPath = Join-Path $PSScriptRoot "validate-translation-xml.ps1"
|
||||
|
||||
if (-not (Test-Path -LiteralPath $validateScriptPath)) {
|
||||
throw "Validation script was not found: '$validateScriptPath'."
|
||||
}
|
||||
|
||||
if (Test-Path -LiteralPath $temporaryRussianPath) {
|
||||
Remove-Item -LiteralPath $temporaryRussianPath -Force
|
||||
}
|
||||
|
||||
Copy-Item -LiteralPath $russianDocument.Path -Destination $temporaryRussianPath -Force
|
||||
$russianDocument = Read-XmlDocument -Path $temporaryRussianPath
|
||||
$resolvedEditsPath = [System.IO.Path]::GetFullPath($EditsPath)
|
||||
if (-not (Test-Path -LiteralPath $resolvedEditsPath)) {
|
||||
throw "Edits file was not found: '$resolvedEditsPath'."
|
||||
}
|
||||
|
||||
$edits = Get-Content -LiteralPath $resolvedEditsPath -Raw | ConvertFrom-Json -Depth 10
|
||||
if ($null -eq $edits) {
|
||||
throw "Edits file is empty or invalid JSON: '$resolvedEditsPath'."
|
||||
}
|
||||
|
||||
$contentListNode = $russianDocument.Xml.SelectSingleNode('/contentList')
|
||||
if ($null -eq $contentListNode) {
|
||||
throw "Target russian.xml does not contain '/contentList': '$($russianDocument.Path)'."
|
||||
}
|
||||
|
||||
$nodeMap = Get-ContentNodeMap -Xml $russianDocument.Xml
|
||||
$updatedEntries = New-Object System.Collections.Generic.List[string]
|
||||
$addedEntries = New-Object System.Collections.Generic.List[string]
|
||||
|
||||
$updates = @()
|
||||
if ($edits.PSObject.Properties.Name -contains "updates" -and $null -ne $edits.updates) {
|
||||
$updates = @($edits.updates)
|
||||
}
|
||||
|
||||
foreach ($edit in $updates) {
|
||||
$contentUid = [string]$edit.contentuid
|
||||
if ([string]::IsNullOrWhiteSpace($contentUid)) {
|
||||
throw "Each update entry must contain non-empty 'contentuid'."
|
||||
}
|
||||
|
||||
if (-not $nodeMap.ContainsKey($contentUid)) {
|
||||
throw "Target russian.xml does not contain contentuid '$contentUid' for update."
|
||||
}
|
||||
|
||||
$node = $nodeMap[$contentUid]
|
||||
if ($edit.PSObject.Properties.Name -contains "version" -and -not [string]::IsNullOrWhiteSpace([string]$edit.version)) {
|
||||
$node.SetAttribute("version", [string]$edit.version)
|
||||
}
|
||||
|
||||
if ($edit.PSObject.Properties.Name -contains "text") {
|
||||
$node.InnerText = [string]$edit.text
|
||||
}
|
||||
|
||||
$updatedEntries.Add($contentUid) | Out-Null
|
||||
}
|
||||
|
||||
$adds = @()
|
||||
if ($edits.PSObject.Properties.Name -contains "adds" -and $null -ne $edits.adds) {
|
||||
$adds = @($edits.adds)
|
||||
}
|
||||
|
||||
if (($updates.Count -eq 0) -and ($adds.Count -eq 0)) {
|
||||
if (Test-Path -LiteralPath $temporaryRussianPath) {
|
||||
Remove-Item -LiteralPath $temporaryRussianPath -Force
|
||||
}
|
||||
Write-Host "[apply-translation-edits.ps1] No edits requested. Original russian.xml left unchanged."
|
||||
return
|
||||
}
|
||||
|
||||
foreach ($edit in $adds) {
|
||||
$contentUid = [string]$edit.contentuid
|
||||
$version = [string]$edit.version
|
||||
$text = [string]$edit.text
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($contentUid)) {
|
||||
throw "Each add entry must contain non-empty 'contentuid'."
|
||||
}
|
||||
|
||||
if ($nodeMap.ContainsKey($contentUid)) {
|
||||
throw "Target russian.xml already contains contentuid '$contentUid'; use 'updates' instead of 'adds'."
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($version)) {
|
||||
throw "Add entry '$contentUid' must contain non-empty 'version'."
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($text)) {
|
||||
throw "Add entry '$contentUid' must contain non-empty 'text'."
|
||||
}
|
||||
|
||||
$newNode = $russianDocument.Xml.CreateElement("content")
|
||||
$newNode.SetAttribute("contentuid", $contentUid)
|
||||
$newNode.SetAttribute("version", $version)
|
||||
$newNode.InnerText = $text
|
||||
[void]$contentListNode.AppendChild($newNode)
|
||||
$nodeMap[$contentUid] = $newNode
|
||||
$addedEntries.Add($contentUid) | Out-Null
|
||||
}
|
||||
|
||||
$settings = New-Object System.Xml.XmlWriterSettings
|
||||
$settings.Encoding = New-Object System.Text.UTF8Encoding($true)
|
||||
$settings.Indent = $true
|
||||
$settings.IndentChars = " "
|
||||
$settings.NewLineChars = "`n"
|
||||
$settings.NewLineHandling = [System.Xml.NewLineHandling]::Replace
|
||||
|
||||
$writer = [System.Xml.XmlWriter]::Create($russianDocument.Path, $settings)
|
||||
try {
|
||||
$russianDocument.Xml.WriteTo($writer)
|
||||
} finally {
|
||||
$writer.Dispose()
|
||||
}
|
||||
|
||||
try {
|
||||
& $validateScriptPath -XmlPath $temporaryRussianPath
|
||||
Move-Item -LiteralPath $temporaryRussianPath -Destination $RussianPath -Force
|
||||
} finally {
|
||||
if (Test-Path -LiteralPath $temporaryRussianPath) {
|
||||
Remove-Item -LiteralPath $temporaryRussianPath -Force
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "[apply-translation-edits.ps1] Updated entries: $($updatedEntries.Count); Added entries: $($addedEntries.Count)."
|
||||
if ($updatedEntries.Count -gt 0) {
|
||||
Write-Host "[apply-translation-edits.ps1] Updated contentuid: $($updatedEntries -join ', ')"
|
||||
}
|
||||
if ($addedEntries.Count -gt 0) {
|
||||
Write-Host "[apply-translation-edits.ps1] Added contentuid: $($addedEntries -join ', ')"
|
||||
}
|
||||
Reference in New Issue
Block a user