YouTube Courses - Learn Smarter

YouTube-Courses.site transforms YouTube videos and playlists into structured courses, making learning more efficient and organized.

Building a Text-to-Speech and Translation Application with Serverless Functions



Introduction

This chapter guides you through the development of a practical web application that combines Text-to-Speech (TTS) and translation functionalities. This project is designed to be educational, focusing on key concepts in modern web development, particularly the use of serverless functions. While the application itself is a useful tool for basic communication across language barriers, the primary objective is to understand and implement serverless functions effectively.

Text-to-Speech (TTS) Text-to-speech is a technology that converts written text into spoken words, allowing computers to “read” text aloud. This technology bridges the gap between written and auditory communication.

We will be utilizing the Google Translate API for translation services and the Web Speech API for text-to-speech. A crucial aspect of this project is handling API keys securely. We will learn why and how to avoid exposing sensitive API keys in client-side code by leveraging serverless functions.

This chapter will cover the following key areas:

  • Setting up the project structure: Organizing files and folders for a clear and maintainable project.
  • Developing the client-side interface: Building the user interface using HTML, CSS, and vanilla JavaScript.
  • Implementing Text-to-Speech functionality: Using the Web Speech API to convert text to speech directly in the browser.
  • Creating serverless functions: Understanding and implementing serverless functions using the Vercel CLI.
  • Integrating the Google Translate API: Utilizing serverless functions to securely access and use the Google Translate API.
  • Local development and deployment: Testing the application locally and deploying it live using Vercel.

Project Setup and Folder Structure

To begin, we need to set up the project environment and structure. This involves creating the necessary folders and files that will house our application’s code.

  1. Create a Project Folder: Start by creating a main project folder. For this example, we’ll name it TTS-translate-app.

    TTS-translate-app/
  2. Establish Core Folders: Inside the project folder, create two primary folders: public and api.

    TTS-translate-app/
    ├── public/
    └── api/
    • public Folder: This folder will contain all the publicly accessible files, meaning the files that are served directly to the user’s browser. This includes:

      • index.html: The main HTML file defining the structure of our web page.
      • styles.css: A stylesheet for any custom CSS styling you want to add.
      • script.js: The client-side JavaScript file containing the logic for user interactions and front-end functionality.
      • assets/ (Optional): A folder to store any assets like images or icons.
    • api Folder: This folder is designated for serverless functions. Any JavaScript files placed here will be treated as serverless function endpoints by Vercel. In our case, we will have:

      • translate.js: This file will contain the serverless function responsible for handling translation requests using the Google Translate API.
  3. Root Level Files: In the root directory of your project (TTS-translate-app/), create the following files:

    TTS-translate-app/
    ├── public/
    ├── api/
    ├── README.md (Optional)
    ├── .env
    ├── .gitignore
    └── vercel.json (or vercel.ignore as mentioned in transcript, should likely be .vercelignore)
    • README.md (Optional): A markdown file for project documentation.

    • .env: This file will store local environment variables, such as API keys, for development purposes. Important: This file should not be committed to version control for security reasons.

    • .gitignore: Specifies intentionally untracked files that Git should ignore. We will add entries to exclude sensitive files and node modules.

      .gitignore A .gitignore file is a text file in the root directory of a Git repository. It lists filename patterns, one per line, that Git should ignore in the repository. This is useful for excluding temporary files, build artifacts, and sensitive information from being tracked.

    • vercel.json (or .vercelignore): (Transcript mentions vercel ignore which is likely a typo and should be .vercelignore or potentially vercel.json depending on intended ignore behavior, .vercelignore is used to specify files and directories that should be excluded when deploying to Vercel. vercel.json is for project settings, not specifically ignoring files. Let’s assume .vercelignore for file exclusion). This file is used to define files and directories that Vercel should ignore during deployment.

      Vercel CLI Vercel CLI (Command Line Interface) is a tool that allows developers to interact with the Vercel platform from their terminal. It is used for deploying applications, managing projects, and running local development servers that simulate the Vercel environment.

    This folder structure provides a clean separation between client-side code, server-side logic (serverless functions), and configuration files.

Building the User Interface (HTML)

