aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Data/Localization.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Data/Localization.cs')
-rw-r--r--src/WixToolset.Data/Localization.cs372
1 files changed, 372 insertions, 0 deletions
diff --git a/src/WixToolset.Data/Localization.cs b/src/WixToolset.Data/Localization.cs
new file mode 100644
index 00000000..658ce14a
--- /dev/null
+++ b/src/WixToolset.Data/Localization.cs
@@ -0,0 +1,372 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Data
4{
5 using System;
6 using System.Collections;
7 using System.Collections.Generic;
8 using System.Diagnostics;
9 using System.Diagnostics.CodeAnalysis;
10 using System.Globalization;
11 using System.IO;
12 using System.Linq;
13 using System.Reflection;
14 using System.Xml;
15 using System.Xml.Linq;
16 using System.Xml.Schema;
17 using WixToolset.Data.Msi;
18 using WixToolset.Data.Rows;
19
20 /// <summary>
21 /// Object that represents a localization file.
22 /// </summary>
23 public sealed class Localization
24 {
25 private static string XmlElementName = "localization";
26
27 private Dictionary<string, WixVariableRow> variables = new Dictionary<string, WixVariableRow>();
28 private Dictionary<string, LocalizedControl> localizedControls = new Dictionary<string, LocalizedControl>();
29
30 /// <summary>
31 /// Instantiates a new localization object.
32 /// </summary>
33 public Localization(int codepage, string culture, IDictionary<string, WixVariableRow> variables, IDictionary<string, LocalizedControl> localizedControls)
34 {
35 this.Codepage = codepage;
36 this.Culture = String.IsNullOrEmpty(culture) ? String.Empty : culture.ToLowerInvariant();
37 this.variables = new Dictionary<string, WixVariableRow>(variables);
38 this.localizedControls = new Dictionary<string, LocalizedControl>(localizedControls);
39 }
40
41 /// <summary>
42 /// Gets the codepage.
43 /// </summary>
44 /// <value>The codepage.</value>
45 public int Codepage { get; private set; }
46
47 /// <summary>
48 /// Gets the culture.
49 /// </summary>
50 /// <value>The culture.</value>
51 public string Culture { get; private set; }
52
53 /// <summary>
54 /// Gets the variables.
55 /// </summary>
56 /// <value>The variables.</value>
57 public ICollection<WixVariableRow> Variables
58 {
59 get { return this.variables.Values; }
60 }
61
62 /// <summary>
63 /// Gets the localized controls.
64 /// </summary>
65 /// <value>The localized controls.</value>
66 public ICollection<KeyValuePair<string, LocalizedControl>> LocalizedControls
67 {
68 get { return this.localizedControls; }
69 }
70
71 /// <summary>
72 /// Merge the information from another localization object into this one.
73 /// </summary>
74 /// <param name="localization">The localization object to be merged into this one.</param>
75 public void Merge(Localization localization)
76 {
77 foreach (WixVariableRow wixVariableRow in localization.Variables)
78 {
79 WixVariableRow existingWixVariableRow;
80 if (!this.variables.TryGetValue(wixVariableRow.Id, out existingWixVariableRow) || (existingWixVariableRow.Overridable && !wixVariableRow.Overridable))
81 {
82 variables[wixVariableRow.Id] = wixVariableRow;
83 }
84 else if (!wixVariableRow.Overridable)
85 {
86 throw new WixException(WixDataErrors.DuplicateLocalizationIdentifier(wixVariableRow.SourceLineNumbers, wixVariableRow.Id));
87 }
88 }
89 }
90
91 /// <summary>
92 /// Loads a localization file from a stream.
93 /// </summary>
94 /// <param name="reader">XmlReader where the intermediate is persisted.</param>
95 /// <param name="tableDefinitions">Collection containing TableDefinitions to use when loading the localization file.</param>
96 /// <returns>Returns the loaded localization.</returns>
97 internal static Localization Read(XmlReader reader, TableDefinitionCollection tableDefinitions)
98 {
99 Debug.Assert("localization" == reader.LocalName);
100
101 int codepage = 0;
102 string culture = null;
103 bool empty = reader.IsEmptyElement;
104
105 while (reader.MoveToNextAttribute())
106 {
107 switch (reader.Name)
108 {
109 case "codepage":
110 codepage = Convert.ToInt32(reader.Value, CultureInfo.InvariantCulture);
111 break;
112 case "culture":
113 culture = reader.Value;
114 break;
115 }
116 }
117
118 TableDefinition wixVariableTable = tableDefinitions["WixVariable"];
119 Dictionary<string, WixVariableRow> variables = new Dictionary<string, WixVariableRow>();
120 Dictionary<string, LocalizedControl> localizedControls = new Dictionary<string, LocalizedControl>();
121
122 if (!empty)
123 {
124 bool done = false;
125
126 while (!done && reader.Read())
127 {
128 switch (reader.NodeType)
129 {
130 case XmlNodeType.Element:
131 switch (reader.LocalName)
132 {
133 case "string":
134 WixVariableRow row = Localization.ReadString(reader, wixVariableTable);
135 variables.Add(row.Id, row);
136 break;
137
138 case "ui":
139 LocalizedControl ui = Localization.ReadUI(reader);
140 localizedControls.Add(ui.GetKey(), ui);
141 break;
142
143 default:
144 throw new XmlException();
145 }
146 break;
147 case XmlNodeType.EndElement:
148 done = true;
149 break;
150 }
151 }
152
153 if (!done)
154 {
155 throw new XmlException();
156 }
157 }
158
159 return new Localization(codepage, culture, variables, localizedControls);
160 }
161
162 /// <summary>
163 /// Writes a localization file into an XML format.
164 /// </summary>
165 /// <param name="writer">XmlWriter where the localization file should persist itself as XML.</param>
166 internal void Write(XmlWriter writer)
167 {
168 writer.WriteStartElement(Localization.XmlElementName, Library.XmlNamespaceUri);
169
170 if (-1 != this.Codepage)
171 {
172 writer.WriteAttributeString("codepage", this.Codepage.ToString(CultureInfo.InvariantCulture));
173 }
174
175 if (!String.IsNullOrEmpty(this.Culture))
176 {
177 writer.WriteAttributeString("culture", this.Culture);
178 }
179
180 foreach (WixVariableRow wixVariableRow in this.variables.Values)
181 {
182 writer.WriteStartElement("string", Library.XmlNamespaceUri);
183
184 writer.WriteAttributeString("id", wixVariableRow.Id);
185
186 if (wixVariableRow.Overridable)
187 {
188 writer.WriteAttributeString("overridable", "yes");
189 }
190
191 writer.WriteCData(wixVariableRow.Value);
192
193 writer.WriteEndElement();
194 }
195
196 foreach (string controlKey in this.localizedControls.Keys)
197 {
198 writer.WriteStartElement("ui", Library.XmlNamespaceUri);
199
200 string[] controlKeys = controlKey.Split('/');
201 string dialog = controlKeys[0];
202 string control = controlKeys[1];
203
204 if (!String.IsNullOrEmpty(dialog))
205 {
206 writer.WriteAttributeString("dialog", dialog);
207 }
208
209 if (!String.IsNullOrEmpty(control))
210 {
211 writer.WriteAttributeString("control", control);
212 }
213
214 LocalizedControl localizedControl = this.localizedControls[controlKey];
215
216 if (Common.IntegerNotSet != localizedControl.X)
217 {
218 writer.WriteAttributeString("x", localizedControl.X.ToString());
219 }
220
221 if (Common.IntegerNotSet != localizedControl.Y)
222 {
223 writer.WriteAttributeString("y", localizedControl.Y.ToString());
224 }
225
226 if (Common.IntegerNotSet != localizedControl.Width)
227 {
228 writer.WriteAttributeString("width", localizedControl.Width.ToString());
229 }
230
231 if (Common.IntegerNotSet != localizedControl.Height)
232 {
233 writer.WriteAttributeString("height", localizedControl.Height.ToString());
234 }
235
236 if (MsiInterop.MsidbControlAttributesRTLRO == (localizedControl.Attributes & MsiInterop.MsidbControlAttributesRTLRO))
237 {
238 writer.WriteAttributeString("rightToLeft", "yes");
239 }
240
241 if (MsiInterop.MsidbControlAttributesRightAligned == (localizedControl.Attributes & MsiInterop.MsidbControlAttributesRightAligned))
242 {
243 writer.WriteAttributeString("rightAligned", "yes");
244 }
245
246 if (MsiInterop.MsidbControlAttributesLeftScroll == (localizedControl.Attributes & MsiInterop.MsidbControlAttributesLeftScroll))
247 {
248 writer.WriteAttributeString("leftScroll", "yes");
249 }
250
251 if (!String.IsNullOrEmpty(localizedControl.Text))
252 {
253 writer.WriteCData(localizedControl.Text);
254 }
255
256 writer.WriteEndElement();
257 }
258
259 writer.WriteEndElement();
260 }
261
262 /// <summary>
263 /// Loads a localization file from a stream.
264 /// </summary>
265 /// <param name="reader">XmlReader where the intermediate is persisted.</param>
266 /// <param name="tableDefinitions">Collection containing TableDefinitions to use when loading the localization file.</param>
267 /// <returns>Returns the loaded localization.</returns>
268 private static WixVariableRow ReadString(XmlReader reader, TableDefinition wixVariableTable)
269 {
270 Debug.Assert("string" == reader.LocalName);
271
272 string id = null;
273 string value = null;
274 bool overridable = false;
275 bool empty = reader.IsEmptyElement;
276
277 while (reader.MoveToNextAttribute())
278 {
279 switch (reader.Name)
280 {
281 case "id":
282 id = reader.Value;
283 break;
284 case "overridable":
285 overridable = reader.Value.Equals("yes");
286 break;
287 }
288 }
289
290
291 if (!empty)
292 {
293 reader.Read();
294
295 value = reader.Value;
296
297 reader.Read();
298
299 if (XmlNodeType.EndElement != reader.NodeType)
300 {
301 throw new XmlException();
302 }
303 }
304
305 WixVariableRow wixVariableRow = new WixVariableRow(SourceLineNumber.CreateFromUri(reader.BaseURI), wixVariableTable);
306 wixVariableRow.Id = id;
307 wixVariableRow.Overridable = overridable;
308 wixVariableRow.Value = value;
309
310 return wixVariableRow;
311 }
312
313 private static LocalizedControl ReadUI(XmlReader reader)
314 {
315 Debug.Assert("ui" == reader.LocalName);
316
317 string dialog = null;
318 string control = null;
319 int x = Common.IntegerNotSet;
320 int y = Common.IntegerNotSet;
321 int width = Common.IntegerNotSet;
322 int height = Common.IntegerNotSet;
323 int attributes = Common.IntegerNotSet;
324 string text = null;
325 bool empty = reader.IsEmptyElement;
326
327 while (reader.MoveToNextAttribute())
328 {
329 switch (reader.Name)
330 {
331 case "dialog":
332 dialog = reader.Value;
333 break;
334 case "control":
335 control = reader.Value;
336 break;
337 case "x":
338 x = Convert.ToInt32(reader.Value, CultureInfo.InvariantCulture);
339 break;
340 case "y":
341 y = Convert.ToInt32(reader.Value, CultureInfo.InvariantCulture);
342 break;
343 case "width":
344 width = Convert.ToInt32(reader.Value, CultureInfo.InvariantCulture);
345 break;
346 case "height":
347 height = Convert.ToInt32(reader.Value, CultureInfo.InvariantCulture);
348 break;
349 case "attributes":
350 attributes = Convert.ToInt32(reader.Value, CultureInfo.InvariantCulture);
351 break;
352 }
353 }
354
355 if (!empty)
356 {
357 reader.Read();
358
359 text = reader.Value;
360
361 reader.Read();
362
363 if (XmlNodeType.EndElement != reader.NodeType)
364 {
365 throw new XmlException();
366 }
367 }
368
369 return new LocalizedControl(dialog, control, x, y, width, height, attributes, text);
370 }
371 }
372}