feat(translate): add Lionbridge translation connector - #656
feat(translate): add Lionbridge translation connector#656markdaugherty wants to merge 15 commits into
Conversation
Builds on the initial connector implementation (adobe#651) with fixes found via live testing against Lionbridge's Content API v2: - providerId must be sent on job submit, not job creation (the API silently drops it on POST /jobs; submit fails without it) - retrievefile needs Accept: application/octet-stream, not the default application/json (403s otherwise); other endpoints are unaffected - add rate-limit handling (429/503 retry with exponential backoff, honoring Retry-After) per Lionbridge's dev guidelines - truncate jobName/requestName to the 250-byte guideline limit - generate and persist a per org/site/env connector GUID, prefixed onto connectorName per Lionbridge's connector-fingerprinting guideline - call the approve endpoint after a successful download/save, closing out the request in Lionbridge's review workflow - fix auth.js to resolve the da-etc origin via the shared DA_ETC export (with env-override support) instead of a hardcoded URL - add test coverage for auth.js, connectorGuid.js, and the full sendAllLanguages/getStatusAll/saveItems flow (previously only statusFor had tests) Verified end-to-end against real Lionbridge staging APIs and, separately, through the actual DA Translate app UI against a real test site (scdemos/lionbridge-demo).
- Add JSDoc to every function in index.js, auth.js, and connectorGuid.js that was missing it. - CONNECTOR_NAME is now "DA Live Localization for Lionbridge" instead of the generic "DA Live Localization", to distinguish it from connectors for other vendors in Lionbridge's own job/connector listings.
…copy Extracted while fixing the same class of issue in the Smartling connector (429s during batch jobs) — rather than maintain two nearly identical retry/backoff implementations, both now share nx/blocks/loc/utils/fetchWithRetry.js. Passes an explicit RETRY_CONFIG (maxRetries: 3, maxDelayMs: 8000, 429/503 only) to preserve this connector's existing tuning exactly; behavior is unchanged.
Audited all 5 loc connectors for duplicate code before extracting anything; two candidates were genuinely duplicated and safe to merge. - nx/blocks/loc/utils/downloadQueue.js: the Queue + setInterval poll-until-every-url-has-status pattern was identical across all 4 real connectors' saveItems. Each now ends with one call instead of ~15 duplicated lines. - nx/blocks/loc/utils/auth.js: Trados's and Lionbridge's auth.js were near-verbatim duplicates of the same da-etc login/token-cache flow. Consolidated into a single module exporting getAccessToken/authReady keyed by connector name; deleted both per-connector auth.js files entirely since they'd shrunk to trivial delegations. Along the way, merged LOGIN_ORIGIN onto the DA_ETC-aware definition (giving Trados a local-dev override it didn't have) and confirmed against da-etc's own routes/ints.js that including ?env= is correct for both connectors, not just Lionbridge (Trados previously never sent it). Left alone: Smartling/GLaaS's auth (fundamentally different flows), Trados/GLaaS's CORS-proxy-wrapper duplication, and GLaaS's partial overlap with the shared dnt.js helpers - flagged, not extracted here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
| export async function getStatusAll({ service, langs, urls, actions }) { | ||
| const { sendMessage, saveState } = actions; | ||
|
|
||
| const jobId = langs[0]?.translation?.jobId; |
There was a problem hiding this comment.
This assumes every language belongs to the first language’s job. Waiting/dependent languages are submitted as separate Lionbridge jobs, so requests from those jobs are never fetched and those languages remain in progress. Please group languages by translation.jobId, fetch requests for each job, and calculate status only for that job’s languages.
| // (REVIEW_TRANSLATION -> TRANSLATION_APPROVED). Failure here doesn't | ||
| // affect the already-successful download/save. | ||
| try { | ||
| await approveRequest(service, jobId, requestId); |
There was a problem hiding this comment.
saveFn() can resolve after a failed DA write while setting url.status = "error". This still approves the Lionbridge request, incorrectly signaling successful delivery and potentially closing its review workflow. Please call approveRequest() only after the save reports explicit success (for example, url.status === "success" or a successful return value).
… follow-up jobs - getStatusAll now groups langs by translation.jobId and fetches/applies status per job, instead of applying a single job's requests to every lang - Fixes status computation once a waitingFor language is submitted in its own follow-up job with a different jobId than the initial batch - Add a test covering status computed independently per job Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- saveItems now checks url.status === 'success' before calling approveRequest, avoiding approval when saveFn failed to persist content - Add a test covering the skipped-approval case Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
# Conflicts: # WORKLOG.md
Summary
nx/blocks/loc/connectors/lionbridge/)isConnected/connect/sendAllLanguages/getStatusAll/saveItemsimplementation against Lionbridge's Content API v2Compliance with Lionbridge's dev guidelines
Retry-AfterjobName/requestNametruncated to the 250-byte limit.da/translate.json), prefixed ontoconnectorNameapproveafter a successful download/save (REVIEW_TRANSLATION→TRANSLATION_APPROVED)cancelTranslationexport — guidelines prohibit connector-initiated cancellationShared connector cleanup
Extracted duplicated logic across all translation connectors into
nx/blocks/loc/utils/:downloadQueue.js— theQueue+poll pattern, previously copy-pasted in every connector'ssaveItemsauth.js— da-etc login/token-cache flow shared by Trados and Lionbridge; both per-connectorauth.jsfiles deleted; fixed Trados never sending?env=; resolves the da-etc origin via the sharedDA_ETCexport (env-override support via?da-etc=) instead of a hardcoded URLfetchWithRetry.js— shared retry/backoff, replacing an inline copy; GLaaS/Smartling/Trados updated to use itTests
sendAllLanguages/getStatusAll/saveItems/connect/GUID generation/statusFor) at parity with Trados/Smartlingtest/loc/utils/auth.test.js,test/loc/utils/fetchWithRetry.test.jsnpm testand lint passDocumentation
Lionbridge was missing from the public
docs.da.liveconnector documentation. Draft updates pending publish:getItems()instead ofsaveItems()Dependency