Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MessageFormat formatters #653

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 25 additions & 54 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ module.exports = function( grunt ) {
paths: {
cldr: "../external/cldrjs/dist/cldr",
"make-plural": "../external/make-plural/make-plural",
messageformat: "../external/messageformat/messageformat",
"messageformat-parser": "../node_modules/messageformat-parser/parser",
"reserved-words": "../node_modules/reserved-words/lib/reserved-words",
"zoned-date-time": "../node_modules/zoned-date-time/src/zoned-date-time"
},
shim: {
Expand All @@ -151,8 +152,7 @@ module.exports = function( grunt ) {
// Only for root id's (the ones in src, not in src's subpaths). Note there's no
// conditional code checking for this type.
onBuildWrite: function( id, path, contents ) {
var messageformat,
name = camelCase( id.replace( /util\/|common\//, "" ) );
var name = camelCase( id.replace( /util\/|common\//, "" ) );

// MakePlural
if ( ( /make-plural/ ).test( id ) ) {
Expand Down Expand Up @@ -200,68 +200,39 @@ module.exports = function( grunt ) {
"/* jshint ignore:end */"
].join( "\n" ) );

// messageformat
} else if ( ( /messageformat/ ).test( id ) ) {
return contents
// messageformat-parser
} else if ( ( /messageformat-parser/.test( id ) ) ) {

// Remove browserify wrappers.
.replace( /^\(function\(f\)\{if\(typeof exports==="object"&&type.*/, "" )
.replace( "},{}],2:[function(require,module,exports){", "" )
.replace( /\},\{"\.\/messageformat-parser":1,"make-plural\/plural.*/, "" )
.replace( /\},\{\}\]\},\{\},\[2\]\)\(2\)[\s\S]*?$/, "" )

// Set `MessageFormat.plurals` and remove `make-plural/plurals`
// completely. This is populated by Globalize on demand.
.replace( /var _cp = \[[\s\S]*?$/, "" )
.replace(
"MessageFormat.plurals = require('make-plural/plurals')",
"MessageFormat.plurals = {}"
)

// Set `MessageFormat._parse`
.replace(
"MessageFormat._parse = require('./messageformat-parser').parse;",
""
)
.replace( /module\.exports = \(function\(\) \{([\s\S]*?)\n\}\)\(\);/, [
"MessageFormat._parse = (function() {",
"$1",
"}()).parse;"
return contents
.replace( /^/, [
"var Parser;",
"/* jshint ignore:start */\n",
"Parser = (function() {"
].join( "\n" ) )
.replace( "module.exports = ", "return " )
.replace( /$/, [
"}());",
"/* jshint ignore:end */"
].join( "\n" ) );

// Remove unused code.
.replace( /if \(!pluralFunc\) \{\n[\s\S]*?\n \}/, "" )
.replace( /if \(!locale\) \{\n[\s\S]*? \}\n/, "this.lc = [locale];" )
.replace( /(MessageFormat\.formatters) = \{[\s\S]*?\n\};/, "$1 = {};" )
.replace( /MessageFormat\.prototype\.setIntlSupport[\s\S]*?\n\};/, "" )
// reserved-words
} else if ( ( /reserved-words/.test( id ) ) ) {

// Wrap everything into a var assignment.
.replace( "module.exports = MessageFormat;", "" )
return contents
.replace( /^/, [
"var MessageFormat;",
"/* jshint ignore:start */",
"MessageFormat = (function() {"
"var reserved;",
"/* jshint ignore:start */\n",
"reserved = (function() {",
"var exports = {};"
].join( "\n" ) )
.replace( "var assert = require\('assert'\);", "" )
.replace( /^\s*assert\(.*;\s*$/gm, "" )
.replace( /$/, [
"return MessageFormat;",
"return exports;",
"}());",
"/* jshint ignore:end */"
].join( "\n" ) );

// message-runtime
} else if ( ( /message-runtime/ ).test( id ) ) {
messageformat = require( "./external/messageformat/messageformat" );
delete messageformat.prototype.runtime.fmt;
delete messageformat.prototype.runtime.pluralFuncs;
contents = contents.replace( "Globalize._messageFormat = {};", [
"/* jshint ignore:start */",
"Globalize._messageFormat = (function() {",
messageformat.prototype.runtime.toString(),
"return {number: number, plural: plural, select: select};",
"}());",
"/* jshint ignore:end */"
].join( "\n" ) );

// ZonedDateTime
} else if ( ( /zoned-date-time/ ).test( id ) ) {
contents = contents.replace(
Expand Down
1 change: 0 additions & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"cldr-data": ">=25",
"es5-shim": "3.4.0",
"make-plural": "eemeli/make-plural.js#3.0.0",
"messageformat": "SlexAxton/messageformat.js#v0.3.0-1",
"qunit": "1.18.0",
"requirejs": "2.1.20",
"requirejs-plugins": "1.0.2",
Expand Down
7 changes: 4 additions & 3 deletions examples/amd-bower/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ require([
"json!cldr-data/supplemental/likelySubtags.json",
"json!cldr-data/supplemental/metaZones.json",
"json!cldr-data/supplemental/plurals.json",
"json!cldr-data/supplemental/ordinals.json",
"json!cldr-data/supplemental/timeData.json",
"json!cldr-data/supplemental/weekData.json",
"json!messages/en.json",
Expand All @@ -54,9 +55,8 @@ require([
"globalize/plural",
"globalize/relative-time",
"globalize/unit"
], function( Globalize, enGregorian, enCurrencies, enDateFields, enNumbers,
enTimeZoneNames, enUnits, currencyData, likelySubtags, metaZones,
pluralsData, timeData, weekData, messages, ianaTzData ) {
], function( Globalize, enGregorian, enCurrencies, enDateFields, enNumbers, enUnits, currencyData,
likelySubtags, pluralsData, ordinalsData, timeData, weekData, messages ) {

var en, like, number;

Expand All @@ -72,6 +72,7 @@ require([
likelySubtags,
metaZones,
pluralsData,
ordinalsData,
timeData,
weekData
);
Expand Down
1 change: 1 addition & 0 deletions examples/node-npm/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Globalize.load(
require( "cldr-data/supplemental/likelySubtags" ),
require( "cldr-data/supplemental/metaZones" ),
require( "cldr-data/supplemental/plurals" ),
require( "cldr-data/supplemental/ordinals" ),
require( "cldr-data/supplemental/timeData" ),
require( "cldr-data/supplemental/weekData" )
);
Expand Down
8 changes: 8 additions & 0 deletions examples/plain-javascript/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,14 @@ <h2>Demo output</h2>
"pluralRule-count-one": "i = 1 and v = 0 @integer 1",
"pluralRule-count-other": " @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …"
}
},
"plurals-type-ordinal": {
"en": {
"pluralRule-count-one": "n % 10 = 1 and n % 100 != 11 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …",
"pluralRule-count-two": "n % 10 = 2 and n % 100 != 12 @integer 2, 22, 32, 42, 52, 62, 72, 82, 102, 1002, …",
"pluralRule-count-few": "n % 10 = 3 and n % 100 != 13 @integer 3, 23, 33, 43, 53, 63, 73, 83, 103, 1003, …",
"pluralRule-count-other": " @integer 0, 4~18, 100, 1000, 10000, 100000, 1000000, …"
}
}
}
});
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@
"matchdep": "0.3.0",
"mocha": "^3.3.0",
"semver": "^5.3.0",
"zoned-date-time": "1.0.0"
"zoned-date-time": "1.0.0",
"messageformat-parser": "^1.0.0",
"reserved-words": "^0.1.1"
},
"commitplease": {
"nohook": true
Expand Down
4 changes: 2 additions & 2 deletions src/common/validate/parameter-type/plural-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ return function( value, name ) {
validateParameterType(
value,
name,
value === undefined || value === "cardinal" || value === "ordinal",
"String \"cardinal\" or \"ordinal\""
value === undefined || value === "cardinal" || value === "ordinal" || value === "both",
"String \"cardinal\" or \"ordinal\" or \"both\""
);
};

Expand Down
9 changes: 8 additions & 1 deletion src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ define([
"./util/object/extend",
"./util/regexp/escape",
"./util/string/pad",
"./util/formatterfn/options",

"cldr/event"
], function( Cldr, createError, formatMessage, runtimeBind, validate, validateCldr,
validateDefaultLocale, validateParameterPresence, validateParameterRange, validateParameterType,
validateParameterTypeLocale, validateParameterTypePlainObject, alwaysArray, alwaysCldr,
isPlainObject, objectExtend, regexpEscape, stringPad ) {
isPlainObject, objectExtend, regexpEscape, stringPad, formatterfnOptions ) {

function validateLikelySubtags( cldr ) {
cldr.once( "get", validateCldr );
Expand Down Expand Up @@ -86,6 +87,12 @@ Globalize.locale = function( locale ) {
return this.cldr;
};

Globalize._messageFmts = {};

Globalize.addMessageFormatterFunction = function( name, fn, options ) {
Globalize._messageFmts[name] = formatterfnOptions( fn, options );
};

/**
* Optimization to avoid duplicating some internal functions across modules.
*/
Expand Down
8 changes: 8 additions & 0 deletions src/currency.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ Globalize.prototype.currencyFormatter = function( currency, options ) {
return returnFn;
};

Globalize.addMessageFormatterFunction( "currency", function( currency, style ) {
var options = {};
if ( style ) {
options.style = style;
}
return this.currencyFormatter( currency, options );
});

/**
* .currencyParser( currency [, options] )
*
Expand Down
22 changes: 21 additions & 1 deletion src/date.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,14 @@ function validateOptionsPreset( options ) {
validateOptionsPresetEach( "datetime", options );
}

var presets = [ "short", "medium", "long", "full" ];

function validateOptionsPresetEach( type, options ) {
var value = options[ type ];
validate(
"E_INVALID_OPTIONS",
"Invalid `{{type}: \"{value}\"}`.",
value === undefined || [ "short", "medium", "long", "full" ].indexOf( value ) !== -1,
value === undefined || presets.indexOf( value ) !== -1,
{ type: type, value: value }
);
}
Expand Down Expand Up @@ -210,6 +212,24 @@ Globalize.prototype.dateToPartsFormatter = function( options ) {
return returnFn;
};

[ "date", "time", "datetime" ].map(function( type ) {
Globalize.addMessageFormatterFunction( type, function( p ) {
var options = {};
if ( p ) {
var trimmed = p.trim();
if ( presets.indexOf( trimmed ) !== -1 ) {
options[type] = trimmed;
} else if ( trimmed.indexOf( "skeleton" ) === 0 && trimmed.indexOf( "," ) !== -1 ) {
var splitArgs = p.split( ",", 2 );
options.skeleton = splitArgs[1].trim();
} else {
options.raw = p;
}
}
return this.dateFormatter( options );
}, { split: false, trim: false });
});

/**
* .dateParser( options )
*
Expand Down
9 changes: 6 additions & 3 deletions src/message-runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ define([
"./common/runtime-key",
"./common/validate/parameter-type/message-variables",
"./core-runtime",
"./message/formatter-fn"
], function( runtimeKey, validateParameterTypeMessageVariables, Globalize, messageFormatterFn ) {
"./message/formatter-fn",
"./message/formatter-runtime"
], function( runtimeKey, validateParameterTypeMessageVariables, Globalize, messageFormatterFn,
messageFormatterRuntime
) {

Globalize._messageFormatterFn = messageFormatterFn;
Globalize._messageFormat = {};
Globalize._messageFormat = new messageFormatterRuntime(); // TODO setStrictNumber
Globalize._validateParameterTypeMessageVariables = validateParameterTypeMessageVariables;

Globalize.messageFormatter =
Expand Down
63 changes: 52 additions & 11 deletions src/message.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
define([
"cldr",
"messageformat",
"./common/create-error",
"./common/create-error/plural-module-presence",
"./common/runtime-bind",
Expand All @@ -12,15 +11,18 @@ define([
"./common/validate/parameter-type",
"./common/validate/parameter-type/plain-object",
"./core",
"./message/compiler",
"./message/formatter-runtime",
"./message/formatter-fn",
"./message/formatter-runtime-bind",
"./util/always-array",

"cldr/event"
], function( Cldr, MessageFormat, createError, createErrorPluralModulePresence, runtimeBind,
], function( Cldr, createError, createErrorPluralModulePresence, runtimeBind,
validateDefaultLocale, validateMessageBundle, validateMessagePresence, validateMessageType,
validateParameterPresence, validateParameterType, validateParameterTypePlainObject, Globalize,
messageFormatterFn, messageFormatterRuntimeBind, alwaysArray ) {
messageCompiler, messageFormatterRuntime, messageFormatterFn, messageFormatterRuntimeBind,
alwaysArray ) {

var slice = [].slice;

Expand Down Expand Up @@ -82,17 +84,56 @@ Globalize.prototype.messageFormatter = function( path ) {
}
validateMessageType( path, message );

// Is plural module present? Yes, use its generator. Nope, use an error generator.
pluralGenerator = this.plural !== undefined ?
this.pluralGenerator() :
createErrorPluralModulePresence;
var compiler = new messageCompiler( this, Globalize._messageFmts );
var formatterSrc = compiler
.compile( message, cldr.locale );

var pluralType = false;
if ( compiler.pluralTypes.cardinal && compiler.pluralTypes.ordinal ) {
pluralType = "both";
} else if ( compiler.pluralTypes.cardinal ) {
pluralType = "cardinal";
} else if ( compiler.pluralTypes.ordinal ) {
pluralType = "ordinal";
}

if ( pluralType !== false ) {

formatter = new MessageFormat( cldr.locale, pluralGenerator ).compile( message );
// Is plural module present? Yes, use its generator. Nope, use an error generator.
pluralGenerator = this.plural !== undefined ?
this.pluralGenerator( { type: pluralType } ) :
createErrorPluralModulePresence;
}

returnFn = messageFormatterFn( formatter );
var runtime = new messageFormatterRuntime( compiler.strictNumberSign );

/* jshint evil:true */
formatter = new Function(
"number, plural, select", messageCompiler.funcname( cldr.locale ),
" var fmt = [].slice.call( arguments, 4 );\n" +
" return " + formatterSrc + "\n"
);

returnFn = messageFormatterFn.apply( this, [
formatter, "call",
runtime.number, runtime.plural, runtime.select, pluralGenerator
].concat( compiler.formatters ) );

var runtimeArgs = [
messageFormatterRuntimeBind(
formatter, formatterSrc, compiler.runtime, pluralType, cldr.locale, compiler.formatters
),
"call"
];

if ( pluralGenerator ) {
runtimeArgs.push( pluralGenerator );
}
runtimeArgs = runtimeArgs.concat(
compiler.formatters
);

runtimeBind( args, cldr, returnFn,
[ messageFormatterRuntimeBind( cldr, formatter ), pluralGenerator ] );
runtimeBind( args, cldr, returnFn, runtimeArgs );

return returnFn;
};
Expand Down
Loading