-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
586 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
define(['react', './generator', 'globalize/currency'], function (React, generator) { | ||
|
||
'use strict'; | ||
|
||
return generator("formatCurrency", ["value", "currency", "options"]); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
define(['react', './generator', 'globalize/date'], function (React, generator) { | ||
|
||
'use strict'; | ||
|
||
return generator("formatDate", ["value", "options"]); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
define(['react', 'globalize'], function (React, Globalize) { | ||
|
||
'use strict'; | ||
|
||
var commonPropNames = ["elements", "locale"]; | ||
|
||
function capitalizeFirstLetter(string) { | ||
return string.charAt(0).toUpperCase() + string.slice(1); | ||
} | ||
|
||
function omit(set) { | ||
return function(element) { | ||
return set.indexOf(element) === -1; | ||
}; | ||
} | ||
|
||
function generator(fn, localPropNames, options) { | ||
options = options || {}; | ||
var Fn = capitalizeFirstLetter(fn); | ||
var beforeFormat = options.beforeFormat || function() {}; | ||
var afterFormat = options.afterFormat || function(formattedValue) { | ||
return formattedValue; | ||
}; | ||
var globalizePropNames = commonPropNames.concat(localPropNames); | ||
|
||
return React.createClass({ | ||
displayName: Fn, | ||
componentWillMount: function() { | ||
this.setup(this.props); | ||
}, | ||
componentWillReceiveProps: function(nextProps) { | ||
this.setup(nextProps); | ||
}, | ||
setup: function(props) { | ||
this.globalize = props.locale ? Globalize(props.locale) : Globalize; | ||
this.domProps = Object.keys(props).filter(omit(globalizePropNames)).reduce(function(memo, propKey) { | ||
memo[propKey] = props[propKey]; | ||
return memo; | ||
}, {}); | ||
|
||
this.globalizePropValues = localPropNames.map(function(element) { | ||
return props[element]; | ||
}); | ||
this.globalizePropValues[0] = props.children; | ||
|
||
beforeFormat.call(this); | ||
var formattedValue = this.globalize[fn].apply(this.globalize, this.globalizePropValues); | ||
this.value = afterFormat.call(this, formattedValue); | ||
}, | ||
render: function() { | ||
return React.DOM.span(this.domProps, this.value); | ||
} | ||
}); | ||
} | ||
|
||
|
||
return generator; | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
define(['globalize', 'react', './generator', 'globalize/message', 'globalize/plural'], function (Globalize, React, generator) { | ||
|
||
'use strict'; | ||
|
||
function messageSetup(globalize, props, globalizePropValues) { | ||
var defaultMessage; | ||
var children = props.children; | ||
var scope = props.scope; | ||
|
||
function getDefaultMessage(children) { | ||
if (typeof children === "string") { | ||
return children; | ||
} else { | ||
throw new Error("Invalid default message type `" + typeof children + "`"); | ||
} | ||
} | ||
|
||
// Set path - path as props supercedes default value. | ||
if (props.path) { | ||
// Override generator assumption. The generator assumes the globalizePropValues[0] | ||
// (path) and props.children to be mutually exclusive, but this isn't | ||
// true here for messages. Because, it's possible to use props.path (for | ||
// path) and props.children for defaultMessage, which are two different | ||
// variables. | ||
globalizePropValues[0] = props.path; | ||
} else { | ||
// Although the generator had already set globalizePropValues[0] (path) as | ||
// props.children, here its type is checked and its value is sanitized. | ||
defaultMessage = getDefaultMessage(children); | ||
globalizePropValues[0] = sanitizePath(defaultMessage); | ||
} | ||
|
||
// Scope path. | ||
if (scope) { | ||
globalizePropValues[0] = scope + "/" + globalizePropValues[0]; | ||
} | ||
|
||
// Development mode only. | ||
if (process.env.NODE_ENV !== "production") { | ||
var path = props.path ? props.path.split("/") : [globalizePropValues[0]]; | ||
/* eslint-disable no-inner-declarations */ | ||
function getMessage(globalize, path) { | ||
return globalize.cldr.get(["globalize-messages/{bundle}"].concat(path)); | ||
} | ||
|
||
function setMessage(globalize, path, message) { | ||
var data = {}; | ||
function set(data, path, value) { | ||
var i; | ||
var node = data; | ||
var length = path.length; | ||
|
||
for (i = 0; i < length - 1; i++) { | ||
if (!node[path[i]]) { | ||
node[path[i]] = {}; | ||
} | ||
node = node[path[i]]; | ||
} | ||
node[path[i]] = value; | ||
} | ||
set(data, [globalize.cldr.attributes.bundle].concat(path), message); | ||
Globalize.loadMessages(data); | ||
} | ||
/* eslint-enable no-inner-declarations */ | ||
|
||
if (globalize.cldr) { | ||
if (!getMessage(globalize, path)) { | ||
defaultMessage = defaultMessage || getDefaultMessage(children); | ||
setMessage(globalize, path, defaultMessage); | ||
} | ||
} | ||
} | ||
} | ||
|
||
function replaceElements(props, formatted) { | ||
var elements = props.elements; | ||
|
||
function _replaceElements(string, elements) { | ||
if (typeof string !== "string") { | ||
throw new Error("Missing or invalid string `" + string + "` (" + typeof string + ")"); | ||
} | ||
if (typeof elements !== "object") { | ||
throw new Error("Missing or invalid elements `" + elements + "` (" + typeof elements + ")"); | ||
} | ||
|
||
// Given [x, y, z], it returns [x, element, y, element, z]. | ||
function spreadElementsInBetweenItems(array, element) { | ||
var getElement = typeof element === "function" ? element : function() { | ||
return element; | ||
}; | ||
return array.slice(1).reduce(function(ret, item, i) { | ||
ret.push(getElement(i), item); | ||
return ret; | ||
}, [array[0]]); | ||
} | ||
|
||
function splice(sourceArray, start, deleteCount, itemsArray) { | ||
[].splice.apply(sourceArray, [start, deleteCount].concat(itemsArray)); | ||
} | ||
|
||
return Object.keys(elements).reduce(function(ret, key) { | ||
var element = elements[key]; | ||
|
||
ret.forEach(function(string, i) { | ||
var aux, contents, regexp, regexp2; | ||
|
||
// Insert array into the correct ret position. | ||
function replaceRetItem(array) { | ||
splice(ret, i, 1, array); | ||
} | ||
|
||
if (typeof string !== "string") { | ||
return; // continue; | ||
} | ||
|
||
// Empty tags, e.g., `[foo/]`. | ||
aux = string.split("[" + key + "/]"); | ||
if (aux.length > 1) { | ||
aux = spreadElementsInBetweenItems(aux, element); | ||
replaceRetItem(aux); | ||
return; // continue; | ||
} | ||
|
||
// Start-end tags, e.g., `[foo]content[/foo]`. | ||
regexp = new RegExp("\\[" + key + "\\][\\s\\S]*?\\[\\/" + key + "\\]", "g"); | ||
regexp2 = new RegExp("\\[" + key + "\\]([\\s\\S]*?)\\[\\/" + key + "\\]"); | ||
aux = string.split(regexp); | ||
if (aux.length > 1) { | ||
contents = string.match(regexp).map(function(content) { | ||
return content.replace(regexp2, "$1"); | ||
}); | ||
aux = spreadElementsInBetweenItems(aux, function(i) { | ||
return React.cloneElement(element, {}, contents[i]); | ||
}); | ||
replaceRetItem(aux); | ||
} | ||
}); | ||
|
||
return ret; | ||
}, [string]); | ||
} | ||
|
||
|
||
// Elements replacement. | ||
if (elements) { | ||
formatted = React.DOM.span.apply(React.DOM.span, [{}].concat(_replaceElements(formatted, elements))); | ||
} | ||
|
||
return formatted; | ||
} | ||
|
||
function sanitizePath(pathString) { | ||
return pathString.trim().replace(/\{/g, "(").replace(/\}/g, ")").replace(/\//g, "|").replace(/\n/g, " ").replace(/ +/g, " ").replace(/"/g, "'"); | ||
} | ||
|
||
// Overload Globalize's `.formatMessage` to allow default message. | ||
var globalizeMessageFormatter = Globalize.messageFormatter; | ||
Globalize.messageFormatter = Globalize.prototype.messageFormatter = function(pathOrMessage) { | ||
var aux = {}; | ||
var sanitizedPath = sanitizePath(pathOrMessage); | ||
|
||
// Globalize runtime | ||
if (!this.cldr) { | ||
// On runtime, the only way for deciding between using sanitizedPath or | ||
// pathOrMessage as path is by checking which formatter exists. | ||
arguments[0] = sanitizedPath; | ||
aux = globalizeMessageFormatter.apply(this, arguments); | ||
arguments[0] = pathOrMessage; | ||
return aux || globalizeMessageFormatter.apply(this, arguments); | ||
} | ||
|
||
var sanitizedPathExists = this.cldr.get(["globalize-messages/{bundle}", sanitizedPath]) !== undefined; | ||
var pathExists = this.cldr.get(["globalize-messages/{bundle}", pathOrMessage]) !== undefined; | ||
|
||
// Want to distinguish between default message and path value - just checking | ||
// for sanitizedPath won't be enough, because sanitizedPath !== pathOrMessage | ||
// for paths like "salutations/hi". | ||
if (!sanitizedPathExists && !pathExists) { | ||
aux[this.cldr.attributes.bundle] = {}; | ||
aux[this.cldr.attributes.bundle][sanitizedPath] = pathOrMessage; | ||
Globalize.loadMessages(aux); | ||
sanitizedPathExists = true; | ||
} | ||
|
||
arguments[0] = sanitizedPathExists ? sanitizedPath : pathOrMessage; | ||
return globalizeMessageFormatter.apply(this, arguments); | ||
}; | ||
|
||
|
||
return generator("formatMessage", ["path", "variables"], { | ||
beforeFormat: function() { | ||
messageSetup(this.globalize, this.props, this.globalizePropValues); | ||
}, | ||
afterFormat: function(formattedValue) { | ||
return replaceElements(this.props, formattedValue); | ||
} | ||
}); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
define(['react', './generator', 'globalize/number'], function (React, generator) { | ||
|
||
'use strict'; | ||
|
||
return generator("formatNumber", ["value", "options"]); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
define(['react', './generator', 'globalize/relative-time'], function (React, generator) { | ||
|
||
'use strict'; | ||
|
||
return generator("formatRelativeTime", ["value", "unit", "options"]); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
'use strict'; | ||
|
||
var React = require('react'); | ||
var generator = require('./generator'); | ||
|
||
|
||
module.exports = generator("formatCurrency", ["value", "currency", "options"]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
'use strict'; | ||
|
||
var React = require('react'); | ||
var generator = require('./generator'); | ||
|
||
|
||
module.exports = generator("formatDate", ["value", "options"]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
'use strict'; | ||
|
||
var React = require('react'); | ||
var Globalize = require('globalize'); | ||
|
||
var commonPropNames = ["elements", "locale"]; | ||
|
||
function capitalizeFirstLetter(string) { | ||
return string.charAt(0).toUpperCase() + string.slice(1); | ||
} | ||
|
||
function omit(set) { | ||
return function(element) { | ||
return set.indexOf(element) === -1; | ||
}; | ||
} | ||
|
||
function generator(fn, localPropNames, options) { | ||
options = options || {}; | ||
var Fn = capitalizeFirstLetter(fn); | ||
var beforeFormat = options.beforeFormat || function() {}; | ||
var afterFormat = options.afterFormat || function(formattedValue) { | ||
return formattedValue; | ||
}; | ||
var globalizePropNames = commonPropNames.concat(localPropNames); | ||
|
||
return React.createClass({ | ||
displayName: Fn, | ||
componentWillMount: function() { | ||
this.setup(this.props); | ||
}, | ||
componentWillReceiveProps: function(nextProps) { | ||
this.setup(nextProps); | ||
}, | ||
setup: function(props) { | ||
this.globalize = props.locale ? Globalize(props.locale) : Globalize; | ||
this.domProps = Object.keys(props).filter(omit(globalizePropNames)).reduce(function(memo, propKey) { | ||
memo[propKey] = props[propKey]; | ||
return memo; | ||
}, {}); | ||
|
||
this.globalizePropValues = localPropNames.map(function(element) { | ||
return props[element]; | ||
}); | ||
this.globalizePropValues[0] = props.children; | ||
|
||
beforeFormat.call(this); | ||
var formattedValue = this.globalize[fn].apply(this.globalize, this.globalizePropValues); | ||
this.value = afterFormat.call(this, formattedValue); | ||
}, | ||
render: function() { | ||
return React.DOM.span(this.domProps, this.value); | ||
} | ||
}); | ||
} | ||
|
||
module.exports = generator; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
'use strict'; | ||
|
||
var FormatCurrency = require('./currency'); | ||
var FormatDate = require('./date'); | ||
var FormatMessage = require('./message'); | ||
var FormatNumber = require('./number'); | ||
var FormatRelativeTime = require('./relative-time'); | ||
|
||
module.exports = { | ||
FormatCurrency: FormatCurrency, | ||
FormatDate: FormatDate, | ||
FormatMessage: FormatMessage, | ||
FormatNumber: FormatNumber, | ||
FormatRelativeTime: FormatRelativeTime | ||
}; |
Oops, something went wrong.