Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Function to determine the file encoding by BOM
- function Get-FileEncoding {
- param (
- [string]$Path
- )
- $fs = [System.IO.File]::OpenRead($Path)
- $bom = New-Object byte[] 4
- $fs.Read($bom, 0, 4) | Out-Null
- $fs.Close()
- if ($bom[0] -eq 0xEF -and $bom[1] -eq 0xBB -and $bom[2] -eq 0xBF) {
- return [System.Text.Encoding]::UTF8
- }
- elseif ($bom[0] -eq 0xFF -and $bom[1] -eq 0xFE) {
- return [System.Text.Encoding]::Unicode
- }
- elseif ($bom[0] -eq 0xFE -and $bom[1] -eq 0xFF) {
- return [System.Text.Encoding]::BigEndianUnicode
- }
- else {
- # If BOM is not found, return UTF8 by default
- return [System.Text.Encoding]::UTF8
- }
- }
- # Function for recursive renaming of files and folders (replace $srcLang with $dstLang)
- function Rename-LocalizationItems ($path, $pattern, $replacement) {
- # First, rename files in the current directory
- Get-ChildItem -Path $path -File | ForEach-Object {
- if ($_.Name -match $pattern) {
- $newName = $_.Name -replace $pattern, $replacement
- Rename-Item -Path $_.FullName -NewName $newName -Force
- Write-Host "Renamed file: $(Join-Path $_.DirectoryName $newName)"
- }
- }
- # Then, process subdirectories recursively
- Get-ChildItem -Path $path -Directory | ForEach-Object {
- Rename-LocalizationItems -path $_.FullName -pattern $pattern -replacement $replacement
- if ($_.Name -match $pattern) {
- $newName = $_.Name -replace $pattern, $replacement
- $parent = Split-Path $_.FullName -Parent
- Rename-Item -Path $_.FullName -NewName $newName -Force
- Write-Host "Renamed folder: $(Join-Path $parent $newName)"
- }
- }
- }
- # Define source and target localization languages for checking
- $srcLang = "english"
- $dstLang = "russian"
- # Paths for folders and files
- $modsFolder = "D:\Games\SteamLibrary\steamapps\workshop\content\1158310"
- $launcherDb = "C:\Users\$env:USERNAME\Documents\Paradox Interactive\Crusader Kings III\launcher-v2.sqlite"
- $sqlite3Path = "D:\mods\Cursader Kings 3\sqlite-tools-win-x64-3490100\sqlite3.exe"
- $destRoot = "C:\Users\$env:USERNAME\Documents\Paradox Interactive\Crusader Kings III\mod"
- # Check if required files exist
- if (!(Test-Path $sqlite3Path)) {
- Write-Host "ERROR: sqlite3.exe not found at: $sqlite3Path" -ForegroundColor Red
- exit
- }
- if (!(Test-Path $launcherDb)) {
- Write-Host "ERROR: launcher-v2.sqlite not found at: $launcherDb" -ForegroundColor Red
- exit
- }
- # Create a backup of the database
- $timestamp = Get-Date -Format "yyyyMMddHHmmss"
- $backupPath = "$launcherDb.$timestamp"
- Copy-Item -Path $launcherDb -Destination $backupPath -Force
- Write-Host "Database backup created: $backupPath"
- # Get data from the database via sqlite3 (CSV output)
- $query = "SELECT ps.name AS playsetName, psm.position, m.displayName, m.steamId
- FROM playsets ps
- JOIN playsets_mods psm ON ps.id = psm.playsetId
- JOIN mods m ON psm.modId = m.id
- WHERE ps.isActive = 1 AND psm.enabled = 1
- ORDER BY psm.position;"
- $csvOutput = & $sqlite3Path $launcherDb ".headers on" ".mode csv" $query
- $modData = $csvOutput | ConvertFrom-Csv
- Write-Host "Data retrieved from database (only active mods):" -ForegroundColor Cyan
- $modData | Format-Table -AutoSize
- # For each mod, identify the localization folder
- foreach ($mod in $modData) {
- $modFolder = Join-Path $modsFolder $mod.steamId
- if (Test-Path $modFolder) {
- # Add mod folder path and its file list to the object
- $mod | Add-Member -MemberType NoteProperty -Name ModFolder -Value $modFolder -Force
- $locRoot = Join-Path $modFolder "localization"
- if (Test-Path $locRoot) {
- $mod | Add-Member -MemberType NoteProperty -Name LocalizationRoot -Value $locRoot -Force
- # Get all files under the localization folder recursively
- $files = Get-ChildItem -Path $locRoot -Recurse -File
- $mod | Add-Member -MemberType NoteProperty -Name LocalizationFiles -Value $files -Force
- }
- }
- else {
- Write-Host "Mod folder not found: $modFolder" -ForegroundColor Yellow
- }
- }
- # Gather missing localization files
- # For each mod, under the localization folder, check: for every file whose name contains $srcLang,
- # determine the expected file path with $srcLang replaced by $dstLang. If such a file does not exist, mark it as missing.
- $modsMissingLocalization = @()
- foreach ($mod in $modData) {
- if ($mod.LocalizationRoot -and $mod.LocalizationFiles) {
- $locRoot = $mod.LocalizationRoot
- $missingFiles = @()
- # Select files whose names contain "english"
- $englishFiles = $mod.LocalizationFiles | Where-Object { $_.Name -like "*$srcLang*" }
- foreach ($file in $englishFiles) {
- # Get relative path with respect to the localization folder
- $relativePath = $file.FullName.Substring($locRoot.Length + 1)
- # Compute the expected relative path replacing "english" with "russian"
- $expectedRelativePath = $relativePath -replace $srcLang, $dstLang
- $expectedFullPath = Join-Path $locRoot $expectedRelativePath
- if (-not (Test-Path $expectedFullPath)) {
- $missingFiles += [PSCustomObject]@{
- RelativePath = $relativePath
- SourceFile = $file.FullName
- ExpectedPath = $expectedFullPath
- }
- }
- }
- if ($missingFiles.Count -gt 0) {
- $modsMissingLocalization += [PSCustomObject]@{
- ModDisplayName = $mod.displayName
- SteamId = $mod.steamId
- LocalizationRoot = $locRoot
- MissingFiles = $missingFiles
- }
- }
- }
- }
- # Display the list of mods with missing (or incomplete) localization ($dstLang)
- Write-Host "Mods with missing (or incomplete) localization ($dstLang):" -ForegroundColor Cyan
- if ($modsMissingLocalization.Count -gt 0) {
- $modsMissingLocalization | Format-Table ModDisplayName, SteamId, @{Name="Missing Files"; Expression={ $_.MissingFiles.Count } } -AutoSize
- } else {
- Write-Host "No mods with missing localization for language '$dstLang' found."
- }
- # Process each mod: remove old mod folders and .mod files, then create new ones and copy missing files
- foreach ($mod in $modsMissingLocalization) {
- $steamId = $mod.SteamId
- $destModFolder = Join-Path $destRoot $steamId
- # If the mod folder already exists, remove it along with its contents
- if (Test-Path $destModFolder) {
- Remove-Item -Path $destModFolder -Recurse -Force
- Write-Host "Existing mod folder removed: $destModFolder"
- }
- # If a .mod file exists, remove it
- $modFilePath = Join-Path $destRoot ("$steamId.mod")
- if (Test-Path $modFilePath) {
- Remove-Item -Path $modFilePath -Force
- Write-Host "Existing mod file removed: $modFilePath"
- }
- # Create a new folder for the mod
- New-Item -ItemType Directory -Path $destModFolder -Force | Out-Null
- # For each missing file, copy the original file while preserving the relative structure to the localization folder
- foreach ($fileInfo in $mod.MissingFiles) {
- # Build the destination path: in the new mod folder create a 'localization' folder and append the file's relative path
- $destLocalizationBase = Join-Path $destModFolder "localization"
- $destFilePath = Join-Path $destLocalizationBase $fileInfo.RelativePath
- $destDir = Split-Path $destFilePath -Parent
- if (!(Test-Path $destDir)) {
- New-Item -ItemType Directory -Path $destDir -Force | Out-Null
- }
- Copy-Item -Path $fileInfo.SourceFile -Destination $destFilePath -Force
- Write-Host "File copied: $destFilePath"
- # Replace file content: change "l_english:" to "l_russian:" while preserving the original encoding
- $origEncoding = Get-FileEncoding -Path $destFilePath
- $content = Get-Content $destFilePath -Raw
- $updatedContent = $content -replace "l_${srcLang}:", "l_${dstLang}:"
- [System.IO.File]::WriteAllText($destFilePath, $updatedContent, $origEncoding)
- Write-Host "Processed file (content replaced): $destFilePath"
- }
- # Rename files and folders in the copied localization folder:
- # Replace "english" with "russian" in file and folder names
- $destLocalizationRoot = Join-Path $destModFolder "localization"
- Rename-LocalizationItems -path $destLocalizationRoot -pattern $srcLang -replacement $dstLang
- # Create descriptor.mod file inside the mod folder
- $descriptorContent = @"
- version="1.*"
- tags={
- "Translation"
- }
- name="$($mod.ModDisplayName) [fake $dstLang]"
- supported_version="1.*"
- "@
- $descriptorPath = Join-Path $destModFolder "descriptor.mod"
- [System.IO.File]::WriteAllText($descriptorPath, $descriptorContent, [System.Text.Encoding]::UTF8)
- Write-Host "Created descriptor.mod for mod $($mod.ModDisplayName) (SteamId: $steamId)"
- # Create the .mod file in the root of $destRoot
- $destModPath = (Join-Path $destRoot $steamId) -replace "\\", "/"
- $modFileContent = @"
- version="1.*"
- tags={
- "Translation"
- }
- name="$($mod.ModDisplayName) [fake $dstLang]"
- supported_version="1.*"
- path="$destModPath"
- "@
- $modFilePath = Join-Path $destRoot ("$steamId.mod")
- [System.IO.File]::WriteAllText($modFilePath, $modFileContent, [System.Text.Encoding]::UTF8)
- Write-Host "Created file $steamId.mod for mod $($mod.ModDisplayName) (SteamId: $steamId)"
- }
Advertisement
Comments
-
- Настройка переменных:
- Откройте скрипт и при необходимости измените следующие переменные:
- $srcLang – исходный язык (например, "english").
- $dstLang – целевой язык (например, "russian").
- $modsFolder – путь к папке с модами (например, D:\Games\SteamLibrary\steamapps\workshop\content\1158310).
- $launcherDb – путь к файлу базы данных. Этот путь стандартный (с использованием $env:USERNAME), менять его не нужно.
- $sqlite3Path – путь к утилите sqlite3 (например, D:\mods\Cursader Kings 3\sqlite-tools-win-x64-3490100\sqlite3.exe).
- $destRoot – папка назначения для созданных модов (например, C:\Users\$env:USERNAME\Documents\Paradox Interactive\Crusader Kings III\mod).
- Запуск через PowerShell ISE:
- Откройте PowerShell ISE.
- Загрузите скрипт (например, CK3_Translate.ps1).
- Нажмите кнопку Run Script или клавишу F5 для выполнения скрипта.
-
- После запуска лаунчера игры, необходимо будет добавить в свой плейсет созданные моды и выставить их в поряде заргузки после оригинальных модов.
-
- Variable Configuration:
- Open the script file and, if necessary, adjust the following variables to match your environment:
- $srcLang – Source language (e.g., "english").
- $dstLang – Target language (e.g., "russian").
- $modsFolder – Path to the mods folder (e.g., D:\Games\SteamLibrary\steamapps\workshop\content\1158310).
- $launcherDb – Path to the launcher-v2.sqlite file. This is set up by default using $env:USERNAME (do not change it).
- $sqlite3Path – Path to the sqlite3 executable (e.g., D:\mods\Cursader Kings 3\sqlite-tools-win-x64-3490100\sqlite3.exe).
- $destRoot – Destination folder for the created mods (e.g., C:\Users\$env:USERNAME\Documents\Paradox Interactive\Crusader Kings III\mod).
- Running the Script via PowerShell ISE:
- Open PowerShell ISE.
- Load the script file (e.g., CK3_Translate.ps1).
- Click the Run Script button or press F5 to execute the script.
-
- 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