Client-side translation does not work in CKAN - internationalization

I am having issues with translating client-side text in CKAN. My site is in french, so here is the problem:
- if I click on the green button "S'abonner" from the left, it should change the button to a red one and show the text "Se désabonner", but instead, it shows me "Unfollow", like in the photos:
And if I click it again it shows me "Follow" (instead of "S'abonner"). So this is a problem on the client side. Normally, when you generate text on the server side you write in the templates _('msgid present in pofile'), but, on the client side, it uses the result from the AJAX call to "/api/i18n/{language}".
I did some digging and it seems that the client-side translation uses the result from the AJAX call to "/api/i18n/fr", but all I get is a json object:
{
"": {
"domain": "ckan",
"lang": "fr",
"plural-forms": "nplurals=2; plural=(n > 1)"
}
}
But, if I look at the ckan demo website, (http://demo.ckan.org/api/i18n/fr), I get a long JSON file, that contains all the translations.
I managed to discover from where this Ajax call is done, apparently it comes from : "src/ckan/ckan/public/base/javascript/client.js", at the function:
getLocaleData: function (locale, success, error) {
var url = this.url('/api/i18n/' + (locale || ''));
return jQuery.getJSON(url).then(success, error);
}
If I replace
var url = this.url('/api/i18n/' + (locale || ''));
with
var url = this.url('http://demo.ckan.org/api/i18n/fr')
the problem is solved, because I get the translations in the json object.
My question is how I can get the right data to be generated, is there a parameter to put in production.ini? Unfortunately, the documentation in CKAN is really poor so I have no leads on this. Does anybody have a clue?
Thanks!

I suspect that you might be running an unreleased branch of CKAN (eg master), so the Javascript translations have not been built.
This is done with the following command:
paster front-end-build -c config_file.ini
Just run this command and the translations should come up fine.
On the main repository this is only done just before releases to avoid complicating the git history.
Check for instance this site running the latest master branch, but on which the front end is built every night:
http://master.ckan.org/fr/dataset/world-countries

Related

Cypress: Switching from cy.route() to cy.intercept()

It seems that most people I read about experence zero trouble with this. I, on the other hand, have a test suite which someone else wrote, in which I'm trying to replace route() with intercept(). The API intercepts are done to handle button clicks etc., and about 99.9% percent of them fails if I just replace it. So, there's obviously some syntax in/use of intercept() I've not found a description for.
Example:
This works:
cy.route('POST', getApiPrefix() + '/prosjektfinansiering/'+ pfId +'/eiendom', result);
This does not work. The button click is not executed:
cy.intercept('POST', getApiPrefix() + '/prosjektfinansiering/'+ pfId +'/eiendom', result);
I've tried adding '**' in front of "/prosjekt...", and I've tried removing 'POST', with no luck.
Any ideas? I'll gladly post more info if necessary.
UPDATE:
Futher attempts:
Getting some hints here and there, it seems that this is a more correct way of using intercept():
return cy.intercept('POST', getApiPrefix() + '/prosjektfinansiering/'+ pfId +'/eiendom', {
body: result
});
This doesn't work, either.
The variables result in these examples is an object describing what is sent back to the frontend of the POST-request in the route matches the api path.
For troubleshooting, I can see that when using intercept(), there is ONE route that is not working when using intercept (the bottom one in the picture). However, I cannot for the life of me see why, and how the route match can be written differently?
Most likely, you're mixing the old use of cy.route() and cy.server(). In my experience, those two won't work well together. It's easier when you're starting fresh with just cy.intercept().
Your update is correct too; You have to encapsulate the return value you want mocked in {body: value}.
from what I am seeing in your circled screenshot, the API is not called after you try to intercept it. (the count under # column is -)
You need to track when the API is to be called and ensure you intercept before the call is made. Cypres can help you with this. You can go through the run steps in the cypress window.
You could also share this if you don't mind.
If you are 100% certain the button makes the call. Steps should be:
cy.intercept()
cy.get('button').click()
In the cypress window, right after the click, you should see the API being called.

Google sheets IMPORTXML fails for ASX data

I am trying to extract the "Forward Dividend & Yield" value from https://finance.yahoo.com/ for multiple companies in different markets, into Google Sheets.
This is successful:
=IMPORTXML("https://finance.yahoo.com/quote/WBS", "//*[#id='quote-summary']/div[2]/table/tbody/tr[6]/td[2]")
But this fails with #N/A:
=IMPORTXML("https://finance.yahoo.com/quote/CBA.AX", "//*[#id='quote-summary']/div[2]/table/tbody/tr[6]/td[2]")
I cannot work out what needs to be different for ASX ticker codes, why does CBA.AX cause a problem?
Huge thanks for any help
When I tested the formula of =IMPORTXML("https://finance.yahoo.com/quote/CBA.AX", "//*"), an error of Error Resource at url not found. occurred. I thought that this might be the reason of your issue.
But, fortunately, when I try to retrieve the HTML from the same URL using Google Apps Script, the HTML could be retrieved. So, in this answer, I would like to propose to retrieve the value using the custom function created by Google Apps Script. The sample script is as follows.
Sample script:
Please copy and paste the following script to the script editor of Google Spreadsheet and save it. And, please put a formula of =SAMPLE("https://finance.yahoo.com/quote/CBA.AX") to a cell. By this, the value is retrieved.
function SAMPLE(url) {
const res = UrlFetchApp.fetch(url).getContentText().match(/DIVIDEND_AND_YIELD-value.+?>(.+?)</);
return res && res.length > 1 ? res[1] : "No value";
}
Result:
When above script is used, the following result is obtained.
Note:
When this script is used, you can also use =SAMPLE("https://finance.yahoo.com/quote/WBS").
In this case, when the HTML structure of the URL is changed, this script might not be able to be used. I think that this situation is the same with IMPORTXML and the xpath. So please be careful this.
References:
Custom Functions in Google Sheets
Class UrlFetchApp
An other solution is to decode the json contained in the source of the web page. Of course you can't use importxml since the web page is built on your side by javascript and not on server's side. You can access data by this way and get a lot of informations
var source = UrlFetchApp.fetch(url).getContentText()
var jsonString = source.match(/(?<=root.App.main = ).*(?=}}}})/g) + '}}}}'
i.e. for what you are looking for you can use
function trailingAnnualDividendRate(){
var url='https://finance.yahoo.com/quote/CBA.AX'
var source = UrlFetchApp.fetch(url).getContentText()
var jsonString = source.match(/(?<=root.App.main = ).*(?=}}}})/g) + '}}}}'
var data = JSON.parse(jsonString)
var dividendRate = data.context.dispatcher.stores.QuoteSummaryStore.summaryDetail.trailingAnnualDividendRate.raw
Logger.log(dividendRate)
}

