Integrando Azure Text Translation en una aplicación React con Next.js

danieljsaldana

Daniel J. Saldaña

Posted on March 10, 2024

Integrando Azure Text Translation en una aplicación React con Next.js

En el mundo globalizado de hoy, proporcionar contenido en varios idiomas puede ser una enorme ventaja para tu aplicación web. Microsoft Azure ofrece un servicio de traducción de texto que se puede integrar fácilmente en cualquier aplicación web. En este tutorial, te mostraré cómo utilizar Azure Text Translation en una aplicación creada con React para el frontend y Next.js para el API de backend.

Paso 1: Configuración del Servicio en Azure

El primer paso es crear y configurar el servicio Azure Text Translation en la consola de Azure:

  1. Iniciar sesión y crear un recurso : Ve a Azure Portal y haz clic en "Crear un recurso". Busca "Translator" y sigue las instrucciones para crearlo.

  2. Configuración del servicio : Elige un nombre para tu servicio, selecciona el plan de precios y la región.

  3. Obtener las claves de acceso : Una vez creado el servicio, ve a "Claves y punto de conexión" para obtener tu "Clave 1" y "Ubicación". Guarda estos valores, los necesitarás más adelante para tu API.

Paso 2: Configuración del Backend con Next.js

Ahora que hemos configurado nuestro servicio en Azure, es hora de crear el backend que manejará las solicitudes de traducción. Este backend se implementará usando Next.js, aprovechando su capacidad para crear API routes de manera sencilla y eficiente.

A continuación, te muestro un ejemplo de cómo configurar un endpoint de API en Next.js para realizar traducciones utilizando el servicio Azure Text Translation:

import axios from 'axios';
import { enableCors } from "@/src/middleware/enableCors";
import { methodValidator } from "@/src/utils/methodValidator";

require('dotenv').config(); 

