Optimisation de la gestion des Pull Requests avec Pipedrive
Ce workflow permet d'automatiser le suivi des Pull Requests GitHub en les intégrant directement dans Pipedrive. Lorsqu'...
Ce workflow optimise le processus de traduction de fichiers SRT, essentiel pour les entreprises qui cherchent à internationaliser leur contenu vidéo. En automatisant la traduction via Google Translate, ce système réduit considérablement le temps et les efforts nécessaires pour convertir des sous-titres dans différentes langues. L'automatisation permet non seulement d'améliorer l'efficacité opérationnelle, mais aussi d'assurer une cohérence et une précision accrues dans les traductions, ce qui est crucial pour maintenir la qualité du contenu. En facilitant l'intégration des traductions directement dans les fichiers SRT d'origine, cette solution offre une flexibilité et une adaptabilité exceptionnelles pour répondre aux besoins variés des marchés internationaux.
Ce workflow optimise le processus de traduction de fichiers SRT, essentiel pour les entreprises qui cherchent à internationaliser leur contenu vidéo. En automatisant la traduction via Google Translate, ce système réduit considérablement le temps et les efforts nécessaires pour convertir des sous-titres dans différentes langues. L'automatisation permet non seulement d'améliorer l'efficacité opérationnelle, mais aussi d'assurer une cohérence et une précision accrues dans les traductions, ce qui est crucial pour maintenir la qualité du contenu. En facilitant l'intégration des traductions directement dans les fichiers SRT d'origine, cette solution offre une flexibilité et une adaptabilité exceptionnelles pour répondre aux besoins variés des marchés internationaux.
Node | Type | Description |
---|---|---|
Split Out | splitOut | Division des données en plusieurs branches |
Google Translate | googleTranslate | Traitement des données |
Aggregate | aggregate | Traitement des données |
Edit Fields | set | Traitement des données |
Convert to File | convertToFile | Traitement des données |
Split SRT Lines | code | Traitement des données |
Generate Binary | code | Traitement des données |
Prep Parts for Translate | code | Traitement des données |
Clean Translations & Group Titles | code | Traitement des données |
Join completed text with double new line | code | Traitement des données |
Respond with file | form | Traitement des données |
Receive SRT File to Translate | formTrigger | Traitement des données |
Sticky Note | stickyNote | Traitement des données |
Extract text from Binary File | extractFromFile | Traitement des données |
Expose Binary | code | Traitement des données |
{
"id": "vssVsRO0FW6InbaY",
"meta": {
"instanceId": "12aa4b47b8cf3d835676e10b2bf760a80a1ff52932c9898603f7b21fc5376f59",
"templateCredsSetupCompleted": true
},
"name": "Translate",
"tags": [],
"nodes": [
{
"id": "7e55613e-c304-47cb-a017-2d912014ea8e",
"name": "Split Out",
"type": "n8n-nodes-base.splitOut",
"position": [
1180,
140
],
"parameters": {
"options": [],
"fieldToSplitOut": "txt"
},
"typeVersion": 1
},
{
"id": "1ab3e545-e7a1-4b3d-a190-d38cb55ebf96",
"name": "Google Translate",
"type": "n8n-nodes-base.googleTranslate",
"position": [
1620,
140
],
"parameters": {
"text": "={{ JSON.stringify($json.parts.secondPart) }}",
"translateTo": "={{ $json.language }}"
},
"credentials": {
"googleTranslateOAuth2Api": {
"id": "ssWzCSWk0cvCXZtz",
"name": "Google Translate account"
}
},
"typeVersion": 2
},
{
"id": "07de7be3-5477-4e6c-b709-f632a3d5f162",
"name": "Aggregate",
"type": "n8n-nodes-base.aggregate",
"position": [
520,
340
],
"parameters": {
"options": [],
"aggregate": "aggregateAllItemData"
},
"typeVersion": 1
},
{
"id": "cbe5892e-3661-42fb-a850-1e0448a53e0a",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"position": [
960,
340
],
"parameters": {
"options": [],
"assignments": {
"assignments": [
{
"id": "498c663a-f372-40fb-9ac9-79f7a60875cc",
"name": "complete_text",
"type": "string",
"value": "={{ $json.complete_text }}"
},
{
"id": "34f3bc06-151d-4819-b6b8-515cf9c05c60",
"name": "file",
"type": "object",
"value": "={{$('Receive SRT File to Translate').first().json}}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "a4e1cc2e-bd2f-4cf7-af03-73e43cda83d3",
"name": "Convert to File",
"type": "n8n-nodes-base.convertToFile",
"position": [
1400,
340
],
"parameters": {
"options": {
"fileName": "={{ $json['Upload SRT file'].filename.replaceAll('.srt',` ${$('Prep Parts for Translate').first().json.language}.srt`)}}",
"mimeType": "={{ $json['Upload SRT file'].mimetype }}"
},
"operation": "toBinary",
"sourceProperty": "=data",
"binaryPropertyName": "file"
},
"typeVersion": 1.1
},
{
"id": "380bc679-4e08-4d5d-a263-d3d873f4f38f",
"name": "Split SRT Lines",
"type": "n8n-nodes-base.code",
"position": [
960,
140
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "let text = $json.data\n\ndelete $json.base64\ndelete $json.binary\n\n\n\/\/ Split by single newlines\nconst lines = text.split('\\n')\n\n\/\/ Create an array to hold grouped subtitle entries\nlet subtitleGroups = []\nlet currentGroup = []\n\n\/\/ Process each line\nfor (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim()\n \n \/\/ If line is empty and we have content in currentGroup, \n \/\/ it's the end of a subtitle entry\n if (line === '' && currentGroup.length > 0) {\n subtitleGroups.push(currentGroup.join('\\n'))\n currentGroup = []\n } \n \/\/ If line is not empty, add to current group\n else if (line !== '') {\n currentGroup.push(line)\n }\n}\n\n\/\/ Add the last group if it has content\nif (currentGroup.length > 0) {\n subtitleGroups.push(currentGroup.join('\\n'))\n}\n\n\/\/ Remove any quotes at the beginning and end of the first and last entries\nif (subtitleGroups.length > 0) {\n subtitleGroups[0] = subtitleGroups[0].replace(\/^\"\/, '')\n subtitleGroups[subtitleGroups.length - 1] = subtitleGroups[subtitleGroups.length - 1].replace(\/\"$\/, '')\n}\n\n\/\/ Store the result\n$input.item.json.txt = subtitleGroups\n\nreturn $input.item;"
},
"typeVersion": 2
},
{
"id": "08215886-05f6-4ecc-9c1f-55c0e4cb6194",
"name": "Generate Binary",
"type": "n8n-nodes-base.code",
"position": [
1180,
340
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "function encodeBase64(text) {\n try {\n \/\/ For browser environments\n if (typeof window !== 'undefined') {\n \/\/ First, create a UTF-8 encoded string\n const utf8String = encodeURIComponent(text)\n .replace(\/%([0-9A-F]{2})\/g, (_, hex) => {\n return String.fromCharCode(parseInt(hex, 16));\n });\n \n \/\/ Then encode to Base64\n return btoa(utf8String);\n } \n \/\/ For Node.js environments\n else if (typeof Buffer !== 'undefined') {\n return Buffer.from(text).toString('base64');\n }\n \n throw new Error('Environment not supported for Base64 encoding');\n } catch (error) {\n console.error('Error encoding to Base64:', error);\n return null;\n }\n}\n\nlet data = encodeBase64($json.complete_text);\n\nconsole.log(data)\n\nlet file = $json.file\n\nfile.data = data;\n\nlet paddingCount = 0;\nif (data.endsWith('==')) paddingCount = 2;\nelse if (data.endsWith('=')) paddingCount = 1;\n\n\/\/ Calculate the decoded size (in bytes)\nfile.size = Math.floor(data.length * 3 \/ 4) - paddingCount;\n\n\nreturn file"
},
"typeVersion": 2
},
{
"id": "299122c1-61d1-4ce4-81b9-ce15d22cd49c",
"name": "Prep Parts for Translate",
"type": "n8n-nodes-base.code",
"position": [
1400,
140
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "function splitBySecondNewline(text) {\n \/\/ Find the position of the first newline\n const firstNewlinePos = text.indexOf('\\n');\n \n if (firstNewlinePos === -1) {\n return { firstPart: text, secondPart: '' }; \/\/ No newlines found\n }\n \n \/\/ Find the position of the second newline\n const secondNewlinePos = text.indexOf('\\n', firstNewlinePos + 1);\n \n if (secondNewlinePos === -1) {\n return { firstPart: text, secondPart: '' }; \/\/ Only one newline found\n }\n \n \/\/ Split the string at the second newline\n const firstPart = text.substring(0, secondNewlinePos);\n const secondPart = text.substring(secondNewlinePos + 1);\n \n return { firstPart, secondPart };\n}\n\nlet lang = $('Receive SRT File to Translate').first().json['Translate to Language']\n\nreturn {\n parts: splitBySecondNewline($json.txt),\n language: lang\n}"
},
"typeVersion": 2
},
{
"id": "8a810ef3-febe-42f7-91c9-6c82dddcc93a",
"name": "Clean Translations & Group Titles",
"type": "n8n-nodes-base.code",
"position": [
300,
340
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "let translated = $json.translatedText.replaceAll(\"\\\\n\",\"\\n\").replaceAll('"',\"\").replaceAll(''',\"'\");\n\nfunction splitIntoTwoLines(text, maxLength = 40) {\n \/\/ If text already contains a newline or is short enough, return as is\n if (text.includes('\\n') || text.length <= maxLength) {\n return text;\n }\n \n \/\/ Find the last space before or at the maxLength\n let splitIndex = text.lastIndexOf(' ', maxLength);\n \n \/\/ If no space was found (rare case with very long words)\n if (splitIndex === -1) {\n splitIndex = maxLength; \/\/ Force split at maxLength\n }\n \n \/\/ Split the text and join with a newline\n const firstLine = text.substring(0, splitIndex);\n const secondLine = text.substring(splitIndex + 1); \/\/ +1 to skip the space\n \n return firstLine + '\\n' + secondLine;\n}\n\n\/\/ Add a new field called 'myNewField' to the JSON of the item\n$input.item.json.complete = `${$('Prep Parts for Translate').item.json.parts.firstPart}\\n` + splitIntoTwoLines(translated)\n\nreturn $input.item;"
},
"typeVersion": 2
},
{
"id": "15b2781c-4b6f-43e7-9ca9-6d6114e5fdab",
"name": "Join completed text with double new line",
"type": "n8n-nodes-base.code",
"position": [
740,
340
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "let texts = $json.data.map(item=>{\n return item.complete\n})\n\n\n$input.item.json.complete_text = texts.join('\\n\\n')\n\nreturn $input.item;"
},
"typeVersion": 2
},
{
"id": "c43efbb6-3fe8-4aa3-8d65-ed3064bcc948",
"name": "Respond with file",
"type": "n8n-nodes-base.form",
"position": [
1620,
340
],
"webhookId": "b783b857-21b3-41a3-85da-2dbf2d85da54",
"parameters": {
"options": [],
"operation": "completion",
"respondWith": "returnBinary",
"completionTitle": "Done",
"inputDataFieldName": "file"
},
"typeVersion": 1
},
{
"id": "13103a23-3b1a-46d1-9731-c281ff1cac06",
"name": "Receive SRT File to Translate",
"type": "n8n-nodes-base.formTrigger",
"position": [
300,
140
],
"webhookId": "8f3c089f-4cbe-4994-9d0e-d86518ef855c",
"parameters": {
"options": {
"appendAttribution": false
},
"formTitle": "upload srt",
"formFields": {
"values": [
{
"fieldType": "dropdown",
"fieldLabel": "Translate to Language",
"fieldOptions": {
"values": [
{
"option": "EN"
},
{
"option": "JP"
}
]
},
"requiredField": true
},
{
"fieldType": "file",
"fieldLabel": "Upload SRT file",
"multipleFiles": false,
"requiredField": true,
"acceptFileTypes": ".srt"
}
]
},
"responseMode": "lastNode"
},
"typeVersion": 2.2
},
{
"id": "7e0f06f4-1e9d-436f-9310-325214e74bb9",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
280,
-280
],
"parameters": {
"width": 760,
"height": 300,
"content": "## Required Credentials\nhttps:\/\/docs.n8n.io\/integrations\/builtin\/credentials\/google\/\n\n## Selecting Language\nYou can update the form to include your preferred language code (that you are translating to), by updating the dropdown field with a new option. \nOr update the Google Translate node language option back to 'fixed' and select your desired language. This will ignore the form option, but is safe to do."
},
"typeVersion": 1
},
{
"id": "29f9621e-3756-48ee-b6f0-e26a9f7aa247",
"name": "Extract text from Binary File",
"type": "n8n-nodes-base.extractFromFile",
"position": [
740,
140
],
"parameters": {
"options": [],
"operation": "text",
"binaryPropertyName": "Upload_SRT_file"
},
"typeVersion": 1
},
{
"id": "0924754e-6d1f-4d82-bb58-f64ebeac7b05",
"name": "Expose Binary",
"type": "n8n-nodes-base.code",
"position": [
520,
140
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "\/\/ Add a new field called 'myNewField' to the JSON of the item\n$input.item.json.binary = $binary;\n\nreturn $input.item;"
},
"typeVersion": 2
}
],
"active": true,
"pinData": {
"Receive SRT File to Translate": [
{
"json": {
"formMode": "production",
"submittedAt": "2025-04-20T05:46:13.787-04:00",
"Upload SRT file": {
"size": 7748,
"filename": "example_file.srt",
"mimetype": "application\/octet-stream"
},
"Translate to Language": "EN"
}
}
]
},
"settings": {
"executionOrder": "v1"
},
"versionId": "824adb39-806e-4d28-8e41-efd9f2e179a8",
"connections": {
"Aggregate": {
"main": [
[
{
"node": "Join completed text with double new line",
"type": "main",
"index": 0
}
]
]
},
"Split Out": {
"main": [
[
{
"node": "Prep Parts for Translate",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "Generate Binary",
"type": "main",
"index": 0
}
]
]
},
"Expose Binary": {
"main": [
[
{
"node": "Extract text from Binary File",
"type": "main",
"index": 0
}
]
]
},
"Convert to File": {
"main": [
[
{
"node": "Respond with file",
"type": "main",
"index": 0
}
]
]
},
"Generate Binary": {
"main": [
[
{
"node": "Convert to File",
"type": "main",
"index": 0
}
]
]
},
"Split SRT Lines": {
"main": [
[
{
"node": "Split Out",
"type": "main",
"index": 0
}
]
]
},
"Google Translate": {
"main": [
[
{
"node": "Clean Translations & Group Titles",
"type": "main",
"index": 0
}
]
]
},
"Prep Parts for Translate": {
"main": [
[
{
"node": "Google Translate",
"type": "main",
"index": 0
}
]
]
},
"Extract text from Binary File": {
"main": [
[
{
"node": "Split SRT Lines",
"type": "main",
"index": 0
}
]
]
},
"Receive SRT File to Translate": {
"main": [
[
{
"node": "Expose Binary",
"type": "main",
"index": 0
}
]
]
},
"Clean Translations & Group Titles": {
"main": [
[
{
"node": "Aggregate",
"type": "main",
"index": 0
}
]
]
},
"Join completed text with double new line": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
}
}
}
Ce workflow permet d'automatiser le suivi des Pull Requests GitHub en les intégrant directement dans Pipedrive. Lorsqu'...
Ce workflow puissant automatise la synchronisation des événements programmés sur Discord avec Google Calendar, garant...
Ce workflow automatise le processus de récupération des commandes de Squarespace et leur enregistrement dans Google Sh...