Let’s create the user interface using HTML in public/index.html. We will use Tailwind CSS for styling to expedite the process, although you can use any CSS framework or write custom CSS.

  1. Basic HTML Boilerplate: Start with a standard HTML5 boilerplate. Set the title to “TTS and Translation App”.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>TTS and Translation App</title>
        <link rel="stylesheet" href="styles.css">
    </head>
    <body>
    
        <script src="script.js"></script>
    </body>
    </html>
  2. Include Tailwind CSS: To use Tailwind CSS, we’ll include it via its Play CDN (Content Delivery Network). Add the following <script> tag inside the <head> section:

    <script src="https://cdn.tailwindcss.com"></script>

    CDN (Content Delivery Network) A Content Delivery Network (CDN) is a geographically distributed network of servers that cache content and deliver it to users based on their geographic location. Using a CDN, like Tailwind Play CDN, allows you to quickly include libraries and frameworks in your projects without needing to install and manage them locally.

  3. Basic Styling in <body>: Apply some basic Tailwind classes to the <body> for background and layout.

    <body class="bg-gray-100 flex justify-center items-center h-screen">
        <!-- Content will go here -->
    </body>
    • bg-gray-100: Sets a light gray background.

    • flex justify-center items-center: Uses flexbox to center content both horizontally and vertically.

    • h-screen: Sets the height to 100% of the viewport height.

    Flexbox Flexbox, or CSS Flexible Box Layout, is a layout module in CSS3 that provides an efficient way to arrange, align, and distribute space among items in a container, even when their size is unknown or dynamic. It is particularly useful for creating responsive and one-dimensional layouts.

    Justify Center & Item Center In Flexbox, justify-content: center; aligns flex items along the main axis of the container (horizontally in a row layout) to the center. align-items: center; aligns flex items along the cross axis (vertically in a row layout) to the center of the container.

  4. Container Card: Create a container element to hold the application’s content, styled as a white card with shadow and rounded corners.

    <div class="bg-white shadow-md rounded-lg p-6 max-w-md w-full">
        <!-- App Content -->
    </div>
    • bg-white: White background.
    • shadow-md: Medium shadow effect.
    • rounded-lg: Large rounded corners.
    • p-6: Padding of 6 units.
    • max-w-md: Maximum width of medium size (Tailwind’s default medium breakpoint).
    • w-full: Full width within its container.
  5. Heading: Add a heading for the application title.

    <h1 class="text-2xl font-semibold text-gray-800 text-center mb-4">TTS and Translation</h1>
    • text-2xl: Text size of 2 extra-large.
    • font-semibold: Semi-bold font weight.
    • text-gray-800: Dark gray text color.
    • text-center: Centers the text.
    • mb-4: Margin bottom of 4 units.
  6. Text Area: Add a <textarea> for user input.

    <textarea id="textInput" placeholder="Enter text to speak and translate" class="border p-2 rounded w-full resize-none"></textarea>
    • id="textInput": ID for JavaScript access.
    • placeholder: Placeholder text.
    • border p-2 rounded w-full: Basic border, padding, rounded corners, and full width.
    • resize-none: Disables textarea resizing.
  7. Language Selection Dropdown: Create a <select> dropdown to choose the target language for translation.

    <div class="mt-4">
        <label for="languageSelect" class="block text-sm font-medium text-gray-700">Select Language</label>
        <select id="languageSelect" class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
            <!-- Options will be populated by JavaScript -->
        </select>
    </div>
    • id="languageSelect": ID for JavaScript access.
    • Tailwind classes for styling the label and select element.
  8. Voice Selection Dropdown: Add another <select> dropdown to choose the voice for TTS.

    <div class="mt-4">
        <label for="voiceSelect" class="block text-sm font-medium text-gray-700">Select Voice</label>
        <select id="voiceSelect" class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
            <!-- Options will be populated by JavaScript -->
        </select>
    </div>
    • id="voiceSelect": ID for JavaScript access.
    • Tailwind classes for styling the label and select element.
  9. Play Button: Add a <button> to trigger the TTS and translation process.

    <button id="playButton" class="mt-6 bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded w-full">
        Speak & Translate
    </button>
    • id="playButton": ID for JavaScript access.
    • Tailwind classes for styling the button.
  10. Link Stylesheet and Script: Ensure you have linked styles.css and script.js in the <head> and before the closing </body> tag respectively, as shown in the boilerplate in step 1.

