1
1
using System ;
2
2
using System . Collections . Generic ;
3
3
using System . IO ;
4
+ using System . IO . Compression ;
4
5
using System . Linq ;
6
+ using System . Net ;
5
7
using System . Windows ;
6
8
using System . Xml ;
9
+ using Octokit ;
7
10
using SPCode . Utils ;
8
- using static SPCode . Utils . DefaultTranslations ;
9
11
10
12
namespace SPCode . Interop
11
13
{
12
14
public class TranslationProvider
13
15
{
14
- public string [ ] AvailableLanguageIDs ;
15
- public string [ ] AvailableLanguages ;
16
-
16
+ public List < string > AvailableLanguageIDs = new ( ) ;
17
+ public List < string > AvailableLanguages = new ( ) ;
17
18
public bool IsDefault = true ;
18
19
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
+ }
20
40
21
41
/// <summary>
22
42
/// Gets the translation of the specified phrase.
23
43
/// </summary>
24
44
/// <param name="phrase">The phrase to return translated</param>
25
45
/// <returns></returns>
26
- public string Get ( string phrase )
46
+ public static string Translate ( string phrase )
27
47
{
28
- return LangDict . ContainsKey ( phrase ) ? LangDict [ phrase ] : "<empty>" ;
48
+ return _langDictionary . ContainsKey ( phrase ) ? _langDictionary [ phrase ] : "<empty>" ;
29
49
}
30
50
31
51
/// <summary>
32
52
/// Loads the specified language.
33
53
/// </summary>
34
54
/// <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 )
37
57
{
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
+ }
43
64
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
46
69
{
47
- try
70
+ // Fill with defaults first
71
+ if ( initial )
48
72
{
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 )
52
75
{
53
- throw new Exception ( "No Root-Node: \" translations \" found" ) ;
76
+ _langDictionary . Add ( node . Name , node . InnerText ) ;
54
77
}
55
78
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 )
58
81
{
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 ;
71
83
}
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 )
73
99
{
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 ;
84
101
}
85
102
}
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 ) )
87
171
{
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 ) ;
92
173
}
174
+ File . Move ( fInfo . FullName , destination ) ;
93
175
}
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 ) ;
96
197
}
97
198
}
98
199
}
0 commit comments