TTS & Translate App | Serverless Functions, Google Translate & Web Speech API

Traversy Media| 00:45:21|Mar 26, 2026
Chapters15
This chapter introduces a serverless-based TTS and translation app using Google Translate API, the Vercel CLI for serverless functions, and a client-side UI that demonstrates text-to-speech in multiple languages without exposing API keys.

A practical, serverless-first TTS and translation app using Google Translate API, Web Speech API, and Vercel for local and production deployment.

Summary

Traversy Media’s walkthrough builds a TTS and translation app that emphasizes serverless architecture. Brad demonstrates how to avoid exposing API keys by routing requests through a Vercel serverless function that talks to Google Translate. The client uses the Web Speech API for text-to-speech and a vanilla JS UI (no framework) to select voices, languages, and input text. The project structure includes a public frontend, an API folder for serverless logic, and environment handling with EnV for local development vs. production. Brad guides you through running the app locally with the Vercel CLI, authenticating, and deploying to Vercel. You’ll see how to fetch available voices, populate language options, and wire the translate endpoint to translate text before speaking it aloud. Practical tips include keeping API keys on the server, adding environment variables in Vercel, and testing the API with Postman during development. By the end, you’ll have a deployable, multilingual TTS app that demonstrates serverless functions as the core value proposition.

Key Takeaways

  • Serverless functions with Vercel protect API keys by handling Google Translate requests on the backend rather than in client-side code.
  • The Google Translate API key is stored in an EnV file for local development and is moved to Vercel’s environment variables for production deployments.
  • Web Speech API is used for TTS voice synthesis, with dynamic voice selection populated from available voices provided by the browser.
  • A dedicated serverless endpoint (/api/translate) handles translation requests, calling Google Translate and returning translated text to the client.
  • The app’s architecture separates frontend (public/) from backend logic (api/ translate.js), enabling a clean, maintainable flow for translating text before speech.
  • The tutorial covers end-to-end setup: project structure, local testing with Vercel CLI, and deployment to Vercel, including environment variable management.
  • User testing is supported with Postman to verify the serverless function responds correctly to POST requests with text and target language.

Who Is This For?

Web developers who want to build a serverless, production-ready TTS + translation tool without exposing API keys in the browser. Ideal for those learning Vercel, serverless functions, and integrating Google Translate with Web Speech API.

Notable Quotes

"'we're going to create a little application that will do TTS and translation to a different language'"
Brad introduces the project goals and the core features: text-to-speech and translation.
""the main focus of this is going to be serverless functions""
Emphasizes the serverless approach to secure API calls to Google Translate.
""you don't want that key to be shown to you know users""
Brad explains why API keys must stay on the server side.
""we'll have it live like it is now""
Shows the goal of deploying to Vercel so others can access the live app.
""if you're talking to someone that is speaking a different language, you can use this""
Wraps up with a real-world use case for the app and its multilingual capability.

Questions This Video Answers

  • how do serverless functions protect API keys when using Google Translate?
  • how to set up Vercel CLI for local development and production deployment?
  • how does the Web Speech API handle multiple voices and languages?
  • how can I test a serverless endpoint locally with Postman before deploying?
  • what are best practices for structuring a frontend and serverless backend in a single project?
