Add FallbackTable for localized strings table to redirect missing texts into other language

This commit is contained in:
Wojciech Figat
2021-11-15 16:37:00 +01:00
parent 1107173e60
commit 80ef2befd5
4 changed files with 59 additions and 5 deletions

View File

@@ -113,6 +113,10 @@ namespace FlaxEditor.Windows.Assets
[CustomEditor(typeof(FlaxEditor.CustomEditors.Editors.CultureInfoEditor))] [CustomEditor(typeof(FlaxEditor.CustomEditors.Editors.CultureInfoEditor))]
public string Locale; public string Locale;
[EditorOrder(5), EditorDisplay("General"), Tooltip("The fallback language table to use for missing keys. Eg. table for 'en-GB' can point to 'en' as a fallback to prevent problem of missing localized strings.")]
[AssetReference(true)]
public LocalizedStringTable FallbackTable;
[EditorOrder(10), EditorDisplay("Entries", EditorDisplayAttribute.InlineStyle), Tooltip("The string table. Maps the message id into the localized text. For plural messages the list contains separate items for value numbers.")] [EditorOrder(10), EditorDisplay("Entries", EditorDisplayAttribute.InlineStyle), Tooltip("The string table. Maps the message id into the localized text. For plural messages the list contains separate items for value numbers.")]
[Collection(Spacing = 10, OverrideEditorTypeName = "FlaxEditor.Windows.Assets.LocalizedStringTableWindow+EntryEditor")] [Collection(Spacing = 10, OverrideEditorTypeName = "FlaxEditor.Windows.Assets.LocalizedStringTableWindow+EntryEditor")]
public Dictionary<string, string[]> Entries; public Dictionary<string, string[]> Entries;
@@ -174,6 +178,7 @@ namespace FlaxEditor.Windows.Assets
return; return;
_asset.Locale = _proxy.Locale; _asset.Locale = _proxy.Locale;
_asset.FallbackTable = _proxy.FallbackTable;
_asset.Entries = _proxy.Entries; _asset.Entries = _proxy.Entries;
if (_asset.Save(_item.Path)) if (_asset.Save(_item.Path))
{ {
@@ -200,6 +205,7 @@ namespace FlaxEditor.Windows.Assets
_proxy = new Proxy _proxy = new Proxy
{ {
Locale = _asset.Locale, Locale = _asset.Locale,
FallbackTable = _asset.FallbackTable,
Entries = _asset.Entries, Entries = _asset.Entries,
}; };
_presenter.Select(_proxy); _presenter.Select(_proxy);

View File

@@ -258,20 +258,35 @@ void Localization::SetCurrentLanguageCulture(const CultureInfo& value)
String Localization::GetString(const String& id, const String& fallback) String Localization::GetString(const String& id, const String& fallback)
{ {
String result; const String* result = nullptr;
for (auto& e : Instance.LocalizedStringTables) for (auto& e : Instance.LocalizedStringTables)
{ {
const auto table = e.Get(); const auto table = e.Get();
const auto messages = table ? table->Entries.TryGet(id) : nullptr; const auto messages = table ? table->Entries.TryGet(id) : nullptr;
if (messages && messages->Count() != 0) if (messages && messages->Count() != 0)
{ {
result = messages->At(0); result = &messages->At(0);
break; break;
} }
} }
if (result.IsEmpty()) if (!result)
result = fallback; {
return result; // Try using fallback tables
for (auto& e : Instance.LocalizedStringTables)
{
const auto table = e.Get();
const auto fallbackTable = table ? table->FallbackTable.Get() : nullptr;
const auto messages = fallbackTable ? fallbackTable->Entries.TryGet(id) : nullptr;
if (messages && messages->Count() != 0)
{
result = &messages->At(0);
break;
}
}
}
if (!result)
result = &fallback;
return *result;
} }
String Localization::GetPluralString(const String& id, int32 n, const String& fallback) String Localization::GetPluralString(const String& id, int32 n, const String& fallback)
@@ -289,6 +304,21 @@ String Localization::GetPluralString(const String& id, int32 n, const String& fa
break; break;
} }
} }
if (!result)
{
// Try using fallback tables
for (auto& e : Instance.LocalizedStringTables)
{
const auto table = e.Get();
const auto fallbackTable = table ? table->FallbackTable.Get() : nullptr;
const auto messages = fallbackTable ? fallbackTable->Entries.TryGet(id) : nullptr;
if (messages && messages->Count() > n)
{
result = &messages->At(n);
break;
}
}
}
if (!result) if (!result)
result = &fallback; result = &fallback;
return String::Format(result->GetText(), n); return String::Format(result->GetText(), n);

