How to translate only text in formatted HTML code using Google Apps Script? - google-apps-script

I have been trying to translate text from HTML code. Here is an example:
var s = '<span>X stopped the</span><icon></icon><subject>breakout session</subject>'
When I try =GOOGLETRANSLATE(s,"en","fi") in Google Sheet, it also changes the tags formatting and translates tags into simple text. Whereas the translation should be only for X stopped the breakout session. But that is not the case.
Then I tried this function:
function TransLang(string){
return LanguageApp.translate(string,'en', 'fi', {contentType: 'text'});
}
This function worked well (for some time), but after that I got an error
Service invoked too many times in one day.
So I am stuck here. Is there any way that we can translate simple text of html code without translating/messing with HTML tags? Is there any regex that can avoid tags and translate all the other simple text?
I hope I am able to state my problem clearly. Please guide me if you have any suggestions. Thank you

Is the text you want always inside a single <span>? Or could there be more than one span or other element types?
This works for extracting the inner text from a single <span>:
function getSpanText() {
let s = '<span>X stopped the</span><icon></icon><subject>breakout session</subject>';
var text = s.match("(?<=<span>).+(?=<\/span>)")[0]
Logger.log(text);
return text
}

So, after a lot of digging, I have been able to find what I was looking for.
function Translator(S){
var sourceLang = "en";
var targetLang = "fi";
var url =
'https://translate.googleapis.com/translate_a/single?client=gtx&sl='
+
sourceLang +
'&tl=' +
targetLang +
'&dt=t&q=' +
encodeURI(S);
var result = JSON.parse(UrlFetchApp.fetch(url).getContentText());
return result[0][0][0];
}
This simple function calls Google translate Api and extracts the result from there. The best thing is you do not have to worry about the tags, as they are not translated by Google, so just the simple text is translated. There is just one limitation in the solution that Api calls are limited, so you can not make more than 5000 calls/day.

Why not using LanguageApp.translate as a custom JS-Function (Extensions >> AppScripts)?!
var spanish = LanguageApp.translate('This is a <strong>test</strong>',
'en', 'es', {contentType: 'html'});
// The code will generate "Esta es una <strong>prueba</strong>".
LanguageApp.translate (apidoc) accepts as fourth option a contentType, which can be text or html.
For huge tables be aware that there are daily limits (quotas)!

Related

How to make new document with JXA?

How to make new document and close? Need this to workaround apple automation buggy insanity. What I try is this:
var app = Application('Keynote')
var doc = app.make(new document) // How to write this correctly?
doc.close({saving: 'no'})
AppleScript and JavaScript syntax is completely different. You have to think more in terms of JavaScript
For example JXA doesn't understand make(new).
You have to create an instance from the class name (note the uppercase spelling) and then call make().
Actually the var keywords and the trailing semicolons are not needed.
keynote = Application('Keynote')
keynote.activate()
newDocument = keynote.Document().make()
Within the parentheses of Document() you can pass parameters similar to AppleScript’s with properties for example
newDocument = keynote.Document({
documentTheme: keynote.themes["Gradient"],
width:1920,
height:1080
})
AppleScript’s multiple word properties like document theme are written as one camelCased word.
To close the frontmost document write
keynote.documents[0].close()

Preserve highlight when copy from Ace Editor

