Skip to content

Commit bcac849

Browse files
committed
feat: add GenerateLookup setting
1 parent bc82369 commit bcac849

File tree

13 files changed

+311
-11
lines changed

13 files changed

+311
-11
lines changed

Catglobe.ResXFileCodeGenerator.Attributes/ResxSettingsAttribute.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,14 @@ public class ResxSettingsAttribute() : Attribute
1919
public Visibility MembersVisibility { get; set; } = Visibility.Private;
2020

2121
/// <summary>
22-
/// Set if it should add a helper to get translations for Enum members of the given type
22+
/// Set if it should add a helper to get translations for Enum members of the given type.
2323
/// </summary>
2424
public Type? ForEnum { get; set; }
25+
26+
/// <summary>
27+
/// Similar to ForEnum, but more generic in that all keys are available. Notice for very large resx files this may cause compile time performance issues.
28+
/// </summary>
29+
public bool GenerateLookup { get; set; }
30+
2531
}
2632

Catglobe.ResXFileCodeGenerator.Tests/Catglobe.ResXFileCodeGenerator.Tests.csproj

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
1010
</PropertyGroup>
1111

12-
<Import Project="../Catglobe.ResXFileCodeGenerator/build/Catglobe.ResXFileCodeGenerator.props" />
12+
<Import Project="../Catglobe.ResXFileCodeGenerator/buildtransitive/Catglobe.ResXFileCodeGenerator.props" />
1313

1414
<ItemGroup>
1515
<PackageReference Include="Shouldly" Version="4.3.0" />
@@ -39,6 +39,12 @@
3939
<EmbeddedResource Update="IntegrationTests\Test1.resx">
4040
<UseResManager>false</UseResManager>
4141
</EmbeddedResource>
42+
<EmbeddedResource Update="IntegrationTests\TestLookup.da.resx">
43+
<SubType>Designer</SubType>
44+
</EmbeddedResource>
45+
<EmbeddedResource Update="IntegrationTests\TestLookup.resx">
46+
<SubType>Designer</SubType>
47+
</EmbeddedResource>
4248
<EmbeddedResource Update="IntegrationTests\TestDaWhenDaDk2.resx">
4349
<UseResManager>false</UseResManager>
4450
</EmbeddedResource>

