Merge branch 'local' of git://github.com/honzapatCZ/FlaxEngine into honzapatCZ-local

# Conflicts:
#	Source/Editor/Windows/Assets/LocalizedStringTableWindow.cs
#	Source/Engine/Localization/Localization.cpp
#	Source/Engine/Localization/LocalizedStringTable.h
This commit is contained in:
Wojciech Figat
2021-12-09 11:31:06 +01:00
7 changed files with 119 additions and 74 deletions

View File

@@ -176,7 +176,6 @@ namespace FlaxEditor.CustomEditors.Editors
allKeys.Add(e.Key);
}
}
_valueElement.TextBox.SetTextAsUser(null);
string newKey = null;
if (string.IsNullOrEmpty(_idElement.Text))
{
@@ -216,17 +215,19 @@ namespace FlaxEditor.CustomEditors.Editors
var newValue = _valueElement.Text;
Editor.Log(newKey + (newValue != null ? " = " + newValue : string.Empty));
var locales = settings.LocalizedStringTables.GroupBy(x => x.Locale);
var defaultLocale = settings.LocalizedStringTables[0].Locale;
foreach (var locale in locales)
{
var table = locale.First();
var entries = table.Entries;
if (table.Locale == "en")
if (table.Locale == defaultLocale)
entries[newKey] = new[] { newValue };
else
entries[newKey] = new[] { string.Empty };
table.Entries = entries;
table.Save();
}
_valueElement.TextBox.SetTextAsUser(null);
_idElement.TextBox.SetTextAsUser(newKey);
Profiler.EndEvent();
}

View File