Creating a simple, basic page object in Nightwatch.js

Ok, so I've read up on the use of page_objects in nightwatch.js, but I'm still getting issues with it (which I'm convinced is due to something obvious and/or simple).
Using http://nightwatchjs.org/guide/#page-objects as the guide, I added the the file cookieremoval.js in my page_objects folder.
module.exports = {
elements: {
removeCookies: {
selector: '.banner_continue--2NyXA'
}
}
}
In my nightwatch.conf.js file I have;
page_objects_path: "tests/functional/config/page_objects",
And in my test script I have;
module.exports = {
"/cars/road-tax redirects to /car-tax/ ": browser => {
browser.url(browser.launch_url + browser.globals.carReviews)
.assert.urlEquals(browser.launchUrl + "/car-reviews/")
.waitForElementPresent('#cookieRemove', 3000)
.click('#cookieRemove')
.end();
},
};
However, when I run the test, I keep getting an error reading;
Timed out while waiting for element <#cookieRemove>
Any ideas why this is not working?
Many thanks
First of all, you never instantiated your page object. You're asking the browser object to search for an unknown element, that's why it's timing out. Your code should look something like this in your test script: var cookieRemoval = browser.page.cookieremoval(); then use this object to access those variables and functions in your page object. For example, if you wanted to access the remove cookie element, then you would do this cookieRemoval.click('#removeCookies');.
Secondly, you will have to know when to use the global browser object and when to use your page object. If you need to access something within your page object, obviously use the page object to call a function or access a variable. Otherwise, browser won't know the element you're looking for exists. Hope this help you out, I would definitely spend some more time learning about objects and specifically how they're used in nightwatch.js.

Conflict between EJS and Marionette

For my single page application, the page is delivered by node-express-ejs on the server side to Maironette-Backbone based client on the browser. Unfortunately, both EJS and Marionette use the syntax "<%= var %>" for plugging in computed values. My page has some values that need to be plugged in by the server and some that will be computed by the client. So I need something like the following snippet to work.
<html> .....
Server Computed = $ <%=serverComputed%>
Client Computed = $ <%=clientComputed%>
....</html>
And my routes.js on the server would have something like,
res.render('test', { serverComputed: '5000' });
But, EJS throws
ReferenceError: .../test.ejs:17
.....
clientComputed is not defined
The following does not help either
res.render('test', { serverComputed: '5000', clientComputed: '<%= clientComputed %>' });
since it as expected, ends up as
$lt:%= clientComputed %>
Is there a way (a market, a processor directive etc) to tell EJS processor to not process a part of the file?
Is there any other way to work around this conflict?
Thanks,
Hemant
Found the solution.
EJS does allow defining your own tags by setting them in the options. So far as I can tell, this is not documented. I only found it by going through the source code. Anyway, the following option setting would avoid conflict with Marionette open-close tags.
On server side, routes.js can specify options like this.
res.render('test', { open: '{{', close: '}}', serverComputed: '5000' });
In the ejs file, now you can have different markups for server-computed and client-computed variables, like so.
Server Computed = $ {{=serverComputed}}
Client Computed = $ <%=clientComputed%>
EJS processor will not process the "<%=clientComputed%>" part.
Hemant

MooTools AJAX Request on unload

i'm trying to lock a row in a db-table when a user is editing the entry.
So there's a field in the table lockthat I set 1 on page load with php.
Then I was trying to unlock the entry (set it 0) when the page is unloaded.
This is my approach. It works fine in IE but not in Firefox, Chrome etc....
The window.onbeforeunload works in all browsers, I tested that.
They just don't do the Request
BUT
if I simple put an alert after req.send(); it works in some browsers but not safari or chrome. So I tried putting something else after it just so that's there's other stuff to do after the request but it doesn't work.
function test() {
var req = new Request({
url: 'inc/ajax/unlock_table.php?unlock_table=regswimmer&unlock_id=',
});
req.send();
alert('bla'); // ONLY WORKS WITH THIS !?!?!?
}
window.onbeforeunload = test;
i've already tried different ways to do the request but nothing seems to work. And the request itself works, just not in this constellation.
ANY help would be appreciated!
Thanks
the request is asynchronous by default. this means it will fork it and not care of the complete, which may or may not come (have time to finish). by placing the alert there you ensure that there is sufficient time for the request to complete.
basically, you may be better off trying one of these things:
add async: false to the request object options. this will ensure the request's completion before moving away.
use an image instead like a tracking pixel.
move over to method: "get" which is a bit faster as it does not contain extra headers and cookie info, may complete better (revert to this if async is delayed too much)
you can do the image like so (will also be $_GET)
new Element("img", {
src: "inc/ajax/unlock_table.php?unlock_table=regswimmer&unlock_id=" + someid + "&seed=" + $random(0, 100000),
styles: {
display: "none"
}
}).inject(document.body);
finally, use window.addEvent("beforeunload", test); or you may mess up mootools' internal garbage collection

Resources