{"id":36366,"date":"2024-11-27T07:00:00","date_gmt":"2024-11-27T15:00:00","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=36366"},"modified":"2024-11-27T15:34:51","modified_gmt":"2024-11-27T23:34:51","slug":"video-subtitle-translation-azure","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure","title":{"rendered":"Video Subtitle Translation in Cloudinary With Azure"},"content":{"rendered":"\n<p>Video captions and subtitles have evolved from an accessibility feature to a universal tool for user engagement. A whopping <a href=\"https:\/\/www.forbes.com\/sites\/tjmccue\/2019\/07\/31\/verizon-media-says-69-percent-of-consumers-watching-video-with-sound-off\/\" target=\"_blank\" rel=\"noreferrer noopener\">80% of viewers<\/a> are more likely to watch a video from beginning to end if captions are available. According to that same study, 69% of viewers keep their sound off in public spaces, while 50% prefer to watch on mute regardless of where they are. <\/p>\n\n\n\n<p>Needless to say, adding captions and subtitles will expand your video&#8217;s reach. This blog post shows you how to automatically generate and translate subtitles using <a href=\"https:\/\/cloudinary.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">Cloudinary<\/a> and <a href=\"https:\/\/cloudinary.com\/documentation\/microsoft_azure_video_indexer_addon\" target=\"_blank\" rel=\"noreferrer noopener\">Microsoft Azure Video Indexer<\/a> in a Next.js app.<\/p>\n\n\n\n<p>Here\u2019s a <a target=\"_blank\" href=\"https:\/\/www.loom.com\/share\/731bb30a1bb04f329e62732d54e66d42?sid=c3e91925-0e95-4439-990e-270c87ed18d3\" rel=\"noreferrer noopener\">preview<\/a> of the demo, where users can view video content with English and Spanish subtitles.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/paper-attachments.dropboxusercontent.com\/s_89B489B4C7E7F120EAEA66A9697DAAD9257E797A007FED97437B41636C79CA67_1732575053951_image.png\" alt=\"\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Setting Up Cloudinary and Next.js<\/h2>\n\n\n\n<p>If you don\u2019t have a Next.js project already, create one by running the following command:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">npx<\/span> <span class=\"hljs-selector-tag\">create-next-app<\/span><span class=\"hljs-keyword\">@14<\/span> subtitle-translation-demo\n\ncd subtitle-translation-demo<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Next, install the <a target=\"_blank\" href=\"https:\/\/www.npmjs.com\/package\/cloudinary\" rel=\"noreferrer noopener\">Cloudinary Node.js SDK<\/a>, which allows you to interact with Cloudinary\u2019s API directly from your app:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">code<\/span>&gt;<\/span>npm install cloudinary<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">code<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Once this package is installed, connect your app to Cloudinary using your Cloudinary API credentials. Navigate to your <a target=\"_blank\" href=\"https:\/\/cloudinary.com\/\" rel=\"noreferrer noopener\">Cloudinary dashboard<\/a> and copy your <strong>cloud name<\/strong>, <strong>API key<\/strong>, and <strong>API secret<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/paper-attachments.dropboxusercontent.com\/s_24A4C6FBD1904FE24CE64975AA4E7474657201ECD72EEB3B5A85CD0A34688AC2_1727519080103_image.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">Cloudinary API keys from its dashboard.<\/figcaption><\/figure>\n\n\n\n<p>Create a <code>.env.local<\/code> file in the root of your project to securely add your Cloudinary credentials:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-wrap-lines\">NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=your_cloud_name\n\nNEXT_PUBLIC_CLOUDINARY_API_KEY=your_api_key\n\nCLOUDINARY_API_SECRET=your_api_secret<\/code><\/span><\/pre>\n\n\n<p>The next step is to initialize Cloudinary by creating a lib &nbsp;folder in the root of your project and a cloudinary.ts file in the folder to configure Cloudinary:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ lib\/cloudinary.ts<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> { v2 <span class=\"hljs-keyword\">as<\/span> cloudinary } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'cloudinary'<\/span>;\n\ncloudinary.config({\n\n\u00a0 <span class=\"hljs-attr\">cloud_name<\/span>: process.env.CLOUDINARY_CLOUD_NAME,\n\n\u00a0 <span class=\"hljs-attr\">api_key<\/span>: process.env.CLOUDINARY_API_KEY,\n\n\u00a0 <span class=\"hljs-attr\">api_secret<\/span>: process.env.CLOUDINARY_API_SECRET,\n\n\u00a0 <span class=\"hljs-attr\">secure<\/span>: <span class=\"hljs-literal\">true<\/span>,\n\n});\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> cloudinary;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This setup allows you to easily interact with Cloudinary\u2019s API throughout your app.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Uploading Video to Cloudinary with Next.js<\/h2>\n\n\n\n<p>With Cloudinary set up, you can now upload videos using <a target=\"_blank\" href=\"https:\/\/nextjs.org\/docs\/app\/building-your-application\/data-fetching\/server-actions-and-mutations\" rel=\"noreferrer noopener\">server actions<\/a>, which helps streamline the process of handling video uploads and optimization directly on the server side, keeping the logic cleaner and more efficient.&nbsp;<\/p>\n\n\n\n<p>Start by creating a form that allows users to select and upload a video. You can include the following form in your page.tsx file, and a loading state, which is used to track the upload process.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ app\/page.tsx<\/span>\n\n<span class=\"hljs-string\">'use client'<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Home<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n\n\u00a0 <span class=\"hljs-keyword\">const<\/span> &#91;loading, setLoading] = useState(<span class=\"hljs-literal\">false<\/span>);\n\n\u00a0 <span class=\"hljs-keyword\">const<\/span> handleSubmit = <span class=\"hljs-keyword\">async<\/span> (event: React.FormEvent&lt;HTMLFormElement&gt;) =&gt; {\n\n\u00a0 \u00a0 event.preventDefault();\n\n\u00a0 \u00a0 setLoading(<span class=\"hljs-literal\">true<\/span>);\n\n\u00a0 \u00a0 <span class=\"hljs-keyword\">const<\/span> formData = <span class=\"hljs-keyword\">new<\/span> FormData(event.currentTarget); <span class=\"hljs-comment\">\/\/ Retrieve the video file<\/span>\n\n\u00a0 \u00a0 <span class=\"hljs-keyword\">try<\/span> {\n\n\u00a0 \u00a0 \u00a0 <span class=\"hljs-comment\">\/\/ Upload video function will go here<\/span>\n\n\u00a0 \u00a0 } <span class=\"hljs-keyword\">catch<\/span> (error) {\n\n\u00a0 \u00a0 \u00a0 <span class=\"hljs-built_in\">console<\/span>.error(<span class=\"hljs-string\">'Upload failed:'<\/span>, error);\n\n\u00a0 \u00a0 } <span class=\"hljs-keyword\">finally<\/span> {\n\n\u00a0 \u00a0 \u00a0 setLoading(<span class=\"hljs-literal\">false<\/span>);\n\n\u00a0 \u00a0 }\n\n\u00a0 };\n\n\u00a0 <span class=\"hljs-keyword\">return<\/span> (\n\n\u00a0 \u00a0 <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span>&gt;<\/span>Upload Your Video<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span> <span class=\"hljs-attr\">onSubmit<\/span>=<span class=\"hljs-string\">{handleSubmit}<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"file\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"video\"<\/span> <span class=\"hljs-attr\">accept<\/span>=<span class=\"hljs-string\">\"video\/*\"<\/span> <span class=\"hljs-attr\">required<\/span> \/&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"submit\"<\/span> <span class=\"hljs-attr\">disabled<\/span>=<span class=\"hljs-string\">{loading}<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 {loading ? 'Uploading...' : 'Upload Video'}\n\n\u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n\n\u00a0 );\n\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Next, create the server action responsible for handling video uploads. This action processes the video and uploads it directly to Cloudinary.<\/p>\n\n\n\n<p>Create an upload.ts file in the app directory of your project and add the following code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ app\/upload.ts<\/span>\n\n<span class=\"hljs-string\">'use server'<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> cloudinary <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/lib\/cloudinary'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">upload<\/span>(<span class=\"hljs-params\">formData: FormData<\/span>) <\/span>{\n\n\u00a0 <span class=\"hljs-keyword\">const<\/span> file = formData.get(<span class=\"hljs-string\">'video'<\/span>) <span class=\"hljs-keyword\">as<\/span> File;\n\n\u00a0 <span class=\"hljs-keyword\">const<\/span> buffer: Buffer = Buffer.from(<span class=\"hljs-keyword\">await<\/span> file.arrayBuffer()); <span class=\"hljs-comment\">\/\/ Convert the video to a buffer<\/span>\n\n\u00a0 <span class=\"hljs-comment\">\/\/ Ensure the public ID is safe for URLs<\/span>\n\n\u00a0 <span class=\"hljs-keyword\">const<\/span> safePublicId = file.name.replace(<span class=\"hljs-regexp\">\/&#91;^a-zA-Z0-9-_]\/g<\/span>, <span class=\"hljs-string\">'_'<\/span>);\n\n\u00a0 <span class=\"hljs-keyword\">const<\/span> uploadResponse = <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Promise<\/span>&lt;{ <span class=\"hljs-attr\">secure_url<\/span>: string; public_id: string }&gt;(\n\n\u00a0 \u00a0 <span class=\"hljs-function\">(<span class=\"hljs-params\">resolve, reject<\/span>) =&gt;<\/span> {\n\n\u00a0 \u00a0 \u00a0 cloudinary.uploader\n\n\u00a0 \u00a0 \u00a0 \u00a0 .upload_stream(\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 {\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">'video'<\/span>,\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">public_id<\/span>: safePublicId,\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 },\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 (error, result) =&gt; {\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-keyword\">if<\/span> (error) {\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 reject(<span class=\"hljs-string\">`Upload failed: <span class=\"hljs-subst\">${error.message}<\/span>`<\/span>);\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 } <span class=\"hljs-keyword\">else<\/span> {\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 resolve(result);\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\n\u00a0 \u00a0 \u00a0 \u00a0 )\n\n\u00a0 \u00a0 \u00a0 \u00a0 .end(buffer); <span class=\"hljs-comment\">\/\/ Stream the video file as a buffer to Cloudinary<\/span>\n\n\u00a0 \u00a0 }\n\n\u00a0 );\n\n\u00a0 <span class=\"hljs-comment\">\/\/ Return the Cloudinary video URL and public ID for further processing<\/span>\n\n\u00a0 <span class=\"hljs-keyword\">return<\/span> {\n\n\u00a0 \u00a0 <span class=\"hljs-attr\">originalUrl<\/span>: uploadResponse.secure_url,\n\n\u00a0 \u00a0 <span class=\"hljs-attr\">videoId<\/span>: uploadResponse.public_id,\n\n\u00a0 };\n\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In the code above:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You retrieve the video file from the form (<code>formData<\/code>), convert it to a buffer for streaming, and sanitize the file name to create a safe public ID.<\/li>\n\n\n\n<li>The video is uploaded to Cloudinary using <code>cloudinary.uploader.upload_stream<\/code>.<\/li>\n\n\n\n<li>Once uploaded, the secure URL (<code>secure_url<\/code>) and public ID (<code>public_id<\/code>) of the video are returned, which will be used later to display or process the video.<\/li>\n<\/ul>\n\n\n\n<p>Now that the server action is in place, let\u2019s update the form handler to trigger the upload function when the form is submitted.<\/p>\n\n\n\n<p>Inside the <code>handleSubmit<\/code> function in <code>page.tsx<\/code>, import the upload function from the <code>upload.ts<\/code> file, and call it like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ app\/page.tsx<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> { upload } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/upload'<\/span>;\n\n<span class=\"hljs-keyword\">try<\/span> {\n\n\u00a0 <span class=\"hljs-keyword\">const<\/span> result = <span class=\"hljs-keyword\">await<\/span> upload(formData); <span class=\"hljs-comment\">\/\/ Trigger video upload to Cloudinary<\/span>\n\n\u00a0 <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">'Video URL:'<\/span>, result.originalUrl); <span class=\"hljs-comment\">\/\/ Log or display the uploaded video URL<\/span>\n\n} <span class=\"hljs-keyword\">catch<\/span> (error) {\n\n\u00a0 <span class=\"hljs-built_in\">console<\/span>.error(<span class=\"hljs-string\">'Upload failed'<\/span>, error);\n\n} <span class=\"hljs-keyword\">finally<\/span> {\n\n\u00a0 setLoading(<span class=\"hljs-literal\">false<\/span>);\n\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>When users submit the form, their video is uploaded to Cloudinary, and the URL is available to view in your Cloudinary media library.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How to Generate and Translate Subtitles With Azure Video Indexer<\/h2>\n\n\n\n<p>With your video uploaded to Cloudinary, you can leverage Microsoft Azure Video Indexer to automatically generate subtitles and translate them into different languages.&nbsp;<\/p>\n\n\n\n<p>The integration between Cloudinary and Azure allows for seamless and efficient transcription and translation. Here is how to use the Microsoft Azure Video Indexer:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 1: Enable the Azure Video Indexer Add-On<\/strong><\/h3>\n\n\n\n<p>To start, you must enable the Azure Video Indexer add-on in your Cloudinary account. Head over to the <a href=\"https:\/\/cloudinary.com\/documentation\/cloudinary_add_ons\" target=\"_blank\" rel=\"noreferrer noopener\">Add-ons<\/a> section from the <a href=\"https:\/\/cloudinary.com\/users\/login\" target=\"_blank\" rel=\"noreferrer noopener\">Cloudinary dashboard<\/a>, search for the <strong>Microsoft Azure Video Indexer<\/strong>, and click it.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/paper-attachments.dropboxusercontent.com\/s_89B489B4C7E7F120EAEA66A9697DAAD9257E797A007FED97437B41636C79CA67_1728857606494_image.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">Cloudinary dashboard to access Microsoft Azure Video Indexer<\/figcaption><\/figure>\n\n\n\n<p>Once there, you can select a subscription plan. For this demo, the free plan (which gives you 30 units per month) will be enough. If you need more, you can choose a paid plan.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/paper-attachments.dropboxusercontent.com\/s_89B489B4C7E7F120EAEA66A9697DAAD9257E797A007FED97437B41636C79CA67_1728857445990_image.png\" alt=\"\"\/><figcaption class=\"wp-element-caption\">Subscription plan selected<\/figcaption><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 2: Request Subtitles Automatically<\/strong><\/h3>\n\n\n\n<p>Once the Azure Video Indexer is set up, you can request automatic subtitles for your video. Azure Video Indexer transcribes the audio in your video into text.<\/p>\n\n\n\n<p>To do this, include the raw_convert parameter in your Cloudinary upload call in the <code>upload.ts<\/code> server action like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ app\/upload.ts<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> uploadResponse = <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Promise<\/span>&lt;{ <span class=\"hljs-attr\">secure_url<\/span>: string; public_id: string }&gt;(\n\n\u00a0 <span class=\"hljs-function\">(<span class=\"hljs-params\">resolve, reject<\/span>) =&gt;<\/span> {\n\n\u00a0 \u00a0 cloudinary.uploader.upload_stream(\n\n\u00a0 \u00a0 \u00a0 {\n\n\u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">'video'<\/span>,\n\n\u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">public_id<\/span>: safePublicId,\n\n\u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">raw_convert<\/span>: <span class=\"hljs-string\">'azure_video_indexer'<\/span>, <span class=\"hljs-comment\">\/\/ Requests the default US English transcript<\/span>\n\n\u00a0 \u00a0 \u00a0 },\n\n\u00a0 \u00a0 \u00a0 (error, result) =&gt; {\n\n\u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-keyword\">if<\/span> (error) {\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 reject(<span class=\"hljs-string\">`Upload failed: <span class=\"hljs-subst\">${error.message}<\/span>`<\/span>);\n\n\u00a0 \u00a0 \u00a0 \u00a0 } <span class=\"hljs-keyword\">else<\/span> {\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 resolve(result);\n\n\u00a0 \u00a0 \u00a0 \u00a0 }\n\n\u00a0 \u00a0 \u00a0 }\n\n\u00a0 \u00a0 ).end(buffer);\n\n\u00a0 }\n\n);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This <code>azure_video_indexer<\/code> parameter used in the code above triggers a call to the Azure Video Indexer API, which transcribes the video asynchronously. When the process is done, a new transcript file (e.g., <code>en-us.azure.transcript<\/code>) is created in your Cloudinary product environment.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 3: Generate Subtitles in Standard Formats (VTT or SRT)<\/strong><\/h3>\n\n\n\n<p>If you want to use the transcript as subtitles in a video player, you can request specific subtitle formats like WebVTT (<code>.vtt)<\/code> or SRT (<code>.srt<\/code>).\u00a0<\/p>\n\n\n\n<p>To do this, append the file type to the <code>raw_convert<\/code> value with a colon, like so:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">code<\/span>&gt;<\/span>raw_convert: 'azure_video_indexer:vtt'<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">code<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This will generate subtitles in <code>.vtt<\/code> format, which can be added as a separate track in HTML5 video players.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 4: Translating Subtitles Automatically<\/strong><\/h3>\n\n\n\n<p>By default, Azure Video Indexer assumes your video is in U.S. English. If your video is in another language, specify the source language using the raw_convert parameter.\u00a0<\/p>\n\n\n\n<p>For example, to generate a transcript in French, you would use:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">cloudinary.v2.uploader.upload(\n\n\u00a0 <span class=\"hljs-string\">\"my-video.mp4\"<\/span>,\u00a0\n\n\u00a0 { <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">'video'<\/span>, <span class=\"hljs-attr\">raw_convert<\/span>: <span class=\"hljs-string\">'azure_video_indexer:fr-FR'<\/span> }\n\n).then(<span class=\"hljs-function\"><span class=\"hljs-params\">result<\/span> =&gt;<\/span> <span class=\"hljs-built_in\">console<\/span>.log(result));<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You can also translate the subtitles into multiple languages by specifying additional target languages after the source language, separated by colons. For example:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">code<\/span>&gt;<\/span>raw_convert: 'azure_video_indexer:fr-FR:pl-PL:he-IL:et-EE'<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">code<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This will first generate a French transcript (as the source language) and then create Polish, Hebrew, and Estonian translations. Keep in mind that you can request up to five languages (including the source language) in a single request.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 5: Combine Translations with Subtitle Formats<\/strong><\/h3>\n\n\n\n<p>If you want to generate both subtitle formats (like .vtt) and translations, specify the subtitle formats before the languages:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">code<\/span>&gt;<\/span>raw_convert: 'azure_video_indexer:srt:vtt:en-US:fr-FR'<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">code<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This will generate <code>.vtt<\/code> and <code>.srt<\/code> subtitles in both U.S. English and French. The resulting files will be stored in Cloudinary with filenames like <code>video-id.en-US.azure.transcript.vtt<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Extracting and Translating Subtitles for Our Demo<\/strong><\/h2>\n\n\n\n<p>For this demo, let\u2019s extract the English subtitles from the video and also generate Spanish translations in WebVTT (<code>.vtt<\/code>) format. This will allow you to display both the original and translated subtitles in your video player in the next section.<\/p>\n\n\n\n<p>To achieve this, update your server action to include both the English (en-US) and Spanish (es-ES) subtitles when uploading the video.&nbsp;<\/p>\n\n\n\n<p>Here\u2019s the code to update the upload function:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ app\/upload.ts<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> uploadResponse = <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Promise<\/span>&lt;{\n\n\u00a0 <span class=\"hljs-attr\">secure_url<\/span>: string;\n\n\u00a0 public_id: string;\n\n}&gt;<span class=\"hljs-function\">(<span class=\"hljs-params\">(resolve, reject<\/span>) =&gt;<\/span> {\n\n\u00a0 cloudinary.uploader.upload_stream(\n\n\u00a0 \u00a0 {\n\n\u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">resource_type<\/span>: <span class=\"hljs-string\">'video'<\/span>,\n\n\u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">public_id<\/span>: safePublicId,\n\n\u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">raw_convert<\/span>: <span class=\"hljs-string\">'azure_video_indexer:vtt:en-US:es-ES'<\/span>, <span class=\"hljs-comment\">\/\/ Request English and Spanish subtitles in VTT format<\/span>\n\n\u00a0 \u00a0 },\n\n\u00a0 \u00a0 (error, result) =&gt; {\n\n\u00a0 \u00a0 \u00a0 <span class=\"hljs-keyword\">if<\/span> (error) {\n\n\u00a0 \u00a0 \u00a0 \u00a0 reject(<span class=\"hljs-string\">`Upload failed: <span class=\"hljs-subst\">${error.message}<\/span>`<\/span>);\n\n\u00a0 \u00a0 \u00a0 } <span class=\"hljs-keyword\">else<\/span> {\n\n\u00a0 \u00a0 \u00a0 \u00a0 resolve(result);\n\n\u00a0 \u00a0 \u00a0 }\n\n\u00a0 \u00a0 }\n\n\u00a0 ).end(buffer);\n\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>With this update, the <code>raw_convert<\/code> parameter requests Azure Video Indexer to generate subtitles in both English and Spanish, returning them in WebVTT format (<code>.vtt<\/code>). These subtitle files will be stored in Cloudinary alongside the video and can be accessed using the video\u2019s public ID.<\/p>\n\n\n\n<p>In the next section, your video player will display both the original English subtitles and the translated Spanish subtitles.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Displaying the Video and Subtitles<\/strong><\/h2>\n\n\n\n<p>For this demo, let\u2019s display two videos side by side. One video will show the original video, while the other will display the video with the generated English and Spanish subtitles.<\/p>\n\n\n\n<p>To achieve this, we retrieve the video URL and video ID upon uploading a video to Cloudinary. These values are stored in individual state variables, along with the Cloudinary cloud name from our <code>.env.local file<\/code>. The video ID and cloud name allow us to render subtitle tracks for each video.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ app\/page.tsx<\/span>\n\n<span class=\"hljs-string\">'use client'<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Home<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n\n\u00a0 \u00a0 <span class=\"hljs-keyword\">const<\/span>&#91;videoUrl, setVideoUrl]= useState&lt;string&gt;(<span class=\"hljs-string\">''<\/span>); <span class=\"hljs-comment\">\/\/ Store video URL<\/span>\n\n\u00a0 \u00a0 <span class=\"hljs-keyword\">const<\/span>&#91;videoId, setVideoId]= useState&lt;string&gt;(<span class=\"hljs-string\">''<\/span>);\n\n\u00a0 \u00a0 <span class=\"hljs-keyword\">const<\/span>&#91;cloudName]= useState&lt;string&gt;(\n\n<span class=\"hljs-string\">`<span class=\"hljs-subst\">${process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME}<\/span>`<\/span>\n\n);\n\n\u00a0 \u00a0 <span class=\"hljs-comment\">\/\/ Handle video upload to Cloudinary and update state with video URL and ID<\/span>\n\n\u00a0 \u00a0 <span class=\"hljs-keyword\">return<\/span> (\n\n\u00a0 \u00a0 \u00a0 \u00a0 <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"min-h-screen flex-col items-center justify-between p-10 mt-14\"<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-3xl text-center pb-5 leading-snug\"<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Translate Video Subtitle With <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">br<\/span> \/&gt;<\/span> Cloudinary and Azure Video Indexer\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex justify-center my-10 items-center \"<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 {\/* Video upload form *\/}\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 {videoUrl &amp;&amp; videoId &amp;&amp; (\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex justify-center space-x-4 mt-10\"<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-lg font-bold text-center mb-4\"<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Uploaded Video\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">video<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">crossOrigin<\/span>=<span class=\"hljs-string\">\"anonymous\"<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">controls<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full max-w-md border-4 rounded\"<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 &gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">source<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"mp4\"<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{videoUrl}<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"video\/mp4\"<\/span> \/&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">video<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-lg font-bold text-center mb-4\"<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Transformed Video\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">video<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">crossOrigin<\/span>=<span class=\"hljs-string\">\"anonymous\"<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">controls<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full max-w-md border-4 rounded\"<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 &gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">source<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"mp4\"<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{videoUrl}<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"video\/mp4\"<\/span> \/&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">track<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">label<\/span>=<span class=\"hljs-string\">\"English\"<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">kind<\/span>=<span class=\"hljs-string\">\"subtitles\"<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">srcLang<\/span>=<span class=\"hljs-string\">\"en\"<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{<\/span>`<span class=\"hljs-attr\">https:<\/span>\/\/<span class=\"hljs-attr\">res.cloudinary.com<\/span>\/${<span class=\"hljs-attr\">cloudName<\/span>}\/<span class=\"hljs-attr\">raw<\/span>\/<span class=\"hljs-attr\">upload<\/span>\/${<span class=\"hljs-attr\">videoId<\/span>}<span class=\"hljs-attr\">.en-US.azure.vtt<\/span>`}\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">default<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">track<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">label<\/span>=<span class=\"hljs-string\">\"Spanish\"<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">kind<\/span>=<span class=\"hljs-string\">\"subtitles\"<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">srcLang<\/span>=<span class=\"hljs-string\">\"es\"<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{<\/span>`<span class=\"hljs-attr\">https:<\/span>\/\/<span class=\"hljs-attr\">res.cloudinary.com<\/span>\/${<span class=\"hljs-attr\">cloudName<\/span>}\/<span class=\"hljs-attr\">raw<\/span>\/<span class=\"hljs-attr\">upload<\/span>\/${<span class=\"hljs-attr\">videoId<\/span>}<span class=\"hljs-attr\">.es-ES.azure.vtt<\/span>`}\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-attr\">default<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">video<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 )}\n\n\u00a0 \u00a0 \u00a0 \u00a0 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n\n\u00a0 \u00a0 );\n\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>In the code above, we place two videos side-by-side in the layout. The first video displays the original upload, while the second includes added subtitle tracks.&nbsp;<\/p>\n\n\n\n<p>The &lt;track&gt; elements specify English and Spanish subtitle files, which are pulled from Cloudinary using URLs that incorporate the video ID and language codes (en-US and es-ES). This setup allows viewers to switch between subtitle languages directly within the video player.<\/p>\n\n\n\n<p>The full code for this demo is available in this <a href=\"https:\/\/github.com\/olawanlejoel\/subtitle-translation-demo\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub repository<\/a>, and you can also view the demo video <a href=\"https:\/\/www.loom.com\/share\/09218943a72e4c07b441b46b66765fea?sid=5bdd7ef6-f285-444e-8beb-5ddc6a0a80d5\">here<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>In this blog post, you\u2019ve learned how to upload videos to Cloudinary, automatically generate subtitles, and translate them using Microsoft Azure Video Indexer \u2014 all within your Next.js app. By following these steps, you can now make your video content accessible to a wider audience.<\/p>\n\n\n\n<p>If you enjoyed this post and want to discuss it more, join the <a target=\"_blank\" href=\"https:\/\/community.cloudinary.com\/\" rel=\"noreferrer noopener\">Cloudinary Community forum<\/a> and its associated <a target=\"_blank\" href=\"https:\/\/discord.com\/invite\/cloudinary\" rel=\"noreferrer noopener\">Discord<\/a>. And contact us today to learn more about Cloudinary\u2019s powerful <a target=\"_blank\" href=\"https:\/\/cloudinary.com\/video_api\" rel=\"noreferrer noopener\">video API<\/a> features.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Resources<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/cloudinary.com\/documentation\/video_manipulation_and_delivery\" target=\"_blank\" rel=\"noreferrer noopener\">Cloudinary Video Documentation<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/cloudinary.com\/documentation\/microsoft_azure_video_indexer_addon\" target=\"_blank\" rel=\"noreferrer noopener\">Microsoft Azure Video Indexer<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/cloudinary.com\/documentation\/video_transcription\" target=\"_blank\" rel=\"noreferrer noopener\">Video transcription<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/nextjs.org\/docs\" target=\"_blank\" rel=\"noreferrer noopener\">Next.js Documentation<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Video captions and subtitles have evolved from an accessibility feature to a universal tool for user engagement. A whopping 80% of viewers are more likely to watch a video from beginning to end if captions are available. According to that same study, 69% of viewers keep their sound off in public spaces, while 50% prefer [&hellip;]<\/p>\n","protected":false},"author":87,"featured_media":36368,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[212,303],"class_list":["post-36366","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-next-js","tag-video"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Video Subtitle Translation in Cloudinary With Azure<\/title>\n<meta name=\"description\" content=\"Video captions and subtitles have evolved from an accessibility feature to a universal tool for user engagement. A whopping 80% of viewers are more likely\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Video Subtitle Translation in Cloudinary With Azure\" \/>\n<meta property=\"og:description\" content=\"Video captions and subtitles have evolved from an accessibility feature to a universal tool for user engagement. A whopping 80% of viewers are more likely\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-11-27T15:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-11-27T23:34:51+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1731104286\/translating_subtitles_cloudinary_azure-blog\/translating_subtitles_cloudinary_azure-blog-jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"melindapham\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"Video Subtitle Translation in Cloudinary With Azure\",\"datePublished\":\"2024-11-27T15:00:00+00:00\",\"dateModified\":\"2024-11-27T23:34:51+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure\"},\"wordCount\":1363,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731104286\/translating_subtitles_cloudinary_azure-blog\/translating_subtitles_cloudinary_azure-blog.jpg?_i=AA\",\"keywords\":[\"Next.js\",\"Video\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2024\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure\",\"url\":\"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure\",\"name\":\"Video Subtitle Translation in Cloudinary With Azure\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731104286\/translating_subtitles_cloudinary_azure-blog\/translating_subtitles_cloudinary_azure-blog.jpg?_i=AA\",\"datePublished\":\"2024-11-27T15:00:00+00:00\",\"dateModified\":\"2024-11-27T23:34:51+00:00\",\"description\":\"Video captions and subtitles have evolved from an accessibility feature to a universal tool for user engagement. A whopping 80% of viewers are more likely\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731104286\/translating_subtitles_cloudinary_azure-blog\/translating_subtitles_cloudinary_azure-blog.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731104286\/translating_subtitles_cloudinary_azure-blog\/translating_subtitles_cloudinary_azure-blog.jpg?_i=AA\",\"width\":2000,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Video Subtitle Translation in Cloudinary With Azure\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\",\"name\":\"melindapham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"caption\":\"melindapham\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Video Subtitle Translation in Cloudinary With Azure","description":"Video captions and subtitles have evolved from an accessibility feature to a universal tool for user engagement. A whopping 80% of viewers are more likely","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure","og_locale":"en_US","og_type":"article","og_title":"Video Subtitle Translation in Cloudinary With Azure","og_description":"Video captions and subtitles have evolved from an accessibility feature to a universal tool for user engagement. A whopping 80% of viewers are more likely","og_url":"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure","og_site_name":"Cloudinary Blog","article_published_time":"2024-11-27T15:00:00+00:00","article_modified_time":"2024-11-27T23:34:51+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1731104286\/translating_subtitles_cloudinary_azure-blog\/translating_subtitles_cloudinary_azure-blog-jpg?_i=AA","type":"image\/jpeg"}],"author":"melindapham","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"Video Subtitle Translation in Cloudinary With Azure","datePublished":"2024-11-27T15:00:00+00:00","dateModified":"2024-11-27T23:34:51+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure"},"wordCount":1363,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731104286\/translating_subtitles_cloudinary_azure-blog\/translating_subtitles_cloudinary_azure-blog.jpg?_i=AA","keywords":["Next.js","Video"],"inLanguage":"en-US","copyrightYear":"2024","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure","url":"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure","name":"Video Subtitle Translation in Cloudinary With Azure","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731104286\/translating_subtitles_cloudinary_azure-blog\/translating_subtitles_cloudinary_azure-blog.jpg?_i=AA","datePublished":"2024-11-27T15:00:00+00:00","dateModified":"2024-11-27T23:34:51+00:00","description":"Video captions and subtitles have evolved from an accessibility feature to a universal tool for user engagement. A whopping 80% of viewers are more likely","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731104286\/translating_subtitles_cloudinary_azure-blog\/translating_subtitles_cloudinary_azure-blog.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731104286\/translating_subtitles_cloudinary_azure-blog\/translating_subtitles_cloudinary_azure-blog.jpg?_i=AA","width":2000,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/video-subtitle-translation-azure#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Video Subtitle Translation in Cloudinary With Azure"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9","name":"melindapham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","caption":"melindapham"}}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1731104286\/translating_subtitles_cloudinary_azure-blog\/translating_subtitles_cloudinary_azure-blog.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/36366","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=36366"}],"version-history":[{"count":1,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/36366\/revisions"}],"predecessor-version":[{"id":36367,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/36366\/revisions\/36367"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/36368"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=36366"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=36366"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=36366"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}