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("(?