Advertisement
anon_user_007

CK3 fake translation 2

Apr 11th, 2025 (edited)
329
0
Never
4
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # Function to determine the file encoding by BOM
  2. function Get-FileEncoding {
  3.     param (
  4.         [string]$Path
  5.     )
  6.     $fs = [System.IO.File]::OpenRead($Path)
  7.     $bom = New-Object byte[] 4
  8.     $fs.Read($bom, 0, 4) | Out-Null
  9.     $fs.Close()
  10.  
  11.     if ($bom[0] -eq 0xEF -and $bom[1] -eq 0xBB -and $bom[2] -eq 0xBF) {
  12.         return [System.Text.Encoding]::UTF8
  13.     }
  14.     elseif ($bom[0] -eq 0xFF -and $bom[1] -eq 0xFE) {
  15.         return [System.Text.Encoding]::Unicode
  16.     }
  17.     elseif ($bom[0] -eq 0xFE -and $bom[1] -eq 0xFF) {
  18.         return [System.Text.Encoding]::BigEndianUnicode
  19.     }
  20.     else {
  21.         # If BOM is not found, return UTF8 by default
  22.         return [System.Text.Encoding]::UTF8
  23.     }
  24. }
  25.  
  26. # Function for recursive renaming of files and folders (replace $srcLang with $dstLang)
  27. function Rename-LocalizationItems ($path, $pattern, $replacement) {
  28.     # First, rename files in the current directory
  29.     Get-ChildItem -Path $path -File | ForEach-Object {
  30.         if ($_.Name -match $pattern) {
  31.             $newName = $_.Name -replace $pattern, $replacement
  32.             Rename-Item -Path $_.FullName -NewName $newName -Force
  33.             Write-Host "Renamed file: $(Join-Path $_.DirectoryName $newName)"
  34.         }
  35.     }
  36.     # Then, process subdirectories recursively
  37.     Get-ChildItem -Path $path -Directory | ForEach-Object {
  38.         Rename-LocalizationItems -path $_.FullName -pattern $pattern -replacement $replacement
  39.         if ($_.Name -match $pattern) {
  40.             $newName = $_.Name -replace $pattern, $replacement
  41.             $parent = Split-Path $_.FullName -Parent
  42.             Rename-Item -Path $_.FullName -NewName $newName -Force
  43.             Write-Host "Renamed folder: $(Join-Path $parent $newName)"
  44.         }
  45.     }
  46. }
  47.  
  48. # Define source and target localization languages for checking
  49. $srcLang = "english"
  50. $dstLang = "russian"
  51.  
  52. # Paths for folders and files
  53. $modsFolder   = "D:\Games\SteamLibrary\steamapps\workshop\content\1158310"
  54. $launcherDb   = "C:\Users\$env:USERNAME\Documents\Paradox Interactive\Crusader Kings III\launcher-v2.sqlite"
  55. $sqlite3Path  = "D:\mods\Cursader Kings 3\sqlite-tools-win-x64-3490100\sqlite3.exe"
  56. $destRoot     = "C:\Users\$env:USERNAME\Documents\Paradox Interactive\Crusader Kings III\mod"
  57.  
  58. # Check if required files exist
  59. if (!(Test-Path $sqlite3Path)) {
  60.     Write-Host "ERROR: sqlite3.exe not found at: $sqlite3Path" -ForegroundColor Red
  61.     exit
  62. }
  63. if (!(Test-Path $launcherDb)) {
  64.     Write-Host "ERROR: launcher-v2.sqlite not found at: $launcherDb" -ForegroundColor Red
  65.     exit
  66. }
  67.  
  68. # Create a backup of the database
  69. $timestamp  = Get-Date -Format "yyyyMMddHHmmss"
  70. $backupPath = "$launcherDb.$timestamp"
  71. Copy-Item -Path $launcherDb -Destination $backupPath -Force
  72. Write-Host "Database backup created: $backupPath"
  73.  
  74. # Get data from the database via sqlite3 (CSV output)
  75. $query = "SELECT ps.name AS playsetName, psm.position, m.displayName, m.steamId
  76.          FROM playsets ps
  77.          JOIN playsets_mods psm ON ps.id = psm.playsetId
  78.          JOIN mods m ON psm.modId = m.id
  79.          WHERE ps.isActive = 1 AND psm.enabled = 1
  80.          ORDER BY psm.position;"
  81. $csvOutput = & $sqlite3Path $launcherDb ".headers on" ".mode csv" $query
  82. $modData   = $csvOutput | ConvertFrom-Csv
  83.  
  84. Write-Host "Data retrieved from database (only active mods):" -ForegroundColor Cyan
  85. $modData | Format-Table -AutoSize
  86.  
  87. # For each mod, identify the localization folder
  88. foreach ($mod in $modData) {
  89.     $modFolder = Join-Path $modsFolder $mod.steamId
  90.     if (Test-Path $modFolder) {
  91.         # Add mod folder path and its file list to the object
  92.         $mod | Add-Member -MemberType NoteProperty -Name ModFolder -Value $modFolder -Force
  93.         $locRoot = Join-Path $modFolder "localization"
  94.         if (Test-Path $locRoot) {
  95.             $mod | Add-Member -MemberType NoteProperty -Name LocalizationRoot -Value $locRoot -Force
  96.             # Get all files under the localization folder recursively
  97.             $files = Get-ChildItem -Path $locRoot -Recurse -File
  98.             $mod | Add-Member -MemberType NoteProperty -Name LocalizationFiles -Value $files -Force
  99.         }
  100.     }
  101.     else {
  102.         Write-Host "Mod folder not found: $modFolder" -ForegroundColor Yellow
  103.     }
  104. }
  105.  
  106. # Gather missing localization files
  107. # For each mod, under the localization folder, check: for every file whose name contains $srcLang,
  108. # determine the expected file path with $srcLang replaced by $dstLang. If such a file does not exist, mark it as missing.
  109. $modsMissingLocalization = @()
  110.  
  111. foreach ($mod in $modData) {
  112.     if ($mod.LocalizationRoot -and $mod.LocalizationFiles) {
  113.         $locRoot = $mod.LocalizationRoot
  114.         $missingFiles = @()
  115.         # Select files whose names contain "english"
  116.         $englishFiles = $mod.LocalizationFiles | Where-Object { $_.Name -like "*$srcLang*" }
  117.         foreach ($file in $englishFiles) {
  118.             # Get relative path with respect to the localization folder
  119.             $relativePath = $file.FullName.Substring($locRoot.Length + 1)
  120.             # Compute the expected relative path replacing "english" with "russian"
  121.             $expectedRelativePath = $relativePath -replace $srcLang, $dstLang
  122.             $expectedFullPath = Join-Path $locRoot $expectedRelativePath
  123.             if (-not (Test-Path $expectedFullPath)) {
  124.                 $missingFiles += [PSCustomObject]@{
  125.                     RelativePath = $relativePath
  126.                     SourceFile   = $file.FullName
  127.                     ExpectedPath = $expectedFullPath
  128.                 }
  129.             }
  130.         }
  131.         if ($missingFiles.Count -gt 0) {
  132.             $modsMissingLocalization += [PSCustomObject]@{
  133.                 ModDisplayName   = $mod.displayName
  134.                 SteamId          = $mod.steamId
  135.                 LocalizationRoot = $locRoot
  136.                 MissingFiles     = $missingFiles
  137.             }
  138.         }
  139.     }
  140. }
  141.  
  142. # Display the list of mods with missing (or incomplete) localization ($dstLang)
  143. Write-Host "Mods with missing (or incomplete) localization ($dstLang):" -ForegroundColor Cyan
  144. if ($modsMissingLocalization.Count -gt 0) {
  145.     $modsMissingLocalization | Format-Table ModDisplayName, SteamId, @{Name="Missing Files"; Expression={ $_.MissingFiles.Count } } -AutoSize
  146. } else {
  147.     Write-Host "No mods with missing localization for language '$dstLang' found."
  148. }
  149.  
  150. # Process each mod: remove old mod folders and .mod files, then create new ones and copy missing files
  151. foreach ($mod in $modsMissingLocalization) {
  152.     $steamId = $mod.SteamId
  153.     $destModFolder = Join-Path $destRoot $steamId
  154.  
  155.     # If the mod folder already exists, remove it along with its contents
  156.     if (Test-Path $destModFolder) {
  157.         Remove-Item -Path $destModFolder -Recurse -Force
  158.         Write-Host "Existing mod folder removed: $destModFolder"
  159.     }
  160.     # If a .mod file exists, remove it
  161.     $modFilePath = Join-Path $destRoot ("$steamId.mod")
  162.     if (Test-Path $modFilePath) {
  163.         Remove-Item -Path $modFilePath -Force
  164.         Write-Host "Existing mod file removed: $modFilePath"
  165.     }
  166.     # Create a new folder for the mod
  167.     New-Item -ItemType Directory -Path $destModFolder -Force | Out-Null
  168.  
  169.     # For each missing file, copy the original file while preserving the relative structure to the localization folder
  170.     foreach ($fileInfo in $mod.MissingFiles) {
  171.         # Build the destination path: in the new mod folder create a 'localization' folder and append the file's relative path
  172.         $destLocalizationBase = Join-Path $destModFolder "localization"
  173.         $destFilePath = Join-Path $destLocalizationBase $fileInfo.RelativePath
  174.         $destDir = Split-Path $destFilePath -Parent
  175.         if (!(Test-Path $destDir)) {
  176.             New-Item -ItemType Directory -Path $destDir -Force | Out-Null
  177.         }
  178.         Copy-Item -Path $fileInfo.SourceFile -Destination $destFilePath -Force
  179.         Write-Host "File copied: $destFilePath"
  180.  
  181.         # Replace file content: change "l_english:" to "l_russian:" while preserving the original encoding
  182.         $origEncoding = Get-FileEncoding -Path $destFilePath
  183.         $content = Get-Content $destFilePath -Raw
  184.         $updatedContent = $content -replace "l_${srcLang}:", "l_${dstLang}:"
  185.         [System.IO.File]::WriteAllText($destFilePath, $updatedContent, $origEncoding)
  186.         Write-Host "Processed file (content replaced): $destFilePath"
  187.     }
  188.  
  189.     # Rename files and folders in the copied localization folder:
  190.     # Replace "english" with "russian" in file and folder names
  191.     $destLocalizationRoot = Join-Path $destModFolder "localization"
  192.     Rename-LocalizationItems -path $destLocalizationRoot -pattern $srcLang -replacement $dstLang
  193.  
  194.     # Create descriptor.mod file inside the mod folder
  195.     $descriptorContent = @"
  196. version="1.*"
  197. tags={
  198.    "Translation"
  199. }
  200. name="$($mod.ModDisplayName) [fake $dstLang]"
  201. supported_version="1.*"
  202. "@
  203.     $descriptorPath = Join-Path $destModFolder "descriptor.mod"
  204.     [System.IO.File]::WriteAllText($descriptorPath, $descriptorContent, [System.Text.Encoding]::UTF8)
  205.     Write-Host "Created descriptor.mod for mod $($mod.ModDisplayName) (SteamId: $steamId)"
  206.  
  207.     # Create the .mod file in the root of $destRoot
  208.     $destModPath = (Join-Path $destRoot $steamId) -replace "\\", "/"
  209.     $modFileContent = @"
  210. version="1.*"
  211. tags={
  212.    "Translation"
  213. }
  214. name="$($mod.ModDisplayName) [fake $dstLang]"
  215. supported_version="1.*"
  216. path="$destModPath"
  217. "@
  218.     $modFilePath = Join-Path $destRoot ("$steamId.mod")
  219.     [System.IO.File]::WriteAllText($modFilePath, $modFileContent, [System.Text.Encoding]::UTF8)
  220.     Write-Host "Created file $steamId.mod for mod $($mod.ModDisplayName) (SteamId: $steamId)"
  221. }
