diff --git a/_config.yml b/_config.yml index f54edddd..d6aefa8a 100644 --- a/_config.yml +++ b/_config.yml @@ -3,3 +3,4 @@ markdown: kramdown title: Recline Data Explorer and Library +exclude: [] diff --git a/_includes/recline-deps.html b/_includes/recline-deps.html index 3e6d7360..fb77d16b 100644 --- a/_includes/recline-deps.html +++ b/_includes/recline-deps.html @@ -46,6 +46,10 @@ + + + + @@ -66,6 +70,8 @@ + + diff --git a/css/grid.css b/css/grid.css index caaef192..05d6f619 100644 --- a/css/grid.css +++ b/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; +} diff --git a/demos/multiview/app.js b/demos/multiview/app.js index bfea4d28..e905ae92 100755 --- a/demos/multiview/app.js +++ b/demos/multiview/app.js @@ -64,10 +64,11 @@ var createMultiView = function(dataset, state) { $el.appendTo(window.explorerDiv); // customize the subviews for the MultiView + var fmt = I18nMessages('recline', recline.View.translations); var views = [ { id: 'grid', - label: 'Grid', + label: fmt.t('Grid'), view: new recline.View.SlickGrid({ model: dataset, state: { @@ -91,15 +92,14 @@ var createMultiView = function(dataset, state) { }, { id: 'graph', - label: 'Graph', + label: fmt.t('Graph'), view: new recline.View.Graph({ model: dataset - }) }, { id: 'map', - label: 'Map', + label: fmt.t('Map'), view: new recline.View.Map({ model: dataset }) diff --git a/dist/recline.css b/dist/recline.css index 5d7f6e86..f1e976fd 100644 --- a/dist/recline.css +++ b/dist/recline.css @@ -219,6 +219,32 @@ 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; +} .recline-map .map { height: 500px; } diff --git a/docs/views.markdown b/docs/views.markdown index 762de79f..d29220e5 100644 --- a/docs/views.markdown +++ b/docs/views.markdown @@ -105,3 +105,94 @@ of such behaviour see the DataExplorer view. See the existing Views. +## Internationalization + +### Adding translations to templates + +Internationalization is implemented with help of [intl-messageformat](https://www.npmjs.com/package/intl-messageformat) library and supports [ICU Message syntax](http://userguide.icu-project.org/formatparse/messages). + +Translation keys are using Mustache tags prefixed by `t.`. You can specify translated strings in two ways: + +1. Simple text with no variables is rendered using Mustache variable-tag +```javascript +$template = '{{ "{{t.Add_row"}}}}'; // will show "Add row" in defaultLocale (English) +``` + +2. Text with variables or special characters is rendered using Mustache section-tag + +```javascript +$template = '{{ "{{#t.desc"}}}}Add first_row field{{ "{{/t.desc"}}}}'; +// using special chars; will show "Add first_row field" in defaultLocale + +$template = '{{ "{{#t.num_records"}}}}{recordCount, plural, =0 {no records} =1{# record} other {# records}}{{ "{{/t.num_records"}}}}'; +// will show "no records", "1 record" or "x records" in defaultLocale (English) +``` + +When using section-tags in existing templates be sure to remove a bracket from variables inside sections: +```javascript +#template___notranslation = '{{ "{{recordCount"}}}} records'; +#template_withtranslation = '{{ "{{#t.num_records"}}}} {recordCount} records {{ "{{/t.num_records"}}}}'; +``` + + +Then setup Mustache to use translation by injecting tranlation tags in `render` function: + +```javascript +// ============== BEFORE =================== + +my.MultiView = Backbone.View.extend({ + render: function() { + var tmplData = this.model.toTemplateJSON(); + var output = Mustache.render(this.template, tmplData); + ... + } +}); + +// ============== AFTER ==================== + +my.MultiView = Backbone.View.extend({ + render: function() { + var tmplData = this.model.toTemplateJSON(); + tmplData = I18nMessages('recline', recline.View.translations).injectMustache(tmplData); // inject Moustache formatter + var output = Mustache.render(this.template, tmplData); + ... + } +}); +``` + +### Language resolution + +By default the language is detected from the root `lang` attributes - ` and ``. + +If you want to override this functionality then override `I18nMessages.languageResolver` with your implementation. + +```html + + +``` + +Libraries can also ask for specific language: `I18nMessages('recline', recline.View.translations, 'pl')`. Language resolver is not used in that case. + +If you're creating templates using default language other than English (why?) set appropriately appHardcodedLocale: `I18nMessages('recline', recline.View.translations, undefined, 'pl')`. Then missing strings won't be reported in console and underscores in simple translations will be converted to spaces. + +### Adding new language + +Create a copy of `src/i18n/pl.js` and translate all the keys. Long English messages can be found in `en.js`. + +### Overriding defined messages + +If you want to override translations from provided locale do it in a script tag after including recline: + +```html + + +``` \ No newline at end of file diff --git a/make b/make index 324b840a..a01a23e4 100755 --- a/make +++ b/make @@ -7,6 +7,8 @@ def cat(): print("** Combining js files") cmd = 'ls src/*.js | grep -v couchdb | xargs cat > dist/recline.js' os.system(cmd) + cmd = 'ls src/**/*.js | grep -v couchdb | xargs cat >> dist/recline.js' + os.system(cmd) cmd = 'cat src/model.js src/backend.memory.js > dist/recline.dataset.js' os.system(cmd) diff --git a/package.json b/package.json index 7fb7550d..7e6a8058 100644 --- a/package.json +++ b/package.json @@ -14,13 +14,18 @@ { "name": "Max Ogden", "email": "max@maxogden.com" + }, + { + "name": "Krzysztof Madejski", + "email": "krzysztof.madejski@epf.org.pl" } ], "dependencies": { "backbone": ">=0.5", "jquery": ">=1.6", "mustache": ">=0.5.2", - "underscore": ">=1.0" + "underscore": ">=1.0", + "intl-messageformat": "1.3.x" }, "homepage": "http://reclinejs.com/", "keywords": [ diff --git a/src/i18n/en.js b/src/i18n/en.js new file mode 100644 index 00000000..f7c26b88 --- /dev/null +++ b/src/i18n/en.js @@ -0,0 +1,14 @@ +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)', + flot_Group_Column: 'Group Column (Axis 1)', + + map_mapping: 'Coordinates source', + map_mapping_lat_lon: 'Latitude / Longitude fields', + map_mapping_geojson: 'GeoJSON field' +}; \ No newline at end of file diff --git a/src/i18n/pl.js b/src/i18n/pl.js new file mode 100644 index 00000000..74c9fa1c --- /dev/null +++ b/src/i18n/pl.js @@ -0,0 +1,69 @@ +this.recline = this.recline || {}; +this.recline.View = this.recline.View || {}; +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', + Search: 'Szukaj', + Add: 'Dodaj', + Add_row: 'Dodaj wiersz', + Delete_row: 'Usuń wiersz', + Reorder_row: 'Przesuń wiersz', + Update: 'Zaktualizuj', + Cancel: 'Anuluj', + Updating_row: 'Aktualizuję wiersz', + Row_updated_successfully: 'Wiersz został zaktualizowany', + Error_saving_row: 'Wystąpił błąd aktualizacji wiersza', + 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ń', + + flot_info: '
Jakie kolumny powinny zostać narysowane na wykresie?
\ +Wybierz je używając menu po prawej, a wykres pojawi się automatycznie.
', + Graph_Type: 'Typ wykresu', + Lines_and_Points: 'Linie z punktami', + Lines: 'Linie', + Points: 'Punkty', + Bars: 'Słupki poziome', + Columns: 'Słupki', + flot_Group_Column: 'Kolumna (Oś X)', + Please_choose: 'Proszę wybrać', + Remove: 'Usuń', + Series: 'Seria', + Axis_2: 'Oś Y', + Add_Series: 'Dodaj serię danych', + Save: 'Zapisz', + + map_mapping: 'Źródło koordynatów', + map_mapping_lat_lon: 'Szerokość i długość geo.', + map_mapping_geojson: 'Jedna kolumna typu GeoJSON', + Latitude_field: 'Kolumna szerokości geo. (WGS84)', + Longitude_field: 'Kolumna długości geo. (WGS84)', + Auto_zoom_to_features: 'Kadruj, aby pokazać wszytkie punkty', + Cluster_markers: 'Łącz pobliskie punkty w grupy', + + num_records: '{recordCount} rekordów' +}; \ No newline at end of file diff --git a/src/view.flot.js b/src/view.flot.js index 17037b55..6d468f80 100644 --- a/src/view.flot.js +++ b/src/view.flot.js @@ -27,9 +27,9 @@ my.Flot = Backbone.View.extend({There\'s no graph here yet because we don\'t know what fields you\'d like to see plotted.
\ -Please tell us by using the menu on the right and a graph will automatically appear.
\ +Please tell us by using the menu on the right and a graph will automatically appear.
{{/t.flot_info}} \