WSL/tools/generateLocalizationHeader.ps1

179 lines
4.3 KiB
PowerShell

# Script to generate Localization.h from resources.resw
param( [Parameter(Mandatory=$true)] $OutFile)
$ErrorActionPreference = "Stop"
$resourceFolder = "$($PSScriptRoot)\..\localization\strings"
$defaultLanguage = "en-US"
$languages = @($defaultLanguage) + (Get-ChildItem -Path $resourceFolder | % { $_.name} | Where { $_ -Ne $defaultLanguage })
$content = @"
// Copyright (C) Microsoft Corporation. All rights reserved.
//
// This file is generated by generateLocalizationHeader.ps1, do not edit it manually.
#pragma once
#include <vector>
#include <stringshared.h>
namespace wsl::shared {
class Localization
{
public:
#ifdef WIN32
#define ARGS std::make_wformat_args
using TChar = wchar_t;
#else
#define ARGS std::make_format_args
using TChar = char;
#define TEXT(X) X
#endif
using TString = std::basic_string<TChar>;
enum class Options
{
Default = 0,
DontImpersonate = 1
};
"@
function getArgumentsFromInserts
{
param(
[string]$Name,
[string]$Content)
[System.Collections.ArrayList]$Arguments = @()
$Content = $Content -Replace '{{', ''
return ([regex]::Matches($Content, "{" )).count
}
function generateEntry
{
param(
[string]$Name,
[hashtable]$AllStrings)
$content = $AllStrings[$defaultLanguage][$Name]
$map = "static const std::vector<std::pair<TString, const TChar*>> strings {`r`n {TEXT(`"$defaultLanguage`"), TEXT(R`"($content)`")}"
foreach ($language in $AllStrings.Keys)
{
if ($language -eq $defaultLanguage)
{
continue
}
$strings = $AllStrings[$language]
if (!$strings.ContainsKey($Name))
{
Write-Host "Warning: string $Name not found in language: $language"
continue
}
$map += ",`r`n {TEXT(`"$language`"), TEXT(R`"($($strings[$Name]))`")}"
}
$map += "}"
$ArgumentsCount = getArgumentsFromInserts -Name $Name -Content $Content
if ($ArgumentsCount -eq 0)
{
return '
/* Message: {1}*/
static inline TString {0}(Options options = Options::Default)
{{
{2};
return LookupString(strings, options);
}}
' -f $Name, $Content.split("`n")[0], $map
}
else
{
$ArgumentTypes = [string]::Join(', ', ((1..$ArgumentsCount) |% {"typename T$_"}))
$ArgumentHeaders = [string]::Join(', ', ((1..$ArgumentsCount) |% {"const T$_& arg$_"}))
$Arguments = [string]::Join(', ', ((1..$ArgumentsCount) |% {"arg$_"}))
return '
/* Message: {4}*/
template <{1}>
static TString {0}({2}, Options options = Options::Default)
{{
{5};
auto message = LookupString(strings, options);
return std::vformat(message, ARGS({3}));
}}
' -f $Name, $ArgumentTypes, $ArgumentHeaders, $Arguments, $Content.split("`n")[0], $map
}
}
function loadStrings
{
param([string]$language)
$xml = [xml](Get-Content "$resourceFolder/$language/Resources.resw" -raw)
$strings = @{}
foreach($entry in $xml.root.data)
{
if ($strings.ContainsKey($entry.name))
{
throw "Entry $($entry.name) duplicated in resource for: $language"
}
# Skip generating strings intended for WSL Settings. These strings are
# unused in native C++ code. Further, their naming is incompatible with
# the function names generated for the localization header (contain '.').
if ($entry.name.StartsWith("Settings_"))
{
continue
}
$strings[$entry.name] = $entry.value
}
return $strings
}
$allStrings = @{}
foreach ($language in $languages)
{
$allStrings[$language] = loadStrings -language $language
}
foreach($entry in $allStrings[$defaultLanguage].Keys)
{
$content += generateEntry -Name $entry -allStrings $allStrings
}
$content += @"
private:
static const TChar* LookupString(const std::vector<std::pair<TString, const TChar*>>& strings, Options options);
};
} // namespace wsl::windows::common
#undef ARGS
"@
Set-Content -Path $OutFile -Encoding UTF8 $content