Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Add support for generating Windows Store listing data. #12

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
steam/
/winstore/obj
/winstore/bin
.vs
winstore-output*
1 change: 1 addition & 0 deletions lang/afrikaans.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/basque.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/belarusian.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/catalan.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/croatian.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/estonian.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/gaelic.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/galician.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/hebrew.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/icelandic.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/indonesian.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/irish.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/latvian.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/lithuanian.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/luxembourgish.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/malay.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/norwegian_nynorsk.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/serbian.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/slovak.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/slovenian.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/tamil.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
1 change: 1 addition & 0 deletions lang/welsh.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
##plural 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are all these languages actually plural 0? Or is it just too much copy/paste?

430 changes: 430 additions & 0 deletions winstore-template.csv

Large diffs are not rendered by default.

271 changes: 271 additions & 0 deletions winstore/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
using CsvHelper;
using System.Globalization;
using System.IO.Compression;
using System.Text;

namespace convert_to_winstore
{
/// <summary>
/// Class representing an OpenTTD language.
/// </summary>
internal class Language
{
/// <summary>
/// Language filename base (e.g. "english");
/// </summary>
public string LangFile { get; }

/// <summary>
/// Windows Store language code (e.g. "en-gb");
/// </summary>
public string StoreCode { get; }

/// <summary>
/// Loaded strings for substitution.
/// </summary>
private Dictionary<string, string> strings;

/// <summary>
/// Creates a new instance of the Language class.
/// </summary>
/// <param name="langFile">Language filename base.</param>
/// <param name="storeCode">Windows Store language code.</param>
public Language(string langFile, string storeCode)
{
LangFile = langFile;
StoreCode = storeCode;
}

/// <summary>
/// Replaces $VARIABLES$ within the specified string with translated strings.
/// </summary>
/// <param name="langPath">Path to the 'lang' folder.</param>
/// <param name="stringToSubstitute">String to work on.</param>
/// <returns>The substituted string.</returns>
public string Substitute(string langPath, string stringToSubstitute)
{
if (strings == null)
{
strings = new Dictionary<string, string>(StringComparer.Ordinal);
string path = Path.Combine(langPath, Path.ChangeExtension(LangFile, ".txt"));

if (!File.Exists(path))
{
// TODO: For now, substitute the English version.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The downside of TODOs: who is going to pick it up when?

So maybe the question .. is it actually a TODO?

path = Path.Combine(langPath, "english.txt");
}

using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (StreamReader sr = new StreamReader(fs, Encoding.UTF8))
{
while (!sr.EndOfStream)
{
string? line = sr.ReadLine();

if (string.IsNullOrWhiteSpace(line) || line.StartsWith('#'))
{
continue;
}

int firstColon = line.IndexOf(':');

if (firstColon < 0)
{
continue;
}

string key = $"${line.Substring(0, firstColon).Trim()}$";
string value = line.Substring(firstColon + 1).Trim();

strings[key] = value;
}
}
}
}

foreach (KeyValuePair<string, string> kvp in strings)
{
stringToSubstitute = stringToSubstitute.Replace(kvp.Key, kvp.Value, StringComparison.Ordinal);
}

return stringToSubstitute;
}
}

internal class Program
{
/// <summary>
/// List of supported languages.
/// </summary>
private static readonly List<Language> languageMappings =
[
new Language("arabic_egypt", "ar-eg"),
new Language("bulgarian", "bg-bg"),
new Language("simplified_chinese", "zh-cn"),
new Language("traditional_chinese", "zh-tw"),
new Language("bulgarian", "bg-bg"),
new Language("czech", "cs-cz"),
new Language("danish", "da-dk"),
new Language("dutch", "nl-nl"),
new Language("finnish", "fi-fi"), // Not currently selected for OpenTTD on the Windows Store
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that comment is true, why is it in here? Or might the comment become untrue at some point? Or should we disable the line in total? :)

new Language("french", "fr-fr"),
new Language("german", "de-de"),
new Language("greek", "el-gr"),
new Language("hungarian", "hu-hu"),
new Language("italian", "it-it"),
new Language("japanese", "ja-jp"),
new Language("korean", "ko-kr"),
new Language("norwegian_bokmal", "nb-no"),
new Language("polish", "pl-pl"),
new Language("portuguese", "pt-pt"),
new Language("brazilian_portuguese", "pt-br"),
new Language("romanian", "ro-ro"),
new Language("russian", "ru-ru"),
new Language("spanish", "es-es"),
new Language("spanish_MX", "es-mx"),
new Language("swedish", "sv-se"),
new Language("thai", "th-th"),
new Language("turkish", "tr-tr"),
new Language("ukrainian", "uk-ua"),
new Language("vietnamese", "vi-vn"),

// The following languages are supported by the Store, but not currently translated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this PR, that is no longer true, is it? So maybe already remove the comment, I would think.

new Language("afrikaans", "af-za"),
new Language("basque", "eu-es"),
new Language("belarusian", "be-by"),
new Language("catalan", "ca-es"),
new Language("croatian", "hr-hr"),
new Language("estonian", "et-ee"),
new Language("gaelic", "gd-gb"),
new Language("galician", "gl-es"),
new Language("hebrew", "he-il"),
new Language("icelandic", "is-is"),
new Language("indonesian", "id-id"),
new Language("irish", "ga-ie"),
new Language("latvian", "lv-lv"),
new Language("lithuanian", "lt-lt"),
new Language("luxembourgish", "lb-lu"),
new Language("malay", "ms-my"),
new Language("norwegian_nynorsk", "no-no"),
new Language("serbian", "sr-latn-rs"),
new Language("slovak", "sk-sk"),
new Language("slovenian", "sl-si"),
new Language("tamil", "ta-in"),
new Language("welsh", "cy-gb")
];

