Support filtering localizations by culture
Rob Mensching committed
Dec 31, 2017 at 02:17 UTC
651ad904724f32f5e993fa73aa11a611d95a1a10
4 files changed
+95
-14
src/WixToolset.Core/CommandLine/BuildCommand.cs
+5
-4
@@ -13,20 +13,20 @@ namespace WixToolset.Core.CommandLine
13
14
internal class BuildCommand : ICommandLineCommand
15
{
16
- public BuildCommand(IServiceProvider serviceProvider, IEnumerable<SourceFile> sources, IDictionary<string, string> preprocessorVariables, IEnumerable<string> locFiles, IEnumerable<string> libraryFiles, string outputPath, OutputType outputType, string cabCachePath, IEnumerable<string> cultures, bool bindFiles, IEnumerable<BindPath> bindPaths, IEnumerable<string> includeSearchPaths, string intermediateFolder, string contentsFile, string outputsFile, string builtOutputsFile)
16
+ public BuildCommand(IServiceProvider serviceProvider, IEnumerable<SourceFile> sources, IDictionary<string, string> preprocessorVariables, IEnumerable<string> locFiles, IEnumerable<string> libraryFiles, IEnumerable<string> filterCultures, string outputPath, OutputType outputType, string cabCachePath, bool bindFiles, IEnumerable<BindPath> bindPaths, IEnumerable<string> includeSearchPaths, string intermediateFolder, string contentsFile, string outputsFile, string builtOutputsFile)
17
{
18
this.ServiceProvider = serviceProvider;
19
this.Messaging = serviceProvider.GetService<IMessaging>();
20
this.ExtensionManager = serviceProvider.GetService<IExtensionManager>();
21
this.LocFiles = locFiles;
22
this.LibraryFiles = libraryFiles;
23
+ this.FilterCultures = filterCultures;
24
this.PreprocessorVariables = preprocessorVariables;
25
this.SourceFiles = sources;
26
this.OutputPath = outputPath;
27
this.OutputType = outputType;
28
29
this.CabCachePath = cabCachePath;
29
- this.Cultures = cultures;
30
this.BindFiles = bindFiles;
31
this.BindPaths = bindPaths;
32
this.IncludeSearchPaths = includeSearchPaths;
@@ -43,6 +43,8 @@ namespace WixToolset.Core.CommandLine
43
44
public IExtensionManager ExtensionManager { get; }
45
46
+ public IEnumerable<string> FilterCultures { get; }
47
+
48
public IEnumerable<string> IncludeSearchPaths { get; }
49
50
public IEnumerable<string> LocFiles { get; }
@@ -59,8 +61,6 @@ namespace WixToolset.Core.CommandLine
61
62
public string CabCachePath { get; }
63
62
- public IEnumerable<string> Cultures { get; }
63
-
64
public bool BindFiles { get; }
65
66
public IEnumerable<BindPath> BindPaths { get; }
@@ -205,6 +205,7 @@ namespace WixToolset.Core.CommandLine
205
{
206
var resolver = new Resolver(this.ServiceProvider);
207
resolver.BindPaths = this.BindPaths;
208
+ resolver.FilterCultures = this.FilterCultures;
209
resolver.IntermediateFolder = this.IntermediateFolder;
210
resolver.IntermediateRepresentation = output;
211
resolver.Localizations = localizations;
src/WixToolset.Core/CommandLine/CommandLineParser.cs
+30
-2
@@ -114,7 +114,7 @@ namespace WixToolset.Core.CommandLine
114
cmdline.GetNextArgumentOrError(ref cabCachePath);
115
return true;
116
117
- case "cultures":
117
+ case "culture":
118
cmdline.GetNextArgumentOrError(cultures);
119
return true;
120
case "contentsfile":
@@ -210,8 +210,9 @@ namespace WixToolset.Core.CommandLine
210
var sourceFiles = GatherSourceFiles(files, outputFolder);
211
var variables = this.GatherPreprocessorVariables(defines);
212
var bindPathList = this.GatherBindPaths(bindPaths);
213
+ var filterCultures = CalculateFilterCultures(cultures);
214
var type = CalculateOutputType(outputType, outputFile);
214
- return new BuildCommand(this.ServiceProvider, sourceFiles, variables, locFiles, libraryFiles, outputFile, type, cabCachePath, cultures, bindFiles, bindPathList, includePaths, intermediateFolder, contentsFile, outputsFile, builtOutputsFile);
215
+ return new BuildCommand(this.ServiceProvider, sourceFiles, variables, locFiles, libraryFiles, filterCultures, outputFile, type, cabCachePath, bindFiles, bindPathList, includePaths, intermediateFolder, contentsFile, outputsFile, builtOutputsFile);
216
}
217
218
case Commands.Compile:
@@ -225,6 +226,33 @@ namespace WixToolset.Core.CommandLine
226
return null;
227
}
228
229
+ private static IEnumerable<string> CalculateFilterCultures(List<string> cultures)
230
+ {
231
+ var result = new List<string>();
232
+
233
+ if (cultures == null)
234
+ {
235
+ }
236
+ else if (cultures.Count == 1 && cultures[0].Equals("null", StringComparison.OrdinalIgnoreCase))
237
+ {
238
+ // When null is used treat it as if cultures wasn't specified. This is
239
+ // needed for batching in the MSBuild task since MSBuild doesn't support
240
+ // empty items.
241
+ }
242
+ else
243
+ {
244
+ foreach (var culture in cultures)
245
+ {
246
+ // Neutral is different from null. For neutral we still want to do culture filtering.
247
+ // Set the culture to the empty string = identifier for the invariant culture.
248
+ var filter = (culture.Equals("neutral", StringComparison.OrdinalIgnoreCase)) ? String.Empty : culture;
249
+ result.Add(filter);
250
+ }
251
+ }
252
+
253
+ return result;
254
+ }
255
+
256
private static OutputType CalculateOutputType(string outputType, string outputFile)
257
{
258
if (String.IsNullOrEmpty(outputType))
src/WixToolset.Core/ResolveContext.cs
+2
@@ -25,6 +25,8 @@ namespace WixToolset.Core
25
26
public IEnumerable<IExtensionData> ExtensionData { get; set; }
27
28
+ public IEnumerable<string> FilterCultures { get; set; }
29
+
30
public string IntermediateFolder { get; set; }
31
32
public Intermediate IntermediateRepresentation { get; set; }
src/WixToolset.Core/Resolver.cs
+58
-8
@@ -31,6 +31,8 @@ namespace WixToolset.Core
31
32
public IEnumerable<Localization> Localizations { get; set; }
33
34
+ public IEnumerable<string> FilterCultures { get; set; }
35
+
36
public ResolveResult Execute()
37
{
38
var extensionManager = this.ServiceProvider.GetService<IExtensionManager>();
@@ -40,6 +42,7 @@ namespace WixToolset.Core
42
context.BindPaths = this.BindPaths;
43
context.Extensions = extensionManager.Create<IResolverExtension>();
44
context.ExtensionData = extensionManager.Create<IExtensionData>();
45
+ context.FilterCultures = this.FilterCultures;
46
context.IntermediateFolder = this.IntermediateFolder;
47
context.IntermediateRepresentation = this.IntermediateRepresentation;
48
context.Localizations = this.Localizations;
@@ -207,29 +210,76 @@ namespace WixToolset.Core
210
{
211
var creator = context.ServiceProvider.GetService<ITupleDefinitionCreator>();
212
213
+ var localizations = FilterLocalizations(context);
214
+
215
+ foreach (var localization in localizations)
216
+ {
217
+ context.VariableResolver.AddLocalization(localization);
218
+ }
219
+
220
+ // Gather all the wix variables.
221
+ var wixVariableTuples = context.IntermediateRepresentation.Sections.SelectMany(s => s.Tuples).OfType<WixVariableTuple>();
222
+ foreach (var tuple in wixVariableTuples)
223
+ {
224
+ context.VariableResolver.AddVariable(tuple.SourceLineNumbers, tuple.WixVariable, tuple.Value, tuple.Overridable);
225
+ }
226
+ }
227
+
228
+ private static IEnumerable<Localization> FilterLocalizations(IResolveContext context)
229
+ {
230
+ var result = new List<Localization>();
231
+ var filter = CalculateCultureFilter(context);
232
+
233
var localizations = context.Localizations.Concat(context.IntermediateRepresentation.Localizations).ToList();
234
212
- // Add localizations from the extensions with data.
235
+ // If there still is no filter, return all localizations.
236
+ AddFilteredLocalizations(result, filter, localizations);
237
+
238
+ // Filter localizations provided by extensions with data.
239
+ var creator = context.ServiceProvider.GetService<ITupleDefinitionCreator>();
240
+
241
foreach (var data in context.ExtensionData)
242
{
243
var library = data.GetLibrary(creator);
244
245
if (library?.Localizations != null)
246
{
219
- localizations.AddRange(library.Localizations);
247
+ var extensionFilter = (!filter.Any() && data.DefaultCulture != null) ? new[] { data.DefaultCulture } : filter;
248
+
249
+ AddFilteredLocalizations(result, extensionFilter, library.Localizations);
250
}
251
}
252
223
- foreach (var localization in localizations)
253
+ return result;
254
+ }
255
+
256
+ private static IEnumerable<string> CalculateCultureFilter(IResolveContext context)
257
+ {
258
+ var filter = context.FilterCultures ?? Array.Empty<string>();
259
+
260
+ // If no filter was specified, look for a language neutral localization file specified
261
+ // from the command-line (not embedded in the intermediate). If found, filter on language
262
+ // neutral.
263
+ if (!filter.Any() && context.Localizations.Any(l => String.IsNullOrEmpty(l.Culture)))
264
{
225
- context.VariableResolver.AddLocalization(localization);
265
+ filter = new[] { String.Empty };
266
}
267
228
- // Gather all the wix variables.
229
- var wixVariableTuples = context.IntermediateRepresentation.Sections.SelectMany(s => s.Tuples).OfType<WixVariableTuple>();
230
- foreach (var tuple in wixVariableTuples)
268
+ return filter;
269
+ }
270
+
271
+ private static void AddFilteredLocalizations(List<Localization> result, IEnumerable<string> filter, IEnumerable<Localization> localizations)
272
+ {
273
+ if (!filter.Any())
274
{
232
- context.VariableResolver.AddVariable(tuple.SourceLineNumbers, tuple.WixVariable, tuple.Value, tuple.Overridable);
275
+ result.AddRange(localizations);
276
+ }
277
+ else // filter localizations in order specified by the filter
278
+ {
279
+ foreach (var culture in filter)
280
+ {
281
+ result.AddRange(localizations.Where(l => culture.Equals(l.Culture, StringComparison.OrdinalIgnoreCase)));
282
+ }
283
}
284
}
285
}