This completes the basic HTML structure for our application’s user interface. The dropdown options for language and voice will be dynamically populated using JavaScript in the next section.

Implementing Text-to-Speech (TTS) with Web Speech API

Now, let’s implement the Text-to-Speech functionality using the Web Speech API in public/script.js.

  1. Get DOM Elements: First, select the HTML elements we need to interact with using JavaScript.

    const voiceSelect = document.querySelector('#voiceSelect');
    const playButton = document.querySelector('#playButton');
    const textInput = document.querySelector('#textInput');
    const languageSelect = document.querySelector('#languageSelect');

    DOM (Document Object Model) The Document Object Model (DOM) is a programming interface for web documents. It represents the page so that programs can change the document structure, style, and content. The DOM represents the document as nodes and objects, allowing programming languages like JavaScript to interact with and manipulate the elements of a web page.

    DOM Manipulation DOM manipulation refers to the process of using JavaScript (or other scripting languages) to interact with and modify the structure, style, and content of a web page’s Document Object Model (DOM). This includes adding, removing, changing elements, attributes, and content in response to user actions or other events.

  2. Load Available Voices: Create a function to load and populate the voice selection dropdown with available voices from the Web Speech API.

    let voices = [];
    
    function loadVoices() {
        voices = speechSynthesis.getVoices();
        voiceSelect.innerHTML = voices
            .map((voice, index) => `<option value="${index}">${voice.name} (${voice.lang})</option>`)
            .join('');
    }
    
    loadVoices(); // Initial load
    
    speechSynthesis.onvoiceschanged = loadVoices; // Update voices if they change

    Web Speech API The Web Speech API provides interfaces for web pages to interact with speech recognition and synthesis (text-to-speech) capabilities. It allows developers to incorporate voice input and output directly into web applications, enhancing user interaction and accessibility.

    Speech Synthesis Utterance The SpeechSynthesisUtterance interface of the Web Speech API represents a speech request. It contains the content the speech synthesis service should read, and information about how to read it (e.g. language, pitch, rate and volume).

    Speech Synthesis The SpeechSynthesis interface of the Web Speech API is the controller interface for the speech synthesis service. It can be used to retrieve information about the synthesis voices available on the device, start, pause, and stop speech, and other things.

    getVoices() method The getVoices() method of the SpeechSynthesis interface returns a list of SpeechSynthesisVoice objects representing all the available voices on the current device.

    This code retrieves the available voices using speechSynthesis.getVoices(), maps them into <option> elements with voice name and language, and sets the innerHTML of the voiceSelect element. It also includes an event listener speechSynthesis.onvoiceschanged to update the voice list if the available voices change (e.g., when new voices are installed on the system).

  3. Play Text-to-Speech: Implement the functionality to play TTS when the play button is clicked.

    playButton.addEventListener('click', () => {
        const text = textInput.value.trim();
        if (!text) {
            alert('Please enter some text.');
            return;
        }
    
        const utterance = new SpeechSynthesisUtterance(text);
        const selectedVoiceIndex = voiceSelect.value;
    
        if (voices[selectedVoiceIndex]) {
            utterance.voice = voices[selectedVoiceIndex];
        }
    
        speechSynthesis.speak(utterance);
    });

    addEventListener() addEventListener() is a fundamental method in JavaScript for attaching event handlers to HTML elements. It allows you to specify a function that should be executed when a specific event occurs on the element (e.g., ‘click’, ‘mouseover’, ‘keydown’).

    SpeechSynthesisUtterance Constructor The SpeechSynthesisUtterance() constructor creates and returns a new SpeechSynthesisUtterance object instance. It takes an optional string parameter which will be set as the utterance’s text content.

    speak() method The speak() method of the SpeechSynthesis interface adds a SpeechSynthesisUtterance to the queue of utterances to be spoken; it will start speaking it when any other utterances queued before it have been spoken.

    This event listener on the playButton does the following:

    • Gets the text from the textInput and trims whitespace.
    • Alerts the user if no text is entered.
    • Creates a new SpeechSynthesisUtterance with the input text.
    • Gets the selected voice index from voiceSelect.
    • If a voice is selected, sets the utterance.voice to the corresponding voice object from the voices array.
    • Calls speechSynthesis.speak(utterance) to initiate speech synthesis.
  4. Populate Language Dropdown: Add code to populate the language selection dropdown. Define an array of supported languages with their ISO codes and names.

    const languages = [
        { code: 'en', name: 'English' },
        { code: 'es', name: 'Spanish' },
        { code: 'fr', name: 'French' },
        { code: 'de', name: 'German' },
        { code: 'it', name: 'Italian' },
        { code: 'ja', name: 'Japanese' },
        { code: 'zh-CN', name: 'Chinese Simplified' },
    ];
    
    function populateLanguageSelect() {
        languages.forEach(({ code, name }) => {
            const option = document.createElement('option');
            option.value = code;
            option.textContent = name;
            languageSelect.appendChild(option);
        });
    }
    
    populateLanguageSelect();
    

    ISO Codes ISO codes, specifically ISO 639 language codes, are international standards that define short codes for languages. These codes are used to represent languages in a standardized way, making it easier for computer systems to process and identify languages across different applications and contexts. For example, ‘en’ represents English, ‘es’ represents Spanish, and ‘fr’ represents French.

    forEach() method The forEach() method executes a provided function once for each element in an array. It is a way to iterate over the elements of an array and perform an action on each element.

    createElement() method The createElement() method in JavaScript is used to create a new HTML element node with the specified tag name. For example, document.createElement('option') creates a new <option> element.

    appendChild() method The appendChild() method of the Node interface adds a node to the end of the list of children of a specified parent node. In this context, it is used to add the newly created <option> element to the <select> element (languageSelect).

    This code defines the languages array and then the populateLanguageSelect function which iterates through this array. For each language, it creates an <option> element, sets its value to the language code, its textContent to the language name, and appends it to the languageSelect dropdown.