Advertisement
Comments
  • anon_user_007
    5 days
    # text 1.23 KB | 0 0
    1. Настройка переменных:
    2. Откройте скрипт и при необходимости измените следующие переменные:
    3.  
    4. $srcLang – исходный язык (например, "english").
    5.  
    6. $dstLang – целевой язык (например, "russian").
    7.  
    8. $modsFolder – путь к папке с модами (например, D:\Games\SteamLibrary\steamapps\workshop\content\1158310).
    9.  
    10. $launcherDb – путь к файлу базы данных. Этот путь стандартный (с использованием $env:USERNAME), менять его не нужно.
    11.  
    12. $sqlite3Path – путь к утилите sqlite3 (например, D:\mods\Cursader Kings 3\sqlite-tools-win-x64-3490100\sqlite3.exe).
    13.  
    14. $destRoot – папка назначения для созданных модов (например, C:\Users\$env:USERNAME\Documents\Paradox Interactive\Crusader Kings III\mod).
    15.  
    16. Запуск через PowerShell ISE:
    17.  
    18. Откройте PowerShell ISE.
    19.  
    20. Загрузите скрипт (например, CK3_Translate.ps1).
    21.  
    22. Нажмите кнопку Run Script или клавишу F5 для выполнения скрипта.
    • anon_user_007
      5 days
      # text 0.26 KB | 0 0
      1. После запуска лаунчера игры, необходимо будет добавить в свой плейсет созданные моды и выставить их в поряде заргузки после оригинальных модов.
  • anon_user_007
    5 days
    # text 0.92 KB | 0 0
    1. Variable Configuration:
    2. Open the script file and, if necessary, adjust the following variables to match your environment:
    3.  
    4. $srcLang – Source language (e.g., "english").
    5.  
    6. $dstLang – Target language (e.g., "russian").
    7.  
    8. $modsFolder – Path to the mods folder (e.g., D:\Games\SteamLibrary\steamapps\workshop\content\1158310).
    9.  
    10. $launcherDb – Path to the launcher-v2.sqlite file. This is set up by default using $env:USERNAME (do not change it).
    11.  
    12. $sqlite3Path – Path to the sqlite3 executable (e.g., D:\mods\Cursader Kings 3\sqlite-tools-win-x64-3490100\sqlite3.exe).
    13.  
    14. $destRoot – Destination folder for the created mods (e.g., C:\Users\$env:USERNAME\Documents\Paradox Interactive\Crusader Kings III\mod).
    15.  
    16. Running the Script via PowerShell ISE:
    17.  
    18. Open PowerShell ISE.
    19.  
    20. Load the script file (e.g., CK3_Translate.ps1).
    21.  
    22. Click the Run Script button or press F5 to execute the script.
    • anon_user_007
      5 days
      # text 0.14 KB | 0 0
      1. After launching the game launcher, you will need to add the created mods to your playset and set them in the loading order after the original mods.
Add Comment
Please, Sign In to add comment
Advertisement