HTML - How to translate page content using Javascript? - javascript

I am doing the following in order to translate my HTML page:
<p data-key="paragraph-1">Hello world</p>
<p data-key="paragraph-2">This is a translated text!</p>
<div ...>
<a data-key="aboutPage" href="about.html">About</a>
</div>
const translations = {
"es": () => ({
"title": "¡Hola mundo!",
"subtitle": "¡Este texto ha sido traducido!",
"routes": {
"aboutPage": "Sobre",
}
}),
...
}
const t = _.memoize(
(
scope,
language = getNavigatorLanguage() ?? DEFAULT_LANGUAGE,
fallbackLanguage = DEFAULT_LANGUAGE,
fallbackText = ""
) => {
const formattedLocale = language.split(/[-_]/)[0]; // Short version: "en", "es", "it"...
const translation = // fallback
(translationGetters[formattedLocale] ?? translationGetters[fallbackLanguage])();
return (
_.get(translation, scope) ??
_.get(translationGetters[DEFAULT_LANGUAGE](), scope, fallbackText)
);
},
(...args) => JSON.stringify(args)
);
$(() => {
$("*[data-key='paragraph-1']").text(t("title"));
$("*[data-key='paragraph-2']").text(t("subtitle"));
$("*[data-key='aboutPage']").text(t("routes.aboutPage"));
});
I come from React Native, where I could simply do:
<Text>
{t("routes.aboutPage")}
</Text>
But I am not sure if it is a good practice (maybe is wrong for SEO or just not good) to do something like this on HTML:
<p>
<script>
t("title")
</script>
</p>
Would I have to use selectors in order translate all my content? Any advices?

STEP 1: Create Translation Function
Let create a new JavaScript file called "translate.js" and then write code to get translation text from JSON file in folder lng based on the selected language.
function Translate() {
//initialization
this.init = function(attribute, lng){
this.attribute = attribute;
this.lng = lng;
}
//translate
this.process = function(){
_self = this;
var xrhFile = new XMLHttpRequest();
//load content data
xrhFile.open("GET", "lng/"+this.lng+".json", false);
xrhFile.onreadystatechange = function ()
{
if(xrhFile.readyState === 4)
{
if(xrhFile.status === 200 || xrhFile.status == 0)
{
var LngObject = JSON.parse(xrhFile.responseText);
var allDom = document.getElementsByTagName("*");
for(var i =0; i < allDom.length; i++){
var elem = allDom[i];
var key = elem.getAttribute(_self.attribute);
if(key != null) {
elem.innerHTML = LngObject[key] ;
}
}
}
}
}
xrhFile.send();
}
}
STEP 2: Switch Language Function
Create a new JavaScript file named "index.js" to begin the translation process
//This function will be called when user click changing language
function translate(lng, tagAttr){
var translate = new Translate();
translate.init(tagAttr, lng);
translate.process();
if(lng == 'en'){
$("#enTranslator").css('color', '#f4623a');
$("#khTranslator").css('color', '#212529');
}
if(lng == 'kh'){
$("#khTranslator").css('color', '#f4623a');
$("#enTranslator").css('color', '#212529');
}
}
$(document).ready(function(){
//This is id of HTML element (English) with attribute lng-tag
$("#enTranslator").click(function(){
translate('en', 'lng-tag');
});
//This is id of HTML element (Khmer) with attribute lng-tag
$("#khTranslator").click(function(){
translate('kh', 'lng-tag');
});
});
STEP 3: Define Your Translation Text in JSON
Let define translation text in JSON file as below
STEP 4: Embed Translation into Your Website
Import both JavaScript file "index.js" and "translate.js" to HTML page
<script src="js/translate.js"></script>
<script src="js/index.js"></script>
Set selected language when first loading the page
<body id="page-top" onload="translate('kh','lng-tag')">
Define HTML element with attribute "lng-tag" for the text you wanted to be translated and value of attribute is the key which define in JSON file
Here is the static website which implements the above method to translate language between Khmer (CAMBODIAN) and English https://praject.co/

Related

JS file not being found in .NET visual studio using Blazor WebAssembly

