Skip to content
This repository was archived by the owner on Sep 11, 2023. It is now read-only.

Commit 6906237

Browse files
authored
Translations rework (#118)
* initial rework of translations * implemented new repo files checking for translation files * finished modifying language parsing and loading * shortened translation method * removed old language file from scripts * made english item in initial language selection window appear first * fixed first boot not setting language properly * documented and ordered a bit * added failsafe for deleted translation files that were in use * small optimization for last change
1 parent be36c06 commit 6906237

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+588
-3072
lines changed

Deploy/Compress_Beta.ps1

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ LiteralPath=
55
"sourcepawn/",
66
"lysis/",
77
"SPCode.exe",
8-
"lang_0_spcode.xml",
98
"GPLv3.txt",
109
"License.txt"
1110
DestinationPath = "SPCode.Beta.Portable.zip"

Deploy/Compress_Stable.ps1

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ LiteralPath=
55
"sourcepawn/",
66
"lysis/",
77
"SPCode.exe",
8-
"lang_0_spcode.xml",
98
"GPLv3.txt",
109
"License.txt"
1110
DestinationPath = "SPCode.Portable.zip"

Deploy/SPCode_Beta.nsi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ SetOutPath $INSTDIR
3636

3737
File SPCode.exe
3838

39-
File lang_0_spcode.xml
4039
File License.txt
4140
File GPLv3.txt
4241

Deploy/SPCode_Stable.nsi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ SetOutPath $INSTDIR
3636

3737
File SPCode.exe
3838

39-
File lang_0_spcode.xml
4039
File License.txt
4140
File GPLv3.txt
4241

Deploy/SpcodeUpdater/Program.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Diagnostics;
33
using System.IO;
4-
using System.Linq;
54
using System.Text;
65
using System.Threading;
76
using System.Windows.Forms;

Interop/HotkeyControl.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Collections.Generic;
33
using System.IO;
44
using System.Linq;
5-
using System.Threading;
65
using System.Windows.Forms;
76
using System.Xml;
87
using SPCode.Utils;

Interop/OptionsControl.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace SPCode
1111
[Serializable]
1212
public class OptionsControl
1313
{
14-
public static int SVersion = 14;
14+
public static int SVersion = 15;
1515
public bool Editor_AgressiveIndentation = true;
1616
public bool Editor_AutoCloseBrackets = true;
1717
public bool Editor_AutoCloseStringChars = true;
@@ -87,6 +87,9 @@ public class OptionsControl
8787
// Version 14
8888
public ActionOnClose ActionOnClose;
8989

90+
// Version 15
91+
public int TranslationsVersion;
92+
9093
public int Version = 11;
9194

9295
public void FillNullToDefaults()
@@ -174,9 +177,13 @@ public void FillNullToDefaults()
174177
SearchOptions.MultilineRegex = false;
175178
SearchOptions.ReplaceType = 0;
176179
}
180+
if (Version < 14)
181+
{
182+
TranslationsVersion = 0;
183+
}
177184

178185
//new Optionsversion - reset new fields to default
179-
Version = SVersion; //then Update Version afterwars
186+
Version = SVersion; //then Update Version afterwards
180187
}
181188
}
182189

Interop/TranslationProvider.cs

Lines changed: 154 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,199 @@
11
using System;
22
using System.Collections.Generic;
33
using System.IO;
4+
using System.IO.Compression;
45
using System.Linq;
6+
using System.Net;
57
using System.Windows;
68
using System.Xml;
9+
using Octokit;
710
using SPCode.Utils;
8-
using static SPCode.Utils.DefaultTranslations;
911

