Internationalisation: Mark up geomap panel edit options (#107140)

mark up geomap panel edit options
This commit is contained in:
Ashley Harrison
2025-07-07 11:30:11 +01:00
committed by GitHub
parent 9b7e2aa5f3
commit 6ce2fac2bb
10 changed files with 235 additions and 91 deletions

View File

@ -11,16 +11,19 @@ import { NumberInput } from 'app/core/components/OptionsUI/NumberInput';
import { validateScaleOptions, validateScaleConfig } from '../scale';
import { ScaleDimensionOptions } from '../types';
const fixedValueOption: SelectableValue<string> = {
label: 'Fixed value',
value: '_____fixed_____',
};
export const ScaleDimensionEditor = (props: StandardEditorProps<ScaleDimensionConfig, ScaleDimensionOptions>) => {
const { value, context, onChange, item } = props;
const { settings } = item;
const styles = useStyles2(getStyles);
const fixedValueOption: SelectableValue<string> = useMemo(
() => ({
label: t('dimensions.scale-dimension-editor.fixed-value-option.label.fixed-value', 'Fixed value'),
value: '_____fixed_____',
}),
[]
);
const fieldName = value?.field;
const isFixed = Boolean(!fieldName);
const names = useFieldDisplayNames(context.data);
@ -53,7 +56,7 @@ export const ScaleDimensionEditor = (props: StandardEditorProps<ScaleDimensionCo
});
}
},
[validateAndDoChange, value]
[validateAndDoChange, value, fixedValueOption.value]
);
const onMinChange = useCallback(

View File

@ -1,4 +1,5 @@
import { Field, FieldType, PanelOptionsEditorBuilder, DataFrame } from '@grafana/data';
import { t } from '@grafana/i18n';
import { FrameGeometrySource, FrameGeometrySourceMode } from '@grafana/schema';
import { GazetteerPathEditor } from 'app/features/geo/editor/GazetteerPathEditor';
@ -14,7 +15,7 @@ export function addLocationFields<TOptions>(
builder.addCustomEditor({
id: 'modeEditor',
path: `${prefix}mode`,
name: 'Location Mode',
name: t('geo.location-editor.name-location-mode', 'Location Mode'),
editor: LocationModeEditor,
settings: { data, source },
});
@ -25,18 +26,18 @@ export function addLocationFields<TOptions>(
builder
.addFieldNamePicker({
path: `${prefix}latitude`,
name: 'Latitude field',
name: t('geo.location-editor.name-latitude-field', 'Latitude field'),
settings: {
filter: (f: Field) => f.type === FieldType.number,
noFieldsMessage: 'No numeric fields found',
noFieldsMessage: t('geo.location-editor.latitude-field.no-fields-message', 'No numeric fields found'),
},
})
.addFieldNamePicker({
path: `${prefix}longitude`,
name: 'Longitude field',
name: t('geo.location-editor.name-longitude-field', 'Longitude field'),
settings: {
filter: (f: Field) => f.type === FieldType.number,
noFieldsMessage: 'No numeric fields found',
noFieldsMessage: t('geo.location-editor.longitude-field.no-fields-message', 'No numeric fields found'),
},
});
break;
@ -44,10 +45,10 @@ export function addLocationFields<TOptions>(
case FrameGeometrySourceMode.Geohash:
builder.addFieldNamePicker({
path: `${prefix}geohash`,
name: 'Geohash field',
name: t('geo.location-editor.name-geohash-field', 'Geohash field'),
settings: {
filter: (f: Field) => f.type === FieldType.string,
noFieldsMessage: 'No strings fields found',
noFieldsMessage: t('geo.location-editor.geohash-field.no-fields-message', 'No strings fields found'),
},
});
break;
@ -56,16 +57,16 @@ export function addLocationFields<TOptions>(
builder
.addFieldNamePicker({
path: `${prefix}lookup`,
name: 'Lookup field',
name: t('geo.location-editor.name-lookup-field', 'Lookup field'),
settings: {
filter: (f: Field) => f.type === FieldType.string,
noFieldsMessage: 'No strings fields found',
noFieldsMessage: t('geo.location-editor.lookup-field.no-fields-message', 'No strings fields found'),
},
})
.addCustomEditor({
id: 'gazetteer',
path: `${prefix}gazetteer`,
name: 'Gazetteer',
name: t('geo.location-editor.name-gazetteer', 'Gazetteer'),
editor: GazetteerPathEditor,
});
}

View File

@ -3,38 +3,12 @@ import { useEffect, useState } from 'react';
import { StandardEditorProps, DataFrame, GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { t } from '@grafana/i18n';
import { FrameGeometrySource, FrameGeometrySourceMode } from '@grafana/schema';
import { Alert, HorizontalGroup, Icon, Select, useStyles2 } from '@grafana/ui';
import { FrameGeometryField, getGeometryField, getLocationMatchers } from '../utils/location';
const MODE_OPTIONS = [
{
value: FrameGeometrySourceMode.Auto,
label: 'Auto',
ariaLabel: selectors.components.Transforms.SpatialOperations.location.autoOption,
description: 'Automatically identify location data based on default field names',
},
{
value: FrameGeometrySourceMode.Coords,
label: 'Coords',
ariaLabel: selectors.components.Transforms.SpatialOperations.location.coords.option,
description: 'Specify latitude and longitude fields',
},
{
value: FrameGeometrySourceMode.Geohash,
label: 'Geohash',
ariaLabel: selectors.components.Transforms.SpatialOperations.location.geohash.option,
description: 'Specify geohash field',
},
{
value: FrameGeometrySourceMode.Lookup,
label: 'Lookup',
ariaLabel: selectors.components.Transforms.SpatialOperations.location.lookup.option,
description: 'Specify Gazetteer and lookup field',
},
];
interface ModeEditorSettings {
data?: DataFrame[];
source?: FrameGeometrySource;
@ -50,6 +24,39 @@ export const LocationModeEditor = ({
}: StandardEditorProps<string, ModeEditorSettings, unknown, unknown>) => {
const [info, setInfo] = useState<FrameGeometryField>();
const MODE_OPTIONS = [
{
value: FrameGeometrySourceMode.Auto,
label: t('geo.location-more-editor.mode-options.label-auto', 'Auto'),
ariaLabel: selectors.components.Transforms.SpatialOperations.location.autoOption,
description: t(
'geo.location-more-editor.mode-options.description-auto',
'Automatically identify location data based on default field names'
),
},
{
value: FrameGeometrySourceMode.Coords,
label: t('geo.location-more-editor.mode-options.label-coords', 'Coords'),
ariaLabel: selectors.components.Transforms.SpatialOperations.location.coords.option,
description: t(
'geo.location-more-editor.mode-options.description-coords',
'Specify latitude and longitude fields'
),
},
{
value: FrameGeometrySourceMode.Geohash,
label: t('geo.location-more-editor.mode-options.label-geohash', 'Geohash'),
ariaLabel: selectors.components.Transforms.SpatialOperations.location.geohash.option,
description: t('geo.location-more-editor.mode-options.description-geohash', 'Specify geohash field'),
},
{
value: FrameGeometrySourceMode.Lookup,
label: t('geo.location-more-editor.mode-options.label-lookup', 'Lookup'),
ariaLabel: selectors.components.Transforms.SpatialOperations.location.lookup.option,
description: t('geo.location-more-editor.mode-options.description-lookup', 'Specify Gazetteer and lookup field'),
},
];
useEffect(() => {
if (item.settings?.source && item.settings?.data?.length && item.settings.data[0]) {
getLocationMatchers(item.settings.source).then((location) => {

View File

@ -9,6 +9,7 @@ import {
getFieldDisplayName,
FieldType,
} from '@grafana/data';
import { t } from '@grafana/i18n';
import { FrameGeometrySource, FrameGeometrySourceMode } from '@grafana/schema';
import { getGeoFieldFromGazetteer, pointFieldFromGeohash, pointFieldFromLonLat } from '../format/utils';
@ -178,7 +179,7 @@ export function getGeometryField(frame: DataFrame, location: LocationFieldMatche
};
}
return {
warning: 'Unable to find location fields',
warning: t('geo.get-geometry-field.warning-unable-to-find', 'Unable to find location fields'),
};
case FrameGeometrySourceMode.Coords:
@ -190,7 +191,7 @@ export function getGeometryField(frame: DataFrame, location: LocationFieldMatche
};
}
return {
warning: 'Select latitude/longitude fields',
warning: t('geo.get-geometry-field.warning-select-lat-long', 'Select latitude/longitude fields'),
};
case FrameGeometrySourceMode.Geohash:
@ -202,7 +203,7 @@ export function getGeometryField(frame: DataFrame, location: LocationFieldMatche
};
}
return {
warning: 'Select geohash field',
warning: t('geo.get-geometry-field.warning-select-geohash', 'Select geohash field'),
};
case FrameGeometrySourceMode.Lookup:
@ -215,13 +216,13 @@ export function getGeometryField(frame: DataFrame, location: LocationFieldMatche
};
}
return {
warning: 'Gazetteer not found',
warning: t('geo.get-geometry-field.warning-gazetteer-not-found', 'Gazetteer not found'),
};
}
return {
warning: 'Select lookup field',
warning: t('geo.get-geometry-field.warning-select-lookup', 'Select lookup field'),
};
}
return { warning: 'unable to find geometry' };
return { warning: t('geo.get-geometry-field.warning-no-geometry', 'unable to find geometry') };
}

View File

@ -242,9 +242,15 @@ export const StyleEditor = (props: Props) => {
value={value?.symbolAlign?.vertical ?? defaultStyleConfig.symbolAlign.vertical}
onChange={onAlignVerticalChange}
options={[
{ value: VerticalAlign.Top, label: capitalize(VerticalAlign.Top) },
{ value: VerticalAlign.Center, label: capitalize(VerticalAlign.Center) },
{ value: VerticalAlign.Bottom, label: capitalize(VerticalAlign.Bottom) },
{ value: VerticalAlign.Top, label: t('geomap.style-editor.vertical-align-options.label-top', 'Top') },
{
value: VerticalAlign.Center,
label: t('geomap.style-editor.vertical-align-options.label-center', 'Center'),
},
{
value: VerticalAlign.Bottom,
label: t('geomap.style-editor.vertical-align-options.label-bottom', 'Bottom'),
},
]}
/>
</Field>
@ -253,9 +259,18 @@ export const StyleEditor = (props: Props) => {
value={value?.symbolAlign?.horizontal ?? defaultStyleConfig.symbolAlign.horizontal}
onChange={onAlignHorizontalChange}
options={[
{ value: HorizontalAlign.Left, label: capitalize(HorizontalAlign.Left) },
{ value: HorizontalAlign.Center, label: capitalize(HorizontalAlign.Center) },
{ value: HorizontalAlign.Right, label: capitalize(HorizontalAlign.Right) },
{
value: HorizontalAlign.Left,
label: t('geomap.style-editor.horizontal-align-options.label-left', 'Left'),
},
{
value: HorizontalAlign.Center,
label: t('geomap.style-editor.horizontal-align-options.label-center', 'Center'),
},
{
value: HorizontalAlign.Right,
label: t('geomap.style-editor.horizontal-align-options.label-right', 'Right'),
},
]}
/>
</Field>

View File

@ -2,6 +2,7 @@ import { get as lodashGet, isEqual } from 'lodash';
import { FrameGeometrySourceMode, getFrameMatchers, MapLayerOptions } from '@grafana/data';
import { NestedPanelOptions, NestedValueAccess } from '@grafana/data/internal';
import { t } from '@grafana/i18n';
import { setOptionImmutably } from 'app/features/dashboard/components/PanelEditor/utils';
import { addLocationFields } from 'app/features/geo/editor/locationEditor';
@ -69,7 +70,7 @@ export function getLayerEditor(opts: LayerEditorOptions): NestedPanelOptions<Map
builder.addSelect({
path: 'type',
name: 'Layer type', // required, but hide space
name: t('geomap.layer-editor.name-layer-type', 'Layer type'), // required, but hide space
settings: {
options: layerTypes.options,
},
@ -80,7 +81,7 @@ export function getLayerEditor(opts: LayerEditorOptions): NestedPanelOptions<Map
builder.addCustomEditor({
id: 'filterData',
path: 'filterData',
name: 'Data',
name: t('geomap.layer-editor.name-data', 'Data'),
editor: FrameSelectionEditor,
defaultValue: undefined,
});
@ -108,11 +109,11 @@ export function getLayerEditor(opts: LayerEditorOptions): NestedPanelOptions<Map
if (handler.registerOptionsUI) {
handler.registerOptionsUI(builder, context);
}
if (!isEqual(opts.category, ['Base layer'])) {
if (!isEqual(opts.category, [t('geomap.layer-editor.category-base-layer', 'Base layer')])) {
if (!layer.hideOpacity) {
builder.addSliderInput({
path: 'opacity',
name: 'Opacity',
name: t('geomap.layer-editor.name-opacity', 'Opacity'),
defaultValue: 1,
settings: {
min: 0,
@ -123,8 +124,8 @@ export function getLayerEditor(opts: LayerEditorOptions): NestedPanelOptions<Map
}
builder.addBooleanSwitch({
path: 'layer-tooltip',
name: 'Display tooltip',
description: 'Show the tooltip for layer',
name: t('geomap.layer-editor.name-display-tooltip', 'Display tooltip'),
description: t('geomap.layer-editor.description-display-tooltip', 'Show the tooltip for layer'),
defaultValue: true,
});
}

View File

@ -15,6 +15,7 @@ import {
FrameGeometrySourceMode,
EventBus,
} from '@grafana/data';
import { t } from '@grafana/i18n';
import { FrameVectorSource } from 'app/features/geo/utils/frameVectorSource';
import { getLocationMatchers } from 'app/features/geo/utils/location';
@ -230,7 +231,7 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
.addCustomEditor({
id: 'config.style',
path: 'config.style',
name: 'Styles',
name: t('geomap.markers-layer.name-styles', 'Styles'),
editor: StyleEditor,
settings: {
displayRotation: true,
@ -239,8 +240,8 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
})
.addBooleanSwitch({
path: 'config.showLegend',
name: 'Show legend',
description: 'Show map legend',
name: t('geomap.markers-layer.name-show-legend', 'Show legend'),
description: t('geomap.markers-layer.description-show-legend', 'Show map legend'),
defaultValue: defaultOptions.showLegend,
});
},

View File

@ -1,5 +1,5 @@
import { PanelPlugin } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { t, Trans } from '@grafana/i18n';
import { config } from '@grafana/runtime';
import { commonOptionsBuilder } from '@grafana/ui';
@ -20,13 +20,13 @@ export const plugin = new PanelPlugin<Options>(GeomapPanel)
},
})
.setPanelOptions((builder, context) => {
let category = ['Map view'];
let category = [t('geomap.category-map-view', 'Map view')];
builder.addCustomEditor({
category,
id: 'view',
path: 'view',
name: 'Initial view', // don't show it
description: 'This location will show when the panel first loads.',
name: t('geomap.name-initial-view', 'Initial view'), // don't show it
description: t('geomap.description-initial-view', 'This location will show when the panel first loads.'),
editor: MapViewEditor,
defaultValue: defaultMapViewConfig,
});
@ -34,8 +34,11 @@ export const plugin = new PanelPlugin<Options>(GeomapPanel)
builder.addBooleanSwitch({
category,
path: 'view.shared',
description: 'Use the same view across multiple panels. Note: this may require a dashboard reload.',
name: 'Share view',
description: t(
'geomap.description-share-view',
'Use the same view across multiple panels. Note: this may require a dashboard reload.'
),
name: t('geomap.name-share-view', 'Share view'),
defaultValue: defaultMapViewConfig.shared,
});
@ -44,8 +47,8 @@ export const plugin = new PanelPlugin<Options>(GeomapPanel)
if (!state?.layers) {
// TODO? show spinner?
} else {
const layersCategory = ['Map layers'];
const basemapCategory = ['Basemap layer'];
const layersCategory = [t('geomap.category-map-layers', 'Map layers')];
const basemapCategory = [t('geomap.category-basemap-layer', 'Basemap layer')];
builder.addCustomEditor({
category: layersCategory,
id: 'layers',
@ -93,59 +96,70 @@ export const plugin = new PanelPlugin<Options>(GeomapPanel)
}
// The controls section
category = ['Map controls'];
category = [t('geomap.category-map-controls', 'Map controls')];
builder
.addBooleanSwitch({
category,
path: 'controls.showZoom',
description: 'Show zoom control buttons in the upper left corner',
name: 'Show zoom control',
description: t('geomap.description-show-zoom', 'Show zoom control buttons in the upper left corner'),
name: t('geomap.name-show-zoom', 'Show zoom control'),
defaultValue: true,
})
.addBooleanSwitch({
category,
path: 'controls.mouseWheelZoom',
description: 'Enable zoom control via mouse wheel',
name: 'Mouse wheel zoom',
description: t('geomap.description-mouse-wheel-zoom', 'Enable zoom control via mouse wheel'),
name: t('geomap.name-mouse-wheel-zoom', 'Mouse wheel zoom'),
defaultValue: true,
})
.addBooleanSwitch({
category,
path: 'controls.showAttribution',
name: 'Show attribution',
description: 'Show the map source attribution info in the lower right',
name: t('geomap.name-show-attribution', 'Show attribution'),
description: t(
'geomap.description-show-attribution',
'Show the map source attribution info in the lower right'
),
defaultValue: true,
})
.addBooleanSwitch({
category,
path: 'controls.showScale',
name: 'Show scale',
description: 'Indicate map scale',
name: t('geomap.name-show-scale', 'Show scale'),
description: t('geomap.description-show-scale', 'Indicate map scale'),
defaultValue: false,
})
.addBooleanSwitch({
category,
path: 'controls.showMeasure',
name: 'Show measure tools',
description: 'Show tools for making measurements on the map',
name: t('geomap.name-show-measure', 'Show measure tools'),
description: t('geomap.description-show-measure', 'Show tools for making measurements on the map'),
defaultValue: false,
})
.addBooleanSwitch({
category,
path: 'controls.showDebug',
name: 'Show debug',
description: 'Show map info',
name: t('geomap.name-show-debug', 'Show debug'),
description: t('geomap.description-show-debug', 'Show map info'),
defaultValue: false,
})
.addRadio({
category,
path: 'tooltip.mode',
name: 'Tooltip',
name: t('geomap.name-tooltip', 'Tooltip'),
defaultValue: TooltipMode.Details,
settings: {
options: [
{ label: 'None', value: TooltipMode.None, description: 'Show contents on click, not hover' },
{ label: 'Details', value: TooltipMode.Details, description: 'Show popup on hover' },
{
label: t('geomap.tooltip-options.label-none', 'None'),
value: TooltipMode.None,
description: t('geomap.tooltip-options.description-none', 'Show contents on click, not hover'),
},
{
label: t('geomap.tooltip-options.label-details', 'Details'),
value: TooltipMode.Details,
description: t('geomap.tooltip-options.description-details', 'Show popup on hover'),
},
],
},
});

View File

@ -14,6 +14,7 @@ import TileSource from 'ol/source/Tile';
import VectorSource from 'ol/source/Vector';
import { DataFrame, GrafanaTheme2, SelectableValue } from '@grafana/data';
import { t } from '@grafana/i18n';
import { getTemplateSrv } from '@grafana/runtime';
import { getColorDimension } from 'app/features/dimensions/color';
import { getScalarDimension } from 'app/features/dimensions/scalar';
@ -132,13 +133,13 @@ export const notifyPanelEditor = (geomapPanel: GeomapPanel, layers: MapLayerStat
export const getNextLayerName = (panel: GeomapPanel) => {
let idx = panel.layers.length; // since basemap is 0, this looks right
while (true && idx < 100) {
const name = `Layer ${idx++}`;
const name = t('geomap.utils.get-next-layer-name', 'Layer {{name}}', { name: idx++ });
if (!panel.byName.has(name)) {
return name;
}
}
return `Layer ${Date.now()}`;
return t('geomap.utils.get-next-layer-name', 'Layer {{name}}', { name: Date.now() });
};
export function isSegmentVisible(

View File

@ -6310,6 +6310,11 @@
}
},
"scale-dimension-editor": {
"fixed-value-option": {
"label": {
"fixed-value": "Fixed value"
}
},
"label-max": "Max",
"label-min": "Min",
"label-value": "Value"
@ -7159,7 +7164,53 @@
"incomplete-request-error": "Sorry, I was unable to complete your request. Please try again.",
"send-custom-feedback": "Send"
},
"geo": {
"get-geometry-field": {
"warning-gazetteer-not-found": "Gazetteer not found",
"warning-no-geometry": "unable to find geometry",
"warning-select-geohash": "Select geohash field",
"warning-select-lat-long": "Select latitude/longitude fields",
"warning-select-lookup": "Select lookup field",
"warning-unable-to-find": "Unable to find location fields"
},
"location-editor": {
"geohash-field": {
"no-fields-message": "No strings fields found"
},
"latitude-field": {
"no-fields-message": "No numeric fields found"
},
"longitude-field": {
"no-fields-message": "No numeric fields found"
},
"lookup-field": {
"no-fields-message": "No strings fields found"
},
"name-gazetteer": "Gazetteer",
"name-geohash-field": "Geohash field",
"name-latitude-field": "Latitude field",
"name-location-mode": "Location Mode",
"name-longitude-field": "Longitude field",
"name-lookup-field": "Lookup field"
},
"location-more-editor": {
"mode-options": {
"description-auto": "Automatically identify location data based on default field names",
"description-coords": "Specify latitude and longitude fields",
"description-geohash": "Specify geohash field",
"description-lookup": "Specify Gazetteer and lookup field",
"label-auto": "Auto",
"label-coords": "Coords",
"label-geohash": "Geohash",
"label-lookup": "Lookup"
}
}
},
"geomap": {
"category-basemap-layer": "Basemap layer",
"category-map-controls": "Map controls",
"category-map-layers": "Map layers",
"category-map-view": "Map view",
"coordinates-map-view-editor": {
"label-latitude": "Latitude",
"label-longitude": "Longitude"
@ -7168,6 +7219,14 @@
"center": "Center:",
"zoom": "Zoom:"
},
"description-initial-view": "This location will show when the panel first loads.",
"description-mouse-wheel-zoom": "Enable zoom control via mouse wheel",
"description-share-view": "Use the same view across multiple panels. Note: this may require a dashboard reload.",
"description-show-attribution": "Show the map source attribution info in the lower right",
"description-show-debug": "Show map info",
"description-show-measure": "Show tools for making measurements on the map",
"description-show-scale": "Indicate map scale",
"description-show-zoom": "Show zoom control buttons in the upper left corner",
"fit-map-view-editor": {
"all-layers-editor-fragment": {
"label-layer": "Layer"
@ -7190,6 +7249,14 @@
"geomap-style-rules-editor": {
"aria-label-add-geomap-style-rule": "Add geomap style rule"
},
"layer-editor": {
"category-base-layer": "Base layer",
"description-display-tooltip": "Show the tooltip for layer",
"name-data": "Data",
"name-display-tooltip": "Display tooltip",
"name-layer-type": "Layer type",
"name-opacity": "Opacity"
},
"layers-editor": {
"label-add-layer": "Add layer",
"no-layers": "No layers?"
@ -7200,16 +7267,35 @@
"label-zoom": "Zoom",
"use-current-map-settings": "Use current map settings"
},
"markers-layer": {
"description-show-legend": "Show map legend",
"name-show-legend": "Show legend",
"name-styles": "Styles"
},
"markers-legend": {
"title-symbol": "Symbol"
},
"measure-overlay": {
"tooltip-show-measure-tools": "Show measure tools"
},
"name-initial-view": "Initial view",
"name-mouse-wheel-zoom": "Mouse wheel zoom",
"name-share-view": "Share view",
"name-show-attribution": "Show attribution",
"name-show-debug": "Show debug",
"name-show-measure": "Show measure tools",
"name-show-scale": "Show scale",
"name-show-zoom": "Show zoom control",
"name-tooltip": "Tooltip",
"plugin": {
"basemap-layer-configured-server-admin": "The basemap layer is configured by the server admin."
},
"style-editor": {
"horizontal-align-options": {
"label-center": "Center",
"label-left": "Left",
"label-right": "Right"
},
"label-align": "Align",
"label-baseline": "Baseline",
"label-color": "Color",
@ -7223,7 +7309,12 @@
"label-symbol-vertical-align": "Symbol vertical align",
"label-text-label": "Text label",
"label-x-offset": "X offset",
"label-y-offset": "Y offset"
"label-y-offset": "Y offset",
"vertical-align-options": {
"label-bottom": "Bottom",
"label-center": "Center",
"label-top": "Top"
}
},
"style-rule-editor": {
"aria-label-comparison-operator": "Comparison operator",
@ -7234,6 +7325,15 @@
"placeholder-feature-property": "Feature property",
"placeholder-numeric-value": "Numeric value",
"placeholder-value": "value"
},
"tooltip-options": {
"description-details": "Show popup on hover",
"description-none": "Show contents on click, not hover",
"label-details": "Details",
"label-none": "None"
},
"utils": {
"get-next-layer-name": "Layer {{name}}"
}
},
"get-enterprise": {