Created
July 29, 2025 14:21
-
-
Save KevinJump/884ab7d32a1cba1181870278b300ad6a to your computer and use it in GitHub Desktop.
Translation Manager : Limbo Tables property mapper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Jumoo.TranslationManager.Core; | |
using Jumoo.TranslationManager.Core.Extensions; | |
using Jumoo.TranslationManager.Core.Models; | |
using Jumoo.TranslationManager.Core.ValueMappers; | |
using Newtonsoft.Json; | |
using Newtonsoft.Json.Linq; | |
using Umbraco.Cms.Core.Services; | |
namespace TranslationManager.Site.Thirteen.Code; | |
/// <summary> | |
/// Provides a value mapper for the Limbo tables property editor, enabling translation of table cell content. | |
/// </summary> | |
/// <remarks> | |
/// This property editor stores its content as a JSON object with an array of 'cells'. | |
/// Each cell contains row and column indices, a value (using a Rich Text Editor), and additional metadata. | |
/// The value in each cell is mapped using the TinyMCE value mapper to support translation of rich text content. | |
/// </remarks> | |
public class LimboTablesMapper : ValueMapperOptionsBase, IValueMapper | |
{ | |
private readonly Lazy<ValueMapperCollection> _mappers; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="LimboTablesMapper"/> class. | |
/// </summary> | |
/// <param name="contentService">The content service.</param> | |
/// <param name="dataTypeService">The data type service.</param> | |
/// <param name="contentTypeService">The content type service.</param> | |
/// <param name="logger">The logger instance.</param> | |
/// <param name="mappers">A lazy-loaded collection of value mappers.</param> | |
public LimboTablesMapper( | |
IContentService contentService, | |
IDataTypeService dataTypeService, | |
IContentTypeService contentTypeService, | |
ILogger<ValueMapperOptionsBase> logger, | |
Lazy<ValueMapperCollection> mappers) | |
: base(contentService, dataTypeService, contentTypeService, logger) | |
{ | |
_mappers = mappers; | |
} | |
/// <summary> | |
/// Gets the name of the value mapper. | |
/// </summary> | |
public string Name => "Limbo Tables Mapper"; | |
/// <summary> | |
/// Gets the list of property editor aliases this mapper supports. | |
/// </summary> | |
public override string[] Editors => ["Limbo.Umbraco.Tables"]; | |
/// <summary> | |
/// Extracts the source value for translation from the Limbo tables property editor. | |
/// </summary> | |
/// <param name="options">The source options containing property and value information.</param> | |
/// <returns> | |
/// A <see cref="TranslationValue"/> representing the table's translatable content, | |
/// or <c>null</c> if the value is not valid or cannot be parsed. | |
/// </returns> | |
public override TranslationValue? GetSourceValue(PropertyValueMapperSourceOptions options) | |
{ | |
var attempt = options.SourceValue.TryConvertTo<string>(); | |
if (!attempt.Success || attempt.Result is null) return null; | |
var jsonValue = JsonConvert.DeserializeObject<JObject>(attempt.Result); | |
if (jsonValue is null) return null; | |
if (jsonValue.ContainsKey("cells") is false) return null; | |
if (jsonValue["cells"] is not JArray data) return null; | |
var translationValue = new TranslationValue(options.DisplayName, options.PropertyTypeAlias, options.Path); | |
foreach (var row in data) | |
{ | |
// data is an array of rows, each row is an array of cells | |
foreach (var cell in row.Cast<JObject>()) | |
{ | |
// we use the rowIndex and columnIndex to identify the cell | |
// this way when the content comes back in we can put it back in the same cell, | |
// even if the translations come back in a different order | |
if (cell.TryGetValue("rowIndex", out var rowIndex) is false | |
|| cell.TryGetValue("columnIndex", out var columnIndex) is false) | |
continue; | |
if (cell.TryGetValue("value", out var cellValue) is false) | |
continue; | |
var cellTranslationValue = _mappers.Value.GetMapperSource(new PropertyValueMapperSourceOptions | |
{ | |
DisplayName = $"{options.DisplayName} [{rowIndex}, {columnIndex}]", | |
PropertyTypeAlias = Umbraco.Cms.Core.Constants.PropertyEditors.Aliases.TinyMce, | |
Path = options.Path.AppendPath($"{rowIndex}-{columnIndex}"), | |
SourceValue = cellValue.ToString(), | |
MasterIsVariant = options.MasterIsVariant, | |
RequireVariant = options.RequireVariant | |
}); | |
if (cellTranslationValue is not null) | |
{ | |
translationValue.InnerValues.Add( | |
$"{rowIndex}-{columnIndex}", | |
cellTranslationValue); | |
} | |
} | |
} | |
return translationValue; | |
} | |
/// <summary> | |
/// Applies translated values to the Limbo tables property editor's JSON structure. | |
/// </summary> | |
/// <param name="options">The target options containing translation values and culture information.</param> | |
/// <returns> | |
/// A JSON string representing the updated table content with translated cell values, | |
/// or <c>null</c> if the value is not valid or cannot be parsed. | |
/// </returns> | |
public override object? GetTargetValue(PropertyValueMapperTargetOptions options) | |
{ | |
var attempt = options.SourceValue.TryConvertTo<string>(); | |
if (!attempt.Success || attempt.Result is null) return null; | |
var jsonValue = JsonConvert.DeserializeObject<JObject>(attempt.Result); | |
if (jsonValue is null) return null; | |
if (jsonValue.ContainsKey("cells") is false) return null; | |
if (jsonValue["cells"] is not JArray data) return null; | |
foreach (var row in data) | |
{ | |
// data is an array of rows, each row is an array of cells | |
foreach (var cell in row.Cast<JObject>()) | |
{ | |
if (cell.TryGetValue("rowIndex", out var rowIndex) is false | |
|| cell.TryGetValue("columnIndex", out var columnIndex) is false) | |
continue; | |
if (cell.TryGetValue("value", out var cellValue) is false) | |
continue; | |
var translation = options.Values.GetInnerValue($"{rowIndex}-{columnIndex}", options.TargetCulture.Name); | |
if (translation is null) | |
continue; | |
var mappedValue = _mappers.Value.GetMapperTarget(new PropertyValueMapperTargetOptions | |
{ | |
PropertyTypeAlias = Umbraco.Cms.Core.Constants.PropertyEditors.Aliases.TinyMce, | |
SourceValue = cellValue.ToString(), | |
Values = translation, | |
SourceCulture = options.SourceCulture, | |
TargetCulture = options.TargetCulture, | |
MasterIsVariant = options.MasterIsVariant, | |
RequireVariant = options.RequireVariant | |
}); | |
cell["value"] = mappedValue.ToString(); | |
} | |
} | |
return JsonConvert.SerializeObject(jsonValue, Formatting.Indented); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment