I'm trying to make a translation in JavaScript on a Drupal site. I'm using the js function Drupal.t(). Everything seems to work; Drupal is loaded, the function gets called, placeholders get replaced, but the translation doesn't happen. The words stay in English, and the words aren't added to the translations database. Does anybody know why this happens and how to get solve it?
I know your post is rather old, but my answer might help others.
I've noticed that Drupal.locale.strings doesn't get populated with the JavaScript calls.
So what I usually do is simply create a portion of PHP code that does this work on the server side. You can do it anywhere in your PHP code. But the best is to do it in the module you are coding. It will then be easier to export it with the Potx module so that you can have your strings in some *.po files for a later use of your module.
If you are in a hurry, you can simply do it in the body of a dummy node (just do a "preview") with the PHP input format:
<?php
print t('Example : %variable', array('%variable' => 'test'));
?>
Once this has been done, you should be able to find your strings and translate them in the admin page.
To regenerate the JavaScript file, you'll have to clear all your cache (with Devel or by visiting the modules page).
Not sure about the javascript part but I've used the t funciton a lot. If you want the strings to show up in the translation table you have to load the corresponding page in two different languages before it will allow you to translate them. Hope that helps.
The Drupal.t() function is very small, so I bet we can just dissect it here.
function (str, args) {
// Fetch the localized version of the string.
if (Drupal.locale.strings && Drupal.locale.strings[str]) {
str = Drupal.locale.strings[str];
}
if (args) {
// Transform arguments before inserting them
for (var key in args) {
switch (key.charAt(0)) {
// Escaped only
case '#':
args[key] = Drupal.checkPlain(args[key]);
break;
// Pass-through
case '!':
break;
// Escaped and placeholder
case '%':
default:
args[key] = Drupal.theme('placeholder', args[key]);
break;
}
str = str.replace(key, args[key]);
}
}
return str;
}
So you can see that it checks Drupal.locale.strings to find the translatable strings for the current locale. Can you pop open a console on your Drupal site and type Drupal.locale and see what it spits out?
In Drupal, to add a new language, you must first enable the Locale module. Have you done that?
Next, you have to import your language through the Translate Interface at admin/build/translate. Have you done that?
Here you can see I've imported French and German: http://grimhappy.com/i/ce75ca.png
¿Are you compressing out the js? Check at the performance section of your site.
Clearing the cache should regenerate the js with the right translations now.
Related
This is the HTML code in file 1, which is calling the function. It is linked to javascript
<form id='next' action='file2.html'>
<button id="nextTwo" onclick="nextTwo()">next2</button>
</form>
This is the JS code that receives the function.
function nextTwo(){
document.getElementById('question').innerHTML=question
}
It is searching for the id before the file changes to where the id is.
Every time I press the button that calls the function it gives me:
"TypeError: Cannot set properties of null (setting 'innerHTML')"
This is because it is searching for the id of "question" in file 1, but the id is in file 2. It tries to find the id in file 1, then it switches to file 2, where the id of "question" is.
How do I make it so that is switches to file 2 first, then searches for the id.
Maybe an if statement with a condition, if the file is switched, although I don't know the how to write that.
Thanks for your help.
This is my Js code, how do I place the arrays value into the file 2 using ajax?
let ants;
let question;
let squestion;
function check() //CHECK
{
switch(1){ //different header number is fine but do '' BUT input box will still be there
case 0:
ants = ['calculations']
question=["Element Symbol that has the atomic number of... ","atomic mass of (round to nearest whole number)..."]
squestion=["1. 50","2. 2","3. 20","4. K"]
case 1:
ants = ["0 (all atoms have a charge of 0)","11","11","4","9","Be","8","8","8"]
question=["Sodium has 11 protons and an mass of 23. What is the...","An atom has an atomic# of 4 and 5 neutrons What is the...", "Oxygen has 8 electrons and a mass of 16"]
squestion=["charge","atomic#","#of electrons", "#of protons","Mass","element symbol", "#of protons", "atomic#", "#of neutrons"]
// ants = ["Sn ","He ","Ca ","39 ", "32 ","Sn ","He ","Ca",]
// question=["Element Symbol that has the atomic number of... ","atomic mass of (round to nearest whole number)..."]
// squestion=["1. 50","2. 2","3. 20","4. K"]
break;
case 2:
ants = ["Carbon", "Chlorine", "Bromine",'Br',"Li","Sc","2","8","8" ]
question=["Carbon", "Chlorine", "Bromine", "Helium",'Br',"Li","Sc" ]
squestion=[]
}
There is a better way to go about this.
By design, forms do not communicate two-way. They take the data entered by the user and carry it over to the processing file (defined by the action= parameter on the form tag). The user is navigated away from the first webpage, and the view changes to that processing file - and it isn't supposed to go back to the first file again. Forms are very basic, primitive constructs.
This is why forms have been almost entirely replaced by AJAX. AJAX is a very simple JavaScript construct (made even simpler via jQuery - TANGENT: although jQuery is no longer recommended because modern JavaScript has made the process much easier - but the jQuery $.ajax() method still works fine and there is tons of info about how to use it).
AJAX allows you to send data from a web page to a back-end (server-side) file that receives any data you send it (optional), does something (optional), and returns new data (optional). The page the user is on need not change, blink or flash. New data received from the server-side file can be received and actively used before returning control to the user... So this sounds like exactly what you need it to do.
The back-end (AJAX) processing file is written in a server-side language (PHP, NodeJS, ASP.Net, Python, etc - PHP is a very popular one for AJAX), but you did not specify which one you wish to use, which is likely why no one responded to your question sooner.
Here are some references that might help. I chose jQuery examples because the AJAX code block $.ajax( //code goes here ).done() is very simple. To do AJAX in pure JavaScript, look for information regarding the Fetch API (newest), and XmlHTTPRequest (older).
Simple jQuery example
Ajax explained with jQuery
Another simple example with explanation
Here is a pure javascript video tutorial (5 mins)
After reviewing the examples, you can construct a basic AJAX test on your side and, if you have any trouble with it, ask another question specifying which language you are trying to do this with, and showing your code so far.
Some URLs in my single-page-app (SPA) contain sensitive information like an access token, user information, etc.
Examples:
/callback#access_token=HBVYTU2Rugv3gUbvgIUY
/?email=username#example.com
I see that hotjar allows suppressing DOM elements and images from tracked data. Is it possible to hide params in URL or at least disable tracking for some pages?
Since you are saying that it is your SPA, you might solve the problem by switching from GET requests (which have the parameters inside the URL) to POST requests. I do not know hotjar, but if you tell the tracking service to analyze URLs only, that would be an option worth considering.
Another option frequently used is to obfuscate your parameters in the URL, see e.g. Best way to obfuscate an e-mail address on a website? However, that is never a really safe solution for sensitive data, since the de-ciphering step is too easy, in particular if your man-in-the-middle has all requests ever send to your SPA.
Edit. I just found in the Hotjar allows RegEx. Assuming you could enter a regular expression of URL-parts to exclude.
The general syntax /foo/bar/ means that foo should be replaced by bar, in our case, we want to delete the given snippet, that why it is /foo//.
For the given case of the access token, the regular expression would be
/callback#access_token=[a-zA-Z0-9]{15}//
and respectively for the email part of the URL
/\?email=(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")#(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])//
This second RegEx partially taken from How to validate an email address using a regular expression?
It seems to me that it's reasonable to assume that tracking scripts will try to access window.location.href or similar to get the current url which they will store.
So a possible solution would be create a dynamic scope which has a different value for window.location.href (with all sensitive info filtered out)
This is how it might work:
// get the tracker script as a string, so you can eval it in a dynamic scope
let trackerScript = 'console.log("Tracked url:", window.location.href)';
// now lets lock it up
function trackerJail(){
let window = {
location: {
// put your filtered url here
href: "not so fast mr.bond"
}
}
eval(String(trackerScript))
}
trackerJail()
If the tracking snippet is wrapped in a function it might be possible to create a dynamic scope for it without running eval by overriding it's prototype instead. But I'm not sure you can count on tracker scripts being wrapped in a neat function you can modify.
Also, there are a couple more ways the script might try to access the URL, so make sure to cover all the exits
If you control the page and order of scripts, you could read the data from the url then delete it before anything else can get to it.
proofOfConcept.html
<script id="firstThingToLoad.js">
console.log(window.location.href);
const keyRegex = /key=[^&]*/;
const key = window.location.href.match(keyRegex);
console.log("I have key", key);
const href = window.location.href.replace(keyRegex, "");
history.replaceState({}, "", href);
</script>
<script id="someSnoopyCode.js">
console.log("I'm snooping: ", window.location.href);
</script>
<body>
Link to private
</body>
Of course the Link to private should not exist as is. Also, this does break refresh and most navigation in general, though there are ways to catch and save that.
I have a comments section on a webpage (similar to like on SO) where people can leave text but also links. It works using a standard textfield which does not allow HTML to be included. There is no formatting options etc.
Because no HTML is allowed, I need to parse links (basically text that begins with http or www) and then wrap it in an <a> tag.
To do this on the server would mean using something like JSoup to parse the text and then do the wrapping before inserting it with the rest of the comment text into my DB.
Alternatively, I was thikning that JQuery could scan ALL the comments on the page and wrap anything beginning with a http or www with the <a> tag.
Which one is the correct/better/more efficient method? I have a hunch that the JQuery way will cause some page slowdowns because its updating the DOM constantly on the fly but would like some confirmation from an expert!
When you consider you might at some point want to parse markdown or replace emoticons with images etc., thinking about the performance impact is a good decision.
Usually, you have 3 options:
1. Transform hyperlinks in the backend
I'll assume PHP here, but the principle stays the same:
function renderComment($comment) {
$commentHtml = transformLinks($comment->comment_text);
// render $commentHtml
}
This has the disadvantage of having to replace texts for every comment, on every page request, and is therefore not recommended. On the plus side, compared to option 2, you only have to store the comment text once.
2. Transform hyperlinks in the backend and store them in the database
Assuming PHP and MySQL:
CREATE TABLE comments (id ..., comment_text TEXT, comment_html TEXT, ...)
^^^^^^^^^^^^
function saveComment($createdOrChangedComment) {
$comment->comment_html = transformLinks($comment->comment_text);
saveToDatabase($comment);
}
function renderComment($comment) {
$commentHtml = $comment->comment_html;
// render $commentHtml
}
This means you have to store the comment text twice in the database, once as text, once as html - assuming you want some sort of "edit" button; if not, only saving the html is fine.
While taking up a bit more database space, this solution only fetches the pre-rendered HTML from the database and is therefore better performance-wise.
3. Transforming hyperlinks in the front-end
jQuery(document).ready(function(){
jQuery('.comment').each(function(commentElement) {
// Do magic
transformCommentToHTML(commentElement);
});
});
This should be fine performance-wise when you only have a few hundred comments.
If there are thousands of comments loaded to the DOM at once (which might be a performance hit in itself, but let's ignore that for now), the parsing might be noticable since it happens synchronously and blocks the browser.
In such a case you can parse/replace one pack of comments at a time (e.g. 300) and return the control back to the browser between parsing.
3.b Transform hyperlinks in the frontend, batch-by-batch
jQuery(document).ready(function(){
var $comments = jQuery('.comment');
var currentComment = 0;
(function transformCommentBatch() {
for (var batchLimit = currentComment + 300; currentComment < $comments.length && currentComment < batchLimit; currentComment++) {
// Do magic
transformCommentToHTML($comments[currentComment]);
}
if (currentComment < $comments.length) {
// Don't freeze the browser, continue in the next frame
setTimeout(transformCommentBatch, 1);
}
}());
});
That way, the browser can handle events and does not appear "frozen" to the user, while your first 300 comments in the DOM are transformed first - these are most likely on top of the page and the only ones visible on page load.
I am very new to javascript and apex and am learning on the job so to speak.
Let me start of by describing what I want to achieve:
I'm trying to block the Function keys from running/executing the browser functions (F1 to bring up help, F3 for find, etc). I found the javascript code to block them, but do not know what to do after that.
Eg, when a user presses F1 it should not display help, but execute a process in apex.
Such a process could for example be to save all information on the apex page text fields to the database.
How can i do this?
See my example code: instead of the alert, how would I go about executing a process and how do I go about writing such a process?
<script language="javascript">
function my_onkeydown_handler() {
switch (event.keyCode) {
case 112: // 'F1'
document.onhelp = function() {
return (false);
}
window.onhelp = function() {
return (false);
}
alert("F1");
NewEntry();
break;
}
}
</script>
$(document).keydown(function(e){
if(e.which===112){
console.log('F1ed');
//NewEntry();
return false;
};
});
Safe to use jQuery, it comes with apex
Also see
Disable specific function key using jquery
Which can be translated to a dynamic action (you didn't specify an apex version. Dynamic actions were introduced with version 4.0). Why would you use them? They're very handy in that you can use them to easily leverage javascript without really knowing a lot about it, and they can be seen in the page structure. This way you don't need javascript cluttering about in several portions of your page. Even for more advanced javascript for which there are no pre-defined actions, you can still put your own code in by using 'Execute Javascript'. Again, accessibility and maintainability! Leverage it!
Create a new dynamic action.
Event: Key Down
Selection Type: DOM Object
DOM Object: document
Condition: None
As for the (true) action:
Action: Execute Javascript Code
Code:
var e = this.browserEvent;
switch (e.which) {
case 112: // 'F1'
alert("F1");
return false;
}
Much nicer and cleaner. And better you get comfortable with them now! Read up on them too.
On to the second part:
What i mean is that when eg F1 is pressed it must not display help
but execute a process in apex for example I would like to save all
information on the apex page text fields to the database. How would I
go about it. See my little code, instead of the alert, how would I go
about executing a process and how do I go about writing such a
process?
This makes me wonder (and frown, but just a little). How familiar are you with apex already? No offense, but this is rather basic functionality you're asking about.
Say you have a report and a form page, generated by the wizard. Say you have no weird things such as this javascript on it, but just barebones.
You go from the report to the form page. Values are fetched through a process and the page is rendered. Now you alter some values and submit the page. The submitted values are then processed in the page processing, and pass through the row processing process, which will insert/update/delete data.
If you are unfamiliar with that concept, i strongly recommend you to at least follow through the Oracle® Database 2 Day + Application Express Developer's Guide (Oracle Apex documentation). Many developers just jump in head-first without giving this guide a glance. Don't. This SHORT (and really, what are maybe a couple of hours) guide will teach you some of the very basics of apex!
Important things such as session state and submitting the page are crucial to understanding what it does.
Now, assuming we have a form page with this bit of javascript on it. Pressing F1 to update the values (read: press F1 to submit the page and invoke the row processing to process the submitted values), you can use the apex javascript api's: apex.submit('APPLY') (DOC).
This will submit the page with request APPLY. This value is important. Note that buttons will submit with their name set to request value aswell, and the row processing does different processing based on a list of valid request values.
var e = this.browserEvent;
switch (e.which) {
case 112: // 'F1'
alert("F1");
apex.submit('APPLY');
return false;
}
Further elaboration:
There are also AJAX Callbacks. These are processes on the serverside which can be invoked through a javascript call to the server. These processes are PLSQL-code, and can for example be used to return data to the calling javascript function, and avoid a full page refresh/submit.
It can be used to save data too of course. The data has to be passed to the server, and the process then works with that data. For example, when a field has been changed and you want to immediatly save this to the database but do not want a full page submit. The callback would be a plsql block which performs an update on a table.
Ajax callbacks are very interesting and useful, but i'd advise you to first get a good grip on the basics before tackling this!
Modified code: jsfiddle
<script language="javascript">
document.onkeydown = function (e) {
switch (e.keyCode) {
case 112: // 'F1'
e.preventDefault(); // prevent default behavior.
e.returnValue = false; // for IE to prevent default behavior.
alert("F1");
NewEntry();
return false;
}
}
</script>
I'm reading a boook on XSS attacks, and I've found an example about XSS filter evasion that is a little weird (IMHO).
This is the example text:
Another possible injection point that could exist is when the developer uses unsanitized
user input as part of the generated HTML within a script element. For example:
<script>
var query_string="<XSS>";
somefunction(query_string);
function somefunction {
...
}
</script>
It appears we have access to the inside of the JavaScript function. Let’s try adding some
quotes and see if we can jump out of the encapsulation:
<script>
var query_string="”<XSS>";
somefunction(query_string);
function somefunction {
...
}
<script>
It worked, and also caused a JavaScript error in the process as shown in Figure 3.38.
Let’s try one more time, but instead of trying to inject HTML, let’s use straight
JavaScript. Because we are in a script tag anyway, why not use it to our advantage?
<script>
var query_string="”;alert(“XSS”);//";
somefunction(query_string);
function somefunction {
...
}
</script>
the bold text is what I suppose to be the user input, taken for example from a form.
Back to my question: is there any way that this kind of attack works? For example, suppose somefunction(query_string) is used to run some sql query, and query_string is a product name to search within the database. If inside the search function I create sql_query = 'SELECT name FROM table WHERE name = "'+query_string+'"';, I think there's no way to inject some string with quotes to "jump out of the encapsulation", i.e inputting YAY";alert('hi');// will not change the JS to this:
var query_string = [user input, in this case YAY";alert('hi');//]
function abc(query_string){
sql_query = "select name FROM table WHERE name = 'YAY';
alert('hi');//
....
}
Am I wrong? What do you think? Can you make me a simple example (if it possible) on how this kind of attack can make some sort of damages?
I thought about something like an online shop, but assuming the JS is not used on server side, the only thing this attack can do is modify the query string and then submit it to the server..
Hope you can understand what I wrote and what I'd like to understand, thanks, best regards.
You should only look at the first line. The rest doesn't come into play in this xss example. It's a badly chosen example. So take this much simple example
var first_name="<XSS>";
In this example <xss> is user generated content. So your e.g. php code looks like this
var first_name="<? echo $firstName; ?>";
$firstName is taken from some database or something else, and was generated by the user who typed it into some textfield. Say the user typed: ";alert("XSS");//. PHP will generate the following code
var first_name="";alert("XSS");//";
Pretty printed:
var first_name="";
alert("XSS");
//";
As you see the user was able to run his code alert("XSS") in every other users browser that visited the page. In this example nothing bad will happen except some alert box, but the user might inject some code that gets the cookie info and sends it to some server, so the attacker can steal someone's login session.
This same problem - forgetting to escape user generated content - also applies for creating sql queries, but this isn't related to this example. The creator of this example should have used query_string in his example, as it is obviously confusing.