Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #3698. ResourceManager GetResourceSet doesn't fallback to default for no translated keys. #3699

Merged
merged 2 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions Terminal.Gui/Drawing/ColorStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ namespace Terminal.Gui;
/// </summary>
public static class ColorStrings
{
private static readonly ResourceManager _resourceManager = new (typeof (Strings));

/// <summary>
/// Gets the W3C standard string for <paramref name="color"/>.
/// </summary>
Expand All @@ -21,7 +19,7 @@ public static class ColorStrings
public static string? GetW3CColorName (Color color)
{
// Fetch the color name from the resource file
return _resourceManager.GetString ($"#{color.R:X2}{color.G:X2}{color.B:X2}", CultureInfo.CurrentUICulture);
return GlobalResources.GetString ($"#{color.R:X2}{color.G:X2}{color.B:X2}", CultureInfo.CurrentUICulture);
}

/// <summary>
Expand All @@ -30,14 +28,18 @@ public static class ColorStrings
/// <returns></returns>
public static IEnumerable<string> GetW3CColorNames ()
{
foreach (DictionaryEntry entry in _resourceManager.GetResourceSet (CultureInfo.CurrentUICulture, true, true)!)
{
string keyName = entry.Key.ToString () ?? string.Empty;
foreach (DictionaryEntry entry in GlobalResources.GetResourceSet (
BDisp marked this conversation as resolved.
Show resolved Hide resolved
CultureInfo.CurrentUICulture,
true,
true,
e =>
{
string keyName = e.Key.ToString () ?? string.Empty;

if (entry.Value is string colorName && keyName.StartsWith ('#'))
{
yield return colorName;
}
return e.Value is string && keyName.StartsWith ('#');
})!)
{
yield return (entry.Value as string)!;
}
}

Expand All @@ -50,7 +52,7 @@ public static IEnumerable<string> GetW3CColorNames ()
public static bool TryParseW3CColorName (string name, out Color color)
{
// Iterate through all resource entries to find the matching color name
foreach (DictionaryEntry entry in _resourceManager.GetResourceSet (CultureInfo.CurrentUICulture, true, true)!)
foreach (DictionaryEntry entry in GlobalResources.GetResourceSet (CultureInfo.CurrentUICulture, true, true)!)
{
if (entry.Value is string colorName && colorName.Equals (name, StringComparison.OrdinalIgnoreCase))
{
Expand Down
70 changes: 70 additions & 0 deletions Terminal.Gui/Resources/GlobalResources.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#nullable enable

using System.Collections;
using System.Globalization;
using System.Resources;

namespace Terminal.Gui.Resources;

/// <summary>
/// Provide static access to the ResourceManagerWrapper
/// </summary>
public static class GlobalResources
{
private static readonly ResourceManagerWrapper _resourceManagerWrapper;

static GlobalResources ()
{
// Initialize the ResourceManagerWrapper once
var resourceManager = new ResourceManager (typeof (Strings));
_resourceManagerWrapper = new (resourceManager);
}

/// <summary>
/// Looks up a resource value for a particular name. Looks in the specified CultureInfo, and if not found, all parent
/// CultureInfos.
/// </summary>
/// <param name="name"></param>
/// <param name="culture"></param>
/// <returns>Null if the resource was not found in the current culture or the invariant culture.</returns>
public static object GetObject (string name, CultureInfo culture = null!) { return _resourceManagerWrapper.GetObject (name, culture); }

/// <summary>
/// Looks up a set of resources for a particular CultureInfo. This is not useful for most users of the ResourceManager
/// - call GetString() or GetObject() instead. The parameters let you control whether the ResourceSet is created if it
/// hasn't yet been loaded and if parent CultureInfos should be loaded as well for resource inheritance.
/// </summary>
/// <param name="culture"></param>
/// <param name="createIfNotExists"></param>
/// <param name="tryParents"></param>
/// <returns></returns>
public static ResourceSet? GetResourceSet (CultureInfo culture, bool createIfNotExists, bool tryParents)
{
return _resourceManagerWrapper.GetResourceSet (culture, createIfNotExists, tryParents)!;
}

/// <summary>
/// Looks up a set of resources for a particular CultureInfo. This is not useful for most users of the ResourceManager
/// - call GetString() or GetObject() instead. The parameters let you control whether the ResourceSet is created if it
/// hasn't yet been loaded and if parent CultureInfos should be loaded as well for resource inheritance. Allows
/// filtering of resources.
/// </summary>
/// <param name="culture"></param>
/// <param name="createIfNotExists"></param>
/// <param name="tryParents"></param>
/// <param name="filter"></param>
/// <returns></returns>
public static ResourceSet? GetResourceSet (CultureInfo culture, bool createIfNotExists, bool tryParents, Func<DictionaryEntry, bool>? filter)
{
return _resourceManagerWrapper.GetResourceSet (culture, createIfNotExists, tryParents, filter)!;
}

/// <summary>
/// Looks up a resource value for a particular name. Looks in the specified CultureInfo, and if not found, all parent
/// CultureInfos.
/// </summary>
/// <param name="name"></param>
/// <param name="culture"></param>
/// <returns>Null if the resource was not found in the current culture or the invariant culture.</returns>
public static string GetString (string name, CultureInfo? culture = null!) { return _resourceManagerWrapper.GetString (name, culture); }
}
112 changes: 112 additions & 0 deletions Terminal.Gui/Resources/ResourceManagerWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#nullable enable

using System.Collections;
using System.Globalization;
using System.Resources;

namespace Terminal.Gui.Resources;

internal class ResourceManagerWrapper (ResourceManager resourceManager)
{
private readonly ResourceManager _resourceManager = resourceManager ?? throw new ArgumentNullException (nameof (resourceManager));

// Optionally, expose other ResourceManager methods as needed
public object GetObject (string name, CultureInfo culture = null!)
{
object value = _resourceManager.GetObject (name, culture)!;

if (Equals (culture, CultureInfo.InvariantCulture))
{
return value;
}

if (value is null)
{
value = _resourceManager.GetObject (name, CultureInfo.InvariantCulture)!;
}

return value;
}

public ResourceSet? GetResourceSet (CultureInfo culture, bool createIfNotExists, bool tryParents)
{
ResourceSet value = _resourceManager.GetResourceSet (culture, createIfNotExists, tryParents)!;

if (Equals (culture, CultureInfo.InvariantCulture))
{
return value;
}

if (value!.Cast<DictionaryEntry> ().Any ())
{
value = _resourceManager.GetResourceSet (CultureInfo.InvariantCulture, createIfNotExists, tryParents)!;
}

return value;
}

public ResourceSet? GetResourceSet (CultureInfo culture, bool createIfNotExists, bool tryParents, Func<DictionaryEntry, bool>? filter)
{
ResourceSet value = _resourceManager.GetResourceSet (culture, createIfNotExists, tryParents)!;

IEnumerable<DictionaryEntry> filteredEntries = value.Cast<DictionaryEntry> ().Where (filter ?? (_ => true));

ResourceSet? filteredValue = ConvertToResourceSet (filteredEntries);

if (Equals (culture, CultureInfo.InvariantCulture))
{
return filteredValue;
}

if (!filteredValue!.Cast<DictionaryEntry> ().Any ())
{
filteredValue = GetResourceSet (CultureInfo.InvariantCulture, createIfNotExists, tryParents, filter)!;
}

return filteredValue;
}

public string GetString (string name, CultureInfo? culture = null!)
{
// Attempt to get the string for the specified culture
string value = _resourceManager.GetString (name, culture)!;

// If it's already using the invariant culture return
if (Equals (culture, CultureInfo.InvariantCulture))
{
return value;
}

// If the string is empty or null, fall back to the invariant culture
if (string.IsNullOrEmpty (value))
{
value = _resourceManager.GetString (name, CultureInfo.InvariantCulture)!;
}

return value;
}

private static ResourceSet? ConvertToResourceSet (IEnumerable<DictionaryEntry> entries)
{
using var memoryStream = new MemoryStream ();

using var resourceWriter = new ResourceWriter (memoryStream);

// Add each DictionaryEntry to the ResourceWriter
foreach (DictionaryEntry entry in entries)
{
resourceWriter.AddResource ((string)entry.Key, entry.Value);
}

// Finish writing to the stream
resourceWriter.Generate ();

// Reset the stream position to the beginning
memoryStream.Position = 0;

// Create a ResourceSet from the MemoryStream
var resourceSet = new ResourceSet (memoryStream);

return resourceSet;
}
}
Loading
Loading