mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-01 09:37:03 +02:00
213 lines
6.2 KiB
C#
213 lines
6.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using JetBrains.Annotations;
|
|
using Linguini.Bundle;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.IoC;
|
|
|
|
namespace Robust.Shared.Localization
|
|
{
|
|
// Basically Fluent.Net is based on an ancient pre-1.0 version of fluent.js.
|
|
// Said version of fluent.js was also a complete garbage fire implementation wise.
|
|
// So Fluent.Net is garbage implementation wise.
|
|
// ...yay
|
|
// (the current implementation of fluent.js is written in TS and actually sane)
|
|
//
|
|
// Because of this, we can't expose it to content, so we have to wrap everything related to functions.
|
|
// This basically mimics the modern typescript fluent.js API. Somewhat.
|
|
|
|
/// <summary>
|
|
/// Function signature runnable by localizations.
|
|
/// </summary>
|
|
/// <param name="args">Contains arguments and options passed to the function by the calling localization.</param>
|
|
public delegate ILocValue LocFunction(LocArgs args);
|
|
|
|
[PublicAPI]
|
|
public readonly struct LocContext
|
|
{
|
|
public CultureInfo Culture => Bundle.Culture;
|
|
|
|
internal readonly FluentBundle Bundle;
|
|
|
|
internal LocContext(FluentBundle bundle)
|
|
{
|
|
Bundle = bundle;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Arguments and options passed to a localization function.
|
|
/// </summary>
|
|
[PublicAPI]
|
|
public readonly struct LocArgs
|
|
{
|
|
public LocArgs(IReadOnlyList<ILocValue> args, IReadOnlyDictionary<string, ILocValue> options)
|
|
{
|
|
Args = args;
|
|
Options = options;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Positional arguments passed to the function, in order.
|
|
/// </summary>
|
|
public IReadOnlyList<ILocValue> Args { get; }
|
|
|
|
/// <summary>
|
|
/// Key-value options passed to the function.
|
|
/// </summary>
|
|
public IReadOnlyDictionary<string, ILocValue> Options { get; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// A value passed around in the localization system.
|
|
/// </summary>
|
|
/// <seealso cref="LocValue{T}"/>
|
|
public interface ILocValue
|
|
{
|
|
/// <summary>
|
|
/// Format this value to a string.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Used when this value is interpolated directly in localizations.
|
|
/// </remarks>
|
|
/// <param name="ctx">Context containing data like culture used.</param>
|
|
/// <returns>The formatted string.</returns>
|
|
string Format(LocContext ctx);
|
|
|
|
/// <summary>
|
|
/// Boxed value stored by this instance.
|
|
/// </summary>
|
|
object? Value { get; }
|
|
|
|
// Matches API doesn't work because Fluent.Net is crap.
|
|
// RIP.
|
|
|
|
/*
|
|
/// <summary>
|
|
/// Checks if this value matches a string in a select expression.
|
|
/// </summary>
|
|
bool Matches(LocContext bundle, string matchValue)
|
|
{
|
|
return false;
|
|
}
|
|
*/
|
|
}
|
|
|
|
/// <summary>
|
|
/// Default implementation of a localization value.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The idea is that inheritors could add extra data like formatting parameters
|
|
/// and then use those by overriding <see cref="Format"/>.
|
|
/// </remarks>
|
|
/// <typeparam name="T">The type of value stored.</typeparam>
|
|
[PublicAPI]
|
|
public abstract record LocValue<T> : ILocValue
|
|
{
|
|
/// <summary>
|
|
/// The stored value.
|
|
/// </summary>
|
|
public T Value { get; init; }
|
|
|
|
object? ILocValue.Value => Value;
|
|
|
|
protected LocValue(T val)
|
|
{
|
|
Value = val;
|
|
}
|
|
|
|
public abstract string Format(LocContext ctx);
|
|
|
|
/*
|
|
public virtual bool Matches(LocContext bundle, string matchValue)
|
|
{
|
|
return false;
|
|
}
|
|
*/
|
|
}
|
|
|
|
public sealed record LocValueNumber(double Value) : LocValue<double>(Value)
|
|
{
|
|
public override string Format(LocContext ctx)
|
|
{
|
|
return Value.ToString(ctx.Culture);
|
|
}
|
|
}
|
|
|
|
public sealed record LocValueDateTime(DateTime Value) : LocValue<DateTime>(Value)
|
|
{
|
|
public override string Format(LocContext ctx)
|
|
{
|
|
return Value.ToString(ctx.Culture);
|
|
}
|
|
}
|
|
|
|
public sealed record LocValueTimeSpan(TimeSpan Value) : LocValue<TimeSpan>(Value)
|
|
{
|
|
public override string Format(LocContext ctx)
|
|
{
|
|
return Value.ToString("g", ctx.Culture);
|
|
}
|
|
}
|
|
|
|
public sealed record LocValueString(string Value) : LocValue<string>(Value)
|
|
{
|
|
public override string Format(LocContext ctx)
|
|
{
|
|
return Value;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Stores an "invalid" string value. Produced by e.g. unresolved variable references.
|
|
/// </summary>
|
|
public sealed record LocValueNone(string Value) : LocValue<string>(Value)
|
|
{
|
|
public override string Format(LocContext ctx)
|
|
{
|
|
return Value;
|
|
}
|
|
}
|
|
|
|
public sealed record LocValueEntity(EntityUid Value) : LocValue<EntityUid>(Value)
|
|
{
|
|
public override string Format(LocContext ctx)
|
|
{
|
|
return IoCManager.Resolve<IEntityManager>().GetComponent<MetaDataComponent>(Value).EntityName;
|
|
}
|
|
}
|
|
|
|
// Matching on these doesn't work so just passing these as string for now.
|
|
|
|
/*public sealed record LocValueBool(bool Value) : LocValue<bool>(Value)
|
|
{
|
|
public override string Format(LocContext bundle)
|
|
{
|
|
return Value.ToString(bundle.Culture);
|
|
}
|
|
|
|
/*
|
|
public override bool Matches(LocContext bundle, string matchValue)
|
|
{
|
|
var word = Value ? "true" : "false";
|
|
return word.Equals(matchValue, StringComparison.InvariantCultureIgnoreCase);
|
|
}
|
|
#1#
|
|
}
|
|
|
|
public sealed record LocValueEnum(Enum Value) : LocValue<Enum>(Value)
|
|
{
|
|
public override string Format(LocContext bundle)
|
|
{
|
|
return Value.ToString().ToLowerInvariant();
|
|
}
|
|
|
|
/*public override bool Matches(LocContext bundle, string matchValue)
|
|
{
|
|
return matchValue.Equals(Value.ToString(), StringComparison.InvariantCultureIgnoreCase);
|
|
}#1#
|
|
}*/
|
|
}
|