/// <summary>
/// English language variants (except "en-gb", which is included in the template).
/// </summary>
private static readonly string[] languageEnglishVariants =
{
"en-au",
"en-us"
};

/// <summary>
/// The English (UK) base translation.
/// </summary>
private static readonly Language englishGb = new Language("english", "en-gb");

static void Main(string[] args)
{
// Either search the current directory for our data, or allow the path to be passed on the command line
string rootPath = (args.Length > 0) ? args[0] : Directory.GetCurrentDirectory();

string templatePath = Path.Combine(rootPath, "winstore-template.csv");
string langPath = Path.Combine(rootPath, "lang");
string outputPath = Path.Combine(rootPath, "winstore-output.csv");

using (StreamWriter writer = new StreamWriter(outputPath, false, Encoding.UTF8))
{
using (CsvWriter csvOut = new CsvWriter(writer, new CultureInfo("en-US")))
{
using (StreamReader reader = new StreamReader(templatePath, true))
{
using (CsvReader csv = new CsvReader(reader, new CultureInfo("en-US")))
{
// Read the header row
csv.Read();

if (!csv.ReadHeader() || csv.HeaderRecord == null)
{
Console.Error.WriteLine("Unable to read header from input CSV.");
return;
}

// Create output headers - one for each language
string[] headers = new string[csv.HeaderRecord.Length + languageMappings.Count + languageEnglishVariants.Length];

csv.HeaderRecord.CopyTo(headers, 0);
languageMappings.Select(l => l.StoreCode).ToArray().CopyTo(headers, csv.HeaderRecord.Length);
languageEnglishVariants.CopyTo(headers, csv.HeaderRecord.Length + languageMappings.Count);

foreach (string value in headers)
{
csvOut.WriteField(value);
}

csvOut.NextRecord();

string[] values = (string[])headers.Clone();

while (csv.Read())
{
string fieldName = csv.GetField(0) ?? string.Empty;
string fieldId = csv.GetField(1) ?? string.Empty;
string fieldType = csv.GetField(2) ?? string.Empty;
string fieldDefault = csv.GetField(3) ?? string.Empty;
string enGbValue = csv.GetField(4) ?? string.Empty;

values[0] = fieldName;
values[1] = fieldId;
values[2] = fieldType;
values[3] = fieldDefault;

for (int i = 4; i < headers.Length; i++)
{
values[i] = enGbValue;
}

if (fieldType.Equals("Text", StringComparison.Ordinal) && enGbValue.Contains('$', StringComparison.Ordinal))
{
// Perform a language lookup and substitution
values[4] = englishGb.Substitute(langPath, values[4]);

int curCol = 5;

foreach (Language l in languageMappings)
{
values[curCol] = l.Substitute(langPath, enGbValue);

// If the string still contains unsubstituted values, use the English version instead
if (values[curCol].Contains('$'))
values[curCol] = values[4];

curCol++;
}

// Manually set the English variants to the same as British English
foreach (string variant in languageEnglishVariants)
{
values[curCol] = values[4];
curCol++;
}
}

foreach (string value in values)
{
csvOut.WriteField(value);
}

csvOut.NextRecord();
}
}
}
}
}
}
}
}
8 changes: 8 additions & 0 deletions winstore/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"profiles": {
"convert-to-winstore": {
"commandName": "Project",
"commandLineArgs": "../../../../"
}
}
}
15 changes: 15 additions & 0 deletions winstore/convert-to-winstore.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>convert_to_winstore</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CsvHelper" Version="33.0.1" />
</ItemGroup>

</Project>