I am trying to add a JS script file called chatfunction.js into my index.html in Blazor but it gives me an error that it cannot find a file. My CSS is linked correctly and the HTML and CSS both show up but it does not provide any of the JS functionality that I have implemented.
I am adding it at the bottom of my HTML in index.html like this:
....
<script src="_framework/blazor.webassembly.js"></script>
<script src="chatfunction.js"></script>
</body>
</html>
Here is my project structure
Now when I try compiling it gives me this error:
(JS) File 'C:/Users/darka/source/repos/chatproject/wwwroot/js/mysrc.js' not found.
I don't get why it can't find it and I am confused as to why it thinks my file is mysrc.js as there is no file like that in my project structure.
Any pointers how to fix this?
Here is the layout of my JS file
var botController = (function () {
})();
var uiController = (function () {
})();
var controller = (function (botCntr, uiCntr) {
var $chatCircle,
$chatBox,
$chatBoxClose,
$chatBoxWelcome,
$chatWraper,
$submitBtn,
$chatInput,
$msg;
/*toggle*/
function hideCircle(evt) {
evt.preventDefault();
$chatCircle.hide('scale');
$chatBox.show('scale');
$chatBoxWelcome.show('scale');
}
function chatBoxCl(evt) {
evt.preventDefault();
$chatCircle.show('scale');
$chatBox.hide('scale');
$chatBoxWelcome.hide('scale');
$chatWraper.hide('scale');
}
function chatOpenMessage(evt) {
evt.preventDefault();
$chatBoxWelcome.hide();
$chatWraper.show();
}
//generate messages on submit click
function submitMsg(evt) {
evt.preventDefault();
//1. get input message data
msg = $chatSubmitBtn.val();
//2.if there is no string button send shoudn't work
if (msg.trim() == '') {
return false;
}
//3. add message to bot controller
callbot(msg);
//4. display message to ui controller
generate_message(msg, 'self');
}
function chatSbmBtn(evt) {
if (evt.keyCode === 13 || evt.which === 13) {
console.log("btn pushed");
}
}
/* var input = uiCntr.getInput();*/
/* $chatSubmitBtn.on("click", hideCircle);*/
function init() {
$chatCircle = $("#chat-circle");
$chatBox = $(".chat-box");
$chatBoxClose = $(".chat-box-toggle");
$chatBoxWelcome = $(".chat-box-welcome__header");
$chatWraper = $("#chat-box__wraper");
$chatInput = $("#chat-input__text");
$submitBtn = $("#chat-submit");
//1. call toggle
$chatCircle.on("click", hideCircle);
$chatBoxClose.on("click", chatBoxCl);
$chatInput.on("click", chatOpenMessage);
//2. call wait message from CRM-human
$submitBtn.on("click", chatSbmBtn);
$chatInput.on("keypress", chatSbmBtn);
//6. get message from bot controller-back end
//7. display bot message to ui controller
}
return {
init: init
};
})(botController, uiController);
$('.chat-input__form').on('submit', function (e) {
e.preventDefault();
msg = $('.chat-input__text').val();
$('.chat-logs').append('<div id="cm-msg-0" class="chat-msg background-warning push-right bot"><div class="cm-msg-text">' + msg + '</div><span class="msg-avatar"><img class="chat-box-overlay_robot" src="https://www.meetsource.com//userStyles/images/user.png"></span></div>');
$('.chat-input__text').val('');
});
$(document).ready(controller.init);
function talk() {
var user = document.getElementById("userBox").value;
document.getElementById("userBox").value = "";
document.getElementById("chatLog").innerHTML += user + "<br>";
}
I think your script line needs to be:
<script src="js/chatfunction.js"></script>

How to display array elements passed into Handlebars file one by one on button click?

Suppose, I have following array of objects successfully sent to handlebars file from my express server:
[
{
"name": "Jon",
"isPositive": true
},
{
"name": "Cercei",
"isPositive": false
}
]
Each time when my button gets clicked, I want to show next element of the array on my view. Is it possible with handlebars? Or do I need something more complex like Vue.js to solve this problem? Here is simple pseudocode I would like to achieve:
<head>
<script>
$(document).ready(() => {
var index = 0;
var currentCharacter = getCurrentCharacter();
start();
});
</script>
</head>
<body>
<h3 id="name"></h3>
<p id="someInfo"> </p>
<button onclick="next()">Next</button>
<script>
function getCurrentCharacter() {
/// somehow access array of objects sent from server
var myCharacters = {{characters}}; // {} used because of handlebars
var character = myCharacters[index];
index += 1;
return character;
}
function start() {
document.getElementById("name").textContent = currentCharacter.name;
/// as you see here, I change my UI based on current object fields/attributes
if (currentCharacter.isPositive) {
document.getElementById("someInfo").style.display = "block";
document.getElementById("someInfo").textContent = "Some text here";
} else {
document.getElementById("someInfo").style.visibility = "hidden";
}
}
function next() {
currentCharacter = getCurrentCharacter();
start();
}
</script>
</body>
Is it possible to have such a logic with handlebars or other templating languages? If they are not build for these purposes, please recommend me another way to solve this problem.

How can I create a language toggle for a wordpress website that actually changes the menu options language as well?

I have an wordpress website which I have to translate to english and spanish. I have created a toggle button to change the content language by setting each language link to a page with different content (i know that is probably dumb) but I just cannot change the language of the sidebars, header and footer. How do I solve this? What can I do so I just have my whole page translated when clicking the button?
Unfortunately I just cannot use any plug-ins, I have to do it completely manually.
to directly change page link to english and spanish mains pages use <base> tag ( see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base )
for texts just add / remove a noDisplay class as appropriate
to keep Language selection for Every page and next connection use LocalStorage -> https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
sample code (I use it in a closure Object)
this is just a start code, you have to complete it for your own app
const LangChooser = (function()
{
const cLangElm = document.querySelectorAll('.cLang')
, langList = ['EN', 'SP'] // english or spanish pages pages
, defLang = 'EN'
, obj_ret = {}
, MemoLang = 'LangChoosed' // name value in local storage
;
let idxLang = langList.indexOf(defLang)
;
function LangdSet(lang)
{
localStorage.setItem(MemoLang, lang )
;
cLangElm.forEach(Elm=>
{
if (Elm.classList.contains(lang))
{ Elm.classList.remove('noDisplay')}
else
{ Elm.classList.add('noDisplay')}
})
}
obj_ret.LangInit = function()
{
let currentLang = localStorage.getItem(MemoLang)
;
if (!currentLang)
{
currentLang = defLang
}
idxLang = langList.indexOf(currentLang)
LangdSet(currentLang)
}
obj_ret.setLang = function(lang)
{
let idx = langList.indexOf(lang)
if (idx<0)
{
throw `${lang} language doesn't exist here !`;
}
idxLang = idx;
LangdSet(lang)
}
obj_ret.toogleNextLang = function()
{
idxLang = ++idxLang %2
LangdSet(langList[idxLang] )
}
obj_ret.getLang = function()
{
return langList[idxLang]
}
return obj_ret
})()
;
function configurePageLang()
{
let currentLang = LangChooser.getLang()
// change bage..
direction.textContent =' base = ' + currentLang
pageLink.href = currentLang + '/'
}
//on load...
LangChooser.LangInit()
configurePageLang()
btLang.onclick=()=>
{
LangChooser.toogleNextLang()
configurePageLang()
}
.noDisplay { display:none }
<base id="pageLink" href="EN/">
<p id="direction"> base = EN </p>
<button id="btLang"> page EN / SP </button>
<p>
a link to page 2
<!-- go to EN/Page2.html or SP/Page2.html -->
</p>
<p class="cLang EN"> This is text in English </p>
<p class="cLang SP noDisplay"> Este es texto en español </p>

Join identical variables with different arrays from multiple external js files in JavaScript

I have made an offline web application:
<!DOCTYPE html>
<html dir="rtl">
<head>
<meta charset="utf-8">
<style><!-- some style here --></style>
<script>
var rqid = location.hash.replace('#','');
var js = Math.ceil(rqid / 100);
var id = rqid - ((js - 1) * 100) - 1;
var tg = document.createElement('script')
tg.src = js + '.js'
tg.type = 'text/javascript'
document.head.appendChild(tg);
window.onload = function load() {
var body='<h1>' + title[id] + '</h1> <article>' + content[id] + '</article>';
document.getElementById("body").innerHTML = body;}
</script>
</head>
<body id='body'>
</body>
</html>
The above is the simplified article.html file, which shows articles stored inside external .js files, each with two variables.
1.js contains
title = ['title of article1','title of article2',...,'title of article100'];
content = ['content of article1','content of article2',...,'content of article100'];
2.js contains
title = ['title of article101','title of article102',...,'title of article200'];
content = ['content of article101','content of article102',...,'content of article200'];
For example, article.html#1 loads 1.js into the html, and then shows article1, and article.html#101 loads 2.js and shows article101.
It works fine, but there's a problem with the search engine I have written for this application. The search engine code is quite bulky. Sharing it here will not be possible.
The problem is the identical variables in the .js files, which are overridden one after one.
<script src="1.js"></script>
<script src="2.js"></script>
<script src="3.js"></script>
So, search is done only in 3.js.
The question is: Is it possible to dynamically join title/content arrays in those .js files and have a unified title/content variable like the following, so the search can be performed in all articles?
title = ['title of article1',...,'title of article200'];
content = ['content of article1',...,'content of article200'];
If it is not possible, simply say no but please do not recommend to restructure the stored data.
I would add that the speed/performance is not a problem, in case it is going to be slow.
Here is a simple example of how you could do this without having to restructure your 1.js, 2.js..
For the purpose of this example I've created a pretend fetch, that can get 1.js, & 2.js, if you have any real URL's to test, we should be able to replace the fetch mock with a real one.
const pretenddata = {
"1.js":
`title = ['title of article1','title of article2','title of article100'];
content = ['content of article1','content of article2','content of article100']`,
"2.js": `title = ['title of article101','title of article102','title of article200'];
content = ['content of article101','content of article102','content of article200'];`
};
//lets create a pretend fetch..
function fetch(url) {
function astext() {
return new Promise((resolve) => {
resolve(pretenddata[url]);
});
}
return new Promise((resolve) => {
resolve({text: astext});
});
}
async function test() {
var combined_title = [];
var combined_content = [];
async function getData(url) {
const r = await(await fetch(url)).text();
var d = new Function(`${r}; return [title, content]`)();
combined_title = combined_title.concat(d[0]);
combined_content = combined_content.concat(d[1]);
}
await Promise.all([
getData("1.js"),
getData("2.js")
]);
console.log(combined_title);
console.log(combined_content);
}
test();
When working with globals across multiple files, it is always a good idea to use some kind of globals structure, that way it is much more explicit as to the fact that the data is, in fact, global, and it makes it much less likely to cause issues with scope pollution.
In your case, you can create a basic object called "globals", which will have a title and content property, just like you were with your global variables. In fact, those actually go on the window object by default, so it works exactly the same - just instead of saying window.title, you can say globals.title, etc. The only difference being that the variables will never be accessed accidentally by default scoping.
window.globals = {};
// file1
(function () {
var title = ['title of article1','title of article2','title of article100'];
var content = ['content of article1','content of article2','content of article100'];
globals.title = globals.title ? globals.title.concat(title) : title;
globals.content = globals.content ? globals.content.concat(content) : content;
})();
// file2
(function () {
var title = ['title of article101','title of article102','title of article200'];
var content = ['content of article101','content of article102','content of article200'];
globals.title = globals.title ? globals.title.concat(title) : title;
globals.content = globals.content ? globals.content.concat(content) : content;
})();
// file3
(function () {
var title = ['title of article201','title of article202','title of article300'];
var content = ['content of article201','content of article202','content of article300'];
globals.title = globals.title ? globals.title.concat(title) : title;
globals.content = globals.content ? globals.content.concat(content) : content;
})();
// final results
console.log(globals.title);
console.log(globals.content);