I am using Ace Editor in my web app. Wonder if it's possible to copy the text inside Ace Editor to clipboard with highlight. With default configurations, if I copy the selected text in Ace Editor to clipboard, it seems that only text content is copied with no html styles.
Thanks a lot for your help!
Unfortunately there is no api for this. you'll need to modify https://github.com/ajaxorg/ace/blob/v1.2.5/lib/ace/keyboard/textinput.js#L290 to also set text/html mime type to some html, rendered similar to https://github.com/ajaxorg/ace/blob/v1.2.5/lib/ace/layer/text.js#L442.
Also you'll need to include the css for the theme in the copied html
I know this is late, but this might be helpful for someone like me who stumbled upon this problem this late.
The basic idea is to get the text that is being copied and use Ace's tokenizer to generate HTML from it:
Add an event listener on the copy/cut event on the editor's container.
You can use clipboard object in event to get the data currently being copied: event.clipboardData?.getData('text/plain')
Rest steps are in code below
// get current tokenizer
const tokenizer = aceSession.getMode().getTokenizer();
// get `Text` object from ace , this will help in generating HTML
const Text = ace.require('ace/layer/text').Text;
// create a wrapper div, all your resultant HTML will come inside this
// also this will contain the basic HTML required to initialize the editor
const root = document.createElement('div');
// this is the main magic object
const rootText = new Text(root);
lines.forEach(line => {
// this converts your text to tokens
const tokens = tokenizer.getLineTokens(line, 'start') as any;
const leadingSpacesCount = (line.match(/^\s*/) || [])[0].length;
const lineGroupEl = document.createElement('div');
lineGroupEl.className = 'ace_line_group';
const lineEl = document.createElement('div');
lineEl.className = 'ace_line';
const spaceSpan = document.createElement('span');
if (tokens && tokens.tokens.length) {
//////////////////////////////////////////////////////
// Magic Happens here, this line is responsible for converting our tokens to HTML elements
rootText.$renderSimpleLine(lineEl, tokens.tokens);
//////////////////////////////////////////////////////
// Leading spaces do not get translated to HTML, add them separately
spaceSpan.innerHTML = ' '.repeat(leadingSpacesCount);
lineEl.insertBefore(spaceSpan, lineEl.children[0]);
} else {
spaceSpan.innerHTML = ' ';
lineEl.appendChild(spaceSpan);
}
lineGroupEl.appendChild(lineEl);
// `root` has a wrapper div, inside which our main div (with class "ace_layer ace_text-layer") lies
root.children[0].appendChild(lineGroupEl);
});
return root.innerHTML;
Now finally, in your eventlistener you can wrap this with any div to give your own custom color to it, and put it to clipboardData with text\html mime type:
event.clipboardData?.setData('text/html', htmlContent);

GoogleAppsScript: How do I trim strings after parsing HTML?

What I'm trying to do is parse & extract the movies title, without all the HTML gunk, from the webpage which will eventually get saved into a spreadsheet. My code:
function myFunction() {
var url = UrlFetchApp.fetch("http://boxofficemojo.com/movies/?id=clashofthetitans2.htm")
var doc = url.getContentText()
var patt1 = doc.match(/<font face\=\"Verdana\"\ssize\=\"6\"><b>.*?<\/b>/i);
//var cleaned = patt1.replace(/^<font face\=\"Verdana\" size\=\"6\"><b>/,"");
//Logger.log(cleaned); Didn't work, get "cannot find function in object" error.
//so tried making a function below:
String.trim = function() {
return this.replace(/^\W<font face\=\"Verdana\"\ssize\=\"6\"><b>/,""); }
Logger.log(patt1.trim());
}
I'm very new to all of this (programming and GoogleScripting in general) I've been referencing w3school.com's JavaScript section but many things on there just don't work with Google Scripts. I'm just not sure what's missing here, is my RegEx wrong? Is there a better/faster way to extract this data instead of RegEx? Any help would be great, Thanks for reading!
While trying to parse information out of HTML that's not under your control is always a bit of a challenge, there is a way you could make this easier on yourself.
I noticed that the title element of each movie page also contains the movie title, like this:
<title>Wrath of the Titans (2012) - Box Office Mojo</title>
You might have more success parsing the title out of this, as it is probably more stable.
var url = UrlFetchApp.fetch("http://boxofficemojo.com/movies/?id=clashofthetitans2.htm");
var doc = url.getContentText();
var match = content.match(/<title>(.+) \([0-9]{4}\) -/);
Logger.log("Movie title is " + match[1]);

Spotify List objects created from localStorage data come up blank

I'm working on a Spotify app and trying to create a views.List object from some stored information in our database. On initial load, a POST is made to get the necessary info. I store this in localstorage so each subsequent request can avoid hitting the database and retrieve the object locally. What's happening though is the List objects I create from localstorage data come up blank, while the POST requests work just fine.
Here is the snippet I'm using to create the list:
var temp_playlist = models.Playlist.fromURI(playlist.uri);
var tempList = new views.List(temp_playlist, function (track) {
return new views.Track(track, views.Track.FIELD.STAR |
views.Track.FIELD.NAME |
views.Track.FIELD.ARTIST |
views.Track.FIELD.DURATION);
});
document.getElementById("tracklist").appendChild(tempList.node);
playlist.uri in the first line is what I'm retrieving either from a POST or from localstorage. The resulting views.List object (tempList) looks identical in both cases except for tempList.node. The one retrieved from localstorage shows these values for innerHTML, innerText, outerHTML, and outerText in console.log:
innerHTML: "<div style="height: 400px; "></div>"
innerText: ""
outerHTML: "<div style="height: 400px; "></div>"
outerText: ""
Whereas the one retrieved via POST has the full data:
innerHTML: "<div style="height: 400px; "><a href="spotify:track:07CnMloaACYeFpwgZ9ihfg" class="sp-item sp-track sp-track-availability-0" title="Boss On The Boat by Tosca" data-itemindex="0" data-viewindex="0" style="-webkit-transform: translateY(0px); ">....
innerText: "3Boss On The BoatTosca6:082....
and so forth..
Any help would be greatly appreciated
Solved this.
I am using hide() and show() to render the tabs in my app. I was constructing the tracklist and then show()ing the div which led to a blank tracklist. If I simply show() the div and then construct the tracklist it works fine.
The reason (I think) it was working for POSTs is because the tracklist was retrieved from the database and the slightly longer loading time probably meant the tracklist was constructed after the div's show() executed. With localStorage I guess the tracklist was constructed before the div was even shown, leading to the error.
Using, the local storage, I did it this way :
sp = getSpotifyApi(1);
var m = sp.require("sp://import/scripts/api/models");
var v = sp.require("sp://import/scripts/api/views");
var pl;
pl = m.Playlist.fromURI(uri);
var player = new v.Player();
player.track = pl.get(0);
player.context = pl;
var list = new v.List(pl);
XXXXX.append($(list.node));
Hope, it will help, as it's working for me
I think I've actually managed to solve this and I think it's bulletproof.
Basically I was trying to solve this by trying to convince the API that it needed to redraw the playlist by hiding things/scrolling things/moving things which worked occasionally but never consistently. It never occurred to me to change the playlist itself. Or at least make the API think the playlist has changed.
You can do so by firing an event on the Playlist object.
var models = sp.require('$api/models');
...
// playlist is your Playlist object. Usually retrieved from models.Playlist.fromURI
playlist.notify(models.EVENT.CHANGE, playlist);
These are just standard Spotify functions and the list updates because it thinks something has changed in the playlist. Hope this helps someone!

Sending values through links

Here is the situation: I have 2 pages.
What I want is to have a number of text links(<a href="">) on page 1 all directing to page 2, but I want each link to send a different value.
On page 2 I want to show that value like this:
Hello you clicked {value}
Another point to take into account is that I can't use any php in this situation, just html.
Can you use any scripting? Something like Javascript. If you can, then pass the values along in the query string (just add a "?ValueName=Value") to the end of your links. Then on the target page retrieve the query string value. The following site shows how to parse it out: Parsing the Query String.
Here's the Javascript code you would need:
var qs = new Querystring();
var v1 = qs.get("ValueName")
From there you should be able to work with the passed value.
Javascript can get it. Say, you're trying to get the querystring value from this url: http://foo.com/default.html?foo=bar
var tabvalue = getQueryVariable("foo");
function getQueryVariable(variable)
{
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++)
{
var pair = vars[i].split("=");
if (pair[0] == variable)
{
return pair[1];
}
}
}
** Not 100% certain if my JS code here is correct, as I didn't test it.
You might be able to accomplish this using HTML Anchors.
http://www.w3schools.com/HTML/html_links.asp
Append your data to the HREF tag of your links ad use javascript on second page to parse the URL and display wathever you want
http://java-programming.suite101.com/article.cfm/how_to_get_url_parts_in_javascript
It's not clean, but it should work.
Use document.location.search and split()
http://www.example.com/example.html?argument=value
var queryString = document.location.search();
var parts = queryString.split('=');
document.write(parts[0]); // The argument name
document.write(parts[1]); // The value
Hope it helps
Well this is pretty basic with javascript, but if you want more of this and more advanced stuff you should really look into php for instance. Using php it's easy to get variables from one page to another, here's an example:
the url:
localhost/index.php?myvar=Hello World
You can then access myvar in index.php using this bit of code:
$myvar =$_GET['myvar'];
Ok thanks for all your replies, i'll take a look if i can find a way to use the scripts.
It's really annoying since i have to work around a CMS, because in the CMS, all pages are created with a Wysiwyg editor which tend to filter out unrecognized tags/scripts.
Edit: Ok it seems that the damn wysiwyg editor only recognizes html tags... (as expected)
Using php
<?
$passthis = "See you on the other side";
echo '<form action="whereyouwantittogo.php" target="_blank" method="post">'.
'<input type="text" name="passthis1" value="'.
$passthis .' " /> '.
'<button type="Submit" value="Submit" >Submit</button>'.
'</form>';
?>
The script for the page you would like to pass the info to:
<?
$thispassed = $_POST['passthis1'];
echo '<textarea>'. $thispassed .'</textarea>';
echo $thispassed;
?>
Use this two codes on seperate pages with the latter at whereyouwantittogo.php and you should be in business.