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
}