Project Structure(Frontend)
The updated Dependencies in package.json file of frontend will look like:
"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
Example: Create the required files and write the following code.
CSS
/* App.css */ * { margin : 0 ; padding : 0 ; box-sizing: border-box; font-family : sans-serif ; } body { display : flex; align-items: center ; justify- content : center ; padding : 0 10px ; min-height : 100 vh; background : #222222 ; } .container { min-width : 700px ; width : 100% ; padding : 30px ; background : #fff ; border-radius: 7px ; box-shadow: 0 10px 20px rgba( 0 , 0 , 0 , 0.01 ); } .wrapper { border-radius: 5px ; border : 1px solid #ccc ; } .wrapper .text-input { display : flex; border-bottom : 1px solid #ccc ; } .text-input .to-text { border-radius: 0px ; border-left : 1px solid #ccc ; } .text-input textarea { height : 250px ; width : 100% ; border : none ; outline : none ; resize: none ; background : none ; font-size : 18px ; padding : 10px 15px ; border-radius: 5px ; } .text-input textarea::placeholder { color : #b7b6b6 ; } .controls, li, .icons, .icons i { display : flex; align-items: center ; justify- content : space-between; } .controls { list-style : none ; padding : 12px 15px ; } .controls .row .icons { width : 38% ; } .controls .row .icons i { width : 50px ; color : #adadad ; font-size : 14px ; cursor : pointer ; transition: transform 0.2 s ease; justify- content : center ; } .controls .row.from .icons { padding-right : 15px ; border-right : 1px solid #ccc ; } .controls .row.to .icons { padding-left : 15px ; border-left : 1px solid #ccc ; } .controls .row select { color : #333 ; border : none ; outline : none ; font-size : 18px ; background : none ; padding-left : 5px ; } .text-input textarea::-webkit-scrollbar { width : 4px ; } .controls .row select::-webkit-scrollbar { width : 8px ; } .text-input textarea::-webkit-scrollbar-track, .controls .row select::-webkit-scrollbar-track { background : #fff ; } .text-input textarea::-webkit-scrollbar-thumb { background : #ddd ; border-radius: 8px ; } .controls .row select::-webkit-scrollbar-thumb { background : #999 ; border-radius: 8px ; border-right : 2px solid #ffffff ; } .controls .exchange { color : #adadad ; cursor : pointer ; font-size : 16px ; transition: transform 0.2 s ease; } .controls i:active { transform: scale( 0.9 ); } .container button { width : 100% ; padding : 14px ; outline : none ; border : none ; color : #fff ; cursor : pointer ; margin-top : 20px ; font-size : 17px ; border-radius: 5px ; background : #2f8d46 ; } .above-container { display : flex; align-items: center ; justify- content : center ; } .above-container-content { font-size : xx-large ; font-weight : 100 ; display : inline ; margin-right : 1% ; margin-bottom : 1% ; color : #ffffff ; } .above-container img { width : 40px ; } |
Javascript
// index.js import React from 'react' ; import ReactDOM from 'react-dom/client' ; import './styles/index.css' ; import App from './components/App' ; const root = ReactDOM.createRoot(document.getElementById( 'root' )); root.render( <React.StrictMode> <App /> </React.StrictMode> ); |
Javascript
// App.js import "../styles/App.css" ; import Translate from "./Translate.js" ; function App() { return ( <> <Translate /> </> ); } export default App; |
Javascript
// data.js const countries = { "am-ET" : "Amharic" , "ar-SA" : "Arabic" , "be-BY" : "Bielarus" , "bem-ZM" : "Bemba" , "bi-VU" : "Bislama" , "bjs-BB" : "Bajan" , "bn-IN" : "Bengali" , "bo-CN" : "Tibetan" , "br-FR" : "Breton" , "bs-BA" : "Bosnian" , "ca-ES" : "Catalan" , "cop-EG" : "Coptic" , "cs-CZ" : "Czech" , "cy-GB" : "Welsh" , "da-DK" : "Danish" , "dz-BT" : "Dzongkha" , "de-DE" : "German" , "dv-MV" : "Maldivian" , "el-GR" : "Greek" , "en-GB" : "English" , "es-ES" : "Spanish" , "et-EE" : "Estonian" , "eu-ES" : "Basque" , "fa-IR" : "Persian" , "fi-FI" : "Finnish" , "fn-FNG" : "Fanagalo" , "fo-FO" : "Faroese" , "fr-FR" : "French" , "gl-ES" : "Galician" , "gu-IN" : "Gujarati" , "ha-NE" : "Hausa" , "he-IL" : "Hebrew" , "hi-IN" : "Hindi" , "hr-HR" : "Croatian" , "hu-HU" : "Hungarian" , "id-ID" : "Indonesian" , "is-IS" : "Icelandic" , "it-IT" : "Italian" , "ja-JP" : "Japanese" , "kk-KZ" : "Kazakh" , "km-KM" : "Khmer" , "kn-IN" : "Kannada" , "ko-KR" : "Korean" , "ku-TR" : "Kurdish" , "ky-KG" : "Kyrgyz" , "la-VA" : "Latin" , "lo-LA" : "Lao" , "lv-LV" : "Latvian" , "men-SL" : "Mende" , "mg-MG" : "Malagasy" , "mi-NZ" : "Maori" , "ms-MY" : "Malay" , "mt-MT" : "Maltese" , "my-MM" : "Burmese" , "ne-NP" : "Nepali" , "niu-NU" : "Niuean" , "nl-NL" : "Dutch" , "no-NO" : "Norwegian" , "ny-MW" : "Nyanja" , "ur-PK" : "Pakistani" , "pau-PW" : "Palauan" , "pa-IN" : "Panjabi" , "ps-PK" : "Pashto" , "pis-SB" : "Pijin" , "pl-PL" : "Polish" , "pt-PT" : "Portuguese" , "rn-BI" : "Kirundi" , "ro-RO" : "Romanian" , "ru-RU" : "Russian" , "sg-CF" : "Sango" , "si-LK" : "Sinhala" , "sk-SK" : "Slovak" , "sm-WS" : "Samoan" , "sn-ZW" : "Shona" , "so-SO" : "Somali" , "sq-AL" : "Albanian" , "sr-RS" : "Serbian" , "sv-SE" : "Swedish" , "sw-SZ" : "Swahili" , "ta-LK" : "Tamil" , "te-IN" : "Telugu" , "tet-TL" : "Tetum" , "tg-TJ" : "Tajik" , "th-TH" : "Thai" , "ti-TI" : "Tigrinya" , "tk-TM" : "Turkmen" , "tl-PH" : "Tagalog" , "tn-BW" : "Tswana" , "to-TO" : "Tongan" , "tr-TR" : "Turkish" , "uk-UA" : "Ukrainian" , "uz-UZ" : "Uzbek" , "vi-VN" : "Vietnamese" , "wo-SN" : "Wolof" , "xh-ZA" : "Xhosa" , "yi-YD" : "Yiddish" , "zu-ZA" : "Zulu" , }; export default countries; |
Javascript
// Translate.js import React, { useEffect } from "react" ; import countries from "./data.js" ; const Translate = () => { useEffect(() => { const fromText = document.querySelector( ".from-text" ); const toText = document.querySelector( ".to-text" ); const exchageIcon = document.querySelector( ".exchange" ); const selectTag = document.querySelectorAll( "select" ); const icons = document.querySelectorAll( ".row i" ); const translateBtn = document.querySelector( "button" ); selectTag.forEach((tag, id) => { for (let country_code in countries) { let selected = id === 0 ? country_code === "en-GB" ? "selected" : "" : country_code === "hi-IN" ? "selected" : "" ; let option = `<option ${selected} value= "${country_code}" >${countries[country_code]}</option>`; tag.insertAdjacentHTML( "beforeend" , option); } }); exchageIcon.addEventListener( "click" , () => { console.log( "helo" ); let tempText = fromText.value; let tempLang = selectTag[0].value; console.log(tempText); console.log(tempLang); fromText.value = toText.value; toText.value = tempText; selectTag[0].value = selectTag[1].value; selectTag[1].value = tempLang; }); fromText.addEventListener( "keyup" , () => { if (!fromText.value) { toText.value = "" ; } }); translateBtn.addEventListener( "click" , async () => { let text = fromText.value.trim(); let translateFrom = selectTag[0].value; let translateTo = selectTag[1].value; if (!text) return ; toText.setAttribute( "placeholder" , "Translating..." ); try { const response = await fetch(`http: //localhost:5000/?text=${text}&source=${translateFrom}&target=${translateTo}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const translatedText = await response.text(); toText.value = translatedText; toText.setAttribute( "placeholder" , "Translation" ); } catch (error) { console.error( "Fetch error:" , error); toText.setAttribute( "placeholder" , "Error in translation" ); } }); icons.forEach((icon) => { icon.addEventListener( "click" , ({ target }) => { if (!fromText.value || !toText.value) return ; if (target.classList.contains( "fa-copy" )) { if (target.id === "from" ) { navigator.clipboard.writeText(fromText.value); } else { navigator.clipboard.writeText(toText.value); } } else { let utterance; if (target.id === "from" ) { utterance = new SpeechSynthesisUtterance(fromText.value); utterance.lang = selectTag[0].value; } else { utterance = new SpeechSynthesisUtterance(toText.value); utterance.lang = selectTag[1].value; } speechSynthesis.speak(utterance); } }); }); }, []); return ( <> <div className= "above-container " > <img src={ "https://media.w3wiki.org/wp-content/uploads/20240306111234/gfg.jpg" } className= "above-container-content" alt= "w3wiki Logo" /> <h1 className= "above-container-content" >Translate</h1> </div> <div className= "container" > <div className= "wrapper" > <div className= "text-input" > <textarea spellCheck= "false" className= "from-text" placeholder= "Enter text" ></textarea> <textarea spellCheck= "false" readOnly disabled className= "to-text" placeholder= "Translation" ></textarea> </div> <ul className= "controls" > <li className= "row from" > <div className= "icons" > <i id= "from" className= "fas fa-volume-up" ></i> <i id= "from" className= "fas fa-copy" ></i> </div> <select></select> </li> <li className= "exchange" > <i className= "fas fa-exchange-alt" ></i> </li> <li className= "row to" > <select></select> <div className= "icons" > <i id= "to" className= "fas fa-volume-up" ></i> <i id= "to" className= "fas fa-copy" ></i> </div> </li> </ul> </div> <button>Translate Text</button> </div> </> ); }; export default Translate; |
Start your application using the following command.
npm start
Output:
Text Translation Tool using MERN Stack
In this article, we’ll walk through the step-by-step process of creating a text translation application with MongoDB, React, ExpressJS, and NodeJS. This application will provide users with a user-friendly interface for translating text between different languages.
Output Preview: Let us have a look at how the final output will look like.
Contact Us