Darp.Utils.ResxSourceGenerator
1.10.0
dotnet add package Darp.Utils.ResxSourceGenerator --version 1.10.0
NuGet\Install-Package Darp.Utils.ResxSourceGenerator -Version 1.10.0
<PackageReference Include="Darp.Utils.ResxSourceGenerator" Version="1.10.0" />
paket add Darp.Utils.ResxSourceGenerator --version 1.10.0
#r "nuget: Darp.Utils.ResxSourceGenerator, 1.10.0"
// Install Darp.Utils.ResxSourceGenerator as a Cake Addin #addin nuget:?package=Darp.Utils.ResxSourceGenerator&version=1.10.0 // Install Darp.Utils.ResxSourceGenerator as a Cake Tool #tool nuget:?package=Darp.Utils.ResxSourceGenerator&version=1.10.0
Darp.Utils.ResxSourceGenerator
A source generator for generating strongly typed singleton resource classes from .resx files.
This implementation was made to support easy updates of the language in the UI by listening to the LanguageChanged
event
and making the class non-static for easier binding and usage as type parameter.
If this does not meet your expectations, check out:
- Microsoft.CodeAnalysis.ResxSourceGenerator
- Meziantou.Framework.ResxSourceGenerator
- Aigamo.ResXGenerator
Usage
To generate sources for your .resx
file, simply include the latest version of the source generator in the corresponding .csproj
<Project>
<ItemGroup>
<PackageReference Include="Darp.Utils.ResxSourceGenerator" Version="X.Y.Z" PrivateAssets="all"/>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="**\*.resx" EmitFormatMethods="true"/>
</ItemGroup>
</Project>
<details> <summary>Generated code</summary>
// <auto-generated/>
#nullable enable
namespace TestProject
{
/// <summary>A strongly typed resource class for '/0/Resources.resx'</summary>
internal sealed partial class Resources
{
private static Resources? _default;
/// <summary>The Default implementation of <see cref="Resources"/></summary>
public static Resources Default => _default ??= new Resources();
public delegate void CultureChangedDelegate(global::System.Globalization.CultureInfo? oldCulture, global::System.Globalization.CultureInfo? newCulture);
/// <summary>Called after the <see cref="Culture"/> was updated. Provides previous culture and the newly set culture</summary>
public event CultureChangedDelegate? CultureChanged;
private global::System.Globalization.CultureInfo? _culture;
/// <summary>Get or set the Culture to be used for all resource lookups issued by this strongly typed resource class.</summary>
public System.Globalization.CultureInfo? Culture
{
get => _culture;
set
{
System.Globalization.CultureInfo? oldCulture = _culture;
_culture = value;
if (!System.Collections.Generic.EqualityComparer<System.Globalization.CultureInfo>.Default.Equals(oldCulture, value))
CultureChanged?.Invoke(oldCulture, value);
}
}
///<summary>Returns the cached ResourceManager instance used by this class.</summary>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public global::System.Resources.ResourceManager ResourceManager { get; } = new global::System.Resources.ResourceManager("TestProject.Resources", typeof(Resources).Assembly);
/// <summary>Get a resource of the <see cref="ResourceManager"/> with the configured <see cref="Culture"/> as a string</summary>
/// <param name="resourceKey">The name of the resource to get</param>
/// <returns>Returns the resource value as a string or the <paramref name="resourceKey"/> if it could not be found</returns>
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public string GetResourceString(string resourceKey) => ResourceManager.GetString(resourceKey, Culture) ?? resourceKey;
private string GetResourceString(string resourceKey, string[]? formatterNames)
{
var value = GetResourceString(resourceKey);
if (formatterNames == null) return value;
for (var i = 0; i < formatterNames.Length; i++)
{
value = value.Replace($"{{{formatterNames[i]}}}", $"{{{i}}}");
}
return value;
}
/// <summary>Get the resource of <see cref="Keys.@Name"/></summary>
/// <value>value {x}</value>
public string @Name => GetResourceString(Keys.@Name);
/// <summary>Format the resource of <see cref="Keys.@Name"/></summary>
/// <value>value {x}</value>
/// <param name="x">The parameter to be used at position {0}</param>
/// <returns>The formatted <see cref="Keys.@Name"/> string</returns>
public string @FormatName(object? x) => string.Format(Culture, GetResourceString(@Name, new[] { "x" }), x);
/// <summary>All keys contained in <see cref="Resources"/></summary>
public static class Keys
{
/// <summary> <list type="table">
/// <item> <term><b>Default</b></term> <description>value {x}</description> </item>
/// <item> <term><b>de-DE</b></term> <description>DE: value {x}</description> </item>
/// </list> </summary>
public const string @Name = @"Name";
}
}
}
</details>
This generated code includes features like
- A lazy
Default
instance which can be used to access the resources - A
CultureChanged
event which will be called each time the language was changed FormatABC
methods which will be generated for each entry with at least one argument- A
Keys
class which provides all the keys - A preview of all possible strings in the XML doc comment
It can be used like this:
string key = TestProject.Resources.Default.Keys.Name; // Name
string nameTemplate = TestProject.Resources.Default.Name; // value {x}
string formattedName = TestProject.Resources.Default.FormatName(x: "1"); // value 1
TestProject.Resources.Default.Culture = CultureInfo.GetCultureInfo("de");
string germanNameTemplate = TestProject.Resources.Default.Name; // DE: value {x}
Configuration
By default, the following configuration is used:
<Project>
<PropertyGroup>
<ResxSourceGenerator_SkipShowResxFilesInHierarchy>true</ResxSourceGenerator_SkipShowResxFilesInHierarchy>
<ResxSourceGenerator_EmitDebugInformation>false</ResxSourceGenerator_EmitDebugInformation>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Darp.Utils.ResxSourceGenerator" Version="X.Y.Z" PrivateAssets="all"/>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Localization\Resources.resx"
GenerateSource="true"
RelativeDir=""
ClassName=""
EmitFormatMethods="false"
Public="false"/>
</ItemGroup>
</Project>
SkipShowResxFilesInHierarchy
By default, there will be a target enabled adding a hierarchy to all of your .resx files with the same name:
| Localization
| Resources1.resx
| Resources1.en-US.resx
| Resources1.de.resx
| Resources2.resx
To disable this behavior, add
<PropertyGroup>
<ResxSourceGenerator_SkipShowResxFilesInHierarchy>true</ResxSourceGenerator_SkipShowResxFilesInHierarchy>
</PropertyGroup>
EmitDebugInformation
You might want to see further debug information about the settings used to generate the class. A header comment will be generated similar to this test
To enable debug data add
<PropertyGroup>
<ResxSourceGenerator_EmitDebugInformation>true</ResxSourceGenerator_EmitDebugInformation>
</PropertyGroup>
GenerateSource
You might not want to include some resource files. For this, specify GenerateSource="false"
<ItemGroup>
<EmbeddedResource Update="Localization\Resources.resx" GenerateSource="false"/>
</ItemGroup>
RelativeDir
You might want to specify a relative path to the resource file after publish. The file will be generated similar to this test
Specify the directory like this:
<ItemGroup>
<EmbeddedResource Update="Localization\Resources.resx" RelativeDir="Relative.Directory"/>
</ItemGroup>
ClassName
By default, the class will be called the way the resource file is. You can specify a custom class name as well The file will be generated similar to this test
Specify the class name like this:
<ItemGroup>
<EmbeddedResource Update="Localization\Resources.resx" ClassName="Some.Name"/>
</ItemGroup>
EmitFormatMethods
For more safety when using parameters in your strings, you can generate FormatABC
methods.
To generate them, add
<ItemGroup>
<EmbeddedResource Update="Localization\Resources.resx" EmitFormatMethods="true"/>
</ItemGroup>
Public
You might need to use the resources outside the project the .resx
file is located in.
To change the access modifier, add
<ItemGroup>
<EmbeddedResource Update="Localization\Resources.resx" Public="true"/>
</ItemGroup>
Diagnostics
DarpResX001 - Empty resource file
This warning occurs, when the source generator has found a .resx
file which does not specify any key-value pairs.
If you intended to skip this file, specify GenerateSource = false. Otherwise, add some values.
DarpResX002 - Invalid Key in resource file
This warning occurs, when the source generator has found an entry with an invalid key which is ignored. For example, those might be empty keys.
To fix this warning, add a valid key name.
DarpResX003 - Missing Value in resource file
This warning occurs, when the source generator has found an entry without a value specified.
To fix this warning, add a value to the key.
DarpResX004 - Duplicate Key in resource file
This warning occurs, when the source generator has found the same key a second time in the same resource file.
To fix this warning, rename the key of the duplicate entry.
DarpResX005 - Missing translation for specific Key
This warning occurs, when the source generator has found multiple related resource files but is missing a key in one of the resource files. Note: This warning will not occur, if a key is present in a translation but not in the default resource file.
To fix this warning, add a translation in the language specific resource file.
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- Microsoft.CodeAnalysis.CSharp (>= 4.11.0)
- Microsoft.CodeAnalysis.CSharp.Workspaces (>= 4.11.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.