Catglobe.ResXFileCodeGenerator.Tests/IntegrationTests/TestEnumAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ public partial class Y
44
{
55
internal partial class X
66
{
7-
[ResxSettings(ForEnum = typeof(XEnum), MembersVisibility = Visibility.Public)]
7+
[ResxSettings(ForEnum = typeof(XEnum), MembersVisibility = Visibility.Public, GenerateLookup = true)]
88
private partial class Z<T3>
99
{
1010

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
namespace Catglobe.ResXFileCodeGenerator.Tests.IntegrationTests;
2+
3+
[ResxSettings(GenerateLookup = true, MembersVisibility = Visibility.Public)]
4+
internal partial class TestLookup;
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<root>
3+
<!--
4+
Microsoft ResX Schema
5+
6+
Version 1.3
7+
8+
The primary goals of this format is to allow a simple XML format
9+
that is mostly human readable. The generation and parsing of the
10+
various data types are done through the TypeConverter classes
11+
associated with the data types.
12+
13+
Example:
14+
15+
... ado.net/XML headers & schema ...
16+
<resheader name="resmimetype">text/microsoft-resx</resheader>
17+
<resheader name="version">1.3</resheader>
18+
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
19+
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
20+
<data name="Name1">this is my long string</data>
21+
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
22+
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
23+
[base64 mime encoded serialized .NET Framework object]
24+
</data>
25+
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
26+
[base64 mime encoded string representing a byte array form of the .NET Framework object]
27+
</data>
28+
29+
There are any number of "resheader" rows that contain simple
30+
name/value pairs.
31+
32+
Each data row contains a name, and value. The row also contains a
33+
type or mimetype. Type corresponds to a .NET class that support
34+
text/value conversion through the TypeConverter architecture.
35+
Classes that don't support this are serialized and stored with the
36+
mimetype set.
37+
38+
The mimetype is used for serialized objects, and tells the
39+
ResXResourceReader how to depersist the object. This is currently not
40+
extensible. For a given mimetype the value must be set accordingly:
41+
42+
Note - application/x-microsoft.net.object.binary.base64 is the format
43+
that the ResXResourceWriter will generate, however the reader can
44+
read any of the formats listed below.
45+
46+
mimetype: application/x-microsoft.net.object.binary.base64
47+
value : The object must be serialized with
48+
: System.Serialization.Formatters.Binary.BinaryFormatter
49+
: and then encoded with base64 encoding.
50+
51+
mimetype: application/x-microsoft.net.object.soap.base64
52+
value : The object must be serialized with
53+
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
54+
: and then encoded with base64 encoding.
55+
56+
mimetype: application/x-microsoft.net.object.bytearray.base64
57+
value : The object must be serialized into a byte array
58+
: using a System.ComponentModel.TypeConverter
59+
: and then encoded with base64 encoding.
60+
-->
61+
62+
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
63+
<xsd:element name="root" msdata:IsDataSet="true">
64+
<xsd:complexType>
65+
<xsd:choice maxOccurs="unbounded">
66+
<xsd:element name="data">
67+
<xsd:complexType>
68+
<xsd:sequence>
69+
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
70+
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
71+
</xsd:sequence>
72+
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
73+
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
74+
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
75+
</xsd:complexType>
76+
</xsd:element>
77+
<xsd:element name="resheader">
78+
<xsd:complexType>
79+
<xsd:sequence>
80+
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
81+
</xsd:sequence>
82+
<xsd:attribute name="name" type="xsd:string" use="required" />
83+
</xsd:complexType>
84+
</xsd:element>
85+
</xsd:choice>
86+
</xsd:complexType>
87+
</xsd:element>
88+
</xsd:schema>
89+
<resheader name="resmimetype">
90+
<value>text/microsoft-resx</value>
91+
</resheader>
92+
<resheader name="version">
93+
<value>1.3</value>
94+
</resheader>
95+
<resheader name="reader">
96+
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
97+
</resheader>
98+
<resheader name="writer">
99+
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
100+
</resheader>
101+
<data name="CreateDate" xml:space="preserve">
102+
<value>OldestDa</value>
103+
</data>
104+
<data name="CreateDateDescending" xml:space="preserve">
105+
<value>NewestDa</value>
106+
</data>
107+
</root>
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<root>
3+
<!--
4+
Microsoft ResX Schema
5+
6+
Version 1.3
7+
8+
The primary goals of this format is to allow a simple XML format
9+
that is mostly human readable. The generation and parsing of the
10+
various data types are done through the TypeConverter classes
11+
associated with the data types.
12+
13+
Example:
14+
15+
... ado.net/XML headers & schema ...
16+
<resheader name="resmimetype">text/microsoft-resx</resheader>
17+
<resheader name="version">1.3</resheader>
18+
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
19+
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
20+
<data name="Name1">this is my long string</data>
21+
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
22+
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
23+
[base64 mime encoded serialized .NET Framework object]
24+
</data>
25+
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
26+
[base64 mime encoded string representing a byte array form of the .NET Framework object]
27+
</data>
28+
29+
There are any number of "resheader" rows that contain simple
30+
name/value pairs.
31+
32+
Each data row contains a name, and value. The row also contains a
33+
type or mimetype. Type corresponds to a .NET class that support
34+
text/value conversion through the TypeConverter architecture.
35+
Classes that don't support this are serialized and stored with the
36+
mimetype set.
37+
38+
The mimetype is used for serialized objects, and tells the
39+
ResXResourceReader how to depersist the object. This is currently not
40+
extensible. For a given mimetype the value must be set accordingly:
41+
42+
Note - application/x-microsoft.net.object.binary.base64 is the format
43+
that the ResXResourceWriter will generate, however the reader can
44+
read any of the formats listed below.
45+
46+
mimetype: application/x-microsoft.net.object.binary.base64
47+
value : The object must be serialized with
48+
: System.Serialization.Formatters.Binary.BinaryFormatter
49+
: and then encoded with base64 encoding.
50+
51+
mimetype: application/x-microsoft.net.object.soap.base64
52+
value : The object must be serialized with
53+
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
54+
: and then encoded with base64 encoding.
55+
56+
mimetype: application/x-microsoft.net.object.bytearray.base64
57+
value : The object must be serialized into a byte array
58+
: using a System.ComponentModel.TypeConverter
59+
: and then encoded with base64 encoding.
60+
-->
61+
62+
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
63+
<xsd:element name="root" msdata:IsDataSet="true">
64+
<xsd:complexType>
65+
<xsd:choice maxOccurs="unbounded">
66+
<xsd:element name="data">
67+
<xsd:complexType>
68+
<xsd:sequence>
69+
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
70+
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
71+
</xsd:sequence>
72+
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
73+
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
74+
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
75+
</xsd:complexType>
76+
</xsd:element>
77+
<xsd:element name="resheader">
78+
<xsd:complexType>
79+
<xsd:sequence>
80+
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
81+
</xsd:sequence>
82+
<xsd:attribute name="name" type="xsd:string" use="required" />
83+
</xsd:complexType>
84+
</xsd:element>
85+
</xsd:choice>
86+
</xsd:complexType>
87+
</xsd:element>
88+
</xsd:schema>
89+
<resheader name="resmimetype">
90+
<value>text/microsoft-resx</value>
91+
</resheader>
92+
<resheader name="version">
93+
<value>1.3</value>
94+
</resheader>
95+
<resheader name="reader">
96+
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
97+
</resheader>
98+
<resheader name="writer">
99+
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
100+
</resheader>
101+
<data name="CreateDate" xml:space="preserve">
102+
<value>Oldest</value>
103+
</data>
104+
<data name="CreateDateDescending" xml:space="preserve">
105+
<value>Newest</value>
106+
</data>
107+
</root>

Catglobe.ResXFileCodeGenerator.Tests/IntegrationTests/TestResxFiles.cs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,17 @@ public void TestDaWhenDaDKt()
5555
TestDaWhenDaDk2.CreateDate.ShouldBe("OldestDaDK");
5656
}
5757

58-
}
58+
[Fact]
59+
public void Lookup()
60+
{
61+
Thread.CurrentThread.CurrentUICulture = new CultureInfo("da");
62+
TestLookup.ToString("CreateDate").ShouldBe("OldestDa");
63+
Thread.CurrentThread.CurrentUICulture = new CultureInfo("da-DK");
64+
TestLookup.ToString("CreateDate").ShouldBe("OldestDa");
65+
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en");
66+
TestLookup.ToString("CreateDate").ShouldBe("Oldest");
67+
68+
}
5969

60-
[ResxSettings()]
61-
internal partial class Test32
62-
{
63-
6470
}
71+

Catglobe.ResXFileCodeGenerator/Catglobe.ResXFileCodeGenerator.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
</PropertyGroup>
3737

3838
<ItemGroup>
39-
<None Include="build\**">
39+
<None Include="buildTransitive\**">
4040
<Pack>true</Pack>
4141
<PackagePath>build\</PackagePath>
4242
</None>

Catglobe.ResXFileCodeGenerator/ClassSpec.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,11 @@ internal sealed record SettingsData
2020
/// Set if it should add a helper to get translations for Enum members of the given type
2121
/// </summary>
2222
public INamedTypeSymbol? ForEnum { get; set; }
23+
24+
/// <summary>
25+
/// Similar to ForEnum, but more generic in that all keys are available
26+
/// </summary>
27+
public bool GenerateLookup{ get; set; }
28+
2329
}
2430

Catglobe.ResXFileCodeGenerator/StringBuilderGenerator.EnumGenerator.cs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ private void GenerateEnumLookup(
4242
builder.Append(" string");
4343
if (!options.NullForgivingOperators)
4444
builder.Append('?');
45-
builder.AppendLineLF(" ToString(__ENUM e) => e switch {");
45+
builder.Append(" ToString(");
46+
builder.Append(enumRef.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
47+
builder.AppendLineLF(" e) => e switch {");
4648
indent += 4;
4749
foreach (var memberName in enumRef.MemberNames)
4850
{
@@ -63,7 +65,43 @@ private void GenerateEnumLookup(
6365
builder.AppendLineLF(",");
6466
}
6567
builder.Append(' ', indent);
66-
builder.AppendLineLF("_ => string.Empty,");
68+
builder.AppendLineLF(options.NullForgivingOperators ? "_ => string.Empty," : "_ => null,");
69+
indent -= 4;
70+
builder.Append(' ', indent);
71+
builder.AppendLineLF("};");
72+
builder.AppendLineLF();
73+
}
74+
private void GenerateLookup(
75+
(Dictionary<string, (string, IXmlLineInfo)> main, List<Dictionary<string, (string, IXmlLineInfo)>> subfiles)
76+
parsed, FileOptions options, int indent, StringBuilder builder, List<Diagnostic> errorsAndWarnings, CancellationToken cancellationToken)
77+
{
78+
builder.Append(' ', indent);
79+
builder.AppendLineLF("/// <summary>");
80+
builder.Append(' ', indent);
81+
builder.AppendLineLF("/// Looks up a localized string for the given key.");
82+
builder.Append(' ', indent);
83+
builder.AppendLineLF("/// </summary>");
84+
85+
builder.Append(' ', indent);
86+
builder.Append(options.MemberVisibility);
87+
builder.Append(options.StaticMembers ? " static" : string.Empty);
88+
builder.Append(" string");
89+
if (!options.NullForgivingOperators)
90+
builder.Append('?');
91+
builder.AppendLineLF(" ToString(string key) => key switch {");
92+
indent += 4;
93+
foreach (var memberName in parsed.main)
94+
{
95+
builder.Append(' ', indent);
96+
builder.Append('"');
97+
builder.Append(memberName.Key);
98+
builder.Append('"');
99+
builder.Append(" => ");
100+
builder.Append(memberName.Key);
101+
builder.AppendLineLF(",");
102+
}
103+
builder.Append(' ', indent);
104+
builder.AppendLineLF(options.NullForgivingOperators ? "_ => string.Empty," : "_ => null,");
67105
indent -= 4;
68106
builder.Append(' ', indent);
69107
builder.AppendLineLF("};");

0 commit comments

Comments
 (0)