Copy-SpoI18nCsv.ps1

<#
.SYNOPSIS
It copies a specific locale from the source file to destination file.

.DESCRIPTION
In order to have matches between source and destination file,
it composes the keys by:
 - splitting destination key
 - replace site's specific GUID
 - looking for the same value in the default locale

Then it uses the keys to get locale value and copies it;

.PARAMETER src
Path of the source file.

.PARAMETER dest
Path of the destination file.

.PARAMETER locale
Locale to copy.
"Eg: it-IT"

.PARAMETER localeKey
Default Locale. Used as a key, it helps to find match.
"Eg: en-US"

.PARAMETER replace
If set, replace destination file;
Otherwise a new file will be created, in the same folder, named:
"<DestinationNameFile>_<DateFormat[yyyMMddHHmm]>.csv"

.PARAMETER delimiter
Choose the delimiter base on the delimiter used in the src/dest files.
Default value is: ","

.EXAMPLE
Copy-SpoI18nCsv -src "<path-to-folder>\<src-filename>.csv" `
                -dest "<path-to-folder>\<dest-filename>.csv" `
                -locale it-IT `
                -localeKey en-US `
                -replace;
#>

function Copy-SpoI18nCsv {
  param (
    [Parameter(Mandatory)]
    [string] $src,

    [Parameter(Mandatory)]
    [string] $dest,

    [Parameter(Mandatory)]
    [ArgumentCompleter({ LocaleArgumentCompleter @args })]
    [string] $locale,

    [Parameter(Mandatory)]
    [ArgumentCompleter({ LocaleArgumentCompleter @args })]
    [string] $localeKey,

    [string] $delimiter = ",",

    [switch] $replace
  )

  $source      = Import-Csv -Path $src  -Encoding utf8BOM -Delimiter $delimiter;
  $destination = Import-Csv -Path $dest -Encoding utf8BOM -Delimiter $delimiter;

  $srcHash  = $source       | Select-Object -Skip 1 | Group-Object Key -AsHashTable -AsString;
  $destHash = $destination  | Select-Object -Skip 1 | Group-Object Key -AsHashTable -AsString;

  # Collection to log "not found keys"
  $notFounds = @();

  foreach ($dKey in $destHash.Keys) {
    $value = "";

    switch -Regex ($dKey) {
      # SITE FIELD / CT
      "^[0]{32}_(FieldTitle|CTName|CTDesc).*$"   
      {
        
        if ( $srcHash.ContainsKey($dKey) ) {
          # This key can be used as is to find value in source file
          $value = $srcHash[$dkey][0]."$locale"
        } else {
          Write-Host "$dkey - not found in source file" -ForegroundColor DarkYellow;
          
          $notFounds += [PSCustomObject]@{
            "Type"      = "Site_Field/CtName/CtDesc"
            "DestKey"   = "$dKey"
            "SourceKey" = "$dkey"
          }
        }
        break;
      }

      # LIST FIELD
      "^[a-z0-9]{32}(?'type'_FieldTitle).*$"       
      {
        $null = $dkey -match "(?'listId'^[a-z0-9]{32})(?'type'_FieldTitle|_CTName|_CTDesc)(?'fieldName'.*)$"   
        $type = $Matches.type; 

        # List title in destination file
        $listTitleKey = $destHash["$($Matches.listId)_ListTitle"].$localeKey;

        # Find source list id
        $sourceListId = Get-ListId -list $source -title $listTitleKey -key $localeKey;

        if ($sourceListId) {
          $sourceKey = "$($sourceListId)$($type)$($Matches.fieldName)";

          $value = $srcHash[$sourceKey][0]."$locale";
        } 

        break;
      }
      
      # LIST CTName / _CTDesc
      "^[a-z0-9]{32}(?'type'_CTName|_CTDesc).*$"  {
        $null = $dkey -match "(?'listId'^[a-z0-9]{32})(?'type'_CTName|_CTDesc)(?'listCtId'.*)$";
        $type = $Matches.type; 
        $listCtId = $Matches.listCtId; 

        # List title in destination file
        $listTitleKey = $destHash["$($Matches.listId)_ListTitle"].$localeKey;

        # Find source list id
        $sourceListId = Get-ListId -list $source -title $listTitleKey -key $localeKey;

        if ($sourceListId) {
          # [ListId][Type][SITE_CT_ID]
          $sourceKey = "$($sourceListId)$($type)$($listCtId.Substring(0, 40))";
  
          $sourceItem = $source | Where-Object {
            $_.key -like "$sourceKey*"
          }
  
          if ($sourceItem -and $sourceItem.Count -eq 1) {
            $value = $sourceItem.$locale;
          } else {
            $notFounds += [PSCustomObject]@{
              "Type"      = "$type"
              "DestKey"   = "$dKey"
              "SourceKey" = "$sourceKey"
            }
          }
        }

        break;
      }
      
      # LIST TITLE
      "^[a-z0-9]{32}_ListTitle$"          
      {
        $listTitleKey = $destHash[$dkey][0].$localeKey;

        $sourceListId = Get-ListId -list $source -title $listTitleKey -key $localeKey;

        if ($sourceListId) {
          $value = $srcHash["$($sourceListId)_ListTitle"][0]."$locale";
        }

        break;
      }

      # LIST DESC
      "^[a-z0-9]{32}_ListDescription$"    
      {
        $null = $dkey -match "(?'listId'^[a-z0-9]{32})_ListDescription$"   

        # List title in destination file
        $listTitleKey = $destHash["$($Matches.listId)_ListTitle"].$localeKey;

        # Find source list id
        $sourceListId = Get-ListId -list $source -title $listTitleKey -key $localeKey;
        
        if ($sourceListId) {
          $sourceKey = "$($sourceListId)_ListDescription";
  
          $value = $srcHash[$sourceKey][0]."$locale";
        }

        break;
      }

      # VIEW TITLE
      "^[a-z0-9]{32}_ViewTitle\{.*\}$"    
      {
        $null = $dkey -match "(?'listId'^[a-z0-9]{32})_ViewTitle.*$" 

        # List title in destination file
        $listTitleKey = $destHash["$($Matches.listId)_ListTitle"].$localeKey;

        # Find source list id
        $sourceListId = Get-ListId -list $source -title $listTitleKey -key $localeKey;

        if ($sourceListId) {
          $sourceKey = "$($sourceListId)_ViewTitle"
  
          $notFounds += [PSCustomObject]@{
            "Type"      = "_ViewTitle"
            "DestKey"   = "$dKey"
            "SourceKey" = "$sourceKey"
          }
        }

        break;
      }
    }

    if ($value) {
      # Copy source value to destination
      $destHash[$dkey][0]."$locale" = $value;
    }
  }

  if ($replace) {
    $destination | Export-Csv -Path $dest -Force -Encoding utf8BOM;
  } else {
    $parentFolder = Split-Path $dest -Parent;
    $fileName     = Split-Path $dest -LeafBase;
    $suffix       = Get-Date -Format "yyyMMddHHmm";

    $destination | Export-Csv -Path "$parentFolder/$($fileName)_$suffix.csv";
  }

  if ($notFounds.Count -gt 0) {
    Write-Host @"
--------------------------------------------------------
I'm sorry, I can't find any matches for these keys.
I almost did it all, be grateful.

If you can do better, feel free to make a pull-request.
--------------------------------------------------------
"@
 `
      -ForegroundColor Magenta;

    return $notFounds
  }
}

function Get-ListId {
  param ( 
    [Parameter(Mandatory)]
    [object[]] $list,

    [Parameter(Mandatory)]
    [string] $title,

    [Parameter(Mandatory)]
    [string] $key
  )

  $listItem = $list | Where-Object { 
    ($_.key -like "*_ListTitle") -and 
    ($_.$key -eq $title)
  };

  if ($listItem) {
    return $listItem.Key.Replace("_ListTitle", "");
  } else {
    return $null;
  }
}