diff --git a/Claunia.Localization.Core/Claunia.Localization.Core.csproj b/Claunia.Localization.Core/Claunia.Localization.Core.csproj new file mode 100644 index 0000000..185a24c --- /dev/null +++ b/Claunia.Localization.Core/Claunia.Localization.Core.csproj @@ -0,0 +1,7 @@ + + + + netstandard1.6 + + + diff --git a/Claunia.Localization.Core/Language.cs b/Claunia.Localization.Core/Language.cs new file mode 100644 index 0000000..15b76ad --- /dev/null +++ b/Claunia.Localization.Core/Language.cs @@ -0,0 +1,32 @@ +namespace Claunia.Localization.Core +{ + /// Enumerates programming languages for parameters + public enum Language + { + C, + ObjectiveC, + CSharp, + Shell, + Python, + Lisp, + EmacsLisp, + PythonBraced, + Librep, + Scheme, + Smalltalk, + Java, + Awk, + ObjectPascal, + Ycp, + Tcl, + Perl, + Php, + GccInternal, + GfcInternal, + Qt, + QtPlural, + Kde, + Boost, + JavaScript + } +} \ No newline at end of file diff --git a/Claunia.Localization.Core/Localization.cs b/Claunia.Localization.Core/Localization.cs new file mode 100644 index 0000000..9469e25 --- /dev/null +++ b/Claunia.Localization.Core/Localization.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.ObjectModel; +using System.Linq; + +namespace Claunia.Localization.Core +{ + /// + /// Represents the localization + /// + public class Localization + { + readonly ObservableCollection messages; + readonly ObservableCollection translators; + + public Localization() + { + Creation = DateTime.UtcNow; + LastWritten = DateTime.UtcNow; + Project = new Project(); + Project.ProjectModified += OnModified; + translators = new ObservableCollection(); + Translators = new ReadOnlyObservableCollection(translators); + translators.CollectionChanged += OnModified; + messages = new ObservableCollection(); + Messages = new ReadOnlyObservableCollection(messages); + messages.CollectionChanged += OnModified; + } + + /// Date this localization has been created + public DateTime Creation { get; } + /// Date this localization has been modified + public DateTime LastWritten { get; private set; } + /// Project this localization belongs to + public Project Project { get; } + /// List of translators that have worked in this localization + public ReadOnlyObservableCollection Translators { get; } + /// + /// List of messages present in this localization + /// + public ReadOnlyObservableCollection Messages { get; } + + void OnModified(object sender, EventArgs args) + { + LastWritten = DateTime.UtcNow; + } + + /// + /// Adds a new translator to the localization + /// + /// Translator full name, english-form, in ASCII + /// Translator e-mail + /// Translator full name, in native form + /// The new translator + public Translator NewTranslator(string name, string email, string nativeName = null) + { + int id = translators.Max(t => t.Id) + 1; + Translator translator = new Translator(id) {Name = name, Email = email}; + translator.Modified += OnModified; + + translators.Add(translator); + + return translator; + } + + /// + /// Removes a translator from the localization + /// + /// Translator to remove + /// true if the translator has been removed successfully, false otherwise + public bool RemoveTranslator(Translator translator) => !(translator is null) && translators.Remove(translator); + + /// + /// Removes a translator from the localization + /// + /// ID of the translator to remove + /// true if the translator has been removed successfully, false otherwise + public bool RemoveTranslator(int id) + { + Translator translator = translators.FirstOrDefault(t => t.Id == id); + return !(translator is null) && translators.Remove(translator); + } + + public Message NewMessage() + { + Message message = new Message(); + message.Modified += OnModified; + + messages.Add(message); + + return message; + } + + public bool RemoveMessage(Message message) => !(message is null) && messages.Remove(message); + + public bool RemoveMessage(string id) + { + Message message = messages.FirstOrDefault(t => t.Id == id); + return !(message is null) && messages.Remove(message); + } + } +} \ No newline at end of file diff --git a/Claunia.Localization.Core/LocalizedString.cs b/Claunia.Localization.Core/LocalizedString.cs new file mode 100644 index 0000000..ebfbd45 --- /dev/null +++ b/Claunia.Localization.Core/LocalizedString.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.ObjectModel; + +namespace Claunia.Localization.Core +{ + /// + /// Represent a localized string + /// + public sealed class LocalizedString + { + readonly ObservableCollection plurals; + string comments; + string locale; + internal EventHandler Modified; + string singular; + int? translator; + + internal LocalizedString() + { + plurals = new ObservableCollection(); + plurals.CollectionChanged += (sender, args) => Modified?.Invoke(this, EventArgs.Empty); + Plurals = new ReadOnlyObservableCollection(plurals); + } + + /// + /// Contains the singular, or only, text for this string + /// + public string Singular + { + get => singular; + set + { + singular = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Which locale this string is in. Format is ll_CC with ll as ISO 639-2 language code and CC as ISO 3166 two letter + /// uppercase country code. _CC can be omitted. + /// + public string Locale + { + get => locale; + set + { + locale = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// ID of the translator, in this localization, that wrote this string + /// + public int? Translator + { + get => translator; + set + { + translator = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Translator comments + /// + public string Comments + { + get => comments; + set + { + comments = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Plural forms for this string + /// + public ReadOnlyObservableCollection Plurals { get; } + + /// + /// Initializes a new plural in this message + /// + /// The newly initialized plural + public Plural NewPlural() + { + Plural parameter = new Plural(); + parameter.Modified += Modified; + plurals.Add(parameter); + + return parameter; + } + + /// + /// Removes a plural + /// + /// The plural to remove + /// true if the plural string has been removed successfully, false otherwise + public bool RemovePlural(Plural parameter) => plurals.Remove(parameter); + } +} \ No newline at end of file diff --git a/Claunia.Localization.Core/Message.cs b/Claunia.Localization.Core/Message.cs new file mode 100644 index 0000000..1c6b8b4 --- /dev/null +++ b/Claunia.Localization.Core/Message.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.ObjectModel; + +namespace Claunia.Localization.Core +{ + /// + /// Represent a message and its translations + /// + public sealed class Message + { + readonly ObservableCollection parameters; + readonly ObservableCollection translations; + string comments; + string context; + string id; + internal EventHandler Modified; + string previousContext; + string reference; + + internal Message() + { + Source = new LocalizedString(); + Source.Modified += Modified; + translations = new ObservableCollection(); + translations.CollectionChanged += (sender, args) => Modified?.Invoke(this, EventArgs.Empty); + parameters = new ObservableCollection(); + parameters.CollectionChanged += (sender, args) => Modified?.Invoke(this, EventArgs.Empty); + Translations = new ReadOnlyObservableCollection(translations); + Parameters = new ReadOnlyObservableCollection(parameters); + } + + /// + /// Describes the context where this message occurs + /// + public string Context + { + get => context; + set + { + context = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Describes the context where the previous version of this message occurred + /// + public string PreviousContext + { + get => previousContext; + set + { + previousContext = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Comments added by the original writer of the message + /// + public string Comments + { + get => comments; + set + { + comments = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Source code line reference or equivalent + /// + public string Reference + { + get => reference; + set + { + reference = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Unique identifier of this message + /// + public string Id + { + get => id; + set + { + id = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Original locale of this message + /// + public LocalizedString Source { get; } + /// + /// List of translations + /// + public ReadOnlyObservableCollection Translations { get; } + /// + /// List of parameters + /// + public ReadOnlyObservableCollection Parameters { get; } + + /// + /// Initializes a new localized string in this message + /// + /// The newly initialized localized string + public LocalizedString NewLocalizedString() + { + LocalizedString localizedString = new LocalizedString(); + localizedString.Modified += Modified; + translations.Add(localizedString); + + return localizedString; + } + + /// + /// Removes a localized string + /// + /// The localized string to remove + /// true if the localized string has been removed successfully, false otherwise + public bool RemoveLocalizedString(LocalizedString localizedString) => translations.Remove(localizedString); + + /// + /// Initializes a new parameter in this message + /// + /// The newly initialized parameter + public Parameter NewParameter() + { + Parameter parameter = new Parameter(); + parameter.Modified += Modified; + parameters.Add(parameter); + + return parameter; + } + + /// + /// Removes a parameter + /// + /// The parameter to remove + /// true if the parameter string has been removed successfully, false otherwise + public bool RemoveParameter(Parameter parameter) => parameters.Remove(parameter); + } +} \ No newline at end of file diff --git a/Claunia.Localization.Core/Parameter.cs b/Claunia.Localization.Core/Parameter.cs new file mode 100644 index 0000000..75281f4 --- /dev/null +++ b/Claunia.Localization.Core/Parameter.cs @@ -0,0 +1,97 @@ +using System; + +namespace Claunia.Localization.Core +{ + /// + /// Explanation of a parameter in a software string to help the translator understand the context and for translation + /// helping software to be able to provide appropriate examples + /// + public class Parameter + { + string description; + int index; + Language language; + long? maximum; + long? minimum; + internal EventHandler Modified; + string type; + + /// + /// Index of parameter in source message + /// + public int Index + { + get => index; + set + { + index = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Programming language for interpretation of messages + /// + public Language Language + { + get => language; + set + { + language = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Simple (single-word) description of parameter type + /// + public string Type + { + get => type; + set + { + type = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Minimum value the parameter can get + /// + public long? Minimum + { + get => minimum; + set + { + minimum = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Maximum value the parameter can get + /// + public long? Maximum + { + get => maximum; + set + { + maximum = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Description of the parameter + /// + public string Description + { + get => description; + set + { + description = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + } +} \ No newline at end of file diff --git a/Claunia.Localization.Core/Plural.cs b/Claunia.Localization.Core/Plural.cs new file mode 100644 index 0000000..e0b33eb --- /dev/null +++ b/Claunia.Localization.Core/Plural.cs @@ -0,0 +1,40 @@ +using System; + +namespace Claunia.Localization.Core +{ + /// + /// Contains the plural forms of a string + /// + public class Plural + { + int items; + internal EventHandler Modified; + string text; + + /// + /// Minimum number (inclusive) of items named to use this plural form + /// + public int Items + { + get => items; + set + { + items = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Plural form of the string + /// + public string Text + { + get => text; + set + { + text = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + } +} \ No newline at end of file diff --git a/Claunia.Localization.Core/Project.cs b/Claunia.Localization.Core/Project.cs new file mode 100644 index 0000000..ff668e3 --- /dev/null +++ b/Claunia.Localization.Core/Project.cs @@ -0,0 +1,51 @@ +using System; + +namespace Claunia.Localization.Core +{ + public class Project + { + string name; + + internal EventHandler ProjectModified; + string url; + string version; + /// + /// Project name + /// + public string Name + { + get => name; + set + { + name = value; + ProjectModified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Project version + /// + public string Version + { + get => version; + set + { + version = value; + ProjectModified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Project URL + /// + public string Url + { + get => url; + set + { + url = value; + ProjectModified?.Invoke(this, EventArgs.Empty); + } + } + } +} \ No newline at end of file diff --git a/Claunia.Localization.Core/Translator.cs b/Claunia.Localization.Core/Translator.cs new file mode 100644 index 0000000..c3d05bc --- /dev/null +++ b/Claunia.Localization.Core/Translator.cs @@ -0,0 +1,63 @@ +using System; + +namespace Claunia.Localization.Core +{ + public class Translator + { + string email; + internal EventHandler Modified; + string name; + string nativeName; + + internal Translator(int id) + { + Id = id; + } + + /// + /// Translator ID, unique in the corresponding localization, and sequential + /// + public int Id { get; } + + /// + /// Translator e-mail + /// + public string Email + { + get => email; + set + { + email = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Translator name, in ASCII, english form + /// + public string Name + { + get => name; + set + { + name = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + + /// + /// Translator full name in native form + /// + public string NativeName + { + get => nativeName ?? Name; + set + { + if(value == name) return; + + nativeName = value; + Modified?.Invoke(this, EventArgs.Empty); + } + } + } +} \ No newline at end of file diff --git a/Claunia.Localization.sln b/Claunia.Localization.sln index 8189da1..3c0961d 100644 --- a/Claunia.Localization.sln +++ b/Claunia.Localization.sln @@ -4,6 +4,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Claunia.Localization", "Cla EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Claunia.Localization.Desktop", "Claunia.Localization\Claunia.Localization.Desktop\Claunia.Localization.Desktop.csproj", "{258FEA96-4E93-4C8F-94EF-1319F93B350D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Claunia.Localization.Core", "Claunia.Localization.Core\Claunia.Localization.Core.csproj", "{CFDFDFC7-9662-4C50-B86A-9E579ACD3DF9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -20,5 +22,9 @@ Global {258FEA96-4E93-4C8F-94EF-1319F93B350D}.Release|Any CPU.ActiveCfg = Release|Any CPU {258FEA96-4E93-4C8F-94EF-1319F93B350D}.Release|Any CPU.Build.0 = Release|Any CPU {258FEA96-4E93-4C8F-94EF-1319F93B350D}.Release|Any CPU.Deploy.0 = Release|Any CPU + {CFDFDFC7-9662-4C50-B86A-9E579ACD3DF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CFDFDFC7-9662-4C50-B86A-9E579ACD3DF9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CFDFDFC7-9662-4C50-B86A-9E579ACD3DF9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CFDFDFC7-9662-4C50-B86A-9E579ACD3DF9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal