Skip to content
Open
Show file tree
Hide file tree
Changes from all 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.24",
"version": "1.1.25",
"description": "Utils for working with Builder.io content",
"main": "./dist/index.js",
"scripts": {
Expand Down
32 changes: 32 additions & 0 deletions packages/utils/src/translation-helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,38 @@ test('getTranslateableFields from content to match snapshot', async () => {
},
},
},
{
meta: {
instructions: 'Button with plain text',
},
id: 'button-plain-text-id',
'@type': '@builder.io/sdk:Element',
component: {
name: 'Core:Button',
options: {
text: 'Cute Baby',
openLinkInNewTab: false,
},
},
},
{
meta: {
instructions: 'Button with pre-localized text',
},
id: 'button-localized-text-id',
'@type': '@builder.io/sdk:Element',
component: {
name: 'Core:Button',
options: {
text: {
'@type': localizedType,
'en-US': 'Click Me!',
Default: 'Click Here',
},
openLinkInNewTab: true,
},
},
},
{
'@type': '@builder.io/sdk:Element',
id: 'builder-custom-component-id',
Expand Down
54 changes: 54 additions & 0 deletions packages/utils/src/translation-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,21 @@ export function getTranslateableFields(
};
}

if (el && el.id && el.component?.name === 'Core:Button' && !el.meta?.excludeFromTranslation) {
const componentText = el.component.options?.text;
if (componentText) {
const textValue = typeof componentText === 'string'
? componentText
: componentText?.[sourceLocaleId] || componentText?.Default;
if (textValue) {
results[`blocks.${el.id}#text`] = {
value: textValue,
instructions: el.meta?.instructions || defaultInstructions,
};
}
}
}

if (el && el.id && el.component?.name === 'Symbol') {
const symbolInputs = Object.entries(el.component?.options?.symbol?.data) || [];
if (symbolInputs.length) {
Expand Down Expand Up @@ -325,6 +340,45 @@ export function applyTranslation(
});
}

// Core:Button special handling - similar to Text component
if (
el &&
el.id &&
el.component?.name === 'Core:Button' &&
!el.meta?.excludeFromTranslation &&
translation[`blocks.${el.id}#text`]
) {
const localizedValues =
typeof el.component.options?.text === 'string'
? {
Default: el.component.options.text,
}
: el.component.options.text;

const updatedElement = {
...el,
meta: {
...el.meta,
translated: true,
// this tells the editor that this is a forced localized input similar to clicking the globe icon
'transformed.text': 'localized',
},
component: {
...el.component,
options: {
...el.component.options,
text: {
'@type': localizedType,
...localizedValues,
[locale]: unescapeStringOrObject(translation[`blocks.${el.id}#text`].value),
},
},
},
};

this.update(updatedElement);
}

// custom components
if (el && el.id && el.meta?.localizedTextInputs) {
// there's a localized input
Expand Down
3 changes: 2 additions & 1 deletion packages/utils/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"esModuleInterop": true,
"skipLibCheck": true,
"strict": true,
"declaration": true
"declaration": true,
"types": []
},
"include": ["./src"],
"exclude": ["node_modules", "**/*.test.ts"]
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-8",
"version": "0.0.23-9",
"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.23",
"@builder.io/utils": "1.1.25",
"fast-json-stable-stringify": "^2.1.0",
"lodash": "^4.17.21",
"object-hash": "^3.0.0",
Expand Down
4 changes: 2 additions & 2 deletions plugins/smartling/src/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -692,8 +692,8 @@ const initializeSmartlingPlugin = async () => {
},
async onClick(content) {
const translationBatch = fastClone(content.meta).translationBatch;
// https://dashboard.smartling.com/app/projects/0e6193784/strings/jobs/schqxtpcnxix
const smartlingFile = `https://dashboard.smartling.com/app/projects/${translationBatch.projectId}/strings/jobs/${translationBatch.translationJobUid}`;
// Filter by file URI (content ID) to show all translations across all jobs
const smartlingFile = `https://dashboard.smartling.com/app/projects/${translationBatch.projectId}/strings/?urlsFilter.urls=${content.id}&limit=200&offset=0`;
window.open(smartlingFile, '_blank', 'noreferrer,noopener');
},
});
Expand Down
12 changes: 8 additions & 4 deletions plugins/smartling/src/smartling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,18 @@ export class SmartlingApi {
}
async updateLocalJob(jobId: string, content: any[]) {
const latestDraft = await appState.getLatestDraft(jobId);
const allContent = [...content];
const processedSymbols = new Set<string>(); // Avoid duplicates

// Get existing entries to check for duplicate symbols
// Get existing entries to check for duplicate content and symbols
const existingEntryIds = new Set((latestDraft.data.entries || []).map((entry: any) => entry.content?.id));

// Filter out content that already exists in the job
const newContent = content.filter(c => !existingEntryIds.has(c.id));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question:
Curious Q: what happens when the smartling job is being processed and we update the content during that time ? Do we have to schedule new job ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That could cause issues, not handling that right now. It would be a new feature request.


const allContent = [...newContent];

// Extract and include symbol content for updates too
for (const contentItem of content) {
for (const contentItem of newContent) {
try {
// Fetch the full content to analyze for symbols
const fullContent = await fetch(
Expand Down Expand Up @@ -159,7 +163,7 @@ export class SmartlingApi {
published: 'draft',
};

const symbolCount = allContent.length - content.length;
const symbolCount = allContent.length - newContent.length;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question:
Won't allContent and newContent will always have same length here ?

Copy link
Contributor Author

@anaghav2023 anaghav2023 Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you check the code above allContent is getting updated. We add symbols to it

if (symbolCount > 0) {
} else {
}
Expand Down
Loading