Serverless FunctionsVercelVercel CLIGoogle Translate APIWeb Speech APIText-to-Speech (TTS)Front-end Vanilla JSEnvironment VariablesAPI Key SecurityPostman Testing
Full Transcript
hey guys so I have a pretty cool project for you today that um that I would suggest following along with and coding with me but if you just want to watch it that's fine too so we're going to create a little application that will do TTS it'll do text to speech and translation to a different language now the main focus of this is going to be serverless functions because we're going to have we're using the Google translate API and you need to use an API key and that's not something that you can put in your client side JavaScript so what we're going to do is use the versel CLI that will allow us to create serverless functions right on our you know on our machine and we'll be able to hit a specific endpoint and that will call the serverless function all right then once we get through all that we'll push to verell and we'll have it live like it is now as you can see here and just to give you an example of what it does if I say like hello world I can choose a language so I'll just keep it at English for now and I can choose all these different voices and the the TTS and the voices are using the web speech API so there's actually a bunch of things you're going to learn in this one little project hello world so you can see that that works if I wanted to say it in Spanish right if I want to change the voice okay so I mean it's a it's a useful project you could use this if you're trying to converse with someone that you know speaks a different language um but the actual project itself isn't really the full you know what I want you to get from it it's the serverless functions because we don't have to create a whole Express back end or or whatever we just simply use the versel CLI and we just create this one file and this is where we can use our API key and we can you know make the request to the the Google translate API and then in the client side JavaScript which is in public this is where um where we use the the web speech API okay so yeah no framework just you know vanilla JavaScript just dealing with the Dom and and I think you're going to get a lot from it so let's get [Music] started all right guys so we're going to get started and you're going to learn quite a bit in this little project you're going to learn about the web speech API you're going to learn about Google Translate you're going to learn about serverless functions which I think is is probably the most valuable thing that you're going to learn in this project um we're going to learn how to do it locally using the versel CLI and we're also going to push to to versel um so I just want to show you the structure of the the folders and files which is pretty simple so we'll have the project folder which you can see I have open in vs code it's TTS translate app there's nothing in it right now but we're going to have a public folder with all of our our public files like the index HTML the script.js which is the client side JavaScript so the event listeners and so on style CSS for any additional styles that you want uh you know aside from tailwind and then an assets folder if you want any images or icons now in addition to public we have an API folder and this is where your serverless functions are going to go so any server side logic is going to go here and we have a translate. JS file that's where we're going to you know hit the the Google translate API and we need to include our API key so that's why it's important that this is in a serverless function and not in the client side JavaScript because you don't want that key to be shown to you know users all right so we'll have that there and then in the root you'll just have a read me which is optional a EnV for local environment variables and then a get ignore and vers sell ignore for anything we don't want to to push all right so that's our the the gist of our structure so let's start off by just creating our public folder okay so public and in that we're going to have an index.html it's our main interface we're also going to have a oops we're going to have a style styles.css file and we're also going to script.js which will be our frontend JavaScript and then in addition to that that will just have an assets folder if you want any images or anything all right so uh we're just going to stick to the public stuff for now let's start off by creating the interface so adding the HTML so I'm going to add a boiler plate here for the title we'll say TTS and translation app and then I'm using um Tailwind so I'm just going to use the play CDN so that consists of just adding the script tag and that's it we can use TA in classes and then let's also add a link to our stylesheet which I'm not going to put anything in but again if you want to add to it it's just good to have it there okay now for the UI I'm I'm going to type some stuff and paste some stuff so on the body let's add a few classes so I do want to have a gray background so we'll do BG gray 100 just very light and then I'm going to make it a flex box where we align everything to the center so we want to do justify Center and item Center and then let's do full height so H screen and then in the body we'll add uh a container actually before we do that let's just put something there I'll just put app and then for now I'm going to open it with the live server extension for vs code so I'll click go live you can also just you know double click on index HTML and open it on your file system but ultimately we're going to be using the versel CLI which will run our project on Local Host 3000 and when we use the versel CLI we can have serverless functions on our local machine and run them all right but for now I'm just using uh live live server so let's get rid of app and let's create a little container here so we'll do BG white let's do shadow um Shadow medium we'll do rounded Das large um padding we'll do six and let's put a Max width of medium and width Dash full so it'll be really narrow layout and then in that in that card or container whatever you want to call it we'll have an H1 let's do a size of text- 2XL let's do font D semibold and we'll do text- gray 800 for the color and we want to center it oops text Center and then we also want to add a margin bottom of four and then in the H1 we'll say TTS and translation save that and that's what we got so far so I'm going to just paste in the the the different inputs so first we have the text area which I'm going to put right under the H1 okay so we have just a text area with some classes border and all that stuff resize To None has a placeholder and then the next thing is going to be the voice selection because with the web speech API which is what we're using for the TTS you can select different voices and different accents or locals so under the text area I'm going to paste this in it's a div with a label that says select voice and then a select tag with an ID of voice select because we're going to bring it into the JavaScript and these options here aren't going to show ultimately um ultimately we're going to get the voice from the web speech API and fill those in here all right and then the last thing we need for now is just the button so I'm going to go under that div that wraps the select and paste in a button okay and this button has an ID of play button and then a bunch of classes that makes it look like that okay and then the last thing we want to do for now is just add a script and the source is going to be the front-end JavaScript script uh script Js and yeah that should do it for now so now we're going to jump into the script.js and this is where we're going to be using the web speech API all right so we're going to use over here you'll see under interfaces um we're going to use the speech synthesis utterance class or interface and this represents a speech request and that's what we want to do we want to take the text that's typed into the text input and we want to make a speech request with that all right and then we we can speak it with the speak method so if I do a search for speak and let's see so right here speech synthesis speak so we're basically going to be doing this we create a new instance of an utterance and then we pass that utterance into the speak method so let's jump back over to our script and we're going to first bring in the things we need so let's say const and we'll bring in the voice select which is that select box box so document oops forgot the equal sign so document Dot and I'm going to use Query selector and that has an ID of voice select okay and then we'll just copy that down a few times next thing we're going to need is the play button so that has an ID of play button and we'll call the variable play button as well and then we have the text we'll call this text input and we're going to select that just by the text tag of text area all right so those are the three things we need at the moment now I want to um play the the TTS so let's say play TTS and we'll do that by taking the play button and let's add an event listener onto that we want to listen for a click and when that happens we'll fire off a function and this is where we want to do that use that web speech API so we'll create an utterance and set that to a new instance of speech right here speech synthesis utterance and that takes in what you want it to utter or what you want it to speak which is going to be our text input but of course we want the value from that text input all right then we want to speak it so we can do that by taking speech uh Speech synthesis and then calling the speak method and passing in the utterance all right so just doing that we should be able to type in something like Hello World hello world and it works okay so very very simple next thing we want to do is be able to have different voices so before we can implement the The Voice you know changing of the voice we need to list them in this select box so basically we need to get them using uh a method called get voices so just to show you that real quick uh if we go to Let's see we should have let me just search for it get uh get voices yeah so right here so voices get voices and then we're basically going to do this Loop through the voices and we're going to create a new Option element for each one okay so let's do that so I'm going to go right above the event listener and let's say load available voices I'm going to initialize an array called voices and then I'm going to have a function called function is going to be called load voices all right and then in that function first thing we'll do is get the voices so let's take our voices array and set that to speech synthesis. get voices okay so we'll have an array of voic now we want to Output those as options so and that's going to go in the voice select box so take our voice select and let's say enter HTML set that to voices and then we're going to add onto that map so this will basically uh you know turn it into an array of of whatever we want in this case it's going to be option values or option tags so let's pass in our function here and we're going to say for each voice and we also want to get the index and let's use back ticks here we're going to create an option oops that should be lowercase so option and value which we're going to set that to the um index okay so the value is the index and let's close up option and then for what we want to display in the option is going to be the voice name so here let's say voice. name and then we'll put a space and then some parentheses and I want the Lang or the it's the the language like en for English es s for Spanish and it won't change the language this this doesn't do that that's where the translate comes in but it will change the accent so here let's say voice. Lang okay now this will give us an array of these and that's not what we want we want it to be outputed as a string so we just have to add on to that do join and just pass in just empty quotes we haven't called this function yet which we do want to do but we also want to call it when the onvo is changed event is fired off so let's say trigger we'll say trigger loading voices when they become available so we can just say speech synthesis Dot and then on voices change and then set it to our load voices load voices function and then also call it initially right here with voices okay now if we take a look you'll see that it shows all the voices okay and it might be different depending on the platform that you're you're using um and if I type in hello hello it works with Samantha if I change it to Aaron hello it you notice it didn't change it's still using that same voice um that's because we need to basically change that um down here when we call that utterance so right under the utterance variable let's say con selected voice okay so we'll have a variable selected voice set that to the voices array and then whatever the value is so voice select which is that that select box we want whatever that value is then we're setting the SE that selected voice to then we're just going to check for that selected voice and then we'll change the utterance because you can set the utterance dovo like this and you can set it to the selected voice so now let's try it again hello Samantha Aaron hello so that's different Albert hello I don't know what's up with Albert he doesn't sound too healthy but it's changed Alice and you can see that this one has a different accent because it has a different uh language this that's the voice Lang all right so that takes care of the most of the client side stuff so the language to change the language is going to be more tricky because we need to uh we need to use the the translate API which uses an API key and we can't just put the API key in this file because everyone would be able to see it and you know use it so that's where the uh the serverless function is going to come in now before we get to that though let's just add the language dropdown so I'm going to go back into the HTML and I'm going to put this language selection drop down right above the voices so right here okay so it's just a again a div with mt4 got the label select and the ID of language select okay so you can see it here and there's nothing showing but what we can do is create the languages we want in our JavaScript and then fill the form fill that with that with the languages so let's go back to our script JS and up at the top here below the you know where we selected everything let's say we want an array of um we'll say array array of supported languages languages with their ISO codes so like en for English es for Spanish Etc so const languages that's going to be an array of objects and the object will have the code which will be in this case en for English and then it'll have the name which will be the longer version of English all right and I'm going to just paste in the rest of these languages and you can use different ones but these are the ones I'm using English Spanish French German Italian Japanese and Chinese simplified all right so now we want to populate this select box with those languages so let's say populate um language select box so we can do that by taking the languages array we want to Loop through with four each and let's pass in our function okay now for the I don't want to I want to get the code and the name so I'm just going to destructure here and get code and name so we have access to those for each one and then we like I said we need to create an option for each language so let's say document do um create ele element oops create not attribute create element and the element we want to create is an option right then we want to fill the option value and the value is going to be the code so n ESF FR and then the text we want to be the long version which is the name so let's say option. text content is going to be equal to the name all right then we we just need to add it to the Dom so we'll say language or yeah language select which is the the select box which I didn't I didn't add yet did I so up here let's just bring in let's say ID language select and that variable language select okay so then we want to take that select box and we just want to append child and we want to append the option so now we can see it shows all the languages that we have in this array so now we we're to the point where we need to create our function our serverless function to reach out to the translate API um but before we do that we need to set up an API key so we're going to have to go to the the Google console which I believe is like console yeah console. cloud. gooogle and from here you're going to want to if you don't have a project already create one this is my tutorials project and then go to API and services and then you're going to want to enable API and services and then search for translate and it's going to be this Cloud translation API you'll see a button here that says enable just click that to enable it then you have to create a key by going to API and services credentials go to create credentials API key it'll generate a key for you okay so you just want to grab that and then what we'll do is put that into a new file in the root called EnV okay and that's going to be we're going to call this Google uncore translate API key and then paste that in okay make sure you use your own I'm going to delete this after anyway so we have that now we're going to have uh a new folder in the root as well called API and in that we're going to have a file called translate. JS and this is where our translate uh serverless function is going to go now to be able to use serverless functions locally while we're in development we need to use the versel CLI so what you're going to do is open up a terminal and run npm install dasg cuz we're installing the globally and then versel okay that way you can just use the versel command all right so now next thing we want to do is authenticate with versel so make sure you have an account I'm going to say versel login and I use GitHub so I'm going to continue with GitHub and you can see I get this success message in the browser so now I'm authenticated with forell in my terminal so the next thing we want to do is create a project okay we're going to make this a versel project by saying versel and then Dev now it's going to ask us some questions it's going to say setup and develop whatever you know the location and name of the app I'm going to say yes and then where to save your project so I have two I have the um the free tier which is this and then I have traversy media which is the a paid tier so I'm going to use my free tier which is probably what most of you guys are going to use link to an existing project I'm going to say no because I haven't created one on versel yet my project name I'll just keep that the directory we want that to be the home so just enter and do you want to modify these settings I'm going to say no all right so what it did is now it created this versel uh folder for our cache it also created a dog ignore which has that versel folder in it now in addition to that I'm going to add node modules and I'm going to add EnV because I don't want those to be added um either okay now also in versell if you go to your dashboard I'm going to reload this you'll see that it's been added here TTS translate app now there's no deployments um we'll do that after but it does it does initialize the project inverse L but now what we can do is is create serverless functions so in this translate JS the way that we create a serverless function is export default and async function function called Handler and that's going to take in request and response so just like as if you were you know using Express and you were creating a route takes in the the HTTP request and response object and then for now just to test it out I'm going to say return res. status of 200 and then I'm going to add on to that adjacent object and just say message and set that to hello world okay so now what I should be able to do is on my local machine you'll see it's actually running on Local Host 3000 so instead of using live server right I'm going to shut off live server and then I'm going to go to uh local host or whatever my loop back and 3000 and I'm going to have my project here and what I can do now is go to slash API SL translate and it should run my serverless function and there it is so we just get our message of hello world okay so and in here we can do any server side code and it's protected from from users from the client now I want this to be a post request when we call this to do the translation I want it to be a post request so what we're going to do is right here let's say if the request. method if that is not equal to post then let's actually just move this in here but let's make this a status of 405 and then we're going to set instead of message I'm going to set it to error and I'm going to say method uh method not allowed because it has to be a post request all right then we want to be able to get the um the body right that we want to be able to get the text and the target language from the body and we can do request. body just like you would with you know an Express back end and I'm just going to destructure from that text um the text and Target which is the language okay then we want to just do a little bit of validation and say if not text or if not Target then I'll just copy this response here paste that in except this is going to be a 40 400 error and let's just say for the error missing text or language all right now we want our API key now remember that's in the EnV file but by default this isn't going to we're not going to be able to access it because we need to use the EnV package locally so what I'm going to do is create a new terminal here and we're going to npm install Das uppercase D because I'm installing it as a Dev dependency EnV okay so that will install it that will now have a a node modules folder and we want to bring that in and call the config method that's all you have to do in order to use you know process.env whatever so um I'm going to I only want that to run locally the Dov package because when we're deployed to verell we add our environment variables right we go here we go to settings environment variables and we add them here I want to use the file so I only want to use the ENB package locally so I'm going to do a conditional here and say if process process. env. nodecore EnV so our node environment if that is not equal to production right so if it's not equal to production then I want to load the EnV package and I want to use the um the config method now I can't just simply do import EnV from. EnV because your Imports have to be the very first thing in the file and this isn't it's within here but we can use what's called a dynamic import and that's going to be asynchronous so I could either do a DOT then or I could use an async function which is what I'm going to do and this is an iffy so it's going to have parentheses after it as well all right but what we can do is just say async and then have a function and in that I'm going to say con. EnV set that to a weit and then import so this is a dynamic import so EnV right and then I simply want to call the config method that's on that object so Dov do and then config all right so we just need to add that in order to use the um the variables in this file so next thing let's actually create a variable for the API key cuz we need to send that with um with our request so we can now get the API key with process. EnV Dot and then Google translate um API key and then let's create a variable for the API URL this is the Google translate endpoint that we need to hit so that's going to be https and then translation. googleapis.com slash language SL translate SL verion 2 so V2 and then we want a query string of key and set that to our API key all right so we have the API key we have the URL now let's make the request so let's do a try catch and in the try I'm going to create a response variable and then make the request with await fetch p pass in our API URL and then some options and we want to set the method to post so method post we want to set headers and set the content Dash type to application SL Json and then we want to send the body and the way that this API works first of all we're going to stringify so stringify it takes an adjacent object with a Q which is the query which we have as our text variable so text then it also takes a Target which we also call the variable Target right so we're talking about the stuff we're getting from the body which ultimately comes from the form and it's called Target so we can just simply do that and then also a format which is always going to be text all right so that is the request now let's check to see if it's not okay okay so if not response. okay then let's get the the error text which we can get from await response. text and then what we want to send back is going to be res. status it's going to be whatever the response do status is and then Json and we'll pass in error set that to the error error text all right now if it's okay if everything works out then we want the data which will be the translated text so we can get that with await response. Json right and then we'll want to send back re status of 200 because everything's okay and then Jason pass in the data okay now in the catch I'm just going to do a console. error and I'll just say error in API call okay and then as far as what we want to send back to the client let's say status 500 and we'll send an error okay and that error will'll just say internal server error and that's it now we can test this out so we can't do it with the browser because remember it has to be a post request so what I'm going to do is open up my Postman uh extension but you can use anything you know any hdb client and say new request and I'm going to make a post request to http localhost 3000 API translate I'm going to do it without sending the body first and I get missing text or language so let's go to body for uh form URL encoded and let's set the text to hello world let's set the target to we can do en which is English and there we go we get back a data object with a translations array with one object in it with a translated text of hello world if I change it to es which is Spanish then I get back the same thing but it's I get the Spanish language okay so we know that our serverless function is working it's doing what it's supposed to so now we need to integrate that into our actual application which is let's go back here all right so we want to integrate that into our client side JavaScript so let's go into script JS and let's see how do we want to let's start off just by creating our translate text function and that's what's going to make the request to our serverless function you're not going to make a request to the translate API from your client you make a request to your own serverless function which then makes a request to the client okay and that's where you want your key you know you don't want to put this into your client side so let's create this function right above the um the play play event listener so let's say translate uh translate text with serverless function so function actually let's make this a sync and we'll call this translate text and it's going to take in the text and it's going to take in the Target Lang target language all right and then we're going to use a tri catch and we're going to do the same thing just like we made a a request to the Google translate API now we're making a request to our serverless functions API so const response we want to await Fetch and we want to pass into that slash API SL translate okay and then as far as the options needs to be a post request um header so content type okay then we want the body okay so the body is going to be um json. stringify and then we want to send text so text uh which is going to be this text that's passed in so we just do that and then the target so Target is going to be set to the Target Lang that's passed in here all right then we want to check it so let's say if not if not response. okay then let's just throw we'll say Throw new error and some back ticks we'll say and we can get the response uh response. status and then I want to show the response text which is a synchronous so we just going to do text okay now if it's if everything goes okay let's get the data so we want to await response. Json and then remember how it looks when it's returned it's a it's a data object with a translations array and then an object in that array with a translated text so keep that in mind because now what we need to do is return uh return data so this is the the data variable that I created but in that is that other data object so data. data and then in that we have a translations array which we want the first and only item and then from that we want the translated text value so that's what we're returning okay and then in the catch let's just do a console. error and we'll say um translation error and then I'm just going to do an alert for the user we'll say failed to translate text and then we'll just return text all right so that's the translate now when we play right we don't want to just play the text we also need to translate it so let's move the stuff um like just you know initializing the utterance and stuff we'll put that in uh its own function so let's say uh TTS we'll just say TTS and then function function play text and it's going to take in the text and then also the voice index all right and then let's say const a actually we can just copy yeah we'll copy this except it's not going to be text input value it's going to be the text that's passed into the function right and then let's just say if in the voices array and we want the voice index which is going to be passed in so if that then let's change the utterance voice set that to the voices array and that specific voice Index right and then we'll just speak it so just like we did here here speech synthesis speak and then utterance all right so we can get rid of all this now and then we need to um call play text and we need to call translate text so and this has to be asynchronous so let's add an async here right and then let's get the text to to pass in which we have the text input element but we want to get the value and then I'm also going to trim it as well so that's the text let's get the target Lang which we get from the language select element but we want the value and then let's get the selected voice index from the voices uh what is it voice select. value all right and then I'm just going to do a just a check to make sure that there's something in text so if there's not then we'll just do an alert and say please please enter some text and return okay and if there's text then we're going to do a try catch and in the try we want to First translate the text before we speak it so let's say const translated text not translate because we already have that function this is translated and then we're going to use the translate text and that's going to take in text and Target Lang all right then we want to play the text so for that we call play text pass in the translated text and pass in the selected voice index all right and then in the catch console. error we'll say error uh I guess error during processing all right and then we'll just alert for the user we'll say an error an error occurred all right all right so let's try it out so I'm going to just do hello world let's try English first hello world hello world okay and then I'm going to change it to Spanish there we go it did the translation change the voice I don't know what is wrong with these voices let's choose uh Aaron okay so that's Spanish Let's Do German hello well let's do Italian Chia Mondo all right so yeah you can see that it's working we can change the voices we can change the language so it does both TTS and translation now if you want to push this to versel that's extremely simple but we do need to add our environment variable so let's grab this so we're going to have this as the key all right so what you do is go to settings and then environment variables pass in the key and then pass in the value okay so we can add that uh yeah save so that gets added now to push this we can just simply save or sell and of course you can you know push to GitHub as well you can do it that way but um and I I will push to GitHub so you guys have this but yeah right here you can see deploy to production so if I go to project and we click on that there we go we have say um let's do something different I'll just what should we put here this is a great little project that I enjoyed this is a great little project that I enjoyed and we'll try Spanish with a different Grand all right so there we go so you have a deployed useful full application I mean if you're you know if you're talking to someone that is speaking a different language um you can type what you want to say in here and then run it they can understand it they can do the same thing so it's actually a pretty useful little project so I really hope you guys enjoyed it if you did please leave a like and let me know what you think and I will see you next time

Get daily recaps from
Traversy Media

AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.