GrafanaUI: Mark up or ignore remaining grafana-ui translations (#102203)

* markup or ignore remaining grafana-ui translations

* fix unit tests, commit betterer results which somehow didn't get autocommitted?! :o

* fix SharedPreferences unit test

* fix remaining unit tests

* fix azure e2e test

* better solution
eledobleefe/query-320-256-66585^2
Ashley Harrison 2 months ago committed by GitHub
parent 5cd8547131
commit d82a877f65
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 99
      .betterer.results
  2. 5
      e2e/cloud-plugins-suite/azure-monitor.spec.ts
  3. 4
      packages/grafana-runtime/src/components/DataSourcePicker.test.tsx
  4. 2
      packages/grafana-ui/src/components/DataLinks/DataLinkSuggestions.tsx
  5. 8
      packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx
  6. 11
      packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx
  7. 3
      packages/grafana-ui/src/components/FileUpload/FileUpload.tsx
  8. 3
      packages/grafana-ui/src/components/InteractiveTable/Expander/index.tsx
  9. 9
      packages/grafana-ui/src/components/MatchersUI/FieldNameByRegexMatcherEditor.tsx
  10. 5
      packages/grafana-ui/src/components/MatchersUI/FieldValueMatcher.tsx
  11. 3
      packages/grafana-ui/src/components/Menu/MenuItem.tsx
  12. 10
      packages/grafana-ui/src/components/Monaco/ReactMonacoEditorLazy.tsx
  13. 5
      packages/grafana-ui/src/components/PanelChrome/PanelMenu.tsx
  14. 11
      packages/grafana-ui/src/components/Select/MultiValue.tsx
  15. 10
      packages/grafana-ui/src/components/Select/SelectBase.tsx
  16. 6
      packages/grafana-ui/src/components/Select/SelectMenu.tsx
  17. 17
      packages/grafana-ui/src/components/Table/CellActions.tsx
  18. 16
      packages/grafana-ui/src/components/Table/FilterList.tsx
  19. 4
      packages/grafana-ui/src/components/Table/FilterPopup.tsx
  20. 4
      packages/grafana-ui/src/components/Table/TableCellInspector.tsx
  21. 4
      packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.tsx
  22. 3
      packages/grafana-ui/src/components/Tags/TagList.tsx
  23. 3
      packages/grafana-ui/src/components/TagsInput/TagItem.tsx
  24. 4
      packages/grafana-ui/src/components/TagsInput/TagsInput.test.tsx
  25. 3
      packages/grafana-ui/src/components/Toggletip/Toggletip.tsx
  26. 3
      packages/grafana-ui/src/components/ToolbarButton/ToolbarButtonRow.tsx
  27. 3
      packages/grafana-ui/src/components/UnitPicker/UnitPicker.tsx
  28. 4
      packages/grafana-ui/src/components/UsersIndicator/UserIcon.tsx
  29. 6
      packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.tsx
  30. 3
      packages/grafana-ui/src/components/VizTooltip/SeriesTable.tsx
  31. 6
      packages/grafana-ui/src/options/builder/axis.tsx
  32. 11
      packages/grafana-ui/src/options/builder/stacking.tsx
  33. 4
      public/app/core/components/SharedPreferences/SharedPreferences.test.tsx
  34. 2
      public/app/features/dashboard-scene/pages/DashboardScenePage.test.tsx
  35. 2
      public/app/features/transformers/fieldToConfigMapping/FieldToConfigMappingEditor.test.tsx
  36. 2
      public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/ArgQueryEditor.test.tsx
  37. 2
      public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsSelector.test.tsx
  38. 2
      public/app/plugins/datasource/tempo/SearchTraceQLEditor/SearchField.test.tsx
  39. 71
      public/locales/en-US/grafana.json

@ -548,9 +548,6 @@ exports[`better eslint`] = {
"packages/grafana-ui/src/components/DataLinks/DataLinkInput.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"packages/grafana-ui/src/components/DataLinks/DataLinkSuggestions.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
@ -559,15 +556,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
],
"packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/FileUpload/FileUpload.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/Forms/Legacy/Input/Input.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"],
@ -585,67 +573,39 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
[0, 0, 0, "Unexpected any. Specify a different type.", "2"]
],
"packages/grafana-ui/src/components/InteractiveTable/Expander/index.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/JSONFormatter/json_explorer/json_explorer.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
],
"packages/grafana-ui/src/components/MatchersUI/FieldNameByRegexMatcherEditor.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/MatchersUI/FieldValueMatcher.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "2"]
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"packages/grafana-ui/src/components/MatchersUI/fieldMatchersUI.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"packages/grafana-ui/src/components/Menu/MenuItem.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/Modal/ModalsContext.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
[0, 0, 0, "Unexpected any. Specify a different type.", "3"]
],
"packages/grafana-ui/src/components/Monaco/ReactMonacoEditorLazy.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"]
],
"packages/grafana-ui/src/components/PanelChrome/PanelContext.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
],
"packages/grafana-ui/src/components/PanelChrome/PanelMenu.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"]
],
"packages/grafana-ui/src/components/PanelChrome/index.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"packages/grafana-ui/src/components/Segment/SegmentSelect.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"packages/grafana-ui/src/components/Select/MultiValue.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/Select/SelectBase.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "2"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "3"],
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
[0, 0, 0, "Unexpected any. Specify a different type.", "7"]
],
"packages/grafana-ui/src/components/Select/SelectMenu.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"]
[0, 0, 0, "Unexpected any. Specify a different type.", "5"]
],
"packages/grafana-ui/src/components/Select/ValueContainer.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
@ -691,21 +651,11 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
[0, 0, 0, "Unexpected any. Specify a different type.", "2"]
],
"packages/grafana-ui/src/components/Table/CellActions.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "2"]
],
"packages/grafana-ui/src/components/Table/Filter.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"packages/grafana-ui/src/components/Table/FilterList.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"]
],
"packages/grafana-ui/src/components/Table/FilterPopup.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"packages/grafana-ui/src/components/Table/FooterRow.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
@ -726,8 +676,7 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "3"]
],
"packages/grafana-ui/src/components/Table/TableCellInspector.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"packages/grafana-ui/src/components/Table/reducer.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
@ -746,33 +695,9 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
[0, 0, 0, "Unexpected any. Specify a different type.", "5"]
],
"packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/Tags/Tag.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"packages/grafana-ui/src/components/Tags/TagList.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/TagsInput/TagItem.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/Toggletip/Toggletip.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/ToolbarButton/ToolbarButtonRow.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/UnitPicker/UnitPicker.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/UsersIndicator/UserIcon.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/ValuePicker/ValuePicker.tsx:5381": [
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"]
],
@ -784,9 +709,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"]
],
"packages/grafana-ui/src/components/VizTooltip/SeriesTable.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"packages/grafana-ui/src/components/VizTooltip/VizTooltip.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
@ -815,18 +737,9 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
],
"packages/grafana-ui/src/options/builder/axis.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "2"]
],
"packages/grafana-ui/src/options/builder/hideSeries.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"packages/grafana-ui/src/options/builder/stacking.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"]
],
"packages/grafana-ui/src/slate-plugins/braces.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],

