From f2d9f3b1157919fcbabecb918023939e35e751a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 1 Jun 2015 18:20:15 +0200 Subject: [PATCH 01/10] start implementing localization functionality --- .../accordion_list_item_table_editions.js | 6 +- js/components/header.js | 58 ++++++++----------- js/constants/languages.js | 8 +++ js/stores/edition_store.js | 4 +- js/utils/lang_utils.js | 13 +++++ 5 files changed, 51 insertions(+), 38 deletions(-) create mode 100644 js/constants/languages.js create mode 100644 js/utils/lang_utils.js diff --git a/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js b/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js index 2b3bd5c0..e18b7a3f 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js @@ -12,6 +12,8 @@ import TableItemText from '../ascribe_table/table_item_text'; import TableItemCheckbox from '../ascribe_table/table_item_checkbox'; import TableItemAclFiltered from '../ascribe_table/table_item_acl_filtered'; +import getText from '../../utils/lang_utils'; + let AccordionListItemTableEditions = React.createClass({ propTypes: { @@ -47,8 +49,8 @@ let AccordionListItemTableEditions = React.createClass({ render() { let columnList = [ new TableColumnContentModel((item) => { return { 'editionId': item.id, 'pieceId': this.props.parentId, 'selectItem': this.selectItem, 'selected': item.selected }}, '', '', TableItemCheckbox, 1, false), - new TableColumnContentModel((item) => { return { 'content': item.edition_number }}, 'num_editions', 'Nr', TableItemText, 1, false), - new TableColumnContentModel((item) => { return { 'content': item.bitcoin_id }}, 'bitcoin_id', 'Bitcoin Address', TableItemText, 5, false), + new TableColumnContentModel((item) => { return { 'content': item.edition_number }}, 'num_editions', '#', TableItemText, 1, false), + new TableColumnContentModel((item) => { return { 'content': item.bitcoin_id }}, 'bitcoin_id', getText('Bitcoin Address'), TableItemText, 5, false), new TableColumnContentModel((item) => { return { 'content': item.acl }}, 'acl', 'Actions', TableItemAclFiltered, 4, false) ]; diff --git a/js/components/header.js b/js/components/header.js index 20855b1b..588f73bf 100644 --- a/js/components/header.js +++ b/js/components/header.js @@ -5,6 +5,12 @@ import AltContainer from 'alt/AltContainer'; import UserActions from '../actions/user_actions'; import UserStore from '../stores/user_store'; +import Nav from 'react-bootstrap/lib/Nav'; +import Navbar from 'react-bootstrap/lib/Navbar'; +import NavItem from 'react-bootstrap/lib/NavItem'; +import DropdownButton from 'react-bootstrap/lib/DropdownButton'; +import MenuItem from 'react-bootstrap/lib/MenuItem'; + let Link = Router.Link; let Header = React.createClass({ @@ -24,40 +30,24 @@ let Header = React.createClass({ render() { return ( - + + + + ); } }); diff --git a/js/constants/languages.js b/js/constants/languages.js new file mode 100644 index 00000000..db14a490 --- /dev/null +++ b/js/constants/languages.js @@ -0,0 +1,8 @@ +const languages = { + 'en-US': { + 'Bitcoin Address': 'Bitcoin Address', + 'Actions': 'Actions' + } +}; + +export default languages; \ No newline at end of file diff --git a/js/stores/edition_store.js b/js/stores/edition_store.js index 9859ec7c..b33e248f 100644 --- a/js/stores/edition_store.js +++ b/js/stores/edition_store.js @@ -1,11 +1,11 @@ import alt from '../alt'; -import EditionAction from '../actions/edition_actions'; +import EditionActions from '../actions/edition_actions'; class EditionStore { constructor() { this.edition = {}; - this.bindActions(EditionAction); + this.bindActions(EditionActions); } onUpdateEdition(edition) { diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js new file mode 100644 index 00000000..b7a7681e --- /dev/null +++ b/js/utils/lang_utils.js @@ -0,0 +1,13 @@ +import languages from '../constants/languages'; + +let getText = function(s) { + let lang = navigator.language || navigator.userLanguage; + if(lang in languages && s in languages[lang]) { + return languages[lang][s]; + } else { + throw new Error('Your language is not supported.'); + // How ironic that this error is thrown in the english language... + } +}; + +export default getText; \ No newline at end of file From 777857b50cee1a32f12efad06b71913ad601de65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 12:00:59 +0200 Subject: [PATCH 02/10] include lodash.templates --- js/utils/lang_utils.js | 17 +++++++++++------ package.json | 5 +++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index b7a7681e..a936294e 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -1,12 +1,17 @@ import languages from '../constants/languages'; +import template from 'lodash.template'; -let getText = function(s) { +let getText = function(s, ...args) { let lang = navigator.language || navigator.userLanguage; - if(lang in languages && s in languages[lang]) { - return languages[lang][s]; - } else { - throw new Error('Your language is not supported.'); - // How ironic that this error is thrown in the english language... + try { + if(lang in languages) { + return languages[lang][s]; + } else { + // just use the english language + return languages['en-US'][s]; + } + } catch(err) { + console.error(err); } }; diff --git a/package.json b/package.json index 38710b47..3007fdf4 100644 --- a/package.json +++ b/package.json @@ -30,11 +30,12 @@ "alt": "^0.16.5", "classnames": "^1.2.2", "isomorphic-fetch": "^2.0.2", + "lodash.template": "^3.6.1", "object-assign": "^2.0.0", "react": "^0.13.2", + "react-bootstrap": "~0.22.6", "react-router": "^0.13.3", - "uglifyjs": "^2.4.10", - "react-bootstrap": "~0.22.6" + "uglifyjs": "^2.4.10" }, "jest": { "scriptPreprocessor": "node_modules/babel-jest", From 6f33b291f9c33277cc5b00ab5d62bde293cc8ed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 13:10:10 +0200 Subject: [PATCH 03/10] remove lodash templates --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 3007fdf4..c3025fc6 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "alt": "^0.16.5", "classnames": "^1.2.2", "isomorphic-fetch": "^2.0.2", - "lodash.template": "^3.6.1", "object-assign": "^2.0.0", "react": "^0.13.2", "react-bootstrap": "~0.22.6", From 68be98c3f0957d8662f9b5f7dea86610c7e6fa29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 13:31:12 +0200 Subject: [PATCH 04/10] integrate string formating functionality --- js/actions/piece_actions.js | 2 +- js/actions/piece_list_actions.js | 1 - .../accordion_list_item_table.js | 4 ++- .../accordion_list_item_table_editions.js | 6 ++-- js/constants/languages.js | 4 ++- js/utils/general_utils.js | 35 ++++++++++++++++++- js/utils/lang_utils.js | 14 ++++---- 7 files changed, 52 insertions(+), 14 deletions(-) diff --git a/js/actions/piece_actions.js b/js/actions/piece_actions.js index d657539b..274ef458 100644 --- a/js/actions/piece_actions.js +++ b/js/actions/piece_actions.js @@ -15,7 +15,7 @@ class PieceActions { this.actions.updatePiece(res.piece); }) .catch((err) => { - console.log(err); + console.log(err); }); } } diff --git a/js/actions/piece_list_actions.js b/js/actions/piece_list_actions.js index 4ec237ca..29c8413f 100644 --- a/js/actions/piece_list_actions.js +++ b/js/actions/piece_list_actions.js @@ -14,7 +14,6 @@ class PieceListActions { PieceListFetcher .fetch(page, pageSize, search, orderBy, orderAsc) .then((res) => { - console.log(res); this.actions.updatePieceList({ page, pageSize, diff --git a/js/components/ascribe_accordion_list/accordion_list_item_table.js b/js/components/ascribe_accordion_list/accordion_list_item_table.js index 9ddb3308..953fffa1 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_table.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_table.js @@ -5,6 +5,8 @@ import TableItem from '../ascribe_table/table_item'; import TableColumnContentModel from '../../models/table_column_content_model'; +import getLangText from '../../utils/lang_utils'; + let AccordionListItemTable = React.createClass({ getInitialState() { return { @@ -78,7 +80,7 @@ let AccordionListItemTableToggle = React.createClass({ - {this.props.show ? 'Hide all ' + this.props.numOfTableItems + ' Editions' : 'Show all ' + this.props.numOfTableItems + ' Editions'} + {this.props.show ? getLangText('Hide all %d Editions', this.props.numOfTableItems) : getLangText('Show all %d Editions', this.props.numOfTableItems)} ); } diff --git a/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js b/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js index e18b7a3f..356e5fe0 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js @@ -12,7 +12,7 @@ import TableItemText from '../ascribe_table/table_item_text'; import TableItemCheckbox from '../ascribe_table/table_item_checkbox'; import TableItemAclFiltered from '../ascribe_table/table_item_acl_filtered'; -import getText from '../../utils/lang_utils'; +import getLangText from '../../utils/lang_utils'; let AccordionListItemTableEditions = React.createClass({ @@ -50,8 +50,8 @@ let AccordionListItemTableEditions = React.createClass({ let columnList = [ new TableColumnContentModel((item) => { return { 'editionId': item.id, 'pieceId': this.props.parentId, 'selectItem': this.selectItem, 'selected': item.selected }}, '', '', TableItemCheckbox, 1, false), new TableColumnContentModel((item) => { return { 'content': item.edition_number }}, 'num_editions', '#', TableItemText, 1, false), - new TableColumnContentModel((item) => { return { 'content': item.bitcoin_id }}, 'bitcoin_id', getText('Bitcoin Address'), TableItemText, 5, false), - new TableColumnContentModel((item) => { return { 'content': item.acl }}, 'acl', 'Actions', TableItemAclFiltered, 4, false) + new TableColumnContentModel((item) => { return { 'content': item.bitcoin_id }}, 'bitcoin_id', getLangText('Bitcoin Address'), TableItemText, 5, false), + new TableColumnContentModel((item) => { return { 'content': item.acl }}, 'acl', getLangText('Actions'), TableItemAclFiltered, 4, false) ]; return ( diff --git a/js/constants/languages.js b/js/constants/languages.js index db14a490..c49caf53 100644 --- a/js/constants/languages.js +++ b/js/constants/languages.js @@ -1,7 +1,9 @@ const languages = { 'en-US': { 'Bitcoin Address': 'Bitcoin Address', - 'Actions': 'Actions' + 'Actions': 'Actions', + 'Hide all %d Editions': 'Hide all %d Editions', + 'Show all %d Editions': 'Show all %d Editions' } }; diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index 7ab180fa..14118d94 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -34,8 +34,41 @@ let GeneralUtils = { let sum = 0; l.forEach((num) => sum += parseFloat(num) || 0); return sum; - } + }, + /* + Taken from http://stackoverflow.com/a/4795914/1263876 + Behaves like C's format string function + + Does not throw errors though if a argument's type is not + matching its template's representative!!! + This essentially means you can use %d or %s for anything... + */ + formatText() { + var args = arguments, + string = args[0], + i = 1; + return string.replace(/%((%)|s|d)/g, function (m) { + // m is the matched format, e.g. %s, %d + var val = null; + if (m[2]) { + val = m[2]; + } else { + val = args[i]; + // A switch statement so that the formatter can be extended. Default is %s + switch (m) { + case '%d': + val = parseFloat(val); + if (isNaN(val)) { + val = 0; + } + break; + } + i++; + } + return val; + }); + } }; export default GeneralUtils; diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index a936294e..0eddcd30 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -1,18 +1,20 @@ import languages from '../constants/languages'; -import template from 'lodash.template'; -let getText = function(s, ...args) { +import GeneralUtils from './general_utils'; + +let getLangText = function(s, ...args) { let lang = navigator.language || navigator.userLanguage; + try { if(lang in languages) { - return languages[lang][s]; + return GeneralUtils.formatText(languages[lang][s], args); } else { // just use the english language - return languages['en-US'][s]; + return GeneralUtils.formatText(languages['en-US'][s], args); } } catch(err) { - console.error(err); + console.error(new Error('Language-string is not in constants file.')); } }; -export default getText; \ No newline at end of file +export default getLangText; \ No newline at end of file From 366fcbf4f3a4ac978f817a56690df1aab5ad9230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 13:42:17 +0200 Subject: [PATCH 05/10] refactor general utils --- js/components/ascribe_table/table_header.js | 1 - js/mixins/table_column_mixin.js | 4 +- js/utils/fetch_api_utils.js | 4 +- js/utils/general_utils.js | 125 +++++++++----------- js/utils/lang_utils.js | 13 +- 5 files changed, 70 insertions(+), 77 deletions(-) diff --git a/js/components/ascribe_table/table_header.js b/js/components/ascribe_table/table_header.js index 8176ad31..44594394 100644 --- a/js/components/ascribe_table/table_header.js +++ b/js/components/ascribe_table/table_header.js @@ -1,7 +1,6 @@ import React from 'react'; import TableColumnMixin from '../../mixins/table_column_mixin'; -import GeneralUtils from '../../utils/general_utils'; import TableHeaderItem from './table_header_item'; import TableColumnContentModel from '../../models/table_column_content_model'; diff --git a/js/mixins/table_column_mixin.js b/js/mixins/table_column_mixin.js index d74214e1..eac266b6 100644 --- a/js/mixins/table_column_mixin.js +++ b/js/mixins/table_column_mixin.js @@ -1,6 +1,6 @@ import React from 'react'; -import GeneralUtils from '../utils/general_utils'; +import { sumNumList } from '../utils/general_utils'; let TableColumnMixin = { /** @@ -11,7 +11,7 @@ let TableColumnMixin = { let bootstrapClasses = ['col-xs-', 'col-sm-', 'col-md-', 'col-lg-']; let listOfRowValues = list.map((column) => column.rowWidth ); - let numOfUsedColumns = GeneralUtils.sumNumList(listOfRowValues); + let numOfUsedColumns = sumNumList(listOfRowValues); if(numOfUsedColumns > numOfColumns) { throw new Error('This table has only ' + numOfColumns + ' columns to assign. You defined ' + numOfUsedColumns + '. Change this in the columnMap you\'re passing to the table.') diff --git a/js/utils/fetch_api_utils.js b/js/utils/fetch_api_utils.js index 47b52e66..ccee8ae5 100644 --- a/js/utils/fetch_api_utils.js +++ b/js/utils/fetch_api_utils.js @@ -1,4 +1,4 @@ -import GeneralUtils from './general_utils'; +import { sanitize } from './general_utils'; // TODO: Create Unittests that test all functions @@ -22,7 +22,7 @@ let FetchApiUtils = { */ argsToQueryParams(obj) { - obj = GeneralUtils.sanitize(obj); + obj = sanitize(obj); return Object .keys(obj) diff --git a/js/utils/general_utils.js b/js/utils/general_utils.js index 14118d94..96f56c1e 100644 --- a/js/utils/general_utils.js +++ b/js/utils/general_utils.js @@ -1,74 +1,63 @@ // TODO: Create Unittests that test all functions -let GeneralUtils = { - /** - * Removes undefined and null values from an key-value object. - */ - sanitize(obj) { - Object - .keys(obj) - .map((key) => { - // By matching null with a double equal, we can match undefined and null - // http://stackoverflow.com/a/15992131 - if(obj[key] == null || obj[key] === '') { - delete obj[key]; - } - }); - - return obj; - }, - - /** - * Returns the values of an object. - */ - valuesOfObject(obj) { - return Object - .keys(obj) - .map(key => obj[key]); - }, - - /** - * Sums up a list of numbers. Like a Epsilon-math-kinda-sum... - */ - sumNumList(l) { - let sum = 0; - l.forEach((num) => sum += parseFloat(num) || 0); - return sum; - }, - - /* - Taken from http://stackoverflow.com/a/4795914/1263876 - Behaves like C's format string function - - Does not throw errors though if a argument's type is not - matching its template's representative!!! - This essentially means you can use %d or %s for anything... - */ - formatText() { - var args = arguments, - string = args[0], - i = 1; - return string.replace(/%((%)|s|d)/g, function (m) { - // m is the matched format, e.g. %s, %d - var val = null; - if (m[2]) { - val = m[2]; - } else { - val = args[i]; - // A switch statement so that the formatter can be extended. Default is %s - switch (m) { - case '%d': - val = parseFloat(val); - if (isNaN(val)) { - val = 0; - } - break; - } - i++; +export function sanitize(obj) { + Object + .keys(obj) + .map((key) => { + // By matching null with a double equal, we can match undefined and null + // http://stackoverflow.com/a/15992131 + if(obj[key] == null || obj[key] === '') { + delete obj[key]; } - return val; }); - } + + return obj; }; -export default GeneralUtils; +/** + * Returns the values of an object. + */ +export function valuesOfObject(obj) { + return Object + .keys(obj) + .map(key => obj[key]); +}; + +/** + * Sums up a list of numbers. Like a Epsilon-math-kinda-sum... + */ +export function sumNumList(l) { + let sum = 0; + l.forEach((num) => sum += parseFloat(num) || 0); + return sum; +}; + +/* + Taken from http://stackoverflow.com/a/4795914/1263876 + Behaves like C's format string function +*/ +export function formatText() { + var args = arguments, + string = args[0], + i = 1; + return string.replace(/%((%)|s|d)/g, function (m) { + // m is the matched format, e.g. %s, %d + var val = null; + if (m[2]) { + val = m[2]; + } else { + val = args[i]; + // A switch statement so that the formatter can be extended. Default is %s + switch (m) { + case '%d': + val = parseFloat(val); + if (isNaN(val)) { + val = 0; + } + break; + } + i++; + } + return val; + }); +}; diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index 0eddcd30..8157caf9 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -1,19 +1,24 @@ import languages from '../constants/languages'; -import GeneralUtils from './general_utils'; +import { formatText } from './general_utils'; let getLangText = function(s, ...args) { let lang = navigator.language || navigator.userLanguage; try { if(lang in languages) { - return GeneralUtils.formatText(languages[lang][s], args); + return formatText(languages[lang][s], args); } else { // just use the english language - return GeneralUtils.formatText(languages['en-US'][s], args); + return formatText(languages['en-US'][s], args); } } catch(err) { - console.error(new Error('Language-string is not in constants file.')); + if(!(s in languages[lang])) { + console.error(new Error('Language-string is not in constants file for string: ' + s)); + } else { + console.error(err); + } + } }; From 347517a0b36a6fb16999ca8e3d24b119f68467fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 13:48:01 +0200 Subject: [PATCH 06/10] refactor all util functions for nicer usability --- .../accordion_list_item_table.js | 2 +- .../accordion_list_item_table_editions.js | 2 +- js/fetchers/edition_fetcher.js | 1 - js/fetchers/piece_list_fetcher.js | 4 +- js/fetchers/user_fetcher.js | 1 - js/utils/fetch.js | 4 +- js/utils/fetch_api_utils.js | 75 +++++++++---------- js/utils/lang_utils.js | 6 +- 8 files changed, 43 insertions(+), 52 deletions(-) diff --git a/js/components/ascribe_accordion_list/accordion_list_item_table.js b/js/components/ascribe_accordion_list/accordion_list_item_table.js index 953fffa1..66eb3baf 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_table.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_table.js @@ -5,7 +5,7 @@ import TableItem from '../ascribe_table/table_item'; import TableColumnContentModel from '../../models/table_column_content_model'; -import getLangText from '../../utils/lang_utils'; +import { getLangText } from '../../utils/lang_utils'; let AccordionListItemTable = React.createClass({ getInitialState() { diff --git a/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js b/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js index 356e5fe0..f14f6016 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_table_editions.js @@ -12,7 +12,7 @@ import TableItemText from '../ascribe_table/table_item_text'; import TableItemCheckbox from '../ascribe_table/table_item_checkbox'; import TableItemAclFiltered from '../ascribe_table/table_item_acl_filtered'; -import getLangText from '../../utils/lang_utils'; +import { getLangText } from '../../utils/lang_utils'; let AccordionListItemTableEditions = React.createClass({ diff --git a/js/fetchers/edition_fetcher.js b/js/fetchers/edition_fetcher.js index 7ce5bdab..46cdf1b7 100644 --- a/js/fetchers/edition_fetcher.js +++ b/js/fetchers/edition_fetcher.js @@ -1,7 +1,6 @@ import fetch from '../utils/fetch'; import AppConstants from '../constants/application_constants'; -import FetchApiUtils from '../utils/fetch_api_utils'; let EditionFetcher = { diff --git a/js/fetchers/piece_list_fetcher.js b/js/fetchers/piece_list_fetcher.js index 9490c6fb..ed867253 100644 --- a/js/fetchers/piece_list_fetcher.js +++ b/js/fetchers/piece_list_fetcher.js @@ -1,5 +1,5 @@ import AppConstants from '../constants/application_constants'; -import FetchApiUtils from '../utils/fetch_api_utils'; +import { generateOrderingQueryParams } from '../utils/fetch_api_utils'; import fetch from '../utils/fetch'; @@ -9,7 +9,7 @@ let PieceListFetcher = { * Can be called with all supplied queryparams the API. */ fetch(page, pageSize, search, orderBy, orderAsc) { - let ordering = FetchApiUtils.generateOrderingQueryParams(orderBy, orderAsc); + let ordering = generateOrderingQueryParams(orderBy, orderAsc); return fetch.get('pieces_list', { page, pageSize, search, ordering }); } }; diff --git a/js/fetchers/user_fetcher.js b/js/fetchers/user_fetcher.js index b5313cd6..df3e887e 100644 --- a/js/fetchers/user_fetcher.js +++ b/js/fetchers/user_fetcher.js @@ -1,7 +1,6 @@ import fetch from '../utils/fetch'; import AppConstants from '../constants/application_constants'; -import FetchApiUtils from '../utils/fetch_api_utils'; let UserFetcher = { diff --git a/js/utils/fetch.js b/js/utils/fetch.js index 37626a71..d533d62d 100644 --- a/js/utils/fetch.js +++ b/js/utils/fetch.js @@ -1,5 +1,5 @@ import { default as _fetch } from 'isomorphic-fetch'; -import FetchApiUtils from '../utils/fetch_api_utils'; +import { argsToQueryParams } from '../utils/fetch_api_utils'; class UrlMapError extends Error {}; @@ -66,7 +66,7 @@ class Fetch { }); if (attachParamsToQuery && params && Object.keys(params).length > 0) { - newUrl += FetchApiUtils.argsToQueryParams(params); + newUrl += argsToQueryParams(params); } return newUrl; diff --git a/js/utils/fetch_api_utils.js b/js/utils/fetch_api_utils.js index ccee8ae5..bf66a45c 100644 --- a/js/utils/fetch_api_utils.js +++ b/js/utils/fetch_api_utils.js @@ -1,8 +1,6 @@ import { sanitize } from './general_utils'; - // TODO: Create Unittests that test all functions -let FetchApiUtils = { /** * Takes a key-value object of this form: @@ -20,48 +18,45 @@ let FetchApiUtils = { * CamelCase gets converted to snake_case! * */ - argsToQueryParams(obj) { +export function argsToQueryParams(obj) { - obj = sanitize(obj); + obj = sanitize(obj); - return Object - .keys(obj) - .map((key, i) => { - let s = ''; + return Object + .keys(obj) + .map((key, i) => { + let s = ''; - if(i === 0) { - s += '?'; - } else { - s += '&'; - } + if(i === 0) { + s += '?'; + } else { + s += '&'; + } - let snakeCaseKey = key.replace(/[A-Z]/, (match) => '_' + match.toLowerCase()); + let snakeCaseKey = key.replace(/[A-Z]/, (match) => '_' + match.toLowerCase()); - return s + snakeCaseKey + '=' + encodeURIComponent(obj[key]); - }) - .join(''); - }, - - /** - * Takes a string and a boolean and generates a string query parameter for - * an API call. - */ - generateOrderingQueryParams(orderBy, orderAsc) { - let interpolation = ''; - - if(!orderAsc) { - interpolation += '-'; - } - - return interpolation + orderBy; - }, - - status(response) { - if (response.status >= 200 && response.status < 300) { - return response - } - throw new Error(response.json()) - } + return s + snakeCaseKey + '=' + encodeURIComponent(obj[key]); + }) + .join(''); }; -export default FetchApiUtils; +/** + * Takes a string and a boolean and generates a string query parameter for + * an API call. + */ +export function generateOrderingQueryParams(orderBy, orderAsc) { + let interpolation = ''; + + if(!orderAsc) { + interpolation += '-'; + } + + return interpolation + orderBy; +}; + +export function status(response) { + if (response.status >= 200 && response.status < 300) { + return response + } + throw new Error(response.json()) +}; diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index 8157caf9..826cf184 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -2,7 +2,7 @@ import languages from '../constants/languages'; import { formatText } from './general_utils'; -let getLangText = function(s, ...args) { +export function getLangText(s, ...args) { let lang = navigator.language || navigator.userLanguage; try { @@ -20,6 +20,4 @@ let getLangText = function(s, ...args) { } } -}; - -export default getLangText; \ No newline at end of file +}; \ No newline at end of file From 3183dae054ab3c0169314a49de79e68711451f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 14:25:26 +0200 Subject: [PATCH 07/10] add german language file and integrated translation method --- .../accordion_list_item.js | 3 ++- .../ascribe_pagination/pagination_button.js | 6 +++-- js/components/header.js | 10 +++++---- js/constants/languages.js | 22 ++++++++++++++++++- js/utils/fetch.js | 2 +- js/utils/lang_utils.js | 1 - 6 files changed, 34 insertions(+), 10 deletions(-) diff --git a/js/components/ascribe_accordion_list/accordion_list_item.js b/js/components/ascribe_accordion_list/accordion_list_item.js index f932b12b..e9bb8742 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item.js +++ b/js/components/ascribe_accordion_list/accordion_list_item.js @@ -2,6 +2,7 @@ import React from 'react'; import AccordionListItemTable from './accordion_list_item_table'; +import { getLangText } from '../../utils/lang_utils'; let AccordionListItem = React.createClass({ propTypes: { @@ -19,7 +20,7 @@ let AccordionListItem = React.createClass({

{this.props.content.title}

-

by {this.props.content.artist_name}

+

{getLangText('by %s', this.props.content.artist_name)}

diff --git a/js/components/ascribe_pagination/pagination_button.js b/js/components/ascribe_pagination/pagination_button.js index ee9c1374..bbb2a789 100644 --- a/js/components/ascribe_pagination/pagination_button.js +++ b/js/components/ascribe_pagination/pagination_button.js @@ -1,6 +1,8 @@ import React from 'react'; import Router from 'react-router'; +import { getLangText } from '../../utils/lang_utils'; + let Link = Router.Link; let PaginationButton = React.createClass({ @@ -25,14 +27,14 @@ let PaginationButton = React.createClass({ page -= 1; directionDisplay = ( - Previous + {getLangText('Previous')} ); } else { page += 1; directionDisplay = ( - Next + {getLangText('Next')} ); } diff --git a/js/components/header.js b/js/components/header.js index 588f73bf..b7a412e0 100644 --- a/js/components/header.js +++ b/js/components/header.js @@ -11,6 +11,8 @@ import NavItem from 'react-bootstrap/lib/NavItem'; import DropdownButton from 'react-bootstrap/lib/DropdownButton'; import MenuItem from 'react-bootstrap/lib/MenuItem'; +import { getLangText } from '../utils/lang_utils'; + let Link = Router.Link; let Header = React.createClass({ @@ -39,12 +41,12 @@ let Header = React.createClass({ diff --git a/js/constants/languages.js b/js/constants/languages.js index c49caf53..5fd15048 100644 --- a/js/constants/languages.js +++ b/js/constants/languages.js @@ -3,7 +3,27 @@ const languages = { 'Bitcoin Address': 'Bitcoin Address', 'Actions': 'Actions', 'Hide all %d Editions': 'Hide all %d Editions', - 'Show all %d Editions': 'Show all %d Editions' + 'Show all %d Editions': 'Show all %d Editions', + 'by %s': 'by %s', + 'Account Settings': 'Account Settings', + 'FAQ': 'FAQ', + 'Terms of Service': 'Terms of Service', + 'Log out': 'Log out', + 'Previous': 'Previous', + 'Next': 'Next' + }, + 'de': { + 'Bitcoin Address': 'Bitcoin Adresse', + 'Actions': 'Aktionen', + 'Hide all %d Editions': 'Zeige all %d Editionen an', + 'Show all %d Editions': 'Verstecke alle %d Editionen', + 'by %s': 'von %s', + 'Account Settings': 'Kontoeinstellungen', + 'FAQ': 'Fragen & Antworten', + 'Terms of Service': 'AGB', + 'Log out': 'Log out', + 'Previous': 'Zurück', + 'Next': 'Weiter' } }; diff --git a/js/utils/fetch.js b/js/utils/fetch.js index d533d62d..038f152f 100644 --- a/js/utils/fetch.js +++ b/js/utils/fetch.js @@ -55,7 +55,7 @@ class Fetch { prepareUrl(url, params, attachParamsToQuery) { let newUrl = this.getUrl(url); let re = /\${(\w+)}/g; - + newUrl = newUrl.replace(re, (match, key) => { let val = params[key] if (!val) { diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index 826cf184..0df598e3 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -4,7 +4,6 @@ import { formatText } from './general_utils'; export function getLangText(s, ...args) { let lang = navigator.language || navigator.userLanguage; - try { if(lang in languages) { return formatText(languages[lang][s], args); From fd0b3c0eadf71add7144e287305d57e5edc14cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 14:29:06 +0200 Subject: [PATCH 08/10] minor stuff --- js/utils/lang_utils.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index 0df598e3..0e94cc72 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -4,6 +4,8 @@ import { formatText } from './general_utils'; export function getLangText(s, ...args) { let lang = navigator.language || navigator.userLanguage; + // this is just for testing, as changing the navigator.language wasn't possible + //lang = 'de'; try { if(lang in languages) { return formatText(languages[lang][s], args); From b5c434aa18b941227d9802f67d6adfdb9b81d4f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 14:33:30 +0200 Subject: [PATCH 09/10] documentation --- js/utils/lang_utils.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index 0e94cc72..fb9ab196 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -2,6 +2,12 @@ import languages from '../constants/languages'; import { formatText } from './general_utils'; +/** + * Is used to translate strings to another language. Basically can be used with C's string format method. + * @param {string} s The string you want to translate + * @param {array} args An array of arguments (essentially JavaScript's this.arguments) that can be used to substitute digits and other strings + * @return {string} The formated string + */ export function getLangText(s, ...args) { let lang = navigator.language || navigator.userLanguage; // this is just for testing, as changing the navigator.language wasn't possible From ff5355f0ee57c4d9fb10998a84644ad6adf949c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 2 Jun 2015 14:43:42 +0200 Subject: [PATCH 10/10] better error messages --- .../ascribe_accordion_list/accordion_list_item_table.js | 5 ++++- js/constants/languages.js | 8 +++++--- js/utils/lang_utils.js | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/js/components/ascribe_accordion_list/accordion_list_item_table.js b/js/components/ascribe_accordion_list/accordion_list_item_table.js index 66eb3baf..45879a07 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_table.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_table.js @@ -76,11 +76,14 @@ let AccordionListItemTableToggle = React.createClass({ }, render() { + let messageShow = this.props.numOfTableItems == 1 ? + getLangText('Show the edition') : + getLangText('Show all %d Editions', this.props.numOfTableItems) return ( - {this.props.show ? getLangText('Hide all %d Editions', this.props.numOfTableItems) : getLangText('Show all %d Editions', this.props.numOfTableItems)} + {this.props.show ? getLangText('Hide') : messageShow} ); } diff --git a/js/constants/languages.js b/js/constants/languages.js index 5fd15048..47e29ee0 100644 --- a/js/constants/languages.js +++ b/js/constants/languages.js @@ -2,7 +2,8 @@ const languages = { 'en-US': { 'Bitcoin Address': 'Bitcoin Address', 'Actions': 'Actions', - 'Hide all %d Editions': 'Hide all %d Editions', + 'Hide': 'Hide', + 'Show the edition': 'Show the edition', 'Show all %d Editions': 'Show all %d Editions', 'by %s': 'by %s', 'Account Settings': 'Account Settings', @@ -15,8 +16,9 @@ const languages = { 'de': { 'Bitcoin Address': 'Bitcoin Adresse', 'Actions': 'Aktionen', - 'Hide all %d Editions': 'Zeige all %d Editionen an', - 'Show all %d Editions': 'Verstecke alle %d Editionen', + 'Hide': 'Verstecke', + 'Show the edition': 'Zeige die Edition', + 'Show all %d Editions': 'Zeige alle %d Editionen an', 'by %s': 'von %s', 'Account Settings': 'Kontoeinstellungen', 'FAQ': 'Fragen & Antworten', diff --git a/js/utils/lang_utils.js b/js/utils/lang_utils.js index fb9ab196..de9f41e5 100644 --- a/js/utils/lang_utils.js +++ b/js/utils/lang_utils.js @@ -11,7 +11,7 @@ import { formatText } from './general_utils'; export function getLangText(s, ...args) { let lang = navigator.language || navigator.userLanguage; // this is just for testing, as changing the navigator.language wasn't possible - //lang = 'de'; + lang = 'de'; try { if(lang in languages) { return formatText(languages[lang][s], args); @@ -21,7 +21,7 @@ export function getLangText(s, ...args) { } } catch(err) { if(!(s in languages[lang])) { - console.error(new Error('Language-string is not in constants file for string: ' + s)); + console.error(new Error('Language-string is not in constants file. Add: "' + s + '" to the "' + lang + '" language file.')); } else { console.error(err); }