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.
///
/// Function signature runnable by localizations.
///
/// Contains arguments and options passed to the function by the calling localization.
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;
}
}
///
/// Arguments and options passed to a localization function.
///
[PublicAPI]
public readonly struct LocArgs
{
public LocArgs(IReadOnlyList args, IReadOnlyDictionary options)
{
Args = args;
Options = options;
}
///
/// Positional arguments passed to the function, in order.
///
public IReadOnlyList Args { get; }
///
/// Key-value options passed to the function.
///
public IReadOnlyDictionary Options { get; }
}
///
/// A value passed around in the localization system.
///
///
public interface ILocValue
{
///
/// Format this value to a string.
///
///
/// Used when this value is interpolated directly in localizations.
///
/// Context containing data like culture used.
/// The formatted string.
string Format(LocContext ctx);
///
/// Boxed value stored by this instance.
///
object? Value { get; }
// Matches API doesn't work because Fluent.Net is crap.
// RIP.
/*
///
/// Checks if this value matches a string in a select expression.
///
bool Matches(LocContext bundle, string matchValue)
{
return false;
}
*/
}
///
/// Default implementation of a localization value.
///
///
/// The idea is that inheritors could add extra data like formatting parameters
/// and then use those by overriding .
///
/// The type of value stored.
[PublicAPI]
public abstract record LocValue : ILocValue
{
///
/// The stored value.
///
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(Value)
{
public override string Format(LocContext ctx)
{
return Value.ToString(ctx.Culture);
}
}
public sealed record LocValueDateTime(DateTime Value) : LocValue(Value)
{
public override string Format(LocContext ctx)
{
return Value.ToString(ctx.Culture);
}
}
public sealed record LocValueTimeSpan(TimeSpan Value) : LocValue(Value)
{
public override string Format(LocContext ctx)
{
return Value.ToString("g", ctx.Culture);
}
}
public sealed record LocValueString(string Value) : LocValue(Value)
{
public override string Format(LocContext ctx)
{
return Value;
}
}
///
/// Stores an "invalid" string value. Produced by e.g. unresolved variable references.
///
public sealed record LocValueNone(string Value) : LocValue(Value)
{
public override string Format(LocContext ctx)
{
return Value;
}
}
public sealed record LocValueEntity(EntityUid Value) : LocValue(Value)
{
public override string Format(LocContext ctx)
{
return IoCManager.Resolve().GetComponent(Value).EntityName;
}
}
// Matching on these doesn't work so just passing these as string for now.
/*public sealed record LocValueBool(bool Value) : LocValue(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(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#
}*/
}