Add LocalizedStringTable
This commit is contained in:
24
Source/Editor/Content/Proxy/LocalizedStringTableProxy.cs
Normal file
24
Source/Editor/Content/Proxy/LocalizedStringTableProxy.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using FlaxEditor.Windows;
|
||||||
|
using FlaxEditor.Windows.Assets;
|
||||||
|
using FlaxEngine;
|
||||||
|
|
||||||
|
namespace FlaxEditor.Content
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="LocalizedStringTable"/> proxy.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="FlaxEditor.Content.JsonAssetProxy" />
|
||||||
|
public class LocalizedStringTableProxy : JsonAssetProxy
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override EditorWindow Open(Editor editor, ContentItem item)
|
||||||
|
{
|
||||||
|
return new LocalizedStringTableWindow(editor, (JsonAssetItem)item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string TypeName => "FlaxEngine.LocalizedStringTable";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -923,6 +923,7 @@ namespace FlaxEditor.Modules
|
|||||||
Proxy.Add(new SkeletonMaskProxy());
|
Proxy.Add(new SkeletonMaskProxy());
|
||||||
Proxy.Add(new GameplayGlobalsProxy());
|
Proxy.Add(new GameplayGlobalsProxy());
|
||||||
Proxy.Add(new VisualScriptProxy());
|
Proxy.Add(new VisualScriptProxy());
|
||||||
|
Proxy.Add(new LocalizedStringTableProxy());
|
||||||
Proxy.Add(new FileProxy());
|
Proxy.Add(new FileProxy());
|
||||||
Proxy.Add(new SpawnableJsonAssetProxy<PhysicalMaterial>());
|
Proxy.Add(new SpawnableJsonAssetProxy<PhysicalMaterial>());
|
||||||
|
|
||||||
|
|||||||
102
Source/Editor/Windows/Assets/LocalizedStringTableWindow.cs
Normal file
102
Source/Editor/Windows/Assets/LocalizedStringTableWindow.cs
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using FlaxEditor.Content;
|
||||||
|
using FlaxEditor.CustomEditors;
|
||||||
|
using FlaxEditor.GUI;
|
||||||
|
using FlaxEngine;
|
||||||
|
using FlaxEngine.GUI;
|
||||||
|
|
||||||
|
namespace FlaxEditor.Windows.Assets
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Editor window to view/modify <see cref="LocalizedStringTable"/> asset.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="LocalizedStringTable" />
|
||||||
|
/// <seealso cref="FlaxEditor.Windows.Assets.AssetEditorWindow" />
|
||||||
|
public sealed class LocalizedStringTableWindow : AssetEditorWindowBase<LocalizedStringTable>
|
||||||
|
{
|
||||||
|
private readonly CustomEditorPresenter _presenter;
|
||||||
|
private readonly ToolStripButton _saveButton;
|
||||||
|
private Proxy _proxy;
|
||||||
|
|
||||||
|
private class Proxy
|
||||||
|
{
|
||||||
|
[EditorOrder(0), Tooltip("The locale of the localized string table (eg. pl-PL).")]
|
||||||
|
public string Locale;
|
||||||
|
|
||||||
|
[EditorOrder(10), Tooltip("The string table. Maps the message id into the localized text. For plural messages the list contains separate items for value numbers.")]
|
||||||
|
public Dictionary<string, string[]> Entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public LocalizedStringTableWindow(Editor editor, AssetItem item)
|
||||||
|
: base(editor, item)
|
||||||
|
{
|
||||||
|
// Toolstrip
|
||||||
|
_saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save32, Save).LinkTooltip("Save");
|
||||||
|
|
||||||
|
// Panel
|
||||||
|
var panel = new Panel(ScrollBars.Vertical)
|
||||||
|
{
|
||||||
|
AnchorPreset = AnchorPresets.StretchAll,
|
||||||
|
Offsets = new Margin(0, 0, _toolstrip.Bottom, 0),
|
||||||
|
Parent = this
|
||||||
|
};
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
_presenter = new CustomEditorPresenter(null, "Loading...");
|
||||||
|
_presenter.Panel.Parent = panel;
|
||||||
|
_presenter.Modified += MarkAsEdited;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Save()
|
||||||
|
{
|
||||||
|
if (!IsEdited)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_asset.Locale = _proxy.Locale;
|
||||||
|
_asset.Entries = _proxy.Entries;
|
||||||
|
if (_asset.Save(_item.Path))
|
||||||
|
{
|
||||||
|
Editor.LogError("Cannot save asset.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearEditedFlag();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void UpdateToolstrip()
|
||||||
|
{
|
||||||
|
_saveButton.Enabled = IsEdited;
|
||||||
|
|
||||||
|
base.UpdateToolstrip();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void OnAssetLoaded()
|
||||||
|
{
|
||||||
|
_proxy = new Proxy
|
||||||
|
{
|
||||||
|
Locale = _asset.Locale,
|
||||||
|
Entries = _asset.Entries,
|
||||||
|
};
|
||||||
|
_presenter.Select(_proxy);
|
||||||
|
ClearEditedFlag();
|
||||||
|
|
||||||
|
base.OnAssetLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnItemReimported(ContentItem item)
|
||||||
|
{
|
||||||
|
// Refresh the properties (will get new data in OnAssetLoaded)
|
||||||
|
_presenter.Deselect();
|
||||||
|
ClearEditedFlag();
|
||||||
|
|
||||||
|
base.OnItemReimported(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,5 +14,10 @@ public class Localization : EngineModule
|
|||||||
base.Setup(options);
|
base.Setup(options);
|
||||||
|
|
||||||
options.PublicDependencies.Add("Scripting");
|
options.PublicDependencies.Add("Scripting");
|
||||||
|
|
||||||
|
if (options.Target.IsEditor)
|
||||||
|
{
|
||||||
|
options.PrivateDependencies.Add("ContentImporters");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
138
Source/Engine/Localization/LocalizedStringTable.cpp
Normal file
138
Source/Engine/Localization/LocalizedStringTable.cpp
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#include "LocalizedStringTable.h"
|
||||||
|
#include "Engine/Serialization/JsonTools.h"
|
||||||
|
#include "Engine/Serialization/SerializationFwd.h"
|
||||||
|
#include "Engine/Content/Factories/JsonAssetFactory.h"
|
||||||
|
#if USE_EDITOR
|
||||||
|
#include "Engine/ContentImporters/CreateJson.h"
|
||||||
|
#include "Engine/Serialization/JsonWriters.h"
|
||||||
|
#include "Engine/Threading/Threading.h"
|
||||||
|
#include "Engine/Core/Log.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
REGISTER_JSON_ASSET(LocalizedStringTable, "FlaxEngine.LocalizedStringTable", true);
|
||||||
|
|
||||||
|
LocalizedStringTable::LocalizedStringTable(const SpawnParams& params, const AssetInfo* info)
|
||||||
|
: JsonAssetBase(params, info)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalizedStringTable::AddString(const StringView& id, const StringView& value)
|
||||||
|
{
|
||||||
|
auto& values = Entries[id];
|
||||||
|
values.Resize(1);
|
||||||
|
values[0] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalizedStringTable::AddPluralString(const StringView& id, const StringView& value, int32 n)
|
||||||
|
{
|
||||||
|
CHECK(n >= 0 && n < 1024);
|
||||||
|
auto& values = Entries[id];
|
||||||
|
values.Resize(Math::Max(values.Count(), n + 1));
|
||||||
|
values[n] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_EDITOR
|
||||||
|
|
||||||
|
bool LocalizedStringTable::Save(const StringView& path)
|
||||||
|
{
|
||||||
|
// Validate state
|
||||||
|
if (WaitForLoaded())
|
||||||
|
{
|
||||||
|
LOG(Error, "Asset loading failed. Cannot save it.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (IsVirtual() && path.IsEmpty())
|
||||||
|
{
|
||||||
|
LOG(Error, "To save virtual asset asset you need to specify the target asset path location.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopeLock lock(Locker);
|
||||||
|
|
||||||
|
// Serialize data
|
||||||
|
rapidjson_flax::StringBuffer outputData;
|
||||||
|
PrettyJsonWriter writerObj(outputData);
|
||||||
|
JsonWriter& writer = writerObj;
|
||||||
|
writer.StartObject();
|
||||||
|
{
|
||||||
|
writer.JKEY("Locale");
|
||||||
|
writer.String(Locale);
|
||||||
|
|
||||||
|
writer.JKEY("Entries");
|
||||||
|
writer.StartObject();
|
||||||
|
for (auto& e : Entries)
|
||||||
|
{
|
||||||
|
writer.Key(e.Key);
|
||||||
|
if (e.Value.Count() == 1)
|
||||||
|
{
|
||||||
|
writer.String(e.Value[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer.StartArray();
|
||||||
|
for (auto& q : e.Value)
|
||||||
|
writer.String(q);
|
||||||
|
writer.EndArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.EndObject();
|
||||||
|
}
|
||||||
|
writer.EndObject();
|
||||||
|
|
||||||
|
// Save asset
|
||||||
|
const bool saveResult = CreateJson::Create(path.HasChars() ? path : GetPath(), outputData, TypeName);
|
||||||
|
if (saveResult)
|
||||||
|
{
|
||||||
|
LOG(Error, "Cannot save \'{0}\'", ToString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Asset::LoadResult LocalizedStringTable::loadAsset()
|
||||||
|
{
|
||||||
|
// Base
|
||||||
|
auto result = JsonAssetBase::loadAsset();
|
||||||
|
if (result != LoadResult::Ok || IsInternalType())
|
||||||
|
return result;
|
||||||
|
|
||||||
|
JsonTools::GetString(Locale, *Data, "Locale");
|
||||||
|
const auto entriesMember = SERIALIZE_FIND_MEMBER((*Data), "Entries");
|
||||||
|
if (entriesMember != Data->MemberEnd() && entriesMember->value.IsObject())
|
||||||
|
{
|
||||||
|
Entries.EnsureCapacity(entriesMember->value.MemberCount());
|
||||||
|
for (auto i = entriesMember->value.MemberBegin(); i != entriesMember->value.MemberEnd(); ++i)
|
||||||
|
{
|
||||||
|
const String key(i->name.GetText());
|
||||||
|
auto& e = Entries[key];
|
||||||
|
auto& value = i->value;
|
||||||
|
if (value.IsString())
|
||||||
|
{
|
||||||
|
e.Resize(1);
|
||||||
|
e[0] = value.GetText();
|
||||||
|
}
|
||||||
|
else if (value.IsArray())
|
||||||
|
{
|
||||||
|
e.Resize(value.Size());
|
||||||
|
for (int32 q = 0; q < e.Count(); q++)
|
||||||
|
e[q] = value[q].GetString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalizedStringTable::unload(bool isReloading)
|
||||||
|
{
|
||||||
|
// Base
|
||||||
|
JsonAssetBase::unload(isReloading);
|
||||||
|
|
||||||
|
Locale.Clear();
|
||||||
|
Entries.Clear();
|
||||||
|
}
|
||||||
57
Source/Engine/Localization/LocalizedStringTable.h
Normal file
57
Source/Engine/Localization/LocalizedStringTable.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Engine/Content/JsonAsset.h"
|
||||||
|
#include "Engine/Core/Collections/Dictionary.h"
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains localized strings table for a given culture.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="JsonAssetBase" />
|
||||||
|
API_CLASS(NoSpawn) class FLAXENGINE_API LocalizedStringTable : public JsonAssetBase
|
||||||
|
{
|
||||||
|
DECLARE_ASSET_HEADER(LocalizedStringTable);
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// The locale of the localized string table (eg. pl-PL).
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD() String Locale;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The string table. Maps the message id into the localized text. For plural messages the list contains separate items for value numbers.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD() Dictionary<String, Array<String>> Entries;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the localized string to the table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The message id. Used for lookups.</param>
|
||||||
|
/// <param name="value">The localized text.</param>
|
||||||
|
API_FUNCTION() void AddString(const StringView& id, const StringView& value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the localized plural string to the table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The message id. Used for lookups.</param>
|
||||||
|
/// <param name="value">The localized text.</param>
|
||||||
|
/// <param name="n">The plural value (0, 1, 2..).</param>
|
||||||
|
API_FUNCTION() void AddPluralString(const StringView& id, const StringView& value, int32 n);
|
||||||
|
|
||||||
|
#if USE_EDITOR
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves this asset to the file. Supported only in Editor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The custom asset path to use for the saving. Use empty value to save this asset to its own storage location. Can be used to duplicate asset. Must be specified when saving virtual asset.</param>
|
||||||
|
/// <returns>True if cannot save data, otherwise false.</returns>
|
||||||
|
API_FUNCTION() bool Save(const StringView& path = StringView::Empty);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// [JsonAssetBase]
|
||||||
|
LoadResult loadAsset() override;
|
||||||
|
void unload(bool isReloading) override;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user