Vega translations (#23677)

add vega translations
This commit is contained in:
pavel06081991 2018-10-31 10:17:53 +03:00 committed by GitHub
parent 48aebf5a62
commit 5a019cc31c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 296 additions and 65 deletions

View file

@ -6,6 +6,7 @@
"kbnVislibVisTypes": "src/core_plugins/kbn_vislib_vis_types",
"markdownVis": "src/core_plugins/markdown_vis",
"metricVis": "src/core_plugins/metric_vis",
"vega": "src/core_plugins/vega",
"tableVis": "src/core_plugins/table_vis",
"regionMap": "src/core_plugins/region_map",
"statusPage": "src/core_plugins/status_page",

View file

@ -17,6 +17,7 @@
* under the License.
*/
import { i18n } from '@kbn/i18n';
import { bypassExternalUrlCheck } from '../vega_view/vega_base_view';
/**
@ -35,7 +36,14 @@ export class EmsFileParser {
*/
parseUrl(obj, url) {
if (typeof url.name !== 'string') {
throw new Error(`data.url with {"%type%": "emsfile"} is missing the "name" of the file`);
throw new Error(i18n.translate('vega.emsFileParser.missingNameOfFileErrorMessage', {
defaultMessage: '{dataUrlParam} with {dataUrlParamValue} requires {nameParam} parameter (name of the file)',
values: {
dataUrlParam: '"data.url"',
dataUrlParamValue: '{"%type%": "emsfile"}',
nameParam: '"name"',
},
}));
}
// Optimization: so initiate remote request as early as we know that we will need it
if (!this._fileLayersP) {
@ -57,7 +65,10 @@ export class EmsFileParser {
for (const { obj, name } of requests) {
const foundLayer = layers.find(v => v.name === name);
if (!foundLayer) {
throw new Error(`emsfile ${JSON.stringify(name)} does not exist`);
throw new Error(i18n.translate('vega.emsFileParser.emsFileNameDoesNotExistErrorMessage', {
defaultMessage: '{emsfile} {emsfileName} does not exist',
values: { emsfileName: JSON.stringify(name), emsfile: 'emsfile' },
}));
}
// This URL can bypass loader sanitization at the later stage

View file

@ -18,6 +18,7 @@
*/
import _ from 'lodash';
import { i18n } from '@kbn/i18n';
const TIMEFILTER = '%timefilter%';
const AUTOINTERVAL = '%autointerval%';
@ -56,7 +57,10 @@ export class EsQueryParser {
if (body === undefined) {
url.body = body = {};
} else if (!_.isPlainObject(body)) {
throw new Error('url.body must be an object');
throw new Error(i18n.translate('vega.esQueryParser.urlBodyValueTypeErrorMessage', {
defaultMessage: '{configName} must be an object',
values: { configName: 'url.body' },
}));
}
// Migrate legacy %context_query% into context & timefield values
@ -64,12 +68,30 @@ export class EsQueryParser {
delete url[LEGACY_CONTEXT];
if (legacyContext !== undefined) {
if (body.query !== undefined) {
throw new Error(`Data url must not have legacy "${LEGACY_CONTEXT}" and "body.query" values at the same time`);
throw new Error(i18n.translate('vega.esQueryParser.dataUrlMustNotHaveLegacyAndBodyQueryValuesAtTheSameTimeErrorMessage', {
defaultMessage: '{dataUrlParam} must not have legacy {legacyContext} and {bodyQueryConfigName} values at the same time',
values: {
legacyContext: `"${LEGACY_CONTEXT}"`,
bodyQueryConfigName: '"body.query"',
dataUrlParam: '"data.url"',
},
}));
} else if (usesContext) {
throw new Error(`Data url must not have "${LEGACY_CONTEXT}" together with "${CONTEXT}" or "${TIMEFIELD}"`);
throw new Error(i18n.translate('vega.esQueryParser.dataUrlMustNotHaveLegacyContextTogetherWithContextOrTimefieldErrorMessage', {
defaultMessage: '{dataUrlParam} must not have {legacyContext} together with {context} or {timefield}',
values: {
legacyContext: `"${LEGACY_CONTEXT}"`,
context: `"${CONTEXT}"`,
timefield: `"${TIMEFIELD}"`,
dataUrlParam: '"data.url"',
},
}));
} else if (legacyContext !== true && (typeof legacyContext !== 'string' || legacyContext.length === 0)) {
throw new Error(`Legacy "${LEGACY_CONTEXT}" can either be true (ignores time range picker), ` +
'or it can be the name of the time field, e.g. "@timestamp"');
throw new Error(i18n.translate('vega.esQueryParser.legacyContextCanBeTrueErrorMessage', {
// eslint-disable-next-line max-len
defaultMessage: 'Legacy {legacyContext} can either be {trueValue} (ignores time range picker), or it can be the name of the time field, e.g. {timestampParam}',
values: { legacyContext: `"${LEGACY_CONTEXT}"`, trueValue: 'true', timestampParam: '"@timestamp"' },
}));
}
usesContext = true;
@ -81,13 +103,26 @@ export class EsQueryParser {
}
result += '}';
this._onWarning(
`Legacy "url": {"${LEGACY_CONTEXT}": ${JSON.stringify(legacyContext)}} should change to ${result}`);
this._onWarning(i18n.translate('vega.esQueryParser.legacyUrlShouldChangeToWarningMessage', {
defaultMessage: 'Legacy {urlParam}: {legacyUrl} should change to {result}',
values: {
legacyUrl: `"${LEGACY_CONTEXT}": ${JSON.stringify(legacyContext)}`,
result,
urlParam: '"url"',
},
}));
}
if (body.query !== undefined) {
if (usesContext) {
throw new Error(`url.${CONTEXT} and url.${TIMEFIELD} must not be used when url.body.query is set`);
throw new Error(i18n.translate('vega.esQueryParser.urlContextAndUrlTimefieldMustNotBeUsedErrorMessage', {
defaultMessage: '{urlContext} and {timefield} must not be used when {queryParam} is set',
values: {
timefield: `url.${TIMEFIELD}`,
urlContext: `url.${CONTEXT}`,
queryParam: 'url.body.query',
},
}));
}
this._injectContextVars(body.query, true);
} else if (usesContext) {
@ -168,7 +203,13 @@ export class EsQueryParser {
if (size === true) {
size = 50; // by default, try to get ~80 values
} else if (typeof size !== 'number') {
throw new Error(`"${AUTOINTERVAL}" must be either true or a number`);
throw new Error(i18n.translate('vega.esQueryParser.autointervalValueTypeErrorMessage', {
defaultMessage: '{autointerval} must be either {trueValue} or a number',
values: {
autointerval: `"${AUTOINTERVAL}"`,
trueValue: 'true',
},
}));
}
const bounds = this._timeCache.getTimeBounds();
obj.interval = EsQueryParser._roundInterval((bounds.max - bounds.min) / size);
@ -190,7 +231,15 @@ export class EsQueryParser {
this._injectContextVars(subObj, isQuery);
continue;
default:
throw new Error(`"${TIMEFILTER}" property must be set to true, "min", or "max"`);
throw new Error(i18n.translate('vega.esQueryParser.timefilterValueErrorMessage', {
defaultMessage: '{timefilter} property must be set to {trueValue}, {minValue}, or {maxValue}',
values: {
timefilter: `"${TIMEFILTER}"`,
trueValue: 'true',
minValue: '"min"',
maxValue: '"max"',
},
}));
}
}
}
@ -227,7 +276,12 @@ export class EsQueryParser {
if (opts.shift) {
const shift = opts.shift;
if (typeof shift !== 'number') {
throw new Error('shift must be a numeric value');
throw new Error(i18n.translate('vega.esQueryParser.shiftMustValueTypeErrorMessage', {
defaultMessage: '{shiftParam} must be a numeric value',
values: {
shiftParam: '"shift"',
},
}));
}
let multiplier;
switch (opts.unit || 'd') {
@ -252,7 +306,13 @@ export class EsQueryParser {
multiplier = 1000;
break;
default:
throw new Error('Unknown unit value. Must be one of: [week, day, hour, minute, second]');
throw new Error(i18n.translate('vega.esQueryParser.unknownUnitValueErrorMessage', {
defaultMessage: 'Unknown {unitParamName} value. Must be one of: [{unitParamValues}]',
values: {
unitParamName: '"unit"',
unitParamValues: '"week", "day", "hour", "minute", "second"',
},
}));
}
result += shift * multiplier;
}

View file

@ -18,6 +18,7 @@
*/
import $ from 'jquery';
import { i18n } from '@kbn/i18n';
/**
* This class processes all Vega spec customizations,
@ -36,12 +37,25 @@ export class UrlParser {
parseUrl(obj, urlObj) {
let url = urlObj.url;
if (!url) {
throw new Error(`data.url requires a url parameter in a form 'https://example.org/path/subpath'`);
throw new Error(i18n.translate('vega.urlParser.dataUrlRequiresUrlParameterInFormErrorMessage', {
defaultMessage: '{dataUrlParam} requires a {urlParam} parameter in a form "{formLink}"',
values: {
dataUrlParam: '"data.url"',
urlParam: '"url"',
formLink: 'https://example.org/path/subpath',
},
}));
}
const query = urlObj.query;
if (!query) {
this._onWarning(`Using a "url": {"%type%": "url", "url": ...} should have a "query" sub-object`);
this._onWarning(i18n.translate('vega.urlParser.urlShouldHaveQuerySubObjectWarningMessage', {
defaultMessage: 'Using a {urlObject} should have a {subObjectName} sub-object',
values: {
urlObject: '"url": {"%type%": "url", "url": ...}',
subObjectName: '"query"',
},
}));
} else {
url += (url.includes('?') ? '&' : '?') + $.param(query);
}

View file

@ -28,6 +28,7 @@ import { Utils } from './utils';
import { EmsFileParser } from './ems_file_parser';
import { UrlParser } from './url_parser';
import { VISUALIZATION_COLORS } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
// Set default single color to match other Kibana visualizations
const defaultColor = VISUALIZATION_COLORS[0];
@ -77,7 +78,9 @@ export class VegaParser {
this.spec = hjson.parse(this.spec, { legacyRoot: false });
}
if (!_.isPlainObject(this.spec)) {
throw new Error('Invalid Vega spec');
throw new Error(i18n.translate('vega.vegaParser.invalidVegaSpecErrorMessage', {
defaultMessage: 'Invalid Vega specification',
}));
}
this.isVegaLite = this._parseSchema();
this.useHover = !this.isVegaLite;
@ -128,7 +131,9 @@ export class VegaParser {
this.spec.projections.length !== 1 ||
this.spec.projections[0].name !== 'projection'
) {
throw new Error('Internal error: VL compiler should have generated a single projection object');
throw new Error(i18n.translate('vega.vegaParser.VLCompilerShouldHaveGeneratedSingleProtectionObjectErrorMessage', {
defaultMessage: 'Internal error: Vega-Lite compiler should have generated a single projection object',
}));
}
delete this.spec.projections;
}
@ -180,7 +185,14 @@ export class VegaParser {
delete this.spec.width;
delete this.spec.height;
} else {
this._onWarning(`The 'width' and 'height' params are ignored with autosize=fit`);
this._onWarning(i18n.translate('vega.vegaParser.widthAndHeightParamsAreIngroredWithAutosizeFitWarningMessage', {
defaultMessage: 'The {widthParam} and {heightParam} params are ignored with {autosizeParam}',
values: {
autosizeParam: 'autosize=fit',
widthParam: '"width"',
heightParam: '"height"',
},
}));
}
}
}
@ -195,13 +207,18 @@ export class VegaParser {
if (this._config.controlsLocation === undefined) {
this.containerDir = 'column';
} else {
throw new Error('Unrecognized controlsLocation value. Expecting one of ["' +
locToDirMap.keys().join('", "') + '"]');
throw new Error(i18n.translate('vega.vegaParser.unrecognizedControlsLocationValueErrorMessage', {
defaultMessage: 'Unrecognized {controlsLocationParam} value. Expecting one of [{locToDirMap}]',
values: { locToDirMap: `"${locToDirMap.keys().join('", "')}"`, controlsLocationParam: 'controlsLocation' }
}));
}
}
const dir = this._config.controlsDirection;
if (dir !== undefined && dir !== 'horizontal' && dir !== 'vertical') {
throw new Error('Unrecognized dir value. Expecting one of ["horizontal", "vertical"]');
throw new Error(i18n.translate('vega.vegaParser.unrecognizedDirValueErrorMessage', {
defaultMessage: 'Unrecognized {dirParam} value. Expecting one of [{expectedValues}]',
values: { expectedValues: '"horizontal", "vertical"', dirParam: 'dir' },
}));
}
this.controlsDir = dir === 'horizontal' ? 'row' : 'column';
}
@ -217,15 +234,27 @@ export class VegaParser {
result = this.spec._hostConfig;
delete this.spec._hostConfig;
if (!_.isPlainObject(result)) {
throw new Error('If present, _hostConfig must be an object');
throw new Error(i18n.translate('vega.vegaParser.hostConfigValueTypeErrorMessage', {
defaultMessage: 'If present, {configName} must be an object',
values: { configName: '"_hostConfig"' },
}));
}
this._onWarning('_hostConfig has been deprecated. Use config.kibana instead.');
this._onWarning(i18n.translate('vega.vegaParser.hostConfigIsDeprecatedWarningMessage', {
defaultMessage: '{deprecatedConfigName} has been deprecated. Use {newConfigName} instead.',
values: {
deprecatedConfigName: '"_hostConfig"',
newConfigName: 'config.kibana',
},
}));
}
if (_.isPlainObject(this.spec.config) && this.spec.config.kibana !== undefined) {
result = this.spec.config.kibana;
delete this.spec.config.kibana;
if (!_.isPlainObject(result)) {
throw new Error('If present, config.kibana must be an object');
throw new Error(i18n.translate('vega.vegaParser.kibanaConfigValueTypeErrorMessage', {
defaultMessage: 'If present, {configName} must be an object',
values: { configName: 'config.kibana' },
}));
}
}
return result || {};
@ -241,13 +270,19 @@ export class VegaParser {
if (result.position === undefined) {
result.position = 'top';
} else if (['top', 'right', 'bottom', 'left'].indexOf(result.position) === -1) {
throw new Error('Unexpected value for the result.position configuration');
throw new Error(i18n.translate('vega.vegaParser.unexpectedValueForPositionConfigurationErrorMessage', {
defaultMessage: 'Unexpected value for the {configurationName} configuration',
values: { configurationName: 'result.position' },
}));
}
if (result.padding === undefined) {
result.padding = 16;
} else if (typeof result.padding !== 'number') {
throw new Error('config.kibana.result.padding is expected to be a number');
throw new Error(i18n.translate('vega.vegaParser.paddingConfigValueTypeErrorMessage', {
defaultMessage: '{configName} is expected to be a number',
values: { configName: 'config.kibana.result.padding' },
}));
}
if (result.centerOnMark === undefined) {
@ -256,7 +291,10 @@ export class VegaParser {
} else if (typeof result.centerOnMark === 'boolean') {
result.centerOnMark = result.centerOnMark ? Number.MAX_VALUE : -1;
} else if (typeof result.centerOnMark !== 'number') {
throw new Error('config.kibana.result.centerOnMark is expected to be true, false, or a number');
throw new Error(i18n.translate('vega.vegaParser.centerOnMarkConfigValueTypeErrorMessage', {
defaultMessage: '{configName} is expected to be {trueValue}, {falseValue}, or a number',
values: { configName: 'config.kibana.result.centerOnMark', trueValue: 'true', falseValue: 'false' },
}));
}
return result;
@ -280,7 +318,10 @@ export class VegaParser {
res[name] = parsed;
return;
}
this._onWarning(`config.kibana.${name} is not valid`);
this._onWarning(i18n.translate('vega.vegaParser.someKibanaConfigurationIsNoValidWarningMessage', {
defaultMessage: '{configName} is not valid',
values: { configName: `config.kibana.${name}` },
}));
}
if (!isZoom) res[name] = 0;
};
@ -294,7 +335,14 @@ export class VegaParser {
// `false` is a valid value
res.mapStyle = this._config.mapStyle === undefined ? `default` : this._config.mapStyle;
if (res.mapStyle !== `default` && res.mapStyle !== false) {
this._onWarning(`config.kibana.mapStyle may either be false or "default"`);
this._onWarning(i18n.translate('vega.vegaParser.mapStyleValueTypeWarningMessage', {
defaultMessage: '{mapStyleConfigName} may either be {mapStyleConfigFirstAllowedValue} or {mapStyleConfigSecondAllowedValue}',
values: {
mapStyleConfigName: 'config.kibana.mapStyle',
mapStyleConfigFirstAllowedValue: 'false',
mapStyleConfigSecondAllowedValue: '"default"',
},
}));
res.mapStyle = `default`;
}
@ -306,7 +354,12 @@ export class VegaParser {
if (!Array.isArray(maxBounds) || maxBounds.length !== 4 ||
!maxBounds.every(v => typeof v === 'number' && Number.isFinite(v))
) {
this._onWarning(`config.kibana.maxBounds must be an array with four numbers`);
this._onWarning(i18n.translate('vega.vegaParser.maxBoundsValueTypeWarningMessage', {
defaultMessage: '{maxBoundsConfigName} must be an array with four numbers',
values: {
maxBoundsConfigName: 'config.kibana.maxBounds',
},
}));
} else {
res.maxBounds = maxBounds;
}
@ -320,7 +373,12 @@ export class VegaParser {
if (val === undefined) {
dstObj[paramName] = dflt;
} else if (typeof val !== 'boolean') {
this._onWarning(`config.kibana.${paramName} must be a boolean value`);
this._onWarning(i18n.translate('vega.vegaParser.someKibanaParamValueTypeWarningMessage', {
defaultMessage: '{configName} must be a boolean value',
values: {
configName: `config.kibana.${paramName}`
},
}));
dstObj[paramName] = dflt;
} else {
dstObj[paramName] = val;
@ -334,7 +392,10 @@ export class VegaParser {
*/
_parseSchema() {
if (!this.spec.$schema) {
this._onWarning(`The input spec does not specify a "$schema", defaulting to "${DEFAULT_SCHEMA}"`);
this._onWarning(i18n.translate('vega.vegaParser.inputSpecDoesNotSpecifySchemaWarningMessage', {
defaultMessage: 'The input spec does not specify a {schemaParam}, defaulting to {defaultSchema}',
values: { defaultSchema: `"${DEFAULT_SCHEMA}"`, schemaParam: '"$schema"' },
}));
this.spec.$schema = DEFAULT_SCHEMA;
}
@ -343,10 +404,14 @@ export class VegaParser {
const libVersion = isVegaLite ? vegaLite.version : vega.version;
if (versionCompare(schema.version, libVersion) > 0) {
this._onWarning(
`The input spec uses ${schema.library} ${schema.version}, but ` +
`current version of ${schema.library} is ${libVersion}.`
);
this._onWarning(i18n.translate('vega.vegaParser.notValidLibraryVersionForInputSpecWarningMessage', {
defaultMessage: 'The input spec uses {schemaLibrary} {schemaVersion}, but current version of {schemaLibrary} is {libraryVersion}.',
values: {
schemaLibrary: schema.library,
schemaVersion: schema.version,
libraryVersion: libVersion,
},
}));
}
return isVegaLite;
@ -371,7 +436,12 @@ export class VegaParser {
const parser = this._urlParsers[type];
if (parser === undefined) {
throw new Error(`url: {"%type%": "${type}"} is not supported`);
throw new Error(i18n.translate('vega.vegaParser.notSupportedUrlTypeErrorMessage', {
defaultMessage: '{urlObject} is not supported',
values: {
urlObject: 'url: {"%type%": "${type}"}',
},
}));
}
let pendingArr = pending[type];
@ -405,7 +475,14 @@ export class VegaParser {
if (key === 'data' && _.isPlainObject(obj.url)) {
// Assume that any "data": {"url": {...}} is a request for data
if (obj.values !== undefined || obj.source !== undefined) {
throw new Error('Data must not have more than one of "url", "values", and "source"');
throw new Error(i18n.translate('vega.vegaParser.dataExceedsSomeParamsUseTimesLimitErrorMessage', {
defaultMessage: 'Data must not have more than one of {urlParam}, {valuesParam}, and {sourceParam}',
values: {
urlParam: '"url"',
valuesParam: '"values"',
sourceParam: '"source"',
},
}));
}
onFind(obj);
} else {

View file

@ -24,7 +24,7 @@
id="vegaHelp"
class="editor_action"
dropdown-toggle
aria-label="Vega help"
aria-label="{{::'vega.editor.vegaHelpButtonAriaLabel' | i18n: {defaultMessage: 'Vega help'} }}"
>
<span class="kuiIcon fa-question-circle"></span>
</button>
@ -34,19 +34,31 @@
aria-labelledby="vegaHelp"
>
<li role="menuitem">
<a target="_blank" rel="noopener noreferrer" href="https://www.elastic.co/guide/en/kibana/master/vega-graph.html">
Kibana Vega Help
</a>
<a
target="_blank"
rel="noopener noreferrer"
href="https://www.elastic.co/guide/en/kibana/master/vega-graph.html"
i18n-id="vega.editor.vegaHelpLinkText"
i18n-default-message="Kibana Vega Help"
></a>
</li>
<li role="menuitem">
<a target="_blank" rel="noopener noreferrer" href="https://vega.github.io/vega-lite/docs/">
Vega-Lite Documentation
</a>
<a
target="_blank"
rel="noopener noreferrer"
href="https://vega.github.io/vega-lite/docs/"
i18n-id="vega.editor.vegaLiteDocumentationLinkText"
i18n-default-message="Vega-Lite Documentation"
></a>
</li>
<li role="menuitem">
<a target="_blank" rel="noopener noreferrer" href="https://vega.github.io/vega/docs/">
Vega Documentation
</a>
<a
target="_blank"
rel="noopener noreferrer"
href="https://vega.github.io/vega/docs/"
i18n-id="vega.editor.vegaDocumentationLinkText"
i18n-default-message="Vega Documentation"
></a>
</li>
</ul>
</span>
@ -55,7 +67,7 @@
id="vegaOptions"
class="editor_action"
dropdown-toggle
aria-label="Vega editor options"
aria-label="{{::'vega.editor.vegaEditorOptionsButtonAriaLabel' | i18n: {defaultMessage: 'Vega editor options'} }}"
>
<span class="kuiIcon fa-wrench"></span>
</button>
@ -65,10 +77,18 @@
aria-labelledby="vegaOptions"
>
<li role="menuitem">
<button ng-click="formatHJson($event)">Reformat as HJSON</button>
<button
ng-click="formatHJson($event)"
i18n-id="vega.editor.reformatAsHJSONButtonLabel"
i18n-default-message="Reformat as HJSON"
></button>
</li>
<li role="menuitem">
<button ng-click="formatJson($event)">Reformat as JSON, delete comments</button>
<button
ng-click="formatJson($event)"
i18n-id="vega.editor.reformatAsJSONButtonLabel"
i18n-default-message="Reformat as JSON, delete comments"
></button>
</li>
</ul>
</span>

View file

@ -17,6 +17,7 @@
* under the License.
*/
import { i18n } from '@kbn/i18n';
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
import { VisFactoryProvider } from 'ui/vis/vis_factory';
import { CATEGORY } from 'ui/vis/vis_category';
@ -41,8 +42,12 @@ VisTypesRegistryProvider.register((Private) => {
return VisFactory.createBaseVisualization({
name: 'vega',
title: 'Vega',
description: 'Create custom visualizations using Vega and VegaLite',
title: i18n.translate('vega.type.vegaTitle', {
defaultMessage: 'Vega',
}),
description: i18n.translate('vega.type.vegaВescription', {
defaultMessage: 'Create custom visualizations using Vega and Vega-Lite',
}),
icon: 'visVega',
category: CATEGORY.OTHER,
visConfig: { defaults: { spec: defaultSpec } },

View file

@ -24,6 +24,7 @@ import * as vega from 'vega-lib';
import * as vegaLite from 'vega-lite';
import { Utils } from '../data_model/utils';
import { VISUALIZATION_COLORS } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { TooltipHandler } from './vega_tooltip';
import { buildQueryFilter } from 'ui/filter_manager/lib';
@ -145,7 +146,13 @@ export class VegaBaseView {
// because user can only supply pure JSON data structure.
uri = uri.url;
} else if (!this._vegaConfig.enableExternalUrls) {
throw new Error('External URLs are not enabled. Add vega.enableExternalUrls: true to kibana.yml');
throw new Error(i18n.translate('vega.vegaParser.baseView.externalUrlsAreNotEnabledErrorMessage', {
defaultMessage: 'External URLs are not enabled. Add {enableExternalUrls} to {kibanaConfigFileName}',
values: {
enableExternalUrls: 'vega.enableExternalUrls: true',
kibanaConfigFileName: 'kibana.yml',
},
}));
}
return originalSanitize(uri, options);
};
@ -233,7 +240,10 @@ export class VegaBaseView {
const handlerFunc = vegaFunctions[funcName];
if (!handlerFunc || !this[handlerFunc]) {
// in case functions don't match the list above
throw new Error(`${funcName}() is not defined for this graph`);
throw new Error(i18n.translate('vega.vegaParser.baseView.functionIsNotDefinedForGraphErrorMessage', {
defaultMessage: '{funcName} is not defined for this graph',
values: { funcName: `${funcName}()` },
}));
}
await this[handlerFunc](...args);
} catch (err) {
@ -308,8 +318,13 @@ export class VegaBaseView {
const startDate = dateMath.parse(start);
const endDate = dateMath.parse(end);
if (!startDate || !endDate || !startDate.isValid() || !endDate.isValid()) {
throw new Error(`Error setting time filter: both time values must be either relative or absolute dates. ` +
`start=${JSON.stringify(start)}, end=${JSON.stringify(end)}`);
throw new Error(i18n.translate('vega.vegaParser.baseView.timeValuesTypeErrorMessage', {
defaultMessage: 'Error setting time filter: both time values must be either relative or absolute dates. {start}, {end}',
values: {
start: `start=${JSON.stringify(start)}`,
end: `end=${JSON.stringify(end)}`,
},
}));
}
reverse = startDate.isAfter(endDate);
if (isValidAbsStart || isValidAbsEnd) {

View file

@ -21,6 +21,7 @@ import { KibanaMap } from 'ui/vis/map/kibana_map';
import * as vega from 'vega-lib';
import { VegaBaseView } from './vega_base_view';
import { VegaMapLayer } from './vega_map_layer';
import { i18n } from '@kbn/i18n';
export class VegaMapView extends VegaBaseView {
@ -37,7 +38,10 @@ export class VegaMapView extends VegaBaseView {
const mapStyle = mapConfig.mapStyle === 'default' ? 'road_map' : mapConfig.mapStyle;
baseMapOpts = tmsServices.find((s) => s.id === mapStyle);
if (!baseMapOpts) {
this.onWarn(`mapStyle ${JSON.stringify(mapStyle)} was not found`);
this.onWarn(i18n.translate('vega.mapView.mapStyleNotFoundWarningMessage', {
defaultMessage: '{mapStyleParam} was not found',
values: { mapStyleParam: `"mapStyle": ${JSON.stringify(mapStyle)}` },
}));
} else {
limitMinZ = baseMapOpts.minZoom;
limitMaxZ = baseMapOpts.maxZoom;
@ -48,10 +52,16 @@ export class VegaMapView extends VegaBaseView {
if (value === undefined) {
value = dflt;
} else if (value < min) {
this.onWarn(`Resetting ${name} to ${min}`);
this.onWarn(i18n.translate('vega.mapView.resettingPropertyToMinValueWarningMessage', {
defaultMessage: 'Resetting {name} to {min}',
values: { name: `"${name}"`, min },
}));
value = min;
} else if (value > max) {
this.onWarn(`Resetting ${name} to ${max}`);
this.onWarn(i18n.translate('vega.mapView.resettingPropertyToMaxValueWarningMessage', {
defaultMessage: 'Resetting {name} to {max}',
values: { name: `"${name}"`, max },
}));
value = max;
}
return value;
@ -60,7 +70,13 @@ export class VegaMapView extends VegaBaseView {
let minZoom = validate('minZoom', mapConfig.minZoom, limitMinZ, limitMinZ, limitMaxZ);
let maxZoom = validate('maxZoom', mapConfig.maxZoom, limitMaxZ, limitMinZ, limitMaxZ);
if (minZoom > maxZoom) {
this.onWarn('minZoom and maxZoom have been swapped');
this.onWarn(i18n.translate('vega.mapView.minZoomAndMaxZoomHaveBeenSwappedWarningMessage', {
defaultMessage: '{minZoomPropertyName} and {maxZoomPropertyName} have been swapped',
values: {
minZoomPropertyName: '"minZoom"',
maxZoomPropertyName: '"maxZoom"',
},
}));
[minZoom, maxZoom] = [maxZoom, minZoom];
}
const zoom = validate('zoom', mapConfig.zoom, 2, minZoom, maxZoom);

View file

@ -17,6 +17,7 @@
* under the License.
*/
import { i18n } from '@kbn/i18n';
import { toastNotifications, Notifier } from 'ui/notify';
import { VegaView } from './vega_view/vega_view';
import { VegaMapView } from './vega_view/vega_map_view';
@ -43,10 +44,19 @@ export function VegaVisualizationProvider(Private, vegaConfig, serviceSettings,
let idxObj;
if (index) {
idxObj = await findObjectByTitle(savedObjectsClient, 'index-pattern', index);
if (!idxObj) throw new Error(`Index "${index}" not found`);
if (!idxObj) {
throw new Error(i18n.translate('vega.visualization.indexNotFoundErrorMessage', {
defaultMessage: 'Index {index} not found',
values: { index: `"${index}"` },
}));
}
} else {
idxObj = await this._vis.API.indexPatterns.getDefault();
if (!idxObj) throw new Error('Unable to find default index');
if (!idxObj) {
throw new Error(i18n.translate('vega.visualization.unableToFindDefaultIndexErrorMessage', {
defaultMessage: 'Unable to find default index',
}));
}
}
return idxObj.id;
}
@ -59,7 +69,9 @@ export function VegaVisualizationProvider(Private, vegaConfig, serviceSettings,
*/
async render(visData, status) {
if (!visData && !this._vegaView) {
toastNotifications.addWarning('Unable to render without data');
toastNotifications.addWarning(i18n.translate('vega.visualization.unableToRenderWithoutDataWarningMessage', {
defaultMessage: 'Unable to render without data',
}));
return;
}