Files
RobustToolbox/Robust.Shared/Localization/LocalizationManager.cs
T

220 lines
7.2 KiB
C#

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.Localization.Macros;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Robust.Shared.Localization
{
internal sealed class LocalizationManager : ILocalizationManagerInternal
{
[Dependency] private readonly IResourceManager _resourceManager = default!;
[Dependency] private readonly ITextMacroFactory _textMacroFactory = default!;
[Dependency] private readonly IRobustMappedStringSerializer _stringSerializer = default!;
private readonly Dictionary<CultureInfo, Catalog> _catalogs = new();
private CultureInfo? _defaultCulture;
public string GetString(string text)
{
if (_defaultCulture == null)
{
return text;
}
var catalog = _catalogs[_defaultCulture];
return catalog.GetString(text);
}
public string GetString(string text, params object[] args)
{
if (_defaultCulture == null)
{
return string.Format(text, args);
}
var catalog = _catalogs[_defaultCulture];
return catalog.GetString(text, args);
}
public string GetParticularString(string context, string text)
{
if (_defaultCulture == null)
{
return text;
}
var catalog = _catalogs[_defaultCulture];
return catalog.GetParticularString(context, text);
}
public string GetParticularString(string context, string text, params object[] args)
{
if (_defaultCulture == null)
{
return string.Format(text, args);
}
var catalog = _catalogs[_defaultCulture];
return catalog.GetParticularString(context, text, args);
}
public string GetPluralString(string text, string pluralText, long n)
{
if (_defaultCulture == null)
{
return n == 1 ? text : pluralText;
}
var catalog = _catalogs[_defaultCulture];
return catalog.GetPluralString(text, pluralText, n);
}
public string GetPluralString(string text, string pluralText, long n, params object[] args)
{
if (_defaultCulture == null)
{
return string.Format(n == 1 ? text : pluralText, args);
}
var catalog = _catalogs[_defaultCulture];
return catalog.GetPluralString(text, pluralText, n, args);
}
public string GetParticularPluralString(string context, string text, string pluralText, long n)
{
if (_defaultCulture == null)
{
return n == 1 ? text : pluralText;
}
var catalog = _catalogs[_defaultCulture];
return catalog.GetParticularPluralString(context, text, pluralText, n, pluralText);
}
public string GetParticularPluralString(string context, string text, string pluralText, long n, params object[] args)
{
if (_defaultCulture == null)
{
return string.Format(n == 1 ? text : pluralText, args);
}
var catalog = _catalogs[_defaultCulture];
return catalog.GetParticularPluralString(context, text, pluralText, n, args);
}
public CultureInfo? DefaultCulture
{
get => _defaultCulture;
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
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 CustomFormatCatalog(culture);
_catalogs.Add(culture, catalog);
_loadData(culture, catalog);
_loadMacros(culture, catalog);
if (DefaultCulture == null)
{
DefaultCulture = culture;
}
}
public void AddLoadedToStringSerializer()
{
_stringSerializer.AddStrings(StringIterator());
IEnumerable<string> StringIterator()
{
foreach (var catalog in _catalogs.Values)
{
foreach (var (key, translations) in catalog.Translations)
{
yield return key;
foreach (var t in translations)
{
yield return t;
}
}
}
}
}
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);
}
private void _loadMacros(CultureInfo culture, CustomFormatCatalog catalog)
{
var macros = _textMacroFactory.GetMacrosForLanguage(culture.IetfLanguageTag);
catalog.CustomFormatProvider = new MacroFormatProvider(new MacroFormatter(macros), culture);
}
}
}