With these steps, the client-side Text-to-Speech functionality is implemented. Users can now type text, select a voice, and have the browser speak the text using the Web Speech API.

Creating Serverless Functions for Translation

To integrate translation using the Google Translate API securely, we will create a serverless function in api/translate.js. This function will act as a proxy, handling the API key and making requests to the Google Translate API on behalf of the client.

  1. Serverless Function Structure: Create the basic structure for a serverless function in api/translate.js.

    export default async function handler(req, res) {
        // Function logic here
    }

    Serverless Functions Serverless functions are event-driven, stateless compute functions that are hosted in the cloud and execute in response to specific triggers, such as HTTP requests, database events, or file uploads. They are “serverless” because developers do not need to manage the underlying servers or infrastructure. Platforms like Vercel automatically scale and manage the execution environment.

    Endpoint In web development, an endpoint is a specific URL or URI (Uniform Resource Identifier) that a client application can access to interact with a server or API. It represents a specific function or resource exposed by the server. In the context of serverless functions, each function often corresponds to a unique endpoint.

    This is the standard structure for a Vercel serverless function. It exports a default asynchronous function named handler that takes req (request) and res (response) objects, similar to Node.js frameworks like Express.

    Express Back End Express is a popular, minimalist web application framework for Node.js. It provides a set of features for building web applications and APIs, including routing, middleware, and template engines. While we are using serverless functions which are lighter weight, traditionally a full-fledged backend for APIs might be built using frameworks like Express.

  2. Handle POST Requests: Configure the function to only accept POST requests. Return an error for other methods.

    export default async function handler(req, res) {
        if (req.method !== 'POST') {
            return res.status(405).json({ error: 'Method Not Allowed' });
        }
    
        // Proceed with translation logic for POST requests
    }

    HTTP Request & HTTP Response HTTP Request is a message sent by a client (e.g., a web browser) to a server to request a resource or action. HTTP Response is the message sent back by the server in reply to the client’s request. These messages follow the Hypertext Transfer Protocol (HTTP), the foundation of data communication on the World Wide Web.

    Status Code An HTTP status code is a three-digit numerical code that a server returns in response to a client’s request. These codes indicate the outcome of the request, such as success (e.g., 200 OK), client error (e.g., 400 Bad Request, 404 Not Found), or server error (e.g., 500 Internal Server Error). 405 Method Not Allowed indicates that the method specified in the request is not allowed for the resource identified by the request URI.

  3. Parse Request Body and Validate Input: Parse the JSON request body to get the text and target language. Validate that both are provided.

    export default async function handler(req, res) {
        if (req.method !== 'POST') {
            return res.status(405).json({ error: 'Method Not Allowed' });
        }
    
        const { text, target } = req.body;
    
        if (!text || !target) {
            return res.status(400).json({ error: 'Missing text or language' });
        }
    
        // Proceed with Google Translate API call
    }

    Request Body The request body is the data sent in an HTTP request message after the request headers. In POST and PUT requests, the body often contains the data that the client wants to send to the server, such as form data or JSON payloads.

    JSON (JavaScript Object Notation) JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write and easy for machines to parse and generate. JSON is commonly used for transmitting data in web applications (e.g., sending data from a server to a client and vice versa).

    Validation In programming, validation is the process of checking if data meets certain criteria or rules before processing it. Input validation, specifically, is crucial for ensuring that user-provided data is correct, reasonable, and secure. It helps prevent errors, security vulnerabilities, and unexpected behavior in applications.

  4. Securely Access API Key: Access the Google Translate API key from environment variables. For local development, we’ll use the dotenv package.

    First, install dotenv as a development dependency:

    npm install -D dotenv

    NPM (Node Package Manager) npm (Node Package Manager) is the default package manager for Node.js. It is used to install, manage, and share JavaScript packages (modules). npm makes it easy to include external libraries and tools in your Node.js projects.

    Dev Dependency In npm, a dev dependency (development dependency) is a package that is required for development and testing purposes but is not needed to run the application in production. Dev dependencies are typically tools like linters, testing frameworks, and build tools. Installing with -D or --save-dev flag in npm adds the package to devDependencies in package.json.

    Then, in api/translate.js, load environment variables using dotenv conditionally for local development:

    if (process.env.NODE_ENV !== 'production') {
        require('dotenv').config();
    }
    
    const apiKey = process.env.GOOGLE_TRANSLATE_API_KEY;
    const apiUrl = `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`;

    .env Package dotenv is a zero-dependency Node.js module that loads environment variables from a .env file into process.env. This allows you to store configuration settings, such as API keys and database credentials, in environment variables, separating them from your code.

    process.env process.env is a global object in Node.js that provides access to environment variables. Environment variables are dynamic-named values that can affect the way running processes will behave on a computer. They are often used to configure applications without hardcoding values directly into the code, especially for sensitive information like API keys or database credentials.

    require() require() is a function in Node.js used to import modules or packages. It is part of Node.js’s module system, allowing you to include external code into your current file. In this context, require('dotenv').config() loads the dotenv package and configures it to load environment variables from a .env file.

    We conditionally load dotenv only when not in production to avoid bundling it in the deployed serverless function (Vercel handles environment variables directly in production). We then retrieve the API key from process.env.GOOGLE_TRANSLATE_API_KEY and construct the Google Translate API URL.

  5. Make Request to Google Translate API: Use the fetch API to make a POST request to the Google Translate API.

    export default async function handler(req, res) {
        // ... (Previous code for method check, input validation, API key setup) ...
    
        try {
            const response = await fetch(apiUrl, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    q: text,
                    target: target,
                    format: 'text',
                }),
            });
    
            if (!response.ok) {
                const errorText = await response.text();
                return res.status(response.status).json({ error: errorText });
            }
    
            const data = await response.json();
            return res.status(200).json({ data });
    
        } catch (error) {
            console.error('Error in API call:', error);
            return res.status(500).json({ error: 'Internal server error' });
        }
    }

    fetch API The fetch API is a modern JavaScript interface for making network requests, such as HTTP requests to fetch resources from servers. It provides a more powerful and flexible alternative to the older XMLHttpRequest. fetch() returns a Promise that resolves to the Response to that request, whether it is successful or not.

    async and await async and await are keywords in JavaScript that are used to work with asynchronous operations in a more synchronous-looking style, making asynchronous code easier to write and read. async marks a function as asynchronous, enabling the use of await inside it. await pauses the execution of the async function until a Promise is resolved, then resumes execution and returns the resolved value.

    try...catch block A try...catch block is a statement in JavaScript (and many other programming languages) used for error handling. Code that might throw an error is placed inside the try block. If an error occurs, the execution immediately jumps to the catch block, which contains code to handle the error gracefully, preventing the program from crashing.

    JSON.stringify() JSON.stringify() is a method in JavaScript that converts a JavaScript object or value to a JSON string. This is necessary when you want to send JavaScript data as the body of an HTTP request, as HTTP bodies are typically text-based.

    This code within the try block makes a fetch request to the Google Translate API endpoint:

    • Method: POST
    • Headers: Sets Content-Type to application/json to indicate we are sending JSON data.
    • Body: Uses JSON.stringify() to convert a JavaScript object into a JSON string containing:
      • q: The text to translate (from the request body).
      • target: The target language code (from the request body).
      • format: Set to text to request plain text translation.

    The code then checks if the response is successful (response.ok). If not, it extracts the error text from the response and returns a 500 status with the error message. If successful, it parses the JSON response (response.json()) and returns a 200 status with the translated data. The catch block handles any errors during the API call itself and returns a 500 status with a generic “Internal server error” message.

  6. Test with Postman (or similar tool): Before integrating into the client-side, it’s useful to test the serverless function directly using a tool like Postman or curl.

    Postman Postman is a popular API client used for testing and developing APIs. It provides a graphical user interface to send HTTP requests to servers and view the responses. Postman simplifies the process of testing API endpoints, setting headers, request bodies, and inspecting responses.

    Configure Postman to send a POST request to http://localhost:3000/api/translate (assuming you are running Vercel CLI in development mode). Set the Content-Type header to application/json and include a JSON body like:

    {
        "text": "Hello world",
        "target": "es"
    }

    You should receive a JSON response from your serverless function containing the translated text. If you encounter errors, check your API key, code for syntax errors, and network connectivity.

