Skip to content

Commit

Permalink
fix(translations): shallow merge lexical block source fields (#218)
Browse files Browse the repository at this point in the history
* feat(crwodinfiles): add fileData.sourceBlocks field

* fix(translations): shallow merge lexical block source fields
  • Loading branch information
thompsonsj authored Oct 28, 2024
1 parent 6a9b44a commit 5161ec1
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 13 deletions.
9 changes: 9 additions & 0 deletions dev-alternative-config/src/lib/payload-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,15 @@ export interface CrowdinFile {
| boolean
| null;
html?: string | null;
sourceBlocks?:
| {
[k: string]: unknown;
}
| unknown[]
| string
| number
| boolean
| null;
};
updatedAt: string;
createdAt: string;
Expand Down
9 changes: 9 additions & 0 deletions dev/src/lib/payload-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,15 @@ export interface CrowdinFile {
| boolean
| null;
html?: string | null;
sourceBlocks?:
| {
[k: string]: unknown;
}
| unknown[]
| string
| number
| boolean
| null;
};
updatedAt: string;
createdAt: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ export const fixture = {
},
"heading": {
"title": "Block configuration in Lexical fields"
}
},
"color": "yellow",
}
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ describe('Lexical editor with multiple blocks', () => {
fields: {
blockName: '',
blockType: 'highlight',
color: "yellow",
content: {
root: {
children: [
Expand Down Expand Up @@ -523,6 +524,7 @@ describe('Lexical editor with multiple blocks', () => {
fields: {
blockName: '',
blockType: 'highlight',
color: "yellow",
content: {
root: {
children: [
Expand Down Expand Up @@ -707,7 +709,132 @@ describe('Lexical editor with multiple blocks', () => {

expect(files[0].fileData).toEqual({
html: `<p>If you add custom blocks, these will also be translated!</p><span data-block-id=${lexicalBlockIds[0]} data-block-type=highlight></span>`,
});
sourceBlocks: JSON.stringify([
{
"id": `${lexicalBlockIds[0]}`,
"blockName": "",
"blockType": "highlight",
"content": {
"root": {
"children": [
{
"children": [
{
"detail": 0,
"format": 0,
"mode": "normal",
"style": "",
"text": "Note a key difference with regular blocks - all ",
"type": "text",
"version": 1
},
{
"detail": 0,
"format": 16,
"mode": "normal",
"style": "",
"text": "text",
"type": "text",
"version": 1
},
{
"detail": 0,
"format": 0,
"mode": "normal",
"style": "",
"text": ", ",
"type": "text",
"version": 1
},
{
"detail": 0,
"format": 16,
"mode": "normal",
"style": "",
"text": "textarea",
"type": "text",
"version": 1
},
{
"detail": 0,
"format": 0,
"mode": "normal",
"style": "",
"text": " and ",
"type": "text",
"version": 1
},
{
"detail": 0,
"format": 16,
"mode": "normal",
"style": "",
"text": "richText",
"type": "text",
"version": 1
},
{
"detail": 0,
"format": 0,
"mode": "normal",
"style": "",
"text": " fields will be sent to Crowdin regardless of whether or not they are ",
"type": "text",
"version": 1
},
{
"children": [
{
"detail": 0,
"format": 0,
"mode": "normal",
"style": "",
"text": "localized fields",
"type": "text",
"version": 1
}
],
"direction": "ltr",
"format": "",
"indent": 0,
"type": "link",
"version": 2,
"fields": {
"linkType": "custom",
"newTab": false,
"url": "https://payloadcms.com/docs/configuration/localization#field-by-field-localization"
}
},
{
"detail": 0,
"format": 0,
"mode": "normal",
"style": "",
"text": ".",
"type": "text",
"version": 1
}
],
"direction": "ltr",
"format": "",
"indent": 0,
"type": "paragraph",
"version": 1
}
],
"direction": "ltr",
"format": "",
"indent": 0,
"type": "root",
"version": 1
}
},
"heading": {
"title": "Block configuration in Lexical fields"
},
"color": "yellow"
}
])});
expect(files[1].fileData).toMatchInlineSnapshot(`
{
"html": "<p>Lexical fields nested within complex layouts - such as this one (a <code>blocks</code> field in an <code>array</code> item within a <code>tab</code>), are supported.</p>",
Expand Down Expand Up @@ -1220,7 +1347,9 @@ describe('Lexical editor with multiple blocks', () => {
},
{
"fields": {
"blockName": "",
"blockType": "highlight",
"color": "yellow",
"content": {
"root": {
"children": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1184,10 +1184,12 @@ describe('Lexical editor with multiple blocks', () => {
},
{
"fields": {
"blockName": "",
"blockType": "cta",
"href": "https://www.npmjs.com/package/payload-crowdin-sync",
"id": "65d67d2591c92e447e7472f7",
"text": "Téléchargez payload-crowdin-sync sur npm!",
"type": "primary",
},
"format": "",
"type": "block",
Expand Down Expand Up @@ -1263,7 +1265,9 @@ describe('Lexical editor with multiple blocks', () => {
},
{
"fields": {
"blockName": "",
"blockType": "highlight",
"color": "green",
"content": {
"root": {
"children": [
Expand Down Expand Up @@ -1305,8 +1309,10 @@ describe('Lexical editor with multiple blocks', () => {
},
{
"fields": {
"blockName": "",
"blockType": "imageText",
"id": "65d67e2291c92e447e7472f9",
"image": "65d67e6a7fb7e9426b3f9f5f",
"title": "Tester une gamme de domaines",
},
"format": "",
Expand Down
26 changes: 15 additions & 11 deletions plugin/src/lib/api/payload-crowdin-sync/files/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface IupdateOrCreateFile {
name: string;
fileData: FileData;
fileType: "html" | "json";
sourceBlocks?: unknown[]
}

export class payloadCrowdinSyncDocumentFilesApi extends payloadCrowdinSyncFilesApi {
Expand Down Expand Up @@ -84,6 +85,7 @@ export class payloadCrowdinSyncDocumentFilesApi extends payloadCrowdinSyncFilesA
name,
fileData,
fileType,
sourceBlocks,
}: IupdateOrCreateFile) {
const empty = isEmpty(fileData);
// Check whether file exists on Crowdin
Expand All @@ -95,13 +97,15 @@ export class payloadCrowdinSyncDocumentFilesApi extends payloadCrowdinSyncFilesA
name,
fileData,
fileType,
sourceBlocks,
});
} else {
updatedCrowdinFile = await this.updateFile({
crowdinFile,
name: name,
fileData,
fileType,
sourceBlocks,
});
}
} else {
Expand All @@ -117,6 +121,7 @@ export class payloadCrowdinSyncDocumentFilesApi extends payloadCrowdinSyncFilesA
name,
fileData,
fileType,
sourceBlocks,
}: {crowdinFile: CrowdinFile} & IupdateOrCreateFile) {
// Update file on Crowdin
const updatedCrowdinFile = await this.crowdinUpdateFile({
Expand All @@ -136,7 +141,7 @@ export class payloadCrowdinSyncDocumentFilesApi extends payloadCrowdinSyncFilesA
...(fileType === "json" && { fileData: { json: (fileData as {
[k: string]: Partial<unknown>;
}) }}),
...(fileType === "html" && { fileData: { html: typeof fileData === 'string' ? fileData : JSON.stringify(fileData) } }),
...(fileType === "html" && { fileData: { html: typeof fileData === 'string' ? fileData : JSON.stringify(fileData), ...(sourceBlocks && { sourceBlocks: JSON.stringify(sourceBlocks) }) } }),
},
req: this.req,
});
Expand All @@ -146,6 +151,7 @@ export class payloadCrowdinSyncDocumentFilesApi extends payloadCrowdinSyncFilesA
name,
fileData,
fileType,
sourceBlocks,
}: IupdateOrCreateFile) {
// Create file on Crowdin
const originalId = this.articleDirectory.originalId
Expand Down Expand Up @@ -179,7 +185,7 @@ export class payloadCrowdinSyncDocumentFilesApi extends payloadCrowdinSyncFilesA
...(fileType === "json" && { fileData: { json: (fileData as {
[k: string]: Partial<unknown>;
}) } }),
...(fileType === "html" && { fileData: { html: typeof fileData === 'string' ? fileData : JSON.stringify(fileData) } }),
...(fileType === "html" && { fileData: { html: typeof fileData === 'string' ? fileData : JSON.stringify(fileData), ...(sourceBlocks && { sourceBlocks: JSON.stringify(sourceBlocks) })} }),
},
req: this.req,
});
Expand Down Expand Up @@ -228,7 +234,7 @@ export class payloadCrowdinSyncDocumentFilesApi extends payloadCrowdinSyncFilesA
collection: CollectionConfig | GlobalConfig;
}) {
// brittle check for Lexical value - improve this detection. Type check? Anything from Payload to indicate the type?
let html
let html, blockContent
const isLexical = Object.prototype.hasOwnProperty.call(value, "root")
if (isLexical) {
const field = findField({
Expand All @@ -241,16 +247,11 @@ export class payloadCrowdinSyncDocumentFilesApi extends payloadCrowdinSyncFilesA
if (editorConfig) {
html = await convertLexicalToHtml(value, editorConfig)
// no need to detect change - this has already been done on the field's JSON object
const blockContent = value && extractLexicalBlockContent(value.root)
if (blockContent && blockContent.length > 0) {
blockContent = value && extractLexicalBlockContent(value.root)
const blockConfig = editorConfig && getLexicalBlockFields(editorConfig)
if (blockContent && blockContent.length > 0 && blockConfig) {
// directory name must be unique from file names - Crowdin API
const folderName = `${this.pluginOptions.lexicalBlockFolderPrefix}${name}`
const blockConfig = getLexicalBlockFields(editorConfig)

if (!blockConfig) {
return
}

/**
* Initialize Crowdin client sourceFilesApi
*/
Expand Down Expand Up @@ -332,6 +333,9 @@ export class payloadCrowdinSyncDocumentFilesApi extends payloadCrowdinSyncFilesA
name: name,
fileData: html,
fileType: "html",
...(!isEmpty(blockContent) && {
sourceBlocks: blockContent
}),
});
}

Expand Down
17 changes: 17 additions & 0 deletions plugin/src/lib/api/payload-crowdin-sync/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { Config, CrowdinFile } from "../../payload-types";
import { getCollectionConfig, getFile, getFileByDocumentID, getFiles, getFilesByDocumentID, getLexicalFieldArticleDirectory } from "../helpers";
import { getLexicalBlockFields, getLexicalEditorConfig } from "../../utilities/lexical";
import { getRelationshipId } from "../../utilities/payload";
import { assign, isEmpty } from "lodash";

interface IgetLatestDocumentTranslation {
collection: string;
Expand Down Expand Up @@ -504,6 +505,7 @@ export class payloadCrowdinSyncTranslationsApi {
private async getBlockTranslations({
blockConfig,
locale,
file,
crowdinArticleDirectoryId,
}: {
blockConfig: {
Expand Down Expand Up @@ -556,6 +558,21 @@ export class payloadCrowdinSyncTranslationsApi {
isLocalized: (field) => !!(field),
});

// merge non-localized fields back in
if (!isEmpty(file.fileData?.sourceBlocks)) {
const sourceBlocks = JSON.parse(`${file.fileData?.sourceBlocks}`) || []
const processed = (docTranslations['blocks'] || []).map((translatedBlock: {id: string}) => {
const sourceBlock = sourceBlocks.find((block: any) => block.id === translatedBlock.id)
if (sourceBlock) {
return assign(sourceBlock, translatedBlock)
}
return translatedBlock
})
return {
blocks: processed
}
}

return docTranslations
}

Expand Down
7 changes: 7 additions & 0 deletions plugin/src/lib/collections/CrowdinFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ const CrowdinFiles: CollectionConfig = {
type: "textarea",
maxLength: 2000000,
},
{
name: "sourceBlocks",
type: "json",
admin: {
description: "Copy Lexical field blocks as a translation source enabling a convenient method of merging block content on translation (i.e. merge non-translated fields like type=select)."
},
}
],
},
],
Expand Down
Loading

0 comments on commit 5161ec1

Please sign in to comment.