My JavaScript works as inline code but not as an include file. Any ideas why and how to fix it?

I have this form:
<form id="searchForm" class="search_field" method="get" action="">
...
...
</form>
Then this javascript:
var form = document.getElementById("searchForm");
form.doSearch1.onclick = searchPage;
form.doSearch2.onclick = searchPage;
form.showFeatureChoices.onclick = function( )
{
var cbs = form.featType;
for ( var c = 0; c < cbs.length; ++c )
{
cbs[c].checked = false;
}
document.getElementById("featuresDiv").style.display = "block";
}
function searchPage()
{
var form = document.getElementById("searchForm");
var searchText = form.searchBox.value.replace(/-/g,"");
form.searchBox.value = searchText;
if (searchText != "")
{
// collect features to search for:
var features = [ ];
var featTypes = form.featType;
for ( var f = 0; f < featTypes.length; ++f )
{
if ( featTypes[f].checked ) features.push( featTypes[f].value );
}
featureList = "'" + features.join("','") + "'";
searchMsg("Searching for '" + searchText + "' ...");
// startStatusUpdate(1000);
// findTask.execute(findParams, showResults);
var accord = dijit.byId("accordianContainer");
var resultsPane = dijit.byId("resultsPane");
accord.selectChild(resultsPane,true);
doSearch( searchText, featureList );
}
else
{
searchMsg("No search criteria entered, enter search text");
}
}
If I embed this code in same file as the <form..., it works fine.
If however, I have this js in another file and use as include file:
<script type="text/javascript" src="Views/JS/main.js"></script>
I get following error: "Object required" and it points to these lines:
form.doSearch1.onclick = searchPage;
form.doSearch2.onclick = searchPage;
Any ideas how to fix this?
Just a bit more info, the js code shown above in a file called main.js which is in a folder called JS and Js is in a folder called Views. The
Thanks a lot in advance
When you include the JavaScript code in the same page, where is it in relation to the form element? (Before or after it?) How about when you reference the external JavaScript file?
I'm guessing that in the former case the code is at the end of the file, while in the latter case the script reference tag is at the beginning?
If that's true then what's happening is this code is being executed before the DOM is ready:
var form = document.getElementById("searchForm");
form.doSearch1.onclick = searchPage;
form.doSearch2.onclick = searchPage;
If the form tag hasn't been rendered to the DOM yet then that first line won't find anything, and the subsequent lines will fail as a result. One approach is to put the script reference tags at the end, but that seems like a hack to me. Sometimes there are good reasons to keep them in the page header, not the least of which is cleaner management of the code in many cases. There are other ways to hold off on executing JavaScript code until the DOM is ready.

Categories