diff --git a/.powershell/Compare-YamlTranslations.ps1 b/.powershell/Compare-YamlTranslations.ps1 new file mode 100644 index 0000000..2f63301 --- /dev/null +++ b/.powershell/Compare-YamlTranslations.ps1 @@ -0,0 +1,244 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Compare two Hugo i18n YAML files and identify missing translation keys. + +.DESCRIPTION + This script compares two YAML translation files and identifies keys that exist in the source + but are missing in the target. It can optionally add the missing keys to the target file. + +.PARAMETER SourceFile + Path to the source YAML file (contains the keys you want to port) + +.PARAMETER TargetFile + Path to the target YAML file (file to be updated) + +.PARAMETER AddMissing + Switch to automatically add missing keys to the target file + +.PARAMETER WhatIf + Show what would be added without actually modifying the target file + +.EXAMPLE + .\Compare-YamlTranslations.ps1 -SourceFile "module\i18n\en.yaml" -TargetFile "site\i18n\en.yaml" + +.EXAMPLE + .\Compare-YamlTranslations.ps1 -SourceFile "module\i18n\en.yaml" -TargetFile "site\i18n\en.yaml" -AddMissing + +.EXAMPLE + .\Compare-YamlTranslations.ps1 -SourceFile "module\i18n\en.yaml" -TargetFile "site\i18n\en.yaml" -AddMissing -WhatIf +#> + +[CmdletBinding()] +param( + [Parameter(Mandatory = $true)] + [string]$SourceFile, + + [Parameter(Mandatory = $true)] + [string]$TargetFile, + + [Parameter(Mandatory = $false)] + [switch]$AddMissing, + + [Parameter(Mandatory = $false)] + [switch]$WhatIf +) + +# Function to parse YAML translation file and extract key-value pairs +function Parse-YamlTranslations { + param([string]$FilePath) + + if (-not (Test-Path $FilePath)) { + throw "File not found: $FilePath" + } + + $content = Get-Content $FilePath -Raw + $translations = @{} + $currentEntry = @{} + + # Split content into lines and process + $lines = $content -split "`n" + + foreach ($line in $lines) { + $line = $line.Trim() + + # Skip empty lines and comments + if ([string]::IsNullOrWhiteSpace($line) -or $line.StartsWith('#')) { + continue + } + + # Check for new entry (starts with - id:) + if ($line -match '^-\s+id:\s*(.+)$') { + # Save previous entry if it exists + if ($currentEntry.id -and $currentEntry.translation) { + $translations[$currentEntry.id] = $currentEntry.translation + } + + # Start new entry + $currentEntry = @{ + id = $matches[1].Trim('"').Trim("'") + translation = $null + } + } + # Check for translation line + elseif ($line -match '^translation:\s*(.+)$') { + if ($currentEntry.id) { + $translationValue = $matches[1].Trim() + # Remove surrounding quotes if present + if (($translationValue.StartsWith('"') -and $translationValue.EndsWith('"')) -or + ($translationValue.StartsWith("'") -and $translationValue.EndsWith("'"))) { + $translationValue = $translationValue.Substring(1, $translationValue.Length - 2) + } + $currentEntry.translation = $translationValue + } + } + } + + # Don't forget the last entry + if ($currentEntry.id -and $currentEntry.translation) { + $translations[$currentEntry.id] = $currentEntry.translation + } + + return $translations +} + +# Function to format YAML entry +function Format-YamlEntry { + param( + [string]$Id, + [string]$Translation + ) + + # Escape translation value if it contains special characters + $escapedTranslation = $Translation + if ($Translation -match '[:"''\\]' -or $Translation.Contains('{{') -or $Translation.Contains('}}')) { + $escapedTranslation = '"' + $Translation.Replace('\', '\\').Replace('"', '\"') + '"' + } + else { + $escapedTranslation = '"' + $Translation + '"' + } + + return @" +- id: $Id + translation: $escapedTranslation + +"@ +} + +try { + Write-Host "đ Comparing YAML translation files..." -ForegroundColor Cyan + Write-Host "Source: $SourceFile" -ForegroundColor Gray + Write-Host "Target: $TargetFile" -ForegroundColor Gray + Write-Host "" + + # Parse both files + Write-Host "đ Parsing source file..." -ForegroundColor Yellow + $sourceTranslations = Parse-YamlTranslations -FilePath $SourceFile + Write-Host " Found $($sourceTranslations.Count) translation keys" -ForegroundColor Green + + Write-Host "đ Parsing target file..." -ForegroundColor Yellow + $targetTranslations = Parse-YamlTranslations -FilePath $TargetFile + Write-Host " Found $($targetTranslations.Count) translation keys" -ForegroundColor Green + Write-Host "" + + # Find missing keys + $missingKeys = @() + $duplicateKeys = @() + $differentValues = @() + + foreach ($sourceKey in $sourceTranslations.Keys) { + if (-not $targetTranslations.ContainsKey($sourceKey)) { + $missingKeys += $sourceKey + } + elseif ($targetTranslations[$sourceKey] -ne $sourceTranslations[$sourceKey]) { + $differentValues += $sourceKey + } + } + + # Find keys that exist in target but not in source (potential duplicates or extras) + foreach ($targetKey in $targetTranslations.Keys) { + if (-not $sourceTranslations.ContainsKey($targetKey)) { + $duplicateKeys += $targetKey + } + } + + # Display results + Write-Host "đ Comparison Results:" -ForegroundColor Cyan + Write-Host "=====================" -ForegroundColor Cyan + + if ($missingKeys.Count -gt 0) { + Write-Host "â Missing keys in target ($($missingKeys.Count)):" -ForegroundColor Red + foreach ($key in $missingKeys | Sort-Object) { + Write-Host " - $key" -ForegroundColor Red + Write-Host " Value: $($sourceTranslations[$key])" -ForegroundColor Gray + } + Write-Host "" + } + else { + Write-Host "â No missing keys found!" -ForegroundColor Green + Write-Host "" + } + + if ($differentValues.Count -gt 0) { + Write-Host "â ī¸ Keys with different values ($($differentValues.Count)):" -ForegroundColor Yellow + foreach ($key in $differentValues | Sort-Object) { + Write-Host " - $key" -ForegroundColor Yellow + Write-Host " Source: $($sourceTranslations[$key])" -ForegroundColor Gray + Write-Host " Target: $($targetTranslations[$key])" -ForegroundColor Gray + } + Write-Host "" + } + + if ($duplicateKeys.Count -gt 0) { + Write-Host "âšī¸ Keys only in target ($($duplicateKeys.Count)):" -ForegroundColor Blue + foreach ($key in $duplicateKeys | Sort-Object) { + Write-Host " - $key" -ForegroundColor Blue + } + Write-Host "" + } + + # Add missing keys if requested + if ($AddMissing -and $missingKeys.Count -gt 0) { + if ($WhatIf) { + Write-Host "đ What would be added to target file:" -ForegroundColor Cyan + foreach ($key in $missingKeys | Sort-Object) { + $entry = Format-YamlEntry -Id $key -Translation $sourceTranslations[$key] + Write-Host $entry -ForegroundColor Green + } + } + else { + Write-Host "â Adding missing keys to target file..." -ForegroundColor Green + + # Read current target content + $targetContent = Get-Content $TargetFile -Raw + + # Add missing entries at the end + $newEntries = "" + foreach ($key in $missingKeys | Sort-Object) { + $newEntries += Format-YamlEntry -Id $key -Translation $sourceTranslations[$key] + } + + # Ensure there's a newline before adding new content + if (-not $targetContent.EndsWith("`n")) { + $targetContent += "`n" + } + + # Add the new entries + $updatedContent = $targetContent + $newEntries + + # Write back to file + Set-Content -Path $TargetFile -Value $updatedContent -NoNewline + + Write-Host "â Successfully added $($missingKeys.Count) missing keys to $TargetFile" -ForegroundColor Green + } + } + elseif ($missingKeys.Count -gt 0) { + Write-Host "đĄ To add missing keys automatically, use the -AddMissing parameter" -ForegroundColor Cyan + Write-Host "đĄ To see what would be added without making changes, use -AddMissing -WhatIf" -ForegroundColor Cyan + } + +} +catch { + Write-Error "An error occurred: $($_.Exception.Message)" + exit 1 +} diff --git a/.powershell/README.md b/.powershell/README.md new file mode 100644 index 0000000..ab0a8fb --- /dev/null +++ b/.powershell/README.md @@ -0,0 +1,166 @@ +# PowerShell Translation Tools + +This folder contains PowerShell scripts to help manage Hugo i18n translation files. + +## Scripts + +### Compare-YamlTranslations.ps1 + +A comprehensive script that compares two YAML translation files and identifies: + +- Missing keys in the target file +- Keys with different values between files +- Keys that exist only in the target file + +**Usage:** + +```powershell +# Basic comparison +.\Compare-YamlTranslations.ps1 -SourceFile "path\to\source.yaml" -TargetFile "path\to\target.yaml" + +# Add missing keys to target file +.\Compare-YamlTranslations.ps1 -SourceFile "path\to\source.yaml" -TargetFile "path\to\target.yaml" -AddMissing + +# Preview what would be added (dry run) +.\Compare-YamlTranslations.ps1 -SourceFile "path\to\source.yaml" -TargetFile "path\to\target.yaml" -AddMissing -WhatIf +``` + +### Sync-Translations.ps1 + +A convenient wrapper script that can either compare the default module and site en.yaml files or work with custom source and target files. + +**Usage:** + +```powershell +# Compare module to site translations (default) +.\Sync-Translations.ps1 + +# Add missing keys from module to site +.\Sync-Translations.ps1 -AddMissing + +# Sync from site to module instead +.\Sync-Translations.ps1 -Direction SiteToModule -AddMissing + +# Preview changes without making them +.\Sync-Translations.ps1 -AddMissing -WhatIf + +# Compare custom files using relative paths +.\Sync-Translations.ps1 -SourceFile "custom\source.yaml" -TargetFile "custom\target.yaml" + +# Compare custom files using absolute paths +.\Sync-Translations.ps1 -SourceFile "C:\path\to\master.yaml" -TargetFile "C:\path\to\local.yaml" -AddMissing + +# Preview what would be added from custom source to target +.\Sync-Translations.ps1 -SourceFile "master.yaml" -TargetFile "local.yaml" -AddMissing -WhatIf +``` + +## Quick Start + +1. **Compare default translations (module to site):** + + ```powershell + cd .powershell + .\Sync-Translations.ps1 + ``` + +2. **Add missing keys from module to site:** + + ```powershell + .\Sync-Translations.ps1 -AddMissing + ``` + +3. **Preview what would be added:** + + ```powershell + .\Sync-Translations.ps1 -AddMissing -WhatIf + ``` + +4. **Compare custom files:** + + ```powershell + .\Sync-Translations.ps1 -SourceFile "path\to\source.yaml" -TargetFile "path\to\target.yaml" + ``` + +## Features + +- **Flexible File Selection**: Use default module/site files or specify custom source and target files +- **Safe Operations**: Use `-WhatIf` to preview changes before applying them +- **Bidirectional Sync**: Sync from module to site, site to module, or between any two YAML files +- **Path Flexibility**: Supports both relative and absolute file paths +- **Detailed Reporting**: Shows missing keys, different values, and extra keys +- **Proper YAML Formatting**: Maintains correct YAML structure and escaping +- **Error Handling**: Validates file existence and provides clear error messages + +## File Structure + +The scripts expect the following structure: + +```text +project-root/ +âââ .powershell/ +â âââ Compare-YamlTranslations.ps1 +â âââ Sync-Translations.ps1 +â âââ README.md +âââ module/ +â âââ i18n/ +â âââ en.yaml +âââ site/ + âââ i18n/ + âââ en.yaml +``` + +## Examples + +### Typical Workflow + +1. **Check what's missing:** + + ```powershell + .\Sync-Translations.ps1 + ``` + +2. **Preview the additions:** + + ```powershell + .\Sync-Translations.ps1 -AddMissing -WhatIf + ``` + +3. **Apply the changes:** + + ```powershell + .\Sync-Translations.ps1 -AddMissing + ``` + +### Advanced Usage + +Compare any two YAML files: + +```powershell +.\Compare-YamlTranslations.ps1 -SourceFile "C:\path\to\master.yaml" -TargetFile "C:\path\to\local.yaml" -AddMissing +``` + +Or use the convenient wrapper: + +```powershell +.\Sync-Translations.ps1 -SourceFile "master.yaml" -TargetFile "local.yaml" -AddMissing +``` + +**Working with different directories:** + +```powershell +# Files in subdirectories (relative to project root) +.\Sync-Translations.ps1 -SourceFile "translations\master\en.yaml" -TargetFile "site\i18n\en.yaml" + +# Absolute paths +.\Sync-Translations.ps1 -SourceFile "C:\translations\master.yaml" -TargetFile "C:\local\site.yaml" + +# Mix of relative and absolute +.\Sync-Translations.ps1 -SourceFile "C:\shared\master.yaml" -TargetFile "local.yaml" +``` + +## Notes + +- The scripts preserve the original formatting and structure of YAML files +- New entries are added at the end of the target file +- Translation values are properly escaped for special characters +- Comments and empty lines are preserved in the target file diff --git a/.powershell/Sync-Translations.ps1 b/.powershell/Sync-Translations.ps1 new file mode 100644 index 0000000..db3002c --- /dev/null +++ b/.powershell/Sync-Translations.ps1 @@ -0,0 +1,144 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Quick comparison script for Hugo i18n files in this project. + +.DESCRIPTION + This script provides an easy way to compare YAML translation files and sync missing translations between them. + You can either use the default module/site files or specify custom source and target files. + +.PARAMETER SourceFile + Path to the source YAML file (contains the keys you want to port). If not specified, uses Direction parameter. + +.PARAMETER TargetFile + Path to the target YAML file (file to be updated). If not specified, uses Direction parameter. + +.PARAMETER Direction + Direction of sync when using default files: "ModuleToSite" (default) or "SiteToModule". Ignored if SourceFile and TargetFile are specified. + +.PARAMETER AddMissing + Switch to automatically add missing keys to the target file + +.PARAMETER WhatIf + Show what would be added without actually modifying the target file + +.EXAMPLE + .\Sync-Translations.ps1 + Compare module to site (default) + +.EXAMPLE + .\Sync-Translations.ps1 -AddMissing + Add missing keys from module to site + +.EXAMPLE + .\Sync-Translations.ps1 -Direction SiteToModule -AddMissing -WhatIf + Show what would be added from site to module + +.EXAMPLE + .\Sync-Translations.ps1 -SourceFile "custom\source.yaml" -TargetFile "custom\target.yaml" -AddMissing + Compare custom files and add missing keys + +.EXAMPLE + .\Sync-Translations.ps1 -SourceFile "C:\full\path\to\master.yaml" -TargetFile ".\local.yaml" -WhatIf + Preview what would be added from a custom source to local target +#> + +[CmdletBinding(DefaultParameterSetName = "DefaultFiles")] +param( + [Parameter(Mandatory = $false, ParameterSetName = "CustomFiles")] + [string]$SourceFile, + + [Parameter(Mandatory = $false, ParameterSetName = "CustomFiles")] + [string]$TargetFile, + + [Parameter(Mandatory = $false, ParameterSetName = "DefaultFiles")] + [ValidateSet("ModuleToSite", "SiteToModule")] + [string]$Direction = "ModuleToSite", + + [Parameter(Mandatory = $false)] + [switch]$AddMissing, + + [Parameter(Mandatory = $false)] + [switch]$WhatIf +) + +# Get the script directory (should be .powershell folder) +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$ProjectRoot = Split-Path -Parent $ScriptDir + +# Determine source and target files +if ($PSCmdlet.ParameterSetName -eq "CustomFiles") { + # Custom files specified + if ([string]::IsNullOrWhiteSpace($SourceFile) -or [string]::IsNullOrWhiteSpace($TargetFile)) { + Write-Error "When using custom files, both SourceFile and TargetFile must be specified." + exit 1 + } + + # Convert relative paths to absolute paths + if (-not [System.IO.Path]::IsPathRooted($SourceFile)) { + $SourceFile = Join-Path $ProjectRoot $SourceFile + } + if (-not [System.IO.Path]::IsPathRooted($TargetFile)) { + $TargetFile = Join-Path $ProjectRoot $TargetFile + } + + Write-Host "đ Syncing translations from CUSTOM SOURCE â CUSTOM TARGET" -ForegroundColor Cyan + Write-Host " Source: $SourceFile" -ForegroundColor Gray + Write-Host " Target: $TargetFile" -ForegroundColor Gray +} else { + # Default files based on Direction + $ModuleFile = Join-Path $ProjectRoot "module\i18n\en.yaml" + $SiteFile = Join-Path $ProjectRoot "site\i18n\en.yaml" + + # Verify default files exist + if (-not (Test-Path $ModuleFile)) { + Write-Error "Module file not found: $ModuleFile" + exit 1 + } + + if (-not (Test-Path $SiteFile)) { + Write-Error "Site file not found: $SiteFile" + exit 1 + } + + # Set source and target based on direction + if ($Direction -eq "ModuleToSite") { + $SourceFile = $ModuleFile + $TargetFile = $SiteFile + Write-Host "đ Syncing translations from MODULE â SITE" -ForegroundColor Cyan + } else { + $SourceFile = $SiteFile + $TargetFile = $ModuleFile + Write-Host "đ Syncing translations from SITE â MODULE" -ForegroundColor Cyan + } +} + +# Verify files exist +if (-not (Test-Path $SourceFile)) { + Write-Error "Source file not found: $SourceFile" + exit 1 +} + +if (-not (Test-Path $TargetFile)) { + Write-Error "Target file not found: $TargetFile" + exit 1 +} + +Write-Host "" + +# Call the main comparison script +$CompareScript = Join-Path $ScriptDir "Compare-YamlTranslations.ps1" +$params = @{ + SourceFile = $SourceFile + TargetFile = $TargetFile +} + +if ($AddMissing) { + $params.AddMissing = $true +} + +if ($WhatIf) { + $params.WhatIf = $true +} + +& $CompareScript @params diff --git a/module/hugo.yaml b/module/hugo.yaml index b2b9266..35893e5 100644 --- a/module/hugo.yaml +++ b/module/hugo.yaml @@ -33,6 +33,10 @@ params: AzureSitesConfig: "#{Guides_AzureSitesConfig}#" GitVersion_SemVer: "v#{GitVersion.SemVer}#" GoogleTagManagerID: "GTM-MOOO" # Replace with your actual GTM ID + features: + guideDetails: true + + sitemap: filename: sitemap.xml changefreq: daily diff --git a/module/layouts/_partials/components/guide-nav-menu.html b/module/layouts/_partials/components/guide-nav-menu.html index 53c070e..ad655b7 100644 --- a/module/layouts/_partials/components/guide-nav-menu.html +++ b/module/layouts/_partials/components/guide-nav-menu.html @@ -55,14 +55,15 @@ {{ i18n "nav_read_guide" | default "Read Guide" }} - + {{ if .Site.Params.features.guideDetails }} + {{/* Guide Details Link */}} {{/* Details Link */}}