@ -222,10 +222,7 @@ describe('Azure monitor datasource', () => {
queriesForm: () => {
e2eSelectors.queryEditor.header.select().find('input').type('Azure Resource Graph{enter}');
cy.wait(1000); // Need to wait for code editor to completely load
e2eSelectors.queryEditor.argsQueryEditor.subscriptions
.input()
.find('[aria-label="select-clear-value"]')
.click();
e2eSelectors.queryEditor.argsQueryEditor.subscriptions.input().find('[aria-label="Clear value"]').click();
e2eSelectors.queryEditor.argsQueryEditor.subscriptions.input().find('input').type('datasources{enter}');
e2e.components.CodeEditor.container().type(
"Resources | where resourceGroup == 'cloud-plugins-e2e-test-azmon' | project name, resourceGroup"

@ -11,7 +11,7 @@ describe('DataSourcePicker', () => {
const onClear = jest.fn();
const select = render(<DataSourcePicker onClear={onClear} />);
const clearButton = select.getByLabelText('select-clear-value');
const clearButton = select.getByLabelText('Clear value');
await userEvent.click(clearButton);
expect(onClear).toHaveBeenCalled();
});
@ -20,7 +20,7 @@ describe('DataSourcePicker', () => {
const select = render(<DataSourcePicker />);
expect(() => {
select.getByLabelText('select-clear-value');
select.getByLabelText('Clear value');
}).toThrowError();
});

@ -87,7 +87,7 @@ export const DataLinkSuggestions = ({ suggestions, ...otherProps }: DataLinkSugg
<DataLinkSuggestionsList
{...otherProps}
suggestions={groupedSuggestions[key]}
label={`${capitalize(key)}`}
label={capitalize(key)}
activeIndex={otherProps.activeIndex}
activeIndexOffset={indexOffset}
key={key}

@ -6,7 +6,7 @@ import { Accept, DropEvent, DropzoneOptions, FileError, FileRejection, useDropzo
import { formattedValueToString, getValueFormat, GrafanaTheme2 } from '@grafana/data';
import { useTheme2 } from '../../themes';
import { Trans } from '../../utils/i18n';
import { t, Trans } from '../../utils/i18n';
import { Alert } from '../Alert/Alert';
import { Icon } from '../Icon/Icon';
@ -189,7 +189,11 @@ export function FileDropzone({ options, children, readAs, onLoad, fileListRender
const size = formattedValueToString(formattedSize);
return (
<div className={styles.errorAlert}>
<Alert title="Upload failed" severity="error" onRemove={clearAlert}>
<Alert
title={t('grafana-ui.file-dropzone.error-title', 'Upload failed')}
severity="error"
onRemove={clearAlert}
>
{errors.map((error) => {
switch (error.code) {
case ErrorCode.FileTooLarge:

@ -4,7 +4,7 @@ import { formattedValueToString, getValueFormat, GrafanaTheme2 } from '@grafana/
import { useStyles2 } from '../../themes';
import { trimFileName } from '../../utils/file';
import { Trans } from '../../utils/i18n';
import { t, Trans } from '../../utils/i18n';
import { Button } from '../Button';
import { Icon } from '../Icon/Icon';
import { IconButton } from '../IconButton/IconButton';
@ -26,7 +26,14 @@ export function FileListItem({ file: customFile, removeFile }: FileListItemProps
return (
<>
<span className={styles.error}>{error.message}</span>
{retryUpload && <IconButton name="sync" tooltip="Retry" tooltipPlacement="top" onClick={retryUpload} />}
{retryUpload && (
<IconButton
name="sync"
tooltip={t('grafana-ui.file-dropzone.item-retry', 'Retry')}
tooltipPlacement="top"
onClick={retryUpload}
/>
)}
{removeFile && (
<IconButton
className={retryUpload ? styles.marginLeft : ''}

@ -10,6 +10,7 @@ import { useStyles2 } from '../../themes';
import { getFocusStyles } from '../../themes/mixins';
import { ComponentSize } from '../../types/size';
import { trimFileName } from '../../utils/file';
import { t } from '../../utils/i18n';
import { getButtonStyles } from '../Button';
import { Icon } from '../Icon/Icon';
@ -67,7 +68,7 @@ export const FileUpload = ({
{showFileName && fileName && (
<span
aria-label="File name"
aria-label={t('grafana-ui.file-upload.file-name', 'File name')}
className={style.fileName}
data-testid={selectors.components.FileUpload.fileNameSpan}
>

@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { CellProps, HeaderProps } from 'react-table';
import { t } from '../../../utils/i18n';
import { IconButton } from '../../IconButton/IconButton';
const expanderContainerStyles = css({
@ -13,7 +14,7 @@ export function ExpanderCell<K extends object>({ row, __rowID }: CellProps<K, vo
return (
<div className={expanderContainerStyles}>
<IconButton
tooltip="toggle row expanded"
tooltip={t('grafana-ui.interactive-table.expand-row-tooltip', 'Toggle row expanded')}
aria-controls={__rowID}
// @ts-expect-error react-table doesn't ship with useExpanded types and we can't use declaration merging without affecting the table viz
name={row.isExpanded ? 'angle-down' : 'angle-right'}

@ -3,6 +3,7 @@ import * as React from 'react';
import { FieldMatcherID, fieldMatchers } from '@grafana/data';
import { t } from '../../utils/i18n';
import { Input } from '../Input/Input';
import { MatcherUIProps, FieldMatcherUIRegistryItem } from './types';
@ -17,7 +18,13 @@ export const FieldNameByRegexMatcherEditor = memo<MatcherUIProps<string>>((props
[onChange]
);
return <Input placeholder="Enter regular expression" defaultValue={options} onBlur={onBlur} />;
return (
<Input
placeholder={t('grafana-ui.field-name-by-regex-matcher.input-placeholder', 'Enter regular expression')}
defaultValue={options}
onBlur={onBlur}
/>
);
});
FieldNameByRegexMatcherEditor.displayName = 'FieldNameByRegexMatcherEditor';

@ -14,6 +14,7 @@ import {
import { ComparisonOperation } from '@grafana/schema';
import { useStyles2 } from '../../themes';
import { t } from '../../utils/i18n';
import { Input } from '../Input/Input';
import { Select } from '../Select/Select';
@ -70,7 +71,7 @@ export const FieldValueMatcherEditor = ({ options, onChange }: Props) => {
value={reducer.current}
options={reducer.options}
onChange={onSetReducer}
placeholder="Select field reducer"
placeholder={t('grafana-ui.field-value-matcher.select-field-placeholder', 'Select field reducer')}
/>
{opts.reducer && !isBool && (
<>
@ -78,7 +79,7 @@ export const FieldValueMatcherEditor = ({ options, onChange }: Props) => {
value={comparisonOperationOptions.find((v) => v.value === opts.op)}
options={comparisonOperationOptions}
onChange={onChangeOp}
aria-label={'Comparison operator'}
aria-label={t('grafana-ui.field-value-matcher.operator-label', 'Comparison operator')}
width={19}
/>

@ -7,6 +7,7 @@ import { GrafanaTheme2, LinkTarget } from '@grafana/data';
import { useStyles2 } from '../../themes';
import { getFocusStyles } from '../../themes/mixins';
import { IconName } from '../../types/icon';
import { t } from '../../utils/i18n';
import { Icon } from '../Icon/Icon';
import { Stack } from '../Layout/Stack/Stack';
@ -180,7 +181,7 @@ export const MenuItem = React.memo(
<div className={cx(styles.rightWrapper, { [styles.withShortcut]: hasShortcut })}>
{hasShortcut && (
<div className={styles.shortcut}>
<Icon name="keyboard" title="keyboard shortcut" />
<Icon name="keyboard" title={t('grafana-ui.menu-item.keyboard-shortcut-label', 'Keyboard shortcut')} />
{shortcut}
</div>
)}

@ -4,6 +4,7 @@ import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useStyles2 } from '../../themes';
import { t } from '../../utils/i18n';
import { useAsyncDependency } from '../../utils/useAsyncDependency';
import { ErrorWithStack } from '../ErrorBoundary/ErrorWithStack';
import { LoadingPlaceholder } from '../LoadingPlaceholder/LoadingPlaceholder';
@ -22,13 +23,18 @@ export const ReactMonacoEditorLazy = (props: ReactMonacoEditorProps) => {
);
if (loading) {
return <LoadingPlaceholder text={'Loading editor'} className={styles.container} />;
return (
<LoadingPlaceholder
text={t('grafana-ui.monaco.loading-placeholder', 'Loading editor')}
className={styles.container}
/>
);
}
if (error) {
return (
<ErrorWithStack
title="React Monaco Editor failed to load"
title={t('grafana-ui.monaco.error-label', 'React Monaco Editor failed to load')}
error={error}
errorInfo={{ componentStack: error?.stack ?? '' }}
/>

@ -3,6 +3,7 @@ import { ReactElement, useCallback } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { t } from '../../utils/i18n';
import { Dropdown } from '../Dropdown/Dropdown';
import { ToolbarButton } from '../ToolbarButton';
import { TooltipPlacement } from '../Tooltip';
@ -40,8 +41,8 @@ export function PanelMenu({
return (
<Dropdown overlay={menu} placement={placement} offset={offset} onVisibleChange={handleVisibility}>
<ToolbarButton
aria-label={`Menu for panel with ${title ? `title ${title}` : 'no title'}`}
title="Menu"
aria-label={t('grafana-ui.panel-menu.label', 'Menu for panel {{ title }}', { title: title ?? 'Untitled' })}
title={t('grafana-ui.panel-menu.title', 'Menu')}
icon="ellipsis-v"
iconSize="md"
narrow

@ -1,6 +1,7 @@
import * as React from 'react';
import { useTheme2 } from '../../themes';
import { t } from '../../utils/i18n';
import { IconButton, Props as IconButtonProps } from '../IconButton/IconButton';
import { getSelectStyles } from './getSelectStyles';
@ -27,5 +28,13 @@ export type MultiValueRemoveProps = {
export const MultiValueRemove = ({ children, innerProps }: React.PropsWithChildren<MultiValueRemoveProps>) => {
const theme = useTheme2();
const styles = getSelectStyles(theme);
return <IconButton {...innerProps} name="times" size="sm" className={styles.multiValueRemove} tooltip="Remove" />;
return (
<IconButton
{...innerProps}
name="times"
size="sm"
className={styles.multiValueRemove}
tooltip={t('grafana-ui.select.multi-value-remove', 'Remove')}
/>
);
};

@ -1,4 +1,3 @@
import { t } from 'i18next';
import { isArray, negate } from 'lodash';
import { ComponentProps, useCallback, useEffect, useRef, useState } from 'react';
import * as React from 'react';
@ -15,7 +14,7 @@ import Creatable from 'react-select/creatable';
import { SelectableValue, toOption } from '@grafana/data';
import { useTheme2 } from '../../themes';
import { Trans } from '../../utils/i18n';
import { t, Trans } from '../../utils/i18n';
import { Icon } from '../Icon/Icon';
import { Spinner } from '../Spinner/Spinner';
@ -351,7 +350,7 @@ export function SelectBase<T, Rest = {}>({
<Icon
name="times"
role="button"
aria-label="select-clear-value"
aria-label={t('grafana-ui.select.clear-value', 'Clear value')}
className={styles.singleValueRemove}
onMouseDown={(e) => {
e.preventDefault();
@ -369,7 +368,10 @@ export function SelectBase<T, Rest = {}>({
},
NoOptionsMessage() {
return (
<div className={styles.loadingMessage} aria-label="No options provided">
<div
className={styles.loadingMessage}
aria-label={t('grafana-ui.select.empty-options', 'No options provided')}
>
{noOptionsMessage}
</div>
);

@ -8,7 +8,7 @@ import { SelectableValue, toIconName } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useTheme2 } from '../../themes/ThemeContext';
import { Trans } from '../../utils/i18n';
import { t, Trans } from '../../utils/i18n';
import { clearButtonStyles } from '../Button';
import { Icon } from '../Icon/Icon';
import { ScrollContainer } from '../ScrollContainer/ScrollContainer';
@ -52,7 +52,7 @@ export const SelectMenu = ({
data-testid={selectors.components.Select.menu}
className={styles.menu}
style={{ maxHeight }}
aria-label="Select options menu"
aria-label={t('grafana-ui.select.menu-label', 'Select options menu')}
>
<ScrollContainer ref={innerRef} maxHeight="inherit" overflowX="hidden" showScrollIndicators padding={0.5}>
{toggleAllOptions && (
@ -185,7 +185,7 @@ export const VirtualizedSelectMenu = ({
className={styles.menu}
height={heightEstimate}
width={widthEstimate}
aria-label="Select options menu"
aria-label={t('grafana-ui.select.menu-label', 'Select options menu')}
itemCount={flattenedChildren.length}
itemSize={VIRTUAL_LIST_ITEM_HEIGHT}
>

@ -2,6 +2,7 @@ import { useCallback } from 'react';
import * as React from 'react';
import { IconSize } from '../../types/icon';
import { t } from '../../utils/i18n';
import { IconButton } from '../IconButton/IconButton';
import { Stack } from '../Layout/Stack/Stack';
import { TooltipPlacement } from '../Tooltip';
@ -58,7 +59,7 @@ export function CellActions({
{inspectEnabled && (
<IconButton
name="eye"
tooltip="Inspect value"
tooltip={t('grafana-ui.table.cell-inspect', 'Inspect value')}
onClick={() => {
if (setInspectCell) {
setInspectCell({ value: cell.value, mode: previewMode });
@ -68,10 +69,20 @@ export function CellActions({
/>
)}
{showFilters && (
<IconButton name={'search-plus'} onClick={onFilterFor} tooltip="Filter for value" {...commonButtonProps} />
<IconButton
name={'search-plus'}
onClick={onFilterFor}
tooltip={t('grafana-ui.table.cell-filter-on', 'Filter for value')}
{...commonButtonProps}
/>
)}
{showFilters && (
<IconButton name={'search-minus'} onClick={onFilterOut} tooltip="Filter out value" {...commonButtonProps} />
<IconButton
name={'search-minus'}
onClick={onFilterOut}
tooltip={t('grafana-ui.table.cell-filter-out', 'Filter out value')}
{...commonButtonProps}
/>
)}
</Stack>
</div>

@ -7,7 +7,7 @@ import { GrafanaTheme2, formattedValueToString, getValueFormat, SelectableValue
import { ButtonSelect, Checkbox, FilterInput, Label, Stack } from '..';
import { useStyles2, useTheme2 } from '../../themes';
import { Trans } from '../../utils/i18n';
import { t, Trans } from '../../utils/i18n';
interface Props {
values: SelectableValue[];
@ -172,7 +172,13 @@ export const FilterList = ({
return (
<Stack direction="column" gap={0.25}>
{!showOperators && <FilterInput placeholder="Filter values" onChange={setSearchFilter} value={searchFilter} />}
{!showOperators && (
<FilterInput
placeholder={t('grafana-ui.table.filter-placeholder', 'Filter values')}
onChange={setSearchFilter}
value={searchFilter}
/>
)}
{showOperators && (
<Stack direction="row" gap={0}>
<ButtonSelect
@ -182,7 +188,11 @@ export const FilterList = ({
value={operator}
tooltip={operator.description}
/>
<FilterInput placeholder="Filter values" onChange={setSearchFilter} value={searchFilter} />
<FilterInput
placeholder={t('grafana-ui.table.filter-placeholder', 'Filter values')}
onChange={setSearchFilter}
value={searchFilter}
/>
</Stack>
)}
{items.length > 0 ? (

@ -6,7 +6,7 @@ import { Field, GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Button, ClickOutsideWrapper, IconButton, Label, Stack } from '..';
import { useStyles2, useTheme2 } from '../../themes';
import { Trans } from '../../utils/i18n';
import { t, Trans } from '../../utils/i18n';
import { FilterList } from './FilterList';
import { TableStyles } from './styles';
@ -75,7 +75,7 @@ export const FilterPopup = ({
</Label>
<IconButton
name="text-fields"
tooltip="Match case"
tooltip={t('grafana-ui.table.filter-popup-match-case', 'Match case')}
style={{ color: matchCase ? theme.colors.text.link : theme.colors.text.disabled }}
onClick={() => {
setMatchCase((s) => !s);

@ -1,7 +1,7 @@
import { isString } from 'lodash';
import { useState } from 'react';
import { Trans } from '../../utils/i18n';
import { t, Trans } from '../../utils/i18n';
import { ClipboardButton } from '../ClipboardButton/ClipboardButton';
import { Drawer } from '../Drawer/Drawer';
import { Stack } from '../Layout/Stack/Stack';
@ -68,7 +68,7 @@ export function TableCellInspector({ value, onDismiss, mode }: TableCellInspecto
);
return (
<Drawer onClose={onDismiss} title="Inspect value" tabs={tabBar}>
<Drawer onClose={onDismiss} title={t('grafana-ui.table.inspect-drawer-title', 'Inspect value')} tabs={tabBar}>
<Stack direction="column" gap={2}>
<ClipboardButton icon="copy" getText={() => text} style={{ marginLeft: 'auto', width: '200px' }}>
<Trans i18nKey="grafana-ui.table.copy">Copy to Clipboard</Trans>

@ -7,7 +7,7 @@ import { DataFrame, CSVConfig, readCSV, GrafanaTheme2 } from '@grafana/data';
import { stylesFactory, withTheme2 } from '../../themes';
import { Themeable2 } from '../../types/theme';
import { Trans } from '../../utils/i18n';
import { t, Trans } from '../../utils/i18n';
import { Icon } from '../Icon/Icon';
import { TextArea } from '../TextArea/TextArea';
@ -74,7 +74,7 @@ export class UnThemedTableInputCSV extends PureComponent<Props, State> {
<div className={styles.tableInputCsv}>
<TextArea
style={{ width, height }}
placeholder="Enter CSV here..."
placeholder={t('grafana-ui.table.csv-placeholder', 'Enter CSV here...')}
value={this.state.text}
onChange={this.onTextChange}
className={styles.textarea}

@ -5,6 +5,7 @@ import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, useTheme2 } from '../../themes';
import { IconName } from '../../types/icon';
import { t } from '../../utils/i18n';
import { SkeletonComponent, attachSkeleton } from '../../utils/skeleton';
import { OnTagClick, Tag } from './Tag';
@ -34,7 +35,7 @@ const TagListComponent = memo(
const numTags = tags.length;
const tagsToDisplay = displayMax ? tags.slice(0, displayMax) : tags;
return (
<ul className={cx(styles.wrapper, className)} aria-label="Tags" ref={ref}>
<ul className={cx(styles.wrapper, className)} aria-label={t('grafana-ui.tags.list-label', 'Tags')} ref={ref}>
{tagsToDisplay.map((tag, i) => (
<li className={styles.li} key={tag}>
<Tag

@ -5,6 +5,7 @@ import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '../../themes';
import { getTagColorsFromName } from '../../utils';
import { t } from '../../utils/i18n';
import { IconButton } from '../IconButton/IconButton';
interface Props {
@ -28,7 +29,7 @@ export const TagItem = ({ name, disabled, onRemove }: Props) => {
name="times"
size="lg"
disabled={disabled}
tooltip={`Remove "${name}" tag`}
tooltip={t('grafana-ui.tags-input.remove', 'Remove tag: {{name}}', { name })}
onClick={() => onRemove(name)}
className={styles.buttonStyles}
/>

@ -7,7 +7,7 @@ describe('TagsInput', () => {
const onChange = jest.fn();
render(<TagsInput onChange={onChange} tags={['One', 'Two']} />);
fireEvent.click(await screen.findByRole('button', { name: /Remove \"One\"/i }));
fireEvent.click(await screen.findByRole('button', { name: /Remove tag: One/i }));
expect(onChange).toHaveBeenCalledWith(['Two']);
});
@ -16,7 +16,7 @@ describe('TagsInput', () => {
const onChange = jest.fn();
render(<TagsInput onChange={onChange} tags={['One', 'Two']} disabled />);
fireEvent.click(await screen.findByRole('button', { name: /Remove \"One\"/i }));
fireEvent.click(await screen.findByRole('button', { name: /Remove tag: One/i }));
expect(onChange).not.toHaveBeenCalled();
});

@ -18,6 +18,7 @@ import { memo, cloneElement, isValidElement, useRef, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, useTheme2 } from '../../themes/ThemeContext';
import { t } from '../../utils/i18n';
import { buildTooltipTheme, getPlacement } from '../../utils/tooltipUtils';
import { IconButton } from '../IconButton/IconButton';
@ -139,7 +140,7 @@ export const Toggletip = memo(
{closeButton && (
<div className={style.headerClose}>
<IconButton
aria-label="Close"
aria-label={t('grafana-ui.toggletip.close', 'Close')}
name="times"
data-testid="toggletip-header-close"
onClick={() => {

@ -7,6 +7,7 @@ import { Children, forwardRef, HTMLAttributes, useState, useRef, useLayoutEffect
import { GrafanaTheme2 } from '@grafana/data';
import { useTheme2 } from '../../themes';
import { t } from '../../utils/i18n';
import { getPortalContainer } from '../Portal/Portal';
import { ToolbarButton } from './ToolbarButton';
@ -87,7 +88,7 @@ export const ToolbarButtonRow = forwardRef<HTMLDivElement, Props>(
<div ref={overflowRef} className={styles.overflowButton}>
<ToolbarButton
variant={showOverflowItems ? 'active' : 'default'}
tooltip="Show more items"
tooltip={t('grafana-ui.toolbar-button-row.show-more', 'Show more items')}
onClick={() => setShowOverflowItems(!showOverflowItems)}
icon="ellipsis-v"
iconOnly

@ -2,6 +2,7 @@ import { PureComponent } from 'react';
import { getValueFormats, SelectableValue } from '@grafana/data';
import { t } from '../../utils/i18n';
import { Cascader, CascaderOption } from '../Cascader/Cascader';
export interface UnitPickerProps {
@ -61,7 +62,7 @@ export class UnitPicker extends PureComponent<UnitPickerProps> {
changeOnSelect={false}
formatCreateLabel={formatCreateLabel}
options={groupOptions}
placeholder="Choose"
placeholder={t('grafana-ui.unit-picker.placeholder', 'Choose')}
isClearable
onSelect={this.props.onChange}
/>

@ -4,7 +4,7 @@ import { useMemo, PropsWithChildren } from 'react';
import { dateTime, DateTimeInput, GrafanaTheme2 } from '@grafana/data';
import { useTheme2 } from '../../themes';
import { Trans } from '../../utils/i18n';
import { t, Trans } from '../../utils/i18n';
import { Tooltip } from '../Tooltip';
import { UserView } from './types';
@ -67,7 +67,7 @@ export const UserIcon = ({
type={'button'}
onClick={onClick}
className={cx(styles.container, onClick && styles.pointer, className)}
aria-label={`${user.name} icon`}
aria-label={t('grafana-ui.user-icon.label', '{{name}} icon', { name: user.name })}
>
{children ? (
<div className={cx(styles.content, styles.textContent)}>{children}</div>

@ -3,6 +3,7 @@ import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '../../themes';
import { t } from '../../utils/i18n';
import { UserIcon } from './UserIcon';
import { UserView } from './types';
@ -28,7 +29,10 @@ export const UsersIndicator = ({ users, onClick, limit = 4 }: UsersIndicatorProp
const tooManyUsers = extraUsers > 99;
return (
<div className={styles.container} aria-label="Users indicator container">
<div
className={styles.container}
aria-label={t('grafana-ui.users-indicator.container-label', 'Users indicator container')}
>
{limitReached && (
<UserIcon onClick={onClick} userView={{ user: { name: 'Extra users' }, lastActiveAt: '' }} showTooltip={false}>
{tooManyUsers ? '...' : `+${extraUsers}`}

@ -4,6 +4,7 @@ import * as React from 'react';
import { GrafanaTheme2, GraphSeriesValue } from '@grafana/data';
import { useStyles2 } from '../../themes';
import { t } from '../../utils/i18n';
import { SeriesIcon } from '../VizLegend/SeriesIcon';
/**
@ -86,7 +87,7 @@ export const SeriesTable = ({ timestamp, series }: SeriesTableProps) => {
return (
<>
{timestamp && (
<div className={styles.timestamp} aria-label="Timestamp">
<div className={styles.timestamp} aria-label={t('grafana-ui.viz-tooltip.timestamp', 'Timestamp')}>
{timestamp}
</div>
)}

@ -13,6 +13,7 @@ import { Input } from '../../components/Input/Input';
import { Stack } from '../../components/Layout/Stack/Stack';
import { Select } from '../../components/Select/Select';
import { graphFieldOptions } from '../../components/uPlot/config';
import { t } from '../../utils/i18n';
const category = ['Axis'];
@ -162,7 +163,7 @@ export const ScaleDistributionEditor = ({ value, onChange }: StandardEditorProps
}}
/>
{(type === ScaleDistribution.Log || type === ScaleDistribution.Symlog) && (
<Field label="Log base">
<Field label={t('grafana-ui.axis-builder.log-base', 'Log base')}>
<Select
options={LOG_DISTRIBUTION_OPTIONS}
value={log}
@ -176,8 +177,9 @@ export const ScaleDistributionEditor = ({ value, onChange }: StandardEditorProps
</Field>
)}
{type === ScaleDistribution.Symlog && (
<Field label="Linear threshold" style={{ marginBottom: 0 }}>
<Field label={t('grafana-ui.axis-builder.linear-threshold', 'Linear threshold')} style={{ marginBottom: 0 }}>
<Input
// eslint-disable-next-line @grafana/no-untranslated-strings
placeholder="1"
value={value?.linearThreshold}
onChange={(v) => {

@ -12,6 +12,7 @@ import { IconButton } from '../../components/IconButton/IconButton';
import { Input } from '../../components/Input/Input';
import { Stack } from '../../components/Layout/Stack/Stack';
import { graphFieldOptions } from '../../components/uPlot/config';
import { t } from '../../utils/i18n';
export const StackingEditor = ({
value,
@ -34,8 +35,14 @@ export const StackingEditor = ({
{context.isOverride && value?.mode && value?.mode !== StackingMode.None && (
<Input
type="text"
placeholder="Group"
suffix={<IconButton name="question-circle" tooltip="Name of the stacking group" tooltipPlacement="top" />}
placeholder={t('grafana-ui.stacking-builder.group', 'Group')}
suffix={
<IconButton
name="question-circle"
tooltip={t('grafana-ui.stacking-builder.group-tooltip', 'Name of the stacking group')}
tooltipPlacement="top"
/>
}
defaultValue={value?.group}
onChange={(v) => {
onChange({

@ -188,9 +188,9 @@ describe('SharedPreferences', () => {
await selectComboboxOptionInTest(await screen.findByRole('combobox', { name: 'Interface theme' }), 'Default');
// there's no default option in this dropdown - there's a clear selection button
// get the parent container, and find the "select-clear-value" button
// get the parent container, and find the "Clear value" button
const dashboardSelect = screen.getByTestId('User preferences home dashboard drop down');
await userEvent.click(within(dashboardSelect).getByRole('button', { name: 'select-clear-value' }));
await userEvent.click(within(dashboardSelect).getByRole('button', { name: 'Clear value' }));
await selectOptionInTest(screen.getByLabelText('Timezone'), 'Default');

@ -203,7 +203,7 @@ describe('DashboardScenePage', () => {
// Wish I could use the menu here but unable t get it to open when I click the menu button
// Somethig with Dropdown that is not working inside react-testing
await userEvent.click(screen.getByLabelText('Menu for panel with title Panel B'));
await userEvent.click(screen.getByLabelText('Menu for panel Panel B'));
const inspectMenuItem = await screen.findAllByText('Inspect');

@ -56,7 +56,7 @@ describe('FieldToConfigMappingEditor', () => {
setup({ mappings: [{ fieldName: 'max', handlerKey: 'min' }] });
const select = (await screen.findByTestId('max-config-key')).childNodes[0];
await userEvent.click(getByLabelText(select as HTMLElement, 'select-clear-value'));
await userEvent.click(getByLabelText(select as HTMLElement, 'Clear value'));
expect(mockOnChange).toHaveBeenCalledWith(expect.arrayContaining([]));
});

@ -165,7 +165,7 @@ describe('ArgQueryEditor', () => {
);
expect(await waitFor(() => screen.findByText('foo'))).toBeInTheDocument();
const clear = screen.getByLabelText('select-clear-value');
const clear = screen.getByLabelText('Clear value');
await userEvent.click(clear);
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ subscriptions: [] }));

@ -284,7 +284,7 @@ describe('LogGroupsSelector', () => {
/>
);
await userEvent.click(screen.getByText('Select log groups'));
await userEvent.click(screen.getByRole('button', { name: 'select-clear-value' }));
await userEvent.click(screen.getByRole('button', { name: 'Clear value' }));
await userEvent.click(screen.getByText('Add log groups'));
expect(onChange).toHaveBeenCalledWith([
{

@ -147,7 +147,7 @@ describe('SearchField', () => {
expect(updateFilter).toHaveBeenCalledWith({ ...filter, tag: 'tag1', value: [] });
// Remove the tag
const tagRemove = await screen.findByLabelText('select-clear-value');
const tagRemove = await screen.findByLabelText('Clear value');
await user.click(tagRemove);
expect(updateFilter).toHaveBeenCalledWith({ ...filter, value: [] });
}

@ -1807,6 +1807,10 @@
"saved": "Saved!",
"saving": "Saving <1></1>"
},
"axis-builder": {
"linear-threshold": "Linear threshold",
"log-base": "Log base"
},
"card": {
"option": "option"
},
@ -1933,16 +1937,38 @@
"field-link-list": {
"external-links-heading": "External links"
},
"field-name-by-regex-matcher": {
"input-placeholder": "Enter regular expression"
},
"field-value-matcher": {
"operator-label": "Comparison operator",
"select-field-placeholder": "Select field reducer"
},
"file-dropzone": {
"cancel-upload": "Cancel upload",
"file-too-large": "File is larger than {{size}}"
"error-title": "Upload failed",
"file-too-large": "File is larger than {{size}}",
"item-retry": "Retry"
},
"file-upload": {
"file-name": "File name"
},
"filter-input": {
"clear": "Clear"
},
"interactive-table": {
"expand-row-tooltip": "Toggle row expanded"
},
"menu-item": {
"keyboard-shortcut-label": "Keyboard shortcut"
},
"modal": {
"close-tooltip": "Close"
},
"monaco": {
"error-label": "React Monaco Editor failed to load",
"loading-placeholder": "Loading editor"
},
"named-colors-palette": {
"text-color-swatch": "Text color",
"transparent-swatch": "Transparent"
@ -1957,6 +1983,10 @@
"next-page": "next page",
"previous-page": "previous page"
},
"panel-menu": {
"label": "Menu for panel {{ title }}",
"title": "Menu"
},
"secret-form-field": {
"reset": "Reset"
},
@ -1966,7 +1996,11 @@
"no-options": "No options found"
},
"select": {
"clear-value": "Clear value",
"default-create-label": "Hit enter to add",
"empty-options": "No options provided",
"menu-label": "Select options menu",
"multi-value-remove": "Remove",
"no-options-label": "No options found",
"placeholder": "Choose"
},
@ -1976,21 +2010,49 @@
"spinner": {
"aria-label": "Loading"
},
"stacking-builder": {
"group": "Group",
"group-tooltip": "Name of the stacking group"
},
"table": {
"cell-filter-on": "Filter for value",
"cell-filter-out": "Filter out value",
"cell-inspect": "Inspect value",
"copy": "Copy to Clipboard",
"csv-counts": "Rows:{{rows}}, Columns:{{columns}} <5></5>",
"csv-placeholder": "Enter CSV here...",
"filter-placeholder": "Filter values",
"filter-popup-apply": "Ok",
"filter-popup-cancel": "Cancel",
"filter-popup-clear": "Clear filter",
"filter-popup-heading": "Filter by values:",
"filter-popup-match-case": "Match case",
"inspect-drawer-title": "Inspect value",
"no-values-label": "No values",
"pagination-summary": "{{itemsRangeStart}} - {{displayedEnd}} of {{numRows}} rows"
},
"tags": {
"list-label": "Tags"
},
"tags-input": {
"add": "Add"
"add": "Add",
"remove": "Remove tag: {{name}}"
},
"toggletip": {
"close": "Close"
},
"toolbar-button-row": {
"show-more": "Show more items"
},
"unit-picker": {
"placeholder": "Choose"
},
"user-icon": {
"active-text": "Active last 15m"
"active-text": "Active last 15m",
"label": "{{name}} icon"
},
"users-indicator": {
"container-label": "Users indicator container"
},
"value-pill": {
"remove-button": "Remove {{children}}"
@ -2004,7 +2066,8 @@
"actions-confirmation-message": "Provide a descriptive prompt to confirm or cancel the action.",
"footer-add-annotation": "Add annotation",
"footer-click-to-action": "Click to {{actionTitle}}",
"footer-click-to-navigate": "Click to open {{linkTitle}}"
"footer-click-to-navigate": "Click to open {{linkTitle}}",
"timestamp": "Timestamp"
}
},
"graph": {

Loading…
Cancel
Save