Integrating Translation into Client-Side JavaScript

Now, integrate the translation serverless function into our client-side JavaScript (public/script.js).

  1. Create translateText Function: Create an asynchronous function translateText to call our serverless function.

    async function translateText(text, targetLang) {
        try {
            const response = await fetch('/api/translate', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({ text, target: targetLang }),
            });
    
            if (!response.ok) {
                const message = `HTTP error! status: ${response.status}`;
                throw new Error(message);
            }
            const data = await response.json();
            return data.data.translations[0].translatedText; // Extract translated text
        } catch (error) {
            console.error('Translation error:', error);
            alert('Failed to translate text.');
            return text; // Return original text in case of error
        }
    }

    This function uses fetch to make a POST request to /api/translate. It sends the text and targetLang to the serverless function. It handles potential errors and returns the translated text from the response, or the original text if translation fails.

  2. Modify playButton Event Listener: Update the playButton event listener to use the translateText function before speaking the text.

    playButton.addEventListener('click', async () => { // Make event handler async
        const text = textInput.value.trim();
        const targetLang = languageSelect.value;
        const selectedVoiceIndex = voiceSelect.value;
    
        if (!text) {
            alert('Please enter some text.');
            return;
        }
    
        try {
            const translatedText = await translateText(text, targetLang); // Translate text
            const utterance = new SpeechSynthesisUtterance(translatedText); // Use translated text
            if (voices[selectedVoiceIndex]) {
                utterance.voice = voices[selectedVoiceIndex];
            }
            speechSynthesis.speak(utterance);
        } catch (error) {
            console.error('Error during processing:', error);
            alert('An error occurred.');
        }
    });

    We make the event listener async to use await when calling translateText. We get the targetLang from the languageSelect dropdown. Inside a try...catch block, we call translateText to get the translatedText. We then create the SpeechSynthesisUtterance with the translatedText instead of the original text. The rest of the TTS logic remains the same.