// Función para eliminar el markdown del texto
function stripMarkdown(markdownText) {
    // Aquí se eliminan diversos elementos de markdown para obtener solo el texto plano
    return markdownText
        .replace(/```

[\s\S]*?

```/g, '')
        .replace(/\([^\)]*\)/g, '')
        .replace(/(\*\*|__)(.*?)(\*\*|__)/g, '$2')
        .replace(/\!\[(.*?)\]\((.*?)\)/g, '')
        .replace(/\[(.*?)\]\((.*?)\)/g, '$1')
        .replace(/(\*\*|__)/g, '')
        .replace(/(\*|-)/g, '')
        .replace(/(#{1,6}) /g, '')
        .replace(/`(.+?)`/g, '')
        .replace(/\n/g, ' ');
}

// Función para eliminar el HTML del texto
function stripHtml(htmlText) {
    // Elimina las etiquetas HTML para obtener solo el texto
    return htmlText.replace(/<[^>]*>/g, '');
}

// La función principal que maneja la solicitud de traducción
const translation = async (req, res) => {
    await enableCors(req, res); // Habilita CORS para la solicitud
    await methodValidator(req, res, 'POST'); // Valida que la solicitud sea de tipo POST

    if (res.headersSent) {
        console.log('La respuesta ya fue enviada.');
        return;
    }

    // Extrae los datos necesarios de la solicitud
    let { title, content, targetLanguage } = req.body;
    if (!title || !content || !targetLanguage) {
        console.log('Faltan datos en la solicitud:', { title, content, targetLanguage });
        return res.status(400).json({ error: 'Faltan datos en la solicitud. Se requieren title, content y targetLanguage.' });
    }

    // Limpia el título y el contenido de markdown y HTML
    title = stripMarkdown(stripHtml(title));
    content = stripMarkdown(stripHtml(content));

    // Configuración para la solicitud a la API de Azure Text Translation
    const translatorConfig = {
        headers: {
            'Ocp-Apim-Subscription-Key': process.env.TRANSLATOR_SUBSCRIPTION_KEY,
            'Ocp-Apim-Subscription-Region': process.env.TRANSLATOR_REGION, 
            'Content-Type': 'application/json'
        },
        params: {
            'api-version': '3.0',
            'to': targetLanguage
        }
    };

    try {
        // Realiza las solicitudes de traducción para el título y el contenido simultáneamente
        const [titleResponse, contentResponse] = await Promise.all([
            axios.post('https://api.cognitive.microsofttranslator.com/translate', [{ Text: title }], translatorConfig),
            axios.post('https://api.cognitive.microsofttranslator.com/translate', [{ Text: content }], translatorConfig)
        ]);

        // Extrae las traducciones del título y el contenido de las respuestas
        const translatedTitle = titleResponse.data[0].translations[0].text;
        const translatedContent = contentResponse.data[0].translations[0].text;

        // Envía la respuesta con el título y contenido traducidos
        return res.status(200).json({
            translatedTitle,
            translatedContent
        });
    } catch (error) {
        console.error('Error durante la traducción:', error);
        return res.status(500).json({
            error: `Error durante la solicitud de traducción: ${error.message}`
        });
    }
};

export default enableCors(translation);

Enter fullscreen mode Exit fullscreen mode

Cómo Funciona

Este backend realiza varios pasos importantes para procesar y responder a las solicitudes de traducción:

  1. Habilitación de CORS : Utiliza un middleware enableCors para permitir solicitudes de origen cruzado, lo cual es crucial para APIs accesibles desde el frontend.

  2. Validación del Método de Solicitud : El methodValidator asegura que solo se acepten solicitudes POST, que es lo esperado para enviar datos de texto a traducir.

  3. Limpieza de Texto : Antes de enviar el texto a la API de Azure, se limpia de markdown y HTML para asegurarse de que la traducción sea sobre el texto puro.

  4. Configuración de la Solicitud de Traducción : Establece los encabezados y parámetros necesarios, incluyendo la clave de suscripción y la región que obtuviste al configurar el servicio Azure.

  5. Envío y Respuesta de la Traducción : Realiza solicitudes HTTP paralelas para traducir tanto el título como el contenido, y luego responde con el texto traducido.

Al implementar esta función en tu backend, proporcionas una forma robusta y segura de integrar traducciones automáticas en tu aplicación.

Entendido, vamos a actualizar el paso 3 del post con el ejemplo de código proporcionado para el componente del frontend y una explicación de cómo funciona:

Paso 3: Integración del Frontend con React

Una vez que el backend está en su lugar, es hora de conectar el frontend para que los usuarios puedan enviar texto para traducir y ver los resultados. Vamos a crear un componente React que maneje esta funcionalidad:

import { useState, useEffect, useMemo } from 'react';
import axios from 'axios';
import sanitizeHtml from 'sanitize-html';
import { marked } from 'marked';
import { SiMicrosofttranslator } from 'react-icons/si';
import { GiAllSeeingEye } from 'react-icons/gi';
import './TranslationController.scss';

const TranslationController = ({ content, title, image }) => {
  // Estados para controlar la UI y almacenar los datos de traducción
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [selectedLanguage, setSelectedLanguage] = useState('');
  const [translatedTitle, setTranslatedTitle] = useState(title);
  const [translatedContent, setTranslatedContent] = useState(content);
  const [isTranslating, setIsTranslating] = useState(false);
  const [tokens, setTokens] = useState(0);
  const [dailyLimitInfo, setDailyLimitInfo] = useState({ dailyLimit: 0, tokensUsedToday: 0 });
  const [errorMessage, setErrorMessage] = useState('');

  // Efectos para cargar información necesaria al cargar el componente
  useEffect(() => {
    fetchDailyLimit();
    fetchTokens();
  }, []);

  // Aquí se definen las funciones para manejar la lógica de negocios, como obtener los tokens y límites diarios,
  // actualizar tokens y realizar la traducción.

  const toggleModal = () => {
    setIsModalOpen(!isModalOpen);
    document.body.classList.toggle('no-scroll', !isModalOpen);
  };

  const handleLanguageChange = (e) => {
    setSelectedLanguage(e.target.value);
  };

  // Funciones para manejar la conversión de Markdown a HTML y la limpieza de HTML

  const translateContent = async () => {
    // Lógica para iniciar la traducción y actualizar los estados basados en la respuesta
  };

  // Lógica para calcular los tokens disponibles basada en la información del límite diario
  const tokensAvailableToday = useMemo(() => {
    const { dailyLimit, tokensUsedToday } = dailyLimitInfo;
    return Math.max(dailyLimit - tokensUsedToday, 0);
  }, [dailyLimitInfo]);

  // Renderiza el componente, mostrando el formulario de traducción, los resultados y cualquier mensaje de error.
  return (
    // JSX para la interfaz del controlador de traducción
  );
};

export default TranslationController;

Enter fullscreen mode Exit fullscreen mode

Cómo Funciona

Este componente de React TranslationController maneja varias tareas importantes:

  1. Estados y Efectos : Utiliza los hooks de React para manejar estados y efectos secundarios. Esto incluye abrir y cerrar el modal de traducción, almacenar el contenido traducido, y rastrear si se está realizando una traducción.

  2. Manejo de Límites y Tokens : Hace solicitudes al backend para obtener y actualizar el número de tokens disponibles y el límite diario de uso. Esto es crucial para no sobrepasar los límites del servicio de traducción.

  3. Selección de Idioma y Traducción : Permite al usuario seleccionar el idioma de destino y envía el contenido a traducir al backend. Muestra el contenido traducido una vez que esté disponible.

  4. Renderización de Markdown y Sanitización de HTML : Convierte el contenido de Markdown a HTML y lo limpia antes de mostrarlo, asegurando que el contenido sea seguro y esté formateado correctamente.

  5. UI Interactiva : Proporciona una interfaz de usuario interactiva y amigable, incluyendo un modal de traducción, selección de idioma y botones para realizar la traducción. También maneja la visualización de mensajes de error y la cantidad de tokens disponibles.

Este componente encapsula toda la lógica necesaria para interactuar con el servicio de traducción y proporcionar una experiencia de usuario fluida y funcional. Con este enfoque, los usuarios pueden traducir fácilmente el título y el contenido de sus publicaciones o documentos directamente desde la interfaz de la aplicación.

💖 💪 🙅 🚩
danieljsaldana
Daniel J. Saldaña

Posted on March 10, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related