Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/utils/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/utils/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@builder.io/utils",
"version": "1.1.27",
"version": "1.1.29",
"description": "Utils for working with Builder.io content",
"main": "./dist/index.js",
"scripts": {
Expand Down
58 changes: 33 additions & 25 deletions packages/utils/src/__snapshots__/translation-helpers.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,31 @@ Object {
}
`;

exports[`getTranslateableFields from carousel content and custom component with subFields to match snapshot 1`] = `
Object {
"blocks.builder-06d3f6da74fb4054ad311afc1dda3675#text": Object {
"instructions": "Visit https://builder.io/fiddle/... for more details",
"value": "<p>I am slide second</p>",
},
"blocks.builder-0a10ae48b6314221bbb7d06d068d623d#text": Object {
"instructions": "Visit https://builder.io/fiddle/... for more details",
"value": "<p>I am slide 1</p>",
},
"blocks.builder-23e0618256ab40799ecf6504bc57fa1c#listItems.0.field1": Object {
"instructions": "Visit https://builder.io/fiddle/... for more details",
"value": "<p>text 1 value</p>",
},
"blocks.builder-23e0618256ab40799ecf6504bc57fa1c#listItems.1.field1": Object {
"instructions": "Visit https://builder.io/fiddle/... for more details",
"value": "<p>text 1.1 value</p>",
},
"blocks.builder-23e0618256ab40799ecf6504bc57fa1c#title.text": Object {
"instructions": "Visit https://builder.io/fiddle/... for more details",
"value": "<p>custom component subField input</p>",
},
}
`;

exports[`getTranslateableFields from content to match snapshot 1`] = `
Object {
"blocks.block-id#text": Object {
Expand Down Expand Up @@ -360,6 +385,14 @@ Object {
"instructions": "Visit https://builder.io/fiddle/... for more details",
"value": "en-us headings!",
},
"blocks.button-localized-text-id#text": Object {
"instructions": "Button with pre-localized text",
"value": "Click Me!",
},
"blocks.button-plain-text-id#text": Object {
"instructions": "Button with plain text",
"value": "Cute Baby",
},
"metadata.seo": Object {
"instructions": "Visit https://builder.io/fiddle/... for more details",
"value": Object {
Expand All @@ -386,28 +419,3 @@ Object {
},
}
`;

exports[`getTranslateableFields from carousel content and custom component with subFields to match snapshot 1`] = `
Object {
"blocks.builder-06d3f6da74fb4054ad311afc1dda3675#text": Object {
"instructions": "Visit https://builder.io/fiddle/... for more details",
"value": "<p>I am slide second</p>",
},
"blocks.builder-0a10ae48b6314221bbb7d06d068d623d#text": Object {
"instructions": "Visit https://builder.io/fiddle/... for more details",
"value": "<p>I am slide 1</p>",
},
"blocks.builder-23e0618256ab40799ecf6504bc57fa1c#listItems.0.field1": Object {
"instructions": "Visit https://builder.io/fiddle/... for more details",
"value": "<p>text 1 value</p>",
},
"blocks.builder-23e0618256ab40799ecf6504bc57fa1c#listItems.1.field1": Object {
"instructions": "Visit https://builder.io/fiddle/... for more details",
"value": "<p>text 1.1 value</p>",
},
"blocks.builder-23e0618256ab40799ecf6504bc57fa1c#title.text": Object {
"instructions": "Visit https://builder.io/fiddle/... for more details",
"value": "<p>custom component subField input</p>",
},
}
`;
54 changes: 46 additions & 8 deletions packages/utils/src/translation-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,27 @@ export function getTranslateableFields(

// blocks
if (blocks) {
// Track how many levels deep we are inside excluded blocks
let excludedDepth = 0;

traverse(blocks).forEach(function (el) {
if (this.key && el && el.meta?.localizedTextInputs) {
// Check if this element starts an exclusion zone
const startsExclusion = el && el.meta?.excludeFromTranslation;
if (startsExclusion) {
excludedDepth++;
}

// After processing children, decrement the counter if this element started an exclusion
this.after(function () {
if (startsExclusion) {
excludedDepth--;
}
});

// Skip translation if we're inside an excluded block (excludedDepth > 0)
const isExcluded = excludedDepth > 0;

if (this.key && el && el.meta?.localizedTextInputs && !isExcluded) {
const localizedTextInputs = el.meta.localizedTextInputs as string[];
if (localizedTextInputs && Array.isArray(localizedTextInputs)) {
localizedTextInputs
Expand All @@ -238,7 +257,7 @@ export function getTranslateableFields(
});
}
}
if (el && el.id && el.component?.name === 'Text' && !el.meta?.excludeFromTranslation) {
if (el && el.id && el.component?.name === 'Text' && !isExcluded) {
const componentText = el.component.options.text;
results[`blocks.${el.id}#text`] = {
value:
Expand All @@ -249,7 +268,7 @@ export function getTranslateableFields(
};
}

if (el && el.id && el.component?.name === 'Core:Button' && !el.meta?.excludeFromTranslation) {
if (el && el.id && el.component?.name === 'Core:Button' && !isExcluded) {
const componentText = el.component.options?.text;
if (componentText) {
const textValue = typeof componentText === 'string'
Expand All @@ -264,7 +283,7 @@ export function getTranslateableFields(
}
}

if (el && el.id && el.component?.name === 'Symbol') {
if (el && el.id && el.component?.name === 'Symbol'&& !isExcluded) {
const symbolInputs = Object.entries(el.component?.options?.symbol?.data) || [];
if (symbolInputs.length) {
const basePath = `blocks.${el.id}.symbolInput`;
Expand Down Expand Up @@ -316,8 +335,27 @@ export function applyTranslation(
}

if (blocks) {
// Track how many levels deep we are inside excluded blocks
let excludedDepth = 0;

traverse(blocks).forEach(function (el) {
if (el && el.id && el.component?.name === 'Symbol') {
// Check if this element starts an exclusion zone
const startsExclusion = el && el.meta?.excludeFromTranslation;
if (startsExclusion) {
excludedDepth++;
}

// After processing children, decrement the counter if this element started an exclusion
this.after(function () {
if (startsExclusion) {
excludedDepth--;
}
});

// Skip translation if we're inside an excluded block (excludedDepth > 0)
const isExcluded = excludedDepth > 0;

if (el && el.id && el.component?.name === 'Symbol' && !isExcluded) {
const symbolInputs = Object.entries(el.component?.options?.symbol?.data) || [];
if (symbolInputs.length) {
const transformedMeta = {};
Expand Down Expand Up @@ -368,7 +406,7 @@ export function applyTranslation(
el &&
el.id &&
el.component?.name === 'Text' &&
!el.meta?.excludeFromTranslation &&
!isExcluded &&
translation[`blocks.${el.id}#text`]
) {
const localizedValues =
Expand Down Expand Up @@ -405,7 +443,7 @@ export function applyTranslation(
el &&
el.id &&
el.component?.name === 'Core:Button' &&
!el.meta?.excludeFromTranslation &&
!isExcluded &&
translation[`blocks.${el.id}#text`]
) {
const localizedValues =
Expand Down Expand Up @@ -440,7 +478,7 @@ export function applyTranslation(
}

// custom components
if (el && el.id && el.meta?.localizedTextInputs) {
if (el && el.id && el.meta?.localizedTextInputs && !isExcluded) {
// there's a localized input
const keys = el.meta?.localizedTextInputs as string[];
let options = el.component.options;
Expand Down
18 changes: 9 additions & 9 deletions plugins/smartling/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions plugins/smartling/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@builder.io/plugin-smartling",
"version": "0.0.23-11",
"version": "0.0.23-13",
"description": "",
"keywords": [],
"main": "dist/plugin.system.js",
Expand Down Expand Up @@ -125,7 +125,7 @@
"typescript": "^3.0.3"
},
"dependencies": {
"@builder.io/utils": "1.1.26",
"@builder.io/utils": "1.1.28",
"fast-json-stable-stringify": "^2.1.0",
"lodash": "^4.17.21",
"object-hash": "^3.0.0",
Expand Down
84 changes: 82 additions & 2 deletions plugins/smartling/src/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ Builder.register('plugin', {
advanced: false,
requiredPermissions: ['admin'],
},
{
name: 'enableVisualContextCapture',
friendlyName: 'Enable Visual Context Capture',
type: 'boolean',
defaultValue: false,
helperText: 'Enable automatic visual context capture for translations',
requiredPermissions: ['admin'],
},
],
onSave: async actions => {
const pluginPrivateKey = await appState.globalState.getPluginPrivateKey(pkg.name);
Expand Down Expand Up @@ -460,7 +468,7 @@ const initializeSmartlingPlugin = async () => {
}
const element = selectedElements[0];
const isExcluded = element.meta?.get(transcludedMetaKey);
return element.component?.name === 'Text' && !isExcluded;
return !isExcluded;
},
onClick(elements) {
elements.forEach(el => el.meta.set('excludeFromTranslation', true));
Expand All @@ -476,13 +484,85 @@ const initializeSmartlingPlugin = async () => {
}
const element = selectedElements[0];
const isExcluded = element.meta?.get(transcludedMetaKey);
return element.component?.name === 'Text' && isExcluded;
return isExcluded;
},
onClick(elements) {
elements.forEach(el => el.meta.set('excludeFromTranslation', false));
},
});


registerContextMenuAction({
label: 'Add String Instructions',
showIf(selectedElements) {
if (selectedElements.length !== 1) {
// todo maybe apply for multiple
return false;
}
const element = selectedElements[0];
return element.meta?.get('instructions') === undefined;
},
async onClick(elements) {
if (elements.length !== 1) {
// todo maybe apply for multiple
return false;
}
const instructions = await appState.dialogs.prompt({
placeholderText: 'Enter string instructions for translation',
});
if (instructions) {
elements[0].meta.set('instructions', instructions);
appState.snackBar.show('String instructions added to content');
}
},
});

registerContextMenuAction({
label: 'Edit String Instructions',
showIf(selectedElements) {
if (selectedElements.length !== 1) {
// todo maybe apply for multiple
return false;
}
const element = selectedElements[0];
return element.meta?.get('instructions') !== undefined;
},
async onClick(elements) {
if (elements.length !== 1) {
// todo maybe apply for multiple
return false;
}
const element = elements[0];
const instructions = element.meta?.get('instructions');
if (instructions !== undefined) {
const newInstructions = await appState.dialogs.prompt({
placeholderText: 'Enter new string instructions for translation',
defaultValue: instructions,
});
if (newInstructions) {
element.meta.set('instructions', newInstructions);
appState.snackBar.show('String instructions updated');
}
}
},
});

registerContextMenuAction({
label: 'Delete String Instructions',
showIf(selectedElements) {
if (selectedElements.length !== 1) {
// todo maybe apply for multiple
return false;
}
const element = selectedElements[0];
return element.meta?.get('instructions') !== undefined;
},
onClick(elements) {
elements[0].meta.delete('instructions');
appState.snackBar.show('String instructions deleted');
},
});

registerContentAction({
label: 'Add to translation job',
showIf(content, model) {
Expand Down
Loading