This commit is contained in:
parent
d871bc40b8
commit
5976edd377
26
css/grid.css
26
css/grid.css
@ -193,3 +193,29 @@ div.data-table-cell-content-numeric > a.data-table-cell-edit {
|
||||
.recline-read-only a.row-header-menu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*************************
|
||||
* WCAG 2.0
|
||||
*************************/
|
||||
|
||||
.wcag_hide {
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:-10000px;
|
||||
width:1px;
|
||||
height:1px;
|
||||
}
|
||||
|
||||
.wcag_hide2 {
|
||||
clip: rect(1px, 1px, 1px, 1px);
|
||||
display: block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.wcag_show_on_focus {
|
||||
font-size: 0 !important;
|
||||
}
|
||||
|
||||
.wcag_show_on_focus:focus {
|
||||
font-size: 1em !important;
|
||||
}
|
||||
|
||||
@ -110,6 +110,7 @@ var createMultiView = function(dataset, state) {
|
||||
model: dataset,
|
||||
el: $el,
|
||||
state: state,
|
||||
locale: 'pl',
|
||||
views: views
|
||||
});
|
||||
return multiView;
|
||||
|
||||
@ -14,6 +14,10 @@
|
||||
{
|
||||
"name": "Max Ogden",
|
||||
"email": "max@maxogden.com"
|
||||
},
|
||||
{
|
||||
"name": "Krzysztof Madejski",
|
||||
"email": "krzysztof.madejski@epf.org.pl"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
|
||||
18
src/i18n/en.js
Normal file
18
src/i18n/en.js
Normal file
@ -0,0 +1,18 @@
|
||||
this.recline = this.recline || {};
|
||||
this.recline.View = this.recline.View || {};
|
||||
this.recline.View.translations = this.recline.View.translations || {};
|
||||
|
||||
this.recline.View.translations['en'] = {
|
||||
'date_required': "A date is required, check field field-date-format",
|
||||
'backend_error': 'There was an error querying the backend',
|
||||
'Distance_km': 'Distance (km)'
|
||||
}
|
||||
|
||||
//
|
||||
//(function(v) {
|
||||
// "use strict";
|
||||
//
|
||||
//
|
||||
//
|
||||
//})(recline.t);
|
||||
//
|
||||
@ -4,7 +4,39 @@ this.recline.View.translations = this.recline.View.translations || {};
|
||||
|
||||
this.recline.View.translations['pl'] = {
|
||||
'Grid': 'Tabela',
|
||||
'Graph': 'Wykres',
|
||||
'Map': 'Mapa',
|
||||
'Timeline': 'Oś czasu',
|
||||
'Search_data': 'Wyszukaj w danych',
|
||||
'Go': 'Szukaj',
|
||||
'Add': 'Dodaj',
|
||||
'Add_row': 'Dodaj wiersz',
|
||||
'Delete_row': 'Usuń wiersz',
|
||||
'Update': 'Zaktualizuj',
|
||||
'Cancel': 'Anuluj',
|
||||
'Filters': 'Filtry',
|
||||
'Add_filter': 'Dodaj filtr',
|
||||
'Remove_this_filter': 'Usuń filtr',
|
||||
'Fields': 'Kolumny',
|
||||
'Field': 'Kolumna',
|
||||
'Filter_type': 'Typ filtra',
|
||||
'Value': 'Wartość',
|
||||
'Range': 'Zakres',
|
||||
'Geo_distance': 'Odległość',
|
||||
'From': 'Od',
|
||||
'To': 'Do',
|
||||
'Longitude': 'Długość geograficzna',
|
||||
'Latitude': 'Szerokość geograficzna',
|
||||
'Distance_km': 'Odległość (km)',
|
||||
'backend_error': 'Wystąpił błąd połączenia z serwerem',
|
||||
'Unknown': '???',
|
||||
'Edit_this_cell': 'Edytuj komórkę',
|
||||
'date_required': "Data jest wymagana: sprawdź kolumnę field-date-format",
|
||||
'Show_field': 'Pokaż kolumnę',
|
||||
'Force_fit_columns': 'Dopasuj kolumny do zawartości',
|
||||
'Expand_and_collapse': 'Rozwiń i zwiń',
|
||||
|
||||
'num_records': '<span class="doc-count">{recordCount}</span> rekordów'
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
//_.extend(my.View, Backbone.I18nView);
|
||||
|
||||
Backbone.I18nView = Backbone.View.extend({
|
||||
defaultLocale: 'en',
|
||||
locale: 'en',
|
||||
initializeI18n: function(locale) {
|
||||
this.locale = locale;
|
||||
@ -24,10 +25,12 @@ Backbone.I18nView = Backbone.View.extend({
|
||||
|
||||
// fallback to key or default message if no translation is defined
|
||||
if (msg == null) {
|
||||
console.warn("Missing locale for " + this.locale + "." + key); // TODO when dfault set and it's default locale then be quiet
|
||||
if (this.locale != this.defaultLocale) {
|
||||
console.warn("Missing locale for " + this.locale + "." + key);
|
||||
}
|
||||
msg = defaultMessage;
|
||||
}
|
||||
if (msg == null) { msg = key; }
|
||||
if (msg == null) { msg = key; } // TODO w domyślnym locale automatycznie usuwaj podkreślenia
|
||||
|
||||
// TODO i18n documentation
|
||||
|
||||
@ -37,36 +40,28 @@ Backbone.I18nView = Backbone.View.extend({
|
||||
|
||||
return formatted;
|
||||
} catch (e) {
|
||||
console.error("Got error while formatting \"" + msg + "\": " + e.message);
|
||||
// todo {{ wywala Message format, trzeba by wyescapować i pwrzywrócic po podmianie
|
||||
var err = "Got error while formatting \"" + msg + "\": " + e.message;
|
||||
if (e.name == 'SyntaxError' && e.found == '{') {
|
||||
err += '. Probably you should change double brackets around variables (Mustache style) to single brackets (Intl style).';
|
||||
}
|
||||
console.error(err);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
// TODO document below error (most probable variables ref hasn't ben changed in template)
|
||||
/* 19:10:40.954 SyntaxError: <template>:1
|
||||
>> <div class="recline-data-explorer"> <div class="alert-messages"></div> <div class="header clearfix"> <div class="navigation"> <div class="btn-group" data-toggle="buttons-radio"> {{#views}} <button href="#{{id}}" data-view="{{id}}" class="btn btn-default">{{label}}</button> {{/views}} </div> </div> <div class="recline-results-info"> {{t.num_records}} -> t + getattr {{#trans.num_records_defmsg}}<span class="doc-count">{{recordCount}}</span> records{{/trans.num_records_defmsg}} -- <span class="doc-count">{{recordCount}}</span> records </div> <div class="menu-right"> <div class="btn-group" data-toggle="buttons-checkbox"> {{#sidebarViews}} <button href="#" data-action="{{id}}" class="btn btn-default">{{label}}</button> {{/sidebarViews}} </div> </div> <div class="query-editor-here" style="display:inline;"></div> </div> <div class="data-view-sidebar"></div> <div class="data-view-container"></div> </div>
|
||||
Expected "0", [1-9] or [^ \t\n\r,.+={}#] but "{" found.1(unknown)
|
||||
*/
|
||||
|
||||
},
|
||||
|
||||
MustacheFormatter: function() {
|
||||
var property_formatter = new Proxy(this, {
|
||||
get(view, name) {
|
||||
return view.t(name);
|
||||
},
|
||||
has(target, prop) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
var section_formatter = new Proxy(this, {
|
||||
var formatter = new Proxy(this, {
|
||||
get(view, name) {
|
||||
return function() {
|
||||
return function (text, render) {
|
||||
var f = function (text, render) {
|
||||
var trans = view.t(name, this, text);
|
||||
return render(text);
|
||||
return render(trans);
|
||||
}
|
||||
f.toString = function() {
|
||||
return view.t(name);
|
||||
}
|
||||
return f;
|
||||
};
|
||||
},
|
||||
has(target, prop) {
|
||||
@ -75,8 +70,7 @@ Expected "0", [1-9] or [^ \t\n\r,.+={}#] but "{" found.1(unknown)
|
||||
});
|
||||
|
||||
return {
|
||||
't': property_formatter,
|
||||
'trans': section_formatter
|
||||
't': formatter,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@ -10,7 +10,7 @@ this.recline.View = this.recline.View || {};
|
||||
// Provides a tabular view on a Dataset.
|
||||
//
|
||||
// Initialize it with a `recline.Model.Dataset`.
|
||||
my.Grid = Backbone.View.extend({
|
||||
my.Grid = Backbone.I18nView.extend({
|
||||
tagName: "div",
|
||||
className: "recline-grid-container",
|
||||
|
||||
@ -113,7 +113,9 @@ my.Grid = Backbone.View.extend({
|
||||
field.set({width: width});
|
||||
}
|
||||
});
|
||||
var htmls = Mustache.render(this.template, this.toTemplateJSON());
|
||||
var tmplData = this.toTemplateJSON();
|
||||
tmplData = _.extend(tmplData, this.MustacheFormatter());
|
||||
var htmls = Mustache.render(this.template, tmplData);
|
||||
this.$el.html(htmls);
|
||||
this.model.records.forEach(function(doc) {
|
||||
var tr = $('<tr />');
|
||||
@ -174,7 +176,7 @@ my.GridRow = Backbone.View.extend({
|
||||
{{#cells}} \
|
||||
<td data-field="{{field}}" style="width: {{width}}px; max-width: {{width}}px; min-width: {{width}}px;"> \
|
||||
<div class="data-table-cell-content"> \
|
||||
<a href="javascript:{}" class="data-table-cell-edit" title="Edit this cell"> </a> \
|
||||
<a href="javascript:{}" class="data-table-cell-edit" title="{{t.Edit_this_cell}}"> </a> \
|
||||
<div class="data-table-cell-value">{{{value}}}</div> \
|
||||
</div> \
|
||||
</td> \
|
||||
@ -201,7 +203,9 @@ my.GridRow = Backbone.View.extend({
|
||||
|
||||
render: function() {
|
||||
this.$el.attr('data-id', this.model.id);
|
||||
var html = Mustache.render(this.template, this.toTemplateJSON());
|
||||
var tmplData = this.toTemplateJSON();
|
||||
tmplData = _.extend(tmplData, this.MustacheFormatter());
|
||||
var html = Mustache.render(this.template, tmplData);
|
||||
this.$el.html(html);
|
||||
return this;
|
||||
},
|
||||
@ -214,8 +218,8 @@ my.GridRow = Backbone.View.extend({
|
||||
<textarea class="data-table-cell-editor-editor" bind="textarea">{{value}}</textarea> \
|
||||
<div id="data-table-cell-editor-actions"> \
|
||||
<div class="data-table-cell-editor-action"> \
|
||||
<button class="okButton btn primary">Update</button> \
|
||||
<button class="cancelButton btn danger">Cancel</button> \
|
||||
<button class="okButton btn primary">{{t.Update}}</button> \
|
||||
<button class="cancelButton btn danger">{{t.Cancel}}</button> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
@ -229,7 +233,8 @@ my.GridRow = Backbone.View.extend({
|
||||
$(e.target).addClass("hidden");
|
||||
var cell = $(e.target).siblings('.data-table-cell-value');
|
||||
cell.data("previousContents", cell.text());
|
||||
var templated = Mustache.render(this.cellEditorTemplate, {value: cell.text()});
|
||||
|
||||
var templated = Mustache.render(this.cellEditorTemplate, _.extend({value: cell.text()}, this.MustacheFormatter()));
|
||||
cell.html(templated);
|
||||
},
|
||||
|
||||
@ -242,6 +247,7 @@ my.GridRow = Backbone.View.extend({
|
||||
var newData = {};
|
||||
newData[field] = newValue;
|
||||
this.model.set(newData);
|
||||
throw "Czym tu jest this? " + this;
|
||||
this.trigger('recline:flash', {message: "Updating row...", loader: true});
|
||||
this.model.save().then(function(response) {
|
||||
this.trigger('recline:flash', {message: "Row updated successfully", category: 'success'});
|
||||
|
||||
@ -38,7 +38,7 @@ this.recline.View = this.recline.View || {};
|
||||
//
|
||||
// * map: the Leaflet map (L.Map)
|
||||
// * features: Leaflet GeoJSON layer containing all the features (L.GeoJSON)
|
||||
my.Map = Backbone.View.extend({
|
||||
my.Map = Backbone.I18nView.extend({
|
||||
template: ' \
|
||||
<div class="recline-map"> \
|
||||
<div class="panel map"></div> \
|
||||
@ -58,6 +58,8 @@ my.Map = Backbone.View.extend({
|
||||
// this will be the Leaflet L.Map object (setup below)
|
||||
this.map = null;
|
||||
|
||||
this.initializeI18n(options.locale || 'en');
|
||||
|
||||
var stateData = _.extend({
|
||||
geomField: null,
|
||||
lonField: null,
|
||||
@ -173,7 +175,7 @@ my.Map = Backbone.View.extend({
|
||||
// Also sets up the editor fields and the map if necessary.
|
||||
render: function() {
|
||||
var self = this;
|
||||
var htmls = Mustache.render(this.template, this.model.toTemplateJSON());
|
||||
var htmls = Mustache.render(this.template, _.extend(this.model.toTemplateJSON(), this.MustacheFormatter()));
|
||||
this.$el.html(htmls);
|
||||
this.$map = this.$el.find('.panel.map');
|
||||
this.redraw();
|
||||
@ -505,7 +507,7 @@ my.Map = Backbone.View.extend({
|
||||
}
|
||||
});
|
||||
|
||||
my.MapMenu = Backbone.View.extend({
|
||||
my.MapMenu = Backbone.I18nView.extend({
|
||||
className: 'editor',
|
||||
|
||||
template: ' \
|
||||
@ -588,7 +590,7 @@ my.MapMenu = Backbone.View.extend({
|
||||
// Also sets up the editor fields and the map if necessary.
|
||||
render: function() {
|
||||
var self = this;
|
||||
var htmls = Mustache.render(this.template, this.model.toTemplateJSON());
|
||||
var htmls = Mustache.render(this.template, _.extend(this.model.toTemplateJSON(), this.MustacheFormatter()));
|
||||
this.$el.html(htmls);
|
||||
|
||||
if (this._geomReady() && this.model.fields.length){
|
||||
|
||||
@ -108,9 +108,7 @@ my.MultiView = Backbone.I18nView.extend({
|
||||
</div> \
|
||||
</div> \
|
||||
<div class="recline-results-info"> \
|
||||
{{t.num_records}} -> t + getattr \
|
||||
{{#trans}}<span class="doc-count">{{recordCount}}</span> records{{/trans}} -- \
|
||||
<span class="doc-count">{{recordCount}}</span> records\
|
||||
{{#t.num_records}}<span class="doc-count">{recordCount}</span> records{{/t.num_records}}\
|
||||
</div> \
|
||||
<div class="menu-right"> \
|
||||
<div class="btn-group" data-toggle="buttons-checkbox"> \
|
||||
@ -133,6 +131,8 @@ my.MultiView = Backbone.I18nView.extend({
|
||||
initialize: function(options) {
|
||||
var self = this;
|
||||
this._setupState(options.state);
|
||||
// todo any better idea to pass locale than by initialization? singleton? or does Intl API handle that?
|
||||
this.initializeI18n(options.locale || 'en');
|
||||
|
||||
// Hash of 'page' views (i.e. those for whole page) keyed by page name
|
||||
if (options.views) {
|
||||
@ -174,13 +174,13 @@ my.MultiView = Backbone.I18nView.extend({
|
||||
} else {
|
||||
this.sidebarViews = [{
|
||||
id: 'filterEditor',
|
||||
label: 'Filters',
|
||||
label: this.t('Filters'),
|
||||
view: new my.FilterEditor({
|
||||
model: this.model
|
||||
})
|
||||
}, {
|
||||
id: 'fieldsView',
|
||||
label: 'Fields',
|
||||
label: this.t('Fields'),
|
||||
view: new my.Fields({
|
||||
model: this.model
|
||||
})
|
||||
@ -206,7 +206,7 @@ my.MultiView = Backbone.I18nView.extend({
|
||||
});
|
||||
this.listenTo(this.model, 'query:done', function() {
|
||||
self.clearNotifications();
|
||||
self.$el.find('.doc-count').text(self.model.recordCount || 'Unknown');
|
||||
self.$el.find('.doc-count').text(self.model.recordCount || this.t('Unknown'));
|
||||
});
|
||||
this.listenTo(this.model, 'query:fail', function(error) {
|
||||
self.clearNotifications();
|
||||
@ -221,7 +221,7 @@ my.MultiView = Backbone.I18nView.extend({
|
||||
msg += error.message;
|
||||
}
|
||||
} else {
|
||||
msg = 'There was an error querying the backend';
|
||||
msg = this.t('backend_error', {}, 'There was an error querying the backend');
|
||||
}
|
||||
self.notify({message: msg, category: 'error', persist: true});
|
||||
});
|
||||
@ -370,6 +370,7 @@ my.MultiView = Backbone.I18nView.extend({
|
||||
|
||||
// now get default data + hash url plus initial state and initial our state object with it
|
||||
var stateData = _.extend({
|
||||
locale: 'en',
|
||||
query: query,
|
||||
'view-graph': graphState,
|
||||
backend: this.model.backend.__type__,
|
||||
|
||||
@ -40,14 +40,14 @@ this.recline.View = this.recline.View || {};
|
||||
// }
|
||||
// });
|
||||
//// NB: you need an explicit height on the element for slickgrid to work
|
||||
my.SlickGrid = Backbone.View.extend({
|
||||
my.SlickGrid = Backbone.I18nView.extend({
|
||||
initialize: function(modelEtc) {
|
||||
var self = this;
|
||||
this.$el.addClass('recline-slickgrid');
|
||||
|
||||
// Template for row delete menu , change it if you don't love
|
||||
this.templates = {
|
||||
"deleterow" : '<button href="#" class="recline-row-delete btn btn-default" title="Delete row">X</button>'
|
||||
"deleterow" : '<button href="#" class="recline-row-delete btn btn-default" title="{{t.Delete_row}}"><span class="wcag_hide">{{t.Delete_row}}</span><span aria-hidden="true">X</span></button>'
|
||||
};
|
||||
|
||||
_.bindAll(this, 'render', 'onRecordChanged');
|
||||
@ -125,9 +125,10 @@ my.SlickGrid = Backbone.View.extend({
|
||||
var validator = function(field) {
|
||||
return function(value){
|
||||
if (field.type == "date" && isNaN(Date.parse(value))){
|
||||
// todo test translation
|
||||
return {
|
||||
valid: false,
|
||||
msg: "A date is required, check field field-date-format"
|
||||
msg: self.t('date_required', {}, "A date is required, check field field-date-format")
|
||||
};
|
||||
} else {
|
||||
return {valid: true, msg :null }
|
||||
@ -436,7 +437,7 @@ my.SlickGrid = Backbone.View.extend({
|
||||
my.GridControl= Backbone.View.extend({
|
||||
className: "recline-row-add",
|
||||
// Template for row edit menu , change it if you don't love
|
||||
template: '<h1><button href="#" class="recline-row-add btn btn-default">Add row</button></h1>',
|
||||
template: '<h1><button href="#" class="recline-row-add btn btn-default">{{t.Add_row}}</button></h1>',
|
||||
|
||||
initialize: function(options){
|
||||
var self = this;
|
||||
@ -514,7 +515,7 @@ my.GridControl= Backbone.View.extend({
|
||||
$input = $('<input type="checkbox" />').data('option', 'autoresize').attr('id','slick-option-autoresize');
|
||||
$input.appendTo($li);
|
||||
$('<label />')
|
||||
.text('Force fit columns')
|
||||
.text(this.t('Force_fit_columns'))
|
||||
.attr('for','slick-option-autoresize')
|
||||
.appendTo($li);
|
||||
if (grid.getOptions().forceFitColumns) {
|
||||
|
||||
@ -22,11 +22,11 @@ this.recline.View = this.recline.View || {};
|
||||
(function($, my) {
|
||||
"use strict";
|
||||
|
||||
my.Fields = Backbone.View.extend({
|
||||
my.Fields = Backbone.I18nView.extend({
|
||||
className: 'recline-fields-view',
|
||||
template: ' \
|
||||
<div class="panel-group fields-list well"> \
|
||||
<h3>Fields <a href="#" class="js-show-hide">+</a></h3> \
|
||||
<h3>{{t.Fields}} <a href="#" class="js-show-hide" title="{{t.Show_field}}"><span class="wcag_hide">{{t.Show_field}}</span><span aria-hidden="true">+</span></a></h3> \
|
||||
{{#fields}} \
|
||||
<div class="panel panel-default field"> \
|
||||
<div class="panel-heading"> \
|
||||
@ -35,7 +35,7 @@ my.Fields = Backbone.View.extend({
|
||||
{{label}} \
|
||||
<small> \
|
||||
{{type}} \
|
||||
<a class="accordion-toggle" data-toggle="collapse" href="#collapse{{id}}"> » </a> \
|
||||
<a class="accordion-toggle" data-toggle="collapse" href="#collapse{{id}}" title="{{t.Expand_and_collapse}}"> <span class="wcag_hide">{{t.Expand_and_collapse}}</span><span aria-hidden="true">»</span> </a> \
|
||||
</small> \
|
||||
</h4> \
|
||||
</div> \
|
||||
@ -87,6 +87,7 @@ my.Fields = Backbone.View.extend({
|
||||
out.facets = field.facets.toJSON();
|
||||
tmplData.fields.push(out);
|
||||
});
|
||||
tmplData = _.extend(tmplData, this.MustacheFormatter());
|
||||
var templated = Mustache.render(this.template, tmplData);
|
||||
this.$el.html(templated);
|
||||
}
|
||||
|
||||
@ -6,15 +6,15 @@ this.recline.View = this.recline.View || {};
|
||||
(function($, my) {
|
||||
"use strict";
|
||||
|
||||
my.FilterEditor = Backbone.View.extend({
|
||||
my.FilterEditor = Backbone.I18nView.extend({
|
||||
className: 'recline-filter-editor well',
|
||||
template: ' \
|
||||
<div class="filters"> \
|
||||
<h3>Filters</h3> \
|
||||
<a href="#" class="js-add-filter">Add filter</a> \
|
||||
<h3>{{t.Filters}}</h3> \
|
||||
<a href="#" class="js-add-filter">{{t.Add_filter}}</a> \
|
||||
<form class="form-stacked js-add" style="display: none;"> \
|
||||
<div class="form-group"> \
|
||||
<label>Field</label> \
|
||||
<label>{{t.Field}}</label> \
|
||||
<select class="fields form-control"> \
|
||||
{{#fields}} \
|
||||
<option value="{{id}}">{{label}}</option> \
|
||||
@ -22,21 +22,21 @@ my.FilterEditor = Backbone.View.extend({
|
||||
</select> \
|
||||
</div> \
|
||||
<div class="form-group"> \
|
||||
<label>Filter type</label> \
|
||||
<label>{{t.Filter_type}}</label> \
|
||||
<select class="filterType form-control"> \
|
||||
<option value="term">Value</option> \
|
||||
<option value="range">Range</option> \
|
||||
<option value="geo_distance">Geo distance</option> \
|
||||
<option value="term">{{t.Value}}</option> \
|
||||
<option value="range">{{t.Range}}</option> \
|
||||
<option value="geo_distance">{{t.Geo_distance}}</option> \
|
||||
</select> \
|
||||
</div> \
|
||||
<button type="submit" class="btn btn-default">Add</button> \
|
||||
<button type="submit" class="btn btn-default">{{t.Add}}</button> \
|
||||
</form> \
|
||||
<form class="form-stacked js-edit"> \
|
||||
{{#filters}} \
|
||||
{{{filterRender}}} \
|
||||
{{/filters}} \
|
||||
{{#filters.length}} \
|
||||
<button type="submit" class="btn btn-default">Update</button> \
|
||||
<button type="submit" class="btn btn-default">{{t.Update}}</button> \
|
||||
{{/filters.length}} \
|
||||
</form> \
|
||||
</div> \
|
||||
@ -47,7 +47,7 @@ my.FilterEditor = Backbone.View.extend({
|
||||
<fieldset> \
|
||||
<legend> \
|
||||
{{field}} <small>{{type}}</small> \
|
||||
<a class="js-remove-filter" href="#" title="Remove this filter" data-filter-id="{{id}}">×</a> \
|
||||
<a class="js-remove-filter" href="#" title="{{t.Remove_this_filter}}" data-filter-id="{{id}}"><span class="wcag_hide">{{t.Remove_this_filter}}</span><span aria-hidden="true">×</span></a> \
|
||||
</legend> \
|
||||
<input class="input-sm" type="text" value="{{term}}" name="term" data-filter-field="{{field}}" data-filter-id="{{id}}" data-filter-type="{{type}}" /> \
|
||||
</fieldset> \
|
||||
@ -58,14 +58,14 @@ my.FilterEditor = Backbone.View.extend({
|
||||
<fieldset> \
|
||||
<legend> \
|
||||
{{field}} <small>{{type}}</small> \
|
||||
<a class="js-remove-filter" href="#" title="Remove this filter" data-filter-id="{{id}}">×</a> \
|
||||
<a class="js-remove-filter" href="#" title="{{t.Remove_this_filter}" data-filter-id="{{id}}"><span class="wcag_hide">{{t.Remove_this_filter}}</span><span aria-hidden="true">×</span></a> \
|
||||
</legend> \
|
||||
<div class="form-group"> \
|
||||
<label class="control-label" for="">From</label> \
|
||||
<label class="control-label" for="">{{t.From}}</label> \
|
||||
<input class="input-sm" type="text" value="{{from}}" name="from" data-filter-field="{{field}}" data-filter-id="{{id}}" data-filter-type="{{type}}" /> \
|
||||
</div> \
|
||||
<div class="form-group"> \
|
||||
<label class="control-label" for="">To</label> \
|
||||
<label class="control-label" for="">{{t.To}}</label> \
|
||||
<input class="input-sm" type="text" value="{{to}}" name="to" data-filter-field="{{field}}" data-filter-id="{{id}}" data-filter-type="{{type}}" /> \
|
||||
</div> \
|
||||
</fieldset> \
|
||||
@ -76,18 +76,18 @@ my.FilterEditor = Backbone.View.extend({
|
||||
<fieldset> \
|
||||
<legend> \
|
||||
{{field}} <small>{{type}}</small> \
|
||||
<a class="js-remove-filter" href="#" title="Remove this filter" data-filter-id="{{id}}">×</a> \
|
||||
<a class="js-remove-filter" href="#" title="{{t.Remove_this_filter}}" data-filter-id="{{id}}"><span class="wcag_hide">{{t.Remove_this_filter}}</span><span aria-hidden="true">×</span></a> \
|
||||
</legend> \
|
||||
<div class="form-group"> \
|
||||
<label class="control-label" for="">Longitude</label> \
|
||||
<label class="control-label" for="">{{t.Longitude}}</label> \
|
||||
<input class="input-sm" type="text" value="{{point.lon}}" name="lon" data-filter-field="{{field}}" data-filter-id="{{id}}" data-filter-type="{{type}}" /> \
|
||||
</div> \
|
||||
<div class="form-group"> \
|
||||
<label class="control-label" for="">Latitude</label> \
|
||||
<label class="control-label" for="">{{t.Latitude}}</label> \
|
||||
<input class="input-sm" type="text" value="{{point.lat}}" name="lat" data-filter-field="{{field}}" data-filter-id="{{id}}" data-filter-type="{{type}}" /> \
|
||||
</div> \
|
||||
<div class="form-group"> \
|
||||
<label class="control-label" for="">Distance (km)</label> \
|
||||
<label class="control-label" for="">{{t.Distance_km}}</label> \
|
||||
<input class="input-sm" type="text" value="{{distance}}" name="distance" data-filter-field="{{field}}" data-filter-id="{{id}}" data-filter-type="{{type}}" /> \
|
||||
</div> \
|
||||
</fieldset> \
|
||||
@ -116,8 +116,10 @@ my.FilterEditor = Backbone.View.extend({
|
||||
});
|
||||
tmplData.fields = this.model.fields.toJSON();
|
||||
tmplData.filterRender = function() {
|
||||
return Mustache.render(self.filterTemplates[this.type], this);
|
||||
var filterData = _.extend(this, this.MustacheFormatter());
|
||||
return Mustache.render(self.filterTemplates[this.type], filterData);
|
||||
};
|
||||
tmplData = _.extend(tmplData, this.MustacheFormatter());
|
||||
var out = Mustache.render(this.template, tmplData);
|
||||
this.$el.html(out);
|
||||
},
|
||||
|
||||
@ -6,7 +6,7 @@ this.recline.View = this.recline.View || {};
|
||||
(function($, my) {
|
||||
"use strict";
|
||||
|
||||
my.QueryEditor = Backbone.View.extend({
|
||||
my.QueryEditor = Backbone.I18nView.extend({
|
||||
className: 'recline-query-editor',
|
||||
template: ' \
|
||||
<form action="" method="GET" class="form-inline" role="form"> \
|
||||
@ -15,11 +15,11 @@ my.QueryEditor = Backbone.View.extend({
|
||||
<div class="input-group-addon"> \
|
||||
<i class="glyphicon glyphicon-search"></i> \
|
||||
</div> \
|
||||
<label for="q">Search</label> \
|
||||
<input class="form-control search-query" type="text" id="q" name="q" value="{{q}}" placeholder="Search data ..."> \
|
||||
<label for="q">{{t.Search}}</label> \
|
||||
<input class="form-control search-query" type="text" id="q" name="q" value="{{q}}" placeholder="{{t.Search_data}} ..."> \
|
||||
</div> \
|
||||
</div> \
|
||||
<button type="submit" class="btn btn-default">Go »</button> \
|
||||
<button type="submit" class="btn btn-default">{{t.Go}} »</button> \
|
||||
</form> \
|
||||
',
|
||||
|
||||
@ -39,6 +39,7 @@ my.QueryEditor = Backbone.View.extend({
|
||||
},
|
||||
render: function() {
|
||||
var tmplData = this.model.toJSON();
|
||||
tmplData = _.extend(tmplData, this.MustacheFormatter());
|
||||
var templated = Mustache.render(this.template, tmplData);
|
||||
this.$el.html(templated);
|
||||
}
|
||||
|
||||
@ -6,21 +6,21 @@ this.recline.View = this.recline.View || {};
|
||||
(function($, my) {
|
||||
"use strict";
|
||||
|
||||
my.ValueFilter = Backbone.View.extend({
|
||||
my.ValueFilter = Backbone.I18nView.extend({
|
||||
className: 'recline-filter-editor well',
|
||||
template: ' \
|
||||
<div class="filters"> \
|
||||
<h3>Filters</h3> \
|
||||
<button class="btn js-add-filter add-filter">Add filter</button> \
|
||||
<h3>{{t.Filters}}</h3> \
|
||||
<button class="btn js-add-filter add-filter">{{t.Add_filter}}</button> \
|
||||
<form class="form-stacked js-add" style="display: none;"> \
|
||||
<fieldset> \
|
||||
<label>Field</label> \
|
||||
<label>{{t.Field}}</label> \
|
||||
<select class="fields form-control"> \
|
||||
{{#fields}} \
|
||||
<option value="{{id}}">{{label}}</option> \
|
||||
{{/fields}} \
|
||||
</select> \
|
||||
<button type="submit" class="btn">Add</button> \
|
||||
<button type="submit" class="btn">{{t.Add}}</button> \
|
||||
</fieldset> \
|
||||
</form> \
|
||||
<form class="form-stacked js-edit"> \
|
||||
@ -28,7 +28,7 @@ my.ValueFilter = Backbone.View.extend({
|
||||
{{{filterRender}}} \
|
||||
{{/filters}} \
|
||||
{{#filters.length}} \
|
||||
<button type="submit" class="btn update-filter">Update</button> \
|
||||
<button type="submit" class="btn update-filter">{{t.Update}}</button> \
|
||||
{{/filters.length}} \
|
||||
</form> \
|
||||
</div> \
|
||||
@ -38,7 +38,7 @@ my.ValueFilter = Backbone.View.extend({
|
||||
<div class="filter-{{type}} filter"> \
|
||||
<fieldset> \
|
||||
{{field}} \
|
||||
<a class="js-remove-filter" href="#" title="Remove this filter" data-filter-id="{{id}}">×</a> \
|
||||
<a class="js-remove-filter" href="#" title="{{t.Remove_this_filter}}" data-filter-id="{{id}}"><span class="wcag_hide">{{t.Remove_this_filter}}</span><span aria-hidden="true">×</span></a> \
|
||||
<input type="text" value="{{term}}" name="term" data-filter-field="{{field}}" data-filter-id="{{id}}" data-filter-type="{{type}}" /> \
|
||||
</fieldset> \
|
||||
</div> \
|
||||
|
||||
@ -33,6 +33,10 @@
|
||||
<script type="text/javascript" src="../vendor/slickgrid/2.2/plugins/slick.rowmovemanager.js"></script>
|
||||
|
||||
<script type="text/javascript" src="../vendor/timeline/js/timeline.js"></script>
|
||||
|
||||
<script type="text/javascript" src="../node_modules/intl-messageformat/dist/intl-messageformat-with-locales.min.js"></script>
|
||||
<script type="module" src="../node_modules/intl-format-cache/lib/memoizer.js"></script>
|
||||
|
||||
<!--[if lte IE 7]>
|
||||
<script language="javascript" type="text/javascript" src="../vendor/json/json2.js"></script>
|
||||
<![endif]-->
|
||||
@ -76,10 +80,12 @@
|
||||
<script type="text/javascript" src="view.map.test.js"></script>
|
||||
<script type="text/javascript" src="view.timeline.test.js"></script>
|
||||
<script type="text/javascript" src="view.multiview.test.js"></script>
|
||||
<script type="text/javascript" src="view.i18n.test.js"></script>
|
||||
<script type="text/javascript" src="util.test.js"></script>
|
||||
<script type="text/javascript" src="widget.filtereditor.test.js"></script>
|
||||
<script type="text/javascript" src="widget.valuefilter.test.js"></script>
|
||||
<script type="text/javascript" src="widget.pager.test.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Qunit Tests</h1>
|
||||
|
||||
143
test/view.i18n.test.js
Normal file
143
test/view.i18n.test.js
Normal file
@ -0,0 +1,143 @@
|
||||
(function ($) {
|
||||
|
||||
module("View - i18n support");
|
||||
|
||||
test('translate simple key custom locale', function () {
|
||||
var dataset = Fixture.getDataset();
|
||||
var view = new recline.View.MultiView({
|
||||
model: dataset,
|
||||
locale: 'pl' // todo or should it go in the state parameter?
|
||||
});
|
||||
|
||||
equal(view.t('Grid'), 'Tabela');
|
||||
});
|
||||
|
||||
test('translate simple key default locale', function () {
|
||||
var dataset = Fixture.getDataset();
|
||||
var view = new recline.View.MultiView({
|
||||
model: dataset
|
||||
});
|
||||
|
||||
equal(view.t('Add_row'), 'Add row');
|
||||
});
|
||||
|
||||
test('override custom locale', function () {
|
||||
var dataset = Fixture.getDataset();
|
||||
var view = new recline.View.MultiView({
|
||||
model: dataset,
|
||||
locale: 'pl'
|
||||
});
|
||||
var oldTranslation = recline.View.translations['pl']['Grid'];
|
||||
|
||||
// set custom strings in external app after recline script
|
||||
recline.View.translations['pl']['Grid'] = 'Dane';
|
||||
|
||||
equal(view.t('Grid'), 'Dane');
|
||||
recline.View.translations['pl']['Grid'] = oldTranslation;
|
||||
});
|
||||
|
||||
test('override default locale', function () {
|
||||
var dataset = Fixture.getDataset();
|
||||
var view = new recline.View.MultiView({
|
||||
model: dataset
|
||||
});
|
||||
var oldTranslation = recline.View.translations['en']['Grid'];
|
||||
|
||||
// set custom strings in external app after recline script
|
||||
recline.View.translations['en']['Grid'] = 'Data';
|
||||
|
||||
equal(view.t('Grid'), 'Data');
|
||||
recline.View.translations['en']['Grid'] = oldTranslation;
|
||||
});
|
||||
|
||||
test('fallback to key if translation not present', function () {
|
||||
var dataset = Fixture.getDataset();
|
||||
var view = new recline.View.MultiView({
|
||||
model: dataset
|
||||
});
|
||||
|
||||
equal(view.t('thiskeydoesnotexist'), 'thiskeydoesnotexist');
|
||||
});
|
||||
|
||||
test('fallback to default message', function () {
|
||||
var dataset = Fixture.getDataset();
|
||||
var view = new recline.View.MultiView({
|
||||
model: dataset
|
||||
});
|
||||
|
||||
equal(view.t('thiskeydoesnotexist', {}, 'Fallback to default message'), 'Fallback to default message');
|
||||
});
|
||||
|
||||
test('mustache formatter - simple key', function () {
|
||||
var dataset = Fixture.getDataset();
|
||||
var view = new recline.View.MultiView({
|
||||
model: dataset,
|
||||
locale: 'pl'
|
||||
});
|
||||
|
||||
var template = '{{t.Grid}}';
|
||||
var tmplData = {};
|
||||
|
||||
// adding i18n support [do it in view before passing data to render functions]
|
||||
tmplData = _.extend(tmplData, view.MustacheFormatter());
|
||||
|
||||
var out = Mustache.render(template, tmplData);
|
||||
equal(out, 'Tabela');
|
||||
});
|
||||
|
||||
test('mustache formatter - complex key', function () {
|
||||
var dataset = Fixture.getDataset();
|
||||
var view = new recline.View.MultiView({
|
||||
model: dataset,
|
||||
});
|
||||
|
||||
var template = '{{#t.num_records}}{recordCount} records{{/t.num_records}}';
|
||||
var tmplData = {recordCount: 5};
|
||||
|
||||
// adding i18n support [do it in view before passing data to render functions]
|
||||
tmplData = _.extend(tmplData, view.MustacheFormatter());
|
||||
|
||||
var out = Mustache.render(template, tmplData);
|
||||
equal(out, '5 records');
|
||||
});
|
||||
|
||||
|
||||
test('translate complex key default locale', function () {
|
||||
var dataset = Fixture.getDataset();
|
||||
var view = new recline.View.MultiView({
|
||||
model: dataset
|
||||
});
|
||||
|
||||
equal(view.t('codeforall', {records: 3}, '<span>{records} records</span>'), '<span>3 records</span>');
|
||||
});
|
||||
|
||||
test('translate complex key custom locale', function () {
|
||||
var dataset = Fixture.getDataset();
|
||||
var view = new recline.View.MultiView({
|
||||
model: dataset,
|
||||
locale: 'pl'
|
||||
});
|
||||
|
||||
recline.View.translations['pl']['codeforall'] = '<span>{records} rekordy</span>';
|
||||
equal(view.t('codeforall', {records: 3}, '<span>{records} records</span>'), '<span>3 rekordy</span>');
|
||||
});
|
||||
|
||||
test('translate complex key custom locale custom count', function () {
|
||||
var dataset = Fixture.getDataset();
|
||||
var view = new recline.View.MultiView({
|
||||
model: dataset,
|
||||
locale: 'pl'
|
||||
});
|
||||
|
||||
// todo custom count string
|
||||
equal(view.t('some_msg', {records: 0}, '<span>{{records}} records</span>'), '<span>brak rekordów</span>');
|
||||
equal(view.t('some_msg', {records: 1}, '<span>{{records}} records</span>'), '<span>1 rekord</span>');
|
||||
equal(view.t('some_msg', {records: 3}, '<span>{{records}} records</span>'), '<span>3 rekordy</span>');
|
||||
equal(view.t('some_msg', {records: 5}, '<span>{{records}} records</span>'), '<span>5 rekordów</span>');
|
||||
});
|
||||
|
||||
|
||||
// todo test dynamic language changes
|
||||
|
||||
})(this.jQuery);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user