diff --git a/dist/plotly-locale-en-us.js b/dist/plotly-locale-en-us.js
new file mode 100644
index 00000000000..b091f1616d2
--- /dev/null
+++ b/dist/plotly-locale-en-us.js
@@ -0,0 +1 @@
+Plotly.register({moduleType:"locale",name:"en-US",dictionary:{"Click to enter Colorscale title":"Click to enter Colorscale title"}});
\ No newline at end of file
diff --git a/dist/plotly-locale-en.js b/dist/plotly-locale-en.js
new file mode 100644
index 00000000000..17c53abca69
--- /dev/null
+++ b/dist/plotly-locale-en.js
@@ -0,0 +1 @@
+Plotly.register({moduleType:"locale",name:"en",dictionary:{"Click to enter Colorscale title":"Click to enter Colourscale title"}});
\ No newline at end of file
diff --git a/dist/translation-keys.txt b/dist/translation-keys.txt
new file mode 100644
index 00000000000..42154ee4f3b
--- /dev/null
+++ b/dist/translation-keys.txt
@@ -0,0 +1,56 @@
+Autoscale // components/modebar/buttons.js:139
+Box Select // components/modebar/buttons.js:103
+Click to enter Colorscale title // plots/plots.js:437
+Click to enter Component A title // plots/ternary/ternary.js:386
+Click to enter Component B title // plots/ternary/ternary.js:400
+Click to enter Component C title // plots/ternary/ternary.js:411
+Click to enter Plot title // plot_api/plot_api.js:579
+Click to enter X axis title // plots/plots.js:435
+Click to enter Y axis title // plots/plots.js:436
+Compare data on hover // components/modebar/buttons.js:167
+Double-click on legend to isolate one trace // components/legend/handle_click.js:90
+Double-click to zoom back out // plots/cartesian/dragbox.js:299
+Download plot as a png // components/modebar/buttons.js:52
+Edit in Chart Studio // components/modebar/buttons.js:76
+IE only supports svg. Changing format to svg. // components/modebar/buttons.js:60
+Lasso Select // components/modebar/buttons.js:112
+Orbital rotation // components/modebar/buttons.js:279
+Pan // components/modebar/buttons.js:94
+Produced with Plotly // components/modebar/modebar.js:256
+Reset // components/modebar/buttons.js:432
+Reset axes // components/modebar/buttons.js:148
+Reset camera to default // components/modebar/buttons.js:314
+Reset camera to last save // components/modebar/buttons.js:322
+Reset view // components/modebar/buttons.js:583
+Reset views // components/modebar/buttons.js:529
+Show closest data on hover // components/modebar/buttons.js:157
+Snapshot succeeded // components/modebar/buttons.js:66
+Sorry, there was a problem downloading your snapshot! // components/modebar/buttons.js:69
+Taking snapshot - this may take a few seconds // components/modebar/buttons.js:57
+Toggle Spike Lines // components/modebar/buttons.js:548
+Toggle show closest data on hover // components/modebar/buttons.js:353
+Turntable rotation // components/modebar/buttons.js:288
+Zoom // components/modebar/buttons.js:85
+Zoom in // components/modebar/buttons.js:121
+Zoom out // components/modebar/buttons.js:130
+close: // traces/ohlc/transform.js:139
+high: // traces/ohlc/transform.js:137
+incoming flow count: // traces/sankey/plot.js:142
+kde: // traces/violin/calc.js:73
+lat: // traces/scattergeo/calc.js:48
+lon: // traces/scattergeo/calc.js:49
+low: // traces/ohlc/transform.js:138
+lower fence: // traces/box/calc.js:134
+max: // traces/box/calc.js:132
+mean ± σ: // traces/box/calc.js:133
+mean: // traces/box/calc.js:133
+median: // traces/box/calc.js:128
+min: // traces/box/calc.js:129
+open: // traces/ohlc/transform.js:136
+outgoing flow count: // traces/sankey/plot.js:143
+q1: // traces/box/calc.js:130
+q3: // traces/box/calc.js:131
+source: // traces/sankey/plot.js:140
+target: // traces/sankey/plot.js:141
+trace // plots/plots.js:439
+upper fence: // traces/box/calc.js:135
\ No newline at end of file
diff --git a/lib/index-basic.js b/lib/index-basic.js
index 4c837e413ad..6bf47b0d84a 100644
--- a/lib/index-basic.js
+++ b/lib/index-basic.js
@@ -15,4 +15,10 @@ Plotly.register([
require('./pie')
]);
+// locales
+Plotly.register([
+ require('./locale-en'),
+ require('./locale-en-us')
+]);
+
module.exports = Plotly;
diff --git a/lib/index-cartesian.js b/lib/index-cartesian.js
index 5818a717748..6dc20783571 100644
--- a/lib/index-cartesian.js
+++ b/lib/index-cartesian.js
@@ -23,4 +23,10 @@ Plotly.register([
require('./violin')
]);
+// locales
+Plotly.register([
+ require('./locale-en'),
+ require('./locale-en-us')
+]);
+
module.exports = Plotly;
diff --git a/lib/index-finance.js b/lib/index-finance.js
index 4759344b760..f53dee82c9f 100644
--- a/lib/index-finance.js
+++ b/lib/index-finance.js
@@ -18,4 +18,10 @@ Plotly.register([
require('./candlestick')
]);
+// locales
+Plotly.register([
+ require('./locale-en'),
+ require('./locale-en-us')
+]);
+
module.exports = Plotly;
diff --git a/lib/index-geo.js b/lib/index-geo.js
index 2283f1f0489..40dec26e9e9 100644
--- a/lib/index-geo.js
+++ b/lib/index-geo.js
@@ -15,4 +15,10 @@ Plotly.register([
require('./choropleth')
]);
+// locales
+Plotly.register([
+ require('./locale-en'),
+ require('./locale-en-us')
+]);
+
module.exports = Plotly;
diff --git a/lib/index-gl2d.js b/lib/index-gl2d.js
index 9c24ec21267..31128063e7a 100644
--- a/lib/index-gl2d.js
+++ b/lib/index-gl2d.js
@@ -18,4 +18,10 @@ Plotly.register([
require('./parcoords')
]);
+// locales
+Plotly.register([
+ require('./locale-en'),
+ require('./locale-en-us')
+]);
+
module.exports = Plotly;
diff --git a/lib/index-gl3d.js b/lib/index-gl3d.js
index 7134846cb7d..b7a635e27f9 100644
--- a/lib/index-gl3d.js
+++ b/lib/index-gl3d.js
@@ -16,4 +16,10 @@ Plotly.register([
require('./mesh3d')
]);
+// locales
+Plotly.register([
+ require('./locale-en'),
+ require('./locale-en-us')
+]);
+
module.exports = Plotly;
diff --git a/lib/index-mapbox.js b/lib/index-mapbox.js
index 17b075b5f49..9c6ed2b4bf3 100644
--- a/lib/index-mapbox.js
+++ b/lib/index-mapbox.js
@@ -14,4 +14,10 @@ Plotly.register([
require('./scattermapbox')
]);
+// locales
+Plotly.register([
+ require('./locale-en'),
+ require('./locale-en-us')
+]);
+
module.exports = Plotly;
diff --git a/lib/index.js b/lib/index.js
index 7dac73a1f64..131ff4e8511 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -71,4 +71,10 @@ Plotly.register([
require('./calendars')
]);
+// locales
+Plotly.register([
+ require('./locale-en.js'),
+ require('./locale-en-us.js')
+]);
+
module.exports = Plotly;
diff --git a/lib/locale-en-us.js b/lib/locale-en-us.js
new file mode 100644
index 00000000000..97996970ae0
--- /dev/null
+++ b/lib/locale-en-us.js
@@ -0,0 +1,17 @@
+/**
+* Copyright 2012-2017, Plotly, Inc.
+* All rights reserved.
+*
+* This source code is licensed under the MIT license found in the
+* LICENSE file in the root directory of this source tree.
+*/
+
+'use strict';
+
+module.exports = {
+ moduleType: 'locale',
+ name: 'en-US',
+ dictionary: {
+ 'Click to enter Colorscale title': 'Click to enter Colorscale title'
+ }
+};
diff --git a/lib/locale-en.js b/lib/locale-en.js
new file mode 100644
index 00000000000..ead5a904c11
--- /dev/null
+++ b/lib/locale-en.js
@@ -0,0 +1,17 @@
+/**
+* Copyright 2012-2017, Plotly, Inc.
+* All rights reserved.
+*
+* This source code is licensed under the MIT license found in the
+* LICENSE file in the root directory of this source tree.
+*/
+
+'use strict';
+
+module.exports = {
+ moduleType: 'locale',
+ name: 'en',
+ dictionary: {
+ 'Click to enter Colorscale title': 'Click to enter Colourscale title'
+ }
+};
diff --git a/package.json b/package.json
index 1f15d00c564..788d6af96b7 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,8 @@
"bundle": "node tasks/bundle.js",
"header": "node tasks/header.js",
"stats": "node tasks/stats.js",
- "build": "npm run preprocess && npm run bundle && npm run header && npm run stats",
+ "find-strings": "node tasks/find_locale_strings.js",
+ "build": "npm run preprocess && npm run find-strings && npm run bundle && npm run header && npm run stats",
"cibuild": "npm run preprocess && node tasks/cibundle.js",
"watch": "node tasks/watch.js",
"lint": "eslint --version && eslint .",
@@ -36,7 +37,7 @@
"test-image": "node tasks/test_image.js",
"test-image-gl2d": "node tasks/test_image.js gl2d_* --queue",
"test-export": "node tasks/test_export.js",
- "test-syntax": "node tasks/test_syntax.js",
+ "test-syntax": "node tasks/test_syntax.js && npm run find-strings",
"test-bundle": "node tasks/test_bundle.js",
"test": "npm run test-jasmine && npm run test-bundle && npm run test-image && npm run test-image-gl2d && npm run test-syntax && npm run lint",
"start-test_dashboard": "node devtools/test_dashboard/server.js",
@@ -121,6 +122,7 @@
"glslify": "^4.0.0",
"gzip-size": "^3.0.0",
"image-size": "^0.5.1",
+ "into-stream": "^3.1.0",
"jasmine-core": "^2.4.1",
"jsdom": "^11.2.0",
"karma": "^1.5.0",
diff --git a/src/components/colorbar/attributes.js b/src/components/colorbar/attributes.js
index aa2c456c9de..197bfa3553f 100644
--- a/src/components/colorbar/attributes.js
+++ b/src/components/colorbar/attributes.js
@@ -177,7 +177,6 @@ module.exports = overrideAll({
title: {
valType: 'string',
role: 'info',
- dflt: 'Click to enter colorscale title',
description: 'Sets the title of the color bar.'
},
titlefont: fontAttrs({
diff --git a/src/components/colorbar/defaults.js b/src/components/colorbar/defaults.js
index be767c67524..469a6528102 100644
--- a/src/components/colorbar/defaults.js
+++ b/src/components/colorbar/defaults.js
@@ -59,7 +59,7 @@ module.exports = function colorbarDefaults(containerIn, containerOut, layout) {
handleTickMarkDefaults(colorbarIn, colorbarOut, coerce, 'linear',
{outerTicks: false, font: layout.font, noHover: true});
- coerce('title');
+ coerce('title', layout._dfltTitle.colorbar);
Lib.coerceFont(coerce, 'titlefont', layout.font);
coerce('titleside');
};
diff --git a/src/components/colorbar/draw.js b/src/components/colorbar/draw.js
index d584c134fa8..57f853006da 100644
--- a/src/components/colorbar/draw.js
+++ b/src/components/colorbar/draw.js
@@ -455,7 +455,7 @@ module.exports = function draw(gd, id) {
propContainer: cbAxisOut,
propName: propName,
traceIndex: trace.index,
- dfltName: 'colorscale',
+ placeholder: fullLayout._dfltTitle.colorbar,
containerGroup: container.select('.cbtitle')
};
diff --git a/src/components/legend/handle_click.js b/src/components/legend/handle_click.js
index 46ce749f16f..933c63f388b 100644
--- a/src/components/legend/handle_click.js
+++ b/src/components/legend/handle_click.js
@@ -87,7 +87,7 @@ module.exports = function handleClick(g, gd, numClicks) {
}
if(numClicks === 1 && SHOWISOLATETIP && gd.data && gd._context.showTips) {
- Lib.notifier('Double click on legend to isolate individual trace', 'long');
+ Lib.notifier(Lib._(gd, 'Double-click on legend to isolate one trace'), 'long');
SHOWISOLATETIP = false;
} else {
SHOWISOLATETIP = false;
diff --git a/src/components/modebar/buttons.js b/src/components/modebar/buttons.js
index 0008398bfdd..681516f5b86 100644
--- a/src/components/modebar/buttons.js
+++ b/src/components/modebar/buttons.js
@@ -17,6 +17,8 @@ var downloadImage = require('../../snapshot/download');
var Icons = require('../../../build/ploticon');
+var _ = Lib._;
+
var modeBarButtons = module.exports = {};
/**
@@ -47,31 +49,31 @@ var modeBarButtons = module.exports = {};
modeBarButtons.toImage = {
name: 'toImage',
- title: 'Download plot as a png',
+ title: function(gd) { return _(gd, 'Download plot as a png'); },
icon: Icons.camera,
click: function(gd) {
var format = 'png';
- Lib.notifier('Taking snapshot - this may take a few seconds', 'long');
+ Lib.notifier(_(gd, 'Taking snapshot - this may take a few seconds'), 'long');
if(Lib.isIE()) {
- Lib.notifier('IE only supports svg. Changing format to svg.', 'long');
+ Lib.notifier(_(gd, 'IE only supports svg. Changing format to svg.'), 'long');
format = 'svg';
}
downloadImage(gd, {'format': format})
.then(function(filename) {
- Lib.notifier('Snapshot succeeded - ' + filename, 'long');
+ Lib.notifier(_(gd, 'Snapshot succeeded') + ' - ' + filename, 'long');
})
.catch(function() {
- Lib.notifier('Sorry there was a problem downloading your snapshot!', 'long');
+ Lib.notifier(_(gd, 'Sorry, there was a problem downloading your snapshot!'), 'long');
});
}
};
modeBarButtons.sendDataToCloud = {
name: 'sendDataToCloud',
- title: 'Edit in Chart Studio',
+ title: function(gd) { return _(gd, 'Edit in Chart Studio'); },
icon: Icons.disk,
click: function(gd) {
Plots.sendDataToCloud(gd);
@@ -80,7 +82,7 @@ modeBarButtons.sendDataToCloud = {
modeBarButtons.zoom2d = {
name: 'zoom2d',
- title: 'Zoom',
+ title: function(gd) { return _(gd, 'Zoom'); },
attr: 'dragmode',
val: 'zoom',
icon: Icons.zoombox,
@@ -89,7 +91,7 @@ modeBarButtons.zoom2d = {
modeBarButtons.pan2d = {
name: 'pan2d',
- title: 'Pan',
+ title: function(gd) { return _(gd, 'Pan'); },
attr: 'dragmode',
val: 'pan',
icon: Icons.pan,
@@ -98,7 +100,7 @@ modeBarButtons.pan2d = {
modeBarButtons.select2d = {
name: 'select2d',
- title: 'Box Select',
+ title: function(gd) { return _(gd, 'Box Select'); },
attr: 'dragmode',
val: 'select',
icon: Icons.selectbox,
@@ -107,7 +109,7 @@ modeBarButtons.select2d = {
modeBarButtons.lasso2d = {
name: 'lasso2d',
- title: 'Lasso Select',
+ title: function(gd) { return _(gd, 'Lasso Select'); },
attr: 'dragmode',
val: 'lasso',
icon: Icons.lasso,
@@ -116,7 +118,7 @@ modeBarButtons.lasso2d = {
modeBarButtons.zoomIn2d = {
name: 'zoomIn2d',
- title: 'Zoom in',
+ title: function(gd) { return _(gd, 'Zoom in'); },
attr: 'zoom',
val: 'in',
icon: Icons.zoom_plus,
@@ -125,7 +127,7 @@ modeBarButtons.zoomIn2d = {
modeBarButtons.zoomOut2d = {
name: 'zoomOut2d',
- title: 'Zoom out',
+ title: function(gd) { return _(gd, 'Zoom out'); },
attr: 'zoom',
val: 'out',
icon: Icons.zoom_minus,
@@ -134,7 +136,7 @@ modeBarButtons.zoomOut2d = {
modeBarButtons.autoScale2d = {
name: 'autoScale2d',
- title: 'Autoscale',
+ title: function(gd) { return _(gd, 'Autoscale'); },
attr: 'zoom',
val: 'auto',
icon: Icons.autoscale,
@@ -143,7 +145,7 @@ modeBarButtons.autoScale2d = {
modeBarButtons.resetScale2d = {
name: 'resetScale2d',
- title: 'Reset axes',
+ title: function(gd) { return _(gd, 'Reset axes'); },
attr: 'zoom',
val: 'reset',
icon: Icons.home,
@@ -152,7 +154,7 @@ modeBarButtons.resetScale2d = {
modeBarButtons.hoverClosestCartesian = {
name: 'hoverClosestCartesian',
- title: 'Show closest data on hover',
+ title: function(gd) { return _(gd, 'Show closest data on hover'); },
attr: 'hovermode',
val: 'closest',
icon: Icons.tooltip_basic,
@@ -162,7 +164,7 @@ modeBarButtons.hoverClosestCartesian = {
modeBarButtons.hoverCompareCartesian = {
name: 'hoverCompareCartesian',
- title: 'Compare data on hover',
+ title: function(gd) { return _(gd, 'Compare data on hover'); },
attr: 'hovermode',
val: function(gd) {
return gd._fullLayout._isHoriz ? 'y' : 'x';
@@ -256,7 +258,7 @@ function handleCartesian(gd, ev) {
modeBarButtons.zoom3d = {
name: 'zoom3d',
- title: 'Zoom',
+ title: function(gd) { return _(gd, 'Zoom'); },
attr: 'scene.dragmode',
val: 'zoom',
icon: Icons.zoombox,
@@ -265,7 +267,7 @@ modeBarButtons.zoom3d = {
modeBarButtons.pan3d = {
name: 'pan3d',
- title: 'Pan',
+ title: function(gd) { return _(gd, 'Pan'); },
attr: 'scene.dragmode',
val: 'pan',
icon: Icons.pan,
@@ -274,7 +276,7 @@ modeBarButtons.pan3d = {
modeBarButtons.orbitRotation = {
name: 'orbitRotation',
- title: 'orbital rotation',
+ title: function(gd) { return _(gd, 'Orbital rotation'); },
attr: 'scene.dragmode',
val: 'orbit',
icon: Icons['3d_rotate'],
@@ -283,7 +285,7 @@ modeBarButtons.orbitRotation = {
modeBarButtons.tableRotation = {
name: 'tableRotation',
- title: 'turntable rotation',
+ title: function(gd) { return _(gd, 'Turntable rotation'); },
attr: 'scene.dragmode',
val: 'turntable',
icon: Icons['z-axis'],
@@ -309,7 +311,7 @@ function handleDrag3d(gd, ev) {
modeBarButtons.resetCameraDefault3d = {
name: 'resetCameraDefault3d',
- title: 'Reset camera to default',
+ title: function(gd) { return _(gd, 'Reset camera to default'); },
attr: 'resetDefault',
icon: Icons.home,
click: handleCamera3d
@@ -317,7 +319,7 @@ modeBarButtons.resetCameraDefault3d = {
modeBarButtons.resetCameraLastSave3d = {
name: 'resetCameraLastSave3d',
- title: 'Reset camera to last save',
+ title: function(gd) { return _(gd, 'Reset camera to last save'); },
attr: 'resetLastSave',
icon: Icons.movie,
click: handleCamera3d
@@ -348,7 +350,7 @@ function handleCamera3d(gd, ev) {
modeBarButtons.hoverClosest3d = {
name: 'hoverClosest3d',
- title: 'Toggle show closest data on hover',
+ title: function(gd) { return _(gd, 'Toggle show closest data on hover'); },
attr: 'hovermode',
val: null,
toggle: true,
@@ -409,7 +411,7 @@ function handleHover3d(gd, ev) {
modeBarButtons.zoomInGeo = {
name: 'zoomInGeo',
- title: 'Zoom in',
+ title: function(gd) { return _(gd, 'Zoom in'); },
attr: 'zoom',
val: 'in',
icon: Icons.zoom_plus,
@@ -418,7 +420,7 @@ modeBarButtons.zoomInGeo = {
modeBarButtons.zoomOutGeo = {
name: 'zoomOutGeo',
- title: 'Zoom out',
+ title: function(gd) { return _(gd, 'Zoom out'); },
attr: 'zoom',
val: 'out',
icon: Icons.zoom_minus,
@@ -427,7 +429,7 @@ modeBarButtons.zoomOutGeo = {
modeBarButtons.resetGeo = {
name: 'resetGeo',
- title: 'Reset',
+ title: function(gd) { return _(gd, 'Reset'); },
attr: 'reset',
val: null,
icon: Icons.autoscale,
@@ -436,7 +438,7 @@ modeBarButtons.resetGeo = {
modeBarButtons.hoverClosestGeo = {
name: 'hoverClosestGeo',
- title: 'Toggle show closest data on hover',
+ title: function(gd) { return _(gd, 'Toggle show closest data on hover'); },
attr: 'hovermode',
val: null,
toggle: true,
@@ -469,7 +471,7 @@ function handleGeo(gd, ev) {
modeBarButtons.hoverClosestGl2d = {
name: 'hoverClosestGl2d',
- title: 'Toggle show closest data on hover',
+ title: function(gd) { return _(gd, 'Toggle show closest data on hover'); },
attr: 'hovermode',
val: null,
toggle: true,
@@ -480,7 +482,7 @@ modeBarButtons.hoverClosestGl2d = {
modeBarButtons.hoverClosestPie = {
name: 'hoverClosestPie',
- title: 'Toggle show closest data on hover',
+ title: function(gd) { return _(gd, 'Toggle show closest data on hover'); },
attr: 'hovermode',
val: 'closest',
icon: Icons.tooltip_basic,
@@ -506,7 +508,7 @@ function toggleHover(gd) {
modeBarButtons.toggleHover = {
name: 'toggleHover',
- title: 'Toggle show closest data on hover',
+ title: function(gd) { return _(gd, 'Toggle show closest data on hover'); },
attr: 'hovermode',
val: null,
toggle: true,
@@ -524,7 +526,7 @@ modeBarButtons.toggleHover = {
modeBarButtons.resetViews = {
name: 'resetViews',
- title: 'Reset views',
+ title: function(gd) { return _(gd, 'Reset views'); },
icon: Icons.home,
click: function(gd, ev) {
var button = ev.currentTarget;
@@ -543,7 +545,7 @@ modeBarButtons.resetViews = {
modeBarButtons.toggleSpikelines = {
name: 'toggleSpikelines',
- title: 'Toggle Spike Lines',
+ title: function(gd) { return _(gd, 'Toggle Spike Lines'); },
icon: Icons.spikeline,
attr: '_cartesianSpikesEnabled',
val: 'on',
@@ -578,7 +580,7 @@ function setSpikelineVisibility(gd) {
modeBarButtons.resetViewMapbox = {
name: 'resetViewMapbox',
- title: 'Reset view',
+ title: function(gd) { return _(gd, 'Reset view'); },
attr: 'reset',
icon: Icons.home,
click: function(gd) {
diff --git a/src/components/modebar/modebar.js b/src/components/modebar/modebar.js
index 5e87b2413a8..9f0ae02f64d 100644
--- a/src/components/modebar/modebar.js
+++ b/src/components/modebar/modebar.js
@@ -123,6 +123,9 @@ proto.createButton = function(config) {
var title = config.title;
if(title === undefined) title = config.name;
+ // for localization: allow title to be a callable that takes gd as arg
+ else if(typeof title === 'function') title = title(this.graphInfo);
+
if(title || title === 0) button.setAttribute('data-title', title);
if(config.attr !== undefined) button.setAttribute('data-attr', config.attr);
@@ -250,7 +253,7 @@ proto.getLogo = function() {
a.href = 'https://plot.ly/';
a.target = '_blank';
- a.setAttribute('data-title', 'Produced with Plotly');
+ a.setAttribute('data-title', Lib._(this.graphInfo, 'Produced with Plotly'));
a.className = 'modebar-btn plotlyjsicon modebar-btn--logo';
a.appendChild(this.createIcon(Icons.plotlylogo));
diff --git a/src/components/rangeslider/draw.js b/src/components/rangeslider/draw.js
index 0e68681356b..54d41e84952 100644
--- a/src/components/rangeslider/draw.js
+++ b/src/components/rangeslider/draw.js
@@ -372,7 +372,8 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
width: opts._width,
height: opts._height,
margin: { t: 0, b: 0, l: 0, r: 0 }
- }
+ },
+ _context: gd._context
};
mockFigure.layout[oppAxisName] = {
diff --git a/src/components/titles/index.js b/src/components/titles/index.js
index a2819784c7b..ad7a6eb17b0 100644
--- a/src/components/titles/index.js
+++ b/src/components/titles/index.js
@@ -20,10 +20,10 @@ var Color = require('../color');
var svgTextUtils = require('../../lib/svg_text_utils');
var interactConstants = require('../../constants/interactions');
-var PLACEHOLDER_RE = /Click to enter .+ title/;
-
var Titles = module.exports = {};
+var numStripRE = / [XY][0-9]* /;
+
/**
* Titles - (re)draw titles on the axes and plot:
* @param {DOM element} gd - the graphDiv
@@ -35,7 +35,7 @@ var Titles = module.exports = {};
* [traceIndex] - include only if this property applies to one trace
* (such as a colorbar title) - then editing pipes to Plotly.restyle
* instead of Plotly.relayout
- * dfltName - the name of the title in placeholder text
+ * placeholder - placeholder text for an empty editable title
* [avoid] {object} - include if this title should move to avoid other elements
* selection - d3 selection of elements to avoid
* side - which direction to move if there is a conflict
@@ -55,8 +55,8 @@ var Titles = module.exports = {};
Titles.draw = function(gd, titleClass, options) {
var cont = options.propContainer;
var prop = options.propName;
+ var placeholder = options.placeholder;
var traceIndex = options.traceIndex;
- var name = options.dfltName;
var avoid = options.avoid || {};
var attributes = options.attributes;
var transform = options.transform;
@@ -80,7 +80,11 @@ Titles.draw = function(gd, titleClass, options) {
var editable = gd._context.edits[editAttr];
if(txt === '') opacity = 0;
- if(txt.match(PLACEHOLDER_RE)) {
+ // look for placeholder text while stripping out numbers from eg X2, Y3
+ // this is just for backward compatibility with the old version that had
+ // "Click to enter X2 title" and may have gotten saved in some old plots,
+ // we don't want this to show up when these are displayed.
+ else if(txt.replace(numStripRE, ' % ') === placeholder.replace(numStripRE, ' % ')) {
opacity = 0.2;
isplaceholder = true;
if(!editable) txt = '';
@@ -199,13 +203,10 @@ Titles.draw = function(gd, titleClass, options) {
el.call(titleLayout);
- var placeholderText = 'Click to enter ' + name + ' title';
-
function setPlaceholder() {
opacity = 0;
isplaceholder = true;
- txt = placeholderText;
- el.text(txt)
+ el.text(placeholder)
.on('mouseover.opacity', function() {
d3.select(this).transition()
.duration(interactConstants.SHOW_PLACEHOLDER).style('opacity', 1);
diff --git a/src/lib/dates.js b/src/lib/dates.js
index c5c05fcfda9..7b959c1c2c4 100644
--- a/src/lib/dates.js
+++ b/src/lib/dates.js
@@ -12,7 +12,7 @@
var d3 = require('d3');
var isNumeric = require('fast-isnumeric');
-var logError = require('./loggers').error;
+var Loggers = require('./loggers');
var mod = require('./mod');
var constants = require('../constants/numerical');
@@ -340,7 +340,7 @@ exports.cleanDate = function(v, dflt, calendar) {
// do not allow milliseconds (old) or jsdate objects (inherently
// described as gregorian dates) with world calendars
if(isWorldCalendar(calendar)) {
- logError('JS Dates and milliseconds are incompatible with world calendars', v);
+ Loggers.error('JS Dates and milliseconds are incompatible with world calendars', v);
return dflt;
}
@@ -351,7 +351,7 @@ exports.cleanDate = function(v, dflt, calendar) {
if(!v && dflt !== undefined) return dflt;
}
else if(!exports.isDateTime(v, calendar)) {
- logError('unrecognized date', v);
+ Loggers.error('unrecognized date', v);
return dflt;
}
return v;
@@ -551,7 +551,7 @@ exports.incrementMonth = function(ms, dMonth, calendar) {
return (cDate.toJD() - EPOCHJD) * ONEDAY + timeMs;
}
catch(e) {
- logError('invalid ms ' + ms + ' in calendar ' + calendar);
+ Loggers.error('invalid ms ' + ms + ' in calendar ' + calendar);
// then keep going in gregorian even though the result will be 'Invalid'
}
}
diff --git a/src/lib/geo_location_utils.js b/src/lib/geo_location_utils.js
index 9d1620e13c9..3879355f104 100644
--- a/src/lib/geo_location_utils.js
+++ b/src/lib/geo_location_utils.js
@@ -34,7 +34,7 @@ exports.locationToFeature = function(locationmode, location, features) {
if(feature.id === locationId) return feature;
}
- Lib.warn([
+ Lib.log([
'Location with id', locationId,
'does not have a matching topojson feature at this resolution.'
].join(' '));
@@ -56,7 +56,7 @@ function countryNameToISO3(countryName) {
if(regex.test(countryName.trim().toLowerCase())) return iso3;
}
- Lib.warn('Unrecognized country name: ' + countryName + '.');
+ Lib.log('Unrecognized country name: ' + countryName + '.');
return false;
}
diff --git a/src/lib/index.js b/src/lib/index.js
index 2912bfdb642..88c7cc495c9 100644
--- a/src/lib/index.js
+++ b/src/lib/index.js
@@ -106,6 +106,8 @@ lib.clearThrottle = throttleModule.clear;
lib.getGraphDiv = require('./get_graph_div');
+lib._ = require('./localize');
+
lib.notifier = require('./notifier');
lib.filterUnique = require('./filter_unique');
diff --git a/src/lib/localize.js b/src/lib/localize.js
new file mode 100644
index 00000000000..4a5e367c12c
--- /dev/null
+++ b/src/lib/localize.js
@@ -0,0 +1,54 @@
+/**
+* Copyright 2012-2017, Plotly, Inc.
+* All rights reserved.
+*
+* This source code is licensed under the MIT license found in the
+* LICENSE file in the root directory of this source tree.
+*/
+
+
+'use strict';
+
+var Registry = require('../registry');
+
+/**
+ * localize: translate a string for the current locale
+ *
+ * @param {object} gd: the graphDiv for context
+ * gd._context.locale determines the language (& optional region/country)
+ * the dictionary for each locale may either be supplied in
+ * gd._context.dictionaries or globally via Plotly.register
+ * @param {string} s: the string to translate
+ */
+module.exports = function localize(gd, s) {
+ var locale = gd._context.locale;
+
+ /*
+ * Priority of lookup:
+ * contextDicts[locale],
+ * registeredDicts[locale],
+ * contextDicts[baseLocale], (if baseLocale is distinct)
+ * registeredDicts[baseLocale]
+ * Return the first translation we find.
+ * This way if you have a regionalization you are allowed to specify
+ * only what's different from the base locale, everything else will
+ * fall back on the base.
+ */
+ for(var i = 0; i < 2; i++) {
+ var dicts = gd._context.dictionaries;
+ for(var j = 0; j < 2; j++) {
+ var dict = dicts[locale];
+ if(dict) {
+ var out = dict[s];
+ if(out) return out;
+ }
+ dicts = Registry.localeRegistry;
+ }
+
+ var baseLocale = locale.split('-')[0];
+ if(baseLocale === locale) break;
+ locale = baseLocale;
+ }
+
+ return s;
+};
diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js
index 205994bf1a6..22016271911 100644
--- a/src/plot_api/plot_api.js
+++ b/src/plot_api/plot_api.js
@@ -565,7 +565,6 @@ function plotPolar(gd, data, layout) {
var opacity = 1;
var txt = gd._fullLayout.title;
if(txt === '' || !txt) opacity = 0;
- var placeholderText = 'Click to enter title';
var titleLayout = function() {
this.call(svgTextUtils.convertToTspans, gd);
@@ -577,6 +576,7 @@ function plotPolar(gd, data, layout) {
.call(titleLayout);
if(gd._context.edits.titleText) {
+ var placeholderText = Lib._(gd, 'Click to enter Plot title');
if(!txt || txt === placeholderText) {
opacity = 0.2;
// placeholder is not going through convertToTspans
diff --git a/src/plot_api/plot_config.js b/src/plot_api/plot_config.js
index 27f4735a24e..b1663e6b9ac 100644
--- a/src/plot_api/plot_config.js
+++ b/src/plot_api/plot_config.js
@@ -122,9 +122,26 @@ module.exports = {
// Turn all console logging on or off (errors will be thrown)
// This should ONLY be set via Plotly.setPlotConfig
- logging: false,
+ // 0: no logs
+ // 1: warnings and errors, but not informational messages
+ // 2: verbose logs
+ logging: 1,
// Set global transform to be applied to all traces with no
// specification needed
- globalTransforms: []
+ globalTransforms: [],
+
+ // Which localization should we use?
+ // Should be a string like 'en' or 'en-US'.
+ locale: 'en-US',
+
+ // Localization dictionaries
+ // Dictionaries can be provided either here (specific to one chart) or globally
+ // by registering them as modules.
+ // Here `dictionaries` should be an object of objects
+ // {'da': {'Reset axes': 'Nulstil aksler', ...}, ...}
+ // When looking for a translation we look at these dictionaries first, then
+ // the ones registered as modules. If those fail, we strip off any
+ // regionalization ('en-US' -> 'en') and try each again
+ dictionaries: {}
};
diff --git a/src/plot_api/register.js b/src/plot_api/register.js
index 359cfb08bfe..bc6a3141be3 100644
--- a/src/plot_api/register.js
+++ b/src/plot_api/register.js
@@ -40,6 +40,10 @@ module.exports = function register(_modules) {
registerComponentModule(newModule);
break;
+ case 'locale':
+ Registry.registerLocale(newModule);
+ break;
+
default:
throw new Error('Invalid module was attempted to be registered!');
}
diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js
index f59434c9963..78fae75a679 100644
--- a/src/plot_api/subroutines.js
+++ b/src/plot_api/subroutines.js
@@ -414,7 +414,7 @@ exports.drawMainTitle = function(gd) {
Titles.draw(gd, 'gtitle', {
propContainer: fullLayout,
propName: 'title',
- dfltName: 'Plot',
+ placeholder: fullLayout._dfltTitle.plot,
attributes: {
x: fullLayout.width / 2,
y: fullLayout._size.t / 2,
diff --git a/src/plot_api/validate.js b/src/plot_api/validate.js
index 95ae68780f2..76c1d11bc7c 100644
--- a/src/plot_api/validate.js
+++ b/src/plot_api/validate.js
@@ -13,6 +13,7 @@
var Lib = require('../lib');
var Plots = require('../plots/plots');
var PlotSchema = require('./plot_schema');
+var dfltConfig = require('./plot_config');
var isPlainObject = Lib.isPlainObject;
var isArray = Array.isArray;
@@ -40,9 +41,9 @@ var isArray = Array.isArray;
* error message (shown in console in logger config argument is enable)
*/
module.exports = function valiate(data, layout) {
- var schema = PlotSchema.get(),
- errorList = [],
- gd = {};
+ var schema = PlotSchema.get();
+ var errorList = [];
+ var gd = {_context: Lib.extendFlat({}, dfltConfig)};
var dataIn, layoutIn;
diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js
index 3b24d00cc41..a72ed431335 100644
--- a/src/plots/cartesian/axes.js
+++ b/src/plots/cartesian/axes.js
@@ -2255,7 +2255,7 @@ axes.doTicks = function(gd, axid, skipTitle) {
Titles.draw(gd, axid + 'title', {
propContainer: ax,
propName: ax._name + '.title',
- dfltName: axLetter.toUpperCase() + ' axis',
+ placeholder: fullLayout._dfltTitle[axLetter],
avoid: avoid,
transform: transform,
attributes: {x: x, y: y, 'text-anchor': 'middle'}
@@ -2481,7 +2481,7 @@ function swapAxisGroup(gd, xIds, yIds) {
if(allEqual) {
if(coerceLinearX) layout[xFullAxes[0]._name].type = 'linear';
if(coerceLinearY) layout[yFullAxes[0]._name].type = 'linear';
- swapAxisAttrs(layout, keyi, xFullAxes, yFullAxes);
+ swapAxisAttrs(layout, keyi, xFullAxes, yFullAxes, gd._fullLayout._dfltTitle);
}
}
@@ -2495,7 +2495,7 @@ function swapAxisGroup(gd, xIds, yIds) {
}
}
-function swapAxisAttrs(layout, key, xFullAxes, yFullAxes) {
+function swapAxisAttrs(layout, key, xFullAxes, yFullAxes, dfltTitle) {
// in case the value is the default for either axis,
// look at the first axis in each list and see if
// this key's value is undefined
@@ -2505,11 +2505,11 @@ function swapAxisAttrs(layout, key, xFullAxes, yFullAxes) {
i;
if(key === 'title') {
// special handling of placeholder titles
- if(xVal === 'Click to enter X axis title') {
- xVal = 'Click to enter Y axis title';
+ if(xVal === dfltTitle.x) {
+ xVal = dfltTitle.y;
}
- if(yVal === 'Click to enter Y axis title') {
- yVal = 'Click to enter X axis title';
+ if(yVal === dfltTitle.y) {
+ yVal = dfltTitle.x;
}
}
diff --git a/src/plots/cartesian/axis_defaults.js b/src/plots/cartesian/axis_defaults.js
index 631255c5a9f..469c5c677c1 100644
--- a/src/plots/cartesian/axis_defaults.js
+++ b/src/plots/cartesian/axis_defaults.js
@@ -37,11 +37,8 @@ var orderedCategories = require('./ordered_categories');
* bgColor: the plot background color, to calculate default gridline colors
*/
module.exports = function handleAxisDefaults(containerIn, containerOut, coerce, options, layoutOut) {
- var letter = options.letter,
- font = options.font || {},
- defaultTitle = 'Click to enter ' +
- (options.title || (letter.toUpperCase() + ' axis')) +
- ' title';
+ var letter = options.letter;
+ var font = options.font || {};
function coerce2(attr, dflt) {
return Lib.coerce2(containerIn, containerOut, layoutAttributes, attr, dflt);
@@ -77,7 +74,7 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce,
// inherit from global font color in case that was provided.
var dfltFontColor = (dfltColor === containerIn.color) ? dfltColor : font.color;
- coerce('title', defaultTitle);
+ coerce('title', layoutOut._dfltTitle[letter]);
Lib.coerceFont(coerce, 'titlefont', {
family: font.family,
size: Math.round(font.size * 1.2),
diff --git a/src/plots/cartesian/dragbox.js b/src/plots/cartesian/dragbox.js
index 1b7ca54a061..ec01349e05d 100644
--- a/src/plots/cartesian/dragbox.js
+++ b/src/plots/cartesian/dragbox.js
@@ -296,7 +296,7 @@ module.exports = function dragBox(gd, plotinfo, x, y, w, h, ns, ew) {
dragTail(zoomMode);
if(SHOWZOOMOUTTIP && gd.data && gd._context.showTips) {
- Lib.notifier('Double-click to
zoom back out', 'long');
+ Lib.notifier(Lib._(gd, 'Double-click to zoom back out'), 'long');
SHOWZOOMOUTTIP = false;
}
}
diff --git a/src/plots/cartesian/set_convert.js b/src/plots/cartesian/set_convert.js
index 08691f1879b..a1ea55c76fd 100644
--- a/src/plots/cartesian/set_convert.js
+++ b/src/plots/cartesian/set_convert.js
@@ -381,11 +381,8 @@ module.exports = function setConvert(ax, fullLayout) {
}
if(!isFinite(ax._m) || !isFinite(ax._b)) {
- Lib.notifier(
- 'Something went wrong with axis scaling',
- 'long');
fullLayout._replotting = false;
- throw new Error('axis scaling');
+ throw new Error('Something went wrong with axis scaling');
}
};
diff --git a/src/plots/command.js b/src/plots/command.js
index 8799ee07fad..a0657084c9b 100644
--- a/src/plots/command.js
+++ b/src/plots/command.js
@@ -114,7 +114,7 @@ exports.manageCommandObserver = function(gd, container, commandList, onchange) {
} else {
// TODO: It'd be really neat to actually give a *reason* for this, but at least a warning
// is a start
- Lib.warn('Unable to automatically bind plot updates to API command');
+ Lib.log('Unable to automatically bind plot updates to API command');
ret.lookupTable = {};
ret.remove = function() {};
diff --git a/src/plots/gl2d/convert.js b/src/plots/gl2d/convert.js
index 78784294fe9..fd50b3a787d 100644
--- a/src/plots/gl2d/convert.js
+++ b/src/plots/gl2d/convert.js
@@ -109,12 +109,13 @@ proto.merge = function(options) {
for(i = 0; i < 2; ++i) {
axisName = AXES[i];
+ var axisLetter = axisName.charAt(0);
// get options relevant to this subplot,
// '_name' is e.g. xaxis, xaxis2, yaxis, yaxis4 ...
ax = options[this.scene[axisName]._name];
- axTitle = /Click to enter .+ title/.test(ax.title) ? '' : ax.title;
+ axTitle = ax.title === this.scene.fullLayout._dfltTitle[axisLetter] ? '' : ax.title;
for(j = 0; j <= 2; j += 2) {
this.labelEnable[i + j] = false;
diff --git a/src/plots/gl3d/layout/axis_defaults.js b/src/plots/gl3d/layout/axis_defaults.js
index d65756b1e06..0df2e8db8b7 100644
--- a/src/plots/gl3d/layout/axis_defaults.js
+++ b/src/plots/gl3d/layout/axis_defaults.js
@@ -44,14 +44,16 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, options) {
handleAxisDefaults(
containerIn,
containerOut,
- coerce, {
+ coerce,
+ {
font: options.font,
letter: axName[0],
data: options.data,
showGrid: true,
bgColor: options.bgColor,
calendar: options.calendar
- });
+ },
+ options.fullLayout);
coerce('gridcolor', colorMix(containerOut.color, options.bgColor, gridLightness).toRgbString());
coerce('title', axName[0]); // shouldn't this be on-par with 2D?
diff --git a/src/plots/gl3d/layout/defaults.js b/src/plots/gl3d/layout/defaults.js
index 04d4f841a8c..56062cc392d 100644
--- a/src/plots/gl3d/layout/defaults.js
+++ b/src/plots/gl3d/layout/defaults.js
@@ -102,7 +102,8 @@ function handleGl3dDefaults(sceneLayoutIn, sceneLayoutOut, coerce, opts) {
scene: opts.id,
data: opts.fullData,
bgColor: bgColorCombined,
- calendar: opts.calendar
+ calendar: opts.calendar,
+ fullLayout: opts.fullLayout
});
Registry.getComponentMethod('annotations3d', 'handleDefaults')(
diff --git a/src/plots/layout_attributes.js b/src/plots/layout_attributes.js
index 7c23ffd77e8..86f473a6afb 100644
--- a/src/plots/layout_attributes.js
+++ b/src/plots/layout_attributes.js
@@ -28,7 +28,6 @@ module.exports = {
title: {
valType: 'string',
role: 'info',
- dflt: 'Click to enter Plot title',
editType: 'layoutstyle',
description: [
'Sets the plot\'s title.'
diff --git a/src/plots/plots.js b/src/plots/plots.js
index 5d0515a0a42..db5d224674a 100644
--- a/src/plots/plots.js
+++ b/src/plots/plots.js
@@ -16,6 +16,7 @@ var Plotly = require('../plotly');
var PlotSchema = require('../plot_api/plot_schema');
var Registry = require('../registry');
var Lib = require('../lib');
+var _ = Lib._;
var Color = require('../components/color');
var BADNUM = require('../constants/numerical').BADNUM;
@@ -418,6 +419,25 @@ plots.supplyDefaults = function(gd) {
// Create all the storage space for frames, but only if doesn't already exist
if(!gd._transitionData) plots.createTransitionData(gd);
+ // So we only need to do this once (and since we have gd here)
+ // get the translated placeholder titles.
+ // These ones get used as default values so need to be known at supplyDefaults
+ // others keep their blank defaults but render the placeholder as desired later
+ // TODO: make these work the same way, only inserting the placeholder text at draw time?
+ // The challenge is that this has slightly different behavior right now in editable mode:
+ // using the placeholder as default makes this text permanently (but lightly) visible,
+ // but explicit '' for these titles gives you a placeholder that's hidden until you mouse
+ // over it - so you're not distracted by it if you really don't want a title, but if you do
+ // and you're new to plotly you may not be able to find it.
+ // When editable=false the two behave the same, no title is drawn.
+ newFullLayout._dfltTitle = {
+ plot: _(gd, 'Click to enter Plot title'),
+ x: _(gd, 'Click to enter X axis title'),
+ y: _(gd, 'Click to enter Y axis title'),
+ colorbar: _(gd, 'Click to enter Colorscale title')
+ };
+ newFullLayout._traceWord = _(gd, 'trace');
+
// first fill in what we can of layout without looking at data
// because fullData needs a few things from layout
@@ -586,8 +606,8 @@ plots._hasPlotType = function(category) {
var modules = this._modules || [];
for(i = 0; i < modules.length; i++) {
- var _ = modules[i];
- if(_.categories && _.categories.indexOf(category) >= 0) {
+ var modulei = modules[i];
+ if(modulei.categories && modulei.categories.indexOf(category) >= 0) {
return true;
}
}
@@ -992,7 +1012,7 @@ plots.supplyTraceDefaults = function(traceIn, traceOutIndex, layout, traceInInde
coerce('type');
coerce('uid');
- coerce('name', 'trace ' + traceInIndex);
+ coerce('name', layout._traceWord + ' ' + traceInIndex);
// coerce subplot attributes of all registered subplot types
var subplotTypes = Object.keys(subplotsRegistry);
@@ -1131,7 +1151,7 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut) {
var globalFont = Lib.coerceFont(coerce, 'font');
- coerce('title');
+ coerce('title', layoutOut._dfltTitle.plot);
Lib.coerceFont(coerce, 'titlefont', {
family: globalFont.family,
diff --git a/src/plots/ternary/ternary.js b/src/plots/ternary/ternary.js
index 6549fe03fa2..1240c653c60 100644
--- a/src/plots/ternary/ternary.js
+++ b/src/plots/ternary/ternary.js
@@ -14,6 +14,7 @@ var tinycolor = require('tinycolor2');
var Plotly = require('../../plotly');
var Lib = require('../../lib');
+var _ = Lib._;
var Color = require('../../components/color');
var Drawing = require('../../components/drawing');
var setConvert = require('../cartesian/set_convert');
@@ -382,7 +383,7 @@ proto.drawAxes = function(doTitles) {
Titles.draw(gd, 'a' + titlesuffix, {
propContainer: aaxis,
propName: _this.id + '.aaxis.title',
- dfltName: 'Component A',
+ placeholder: _(gd, 'Click to enter Component A title'),
attributes: {
x: _this.x0 + _this.w / 2,
y: _this.y0 - aaxis.titlefont.size / 3 - apad,
@@ -396,7 +397,7 @@ proto.drawAxes = function(doTitles) {
Titles.draw(gd, 'b' + titlesuffix, {
propContainer: baxis,
propName: _this.id + '.baxis.title',
- dfltName: 'Component B',
+ placeholder: _(gd, 'Click to enter Component B title'),
attributes: {
x: _this.x0 - bpad,
y: _this.y0 + _this.h + baxis.titlefont.size * 0.83 + bpad,
@@ -407,7 +408,7 @@ proto.drawAxes = function(doTitles) {
Titles.draw(gd, 'c' + titlesuffix, {
propContainer: caxis,
propName: _this.id + '.caxis.title',
- dfltName: 'Component C',
+ placeholder: _(gd, 'Click to enter Component C title'),
attributes: {
x: _this.x0 + _this.w + bpad,
y: _this.y0 + _this.h + caxis.titlefont.size * 0.83 + bpad,
@@ -588,7 +589,7 @@ proto.initInteractions = function() {
Plotly.relayout(gd, attrs);
if(SHOWZOOMOUTTIP && gd.data && gd._context.showTips) {
- Lib.notifier('Double-click to
zoom back out', 'long');
+ Lib.notifier(_(gd, 'Double-click to zoom back out'), 'long');
SHOWZOOMOUTTIP = false;
}
}
diff --git a/src/registry.js b/src/registry.js
index 70b6a2015c6..b688c1df2dd 100644
--- a/src/registry.js
+++ b/src/registry.js
@@ -28,6 +28,7 @@ exports.componentsRegistry = {};
exports.layoutArrayContainers = [];
exports.layoutArrayRegexes = [];
exports.traceLayoutAttributes = {};
+exports.localeRegistry = {};
/**
* register a module as the handler for a trace type
@@ -311,3 +312,39 @@ function getTraceType(traceType) {
if(typeof traceType === 'object') traceType = traceType.type;
return traceType;
}
+
+/**
+ * Register a new locale dictionary
+ *
+ * @param {object} module
+ * @param {string} moduleType
+ * should be 'locale' so that Plotly.register will forward to this function
+ * @param {string} module.name
+ * the locale name. Should be a 2-digit language string ('en', 'de')
+ * optionally with a country/region code ('en-GB', 'de-CH'). If a country
+ * code is used but the base language locale has not yet been supplied,
+ * we will use this locale for the base as well.
+ * @param {object} module.dictionary
+ * the dictionary mapping input strings to localized strings
+ * generally the keys should be the literal input strings, but
+ * if default translations are provided you can use any string as a key.
+ */
+exports.registerLocale = function(_module) {
+ var locale = _module.name;
+ var baseLocale = locale.split('-')[0];
+
+ var newDict = _module.dictionary;
+
+ var locales = exports.localeRegistry;
+
+ // Should we use this dict for the base locale?
+ // In case we're overwriting a previous dict for this locale, check
+ // whether the base matches the full locale dict now. If we're not
+ // overwriting, locales[locale] is undefined so this just checks if
+ // baseLocale already had a dict or not.
+ if(baseLocale !== locale && locales[baseLocale] === locales[locale]) {
+ locales[baseLocale] = newDict;
+ }
+
+ locales[locale] = newDict;
+};
diff --git a/src/traces/box/calc.js b/src/traces/box/calc.js
index f085eb9306b..b6a5fa83139 100644
--- a/src/traces/box/calc.js
+++ b/src/traces/box/calc.js
@@ -11,6 +11,7 @@
var isNumeric = require('fast-isnumeric');
var Lib = require('../../lib');
+var _ = Lib._;
var Axes = require('../../plots/cartesian/axes');
// outlier definition based on http://www.physics.csbsju.edu/stats/box2.html
@@ -122,7 +123,17 @@ module.exports = function calc(gd, trace) {
num: fullLayout[numKey],
dPos: dPos,
posLetter: posLetter,
- valLetter: valLetter
+ valLetter: valLetter,
+ labels: {
+ med: _(gd, 'median:'),
+ min: _(gd, 'min:'),
+ q1: _(gd, 'q1:'),
+ q3: _(gd, 'q3:'),
+ max: _(gd, 'max:'),
+ mean: trace.boxmean === 'sd' ? _(gd, 'mean ± σ:') : _(gd, 'mean:'),
+ lf: _(gd, 'lower fence:'),
+ uf: _(gd, 'upper fence:')
+ }
};
fullLayout[numKey]++;
diff --git a/src/traces/box/hover.js b/src/traces/box/hover.js
index 17cc4c1f84c..839f065e72e 100644
--- a/src/traces/box/hover.js
+++ b/src/traces/box/hover.js
@@ -138,15 +138,12 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) {
// box plots: each "point" gets many labels
var usedVals = {};
var attrs = ['med', 'min', 'q1', 'q3', 'max'];
- var prefixes = ['median', 'min', 'q1', 'q3', 'max'];
if(trace.boxmean || (trace.meanline || {}).visible) {
attrs.push('mean');
- prefixes.push(trace.boxmean === 'sd' ? 'mean ± σ' : 'mean');
}
if(trace.boxpoints || trace.points) {
attrs.push('lf', 'uf');
- prefixes.push('lower fence', 'upper fence');
}
for(var i = 0; i < attrs.length; i++) {
@@ -162,7 +159,7 @@ function hoverOnBoxes(pointData, xval, yval, hovermode) {
pointData2[vLetter + '0'] = pointData2[vLetter + '1'] = valPx;
pointData2[vLetter + 'LabelVal'] = val;
- pointData2[vLetter + 'Label'] = prefixes[i] + ': ' + Axes.hoverLabelText(vAxis, val);
+ pointData2[vLetter + 'Label'] = t.labels[attr] + ' ' + Axes.hoverLabelText(vAxis, val);
if(attr === 'mean' && ('sd' in di) && trace.boxmean === 'sd') {
pointData2[vLetter + 'err'] = di.sd;
diff --git a/src/traces/contourcarpet/calc.js b/src/traces/contourcarpet/calc.js
index e313bbdbaf4..3691800dbd8 100644
--- a/src/traces/contourcarpet/calc.js
+++ b/src/traces/contourcarpet/calc.js
@@ -8,10 +8,8 @@
'use strict';
-var Lib = require('../../lib');
var Axes = require('../../plots/cartesian/axes');
var extendFlat = require('../../lib').extendFlat;
-var Registry = require('../../registry');
var colorscaleCalc = require('../../components/colorscale/calc');
var hasColumns = require('../heatmap/has_columns');
var convertColumnData = require('../heatmap/convert_column_xyz');
@@ -126,18 +124,15 @@ function heatmappishCalc(gd, trace) {
// prepare the raw data
// run makeCalcdata on x and y even for heatmaps, in case of category mappings
var carpet = trace.carpetTrace;
- var aax = carpet.aaxis,
- bax = carpet.baxis,
- isContour = Registry.traceIs(trace, 'contour'),
- zsmooth = isContour ? 'best' : trace.zsmooth,
- a,
+ var aax = carpet.aaxis;
+ var bax = carpet.baxis;
+ var a,
a0,
da,
b,
b0,
db,
- z,
- i;
+ z;
// cancel minimum tick spacings (only applies to bars and boxes)
aax._minDtick = 0;
@@ -157,40 +152,6 @@ function heatmappishCalc(gd, trace) {
trace._emptypoints = findEmpties(z);
trace._interpz = interp2d(z, trace._emptypoints, trace._interpz);
- function noZsmooth(msg) {
- zsmooth = trace._input.zsmooth = trace.zsmooth = false;
- Lib.notifier('cannot fast-zsmooth: ' + msg);
- }
-
- // check whether we really can smooth (ie all boxes are about the same size)
- if(zsmooth === 'fast') {
- if(aax.type === 'log' || bax.type === 'log') {
- noZsmooth('log axis found');
- }
- else {
- if(a.length) {
- var avgda = (a[a.length - 1] - a[0]) / (a.length - 1),
- maxErrX = Math.abs(avgda / 100);
- for(i = 0; i < a.length - 1; i++) {
- if(Math.abs(a[i + 1] - a[i] - avgda) > maxErrX) {
- noZsmooth('a scale is not linear');
- break;
- }
- }
- }
- if(b.length && zsmooth === 'fast') {
- var avgdy = (b[b.length - 1] - b[0]) / (b.length - 1),
- maxErrY = Math.abs(avgdy / 100);
- for(i = 0; i < b.length - 1; i++) {
- if(Math.abs(b[i + 1] - b[i] - avgdy) > maxErrY) {
- noZsmooth('b scale is not linear');
- break;
- }
- }
- }
- }
- }
-
// create arrays of brick boundaries, to be used by autorange and heatmap.plot
var xlen = maxRowLength(z),
xIn = trace.xtype === 'scaled' ? '' : a,
diff --git a/src/traces/heatmap/calc.js b/src/traces/heatmap/calc.js
index b8ce599d5ed..802345d7dca 100644
--- a/src/traces/heatmap/calc.js
+++ b/src/traces/heatmap/calc.js
@@ -82,7 +82,7 @@ module.exports = function calc(gd, trace) {
function noZsmooth(msg) {
zsmooth = trace._input.zsmooth = trace.zsmooth = false;
- Lib.notifier('cannot fast-zsmooth: ' + msg);
+ Lib.warn('cannot use zsmooth: "fast": ' + msg);
}
// check whether we really can smooth (ie all boxes are about the same size)
diff --git a/src/traces/ohlc/transform.js b/src/traces/ohlc/transform.js
index 8e952144afc..db357e012c7 100644
--- a/src/traces/ohlc/transform.js
+++ b/src/traces/ohlc/transform.js
@@ -12,6 +12,7 @@
var isNumeric = require('fast-isnumeric');
var Lib = require('../../lib');
+var _ = Lib._;
var helpers = require('./helpers');
var Axes = require('../../plots/cartesian/axes');
var axisIds = require('../../plots/cartesian/axis_ids');
@@ -132,6 +133,11 @@ exports.calcTransform = function calcTransform(gd, trace, opts) {
close = trace.close,
textIn = trace.text;
+ var openName = _(gd, 'open:') + ' ';
+ var highName = _(gd, 'high:') + ' ';
+ var lowName = _(gd, 'low:') + ' ';
+ var closeName = _(gd, 'close:') + ' ';
+
var len = open.length,
x = [],
y = [],
@@ -183,10 +189,10 @@ exports.calcTransform = function calcTransform(gd, trace, opts) {
var t = [];
if(hasY) {
- t.push('Open: ' + format(ya, o));
- t.push('High: ' + format(ya, h));
- t.push('Low: ' + format(ya, l));
- t.push('Close: ' + format(ya, c));
+ t.push(openName + format(ya, o));
+ t.push(highName + format(ya, h));
+ t.push(lowName + format(ya, l));
+ t.push(closeName + format(ya, c));
}
if(hasText) t.push(getTextItem(i));
diff --git a/src/traces/sankey/plot.js b/src/traces/sankey/plot.js
index 59d978fa4a4..6c4b37b4be4 100644
--- a/src/traces/sankey/plot.js
+++ b/src/traces/sankey/plot.js
@@ -15,6 +15,8 @@ var Color = require('../../components/color');
var Lib = require('../../lib');
var cn = require('./constants').cn;
+var _ = Lib._;
+
function renderableValuePresent(d) {return d !== '';}
function ownTrace(selection, d) {
@@ -135,6 +137,11 @@ module.exports = function plot(gd, calcData) {
});
};
+ var sourceLabel = _(gd, 'source:') + ' ';
+ var targetLabel = _(gd, 'target:') + ' ';
+ var incomingLabel = _(gd, 'incoming flow count:') + ' ';
+ var outgoingLabel = _(gd, 'outgoing flow count:') + ' ';
+
var linkHoverFollow = function(element, d) {
var trace = d.link.trace;
var rootBBox = gd._fullLayout._paperdiv.node().getBoundingClientRect();
@@ -148,8 +155,8 @@ module.exports = function plot(gd, calcData) {
name: d3.format(d.valueFormat)(d.link.value) + d.valueSuffix,
text: [
d.link.label || '',
- ['Source:', d.link.source.label].join(' '),
- ['Target:', d.link.target.label].join(' ')
+ sourceLabel + d.link.source.label,
+ targetLabel + d.link.target.label
].filter(renderableValuePresent).join('
'),
color: castHoverOption(trace, 'bgcolor') || Color.addOpacity(d.tinyColorHue, 1),
borderColor: castHoverOption(trace, 'bordercolor'),
@@ -209,8 +216,8 @@ module.exports = function plot(gd, calcData) {
name: d3.format(d.valueFormat)(d.node.value) + d.valueSuffix,
text: [
d.node.label,
- ['Incoming flow count:', d.node.targetLinks.length].join(' '),
- ['Outgoing flow count:', d.node.sourceLinks.length].join(' ')
+ incomingLabel + d.node.targetLinks.length,
+ outgoingLabel + d.node.sourceLinks.length
].filter(renderableValuePresent).join('
'),
color: castHoverOption(trace, 'bgcolor') || d.tinyColorHue,
borderColor: castHoverOption(trace, 'bordercolor'),
diff --git a/src/traces/scattergeo/calc.js b/src/traces/scattergeo/calc.js
index 668e4e24aed..1ec011c4dde 100644
--- a/src/traces/scattergeo/calc.js
+++ b/src/traces/scattergeo/calc.js
@@ -16,6 +16,8 @@ var calcMarkerColorscale = require('../scatter/colorscale_calc');
var arraysToCalcdata = require('../scatter/arrays_to_calcdata');
var calcSelection = require('../scatter/calc_selection');
+var _ = require('../../lib')._;
+
module.exports = function calc(gd, trace) {
var hasLocationData = Array.isArray(trace.locations);
var len = hasLocationData ? trace.locations.length : trace.lon.length;
@@ -40,5 +42,14 @@ module.exports = function calc(gd, trace) {
calcMarkerColorscale(trace);
calcSelection(calcTrace, trace);
+ if(len) {
+ calcTrace[0].t = {
+ labels: {
+ lat: _(gd, 'lat:') + ' ',
+ lon: _(gd, 'lon:') + ' '
+ }
+ };
+ }
+
return calcTrace;
};
diff --git a/src/traces/scattergeo/hover.js b/src/traces/scattergeo/hover.js
index 56aa35c359d..04e85b2ff7c 100644
--- a/src/traces/scattergeo/hover.js
+++ b/src/traces/scattergeo/hover.js
@@ -65,12 +65,12 @@ module.exports = function hoverPoints(pointData, xval, yval) {
pointData.lat = lonlat[1];
pointData.color = getTraceColor(trace, di);
- pointData.extraText = getExtraText(trace, di, geo.mockAxis);
+ pointData.extraText = getExtraText(trace, di, geo.mockAxis, cd[0].t.labels);
return [pointData];
};
-function getExtraText(trace, pt, axis) {
+function getExtraText(trace, pt, axis, labels) {
var hoverinfo = pt.hi || trace.hoverinfo;
var parts = hoverinfo === 'all' ?
@@ -92,9 +92,9 @@ function getExtraText(trace, pt, axis) {
} else if(hasLon && hasLat) {
text.push('(' + format(pt.lonlat[0]) + ', ' + format(pt.lonlat[1]) + ')');
} else if(hasLon) {
- text.push('lon: ' + format(pt.lonlat[0]));
+ text.push(labels.lon + format(pt.lonlat[0]));
} else if(hasLat) {
- text.push('lat: ' + format(pt.lonlat[1]));
+ text.push(labels.lat + format(pt.lonlat[1]));
}
if(hasText) {
diff --git a/src/traces/scattermapbox/hover.js b/src/traces/scattermapbox/hover.js
index d9805ed152a..3638e8ae18a 100644
--- a/src/traces/scattermapbox/hover.js
+++ b/src/traces/scattermapbox/hover.js
@@ -61,12 +61,12 @@ module.exports = function hoverPoints(pointData, xval, yval) {
pointData.y1 = yc + rad;
pointData.color = getTraceColor(trace, di);
- pointData.extraText = getExtraText(trace, di);
+ pointData.extraText = getExtraText(trace, di, cd[0].t.labels);
return [pointData];
};
-function getExtraText(trace, di) {
+function getExtraText(trace, di, labels) {
var hoverinfo = di.hi || trace.hoverinfo;
var parts = hoverinfo.split('+');
var isAll = parts.indexOf('all') !== -1;
@@ -85,9 +85,9 @@ function getExtraText(trace, di) {
if(isAll || (hasLon && hasLat)) {
text.push('(' + format(lonlat[0]) + ', ' + format(lonlat[1]) + ')');
} else if(hasLon) {
- text.push('lon: ' + format(lonlat[0]));
+ text.push(labels.lon + format(lonlat[0]));
} else if(hasLat) {
- text.push('lat: ' + format(lonlat[1]));
+ text.push(labels.lat + format(lonlat[1]));
}
if(isAll || parts.indexOf('text') !== -1) {
diff --git a/src/traces/violin/calc.js b/src/traces/violin/calc.js
index e4b0332824e..34064a9b01a 100644
--- a/src/traces/violin/calc.js
+++ b/src/traces/violin/calc.js
@@ -70,6 +70,8 @@ module.exports = function calc(gd, trace) {
groupStats.maxCount = Math.max(groupStats.maxCount, vals.length);
}
+ cd[0].t.labels.kde = Lib._(gd, 'kde:');
+
return cd;
};
diff --git a/src/traces/violin/hover.js b/src/traces/violin/hover.js
index 32ea61ba63a..a6363cf2761 100644
--- a/src/traces/violin/hover.js
+++ b/src/traces/violin/hover.js
@@ -62,7 +62,7 @@ module.exports = function hoverPoints(pointData, xval, yval, hovermode, hoverLay
kdePointData[pLetter + '0'] = pOnPath[0];
kdePointData[pLetter + '1'] = pOnPath[1];
kdePointData[vLetter + '0'] = kdePointData[vLetter + '1'] = vValPx;
- kdePointData[vLetter + 'Label'] = vLetter + ': ' + Axes.hoverLabelText(vAxis, vVal) + ', kde: ' + kdeVal.toFixed(3);
+ kdePointData[vLetter + 'Label'] = vLetter + ': ' + Axes.hoverLabelText(vAxis, vVal) + ', ' + cd[0].t.labels.kde + ' ' + kdeVal.toFixed(3);
closeData.push(kdePointData);
violinLineAttrs = {stroke: pointData.color};
diff --git a/tasks/bundle.js b/tasks/bundle.js
index dd767f018ff..a6d7cd3dd64 100644
--- a/tasks/bundle.js
+++ b/tasks/bundle.js
@@ -1,7 +1,11 @@
+var path = require('path');
+var glob = require('glob');
+
var constants = require('./util/constants');
var common = require('./util/common');
var _bundle = require('./util/browserify_wrapper');
var makeSchema = require('./util/make_schema');
+var wrapLocale = require('./util/wrap_locale');
/*
* This script takes one argument
*
@@ -54,3 +58,13 @@ constants.partialBundlePaths.forEach(function(pathObj) {
pathToMinBundle: pathObj.distMin
});
});
+
+// "Browserify" the locales
+var localeGlob = path.join(constants.pathToLib, 'locale-*.js');
+glob(localeGlob, function(err, files) {
+ files.forEach(function(file) {
+ var outName = 'plotly-' + path.basename(file);
+ var outPath = path.join(constants.pathToDist, outName);
+ wrapLocale(file, outPath);
+ });
+});
diff --git a/tasks/find_locale_strings.js b/tasks/find_locale_strings.js
new file mode 100644
index 00000000000..ff1da8552e3
--- /dev/null
+++ b/tasks/find_locale_strings.js
@@ -0,0 +1,98 @@
+var path = require('path');
+var fs = require('fs');
+
+var falafel = require('falafel');
+var glob = require('glob');
+
+var constants = require('./util/constants');
+var srcGlob = path.join(constants.pathToSrc, '**/*.js');
+
+var common = require('./util/common');
+
+var EXIT_CODE = 0;
+
+var localizeRE = /(^|[\.])(_|localize)$/;
+
+// main
+findLocaleStrings();
+
+function findLocaleStrings() {
+ glob(srcGlob, function(err, files) {
+ if(err) {
+ EXIT_CODE = 1;
+ console.log(err);
+ return;
+ }
+
+ var dict = {};
+ var hasTranslation = false;
+ var maxLen = 0;
+
+ files.forEach(function(file) {
+ var code = fs.readFileSync(file, 'utf-8');
+ var filePartialPath = file.substr(constants.pathToSrc.length);
+
+ falafel(code, {locations: true}, function(node) {
+ // parse through code string looking for translated strings
+ // You may either assign `Lib.localize` to `_` and use that, or
+ // call `Lib.localize` directly.
+ if(node.type === 'CallExpression' &&
+ (node.callee.name === '_' || node.callee.source() === 'Lib._')
+ ) {
+ var strNode = node.arguments[1];
+ if(node.arguments.length !== 2) {
+ logError(file, node, 'Localize takes 2 args');
+ }
+ if(strNode.type !== 'Literal') {
+ logError(file, node, 'Translated string must be a literal');
+ }
+ if(!dict[strNode.value]) {
+ dict[strNode.value] = filePartialPath + ':' + node.loc.start.line;
+ maxLen = Math.max(maxLen, strNode.value.length);
+ hasTranslation = true;
+ }
+ }
+
+ // make sure localize is the only thing we assign to a variable `_`
+ // NB: this does not preclude using `_` for an unused function arg
+ else if(node.type === 'VariableDeclarator' && node.id.name === '_') {
+ var src = node.init.source();
+ if(!localizeRE.test(src)) {
+ logError(file, node, 'Use `_` only to mean localization');
+ }
+ }
+ });
+ });
+
+ if(!hasTranslation) {
+ console.error('Found no translations.');
+ EXIT_CODE = 1;
+ }
+
+ if(!EXIT_CODE) {
+ var strings = Object.keys(dict).sort().map(function(k) {
+ return k + spaces(maxLen - k.length) + ' // ' + dict[k];
+ }).join('\n');
+ common.writeFile(constants.pathToTranslationKeys, strings);
+ console.log('ok find_locale_strings');
+ }
+ });
+}
+
+function logError(file, node, msg) {
+ console.error(file + ' [line ' + node.loc.start.line + '] ' + msg +
+ '\n ' + node.source());
+ EXIT_CODE = 1;
+}
+
+function spaces(len) {
+ var out = '';
+ for(var i = 0; i < len; i++) out += ' ';
+ return out;
+}
+
+process.on('exit', function() {
+ if(EXIT_CODE) {
+ throw new Error('find_locale_strings failed.');
+ }
+});
diff --git a/tasks/util/constants.js b/tasks/util/constants.js
index 46f0ba357d4..20fa44fd695 100644
--- a/tasks/util/constants.js
+++ b/tasks/util/constants.js
@@ -42,6 +42,7 @@ module.exports = {
pathToPlotlyDistWithMeta: path.join(pathToDist, 'plotly-with-meta.js'),
pathToSchema: path.join(pathToDist, 'plot-schema.json'),
+ pathToTranslationKeys: path.join(pathToDist, 'translation-keys.txt'),
partialBundleNames: partialBundleNames,
partialBundlePaths: partialBundlePaths,
diff --git a/tasks/util/wrap_locale.js b/tasks/util/wrap_locale.js
new file mode 100644
index 00000000000..cfd86612fc7
--- /dev/null
+++ b/tasks/util/wrap_locale.js
@@ -0,0 +1,41 @@
+var fs = require('fs');
+var path = require('path');
+
+var minify = require('minify-stream');
+var intoStream = require('into-stream');
+
+var constants = require('./constants');
+
+var prefix = 'Plotly.register(';
+var suffix = ');';
+
+var moduleMarker = 'module.exports = ';
+
+/** Wrap a locale json file into a standalone js file
+ *
+ * @param {string} pathToInput path to the locale json file
+ * @param {string} pathToOutput path to destination file
+ *
+ * Logs basename of bundle when completed.
+ */
+module.exports = function wrap_locale(pathToInput, pathToOutput) {
+ fs.readFile(pathToInput, 'utf8', function(err, data) {
+ var moduleStart = data.indexOf(moduleMarker) + moduleMarker.length;
+ var moduleEnd = data.indexOf(';', moduleStart);
+
+ var rawOut = prefix + data.substr(moduleStart, moduleEnd - moduleStart) + suffix;
+
+ intoStream(rawOut)
+ .pipe(minify(constants.uglifyOptions))
+ .pipe(fs.createWriteStream(pathToOutput))
+ .on('finish', function() {
+ logger(pathToOutput);
+ });
+ });
+};
+
+function logger(pathToOutput) {
+ var log = 'ok ' + path.basename(pathToOutput);
+
+ console.log(log);
+}
diff --git a/test/image/mocks/geo_choropleth-text.json b/test/image/mocks/geo_choropleth-text.json
index 083dae0fd85..d4a10cd441b 100644
--- a/test/image/mocks/geo_choropleth-text.json
+++ b/test/image/mocks/geo_choropleth-text.json
@@ -6,7 +6,6 @@
"text": [
"Angola",
"Albania",
- "Arab World",
"United Arab Emirates",
"Argentina",
"Armenia",
@@ -17,7 +16,6 @@
"Benin",
"Bangladesh",
"Bulgaria",
- "Bahrain",
"Bosnia and Herzegovina",
"Belarus",
"Bolivia",
@@ -25,7 +23,6 @@
"Brunei Darussalam",
"Botswana",
"Canada",
- "Central Europe and the Baltics",
"Switzerland",
"Chile",
"China",
@@ -34,7 +31,6 @@
"Congo, Rep.",
"Colombia",
"Costa Rica",
- "Caribbean small states",
"Cuba",
"Cyprus",
"Czech Republic",
@@ -42,19 +38,12 @@
"Denmark",
"Dominican Republic",
"Algeria",
- "East Asia & Pacific (developing only)",
- "East Asia & Pacific (all income levels)",
- "Europe & Central Asia (developing only)",
- "Europe & Central Asia (all income levels)",
"Ecuador",
"Egypt, Arab Rep.",
- "Euro area",
"Eritrea",
"Spain",
"Estonia",
"Ethiopia",
- "European Union",
- "Fragile and conflict affected situations",
"Finland",
"France",
"Gabon",
@@ -63,10 +52,7 @@
"Ghana",
"Greece",
"Guatemala",
- "High income",
- "Hong Kong SAR, China",
"Honduras",
- "Heavily indebted poor countries (HIPC)",
"Croatia",
"Haiti",
"Hungary",
@@ -88,44 +74,29 @@
"Korea, Rep.",
"Kosovo",
"Kuwait",
- "Latin America & Caribbean (developing only)",
"Lebanon",
"Libya",
- "Latin America & Caribbean (all income levels)",
- "Least developed countries: UN classification",
- "Low income",
"Sri Lanka",
- "Lower middle income",
- "Low & middle income",
"Lithuania",
"Luxembourg",
"Latvia",
"Morocco",
"Moldova",
- "Middle East & North Africa (all income levels)",
"Mexico",
- "Middle income",
"Macedonia, FYR",
- "Malta",
"Myanmar",
- "Middle East & North Africa (developing only)",
"Montenegro",
"Mongolia",
"Mozambique",
"Malaysia",
- "North America",
"Namibia",
"Nigeria",
"Nicaragua",
"Netherlands",
- "High income: nonOECD",
"Norway",
"Nepal",
"New Zealand",
- "High income: OECD",
- "OECD members",
"Oman",
- "Other small states",
"Pakistan",
"Panama",
"Peru",
@@ -137,16 +108,11 @@
"Qatar",
"Romania",
"Russian Federation",
- "South Asia",
"Saudi Arabia",
"Sudan",
"Senegal",
- "Singapore",
"El Salvador",
"Serbia",
- "Sub-Saharan Africa (developing only)",
- "Sub-Saharan Africa (all income levels)",
- "Small states",
"Slovak Republic",
"Slovenia",
"Sweden",
@@ -160,13 +126,11 @@
"Turkey",
"Tanzania",
"Ukraine",
- "Upper middle income",
"Uruguay",
"United States",
"Uzbekistan",
"Venezuela, RB",
"Vietnam",
- "World",
"Yemen, Rep.",
"South Africa",
"Congo, Dem. Rep.",
@@ -177,7 +141,6 @@
"locations": [
"AGO",
"ALB",
- "ARB",
"ARE",
"ARG",
"ARM",
@@ -188,7 +151,6 @@
"BEN",
"BGD",
"BGR",
- "BHR",
"BIH",
"BLR",
"BOL",
@@ -196,7 +158,6 @@
"BRN",
"BWA",
"CAN",
- "CEB",
"CHE",
"CHL",
"CHN",
@@ -205,7 +166,6 @@
"COG",
"COL",
"CRI",
- "CSS",
"CUB",
"CYP",
"CZE",
@@ -213,19 +173,12 @@
"DNK",
"DOM",
"DZA",
- "EAP",
- "EAS",
- "ECA",
- "ECS",
"ECU",
"EGY",
- "EMU",
"ERI",
"ESP",
"EST",
"ETH",
- "EUU",
- "FCS",
"FIN",
"FRA",
"GAB",
@@ -234,10 +187,7 @@
"GHA",
"GRC",
"GTM",
- "HIC",
- "HKG",
"HND",
- "HPC",
"HRV",
"HTI",
"HUN",
@@ -259,44 +209,29 @@
"KOR",
null,
"KWT",
- "LAC",
"LBN",
"LBY",
- "LCN",
- "LDC",
- "LIC",
"LKA",
- "LMC",
- "LMY",
"LTU",
"LUX",
"LVA",
"MAR",
"MDA",
- "MEA",
"MEX",
- "MIC",
"MKD",
- "MLT",
"MMR",
- "MNA",
"MNE",
"MNG",
"MOZ",
"MYS",
- "NAC",
"NAM",
"NGA",
"NIC",
"NLD",
- "NOC",
"NOR",
"NPL",
"NZL",
- "OEC",
- "OED",
"OMN",
- "OSS",
"PAK",
"PAN",
"PER",
@@ -308,16 +243,11 @@
"QAT",
"ROU",
"RUS",
- "SAS",
"SAU",
"SDN",
"SEN",
- "SGP",
"SLV",
"SRB",
- "SSA",
- "SSF",
- "SST",
"SVK",
"SVN",
"SWE",
@@ -331,13 +261,11 @@
"TUR",
"TZA",
"UKR",
- "UMC",
"URY",
"USA",
"UZB",
"VEN",
"VNM",
- "WLD",
"YEM",
"ZAF",
"COD",
@@ -347,7 +275,6 @@
"z": [
-639.491311425916,
21.2123434330386,
- -174.09958727740897,
-179.388449582104,
-1.7041523393343299,
64.6472749649232,
@@ -358,7 +285,6 @@
43.7551733199028,
16.2437267991142,
40.8264927168205,
- -87.1314080230412,
32.1996898013473,
85.0287198176801,
-128.063878318709,
@@ -366,7 +292,6 @@
-473.19072663497,
51.559108167064295,
-57.762778129169995,
- 37.8834751149095,
51.797306948137894,
70.20999876067239,
10.1199583054877,
@@ -375,7 +300,6 @@
-1049.5396433485,
-227.160178703599,
47.568660123804904,
- -84.4378809914236,
53.2701580058226,
96.35067157026708,
28.2067516919418,
@@ -383,19 +307,12 @@
-20.676751564727898,
89.0065422703776,
-275.329807125617,
- 3.51516098241885,
- 15.9565539656918,
- 4.834165156088309,
- 4.47727995132693,
-120.140677617521,
-20.1443985137915,
- 60.290587578546706,
21.9698628260283,
73.1513003612455,
11.451277242441599,
5.470357790113879,
- 51.2509379809447,
- -113.368328338844,
52.3663262919339,
48.1770056841254,
-622.021499760279,
@@ -404,10 +321,7 @@
32.7335325055656,
65.79698915080941,
26.4857611165643,
- 4.0046341022129,
- 99.6180015703119,
51.4003670732292,
- -19.7892791292931,
50.7301557348727,
28.012679109440302,
56.964989755763796,
@@ -429,44 +343,29 @@
82.02869222037559,
25.4365519637175,
-313.221929844778,
- -30.901110969748398,
96.75733945025999,
-334.220009251031,
- -28.5474513014272,
- -53.2426615565718,
- 3.76210562385273,
43.684467843411795,
- -5.83892226829784,
- -9.19186639970595,
78.45308301715771,
97.09329590523991,
54.4826301674269,
94.5657637772992,
96.2080909469791,
- -140.35413698363502,
-27.340652771459897,
- -9.65202041824149,
43.949428786285296,
- 99.6542636298781,
-60.959456318897494,
- -90.98129479054121,
24.078361622635498,
-325.17346937593896,
-22.1335972337041,
-18.2148003028243,
- 14.073188529997198,
79.576005073708,
-121.28196341185301,
48.0103598393906,
16.3149384313268,
- -97.9560487495735,
-529.149021741409,
13.119464681168498,
7.69726241823141,
- 29.2384675884995,
- 28.277574597396697,
-211.51288938573,
- -138.461673060562,
23.731166221174696,
77.2777805633777,
-0.8096633744691509,
@@ -478,16 +377,11 @@
-515.549485382505,
21.575573631121003,
-84.1182920382627,
- 25.974081504352498,
-180.230853147343,
-111.00394800083599,
52.772861382765704,
- 97.5436313612422,
46.294560725901604,
32.074863494552304,
- -61.3730990794329,
- -61.3730990794329,
- -96.5210737821686,
65.18296765045,
48.4287551391239,
34.715333373425395,
@@ -501,13 +395,11 @@
69.3482069478227,
6.9525763336832,
40.5086856291844,
- -11.1307458243133,
50.792767419753,
22.211408716366602,
-25.967696793077604,
-162.997187469107,
-12.6903585180516,
- -2.45491860900522,
-131.876654010171,
-14.705281572926301,
-1.3275812135438898,
diff --git a/test/jasmine/assets/modebar_button.js b/test/jasmine/assets/modebar_button.js
index ad485f2601c..ba3c1182461 100644
--- a/test/jasmine/assets/modebar_button.js
+++ b/test/jasmine/assets/modebar_button.js
@@ -6,8 +6,14 @@ var modeBarButtons = require('../../../src/components/modebar/buttons');
module.exports = function selectButton(modeBar, name) {
var button = {};
+ var title = modeBarButtons[name].title;
+
+ if(typeof title === 'function') {
+ title = title(modeBar.graphInfo);
+ }
+
var node = button.node = d3.select(modeBar.element)
- .select('[data-title="' + modeBarButtons[name].title + '"]')
+ .select('[data-title="' + title + '"]')
.node();
button.click = function() {
diff --git a/test/jasmine/assets/supply_defaults.js b/test/jasmine/assets/supply_defaults.js
new file mode 100644
index 00000000000..259950a647e
--- /dev/null
+++ b/test/jasmine/assets/supply_defaults.js
@@ -0,0 +1,14 @@
+'use strict';
+
+var Plots = require('@src/plots/plots');
+
+/**
+ * supplyDefaults that fills in necessary _context
+ */
+module.exports = function supplyDefaults(gd) {
+ if(!gd._context) gd._context = {};
+ if(!gd._context.locale) gd._context.locale = 'en';
+ if(!gd._context.dictionaries) gd._context.dictionaries = {};
+
+ Plots.supplyDefaults(gd);
+};
diff --git a/test/jasmine/tests/annotations_test.js b/test/jasmine/tests/annotations_test.js
index 2f96fb22954..592677ae9f4 100644
--- a/test/jasmine/tests/annotations_test.js
+++ b/test/jasmine/tests/annotations_test.js
@@ -98,6 +98,11 @@ describe('Test annotations', function() {
});
it('should clean *xclick* and *yclick* values', function() {
+ var errors = [];
+ spyOn(Loggers, 'error').and.callFake(function(msg) {
+ errors.push(msg);
+ });
+
var layoutIn = {
annotations: [{
clicktoshow: 'onoff',
@@ -139,6 +144,7 @@ describe('Test annotations', function() {
expect(layoutOut.annotations[1]._yclick).toBe(undefined, 'invalid date');
expect(layoutOut.annotations[2]._xclick).toBe(2, 'log');
expect(layoutOut.annotations[2]._yclick).toBe('A', 'category');
+ expect(errors.length).toBe(1);
});
});
});
diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js
index fb269708016..2e33ddab044 100644
--- a/test/jasmine/tests/axes_test.js
+++ b/test/jasmine/tests/axes_test.js
@@ -3,6 +3,7 @@ var d3 = require('d3');
var Plots = require('@src/plots/plots');
var Lib = require('@src/lib');
+var Loggers = require('@src/lib/loggers');
var Color = require('@src/components/color');
var tinycolor = require('tinycolor2');
@@ -14,6 +15,7 @@ var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var failTest = require('../assets/fail_test');
var selectButton = require('../assets/modebar_button');
+var supplyDefaults = require('../assets/supply_defaults');
describe('Test axes', function() {
@@ -49,7 +51,7 @@ describe('Test axes', function() {
type: 'date'
};
- Plots.supplyDefaults(gd);
+ supplyDefaults(gd);
Axes.swap(gd, [0]);
@@ -80,7 +82,7 @@ describe('Test axes', function() {
expectedLayoutAfter.xaxis.type = 'linear';
expectedLayoutAfter.yaxis.type = 'linear';
- Plots.supplyDefaults(gd);
+ supplyDefaults(gd);
Axes.swap(gd, [0]);
@@ -160,7 +162,7 @@ describe('Test axes', function() {
{x: 5, y: 0.5, xref: 'x', yref: 'paper'}
];
- Plots.supplyDefaults(gd);
+ supplyDefaults(gd);
Axes.swap(gd, [0, 1]);
@@ -177,7 +179,8 @@ describe('Test axes', function() {
beforeEach(function() {
layoutOut = {
_has: Plots._hasPlotType,
- _basePlotModules: []
+ _basePlotModules: [],
+ _dfltTitle: {x: 'x', y: 'y'}
};
fullData = [];
});
@@ -1186,6 +1189,11 @@ describe('Test axes', function() {
expect(axOut.tick0).toBe('2000-01-01');
expect(axOut.dtick).toBe('M12');
+ var errors = [];
+ spyOn(Loggers, 'error').and.callFake(function(msg) {
+ errors.push(msg);
+ });
+
// now some stuff that shouldn't work, should give defaults
[
['next thursday', -1],
@@ -1193,12 +1201,13 @@ describe('Test axes', function() {
['', 'M0.5'],
['', 'M-1'],
['', '2000-01-01']
- ].forEach(function(v) {
+ ].forEach(function(v, i) {
axIn = {tick0: v[0], dtick: v[1]};
axOut = {};
mockSupplyDefaults(axIn, axOut, 'date');
expect(axOut.tick0).toBe('2000-01-01');
expect(axOut.dtick).toBe(oneDay);
+ expect(errors.length).toBe(i + 1);
});
});
diff --git a/test/jasmine/tests/bar_test.js b/test/jasmine/tests/bar_test.js
index b3f02aedcf2..68c9cbb9700 100644
--- a/test/jasmine/tests/bar_test.js
+++ b/test/jasmine/tests/bar_test.js
@@ -11,6 +11,7 @@ var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var fail = require('../assets/fail_test');
var checkTicks = require('../assets/custom_assertions').checkTicks;
+var supplyAllDefaults = require('../assets/supply_defaults');
var d3 = require('d3');
@@ -1520,10 +1521,11 @@ function mockBarPlot(dataWithoutTraceType, layout) {
var gd = {
data: dataWithTraceType,
layout: layout || {},
- calcdata: []
+ calcdata: [],
+ _context: {locale: 'en', dictionaries: {}}
};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
Plots.doCalcdata(gd);
var plotinfo = {
diff --git a/test/jasmine/tests/carpet_test.js b/test/jasmine/tests/carpet_test.js
index 4e2164188da..1bae596789d 100644
--- a/test/jasmine/tests/carpet_test.js
+++ b/test/jasmine/tests/carpet_test.js
@@ -14,6 +14,8 @@ var fail = require('../assets/fail_test');
var mouseEvent = require('../assets/mouse_event');
var assertHoverLabelContent = require('../assets/custom_assertions').assertHoverLabelContent;
+var supplyAllDefaults = require('../assets/supply_defaults');
+
describe('carpet supplyDefaults', function() {
'use strict';
@@ -114,13 +116,13 @@ describe('carpet supplyDefaults', function() {
describe('supplyDefaults visibility check', function() {
it('does not hide empty subplots', function() {
var gd = {data: [], layout: {xaxis: {}}};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(gd._fullLayout.xaxis.visible).toBe(true);
});
it('does not hide axes with non-carpet traces', function() {
var gd = {data: [{x: []}]};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(gd._fullLayout.xaxis.visible).toBe(true);
});
@@ -135,7 +137,7 @@ describe('supplyDefaults visibility check', function() {
type: 'contourcarpet',
z: [[1, 2, 3], [4, 5, 6]],
}]};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(gd._fullLayout.xaxis.visible).toBe(true);
});
@@ -149,7 +151,7 @@ describe('supplyDefaults visibility check', function() {
type: 'contourcarpet',
z: [[1, 2, 3], [4, 5, 6]],
}]};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(gd._fullLayout.xaxis.visible).toBe(false);
});
@@ -179,7 +181,7 @@ describe('supplyDefaults visibility check', function() {
}]
};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(gd._fullLayout.xaxis.visible).toBe(true);
});
@@ -209,7 +211,7 @@ describe('supplyDefaults visibility check', function() {
}]
};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(gd._fullLayout.xaxis.visible).toBe(true);
});
});
diff --git a/test/jasmine/tests/choropleth_test.js b/test/jasmine/tests/choropleth_test.js
index 9c2465e5ff9..9dd6cf79b02 100644
--- a/test/jasmine/tests/choropleth_test.js
+++ b/test/jasmine/tests/choropleth_test.js
@@ -22,7 +22,8 @@ describe('Test choropleth', function() {
var defaultColor = '#444',
layout = {
- font: Plots.layoutAttributes.font
+ font: Plots.layoutAttributes.font,
+ _dfltTitle: {colorbar: 'cb'}
};
beforeEach(function() {
@@ -171,7 +172,7 @@ describe('choropleth bad data', function() {
afterEach(destroyGraphDiv);
it('should not throw an error with bad locations', function(done) {
- spyOn(Lib, 'warn');
+ spyOn(Lib, 'log');
Plotly.newPlot(gd, [{
locations: ['canada', 0, null, '', 'utopia'],
z: [1, 2, 3, 4, 5],
@@ -179,8 +180,8 @@ describe('choropleth bad data', function() {
type: 'choropleth'
}])
.then(function() {
- // only utopia warns - others are silently ignored
- expect(Lib.warn).toHaveBeenCalledTimes(1);
+ // only utopia logs - others are silently ignored
+ expect(Lib.log).toHaveBeenCalledTimes(1);
})
.catch(fail)
.then(done);
diff --git a/test/jasmine/tests/colorscale_test.js b/test/jasmine/tests/colorscale_test.js
index 462d53c2a08..3eaa7c902d5 100644
--- a/test/jasmine/tests/colorscale_test.js
+++ b/test/jasmine/tests/colorscale_test.js
@@ -195,7 +195,8 @@ describe('Test colorscale:', function() {
describe('handleDefaults (heatmap-like version)', function() {
var handleDefaults = Colorscale.handleDefaults,
layout = {
- font: Plots.layoutAttributes.font
+ font: Plots.layoutAttributes.font,
+ _dfltTitle: {colorbar: 'cb'}
},
opts = {prefix: '', cLetter: 'z'};
var traceIn, traceOut;
@@ -265,7 +266,8 @@ describe('Test colorscale:', function() {
describe('handleDefaults (scatter-like version)', function() {
var handleDefaults = Colorscale.handleDefaults,
layout = {
- font: Plots.layoutAttributes.font
+ font: Plots.layoutAttributes.font,
+ _dfltTitle: {colorbar: 'cb'}
},
opts = {prefix: 'marker.', cLetter: 'c'};
var traceIn, traceOut;
diff --git a/test/jasmine/tests/command_test.js b/test/jasmine/tests/command_test.js
index e3bef641bcf..ba061fefb3d 100644
--- a/test/jasmine/tests/command_test.js
+++ b/test/jasmine/tests/command_test.js
@@ -519,7 +519,7 @@ describe('component bindings', function() {
it('logs a warning if unable to create an observer', function() {
var warnings = 0;
- spyOn(Lib, 'warn').and.callFake(function() {
+ spyOn(Lib, 'log').and.callFake(function() {
warnings++;
});
diff --git a/test/jasmine/tests/contour_test.js b/test/jasmine/tests/contour_test.js
index 989a164eeb4..279b451bf46 100644
--- a/test/jasmine/tests/contour_test.js
+++ b/test/jasmine/tests/contour_test.js
@@ -10,6 +10,7 @@ var fail = require('../assets/fail_test');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var checkTicks = require('../assets/custom_assertions').checkTicks;
+var supplyAllDefaults = require('../assets/supply_defaults');
describe('contour defaults', function() {
@@ -20,7 +21,8 @@ describe('contour defaults', function() {
var defaultColor = '#444',
layout = {
- font: Plots.layoutAttributes.font
+ font: Plots.layoutAttributes.font,
+ _dfltTitle: {colorbar: 'cb'}
};
var supplyDefaults = Contour.supplyDefaults;
@@ -64,7 +66,7 @@ describe('contour defaults', function() {
y: [1, 2],
z: [[1, 2], [3, 4]]
};
- supplyDefaults(traceIn, traceOut, defaultColor, {calendar: 'islamic'});
+ supplyDefaults(traceIn, traceOut, defaultColor, Lib.extendFlat({calendar: 'islamic'}, layout));
// we always fill calendar attributes, because it's hard to tell if
// we're on a date axis at this point.
@@ -80,7 +82,7 @@ describe('contour defaults', function() {
xcalendar: 'coptic',
ycalendar: 'ethiopian'
};
- supplyDefaults(traceIn, traceOut, defaultColor, {calendar: 'islamic'});
+ supplyDefaults(traceIn, traceOut, defaultColor, Lib.extendFlat({calendar: 'islamic'}, layout));
// we always fill calendar attributes, because it's hard to tell if
// we're on a date axis at this point.
@@ -182,7 +184,7 @@ describe('contour calc', function() {
trace = Lib.extendFlat({}, base, opts),
gd = { data: [trace] };
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
var fullTrace = gd._fullData[0];
var out = Contour.calc(gd, fullTrace)[0];
diff --git a/test/jasmine/tests/finance_test.js b/test/jasmine/tests/finance_test.js
index 5abf1e455be..5df5ba59e10 100644
--- a/test/jasmine/tests/finance_test.js
+++ b/test/jasmine/tests/finance_test.js
@@ -5,6 +5,7 @@ var Lib = require('@src/lib');
var d3 = require('d3');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
+var supplyAllDefaults = require('../assets/supply_defaults');
var mock0 = {
open: [33.01, 33.31, 33.50, 32.06, 34.12, 33.05, 33.31, 33.50],
@@ -29,7 +30,7 @@ describe('finance charts defaults:', function() {
layout: layout
};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
return gd;
}
@@ -389,7 +390,7 @@ describe('finance charts calc transforms:', function() {
layout: layout || {}
};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
Plots.doCalcdata(gd);
return gd.calcdata.map(calcDatatoTrace);
@@ -474,10 +475,10 @@ describe('finance charts calc transforms:', function() {
expect(out[0].hoverinfo).toEqual('x+text+name');
expect(out[0].text[0])
- .toEqual('Open: 33.01
High: 34.2
Low: 31.7
Close: 34.1
A');
+ .toEqual('open: 33.01
high: 34.2
low: 31.7
close: 34.1
A');
expect(out[0].hoverinfo).toEqual('x+text+name');
expect(out[1].text[0])
- .toEqual('Open: 33.31
High: 34.37
Low: 30.75
Close: 31.93
B');
+ .toEqual('open: 33.31
high: 34.37
low: 30.75
close: 31.93
B');
expect(out[2].hoverinfo).toEqual('x+text');
expect(out[2].text[0]).toEqual('IMPORTANT');
@@ -487,10 +488,10 @@ describe('finance charts calc transforms:', function() {
expect(out[4].hoverinfo).toEqual('text');
expect(out[4].text[0])
- .toEqual('Open: 33.01
High: 34.2
Low: 31.7
Close: 34.1');
+ .toEqual('open: 33.01
high: 34.2
low: 31.7
close: 34.1');
expect(out[5].hoverinfo).toEqual('text');
expect(out[5].text[0])
- .toEqual('Open: 33.31
High: 34.37
Low: 30.75
Close: 31.93');
+ .toEqual('open: 33.31
high: 34.37
low: 30.75
close: 31.93');
expect(out[6].hoverinfo).toEqual('x');
expect(out[6].text[0]).toEqual('');
diff --git a/test/jasmine/tests/fx_test.js b/test/jasmine/tests/fx_test.js
index 54906198400..1c425b84357 100644
--- a/test/jasmine/tests/fx_test.js
+++ b/test/jasmine/tests/fx_test.js
@@ -1,9 +1,9 @@
var Plotly = require('@lib/index');
-var Plots = require('@src/plots/plots');
var d3 = require('d3');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
+var supplyAllDefaults = require('../assets/supply_defaults');
describe('Fx defaults', function() {
'use strict';
@@ -14,7 +14,7 @@ describe('Fx defaults', function() {
layout: layout || {}
};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
return {
data: gd._fullData,
diff --git a/test/jasmine/tests/gl3daxes_test.js b/test/jasmine/tests/gl3daxes_test.js
index fad1f8c222b..ea8f219e834 100644
--- a/test/jasmine/tests/gl3daxes_test.js
+++ b/test/jasmine/tests/gl3daxes_test.js
@@ -12,7 +12,8 @@ describe('Test Gl3dAxes', function() {
font: 'Open Sans',
scene: {id: 'scene'},
data: [{x: [], y: []}],
- bgColor: '#fff'
+ bgColor: '#fff',
+ fullLayout: {_dfltTitle: {x: 'xxx', y: 'yyy', colorbar: 'cbbb'}}
};
beforeEach(function() {
diff --git a/test/jasmine/tests/gl3dlayout_test.js b/test/jasmine/tests/gl3dlayout_test.js
index 4ae24334afd..cbcdaf72ea4 100644
--- a/test/jasmine/tests/gl3dlayout_test.js
+++ b/test/jasmine/tests/gl3dlayout_test.js
@@ -18,7 +18,7 @@ describe('Test Gl3d layout defaults', function() {
var supplyLayoutDefaults = Gl3d.supplyLayoutDefaults;
beforeEach(function() {
- layoutOut = { _basePlotModules: ['gl3d'] };
+ layoutOut = { _basePlotModules: ['gl3d'], _dfltTitle: {x: 'xxx', y: 'yyy', colorbar: 'cbbb'} };
// needs a scene-ref in a trace in order to be detected
fullData = [ { type: 'scatter3d', scene: 'scene' }];
diff --git a/test/jasmine/tests/heatmap_test.js b/test/jasmine/tests/heatmap_test.js
index 81e7737c736..70c86e4e816 100644
--- a/test/jasmine/tests/heatmap_test.js
+++ b/test/jasmine/tests/heatmap_test.js
@@ -9,6 +9,7 @@ var Heatmap = require('@src/traces/heatmap');
var d3 = require('d3');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
+var supplyAllDefaults = require('../assets/supply_defaults');
describe('heatmap supplyDefaults', function() {
@@ -19,7 +20,8 @@ describe('heatmap supplyDefaults', function() {
var defaultColor = '#444',
layout = {
- font: Plots.layoutAttributes.font
+ font: Plots.layoutAttributes.font,
+ _dfltTitle: {colorbar: 'cb'}
};
var supplyDefaults = Heatmap.supplyDefaults;
@@ -131,7 +133,7 @@ describe('heatmap supplyDefaults', function() {
y: [1, 2],
z: [[1, 2], [3, 4]]
};
- supplyDefaults(traceIn, traceOut, defaultColor, {calendar: 'islamic'});
+ supplyDefaults(traceIn, traceOut, defaultColor, Lib.extendDeep({calendar: 'islamic'}, layout));
// we always fill calendar attributes, because it's hard to tell if
// we're on a date axis at this point.
@@ -147,7 +149,7 @@ describe('heatmap supplyDefaults', function() {
xcalendar: 'coptic',
ycalendar: 'ethiopian'
};
- supplyDefaults(traceIn, traceOut, defaultColor, {calendar: 'islamic'});
+ supplyDefaults(traceIn, traceOut, defaultColor, Lib.extendDeep({calendar: 'islamic'}, layout));
// we always fill calendar attributes, because it's hard to tell if
// we're on a date axis at this point.
@@ -298,7 +300,7 @@ describe('heatmap calc', function() {
trace = Lib.extendFlat({}, base, opts),
gd = { data: [trace] };
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
var fullTrace = gd._fullData[0];
var fullLayout = gd._fullLayout;
diff --git a/test/jasmine/tests/histogram2d_test.js b/test/jasmine/tests/histogram2d_test.js
index 9529d3b380a..2ce0783e677 100644
--- a/test/jasmine/tests/histogram2d_test.js
+++ b/test/jasmine/tests/histogram2d_test.js
@@ -1,17 +1,23 @@
var Plotly = require('@lib/index');
-var Plots = require('@src/plots/plots');
var Lib = require('@src/lib');
-var supplyDefaults = require('@src/traces/histogram2d/defaults');
+var supplyDefaultsRaw = require('@src/traces/histogram2d/defaults');
var calc = require('@src/traces/histogram2d/calc');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var fail = require('../assets/fail_test');
+var supplyAllDefaults = require('../assets/supply_defaults');
describe('Test histogram2d', function() {
'use strict';
+ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
+ layout._dfltTitle = {colorbar: 'cb'};
+
+ return supplyDefaultsRaw(traceIn, traceOut, defaultColor, layout);
+ }
+
describe('supplyDefaults', function() {
var traceIn,
traceOut;
@@ -115,7 +121,7 @@ describe('Test histogram2d', function() {
trace = Lib.extendFlat({}, base, opts),
gd = { data: [trace] };
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
var fullTrace = gd._fullData[0];
var out = calc(gd, fullTrace);
diff --git a/test/jasmine/tests/histogram_test.js b/test/jasmine/tests/histogram_test.js
index 60f4d57abd0..c4ce0a0c6bb 100644
--- a/test/jasmine/tests/histogram_test.js
+++ b/test/jasmine/tests/histogram_test.js
@@ -1,5 +1,4 @@
var Plotly = require('@lib/index');
-var Plots = require('@src/plots/plots');
var Lib = require('@src/lib');
var setConvert = require('@src/plots/cartesian/set_convert');
@@ -9,6 +8,7 @@ var getBinSpanLabelRound = require('@src/traces/histogram/bin_label_vals');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
+var supplyAllDefaults = require('../assets/supply_defaults');
describe('Test histogram', function() {
@@ -177,7 +177,7 @@ describe('Test histogram', function() {
});
}
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
var fullTrace = gd._fullData[0];
var out = calc(gd, fullTrace);
diff --git a/test/jasmine/tests/lib_date_test.js b/test/jasmine/tests/lib_date_test.js
index 2c5cd93e615..592d111ed22 100644
--- a/test/jasmine/tests/lib_date_test.js
+++ b/test/jasmine/tests/lib_date_test.js
@@ -1,6 +1,7 @@
var isNumeric = require('fast-isnumeric');
var Lib = require('@src/lib');
+var Loggers = require('@src/lib/loggers');
var calComponent = require('@src/components/calendars');
// use only the parts of world-calendars that we've imported for our tests
@@ -360,6 +361,11 @@ describe('dates', function() {
});
it('should fail numbers & js Dates out of range, and other bad objects', function() {
+ var errors = [];
+ spyOn(Loggers, 'error').and.callFake(function(msg) {
+ errors.push(msg);
+ });
+
[
new Date(-20000, 0, 1),
new Date(20000, 0, 1),
@@ -372,6 +378,8 @@ describe('dates', function() {
if(!isNumeric(+v)) expect(Lib.cleanDate(+v)).toBeUndefined();
expect(Lib.cleanDate(v, '2000-01-01')).toBe('2000-01-01');
});
+
+ expect(errors.length).toBe(16);
});
it('should not alter valid date strings, even to truncate them', function() {
diff --git a/test/jasmine/tests/localize_test.js b/test/jasmine/tests/localize_test.js
new file mode 100644
index 00000000000..4d1989a65e7
--- /dev/null
+++ b/test/jasmine/tests/localize_test.js
@@ -0,0 +1,109 @@
+var Lib = require('@src/lib');
+var _ = Lib._;
+var registry = require('@src/registry');
+
+var Plotly = require('@lib');
+var createGraphDiv = require('../assets/create_graph_div');
+var destroyGraphDiv = require('../assets/destroy_graph_div');
+var failTest = require('../assets/fail_test');
+
+describe('localization', function() {
+ 'use strict';
+
+ var gd;
+ var preregisteredDicts;
+
+ beforeEach(function() {
+ gd = createGraphDiv();
+
+ // empty out any dictionaries we might register by default
+ preregisteredDicts = registry.localeRegistry;
+ registry.localeRegistry = {};
+ });
+
+ afterEach(function() {
+ destroyGraphDiv();
+ registry.localeRegistry = preregisteredDicts;
+ });
+
+ function plot(locale, dicts) {
+ var config = {};
+ if(locale) config.locale = locale;
+ if(dicts) config.dictionaries = dicts;
+
+ return Plotly.newPlot(gd, [{y: [1, 2]}], {}, config);
+ }
+
+ it('uses the input string if no dictionaries are provided', function(done) {
+ plot()
+ .then(function() {
+ ['a', 'list of', 'Test strings 234!!!'].forEach(function(s) {
+ expect(_(gd, s)).toBe(s);
+ });
+ })
+ .catch(failTest)
+ .then(done);
+ });
+
+ it('uses the region first, then language (registered case)', function(done) {
+ plot('en-AU')
+ .then(function() {
+ expect(_(gd, 'dollar')).toBe('dollar');
+
+ // "en-GB" is registered first, so it gets copied into the base "en"
+ Plotly.register({moduleType: 'locale', name: 'en-GB', dictionary: {dollar: 'pound'}});
+ Plotly.register({moduleType: 'locale', name: 'en-US', dictionary: {dollar: 'greenback', cent: 'penny'}});
+
+ expect(_(gd, 'dollar')).toBe('pound');
+ // copying to the base happens at the dictionary level, so items missing
+ // from the first dictionary will not be picked up from later ones
+ expect(_(gd, 'cent')).toBe('cent');
+
+ // "en-AU" is exactly what we're looking for.
+ Plotly.register({moduleType: 'locale', name: 'en-AU', dictionary: {dollar: 'dollah'}});
+
+ expect(_(gd, 'dollar')).toBe('dollah');
+ expect(_(gd, 'cent')).toBe('cent');
+ })
+ .catch(failTest)
+ .then(done);
+ });
+
+ it('gives higher precedence to region than context vs registered', function(done) {
+ // four dictionaries, highest to lowest priority
+ // hopefully nobody will supply this many conflicting dictionaries, but
+ // if they do, this is what should happen!
+ var ctx_fr_QC = {
+ a: 'a-ctx-QC'
+ };
+ Plotly.register({moduleType: 'locale', name: 'fr-QC', dictionary: {
+ a: 'a-reg-QC', b: 'b-reg-QC'
+ }});
+ var ctx_fr = {
+ a: 'a-ctx', b: 'b-ctx', c: 'c-ctx'
+ };
+ Plotly.register({moduleType: 'locale', name: 'fr', dictionary: {
+ a: 'a-reg', b: 'b-reg', c: 'c-reg', d: 'd-reg'
+ }});
+
+ plot('fr-QC', {fr: ctx_fr, 'fr-QC': ctx_fr_QC})
+ .then(function() {
+ expect(_(gd, 'a')).toBe('a-ctx-QC');
+ expect(_(gd, 'b')).toBe('b-reg-QC');
+ expect(_(gd, 'c')).toBe('c-ctx');
+ expect(_(gd, 'd')).toBe('d-reg');
+ expect(_(gd, 'e')).toBe('e');
+ })
+ .catch(failTest)
+ .then(done);
+ });
+
+ it('does not generate an automatic base language dictionary in context', function(done) {
+ plot('fr', {'fr-QC': {fries: 'poutine'}})
+ .then(function() {
+ expect(_(gd, 'fries')).toBe('fries');
+ })
+ .catch(failTest)
+ .then(done);
+ });
+});
diff --git a/test/jasmine/tests/mapbox_test.js b/test/jasmine/tests/mapbox_test.js
index 68590653f1f..67dff7bae4e 100644
--- a/test/jasmine/tests/mapbox_test.js
+++ b/test/jasmine/tests/mapbox_test.js
@@ -1,5 +1,4 @@
var Plotly = require('@lib');
-var Plots = require('@src/plots/plots');
var Lib = require('@src/lib');
var constants = require('@src/plots/mapbox/constants');
@@ -10,6 +9,7 @@ var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var mouseEvent = require('../assets/mouse_event');
var failTest = require('../assets/fail_test');
+var supplyAllDefaults = require('../assets/supply_defaults');
var customAssertions = require('../assets/custom_assertions');
var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle;
@@ -180,7 +180,7 @@ describe('mapbox defaults', function() {
layout: {}
};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(gd._fullLayout.dragmode).toBe('pan');
});
});
diff --git a/test/jasmine/tests/modebar_test.js b/test/jasmine/tests/modebar_test.js
index 1b37fd74b25..425732ef006 100644
--- a/test/jasmine/tests/modebar_test.js
+++ b/test/jasmine/tests/modebar_test.js
@@ -37,7 +37,9 @@ describe('ModeBar', function() {
displaylogo: true,
displayModeBar: true,
modeBarButtonsToRemove: [],
- modeBarButtonsToAdd: []
+ modeBarButtonsToAdd: [],
+ locale: 'en',
+ dictionaries: {}
}
};
}
diff --git a/test/jasmine/tests/parcoords_test.js b/test/jasmine/tests/parcoords_test.js
index a632a4d21d2..1b8772d354c 100644
--- a/test/jasmine/tests/parcoords_test.js
+++ b/test/jasmine/tests/parcoords_test.js
@@ -8,6 +8,7 @@ var attributes = require('@src/traces/parcoords/attributes');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var mouseEvent = require('../assets/mouse_event');
+var supplyAllDefaults = require('../assets/supply_defaults');
// mock with two dimensions (one panel); special case, e.g. left and right panel is obv. the same
var mock2 = require('@mocks/gl2d_parcoords_2.json');
@@ -33,7 +34,7 @@ describe('parcoords initialization tests', function() {
it('should not coerce trace opacity', function() {
var gd = Lib.extendDeep({}, mock1);
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(gd._fullData[0].opacity).toBeUndefined();
});
@@ -46,7 +47,7 @@ describe('parcoords initialization tests', function() {
color: 'blue'
};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
var expected = {
family: 'Gravitas',
@@ -169,7 +170,7 @@ describe('parcoords initialization tests', function() {
function _calc(trace) {
var gd = { data: [trace] };
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
var fullTrace = gd._fullData[0];
Parcoords.calc(gd, fullTrace);
diff --git a/test/jasmine/tests/plot_api_test.js b/test/jasmine/tests/plot_api_test.js
index 59a02aa79c5..6974f8ff63a 100644
--- a/test/jasmine/tests/plot_api_test.js
+++ b/test/jasmine/tests/plot_api_test.js
@@ -16,6 +16,7 @@ var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var fail = require('../assets/fail_test');
var checkTicks = require('../assets/custom_assertions').checkTicks;
+var supplyAllDefaults = require('../assets/supply_defaults');
describe('Test plot api', function() {
@@ -516,7 +517,7 @@ describe('Test plot api', function() {
subroutines[m].calls.reset();
});
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
Plots.doCalcdata(gd);
return gd;
}
@@ -576,7 +577,7 @@ describe('Test plot api', function() {
});
function mockDefaultsAndCalc(gd) {
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
gd.calcdata = gd._fullData.map(function(trace) {
return [{x: 1, y: 1, trace: trace}];
});
diff --git a/test/jasmine/tests/plots_test.js b/test/jasmine/tests/plots_test.js
index 355a7daf07b..b6f31cab997 100644
--- a/test/jasmine/tests/plots_test.js
+++ b/test/jasmine/tests/plots_test.js
@@ -5,6 +5,7 @@ var Lib = require('@src/lib');
var d3 = require('d3');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
+var supplyAllDefaults = require('../assets/supply_defaults');
describe('Test Plots', function() {
@@ -20,7 +21,7 @@ describe('Test Plots', function() {
}
};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(gd.layout.height).toBe(height);
expect(gd._fullLayout).toBeDefined();
expect(gd._fullLayout.height).toBe(height);
@@ -70,7 +71,7 @@ describe('Test Plots', function() {
layout: newLayout
};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(gd._fullData[0].z).toBe(newData[0].z);
expect(gd._fullData[1].z).toBe(newData[1].z);
@@ -94,7 +95,7 @@ describe('Test Plots', function() {
var data = [trace0, trace1];
var gd = { data: data };
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(gd.data).toBe(data);
@@ -116,7 +117,7 @@ describe('Test Plots', function() {
function testSanitizeMarginsHasBeenCalledOnlyOnce(gd) {
spyOn(Plots, 'sanitizeMargins').and.callThrough();
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(Plots.sanitizeMargins).toHaveBeenCalledTimes(1);
}
@@ -159,7 +160,12 @@ describe('Test Plots', function() {
layoutOut,
expected;
- var supplyLayoutDefaults = Plots.supplyLayoutGlobalDefaults;
+ function supplyLayoutDefaults(layoutIn, layoutOut) {
+ layoutOut._dfltTitle = {
+ plot: 'ppplot'
+ };
+ return Plots.supplyLayoutGlobalDefaults(layoutIn, layoutOut);
+ }
beforeEach(function() {
layoutOut = {};
diff --git a/test/jasmine/tests/range_slider_test.js b/test/jasmine/tests/range_slider_test.js
index 1cd215ab62c..3cdfa6a2237 100644
--- a/test/jasmine/tests/range_slider_test.js
+++ b/test/jasmine/tests/range_slider_test.js
@@ -1,5 +1,4 @@
var Plotly = require('@lib/index');
-var Plots = require('@src/plots/plots');
var Lib = require('@src/lib');
var setConvert = require('@src/plots/cartesian/set_convert');
@@ -11,6 +10,7 @@ var d3 = require('d3');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var mouseEvent = require('../assets/mouse_event');
+var supplyAllDefaults = require('../assets/supply_defaults');
var TOL = 6;
@@ -585,7 +585,7 @@ describe('the range slider', function() {
}
};
- Plots.supplyDefaults(mock);
+ supplyAllDefaults(mock);
expect(mock._fullLayout.xaxis.rangeslider.visible).toBe(true);
expect(mock._fullLayout.yaxis.fixedrange).toBe(true);
@@ -603,7 +603,7 @@ describe('the range slider', function() {
}
};
- Plots.supplyDefaults(mock);
+ supplyAllDefaults(mock);
expect(mock._fullLayout.xaxis.rangeslider.visible).toBe(true);
expect(mock._fullLayout.yaxis.fixedrange).toBe(false);
diff --git a/test/jasmine/tests/sankey_test.js b/test/jasmine/tests/sankey_test.js
index 33e36cee22d..573d3aa57c2 100644
--- a/test/jasmine/tests/sankey_test.js
+++ b/test/jasmine/tests/sankey_test.js
@@ -4,7 +4,6 @@ var Lib = require('@src/lib');
var d3 = require('d3');
var mock = require('@mocks/sankey_energy.json');
var mockDark = require('@mocks/sankey_energy_dark.json');
-var Plots = require('@src/plots/plots');
var Sankey = require('@src/traces/sankey');
var createGraphDiv = require('../assets/create_graph_div');
@@ -12,6 +11,7 @@ var destroyGraphDiv = require('../assets/destroy_graph_div');
var fail = require('../assets/fail_test');
var mouseEvent = require('../assets/mouse_event');
var assertHoverLabelStyle = require('../assets/custom_assertions').assertHoverLabelStyle;
+var supplyAllDefaults = require('../assets/supply_defaults');
describe('sankey tests', function() {
@@ -87,7 +87,7 @@ describe('sankey tests', function() {
it('should not coerce trace opacity', function() {
var gd = Lib.extendDeep({}, mock);
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(gd._fullData[0].opacity).toBeUndefined();
});
@@ -223,7 +223,7 @@ describe('sankey tests', function() {
function _calc(trace) {
var gd = { data: [trace] };
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
var fullTrace = gd._fullData[0];
Sankey.calc(gd, fullTrace);
return fullTrace;
@@ -231,30 +231,19 @@ describe('sankey tests', function() {
var base = { type: 'sankey' };
- it('circularity is detected', function() {
+ describe('remove nodes if encountering circularity', function() {
+ var errors;
- var errors = [];
- spyOn(Lib, 'error').and.callFake(function(msg) {
- errors.push(msg);
+ beforeEach(function() {
+ errors = [];
+ spyOn(Lib, 'error').and.callFake(function(msg) {
+ errors.push(msg);
+ });
});
- _calc(Lib.extendDeep({}, base, {
- node: {
- label: ['a', 'b', 'c']
- },
- link: {
- value: [1, 1, 1],
- source: [0, 1, 2],
- target: [1, 2, 0]
- }
- }));
-
- expect(errors.length).toEqual(1);
- });
-
- describe('remove nodes if encountering circularity', function() {
-
it('removing a single self-pointing node', function() {
+ expect(errors.length).toBe(0);
+
var fullTrace = _calc(Lib.extendDeep({}, base, {
node: {
label: ['a']
@@ -270,10 +259,12 @@ describe('sankey tests', function() {
expect(fullTrace.link.value).toEqual([], 'link value(s) removed');
expect(fullTrace.link.source).toEqual([], 'link source(s) removed');
expect(fullTrace.link.target).toEqual([], 'link target(s) removed');
-
+ expect(errors.length).toBe(1);
});
it('removing everything if detecting a circle', function() {
+ expect(errors.length).toBe(0);
+
var fullTrace = _calc(Lib.extendDeep({}, base, {
node: {
label: ['a', 'b', 'c', 'd', 'e']
@@ -289,7 +280,7 @@ describe('sankey tests', function() {
expect(fullTrace.link.value).toEqual([], 'link value(s) removed');
expect(fullTrace.link.source).toEqual([], 'link source(s) removed');
expect(fullTrace.link.target).toEqual([], 'link target(s) removed');
-
+ expect(errors.length).toBe(1);
});
});
});
@@ -390,7 +381,7 @@ describe('sankey tests', function() {
_hover(404, 302);
assertLabel(
- ['Solid', 'Incoming flow count: 4', 'Outgoing flow count: 3', '447TWh'],
+ ['Solid', 'incoming flow count: 4', 'outgoing flow count: 3', '447TWh'],
['rgb(148, 103, 189)', 'rgb(255, 255, 255)', 13, 'Arial', 'rgb(255, 255, 255)']
);
})
@@ -398,7 +389,7 @@ describe('sankey tests', function() {
_hover(450, 300);
assertLabel(
- ['Source: Solid', 'Target: Industry', '46TWh'],
+ ['source: Solid', 'target: Industry', '46TWh'],
['rgb(0, 0, 96)', 'rgb(255, 255, 255)', 13, 'Arial', 'rgb(255, 255, 255)']
);
@@ -408,7 +399,7 @@ describe('sankey tests', function() {
_hover(404, 302);
assertLabel(
- ['Solid', 'Incoming flow count: 4', 'Outgoing flow count: 3', '447TWh'],
+ ['Solid', 'incoming flow count: 4', 'outgoing flow count: 3', '447TWh'],
['rgb(148, 103, 189)', 'rgb(255, 255, 255)', 13, 'Roboto', 'rgb(255, 255, 255)']
);
})
@@ -416,7 +407,7 @@ describe('sankey tests', function() {
_hover(450, 300);
assertLabel(
- ['Source: Solid', 'Target: Industry', '46TWh'],
+ ['source: Solid', 'target: Industry', '46TWh'],
['rgb(0, 0, 96)', 'rgb(255, 255, 255)', 13, 'Roboto', 'rgb(255, 255, 255)']
);
@@ -431,7 +422,7 @@ describe('sankey tests', function() {
_hover(404, 302);
assertLabel(
- ['Solid', 'Incoming flow count: 4', 'Outgoing flow count: 3', '447TWh'],
+ ['Solid', 'incoming flow count: 4', 'outgoing flow count: 3', '447TWh'],
['rgb(255, 0, 0)', 'rgb(0, 0, 255)', 20, 'Roboto', 'rgb(0, 0, 0)']
);
})
@@ -439,7 +430,7 @@ describe('sankey tests', function() {
_hover(450, 300);
assertLabel(
- ['Source: Solid', 'Target: Industry', '46TWh'],
+ ['source: Solid', 'target: Industry', '46TWh'],
['rgb(255, 0, 0)', 'rgb(0, 0, 255)', 20, 'Roboto', 'rgb(0, 0, 0)']
);
})
@@ -463,7 +454,7 @@ describe('sankey tests', function() {
_hover(450, 300);
assertLabel(
- ['Source: Solid', 'Target: Industry', '46TWh'],
+ ['source: Solid', 'target: Industry', '46TWh'],
['rgb(0, 0, 96)', 'rgb(255, 255, 255)', 13, 'Arial', 'rgb(255, 255, 255)']
);
})
diff --git a/test/jasmine/tests/scattergeo_test.js b/test/jasmine/tests/scattergeo_test.js
index c1a51f4b23c..1c9e107e020 100644
--- a/test/jasmine/tests/scattergeo_test.js
+++ b/test/jasmine/tests/scattergeo_test.js
@@ -1,5 +1,4 @@
var Plotly = require('@lib');
-var Plots = require('@src/plots/plots');
var Lib = require('@src/lib');
var BADNUM = require('@src/constants/numerical').BADNUM;
@@ -14,6 +13,7 @@ var customAssertions = require('../assets/custom_assertions');
var assertHoverLabelStyle = customAssertions.assertHoverLabelStyle;
var assertHoverLabelContent = customAssertions.assertHoverLabelContent;
var fail = require('../assets/fail_test');
+var supplyAllDefaults = require('../assets/supply_defaults');
describe('Test scattergeo defaults', function() {
var traceIn,
@@ -90,11 +90,12 @@ describe('Test scattergeo calc', function() {
var trace = Lib.extendFlat({}, base, opts);
var gd = { data: [trace] };
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
var fullTrace = gd._fullData[0];
return ScatterGeo.calc(gd, fullTrace).map(function(obj) {
delete obj.i;
+ delete obj.t;
return obj;
});
}
@@ -347,15 +348,15 @@ describe('scattergeo bad data', function() {
afterEach(destroyGraphDiv);
it('should not throw an error with bad locations', function(done) {
- spyOn(Lib, 'warn');
+ spyOn(Lib, 'log');
Plotly.newPlot(gd, [{
locations: ['canada', 0, null, '', 'utopia'],
locationmode: 'country names',
type: 'scattergeo'
}])
.then(function() {
- // only utopia warns - others are silently ignored
- expect(Lib.warn).toHaveBeenCalledTimes(1);
+ // only utopia logs - others are silently ignored
+ expect(Lib.log).toHaveBeenCalledTimes(1);
})
.catch(fail)
.then(done);
diff --git a/test/jasmine/tests/scattermapbox_test.js b/test/jasmine/tests/scattermapbox_test.js
index 729b4cd6abc..bc355973a2e 100644
--- a/test/jasmine/tests/scattermapbox_test.js
+++ b/test/jasmine/tests/scattermapbox_test.js
@@ -8,6 +8,7 @@ var convert = require('@src/traces/scattermapbox/convert');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var fail = require('../assets/fail_test');
+var supplyAllDefaults = require('../assets/supply_defaults');
var mouseEvent = require('../assets/mouse_event');
var click = require('../assets/click');
@@ -112,7 +113,7 @@ describe('scattermapbox convert', function() {
function _convert(trace) {
var gd = { data: [trace] };
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
var fullTrace = gd._fullData[0];
Plots.doCalcdata(gd, fullTrace);
diff --git a/test/jasmine/tests/scatterternary_test.js b/test/jasmine/tests/scatterternary_test.js
index ad46a26303f..4396be60261 100644
--- a/test/jasmine/tests/scatterternary_test.js
+++ b/test/jasmine/tests/scatterternary_test.js
@@ -1,5 +1,4 @@
var Plotly = require('@lib');
-var Plots = require('@src/plots/plots');
var Lib = require('@src/lib');
var ScatterTernary = require('@src/traces/scatterternary');
@@ -8,6 +7,7 @@ var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var fail = require('../assets/fail_test');
var customAssertions = require('../assets/custom_assertions');
+var supplyAllDefaults = require('../assets/supply_defaults');
var assertClip = customAssertions.assertClip;
var assertNodeDisplay = customAssertions.assertNodeDisplay;
@@ -149,7 +149,7 @@ describe('scatterternary defaults', function() {
};
var gd = {data: [traceIn, {}]};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(gd._fullData[0].hoverinfo).toBe('all');
});
@@ -163,7 +163,7 @@ describe('scatterternary defaults', function() {
};
var gd = {data: [traceIn]};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(gd._fullData[0].hoverinfo).toBe('a+b+c+text');
});
diff --git a/test/jasmine/tests/select_test.js b/test/jasmine/tests/select_test.js
index 38bf19fb1ba..0010264a62e 100644
--- a/test/jasmine/tests/select_test.js
+++ b/test/jasmine/tests/select_test.js
@@ -889,7 +889,7 @@ describe('Test select box and lasso per trace:', function() {
[[350, 200], [400, 250]],
function() {
assertPoints([['GBR', 26.507354205352502], ['IRL', 86.4125147625692]]);
- assertSelectedPoints({0: [54, 68]});
+ assertSelectedPoints({0: [43, 54]});
assertRanges([[-19.11, 63.06], [7.31, 53.72]]);
},
[280, 190],
@@ -904,7 +904,7 @@ describe('Test select box and lasso per trace:', function() {
[[350, 200], [400, 200], [400, 250], [350, 250], [350, 200]],
function() {
assertPoints([['GBR', 26.507354205352502], ['IRL', 86.4125147625692]]);
- assertSelectedPoints({0: [54, 68]});
+ assertSelectedPoints({0: [43, 54]});
assertLassoPoints([
[-19.11, 63.06], [5.50, 65.25], [7.31, 53.72], [-12.90, 51.70], [-19.11, 63.06]
]);
diff --git a/test/jasmine/tests/surface_test.js b/test/jasmine/tests/surface_test.js
index 96aa26f0193..b7d23716bc7 100644
--- a/test/jasmine/tests/surface_test.js
+++ b/test/jasmine/tests/surface_test.js
@@ -10,7 +10,7 @@ describe('Test surface', function() {
var supplyDefaults = Surface.supplyDefaults;
var defaultColor = '#444',
- layout = {};
+ layout = {_dfltTitle: {colorbar: 'cb'}};
var traceIn, traceOut;
@@ -155,7 +155,7 @@ describe('Test surface', function() {
traceIn = {
z: [[1, 2, 3], [2, 1, 2]]
};
- supplyDefaults(traceIn, traceOut, defaultColor, {calendar: 'islamic'});
+ supplyDefaults(traceIn, traceOut, defaultColor, Lib.extendFlat({calendar: 'islamic'}, layout));
// we always fill calendar attributes, because it's hard to tell if
// we're on a date axis at this point.
diff --git a/test/jasmine/tests/table_test.js b/test/jasmine/tests/table_test.js
index ddc2676d4cb..5e599cd593e 100644
--- a/test/jasmine/tests/table_test.js
+++ b/test/jasmine/tests/table_test.js
@@ -1,12 +1,12 @@
var Plotly = require('@lib/index');
var Lib = require('@src/lib');
-var Plots = require('@src/plots/plots');
var Table = require('@src/traces/table');
var attributes = require('@src/traces/table/attributes');
var cn = require('@src/traces/table/constants').cn;
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
+var supplyAllDefaults = require('../assets/supply_defaults');
var mockMulti = require('@mocks/table_latex_multitrace.json');
@@ -35,7 +35,7 @@ describe('table initialization tests', function() {
it('should not coerce trace opacity', function() {
var gd = Lib.extendDeep({}, mock1);
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
expect(gd._fullData[0].opacity).toBeUndefined();
});
@@ -50,7 +50,7 @@ describe('table initialization tests', function() {
color: 'blue'
};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
var expected = {
family: 'Gravitas',
diff --git a/test/jasmine/tests/transform_filter_test.js b/test/jasmine/tests/transform_filter_test.js
index 7caee22f0e6..cc7034c739d 100644
--- a/test/jasmine/tests/transform_filter_test.js
+++ b/test/jasmine/tests/transform_filter_test.js
@@ -7,6 +7,7 @@ var Lib = require('@src/lib');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var customAssertions = require('../assets/custom_assertions');
+var supplyAllDefaults = require('../assets/supply_defaults');
var assertDims = customAssertions.assertDims;
var assertStyle = customAssertions.assertStyle;
@@ -97,7 +98,7 @@ describe('filter transforms calc:', function() {
layout: layout || {}
};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
Plots.doCalcdata(gd);
return gd.calcdata.map(calcDatatoTrace);
diff --git a/test/jasmine/tests/transform_multi_test.js b/test/jasmine/tests/transform_multi_test.js
index 94deb0f5505..829d84569db 100644
--- a/test/jasmine/tests/transform_multi_test.js
+++ b/test/jasmine/tests/transform_multi_test.js
@@ -7,6 +7,7 @@ var Lib = require('@src/lib');
var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var customAssertions = require('../assets/custom_assertions');
+var supplyAllDefaults = require('../assets/supply_defaults');
var assertDims = customAssertions.assertDims;
var assertStyle = customAssertions.assertStyle;
@@ -866,7 +867,7 @@ describe('supplyDefaults with groupby + filter', function() {
layout: layout || {}
};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
Plots.doCalcdata(gd);
return gd.calcdata.map(calcDatatoTrace);
diff --git a/test/jasmine/tests/transform_sort_test.js b/test/jasmine/tests/transform_sort_test.js
index cddb44a7acc..38e2be3b79d 100644
--- a/test/jasmine/tests/transform_sort_test.js
+++ b/test/jasmine/tests/transform_sort_test.js
@@ -7,6 +7,7 @@ var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var fail = require('../assets/fail_test');
var mouseEvent = require('../assets/mouse_event');
+var supplyAllDefaults = require('../assets/supply_defaults');
describe('Test sort transform defaults:', function() {
function _supply(trace, layout) {
@@ -76,7 +77,7 @@ describe('Test sort transform calc:', function() {
layout: layout || {}
};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
Plots.doCalcdata(gd);
return gd.calcdata.map(calcDatatoTrace);
diff --git a/test/jasmine/tests/violin_test.js b/test/jasmine/tests/violin_test.js
index 755d2b20e19..0e57bb51318 100644
--- a/test/jasmine/tests/violin_test.js
+++ b/test/jasmine/tests/violin_test.js
@@ -9,6 +9,7 @@ var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');
var fail = require('../assets/fail_test');
var mouseEvent = require('../assets/mouse_event');
+var supplyAllDefaults = require('../assets/supply_defaults');
var customAssertions = require('../assets/custom_assertions');
var assertHoverLabelContent = customAssertions.assertHoverLabelContent;
@@ -152,7 +153,7 @@ describe('Test violin calc:', function() {
layout: layout || {},
calcdata: []
};
- Plots.supplyDefaults(gd);
+ supplyAllDefaults(gd);
Plots.doCalcdata(gd);
cd = gd.calcdata[0];
fullLayout = gd._fullLayout;