diff --git a/Client/Client.csproj b/Client/Client.csproj
index 8db79c0..9814e17 100644
--- a/Client/Client.csproj
+++ b/Client/Client.csproj
@@ -51,6 +51,7 @@
+
@@ -88,13 +89,18 @@
-
-
+
+
+
Designer
-
+
Designer
+
+
+
+
diff --git a/Client/ConsoleForms/ConsoleController.cs b/Client/ConsoleForms/ConsoleController.cs
index d4af291..771f448 100644
--- a/Client/ConsoleForms/ConsoleController.cs
+++ b/Client/ConsoleForms/ConsoleController.cs
@@ -211,9 +211,9 @@ namespace Client.ConsoleForms
}
}
- private static ViewData DoElementParse(XmlNode el)
+ private static ViewData DoElementParse(XmlNode el, LangManager lang)
{
- ViewData data = new ViewData(el.LocalName, el.InnerText);
+ ViewData data = new ViewData(el.LocalName, lang.MapIfExists(el.InnerText));
if (el.Attributes != null)
foreach (var attr in el.Attributes)
@@ -222,14 +222,14 @@ namespace Client.ConsoleForms
if (el.ChildNodes != null)
foreach (var child in el.ChildNodes)
- if (child is XmlNode) data.nestedData.Add(DoElementParse((XmlNode)child));
+ if (child is XmlNode) data.nestedData.Add(DoElementParse((XmlNode)child, lang));
return data;
}
private static Dictionary>> cache = new Dictionary>>();
- public static List> LoadResourceViews(string name, bool doCache = true)
+ public static List> LoadResourceViews(string name, LangManager lang, bool doCache = true)
{
if (cache.ContainsKey(name))
return cache[name];
@@ -237,10 +237,10 @@ namespace Client.ConsoleForms
PropertyInfo[] properties = typeof(Resources).GetProperties(BindingFlags.NonPublic | BindingFlags.Static);
foreach (var prop in properties)
if (prop.Name.Equals(name) && prop.PropertyType.Equals(typeof(string)))
- return LoadViews((string)prop.GetValue(null), doCache ? name : null);
+ return LoadViews((string)prop.GetValue(null), lang, doCache ? name : null);
throw new SystemException($"Resource { name } could not be located!");
}
- public static List> LoadViews(string xml, string cacheID = null)
+ public static List> LoadViews(string xml, LangManager lang, string cacheID = null)
{
if (cacheID != null && cache.ContainsKey(cacheID))
return cache[cacheID];
@@ -254,25 +254,25 @@ namespace Client.ConsoleForms
foreach (var child in doc.FirstChild.NextSibling.ChildNodes)
if (!(child is XmlNode) || child is XmlComment) continue;
- else views.Add(LoadView(ns, DoElementParse((XmlNode)child)));
+ else views.Add(LoadView(ns, DoElementParse((XmlNode)child, lang), lang));
if (cacheID != null) cache[cacheID] = views;
return views;
}
- public static Tuple LoadView(string ns, ViewData data)
+ public static Tuple LoadView(string ns, ViewData data, LangManager lang)
{
Type type;
try { type = Type.GetType(ns + '.' + data.Name, true); }
catch { type = Type.GetType(data.Name, true); }
- ConstructorInfo info = type.GetConstructor(new Type[] { typeof(ViewData) });
+ ConstructorInfo info = type.GetConstructor(new Type[] { typeof(ViewData), typeof(LangManager) });
string id = data.attributes.ContainsKey("id") ? data.attributes["id"] : "";
data.attributes["xmlns"] = ns;
- return new Tuple(id, (View)info.Invoke(new object[] { data }));
+ return new Tuple(id, (View)info.Invoke(new object[] { data, lang }));
}
public delegate void Runnable();
@@ -284,7 +284,8 @@ namespace Client.ConsoleForms
.SetAttribute("padding_right", 2)
.SetAttribute("padding_top", 1)
.SetAttribute("padding_bottom", 1)
- .AddNested(new ViewData("Text", message)) // Add message
+ .AddNested(new ViewData("Text", message)), // Add message
+ LangManager.NO_LANG
)
{
BackgroundColor = ConsoleColor.White,
diff --git a/Client/ConsoleForms/Context.cs b/Client/ConsoleForms/Context.cs
index 672ac99..2c3ec8b 100644
--- a/Client/ConsoleForms/Context.cs
+++ b/Client/ConsoleForms/Context.cs
@@ -16,10 +16,23 @@ namespace Client.ConsoleForms
protected readonly ReadOnlyCollection> views;
protected readonly ContextManager manager;
- public Context(ContextManager manager, string contextName, bool asResource = true)
+ private delegate List> ViewLoader(string data, LangManager lang);
+ public Context(ContextManager manager, params string[] contextNames) : this(manager, true, contextNames) { }
+ public Context(ContextManager manager, bool asResource, params string[] contextNames)
{
this.manager = manager;
- views = new ReadOnlyCollectionBuilder>(asResource ? ConsoleController.LoadResourceViews(contextName) : ConsoleController.LoadViews(contextName)).ToReadOnlyCollection();
+
+ ViewLoader loader;
+ if (asResource) loader = (d, m) => ConsoleController.LoadResourceViews(d, m);
+ else loader = (d, m) => ConsoleController.LoadViews(d, m);
+
+ List> l = new List>();
+ foreach(var contextName in contextNames)
+ foreach (var viewPair in loader(contextName, manager.I18n))
+ if (l.GetNamed(viewPair.Item1) != null) throw new SystemException($"View with id=\"{viewPair.Item1}\" has already been loaded!");
+ else l.Add(viewPair);
+
+ views = new ReadOnlyCollectionBuilder>(l).ToReadOnlyCollection();
}
public virtual bool Update(ConsoleController.KeyEvent keypress, bool hasKeypress = true)
diff --git a/Client/ConsoleForms/ContextManager.cs b/Client/ConsoleForms/ContextManager.cs
index e9d627d..c52c1e8 100644
--- a/Client/ConsoleForms/ContextManager.cs
+++ b/Client/ConsoleForms/ContextManager.cs
@@ -9,6 +9,13 @@ namespace Client.ConsoleForms
public sealed class ContextManager
{
public Context Current { get; private set; }
+ public LangManager I18n { get; private set; }
+
+ public ContextManager(bool doLang = true)
+ {
+ if (doLang) I18n = LangManager.LoadLang();
+ else I18n = LangManager.NO_LANG;
+ }
public void LoadContext(Context ctx)
{
diff --git a/Client/ConsoleForms/Graphics/ButtonView.cs b/Client/ConsoleForms/Graphics/ButtonView.cs
index 40a354e..83141f9 100644
--- a/Client/ConsoleForms/Graphics/ButtonView.cs
+++ b/Client/ConsoleForms/Graphics/ButtonView.cs
@@ -12,7 +12,7 @@ namespace Client.ConsoleForms.Graphics
{
protected SubmissionEvent evt;
- public ButtonView(ViewData parameters) : base(parameters)
+ public ButtonView(ViewData parameters, LangManager lang) : base(parameters, lang)
{
}
diff --git a/Client/ConsoleForms/Graphics/DialogView.cs b/Client/ConsoleForms/Graphics/DialogView.cs
index dc731f1..30f08cc 100644
--- a/Client/ConsoleForms/Graphics/DialogView.cs
+++ b/Client/ConsoleForms/Graphics/DialogView.cs
@@ -29,12 +29,12 @@ namespace Client.ConsoleForms.Graphics
private static int ComputeLength(Tuple[] opts) => opts.CollectiveLength(true) + opts.Length - 1;
- public DialogView(ViewData parameters) :
+ public DialogView(ViewData parameters, LangManager lang) :
base(parameters.SetAttribute("width",
Math.Max(
parameters.AttribueAsInt("width") < 1 ? parameters.NestedText("Text").Length : parameters.AttribueAsInt("width"),
ComputeLength(parameters.Get("Options").CollectSub("Option"))
- )))
+ )), lang)
{
ViewData optionsData = parameters.Get("Options");
this.options = optionsData.nestedData.Filter(p => p.Name.Equals("Option")).ToArray();
diff --git a/Client/ConsoleForms/Graphics/InputView.cs b/Client/ConsoleForms/Graphics/InputView.cs
index 3142a24..9955adf 100644
--- a/Client/ConsoleForms/Graphics/InputView.cs
+++ b/Client/ConsoleForms/Graphics/InputView.cs
@@ -120,7 +120,7 @@ namespace Client.ConsoleForms.Graphics
public SubmissionListener SubmissionsListener { protected get; set; }
public TextEnteredListener InputListener { protected get; set; }
- public InputView(ViewData parameters) : base(parameters)
+ public InputView(ViewData parameters, LangManager lang) : base(parameters, lang)
{
int
sBC = parameters.AttribueAsInt("textfield_select_color", (int)ConsoleColor.Gray),
diff --git a/Client/ConsoleForms/Graphics/ListView.cs b/Client/ConsoleForms/Graphics/ListView.cs
index abc7459..ab84136 100644
--- a/Client/ConsoleForms/Graphics/ListView.cs
+++ b/Client/ConsoleForms/Graphics/ListView.cs
@@ -15,7 +15,7 @@ namespace Client.ConsoleForms.Graphics
public override Region Occlusion => new Region(new Rectangle(0, 0, ContentWidth, ContentHeight));
- public ListView(ViewData parameters) : base(parameters)
+ public ListView(ViewData parameters, LangManager lang) : base(parameters, lang)
{
SelectBackground = (ConsoleColor)parameters.AttribueAsInt("background_select_color", (int)ConsoleColor.Gray);
SelectText = (ConsoleColor)parameters.AttribueAsInt("text_select_color", (int)ConsoleColor.Gray);
@@ -29,7 +29,7 @@ namespace Client.ConsoleForms.Graphics
// Limit content width
if (limited && view.AttribueAsInt("width") > maxWidth) view.attributes["width"] = maxWidth.ToString();
- Tuple v = ConsoleController.LoadView(parameters.attributes["xmlns"], view); // Load the view in with standard namespace
+ Tuple v = ConsoleController.LoadView(parameters.attributes["xmlns"], view, I18n); // Load the view in with standard namespace
innerViews.Add(v);
if (!limited) maxWidth = Math.Max(v.Item2.ContentWidth, maxWidth);
diff --git a/Client/ConsoleForms/Graphics/TextView.cs b/Client/ConsoleForms/Graphics/TextView.cs
index ff07dfb..2bf337f 100644
--- a/Client/ConsoleForms/Graphics/TextView.cs
+++ b/Client/ConsoleForms/Graphics/TextView.cs
@@ -41,7 +41,7 @@ namespace Client.ConsoleForms.Graphics
//public char Border { get; set; }
//public ConsoleColor BorderColor { get; set; }
- public TextView(ViewData parameters) : base(parameters)
+ public TextView(ViewData parameters, LangManager lang) : base(parameters, lang)
{
//BorderColor = (ConsoleColor) parameters.AttribueAsInt("border", (int)ConsoleColor.Blue);
diff --git a/Client/ConsoleForms/Graphics/View.cs b/Client/ConsoleForms/Graphics/View.cs
index e6ac36a..c45a451 100644
--- a/Client/ConsoleForms/Graphics/View.cs
+++ b/Client/ConsoleForms/Graphics/View.cs
@@ -29,8 +29,9 @@ namespace Client.ConsoleForms.Graphics
public int ContentHeight { get; protected set; }
public abstract Region Occlusion { get; }
public bool Dirty { get; set; }
+ public LangManager I18n { get; private set; }
- public View(ViewData parameters)
+ public View(ViewData parameters, LangManager lang)
{
padding = new AbsolutePadding(parameters.AttribueAsInt("padding_left"), parameters.AttribueAsInt("padding_right"), parameters.AttribueAsInt("padding_top"), parameters.AttribueAsInt("padding_bottom"));
gravity = (Gravity)parameters.AttribueAsInt("gravity");
@@ -39,6 +40,7 @@ namespace Client.ConsoleForms.Graphics
TextColor = (ConsoleColor)parameters.AttribueAsInt("color_text", (int)ConsoleColor.Black);
Border = ' ';
DrawBorder = parameters.attributes.ContainsKey("border");
+ I18n = lang;
back_data = parameters.GetAttribute("back");
@@ -108,7 +110,7 @@ namespace Client.ConsoleForms.Graphics
{
string[] components;
if (action == null || !action.Contains(':') || (components = action.Split(':')).Length != 2) return () => { };
- var views = ConsoleController.LoadResourceViews(components[0]);
+ var views = ConsoleController.LoadResourceViews(components[0], I18n);
var view = views.GetNamed(components[1]);
return () =>
{
diff --git a/Client/ConsoleForms/LangManager.cs b/Client/ConsoleForms/LangManager.cs
new file mode 100644
index 0000000..aa98b4e
--- /dev/null
+++ b/Client/ConsoleForms/LangManager.cs
@@ -0,0 +1,141 @@
+using Client.Properties;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml;
+
+namespace Client.ConsoleForms
+{
+ public sealed class LangManager
+ {
+ private const string MAPPING_PREFIX = "@string/";
+
+ public static readonly LangManager NO_LANG = new LangManager(true);
+
+ private readonly Dictionary mappings;
+ public string Name { get; }
+
+
+ private LangManager(bool b)
+ {
+ mappings = new Dictionary();
+ Name = "";
+ }
+
+ public LangManager(string langName = "en_US", bool fromResource = true)
+ {
+ string from = null;
+ if (fromResource)
+ {
+ PropertyInfo[] properties = typeof(Resources).GetProperties(BindingFlags.NonPublic | BindingFlags.Static);
+ foreach (var prop in properties)
+ if (prop.Name.Equals("strings_lang_" + langName) && prop.PropertyType.Equals(typeof(string)))
+ {
+ from = (string)prop.GetValue(null);
+ break;
+ }
+ if (from == null)
+ {
+ mappings = new Dictionary();
+ Name = "";
+ return;
+ }
+ }
+ else from = langName;
+ mappings = DoMapping(from, out string name);
+ Name = name;
+ }
+
+ public bool HasMapping(string name) => name.StartsWith(MAPPING_PREFIX) && mappings.ContainsKey(StripPrefix(name));
+ public string GetMapping(string name) => mappings[StripPrefix(name)];
+ public string MapIfExists(string name) => HasMapping(name) ? GetMapping(name) : name;
+ private string StripPrefix(string from) => from.Substring(MAPPING_PREFIX.Length);
+
+ private Dictionary DoMapping(string xml, out string label)
+ {
+ XmlDocument doc = new XmlDocument();
+ doc.LoadXml(xml);
+ XmlNode lang = doc.GetElementsByTagName("Strings").Item(0);
+
+ // Janky way of setting label since the compiler apparently doesn't accept it in an else-statement
+ label = null;
+ if (lang is XmlElement lang_el && lang_el.HasAttribute("label")) label = lang_el.GetAttribute("label");
+
+ // Read language mappings
+ Dictionary map = new Dictionary();
+ foreach(var node in lang.ChildNodes)
+ if(node is XmlElement el && el.Name.Equals("Entry") && el.HasAttribute("name"))
+ map.Add(el.GetAttribute("name"), el.InnerText);
+ return map;
+ }
+
+ public static LangManager LoadLang(string langMeta = "strings_meta", bool fromResource = true)
+ {
+ if (fromResource)
+ {
+ PropertyInfo[] properties = typeof(Resources).GetProperties(BindingFlags.NonPublic | BindingFlags.Static);
+ foreach (var prop in properties)
+ if (prop.Name.Equals(langMeta) && prop.PropertyType.Equals(typeof(string)))
+ return new LangManager(ProcessMeta((string)prop.GetValue(null)));
+ }
+ return new LangManager(ProcessMeta(langMeta));
+ }
+
+ private static string ProcessMeta(string metaString)
+ {
+ XmlDocument doc = new XmlDocument();
+ doc.LoadXml(metaString);
+ XmlNode lang = doc.GetElementsByTagName("Lang").Item(0);
+ List priorities = new List();
+ foreach(var node in lang.ChildNodes)
+ if (node is XmlElement el)
+ {
+ if (el.Name.Equals("Default")) priorities.Insert(0, (XmlElement)node);
+ else if (el.Name.Equals("Fallback"))
+ {
+ for (int i = 0; i < priorities.Count; ++i)
+ if (!priorities[i].Name.Equals("Default") && ComparePriority(el, priorities[i]))
+ {
+ priorities.Insert(i, el);
+ break;
+ }
+ else if (i == priorities.Count - 1)
+ {
+ priorities.Add(el);
+ break;
+ }
+ }
+ }
+
+ PropertyInfo[] properties = typeof(Resources).GetProperties(BindingFlags.NonPublic | BindingFlags.Static);
+
+ // Check if we can use system language
+ string culture = System.Globalization.CultureInfo.InstalledUICulture.Name.Replace('-', '_');
+ foreach(var elt in priorities)
+ if (elt.InnerText.Equals(culture))
+ {
+ foreach (var prop in properties)
+ if (prop.Name.Equals("strings_lang_" + culture) && prop.PropertyType.Equals(typeof(string)))
+ return culture;
+
+ priorities.Remove(elt);
+ break;
+ }
+
+ // Use defults and fallbacks
+ for (int i = 0; i el1.HasAttribute("priority") && int.TryParse(el1.GetAttribute("priority"), out int el1_prio) && (!el2.HasAttribute("priority") || !int.TryParse(el2.GetAttribute("priority"), out int el2_prio) || el1_prio < el2_prio);
+ }
+}
diff --git a/Client/Context/NetContext.cs b/Client/Context/NetContext.cs
index 521aa0b..61bd699 100644
--- a/Client/Context/NetContext.cs
+++ b/Client/Context/NetContext.cs
@@ -12,7 +12,7 @@ namespace Client
{
public class NetContext : Context
{
- public NetContext(ContextManager manager) : base(manager, "Networking")
+ public NetContext(ContextManager manager) : base(manager, "Networking", "Common")
{
// Just close when anything is selected and "submitted"
RegisterSelectListeners((s, i, v) => controller.CloseView(s), "EmptyFieldError", "IPError", "PortError", "ConnectionError");
diff --git a/Client/Context/SessionContext.cs b/Client/Context/SessionContext.cs
index ac4f842..e1a0055 100644
--- a/Client/Context/SessionContext.cs
+++ b/Client/Context/SessionContext.cs
@@ -15,7 +15,7 @@ namespace Client
private readonly BankNetInteractor interactor;
private readonly string sessionID;
- public SessionContext(ContextManager manager, BankNetInteractor interactor, string sessionID) : base(manager, "Session")
+ public SessionContext(ContextManager manager, BankNetInteractor interactor, string sessionID) : base(manager, "Session", "Common")
{
this.interactor = interactor;
this.sessionID = sessionID;
diff --git a/Client/Context/WelcomeContext.cs b/Client/Context/WelcomeContext.cs
index 38d58e8..8ce522b 100644
--- a/Client/Context/WelcomeContext.cs
+++ b/Client/Context/WelcomeContext.cs
@@ -17,7 +17,7 @@ namespace Client
private Promise promise;
private bool forceDestroy = true;
- public WelcomeContext(ContextManager manager, BankNetInteractor connection) : base(manager, "Setup")
+ public WelcomeContext(ContextManager manager, BankNetInteractor connection) : base(manager, "Setup", "Common")
{
this.interactor = connection;
diff --git a/Client/Layout/Session.xml b/Client/Layout/Session.xml
deleted file mode 100644
index 29acf1d..0000000
--- a/Client/Layout/Session.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
- Login succeeded!
-
-
\ No newline at end of file
diff --git a/Client/Program.cs b/Client/Program.cs
index 2676bf0..7542146 100644
--- a/Client/Program.cs
+++ b/Client/Program.cs
@@ -18,6 +18,7 @@ namespace ConsoleForms
// Set up timestamps in debug output
DebugStream = new TimeStampWriter(DebugStream, "HH:mm:ss.fff");
+
Padding p = new AbsolutePadding(2, 2, 1, 1);
Console.CursorVisible = false;
diff --git a/Client/Properties/Resources.Designer.cs b/Client/Properties/Resources.Designer.cs
index 7f3fea7..565196b 100644
--- a/Client/Properties/Resources.Designer.cs
+++ b/Client/Properties/Resources.Designer.cs
@@ -60,6 +60,27 @@ namespace Client.Properties {
}
}
+ ///
+ /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?>
+ ///<Resources>
+ /// <DialogView id="EmptyFieldError"
+ /// padding_left="2"
+ /// padding_right="2"
+ /// padding_top="1"
+ /// padding_bottom="1">
+ /// <Options>
+ /// <Option>Ok</Option>
+ /// </Options>
+ /// <Text>@string/ERR_empty</Text>
+ /// </DialogView>
+ ///</Resources>.
+ ///
+ internal static string Common {
+ get {
+ return ResourceManager.GetString("Common", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized resource of type System.Byte[].
///
@@ -82,9 +103,9 @@ namespace Client.Properties {
///
/// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?>
- ///<Elements xmlns="ConsoleForms">
+ ///<Elements xmlns="Client.ConsoleForms.Graphics">
/// <!-- Networking context -->
- /// <InputTextBox id="NetConnect"
+ /// <InputView id="NetConnect"
/// padding_left="2"
/// padding_right="2"
/// padding_top="1"
@@ -93,8 +114,8 @@ namespace Client.Properties {
/// <Field input_type="decimal" max_length="15">Server IP:</Field>
/// <Field default="80" input_type="integer" max_length="5">Port:</Field>
/// </Fields>
- /// <Text>Server connection configuration</Text>
- /// </Input [rest of string was truncated]";.
+ /// <Text>@string/NC_head</Text>
+ /// </InputVie [rest of string was truncated]";.
///
internal static string Networking {
get {
@@ -104,8 +125,8 @@ namespace Client.Properties {
///
/// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?>
- ///<Elements xmlns="ConsoleForms">
- /// <DialogBox id="Success"
+ ///<Elements xmlns="Client.ConsoleForms.Graphics">
+ /// <DialogView id="Success"
/// padding_left="2"
/// padding_right="2"
/// padding_top="1"
@@ -114,8 +135,17 @@ namespace Client.Properties {
/// <Option>Quit</Option>
/// </Options>
/// <Text>Login succeeded!</Text>
- /// </DialogBox>
- ///</Elements>.
+ /// </DialogView>
+ ///
+ /// <TextView id="balance"
+ /// padding_left="2"
+ /// padding_right="2"
+ /// padding_top="1"
+ /// padding_bottom="1">
+ /// <Text>Balance: $balance</Text>
+ /// </TextView>
+ ///
+ /// <ListView id= [rest of string was truncated]";.
///
internal static string Session {
get {
@@ -125,10 +155,10 @@ namespace Client.Properties {
///
/// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?>
- ///<Elements xmlns="ConsoleForms">
+ ///<Elements xmlns="Client.ConsoleForms.Graphics">
///
/// <!-- Welcome screen -->
- /// <DialogBox id="WelcomeScreen"
+ /// <DialogView id="WelcomeScreen"
/// padding_left="2"
/// padding_right="2"
/// padding_top="1"
@@ -138,12 +168,74 @@ namespace Client.Properties {
/// <Option event="Setup:Login" close="true">Login</Option>
/// <Option event="Setup:Register" close="true">Register</Option>
/// </Options>
- /// <Text>Welcome to the Tofvesson banking system! To conti [rest of string was truncated]";.
+ /// <Text>Welcome to the Tofvesson banking [rest of string was truncated]";.
///
internal static string Setup {
get {
return ResourceManager.GetString("Setup", resourceCulture);
}
}
+
+ ///
+ /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?>
+ ///<Strings label="English">
+ /// <Entry name="NC_head">Server configuration</Entry>
+ /// <Entry name="NC_sec">The selected server's identity could not be verified. This implies that it is not an official server. Continue?</Entry>
+ /// <Entry name="NC_stall">Connecting to server...</Entry>
+ ///
+ /// <Entry name="ERR_empty">One of more required field was empty!</Entry>
+ ///</Strings>.
+ ///
+ internal static string strings_lang_en_GB {
+ get {
+ return ResourceManager.GetString("strings_lang_en_GB", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?>
+ ///<Strings label="English">
+ /// <Entry name="NC_head">Server configuration</Entry>
+ /// <Entry name="NC_sec">The selected server's identity could not be verified. This implies that it is not an official server. Continue?</Entry>
+ /// <Entry name="NC_stall">Connecting to server...</Entry>
+ ///
+ /// <Entry name="ERR_empty">One of more required field was empty!</Entry>
+ ///</Strings>.
+ ///
+ internal static string strings_lang_en_US {
+ get {
+ return ResourceManager.GetString("strings_lang_en_US", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?>
+ ///<Strings label="Svenska">
+ /// <Entry name="NC_head">Serverkonfiguration</Entry>
+ /// <Entry name="NC_sec">Den valda serverns identitet kunde inte verifieras. Detta innebär att det inte är en officiell server. Fortsätt?</Entry>
+ /// <Entry name="NC_stall">Kopplar upp mot servern...</Entry>
+ ///
+ /// <Entry name="ERR_empty">Ett eller fler obligatoriska inputfält är tomma!</Entry>
+ ///</Strings>.
+ ///
+ internal static string strings_lang_sv_SE {
+ get {
+ return ResourceManager.GetString("strings_lang_sv_SE", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?>
+ ///<Lang>
+ /// <Default>sv_SE</Default>
+ /// <Fallback priority="0">en_US</Fallback>
+ /// <Fallback priority="1">en_GB></Fallback>
+ ///</Lang>.
+ ///
+ internal static string strings_meta {
+ get {
+ return ResourceManager.GetString("strings_meta", resourceCulture);
+ }
+ }
}
}
diff --git a/Client/Properties/Resources.resx b/Client/Properties/Resources.resx
index 6b23c02..bd259ac 100644
--- a/Client/Properties/Resources.resx
+++ b/Client/Properties/Resources.resx
@@ -124,13 +124,28 @@
..\Resources\0x200.n;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ ..\Resources\Layout\Common.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
+
- ..\Layout\Networking.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
+ ..\Resources\Layout\Networking.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
- ..\Layout\Session.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
+ ..\Resources\Layout\Session.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
- ..\Layout\Setup.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
+ ..\Resources\Layout\Setup.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
+
+
+ ..\Resources\Strings\en_US\strings.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
+
+
+ ..\Resources\Strings\sv_SE\strings.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
+
+
+ ..\Resources\Strings\Meta.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
+
+
+ ..\Resources\Strings\en_GB\strings.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
\ No newline at end of file
diff --git a/Client/Resources/Layout/Common.xml b/Client/Resources/Layout/Common.xml
new file mode 100644
index 0000000..31594e9
--- /dev/null
+++ b/Client/Resources/Layout/Common.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ @string/ERR_empty
+
+
\ No newline at end of file
diff --git a/Client/Layout/Networking.xml b/Client/Resources/Layout/Networking.xml
similarity index 57%
rename from Client/Layout/Networking.xml
rename to Client/Resources/Layout/Networking.xml
index c4af0c3..c8536a9 100644
--- a/Client/Layout/Networking.xml
+++ b/Client/Resources/Layout/Networking.xml
@@ -7,10 +7,10 @@
padding_top="1"
padding_bottom="1">
- Server IP:
- Port:
+ @string/NC_ip
+ @string/NC_port
- Server connection configuration
+ @string/NC_head
-
-
+
+
- The identity of the server could not be verified. Continue?
+ @string/NC_sec
-
+
- Connecting to server...
-
-
-
-
-
-
-
- One or more required input field is empty
+ @string/NC_stall
-
+
- The supplied IP-address is not valid
+ @string/NC_iperr
-
+
- The supplied port is not valid
+ @string/NC_porterr
-
+
- Could not connect to server
+ @string/NC_connerr
\ No newline at end of file
diff --git a/Client/Resources/Layout/Session.xml b/Client/Resources/Layout/Session.xml
new file mode 100644
index 0000000..b4f9846
--- /dev/null
+++ b/Client/Resources/Layout/Session.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+ Login succeeded!
+
+
+
+ @string/SE_bal
+
+
+
+
\ No newline at end of file
diff --git a/Client/Layout/Setup.xml b/Client/Resources/Layout/Setup.xml
similarity index 63%
rename from Client/Layout/Setup.xml
rename to Client/Resources/Layout/Setup.xml
index cba1902..9222c22 100644
--- a/Client/Layout/Setup.xml
+++ b/Client/Resources/Layout/Setup.xml
@@ -9,10 +9,10 @@
padding_bottom="1"
width="42">
-
-
+
+
- Welcome to the Tofvesson banking system! To continue, press [ENTER] To go back, press [ESCAPE]
+ @string/SU_welcome
@@ -24,11 +24,11 @@
width="35"
back="Setup:WelcomeScreen">
- Username:
- Password:
- Repeat password:
+ @string/SU_usr
+ @string/SU_pwd
+ @string/SU_pwdrep
- Register Account
+ @string/SU_reg
- Registering...
+ @string/SU_regstall
-
+
- An account with this username already exists!
+ @string/SU_dup
-
+
- The entered passwords don't match!
+ @string/SU_mismatch
Yes
- The password you have supplied has been deemed to be weak. Are you sure you want to continue?
+ @string/SU_weak
@@ -86,10 +86,10 @@
width="35"
back="Setup:WelcomeScreen">
- Username:
- Password:
+ @string/SU_usr
+ @string/SU_pwd
- Log in
+ @string/SU_login
- Authenticating...
+ @string/SU_authstall
-
-
-
-
-
-
- One or more required input field is empty
-
-
+
- The given username or password was incorrect
+ @string/SU_usrerr
\ No newline at end of file
diff --git a/Client/Resources/Strings/Meta.xml b/Client/Resources/Strings/Meta.xml
new file mode 100644
index 0000000..ff86686
--- /dev/null
+++ b/Client/Resources/Strings/Meta.xml
@@ -0,0 +1,6 @@
+
+
+ sv_SE
+ en_US
+ en_GB
+
\ No newline at end of file
diff --git a/Client/Resources/Strings/en_GB/strings.xml b/Client/Resources/Strings/en_GB/strings.xml
new file mode 100644
index 0000000..72ded50
--- /dev/null
+++ b/Client/Resources/Strings/en_GB/strings.xml
@@ -0,0 +1,39 @@
+
+
+ Server configuration
+ The selected server's identity could not be verified. This implies that it is not an official server. Continue?
+ Connecting to server...
+ Continue
+ Cancel
+ Server IP:
+ Port:
+ The supplied IP-address is not valid
+ The supplied port is not valid
+ Could not connect to server
+
+ Welcome to the Tofvesson banking system! To continue, press [ENTER] To go back, press [ESCAPE]
+ Register Account
+ Registering...
+ An account with this username already exists!
+ The entered passwords don't match!
+ The password you have supplied has been deemed to be weak. Are you sure you want to continue?
+ Log in
+ Authenticating...
+ The given username or password was incorrect
+ Username:
+ Password:
+ Repeat password:
+ Register
+ Login
+
+ Balance: $1
+ View transaction history
+ Transfer funds
+ Update password
+
+ Ok
+ Yes
+ No
+
+ One of more required field was empty!
+
\ No newline at end of file
diff --git a/Client/Resources/Strings/en_US/strings.xml b/Client/Resources/Strings/en_US/strings.xml
new file mode 100644
index 0000000..72ded50
--- /dev/null
+++ b/Client/Resources/Strings/en_US/strings.xml
@@ -0,0 +1,39 @@
+
+
+ Server configuration
+ The selected server's identity could not be verified. This implies that it is not an official server. Continue?
+ Connecting to server...
+ Continue
+ Cancel
+ Server IP:
+ Port:
+ The supplied IP-address is not valid
+ The supplied port is not valid
+ Could not connect to server
+
+ Welcome to the Tofvesson banking system! To continue, press [ENTER] To go back, press [ESCAPE]
+ Register Account
+ Registering...
+ An account with this username already exists!
+ The entered passwords don't match!
+ The password you have supplied has been deemed to be weak. Are you sure you want to continue?
+ Log in
+ Authenticating...
+ The given username or password was incorrect
+ Username:
+ Password:
+ Repeat password:
+ Register
+ Login
+
+ Balance: $1
+ View transaction history
+ Transfer funds
+ Update password
+
+ Ok
+ Yes
+ No
+
+ One of more required field was empty!
+
\ No newline at end of file
diff --git a/Client/Resources/Strings/sv_SE/strings.xml b/Client/Resources/Strings/sv_SE/strings.xml
new file mode 100644
index 0000000..8157cf9
--- /dev/null
+++ b/Client/Resources/Strings/sv_SE/strings.xml
@@ -0,0 +1,8 @@
+
+
+ Serverkonfiguration
+ Den valda serverns identitet kunde inte verifieras. Detta innebär att det inte är en officiell server. Fortsätt?
+ Kopplar upp mot servern...
+
+ Ett eller fler obligatoriska inputfält är tomma!
+
\ No newline at end of file
diff --git a/Common/RSA.cs b/Common/RSA.cs
index 92859a7..077f0f9 100644
--- a/Common/RSA.cs
+++ b/Common/RSA.cs
@@ -178,5 +178,16 @@ namespace Tofvesson.Crypto
public override bool Equals(object obj)
=> obj is RSA && ((RSA)obj).CanDecrypt == CanDecrypt && ((RSA)obj).e.Equals(e) && ((RSA)obj).n.Equals(n) && (!CanDecrypt || ((RSA)obj).d.Equals(d));
+
+ public override int GetHashCode()
+ {
+ var hashCode = 2073836280;
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(e);
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(n);
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(d);
+ hashCode = hashCode * -1521134295 + CanEncrypt.GetHashCode();
+ hashCode = hashCode * -1521134295 + CanDecrypt.GetHashCode();
+ return hashCode;
+ }
}
}
diff --git a/Server/Database.cs b/Server/Database.cs
index cf5ff6d..3d07cd7 100644
--- a/Server/Database.cs
+++ b/Server/Database.cs
@@ -403,6 +403,16 @@ namespace Server
return true;
}
+
+ public override int GetHashCode()
+ {
+ var hashCode = 495068346;
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Text);
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Name);
+ hashCode = hashCode * -1521134295 + EqualityComparer>.Default.GetHashCode(Attributes);
+ hashCode = hashCode * -1521134295 + EqualityComparer>.Default.GetHashCode(NestedEntries);
+ return hashCode;
+ }
}
public class User