diff --git a/.i18nrc.json b/.i18nrc.json index b5fa1353f39db..fc748eaab5e6d 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -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", diff --git a/src/core_plugins/vega/public/data_model/ems_file_parser.js b/src/core_plugins/vega/public/data_model/ems_file_parser.js index bc6609dba33e9..da051cc1bdf95 100644 --- a/src/core_plugins/vega/public/data_model/ems_file_parser.js +++ b/src/core_plugins/vega/public/data_model/ems_file_parser.js @@ -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 diff --git a/src/core_plugins/vega/public/data_model/es_query_parser.js b/src/core_plugins/vega/public/data_model/es_query_parser.js index 4690af34f228f..5d94afd688b24 100644 --- a/src/core_plugins/vega/public/data_model/es_query_parser.js +++ b/src/core_plugins/vega/public/data_model/es_query_parser.js @@ -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; } diff --git a/src/core_plugins/vega/public/data_model/url_parser.js b/src/core_plugins/vega/public/data_model/url_parser.js index 71f0c3f84a38a..837a443404d1e 100644 --- a/src/core_plugins/vega/public/data_model/url_parser.js +++ b/src/core_plugins/vega/public/data_model/url_parser.js @@ -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); } diff --git a/src/core_plugins/vega/public/data_model/vega_parser.js b/src/core_plugins/vega/public/data_model/vega_parser.js index 8f5784891e67a..e7e78d1f6f385 100644 --- a/src/core_plugins/vega/public/data_model/vega_parser.js +++ b/src/core_plugins/vega/public/data_model/vega_parser.js @@ -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 { diff --git a/src/core_plugins/vega/public/vega_editor_template.html b/src/core_plugins/vega/public/vega_editor_template.html index 60cc33fb159b8..8d13a7bdfa953 100644 --- a/src/core_plugins/vega/public/vega_editor_template.html +++ b/src/core_plugins/vega/public/vega_editor_template.html @@ -24,7 +24,7 @@ id="vegaHelp" class="editor_action" dropdown-toggle - aria-label="Vega help" + aria-label="{{::'vega.editor.vegaHelpButtonAriaLabel' | i18n: {defaultMessage: 'Vega help'} }}" > @@ -34,19 +34,31 @@ aria-labelledby="vegaHelp" >
  • - - Kibana Vega Help - +
  • - - Vega-Lite Documentation - +
  • - - Vega Documentation - +
  • @@ -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'} }}" > @@ -65,10 +77,18 @@ aria-labelledby="vegaOptions" >
  • - +
  • - +
  • diff --git a/src/core_plugins/vega/public/vega_type.js b/src/core_plugins/vega/public/vega_type.js index bceb0de976775..e96fba000b4c0 100644 --- a/src/core_plugins/vega/public/vega_type.js +++ b/src/core_plugins/vega/public/vega_type.js @@ -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 } }, diff --git a/src/core_plugins/vega/public/vega_view/vega_base_view.js b/src/core_plugins/vega/public/vega_view/vega_base_view.js index 7d7bdb2e6f25c..d37304b28837a 100644 --- a/src/core_plugins/vega/public/vega_view/vega_base_view.js +++ b/src/core_plugins/vega/public/vega_view/vega_base_view.js @@ -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) { diff --git a/src/core_plugins/vega/public/vega_view/vega_map_view.js b/src/core_plugins/vega/public/vega_view/vega_map_view.js index 1eb7d2c3ced54..48f90fa510c5c 100644 --- a/src/core_plugins/vega/public/vega_view/vega_map_view.js +++ b/src/core_plugins/vega/public/vega_view/vega_map_view.js @@ -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); diff --git a/src/core_plugins/vega/public/vega_visualization.js b/src/core_plugins/vega/public/vega_visualization.js index c51ebcbb2042e..7108e60fdc999 100644 --- a/src/core_plugins/vega/public/vega_visualization.js +++ b/src/core_plugins/vega/public/vega_visualization.js @@ -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; }