Local Development and Testing

  1. Install Vercel CLI (if not already installed):

    npm install -g vercel

    npm install -g npm install -g <package-name> is an npm command used to install a Node.js package globally on your system. When a package is installed globally, its executables are added to your system’s PATH, allowing you to run commands from that package from anywhere in your terminal. This is often used for command-line tools like Vercel CLI.

  2. Login to Vercel:

    vercel login

    This will open a browser window to authenticate with your Vercel account.

  3. Start Vercel Development Server: In your project directory, run:

    vercel dev

    vercel dev vercel dev is a command in the Vercel CLI that starts a local development server that emulates the Vercel production environment. It allows you to test your serverless functions, frontend code, and Vercel configuration locally before deploying to production. It typically runs your application on http://localhost:3000.

    This command starts a local development server on http://localhost:3000. It will automatically detect your serverless functions in the api directory and make them accessible.

  4. Test the Application: Open http://localhost:3000 in your browser. Test the Text-to-Speech and translation functionalities. Ensure that translation works correctly and that no API key is exposed in the client-side code.

    Localhost Localhost is a hostname that refers to the loopback network interface (IP address 127.0.0.1) of your computer. When you access http://localhost:<port> or http://127.0.0.1:<port> in a web browser, you are making a request to a server running on your own machine at the specified port. vercel dev runs your application on localhost, allowing you to test it locally.

  5. Debug (if necessary): If you encounter issues, use browser developer tools (Console and Network tabs) and server-side logs (printed to your terminal where vercel dev is running) to diagnose and fix errors.

    Vanilla JavaScript Vanilla JavaScript refers to using plain JavaScript without relying on any external libraries or frameworks. It emphasizes writing JavaScript code using only the built-in features of the language and the browser’s Web APIs. This approach can be beneficial for learning the fundamentals of JavaScript and for projects where minimal dependencies are desired.

    Our project is built with vanilla JavaScript, meaning we are using core JavaScript features and Web APIs without relying on external frameworks like React, Angular, or Vue.js for the client-side logic.

