mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
Some work supporting localization.
Far from complete, but a good start.
This commit is contained in:
@@ -33,6 +33,7 @@ using Robust.Shared.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
@@ -43,6 +44,7 @@ using Robust.Client.ViewVariables;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Asynchronous;
|
||||
using Robust.Shared.Interfaces.Resources;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
namespace Robust.Client
|
||||
{
|
||||
@@ -74,6 +76,7 @@ namespace Robust.Client
|
||||
[Dependency] private readonly IDiscordRichPresence _discord;
|
||||
[Dependency] private readonly IClyde _clyde;
|
||||
[Dependency] private readonly IFontManagerInternal _fontManager;
|
||||
[Dependency] private readonly ILocalizationManager _localizationManager;
|
||||
|
||||
private void Startup()
|
||||
{
|
||||
@@ -103,6 +106,10 @@ namespace Robust.Client
|
||||
_resourceCache.Initialize(userDataDir);
|
||||
_resourceCache.LoadBaseResources();
|
||||
|
||||
// Default to en-US.
|
||||
// Perhaps in the future we could make a command line arg or something to change this default.
|
||||
_localizationManager.LoadCulture(new CultureInfo("en-US"));
|
||||
|
||||
// Bring display up as soon as resources are mounted.
|
||||
_displayManager.Initialize();
|
||||
_displayManager.SetWindowTitle("Space Station 14");
|
||||
|
||||
@@ -59,6 +59,7 @@ using Robust.Client.ViewVariables;
|
||||
using Robust.Shared.Asynchronous;
|
||||
using Robust.Shared.Interfaces.Resources;
|
||||
using Robust.Shared.Exceptions;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Robust.Client
|
||||
@@ -93,6 +94,7 @@ namespace Robust.Client
|
||||
IoCManager.Register<ITaskManager, TaskManager>();
|
||||
IoCManager.Register<IRuntimeLog, RuntimeLog>();
|
||||
IoCManager.Register<IDynamicTypeFactory, DynamicTypeFactory>();
|
||||
IoCManager.Register<ILocalizationManager, LocalizationManager>();
|
||||
|
||||
// Client stuff.
|
||||
IoCManager.Register<IGameController, GameController>();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@@ -44,6 +45,7 @@ using Robust.Shared.Utility;
|
||||
using Robust.Shared.Interfaces.Log;
|
||||
using Robust.Shared.Interfaces.Resources;
|
||||
using Robust.Shared.Exceptions;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
namespace Robust.Server
|
||||
{
|
||||
@@ -80,6 +82,8 @@ namespace Robust.Server
|
||||
private readonly ISystemConsoleManager _systemConsole;
|
||||
[Dependency]
|
||||
private readonly ITaskManager _taskManager;
|
||||
[Dependency]
|
||||
private readonly ILocalizationManager _localizationManager;
|
||||
|
||||
private FileLogHandler fileLogHandler;
|
||||
private IGameLoop _mainLoop;
|
||||
@@ -187,6 +191,11 @@ namespace Robust.Server
|
||||
_resources.MountContentDirectory($@"{ContentRootDir}Resources/");
|
||||
#endif
|
||||
|
||||
// Default to en-US.
|
||||
// Perhaps in the future we could make a command line arg or something to change this default.
|
||||
_localizationManager.LoadCulture(new CultureInfo("en-US"));
|
||||
|
||||
|
||||
//mount the engine content pack
|
||||
// _resources.MountContentPack(@"EngineContentPack.zip");
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ using Robust.Server.Timing;
|
||||
using Robust.Server.ViewVariables;
|
||||
using Robust.Shared.Asynchronous;
|
||||
using Robust.Shared.Exceptions;
|
||||
using Robust.Shared.Localization;
|
||||
|
||||
namespace Robust.Server
|
||||
{
|
||||
@@ -118,6 +119,7 @@ namespace Robust.Server
|
||||
IoCManager.Register<ITaskManager, TaskManager>();
|
||||
IoCManager.Register<IRuntimeLog, RuntimeLog>();
|
||||
IoCManager.Register<IDynamicTypeFactory, DynamicTypeFactory>();
|
||||
IoCManager.Register<ILocalizationManager, LocalizationManager>();
|
||||
|
||||
// Server stuff.
|
||||
IoCManager.Register<IEntityManager, ServerEntityManager>();
|
||||
|
||||
51
Robust.Shared/Localization/ILocalizationManager.cs
Normal file
51
Robust.Shared/Localization/ILocalizationManager.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace Robust.Shared.Localization
|
||||
{
|
||||
public interface ILocalizationManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a string translated for the current culture.
|
||||
/// </summary>
|
||||
/// <param name="text">The string to get translated.</param>
|
||||
/// <returns>
|
||||
/// The translated string if a translation is available, otherwise the string is returned.
|
||||
/// </returns>
|
||||
string GetString(string text);
|
||||
|
||||
/// <summary>
|
||||
/// Version of <see cref="GetString(string)"/> that also runs string formatting.
|
||||
/// </summary>
|
||||
string GetString(string text, params object[] args);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string inside a context or category.
|
||||
/// </summary>
|
||||
string GetParticularString(string context, string text);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string inside a context or category with formatting.
|
||||
/// </summary>
|
||||
string GetParticularString(string context, string text, params object[] args);
|
||||
|
||||
string GetPluralString(string text, string pluralText, long n);
|
||||
|
||||
string GetPluralString(string text, string pluralText, long n, params object[] args);
|
||||
|
||||
string GetParticularPluralString(string context, string text, string pluralText, long n);
|
||||
|
||||
string GetParticularPluralString(string context, string text, string pluralText, long n, params object[] args);
|
||||
|
||||
/// <summary>
|
||||
/// Default culture used by other methods when no culture is explicitly specified.
|
||||
/// Changing this also changes the current thread's culture.
|
||||
/// </summary>
|
||||
CultureInfo DefaultCulture { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Load data for a culture.
|
||||
/// </summary>
|
||||
/// <param name="culture"></param>
|
||||
void LoadCulture(CultureInfo culture);
|
||||
}
|
||||
}
|
||||
150
Robust.Shared/Localization/LocalizationManager.cs
Normal file
150
Robust.Shared/Localization/LocalizationManager.cs
Normal file
@@ -0,0 +1,150 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NGettext;
|
||||
using Robust.Shared.Interfaces.Resources;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Utility;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Robust.Shared.Localization
|
||||
{
|
||||
internal sealed class LocalizationManager : ILocalizationManager
|
||||
{
|
||||
[Dependency] private readonly IResourceManager _resourceManager;
|
||||
|
||||
private readonly Dictionary<CultureInfo, Catalog> _catalogs = new Dictionary<CultureInfo, Catalog>();
|
||||
private CultureInfo _defaultCulture;
|
||||
|
||||
public string GetString(string text)
|
||||
{
|
||||
var catalog = _catalogs[_defaultCulture];
|
||||
return catalog.GetString(text);
|
||||
}
|
||||
|
||||
public string GetString(string text, params object[] args)
|
||||
{
|
||||
var catalog = _catalogs[_defaultCulture];
|
||||
return catalog.GetString(text, args);
|
||||
}
|
||||
|
||||
public string GetParticularString(string context, string text)
|
||||
{
|
||||
var catalog = _catalogs[_defaultCulture];
|
||||
return catalog.GetParticularString(context, text);
|
||||
}
|
||||
|
||||
public string GetParticularString(string context, string text, params object[] args)
|
||||
{
|
||||
var catalog = _catalogs[_defaultCulture];
|
||||
return catalog.GetParticularString(context, text, args);
|
||||
}
|
||||
|
||||
public string GetPluralString(string text, string pluralText, long n)
|
||||
{
|
||||
var catalog = _catalogs[_defaultCulture];
|
||||
return catalog.GetParticularString(text, pluralText, n);
|
||||
}
|
||||
|
||||
public string GetPluralString(string text, string pluralText, long n, params object[] args)
|
||||
{
|
||||
var catalog = _catalogs[_defaultCulture];
|
||||
return catalog.GetParticularString(text, pluralText, n, args);
|
||||
}
|
||||
|
||||
public string GetParticularPluralString(string context, string text, string pluralText, long n)
|
||||
{
|
||||
var catalog = _catalogs[_defaultCulture];
|
||||
return catalog.GetParticularString(context, text, n, pluralText);
|
||||
}
|
||||
|
||||
public string GetParticularPluralString(string context, string text, string pluralText, long n, params object[] args)
|
||||
{
|
||||
var catalog = _catalogs[_defaultCulture];
|
||||
return catalog.GetParticularPluralString(context, text, pluralText, n, args);
|
||||
}
|
||||
|
||||
public CultureInfo DefaultCulture
|
||||
{
|
||||
get => _defaultCulture;
|
||||
set
|
||||
{
|
||||
if (!_catalogs.ContainsKey(value))
|
||||
{
|
||||
throw new ArgumentException("That culture is not yet loaded and cannot be used.", nameof(value));
|
||||
}
|
||||
|
||||
_defaultCulture = value;
|
||||
CultureInfo.CurrentCulture = value;
|
||||
CultureInfo.CurrentUICulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadCulture(CultureInfo culture)
|
||||
{
|
||||
var catalog = new Catalog(culture);
|
||||
_catalogs.Add(culture, catalog);
|
||||
|
||||
_loadData(culture, catalog);
|
||||
if (DefaultCulture == null)
|
||||
{
|
||||
DefaultCulture = culture;
|
||||
}
|
||||
}
|
||||
|
||||
private void _loadData(CultureInfo culture, Catalog catalog)
|
||||
{
|
||||
// Load data from .yml files.
|
||||
// Data is loaded from /Locale/<language-code>/*
|
||||
|
||||
var root = new ResourcePath($"/Locale/{culture.IetfLanguageTag}/");
|
||||
|
||||
foreach (var file in _resourceManager.ContentFindFiles(root))
|
||||
{
|
||||
var yamlFile = root / file;
|
||||
_loadFromFile(yamlFile, catalog);
|
||||
}
|
||||
}
|
||||
|
||||
private void _loadFromFile(ResourcePath filePath, Catalog catalog)
|
||||
{
|
||||
var yamlStream = new YamlStream();
|
||||
using (var fileStream = _resourceManager.ContentFileRead(filePath))
|
||||
using (var reader = new StreamReader(fileStream, EncodingHelpers.UTF8))
|
||||
{
|
||||
yamlStream.Load(reader);
|
||||
}
|
||||
|
||||
foreach (var entry in yamlStream.Documents
|
||||
.SelectMany(d => (YamlSequenceNode) d.RootNode)
|
||||
.Cast<YamlMappingNode>())
|
||||
{
|
||||
_readEntry(entry, catalog);
|
||||
}
|
||||
}
|
||||
|
||||
private static void _readEntry(YamlMappingNode entry, Catalog catalog)
|
||||
{
|
||||
var id = entry.GetNode("msgid").AsString();
|
||||
var str = entry.GetNode("msgstr");
|
||||
string[] strings;
|
||||
if (str is YamlScalarNode scalar)
|
||||
{
|
||||
strings = new[] {scalar.AsString()};
|
||||
}
|
||||
else if (str is YamlSequenceNode sequence)
|
||||
{
|
||||
strings = sequence.Children.Select(c => c.AsString()).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Improve error reporting here.
|
||||
throw new Exception("Invalid format in translation file.");
|
||||
}
|
||||
|
||||
catalog.Translations.Add(id, strings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using Robust.Shared.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
@@ -22,6 +23,8 @@ namespace Robust.Shared.GameObjects
|
||||
[Prototype("entity")]
|
||||
public class EntityPrototype : IPrototype, IIndexedPrototype, ISyncingPrototype
|
||||
{
|
||||
[Dependency] private readonly ILocalizationManager _localization;
|
||||
|
||||
/// <summary>
|
||||
/// The type string of this prototype used in files.
|
||||
/// </summary>
|
||||
@@ -143,7 +146,7 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
if (mapping.TryGetNode("name", out YamlNode node))
|
||||
{
|
||||
Name = node.AsString();
|
||||
Name = _localization.GetString(node.AsString());
|
||||
}
|
||||
|
||||
if (mapping.TryGetNode("class", out node))
|
||||
@@ -163,7 +166,7 @@ namespace Robust.Shared.GameObjects
|
||||
// DESCRIPTION
|
||||
if (mapping.TryGetNode("description", out node))
|
||||
{
|
||||
Description = node.AsString();
|
||||
Description = _localization.GetString(node.AsString());
|
||||
}
|
||||
|
||||
// COMPONENTS
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using YamlDotNet.RepresentationModel;
|
||||
using Robust.Shared.Localization;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Robust.Shared.Prototypes
|
||||
{
|
||||
|
||||
@@ -94,6 +94,8 @@ namespace Robust.Shared.Prototypes
|
||||
{
|
||||
[Dependency]
|
||||
private readonly IReflectionManager ReflectionManager;
|
||||
[Dependency]
|
||||
private readonly IDynamicTypeFactory _dynamicTypeFactory;
|
||||
private readonly Dictionary<string, Type> prototypeTypes = new Dictionary<string, Type>();
|
||||
|
||||
[Dependency]
|
||||
@@ -287,7 +289,7 @@ namespace Robust.Shared.Prototypes
|
||||
}
|
||||
|
||||
var prototypeType = prototypeTypes[type];
|
||||
var prototype = (IPrototype)Activator.CreateInstance(prototypeType);
|
||||
var prototype = (IPrototype)_dynamicTypeFactory.CreateInstance(prototypeType);
|
||||
prototype.LoadFrom(node);
|
||||
prototypes[prototypeType].Add(prototype);
|
||||
var indexedPrototype = prototype as IIndexedPrototype;
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
<PackageReference Include="NetSerializer" Version="4.1.0" />
|
||||
<PackageReference Include="Nett" Version="0.9.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||
<PackageReference Include="NGettext" Version="0.6.3" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.0.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.2" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
@@ -171,6 +172,8 @@
|
||||
<Compile Include="Interfaces\Resources\IResourceManager.cs" />
|
||||
<Compile Include="Interfaces\Resources\IWritableDirProvider.cs" />
|
||||
<Compile Include="Interfaces\Serialization\IRobustSerializer.cs" />
|
||||
<Compile Include="Localization\ILocalizationManager.cs" />
|
||||
<Compile Include="Localization\LocalizationManager.cs" />
|
||||
<Compile Include="Map\IMapGrid.cs" />
|
||||
<Compile Include="Interfaces\Map\IMapManager.cs" />
|
||||
<Compile Include="Interfaces\Map\ITileDefinition.cs" />
|
||||
|
||||
@@ -68,6 +68,7 @@ using Robust.Shared.Interfaces.Serialization;
|
||||
using Robust.Shared.Interfaces.Timers;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
@@ -200,6 +201,7 @@ namespace Robust.UnitTesting
|
||||
IoCManager.Register<ITaskManager, TaskManager>();
|
||||
IoCManager.Register<IRuntimeLog, RuntimeLog>();
|
||||
IoCManager.Register<IDynamicTypeFactory, DynamicTypeFactory>();
|
||||
IoCManager.Register<ILocalizationManager, LocalizationManager>();
|
||||
|
||||
switch (Project)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user