@joebigelow / wix / commits / 7b013ac6

Support serializing localization information in Intermediates

Rob Mensching committed Dec 30, 2017 at 01:31 UTC 7b013ac66a36e0f73d480ef28771a65f64b57e19
6 files changed +253 -20
src/WixToolset.Data/Bind/BindVariable.cs
+31 -2
@@ -1,9 +1,11 @@
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
3 -namespace WixToolset.Data.Rows
3 +namespace WixToolset.Data.Bind
4 {
5 + using SimpleJson;
6 +
7 /// <summary>
6 - /// Specialization of a row for the WixVariable table.
8 + /// Bind variable.
9 /// </summary>
10 public sealed class BindVariable
11 {
@@ -29,5 +31,32 @@ namespace WixToolset.Data.Rows
31 /// </summary>
32 /// <value>Whether this variable is overridable.</value>
33 public bool Overridable { get; set; }
34 +
35 + internal JsonObject Serialize()
36 + {
37 + var jsonObject = new JsonObject
38 + {
39 + { "name", this.Id },
40 + };
41 +
42 + jsonObject.AddIsNotNullOrEmpty("value", this.Value);
43 + jsonObject.AddNonDefaultValue("overridable", this.Overridable, false);
44 + jsonObject.AddNonDefaultValue("ln", this.SourceLineNumbers?.Serialize());
45 +
46 + return jsonObject;
47 + }
48 +
49 + internal static BindVariable Deserialize(JsonObject jsonObject)
50 + {
51 + var variable = new BindVariable()
52 + {
53 + Id = jsonObject.GetValueOrDefault<string>("name"),
54 + Value = jsonObject.GetValueOrDefault<string>("value"),
55 + Overridable = jsonObject.GetValueOrDefault("overridable", false),
56 + SourceLineNumbers = jsonObject.GetValueOrDefault<SourceLineNumber>("ln")
57 + };
58 +
59 + return variable;
60 + }
61 }
62 }
src/WixToolset.Data/Intermediate.cs
+17 -17
@@ -198,17 +198,17 @@ namespace WixToolset.Data
198 jsonObject.Add("definitions", customDefinitionsJson);
199 }
200
201 - //if (this.Localizations.Any())
202 - //{
203 - // var localizationsJson = new JsonArray();
204 - // foreach (var localization in this.Localizations)
205 - // {
206 - // var localizationJson = localization.Serialize();
207 - // localizationsJson.Add(localizationJson);
208 - // }
209 -
210 - // jsonObject.Add("localizations", localizationsJson);
211 - //}
201 + if (this.Localizations.Any())
202 + {
203 + var localizationsJson = new JsonArray();
204 + foreach (var localization in this.Localizations)
205 + {
206 + var localizationJson = localization.Serialize();
207 + localizationsJson.Add(localizationJson);
208 + }
209 +
210 + jsonObject.Add("localizations", localizationsJson);
211 + }
212
213 var json = SimpleJson.SerializeObject(jsonObject);
214 writer.Write(json);
@@ -272,12 +272,12 @@ namespace WixToolset.Data
272
273 var localizations = new Dictionary<string, Localization>(StringComparer.OrdinalIgnoreCase);
274
275 - //var localizationsJson = jsonObject.GetValueOrDefault<JsonArray>("localizations") ?? new JsonArray();
276 - //foreach (JsonObject localizationJson in localizationsJson)
277 - //{
278 - // var localization = Localization.Deserialize(localizationJson);
279 - // localizations.Add(localization.Culture, localization);
280 - //}
275 + var localizationsJson = jsonObject.GetValueOrDefault<JsonArray>("localizations") ?? new JsonArray();
276 + foreach (JsonObject localizationJson in localizationsJson)
277 + {
278 + var localization = Localization.Deserialize(localizationJson);
279 + localizations.Add(localization.Culture, localization);
280 + }
281
282 return new Intermediate(id, sections, localizations, null);
283 }
src/WixToolset.Data/Json/JsonObjectExtensions.cs
+45
@@ -7,6 +7,51 @@ namespace WixToolset.Data
7
8 internal static class JsonObjectExtensions
9 {
10 + public static JsonObject AddNonDefaultValue(this JsonObject jsonObject, string key, bool value, bool defaultValue = default(bool))
11 + {
12 + if (value != defaultValue)
13 + {
14 + jsonObject.Add(key, value);
15 + }
16 +
17 + return jsonObject;
18 + }
19 +
20 + public static JsonObject AddNonDefaultValue(this JsonObject jsonObject, string key, int value, int defaultValue = default(int))
21 + {
22 + if (value != defaultValue)
23 + {
24 + jsonObject.Add(key, value);
25 + }
26 +
27 + return jsonObject;
28 + }
29 +
30 + public static JsonObject AddNonDefaultValue(this JsonObject jsonObject, string key, object value, object defaultValue = null)
31 + {
32 + if (value != defaultValue)
33 + {
34 + jsonObject.Add(key, value);
35 + }
36 +
37 + return jsonObject;
38 + }
39 +
40 + public static JsonObject AddIsNotNullOrEmpty(this JsonObject jsonObject, string key, string value)
41 + {
42 + if (!String.IsNullOrEmpty(value))
43 + {
44 + jsonObject.Add(key, value);
45 + }
46 +
47 + return jsonObject;
48 + }
49 +
50 + public static bool GetValueOrDefault(this JsonObject jsonObject, string key, bool defaultValue)
51 + {
52 + return jsonObject.TryGetValue(key, out var value) ? Convert.ToBoolean(value) : defaultValue;
53 + }
54 +
55 public static int GetValueOrDefault(this JsonObject jsonObject, string key, int defaultValue)
56 {
57 return jsonObject.TryGetValue(key, out var value) ? Convert.ToInt32(value) : defaultValue;
src/WixToolset.Data/Localization.cs
+71 -1
@@ -7,8 +7,9 @@ namespace WixToolset.Data
7 using System.Diagnostics;
8 using System.Globalization;
9 using System.Xml;
10 + using SimpleJson;
11 using WixToolset.Data.Msi;
11 - using WixToolset.Data.Rows;
12 + using WixToolset.Data.Bind;
13
14 /// <summary>
15 /// Object that represents a localization file.
@@ -74,6 +75,75 @@ namespace WixToolset.Data
75 }
76 }
77
78 + internal JsonObject Serialize()
79 + {
80 + var jsonObject = new JsonObject
81 + {
82 + { "codepage", this.Codepage },
83 + };
84 +
85 + jsonObject.AddIsNotNullOrEmpty("culture", this.Culture);
86 +
87 + // Serialize bind variables.
88 + if (this.Variables.Count > 0)
89 + {
90 + var variablesJson = new JsonArray(this.Variables.Count);
91 +
92 + foreach (var variable in this.Variables)
93 + {
94 + var variableJson = variable.Serialize();
95 +
96 + variablesJson.Add(variableJson);
97 + }
98 +
99 + jsonObject.Add("variables", variablesJson);
100 + }
101 +
102 + // Serialize localized control.
103 + if (this.LocalizedControls.Count > 0)
104 + {
105 + var controlsJson = new JsonObject();
106 +
107 + foreach (var controlWithKey in this.LocalizedControls)
108 + {
109 + var controlJson = controlWithKey.Value.Serialize();
110 +
111 + controlsJson.Add(controlWithKey.Key, controlJson);
112 + }
113 +
114 + jsonObject.Add("controls", controlsJson);
115 + }
116 +
117 + return jsonObject;
118 + }
119 +
120 + internal static Localization Deserialize(JsonObject jsonObject)
121 + {
122 + var codepage = jsonObject.GetValueOrDefault("codepage", 0);
123 + var culture = jsonObject.GetValueOrDefault<string>("culture");
124 +
125 + var variables = new Dictionary<string, BindVariable>();
126 + var variablesJson = jsonObject.GetValueOrDefault("variables", new JsonArray());
127 + foreach (JsonObject variableJson in variablesJson)
128 + {
129 + var bindPath = BindVariable.Deserialize(variableJson);
130 + variables.Add(bindPath.Id, bindPath);
131 + }
132 +
133 + var controls = new Dictionary<string, LocalizedControl>();
134 + var controlsJson = jsonObject.GetValueOrDefault<JsonObject>("controls");
135 + if (controlsJson != null)
136 + {
137 + foreach (var controlJsonWithKey in controlsJson)
138 + {
139 + var control = LocalizedControl.Deserialize((JsonObject)controlJsonWithKey.Value);
140 + controls.Add(controlJsonWithKey.Key, control);
141 + }
142 + }
143 +
144 + return new Localization(codepage, culture, variables, controls);
145 + }
146 +
147 /// <summary>
148 /// Loads a localization file from a stream.
149 /// </summary>
src/WixToolset.Data/LocalizedControl.cs
+33
@@ -3,6 +3,7 @@
3 namespace WixToolset.Data
4 {
5 using System;
6 + using SimpleJson;
7
8 public class LocalizedControl
9 {
@@ -47,5 +48,37 @@ namespace WixToolset.Data
48 /// <param name="control">The id of the control.</param>
49 /// <returns>The localized control id.</returns>
50 public static string GetKey(string dialog, string control) => String.Concat(dialog, "/", control);
51 +
52 + internal JsonObject Serialize()
53 + {
54 + var jsonObject = new JsonObject
55 + {
56 + { "dialog", this.Dialog },
57 + };
58 +
59 + jsonObject.AddIsNotNullOrEmpty("control", this.Control);
60 + jsonObject.AddNonDefaultValue("x", this.X, 0);
61 + jsonObject.AddNonDefaultValue("y", this.Y, 0);
62 + jsonObject.AddNonDefaultValue("width", this.Width, 0);
63 + jsonObject.AddNonDefaultValue("height", this.Height, 0);
64 + jsonObject.AddNonDefaultValue("attribs", this.Attributes, 0);
65 + jsonObject.AddIsNotNullOrEmpty("text", this.Text);
66 +
67 + return jsonObject;
68 + }
69 +
70 + internal static LocalizedControl Deserialize(JsonObject jsonObject)
71 + {
72 + var dialog = jsonObject.GetValueOrDefault<string>("dialog");
73 + var control = jsonObject.GetValueOrDefault<string>("control");
74 + var x = jsonObject.GetValueOrDefault("x", 0);
75 + var y = jsonObject.GetValueOrDefault("y", 0);
76 + var width = jsonObject.GetValueOrDefault("width", 0);
77 + var height = jsonObject.GetValueOrDefault("height", 0);
78 + var attribs = jsonObject.GetValueOrDefault("attribs", 0);
79 + var text = jsonObject.GetValueOrDefault<string>("text");
80 +
81 + return new LocalizedControl(dialog, control, x, y, width, height, attribs, text);
82 + }
83 }
84 }
src/test/WixToolsetTest.Data/SerializeFixture.cs
+56
@@ -6,6 +6,7 @@ namespace WixToolsetTest.Data
6 using System.IO;
7 using System.Linq;
8 using WixToolset.Data;
9 + using WixToolset.Data.Bind;
10 using WixToolset.Data.Tuples;
11 using Xunit;
12
@@ -39,5 +40,60 @@ namespace WixToolsetTest.Data
40 Assert.Equal("TestFolder", tuple.Directory_);
41 Assert.Equal(2, tuple.Attributes);
42 }
43 +
44 + [Fact]
45 + public void CanSaveAndLoadIntermediateWithLocalization()
46 + {
47 + var sln = new SourceLineNumber("test.wxs", 10);
48 +
49 + var bindVariables = new[]
50 + {
51 + new BindVariable { Id = "TestVar1", Value = "TestValue1", SourceLineNumbers = sln },
52 + new BindVariable { Id = "TestVar2", Value = "TestValue2", Overridable = true, SourceLineNumbers = sln },
53 + };
54 +
55 + var controls = new[]
56 + {
57 + new LocalizedControl("TestDlg1", "TestControl1", 10, 10, 100, 100, 0, null),
58 + new LocalizedControl("TestDlg1", "TestControl2", 100, 90, 50, 70, 0, "localized"),
59 + };
60 +
61 + var localizations = new[]
62 + {
63 + new Localization(65001, null, bindVariables.ToDictionary(b => b.Id), controls.ToDictionary(c => c.GetKey()))
64 + };
65 +
66 + var section = new IntermediateSection("test", SectionType.Product, 65001);
67 +
68 + section.Tuples.Add(new ComponentTuple(sln, new Identifier("TestComponent", AccessModifier.Public))
69 + {
70 + ComponentId = new Guid(1, 0, 0, new byte[8]).ToString("B"),
71 + Directory_ = "TestFolder",
72 + Attributes = 2,
73 + });
74 +
75 + var intermediate = new Intermediate("TestIntermediate", new[] { section }, localizations.ToDictionary(l => l.Culture), null);
76 +
77 + var path = Path.GetTempFileName();
78 + try
79 + {
80 + intermediate.Save(path);
81 +
82 + var loaded = Intermediate.Load(path);
83 +
84 + var loc = loaded.Localizations.Single();
85 + Assert.Equal(65001, loc.Codepage);
86 + Assert.Empty(loc.Culture);
87 + Assert.Equal(new[]
88 + {
89 + "TestVar1/TestValue1/False",
90 + "TestVar2/TestValue2/True",
91 + }, loc.Variables.Select(v => String.Join("/", v.Id, v.Value, v.Overridable)).ToArray());
92 + }
93 + finally
94 + {
95 + File.Delete(path);
96 + }
97 + }
98 }
99 }