View File

@@ -60,6 +60,12 @@ bool LocalizedStringTable::Save(const StringView& path)
writer.JKEY("Locale"); writer.JKEY("Locale");
writer.String(Locale); writer.String(Locale);
if (FallbackTable.GetID().IsValid())
{
writer.JKEY("FallbackTable");
writer.Guid(FallbackTable.GetID());
}
writer.JKEY("Entries"); writer.JKEY("Entries");
writer.StartObject(); writer.StartObject();
for (auto& e : Entries) for (auto& e : Entries)
@@ -102,6 +108,9 @@ Asset::LoadResult LocalizedStringTable::loadAsset()
return result; return result;
JsonTools::GetString(Locale, *Data, "Locale"); JsonTools::GetString(Locale, *Data, "Locale");
Guid fallbackTable = Guid::Empty;
JsonTools::GetGuid(fallbackTable, *Data, "FallbackTable");
FallbackTable = fallbackTable;
const auto entriesMember = SERIALIZE_FIND_MEMBER((*Data), "Entries"); const auto entriesMember = SERIALIZE_FIND_MEMBER((*Data), "Entries");
if (entriesMember != Data->MemberEnd() && entriesMember->value.IsObject()) if (entriesMember != Data->MemberEnd() && entriesMember->value.IsObject())
{ {
@@ -134,5 +143,6 @@ void LocalizedStringTable::unload(bool isReloading)
JsonAssetBase::unload(isReloading); JsonAssetBase::unload(isReloading);
Locale.Clear(); Locale.Clear();
FallbackTable = nullptr;
Entries.Clear(); Entries.Clear();
} }

View File

@@ -5,6 +5,7 @@
#include "Engine/Content/JsonAsset.h" #include "Engine/Content/JsonAsset.h"
#include "Engine/Core/Collections/Array.h" #include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Collections/Dictionary.h" #include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Scripting/SoftObjectReference.h"
/// <summary> /// <summary>
/// Contains localized strings table for a given culture. /// Contains localized strings table for a given culture.
@@ -14,17 +15,24 @@ API_CLASS(NoSpawn) class FLAXENGINE_API LocalizedStringTable : public JsonAssetB
{ {
DECLARE_ASSET_HEADER(LocalizedStringTable); DECLARE_ASSET_HEADER(LocalizedStringTable);
public: public:
/// <summary> /// <summary>
/// The locale of the localized string table (eg. pl-PL). /// The locale of the localized string table (eg. pl-PL).
/// </summary> /// </summary>
API_FIELD() String Locale; API_FIELD() String Locale;
/// <summary>
/// The fallback language table to use for missing keys. Eg. table for 'en-GB' can point to 'en' as a fallback to prevent problem of missing localized strings.
/// </summary>
API_FIELD() SoftObjectReference<LocalizedStringTable> FallbackTable;
/// <summary> /// <summary>
/// The string table. Maps the message id into the localized text. For plural messages the list contains separate items for value numbers. /// The string table. Maps the message id into the localized text. For plural messages the list contains separate items for value numbers.
/// </summary> /// </summary>
API_FIELD() Dictionary<String, Array<String>> Entries; API_FIELD() Dictionary<String, Array<String>> Entries;
public: public:
/// <summary> /// <summary>
/// Adds the localized string to the table. /// Adds the localized string to the table.
/// </summary> /// </summary>