Deployment to Vercel

Once you are satisfied with your local testing, you can deploy the application live to Vercel.

  1. Add Environment Variable on Vercel: Before deploying, ensure you have set the GOOGLE_TRANSLATE_API_KEY environment variable in your Vercel project settings.

    • Go to your Vercel project dashboard online.
    • Navigate to Settings > Environment Variables.
    • Add a new environment variable named GOOGLE_TRANSLATE_API_KEY and paste your Google Translate API key as the value.
    • Save the settings.
  2. Deploy with Vercel CLI: In your project directory, run:

    vercel --prod

    vercel --prod vercel --prod is a command in the Vercel CLI used to deploy your application to Vercel’s production environment. The --prod flag ensures that the deployment is treated as a production deployment, typically applying production settings and optimizations. It will build your project, upload the necessary files, and deploy your application to a live URL on Vercel.

    This command builds your project and deploys it to Vercel. Vercel will automatically detect the project type, build the necessary assets, and deploy your application. You will receive a live URL once deployment is complete.

  3. Access Live Application: Open the provided live URL in your browser to access your deployed Text-to-Speech and Translation application. Test to confirm it is working as expected in the production environment.

    Production Environment A production environment is the live environment where an application is deployed and made available to end-users. It is the final stage after development, testing, and staging, representing the real-world, operational setting for the application. In contrast to development and staging environments, the production environment is focused on stability, performance, and reliability for user access.

Conclusion

Congratulations! You have successfully built a Text-to-Speech and translation web application using serverless functions. This project demonstrates several important concepts:

  • Client-side web development: Using HTML, CSS, and JavaScript to create an interactive user interface.
  • Web Speech API: Implementing Text-to-Speech functionality directly in the browser.
  • Serverless functions: Creating secure backend logic using serverless functions to handle API keys and interact with external services.
  • Google Translate API: Integrating translation capabilities into a web application.
  • Secure API key management: Protecting sensitive API keys by using serverless functions as a proxy.
  • Local development and deployment workflows: Using Vercel CLI for local testing and seamless deployment to a live environment.

This project serves as a solid foundation for further exploration and expansion. You could extend this application by adding more languages, voice options, UI enhancements, or integrating with other APIs and services. The use of serverless functions provides a scalable and secure approach for building modern web applications.