diff --git a/Robust.Shared/Localization/ILocalizationManager.cs b/Robust.Shared/Localization/ILocalizationManager.cs index 10c592086d8..802a446b27f 100644 --- a/Robust.Shared/Localization/ILocalizationManager.cs +++ b/Robust.Shared/Localization/ILocalizationManager.cs @@ -1,5 +1,5 @@ using System; -using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using JetBrains.Annotations; using Robust.Shared.ContentPack; @@ -31,11 +31,15 @@ public interface ILocalizationManager /// string GetString(string messageId); + bool TryGetString(string messageId, [NotNullWhen(true)] out string? value); + /// /// Version of that supports arguments. /// string GetString(string messageId, params (string, object)[] args); + bool TryGetString(string messageId, [NotNullWhen(true)] out string? value, params (string, object)[] args); + /// /// Default culture used by other methods when no culture is explicitly specified. /// Changing this also changes the current thread's culture. diff --git a/Robust.Shared/Localization/Loc.cs b/Robust.Shared/Localization/Loc.cs index 11b1b092ddc..9446374599b 100644 --- a/Robust.Shared/Localization/Loc.cs +++ b/Robust.Shared/Localization/Loc.cs @@ -1,5 +1,5 @@ using System; -using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using JetBrains.Annotations; using Robust.Shared.ContentPack; @@ -36,6 +36,11 @@ public static string GetString(string messageId) return LocalizationManager.GetString(messageId); } + public static bool TryGetString(string messageId, [NotNullWhen(true)] out string? message) + { + return LocalizationManager.TryGetString(messageId, out message); + } + /// /// Version of that supports arguments. /// @@ -44,6 +49,14 @@ public static string GetString(string messageId, params (string,object)[] args) return LocalizationManager.GetString(messageId, args); } + public static bool TryGetString( + string messageId, + [NotNullWhen(true)] out string? value, + params (string, object)[] args) + { + return LocalizationManager.TryGetString(messageId, out value, args); + } + /// /// Load data for a culture. /// diff --git a/Robust.Shared/Localization/LocalizationManager.cs b/Robust.Shared/Localization/LocalizationManager.cs index ec3ef4b5416..be63a666eb0 100644 --- a/Robust.Shared/Localization/LocalizationManager.cs +++ b/Robust.Shared/Localization/LocalizationManager.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using Fluent.Net; +using Fluent.Net.RuntimeAst; using JetBrains.Annotations; using Robust.Shared.ContentPack; using Robust.Shared.Log; @@ -20,42 +22,107 @@ internal sealed class LocalizationManager : ILocalizationManagerInternal public string GetString(string messageId) { if (_defaultCulture == null) - { return messageId; - } - var context = _contexts[_defaultCulture]; - var message = context.GetMessage(messageId); - if (message == null) + if (!TryGetString(messageId, out var msg)) { Logger.WarningS("Loc", $"Unknown messageId ({_defaultCulture.IetfLanguageTag}): {messageId}"); - return messageId; + msg = messageId; } - return context.Format(message, null, null); + return msg; + } + + public bool TryGetString(string messageId, [NotNullWhen(true)] out string? value) + { + if (!TryGetNode(messageId, out var context, out var node)) + { + value = null; + return false; + } + + value = context.Format(node, null, null); + return true; } public string GetString(string messageId, params (string, object)[] args0) { if (_defaultCulture == null) - { return messageId; + + if (!TryGetString(messageId, out var msg, args0)) + { + Logger.WarningS("Loc", $"Unknown messageId ({_defaultCulture.IetfLanguageTag}): {messageId}"); + msg = messageId; } - var context = _contexts[_defaultCulture]; - var message = context.GetMessage(messageId); + + return msg; + } + + public bool TryGetString(string messageId, [NotNullWhen(true)] out string? value, params (string, object)[] args0) + { + if (!TryGetNode(messageId, out var context, out var node)) + { + value = null; + return false; + } + var args = new Dictionary(); - foreach (var vari in args0) + foreach (var (k, v) in args0) { - args.Add(vari.Item1, vari.Item2); + args.Add(k, v); } + value = context.Format(node, args, null); + return false; + } + + private bool TryGetNode( + string messageId, + [NotNullWhen(true)] out MessageContext? ctx, + [NotNullWhen(true)] out Node? node) + { + if (_defaultCulture == null) + { + ctx = null; + node = null; + return false; + } + + ctx = _contexts[_defaultCulture]; + string? attribName = null; + + if (messageId.Contains('.')) + { + var split = messageId.Split('.'); + messageId = split[0]; + attribName = split[1]; + } + + var message = ctx.GetMessage(messageId); + if (message == null) { - Logger.WarningS("Loc", $"Unknown messageId ({_defaultCulture.IetfLanguageTag}): {messageId}"); - return messageId; + node = null; + return false; + } + + if (attribName != null) + { + if (!message.Attributes.TryGetValue(attribName, out var attrib)) + { + node = null; + return false; + } + + node = attrib; + } + else + { + node = message; } - return context.Format(message, args, null); + return true; } /// @@ -94,7 +161,7 @@ public void LoadCulture(IResourceManager resourceManager, CultureInfo culture) { var context = new MessageContext( culture.Name, - new MessageContextOptions { UseIsolating = false } + new MessageContextOptions {UseIsolating = false} ); _contexts.Add(culture, context); @@ -144,7 +211,8 @@ private static void _loadData(IResourceManager resourceManager, CultureInfo cult } } - private static void _loadFromFile(IResourceManager resourceManager, ResourcePath filePath, MessageContext context) + private static void _loadFromFile(IResourceManager resourceManager, ResourcePath filePath, + MessageContext context) { using (var fileStream = resourceManager.ContentFileRead(filePath)) using (var reader = new StreamReader(fileStream, EncodingHelpers.UTF8)) diff --git a/Robust.Shared/Prototypes/EntityPrototype.cs b/Robust.Shared/Prototypes/EntityPrototype.cs index 8f1eb86afed..fc50162c60e 100644 --- a/Robust.Shared/Prototypes/EntityPrototype.cs +++ b/Robust.Shared/Prototypes/EntityPrototype.cs @@ -146,12 +146,18 @@ public EntityPrototype() public void LoadFrom(YamlMappingNode mapping) { + var loc = IoCManager.Resolve(); ID = mapping.GetNode("id").AsString(); if (mapping.TryGetNode("name", out var node)) { _nameModified = true; - Name = Loc.GetString(node.AsString()); + Name = loc.GetString(node.AsString()); + } + else if (loc.TryGetString($"ent-{CaseConversion.PascalToKebab(ID)}", out var name)) + { + _nameModified = true; + Name = loc.GetString(name); } if (mapping.TryGetNode("parent", out node)) @@ -163,12 +169,17 @@ public void LoadFrom(YamlMappingNode mapping) if (mapping.TryGetNode("description", out node)) { _descriptionModified = true; - Description = Loc.GetString(node.AsString()); + Description = loc.GetString(node.AsString()); + } + else if (loc.TryGetString($"ent-{CaseConversion.PascalToKebab(ID)}.desc", out var name)) + { + _descriptionModified = true; + Description = loc.GetString(name); } if (mapping.TryGetNode("suffix", out node)) { - EditorSuffix = Loc.GetString(node.AsString()); + EditorSuffix = loc.GetString(node.AsString()); } // COMPONENTS diff --git a/Robust.Shared/Utility/CaseConversion.cs b/Robust.Shared/Utility/CaseConversion.cs new file mode 100644 index 00000000000..a35fb4030d2 --- /dev/null +++ b/Robust.Shared/Utility/CaseConversion.cs @@ -0,0 +1,18 @@ +using System.Text.RegularExpressions; + +namespace Robust.Shared.Utility +{ + public static class CaseConversion + { + private static readonly Regex PascalToKebabRegex = + new Regex("(?