# 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 #include 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; 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> 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>& strings, Options options); }; } // namespace wsl::windows::common #undef ARGS "@ Set-Content -Path $OutFile -Encoding UTF8 $content