Add LocalizedString

This commit is contained in:
Wojtek Figat
2021-04-19 16:24:14 +02:00
parent f1b82b788b
commit 983190b9a0
5 changed files with 354 additions and 0 deletions

View File

@@ -2,6 +2,7 @@
#include "Localization.h"
#include "CultureInfo.h"
#include "LocalizedString.h"
#include "LocalizationSettings.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/Config/GameSettings.h"
@@ -46,6 +47,72 @@ void LocalizationSettings::Deserialize(DeserializeStream& stream, ISerializeModi
DESERIALIZE(LocalizedStringTables);
}
LocalizedString::LocalizedString(const LocalizedString& other)
: Id(other.Id)
, Value(other.Value)
{
}
LocalizedString::LocalizedString(LocalizedString&& other) noexcept
: Id(MoveTemp(other.Id))
, Value(MoveTemp(other.Value))
{
}
LocalizedString::LocalizedString(const StringView& value)
: Value(value)
{
}
LocalizedString::LocalizedString(String&& value) noexcept
: Value(MoveTemp(value))
{
}
LocalizedString& LocalizedString::operator=(const LocalizedString& other)
{
if (this != &other)
{
Id = other.Id;
Value = other.Value;
}
return *this;
}
LocalizedString& LocalizedString::operator=(LocalizedString&& other) noexcept
{
if (this != &other)
{
Id = MoveTemp(other.Id);
Value = MoveTemp(other.Value);
}
return *this;
}
LocalizedString& LocalizedString::operator=(const StringView& value)
{
Id.Clear();
Value = value;
return *this;
}
LocalizedString& LocalizedString::operator=(String&& value) noexcept
{
Id.Clear();
Value = MoveTemp(value);
return *this;
}
String LocalizedString::ToString() const
{
return Localization::GetString(Id, Value);
}
String LocalizedString::ToStringPlural(int32 n) const
{
return Localization::GetPluralString(Id, n, Value);
}
void LocalizationService::OnLocalizationChanged()
{
PROFILE_CPU();

View File

@@ -0,0 +1,103 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using System;
namespace FlaxEngine
{
partial class LocalizedString : IEquatable<LocalizedString>, IEquatable<string>, IComparable, IComparable<LocalizedString>, IComparable<string>
{
/// <summary>
/// Initializes a new instance of the <see cref="LocalizedString"/> class.
/// </summary>
/// <param name="value">The value.</param>
public LocalizedString(string value)
{
Value = value;
}
/// <summary>
/// Gets the localized plural string for the current language by using string id lookup.
/// </summary>
/// <param name="n">The value count for plural message selection.</param>
/// <returns>The localized text.</returns>
public string ToStringPlural(int n)
{
return string.IsNullOrEmpty(Value) ? Localization.GetPluralString(Id, n) : Value;
}
/// <summary>
/// Implicit converter of <see cref="LocalizedString"/> into <see cref="string"/>.
/// </summary>
/// <param name="str">The localized string.</param>
/// <returns>The string.</returns>
public static implicit operator string(LocalizedString str)
{
return str.ToString();
}
/// <summary>
/// Implicit converter of <see cref="string"/> into <see cref="LocalizedString"/>.
/// </summary>
/// <param name="str">The string.</param>
/// <returns>The localized string.</returns>
public static implicit operator LocalizedString(string str)
{
return new LocalizedString(str);
}
/// <inheritdoc />
public int CompareTo(object obj)
{
if (obj is string asString)
return CompareTo(asString);
if (obj is LocalizedString asLocalizedString)
return CompareTo(asLocalizedString);
return 0;
}
/// <inheritdoc />
public bool Equals(LocalizedString other)
{
return Id == other.Id && Value == other.Value;
}
/// <inheritdoc />
public bool Equals(string other)
{
return Value == other || Localization.GetString(Id) == other;
}
/// <inheritdoc />
public int CompareTo(LocalizedString other)
{
return string.Compare(ToString(), ToString(), StringComparison.Ordinal);
}
/// <inheritdoc />
public int CompareTo(string other)
{
return string.Compare(ToString(), other, StringComparison.Ordinal);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
return ReferenceEquals(this, obj) || obj is LocalizedString other && Equals(other);
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
{
return ((Id != null ? Id.GetHashCode() : 0) * 397) ^ (Value != null ? Value.GetHashCode() : 0);
}
}
/// <inheritdoc />
public override string ToString()
{
return string.IsNullOrEmpty(Value) ? Localization.GetString(Id) : Value;
}
}
}

View File

@@ -0,0 +1,114 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Core/Types/String.h"
#include "Engine/Serialization/SerializationFwd.h"
/// <summary>
/// The string container that supports using localized text.
/// </summary>
API_CLASS(Sealed) class FLAXENGINE_API LocalizedString
{
DECLARE_SCRIPTING_TYPE_MINIMAL(LocalizedString);
public:
/// <summary>
/// The localized string identifier. Used to lookup text value for a current language (via <see cref="Localization::GetString"/>).
/// </summary>
API_FIELD() String Id;
/// <summary>
/// The overriden string value to use. If empty, the localized string will be used.
/// </summary>
API_FIELD() String Value;
public:
LocalizedString() = default;
LocalizedString(const LocalizedString& other);
LocalizedString(LocalizedString&& other) noexcept;
LocalizedString(const StringView& value);
LocalizedString(String&& value) noexcept;
LocalizedString& operator=(const LocalizedString& other);
LocalizedString& operator=(LocalizedString&& other) noexcept;
LocalizedString& operator=(const StringView& value);
LocalizedString& operator=(String&& value) noexcept;
friend bool operator==(const LocalizedString& a, const LocalizedString& b)
{
return a.Id == b.Id && a.Value == b.Value;
}
friend bool operator!=(const LocalizedString& a, const LocalizedString& b)
{
return !(a == b);
}
friend bool operator==(const LocalizedString& a, const StringView& b)
{
return a.Value == b || a.ToString() == b;
}
friend bool operator!=(const LocalizedString& a, const StringView& b)
{
return !(a == b);
}
public:
String ToString() const;
String ToStringPlural(int32 n) const;
};
inline uint32 GetHash(const LocalizedString& key)
{
return GetHash(key.ToString());
}
namespace Serialization
{
inline bool ShouldSerialize(const LocalizedString& v, const void* otherObj)
{
return !otherObj || v != *(LocalizedString*)otherObj;
}
inline void Serialize(ISerializable::SerializeStream& stream, const LocalizedString& v, const void* otherObj)
{
if (v.Id.IsEmpty())
{
stream.String(v.Value);
}
else
{
stream.StartObject();
stream.JKEY("Id");
stream.String(v.Id);
stream.JKEY("Value");
stream.String(v.Value);
stream.EndObject();
}
}
inline void Deserialize(ISerializable::DeserializeStream& stream, LocalizedString& v, ISerializeModifier* modifier)
{
if (stream.IsString())
{
v.Id = String::Empty;
v.Value = stream.GetText();
}
else if (stream.IsObject())
{
auto e = SERIALIZE_FIND_MEMBER(stream, "Id");
if (e != stream.MemberEnd())
v.Id = e->value.GetString();
e = SERIALIZE_FIND_MEMBER(stream, "Value");
if (e != stream.MemberEnd())
v.Value = e->value.GetString();
}
else
{
v = LocalizedString();
}
}
}
DEFINE_DEFAULT_FORMATTING_VIA_TO_STRING(LocalizedString);

View File

@@ -219,6 +219,75 @@ namespace FlaxEngine.Json
public override bool CanWriteDiff => true;
}
/// <summary>
/// Serialize LocalizedString as inlined text is not using localization (Id member is empty).
/// </summary>
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
internal class LocalizedStringConverter : JsonConverter
{
/// <inheritdoc />
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
var str = (LocalizedString)value;
if (string.IsNullOrEmpty(str.Id))
{
writer.WriteValue(str.Value);
}
else
{
writer.WriteStartObject();
writer.WritePropertyName("Id");
writer.WriteValue(str.Id);
writer.WritePropertyName("Value");
writer.WriteValue(str.Value);
writer.WriteEndObject();
}
}
/// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
var str = existingValue as LocalizedString ?? new LocalizedString();
if (reader.TokenType == JsonToken.String)
{
str.Id = null;
str.Value = (string)reader.Value;
}
else if (reader.TokenType == JsonToken.StartObject)
{
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.PropertyName:
{
var propertyName = (string)reader.Value;
switch (propertyName)
{
case "Id":
str.Id = reader.ReadAsString();
break;
case "Value":
str.Value = reader.ReadAsString();
break;
}
break;
}
case JsonToken.Comment: break;
default: return str;
}
}
}
return str;
}
/// <inheritdoc />
public override bool CanConvert(Type objectType)
{
return objectType == typeof(LocalizedString);
}
}
/*
/// <summary>
/// Serialize Guid values using `N` format

View File

@@ -83,6 +83,7 @@ namespace FlaxEngine.Json
settings.Converters.Add(new SoftObjectReferenceConverter());
settings.Converters.Add(new MarginConverter());
settings.Converters.Add(new VersionConverter());
settings.Converters.Add(new LocalizedStringConverter());
//settings.Converters.Add(new GuidConverter());
return settings;
}