1012
namespace SPCode.Interop
1113
{
1214
public class TranslationProvider
1315
{
14-
public string[] AvailableLanguageIDs;
15-
public string[] AvailableLanguages;
16-
16+
public List<string> AvailableLanguageIDs = new();
17+
public List<string> AvailableLanguages = new();
1718
public bool IsDefault = true;
1819

19-
private readonly Dictionary<string, string> LangDict = new(StringComparer.OrdinalIgnoreCase);
20+
private readonly string _tempDir = Paths.GetTempDirectory();
21+
private readonly string _translationsDir = Paths.GetTranslationsDirectory();
22+
private static readonly Dictionary<string, string> _langDictionary = new(StringComparer.OrdinalIgnoreCase);
23+
private Release _latestVersion;
24+
25+
public TranslationProvider()
26+
{
27+
// Make sure translations dir exists
28+
if (!Directory.Exists(_translationsDir))
29+
{
30+
Directory.CreateDirectory(_translationsDir);
31+
}
32+
33+
if (IsUpdateAvailable())
34+
{
35+
UpdateTranslations();
36+
}
37+
38+
ParseTranslationFiles();
39+
}
2040

2141
/// <summary>
2242
/// Gets the translation of the specified phrase.
2343
/// </summary>
2444
/// <param name="phrase">The phrase to return translated</param>
2545
/// <returns></returns>
26-
public string Get(string phrase)
46+
public static string Translate(string phrase)
2747
{
28-
return LangDict.ContainsKey(phrase) ? LangDict[phrase] : "<empty>";
48+
return _langDictionary.ContainsKey(phrase) ? _langDictionary[phrase] : "<empty>";
2949
}
3050

3151
/// <summary>
3252
/// Loads the specified language.
3353
/// </summary>
3454
/// <param name="lang">The language to load</param>
35-
/// <param name="Initial"></param>
36-
public void LoadLanguage(string lang, bool Initial = false)
55+
/// <param name="initial">Whether this was the startup initial method call</param>
56+
public void LoadLanguage(string lang, bool initial = false)
3757
{
38-
DefaultLangDict.Keys.ToList().ForEach(x => LangDict[x] = DefaultLangDict[x]);
39-
var languageList = new List<string>();
40-
var languageIDList = new List<string>();
41-
languageList.Add("English");
42-
languageIDList.Add("");
58+
// This is probably the first boot ever
59+
if (lang == string.Empty)
60+
{
61+
lang = Constants.DefaultLanguageID;
62+
Program.OptionsObject.Language = lang;
63+
}
4364
lang = lang.Trim().ToLowerInvariant();
44-
IsDefault = (string.IsNullOrEmpty(lang) || lang.ToLowerInvariant() == "en") && Initial;
45-
if (File.Exists(Constants.LanguagesFile))
65+
IsDefault = (string.IsNullOrEmpty(lang) || lang.ToLowerInvariant() == Constants.DefaultLanguageID) && initial;
66+
var doc = new XmlDocument();
67+
68+
try
4669
{
47-
try
70+
// Fill with defaults first
71+
if (initial)
4872
{
49-
var document = new XmlDocument();
50-
document.Load(Constants.LanguagesFile);
51-
if (document.ChildNodes.Count < 1)
73+
doc.Load(Path.Combine(_translationsDir, Constants.DefaultTranslationsFile));
74+
foreach (XmlNode node in doc.ChildNodes[0].ChildNodes)
5275
{
53-
throw new Exception("No Root-Node: \"translations\" found");
76+
_langDictionary.Add(node.Name, node.InnerText);
5477
}
5578

56-
XmlNode rootLangNode = null;
57-
foreach (XmlNode childNode in document.ChildNodes[0].ChildNodes)
79+
// Return if the attempted language to load is the default one
80+
if (lang == Constants.DefaultLanguageID)
5881
{
59-
var lID = childNode.Name;
60-
var lNm = lID;
61-
if (childNode.Name.ToLowerInvariant() == lang)
62-
{
63-
rootLangNode = childNode;
64-
}
65-
if (childNode.FirstChild.Name.ToLowerInvariant() == "language")
66-
{
67-
lNm = childNode.FirstChild.InnerText;
68-
}
69-
languageList.Add(lNm);
70-
languageIDList.Add(lID);
82+
return;
7183
}
72-
if (rootLangNode != null)
84+
}
85+
86+
var file = Path.Combine(_translationsDir, $"{lang}.xml");
87+
if (!File.Exists(file))
88+
{
89+
UpdateTranslations();
90+
LoadLanguage(lang);
91+
return;
92+
}
93+
else
94+
{
95+
doc.Load(file);
96+
97+
// Replace existing keys with the ones available in this file
98+
foreach (XmlNode node in doc.ChildNodes[0].ChildNodes)
7399
{
74-
foreach (XmlNode node in rootLangNode.ChildNodes)
75-
{
76-
if (node.NodeType == XmlNodeType.Comment)
77-
{
78-
continue;
79-
}
80-
var nn = node.Name.ToLowerInvariant();
81-
var nv = node.InnerText;
82-
LangDict[nn] = nv;
83-
}
100+
_langDictionary[node.Name] = node.InnerText;
84101
}
85102
}
86-
catch (Exception e)
103+
}
104+
catch (Exception)
105+
{
106+
throw;
107+
}
108+
}
109+
110+
/// <summary>
111+
/// Gets all of the translation files and adds them to the global available languages list.
112+
/// </summary>
113+
public void ParseTranslationFiles()
114+
{
115+
try
116+
{
117+
var filesDir = Directory.GetFiles(_translationsDir).Where(x => x.EndsWith(".xml"));
118+
foreach (var file in filesDir)
119+
{
120+
// Create wrapper
121+
var fInfo = new FileInfo(file);
122+
123+
// Parse content in an XML object
124+
var doc = new XmlDocument();
125+
doc.LoadXml(File.ReadAllText(fInfo.FullName));
126+
127+
// Get language name and ID
128+
var langName = doc.ChildNodes[0].ChildNodes
129+
.Cast<XmlNode>()
130+
.Single(x => x.Name == "language")
131+
.InnerText;
132+
var langID = fInfo.Name.Substring(0, fInfo.Name.IndexOf('.'));
133+
134+
// Add file to the available languages lists
135+
AvailableLanguages.Add(langName);
136+
AvailableLanguageIDs.Add(langID);
137+
}
138+
}
139+
catch (Exception ex)
140+
{
141+
MessageBox.Show($"There was a problem while updating the translations file.\n" +
142+
$"Details: {ex.Message}");
143+
}
144+
}
145+
146+
/// <summary>
147+
/// Downloads the latest translation files release from GitHub for SPCode to parse them.
148+
/// </summary>
149+
public void UpdateTranslations()
150+
{
151+
// Clear temp folder before beggining
152+
DirUtils.ClearTempFolder();
153+
154+
// Download latest release zip file
155+
var wc = new WebClient();
156+
var downloadedFile = Path.Combine(_tempDir, "langs.zip");
157+
wc.Headers.Add(HttpRequestHeader.UserAgent, Constants.ProductHeaderValueName);
158+
wc.DownloadFile(_latestVersion.ZipballUrl, downloadedFile);
159+
160+
// Decompress and replace all of its files
161+
ZipFile.ExtractToDirectory(downloadedFile, _tempDir);
162+
var filesDir = Directory.GetFiles(Directory.GetDirectories(_tempDir)[0]).Where(x => x.EndsWith(".xml"));
163+
foreach (var file in filesDir)
164+
{
165+
// Create wrapper
166+
var fInfo = new FileInfo(file);
167+
168+
// Replace current file with this one
169+
var destination = Path.Combine(_translationsDir, fInfo.Name);
170+
if (File.Exists(destination))
87171
{
88-
MessageBox.Show("An error occured while reading the language-file. Without them, the editor wont show translations." + Environment.NewLine + "Details: " + e.Message
89-
, "Error while reading configs."
90-
, MessageBoxButton.OK
91-
, MessageBoxImage.Warning);
172+
File.Delete(destination);
92173
}
174+
File.Move(fInfo.FullName, destination);
93175
}
94-
AvailableLanguages = languageList.ToArray();
95-
AvailableLanguageIDs = languageIDList.ToArray();
176+
177+
// Delete all temp folder contents
178+
DirUtils.ClearTempFolder();
179+
180+
// Update version to options object
181+
Program.OptionsObject.TranslationsVersion = int.Parse(_latestVersion.Name);
182+
}
183+
184+
/// <summary>
185+
/// Compares the stored version of the translations release with the one from GitHub
186+
/// </summary>
187+
/// <returns>Whether there's an update available</returns>
188+
public bool IsUpdateAvailable()
189+
{
190+
var client = new GitHubClient(new ProductHeaderValue(Constants.ProductHeaderValueName));
191+
var versionStored = Program.OptionsObject.TranslationsVersion;
192+
193+
_latestVersion = client.Repository.Release.GetAll(Constants.OrgName,
194+
Constants.TranslationsRepoName).Result[0];
195+
196+
return versionStored < int.Parse(_latestVersion.Name);
96197
}
97198
}
98199
}