@@ -18,6 +18,7 @@ public:
CultureInfo CurrentCulture;
CultureInfo CurrentLanguage;
Array<AssetReference<LocalizedStringTable>> LocalizedStringTables;
Array<AssetReference<LocalizedStringTable>> FallbackStringTables;
LocalizationService()
: EngineService(TEXT("Localization"), -500)
@@ -28,6 +29,42 @@ public:
void OnLocalizationChanged();
const String& Get(const String& id, int32 index, const String& fallback) const
{
if (id.IsEmpty())
return fallback;
// Try current tables
for (auto& e : LocalizedStringTables)
{
const auto table = e.Get();
const auto messages = table ? table->Entries.TryGet(id) : nullptr;
if (messages && messages->Count() > index)
return messages->At(index);
}
// Try fallback tables for current tables
for (auto& e : 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() > index)
return messages->At(index);
}
// Try fallback language tables
for (auto& e : FallbackStringTables)
{
const auto table = e.Get();
const auto messages = table ? table->Entries.TryGet(id) : nullptr;
if (messages && messages->Count() > index)
return messages->At(index);
}
return fallback;
}
bool Init() override;
};
@@ -46,6 +83,7 @@ void LocalizationSettings::Apply()
void LocalizationSettings::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
{
DESERIALIZE(LocalizedStringTables);
DESERIALIZE(DefaultFallbackLanguage);
}
LocalizedString::LocalizedString(const LocalizedString& other)
@@ -119,10 +157,12 @@ void LocalizationService::OnLocalizationChanged()
PROFILE_CPU();
Instance.LocalizedStringTables.Clear();
Instance.FallbackStringTables.Clear();
const StringView en(TEXT("en"));
// Collect all localization tables into mapping locale -> tables
auto& settings = *LocalizationSettings::Get();
Dictionary<String, Array<AssetReference<LocalizedStringTable>, InlinedAllocation<8>>> tables;
Dictionary<String, Array<AssetReference<LocalizedStringTable>, InlinedAllocation<32>>> tables;
for (auto& e : settings.LocalizedStringTables)
{
auto table = e.Get();
@@ -142,9 +182,13 @@ void LocalizationService::OnLocalizationChanged()
table = tables.TryGet(parentLanguage.GetName());
if (!table)
{
// Fallback to English
const CultureInfo english("en");
table = tables.TryGet(english.GetName());
// Fallback to Default
table = tables.TryGet(settings.DefaultFallbackLanguage);
if (!table)
{
// Fallback to English
table = tables.TryGet(en);
}
}
}
@@ -162,6 +206,17 @@ void LocalizationService::OnLocalizationChanged()
}
LOG(Info, "Using localization for {0}", locale);
Instance.LocalizedStringTables.Add(table->Get(), table->Count());
if (locale != settings.DefaultFallbackLanguage || locale != en)
{
// Cache fallback language tables to support additional text resolving in case of missing entries in the current language
table = tables.TryGet(settings.DefaultFallbackLanguage);
if (!table)
table = tables.TryGet(en);
if (table)
{
Instance.FallbackStringTables.Add(table->Get(), table->Count());
}
}
}
#if PLATFORM_ANDROID
@@ -193,8 +248,12 @@ void LocalizationService::OnLocalizationChanged()
{
std::locale::global(std::locale(localeName));
}
catch (std::runtime_error const&) {}
catch (...) {}
catch (std::runtime_error const&)
{
}
catch (...)
{
}
}
#endif
@@ -258,68 +317,12 @@ void Localization::SetCurrentLanguageCulture(const CultureInfo& value)
String Localization::GetString(const String& id, const String& fallback)
{
const String* result = nullptr;
for (auto& e : Instance.LocalizedStringTables)
{
const auto table = e.Get();
const auto messages = table ? table->Entries.TryGet(id) : nullptr;
if (messages && messages->Count() != 0)
{
result = &messages->At(0);
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() != 0)
{
result = &messages->At(0);
break;
}
}
}
if (!result)
result = &fallback;
return *result;
return Instance.Get(id, 0, fallback);
}
String Localization::GetPluralString(const String& id, int32 n, const String& fallback)
{
CHECK_RETURN(n >= 1, fallback);
n--;
const String* result = nullptr;
for (auto& e : Instance.LocalizedStringTables)
{
const auto table = e.Get();
const auto messages = table ? table->Entries.TryGet(id) : nullptr;
if (messages && messages->Count() > n)
{
result = &messages->At(n);
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)
result = &fallback;
return String::Format(result->GetText(), n);
CHECK_RETURN(n >= 1, String::Format(fallback.GetText(), n));
const String& format = Instance.Get(id, n - 1, fallback);
return String::Format(format.GetText(), n);
}

View File

@@ -10,7 +10,7 @@
/// </summary>
API_CLASS(Static) class FLAXENGINE_API Localization
{
DECLARE_SCRIPTING_TYPE_MINIMAL(Localization);
DECLARE_SCRIPTING_TYPE_MINIMAL(Localization);
public:
/// <summary>
/// Gets the current culture (date, time, currency and values formatting locale).

View File

@@ -11,7 +11,7 @@
/// </summary>
API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_API LocalizationSettings : public SettingsBase
{
DECLARE_SCRIPTING_TYPE_MINIMAL(LocalizationSettings);
DECLARE_SCRIPTING_TYPE_MINIMAL(LocalizationSettings);
public:
/// <summary>
/// The list of the string localization tables used by the game.
@@ -19,6 +19,12 @@ public:
API_FIELD()
Array<AssetReference<LocalizedStringTable>> LocalizedStringTables;
/// <summary>
/// The default fallback language to use if localization system fails to pick the system locale language (eg. en-GB).
/// </summary>
API_FIELD()
String DefaultFallbackLanguage;
public:
/// <summary>
/// Gets the instance of the settings asset (default value if missing). Object returned by this method is always loaded with valid data to use.

View File

@@ -41,7 +41,7 @@ namespace FlaxEngine
/// <returns>The localized text.</returns>
public string ToStringPlural(int n)
{
return string.IsNullOrEmpty(Value) ? Localization.GetPluralString(Id, n) : Value;
return string.IsNullOrEmpty(Value) ? Localization.GetPluralString(Id, n) : string.Format(Value, n);
}
/// <summary>

View File

@@ -33,6 +33,28 @@ void LocalizedStringTable::AddPluralString(const StringView& id, const StringVie
values[n] = value;
}
String LocalizedStringTable::GetString(const String& id) const
{
StringView result;
const auto messages = Entries.TryGet(id);
if (messages && messages->Count() != 0)
result = messages->At(0);
if (result.IsEmpty() && FallbackTable)
result = FallbackTable->GetString(id);
return result;
}
String LocalizedStringTable::GetPluralString(const String& id, int32 n) const
{
StringView result;
const auto messages = Entries.TryGet(id);
if (messages && messages->Count() > n)
result = messages->At(n);
if (result.IsEmpty() && FallbackTable)
result = FallbackTable->GetPluralString(id, n);
return String::Format(result.GetNonTerminatedText(), n);
}
#if USE_EDITOR
bool LocalizedStringTable::Save(const StringView& path)

View File

@@ -13,9 +13,8 @@
/// <seealso cref="JsonAssetBase" />
API_CLASS(NoSpawn) class FLAXENGINE_API LocalizedStringTable : public JsonAssetBase
{
DECLARE_ASSET_HEADER(LocalizedStringTable);
DECLARE_ASSET_HEADER(LocalizedStringTable);
public:
/// <summary>
/// The locale of the localized string table (eg. pl-PL).
/// </summary>
@@ -32,7 +31,6 @@ public:
API_FIELD() Dictionary<String, Array<String>> Entries;
public:
/// <summary>
/// Adds the localized string to the table.
/// </summary>
@@ -48,6 +46,21 @@ public:
/// <param name="n">The plural value (0, 1, 2..).</param>
API_FUNCTION() void AddPluralString(const StringView& id, const StringView& value, int32 n);
/// <summary>
/// Gets the localized string by using string id lookup. Uses fallback table if text is not included in this table.
/// </summary>
/// <param name="id">The message identifier.</param>
/// <returns>The localized text.</returns>
API_FUNCTION() String GetString(const String& id) const;
/// <summary>
/// Gets the localized plural string by using string id lookup. Uses fallback table if text is not included in this table.
/// </summary>
/// <param name="id">The message identifier.</param>
/// <param name="n">The value count for plural message selection.</param>
/// <returns>The localized text.</returns>
API_FUNCTION() String GetPluralString(const String& id, int32 n) const;
#if USE_EDITOR
/// <summary>