Interop/Updater/UpdateCheck.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ private static async Task<IEnumerable<Release>> GetAllReleases()
107107
PageSize = 10
108108
};
109109

110-
var client = new GitHubClient(new ProductHeaderValue("spcode-client"));
111-
var releases = await client.Repository.Release.GetAll("SPCodeOrg", "SPCode", apiOptions);
110+
var client = new GitHubClient(new ProductHeaderValue(Constants.ProductHeaderValueName));
111+
var releases = await client.Repository.Release.GetAll(Constants.OrgName, Constants.MainRepoName, apiOptions);
112112
#if BETA
113113
var finalReleasesList = releases.Where(x => x.Prerelease);
114114
#else

Interop/Updater/UpdateWindow.xaml.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using MahApps.Metro.Controls.Dialogs;
1313
using MdXaml;
1414
using SPCode.Utils;
15+
using static SPCode.Interop.TranslationProvider;
1516

1617
namespace SPCode.Interop.Updater
1718
{
@@ -85,11 +86,11 @@ public void PrepareUpdateWindow(bool OnlyChangelog = false)
8586
}
8687
else
8788
{
88-
Title = string.Format(Program.Translations.Get("VersionAvailable"), updateInfo.AllReleases[0].TagName);
89-
MainLine.Text = Program.Translations.Get("WantToUpdate");
90-
ActionYesButton.Content = Program.Translations.Get("Yes");
91-
ActionNoButton.Content = Program.Translations.Get("No");
92-
ActionGithubButton.Content = Program.Translations.Get("ViewGithub");
89+
Title = string.Format(Translate("VersionAvailable"), updateInfo.AllReleases[0].TagName);
90+
MainLine.Text = Translate("WantToUpdate");
91+
ActionYesButton.Content = Translate("Yes");
92+
ActionNoButton.Content = Translate("No");
93+
ActionGithubButton.Content = Translate("ViewGithub");
9394
}
9495

9596
var releasesBody = new StringBuilder();
@@ -131,8 +132,8 @@ private void StartUpdate()
131132
ActionYesButton.Visibility = Visibility.Hidden;
132133
ActionNoButton.Visibility = Visibility.Hidden;
133134
ActionGithubButton.Visibility = Visibility.Hidden;
134-
MainLine.Text = string.Format(Program.Translations.Get("UpdatingTo"), updateInfo.AllReleases[0].TagName);
135-
SubLine.Text = Program.Translations.Get("DownloadingUpdater");
135+
MainLine.Text = string.Format(Translate("UpdatingTo"), updateInfo.AllReleases[0].TagName);
136+
SubLine.Text = Translate("DownloadingUpdater");
136137
var t = new Thread(UpdateDownloadWorker);
137138
t.Start();
138139
}
@@ -180,7 +181,7 @@ private void UpdateDownloadWorker()
180181
/// </summary>
181182
private void FinalizeUpdate()
182183
{
183-
SubLine.Text = Program.Translations.Get("StartingUpdater");
184+
SubLine.Text = Translate("StartingUpdater");
184185
UpdateLayout();
185186
try
186187
{

0 commit comments

Comments
 (0)