diff --git a/apps/alerting/notifications/pkg/apis/alerting_manifest.go b/apps/alerting/notifications/pkg/apis/alerting_manifest.go index 4ea6c3da1c7..9b1e424d463 100644 --- a/apps/alerting/notifications/pkg/apis/alerting_manifest.go +++ b/apps/alerting/notifications/pkg/apis/alerting_manifest.go @@ -14,8 +14,6 @@ import ( v0alpha1 "github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/alerting/v0alpha1" ) -var () - var appManifestData = app.ManifestData{ AppName: "alerting", Group: "notifications.alerting.grafana.app", diff --git a/apps/dashboard/pkg/apis/dashboard_manifest.go b/apps/dashboard/pkg/apis/dashboard_manifest.go index 60161eef179..e9fa97d8017 100644 --- a/apps/dashboard/pkg/apis/dashboard_manifest.go +++ b/apps/dashboard/pkg/apis/dashboard_manifest.go @@ -14,8 +14,6 @@ import ( v2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1" ) -var () - var appManifestData = app.ManifestData{ AppName: "dashboard", Group: "dashboard.grafana.app", diff --git a/apps/folder/pkg/apis/folder_manifest.go b/apps/folder/pkg/apis/folder_manifest.go index 8525663fea8..8491ddc6083 100644 --- a/apps/folder/pkg/apis/folder_manifest.go +++ b/apps/folder/pkg/apis/folder_manifest.go @@ -14,8 +14,6 @@ import ( v1beta1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" ) -var () - var appManifestData = app.ManifestData{ AppName: "folder", Group: "folder.grafana.app", diff --git a/apps/iam/pkg/apis/iam_manifest.go b/apps/iam/pkg/apis/iam_manifest.go index a7dba866021..b80f5e5eee3 100644 --- a/apps/iam/pkg/apis/iam_manifest.go +++ b/apps/iam/pkg/apis/iam_manifest.go @@ -14,8 +14,6 @@ import ( v0alpha1 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" ) -var () - var appManifestData = app.ManifestData{ AppName: "iam", Group: "iam.grafana.app", diff --git a/apps/playlist/pkg/apis/playlist_manifest.go b/apps/playlist/pkg/apis/playlist_manifest.go index cecef6199d9..7973fdf4e6d 100644 --- a/apps/playlist/pkg/apis/playlist_manifest.go +++ b/apps/playlist/pkg/apis/playlist_manifest.go @@ -14,8 +14,6 @@ import ( v0alpha1 "github.com/grafana/grafana/apps/playlist/pkg/apis/playlist/v0alpha1" ) -var () - var appManifestData = app.ManifestData{ AppName: "playlist", Group: "playlist.grafana.app", diff --git a/eslint.config.js b/eslint.config.js index d4da985724c..28bc0da1adb 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -20,7 +20,11 @@ const getEnvConfig = require('./scripts/webpack/env-util'); const envConfig = getEnvConfig(); const enableBettererRules = envConfig.frontend_dev_betterer_eslint_rules; -const pluginsToTranslate = ['public/app/plugins/datasource/azuremonitor', 'public/app/plugins/datasource/mssql']; +const pluginsToTranslate = [ + 'public/app/plugins/panel', + 'public/app/plugins/datasource/azuremonitor', + 'public/app/plugins/datasource/mssql', +]; /** * @type {Array} diff --git a/packages/grafana-e2e-selectors/src/selectors/components.ts b/packages/grafana-e2e-selectors/src/selectors/components.ts index 0cfe9907c6a..343dc58efcb 100644 --- a/packages/grafana-e2e-selectors/src/selectors/components.ts +++ b/packages/grafana-e2e-selectors/src/selectors/components.ts @@ -578,6 +578,7 @@ export const versionedComponents = { }, measureButton: { + '12.1.0': 'data-testid panel-editor-measure-button', '9.2.0': 'show measure tools', }, diff --git a/pkg/services/folder/folderimpl/sqlstore_test.go b/pkg/services/folder/folderimpl/sqlstore_test.go index 4f5b915ac48..084c7cf9e9f 100644 --- a/pkg/services/folder/folderimpl/sqlstore_test.go +++ b/pkg/services/folder/folderimpl/sqlstore_test.go @@ -1002,10 +1002,10 @@ func CreateOrg(t *testing.T, db db.DB, cfg *setting.Cfg) int64 { requester := &identity.StaticRequester{ OrgID: 1, Permissions: map[int64]map[string][]string{ - 1: map[string][]string{ + 1: { accesscontrol.ActionOrgsDelete: {"*"}, }, - 2: map[string][]string{ + 2: { accesscontrol.ActionOrgsDelete: {"*"}, }, }, diff --git a/pkg/services/org/orgimpl/org_delete_svc_test.go b/pkg/services/org/orgimpl/org_delete_svc_test.go index bcc966a1b6d..78c7ad28467 100644 --- a/pkg/services/org/orgimpl/org_delete_svc_test.go +++ b/pkg/services/org/orgimpl/org_delete_svc_test.go @@ -31,10 +31,10 @@ func TestDeletionService_Delete(t *testing.T) { requester := &identity.StaticRequester{ OrgID: 1, Permissions: map[int64]map[string][]string{ - 1: map[string][]string{ + 1: { accesscontrol.ActionOrgsDelete: {"*"}, }, - 2: map[string][]string{ + 2: { accesscontrol.ActionOrgsDelete: {"*"}, }, }, @@ -52,10 +52,10 @@ func TestDeletionService_Delete(t *testing.T) { requester = &identity.StaticRequester{ OrgID: 1, Permissions: map[int64]map[string][]string{ - 1: map[string][]string{ + 1: { accesscontrol.ActionOrgsRead: {"*"}, }, - 2: map[string][]string{ + 2: { accesscontrol.ActionOrgsRead: {"*"}, }, }, diff --git a/public/app/plugins/panel/alertlist/GroupByWithLoading.tsx b/public/app/plugins/panel/alertlist/GroupByWithLoading.tsx index 30b54432538..3cb04653b22 100644 --- a/public/app/plugins/panel/alertlist/GroupByWithLoading.tsx +++ b/public/app/plugins/panel/alertlist/GroupByWithLoading.tsx @@ -2,6 +2,7 @@ import { isEmpty, uniq } from 'lodash'; import { useEffect, useMemo } from 'react'; import { SelectableValue } from '@grafana/data'; +import { useTranslate } from '@grafana/i18n'; import { Icon, MultiSelect } from '@grafana/ui'; import { useUnifiedAlertingSelector } from 'app/features/alerting/unified/hooks/useUnifiedAlertingSelector'; import { fetchAllPromRulesAction } from 'app/features/alerting/unified/state/actions'; @@ -24,6 +25,7 @@ interface Props { } export const GroupBy = (props: Props) => { + const { t } = useTranslate(); const { onChange, id, defaultValue, dataSource } = props; const dispatch = useDispatch(); @@ -65,8 +67,8 @@ export const GroupBy = (props: Props) => { id={id} isLoading={loading} defaultValue={defaultValue} - aria-label={'group by label keys'} - placeholder="Group by" + aria-label={t('alertlist.group-by.aria-label-group-by-label-keys', 'group by label keys')} + placeholder={t('alertlist.group-by.placeholder-group-by', 'Group by')} prefix={} onChange={(items) => { onChange(items.map((item) => item.value ?? '')); diff --git a/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx b/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx index be6401e3ad1..fa81e2bc8ec 100644 --- a/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx +++ b/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx @@ -4,6 +4,7 @@ import { useEffect, useMemo } from 'react'; import { useEffectOnce, useToggle } from 'react-use'; import { GrafanaTheme2, PanelProps } from '@grafana/data'; +import { Trans, useTranslate } from '@grafana/i18n'; import { TimeRangeUpdatedEvent } from '@grafana/runtime'; import { Alert, @@ -94,6 +95,7 @@ const fetchPromAndRuler = ({ }; function UnifiedAlertList(props: PanelProps) { + const { t } = useTranslate(); const dispatch = useDispatch(); const [limitInstances, toggleLimit] = useToggle(true); const [, gmaViewAllowed] = useAlertingAbility(AlertingAction.ViewAlertRule); @@ -249,7 +251,7 @@ function UnifiedAlertList(props: PanelProps) { )} {/* loading moved here to avoid twitching */} - {renderLoading && } + {renderLoading && } ); } @@ -450,12 +452,17 @@ export const getStyles = (theme: GrafanaTheme2) => ({ }); export function UnifiedAlertListPanel(props: PanelProps) { + const { t } = useTranslate(); const [, gmaReadAllowed] = useAlertingAbility(AlertingAction.ViewAlertRule); const [, externalReadAllowed] = useAlertingAbility(AlertingAction.ViewExternalAlertRule); if (!gmaReadAllowed && !externalReadAllowed) { return ( - Sorry, you do not have the required permissions to read alert rules + + + Sorry, you do not have the required permissions to read alert rules. + + ); } diff --git a/public/app/plugins/panel/alertlist/module.tsx b/public/app/plugins/panel/alertlist/module.tsx index 2d0e2ef64c5..c176845cf1e 100644 --- a/public/app/plugins/panel/alertlist/module.tsx +++ b/public/app/plugins/panel/alertlist/module.tsx @@ -1,4 +1,5 @@ import { DataSourceInstanceSettings, PanelPlugin } from '@grafana/data'; +import { Trans } from '@grafana/i18n'; import { Button, Stack } from '@grafana/ui'; import { NestedFolderPicker } from 'app/core/components/NestedFolderPicker/NestedFolderPicker'; import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker'; @@ -127,7 +128,7 @@ const unifiedAlertList = new PanelPlugin(UnifiedAlertLi }} /> ); diff --git a/public/app/plugins/panel/alertlist/unified-alerting/UngroupedView.tsx b/public/app/plugins/panel/alertlist/unified-alerting/UngroupedView.tsx index 35a58263e22..df9591a9507 100644 --- a/public/app/plugins/panel/alertlist/unified-alerting/UngroupedView.tsx +++ b/public/app/plugins/panel/alertlist/unified-alerting/UngroupedView.tsx @@ -2,6 +2,7 @@ import { css, cx } from '@emotion/css'; import { useLocation } from 'react-use'; import { GrafanaTheme2, intervalToAbbreviatedDurationString } from '@grafana/data'; +import { useTranslate, Trans } from '@grafana/i18n'; import { Icon, Stack, useStyles2 } from '@grafana/ui'; import alertDef from 'app/features/alerting/state/alertDef'; import { Spacer } from 'app/features/alerting/unified/components/Spacer'; @@ -36,6 +37,7 @@ function getGrafanaInstancesTotal(totals: Partial { + const { t } = useTranslate(); const styles = useStyles2(getStyles); const stateStyle = useStyles2(getStateTagStyles); const { href: returnTo } = useLocation(); @@ -93,9 +95,11 @@ const UngroupedModeView = ({ rules, options, handleInstancesLimit, limitInstance target="__blank" className={styles.link} rel="noopener" - aria-label="View alert rule" + aria-label={t('alertlist.ungrouped-mode-view.aria-label-view-alert-rule', 'View alert rule')} > - View alert rule + + View alert rule + )} @@ -105,15 +109,14 @@ const UngroupedModeView = ({ rules, options, handleInstancesLimit, limitInstance {alertStateToReadable(alertingRule.state)} {' '} {firstActiveAt && alertingRule.state !== PromAlertingRuleState.Inactive && ( - <> - for{' '} - - {intervalToAbbreviatedDurationString({ - start: firstActiveAt, - end: Date.now(), - })} - - + + for {'{{duration}}'} + )} diff --git a/public/app/plugins/panel/annolist/AnnoListPanel.tsx b/public/app/plugins/panel/annolist/AnnoListPanel.tsx index 9ad76a71491..2e01cd495a1 100644 --- a/public/app/plugins/panel/annolist/AnnoListPanel.tsx +++ b/public/app/plugins/panel/annolist/AnnoListPanel.tsx @@ -12,6 +12,8 @@ import { locationUtil, PanelProps, } from '@grafana/data'; +import { Trans } from '@grafana/i18n'; +import { t } from '@grafana/i18n/internal'; import { config, getBackendSrv, locationService } from '@grafana/runtime'; import { Button, ScrollContainer, stylesFactory, TagList } from '@grafana/ui'; import { AbstractList } from '@grafana/ui/internal'; @@ -247,7 +249,11 @@ export class AnnoListPanel extends PureComponent { render() { const { loaded, annotations, queryUser, queryTags } = this.state; if (!loaded) { - return
loading...
; + return ( +
+ Loading... +
+ ); } // Previously we showed inidication that it covered all time @@ -262,14 +268,20 @@ export class AnnoListPanel extends PureComponent { {hasFilter && (
- Filter: + + Filter: + {queryUser && ( @@ -287,7 +299,11 @@ export class AnnoListPanel extends PureComponent {
)} - {annotations.length < 1 &&
No Annotations Found
} + {annotations.length < 1 && ( +
+ No annotations found +
+ )} `${item.id}`} />
diff --git a/public/app/plugins/panel/annolist/AnnotationListItem.tsx b/public/app/plugins/panel/annolist/AnnotationListItem.tsx index 4731081b03a..ecf22f9f597 100644 --- a/public/app/plugins/panel/annolist/AnnotationListItem.tsx +++ b/public/app/plugins/panel/annolist/AnnotationListItem.tsx @@ -2,6 +2,7 @@ import { css } from '@emotion/css'; import { MouseEvent } from 'react'; import { AnnotationEvent, DateTimeInput, GrafanaTheme2, PanelProps } from '@grafana/data'; +import { Trans } from '@grafana/i18n'; import { Card, TagList, Tooltip, RenderUserContentAsHTML, useStyles2 } from '@grafana/ui'; import { Options } from './panelcfg.gen'; @@ -79,8 +80,10 @@ const Avatar = ({ onClick, avatarUrl, login, email }: AvatarProps) => { }; const tooltipContent = ( - Created by: -
{email} + + Created by: +
{{ email }} +
); diff --git a/public/app/plugins/panel/barchart/TickSpacingEditor.tsx b/public/app/plugins/panel/barchart/TickSpacingEditor.tsx index 123e058e956..57a811d864f 100644 --- a/public/app/plugins/panel/barchart/TickSpacingEditor.tsx +++ b/public/app/plugins/panel/barchart/TickSpacingEditor.tsx @@ -1,4 +1,5 @@ import { SelectableValue, StandardEditorProps } from '@grafana/data'; +import { useTranslate } from '@grafana/i18n'; import { Checkbox, HorizontalGroup, RadioButtonGroup, Tooltip } from '@grafana/ui'; const GAPS_OPTIONS: Array> = [ @@ -25,6 +26,7 @@ const GAPS_OPTIONS: Array> = [ ]; export const TickSpacingEditor = (props: StandardEditorProps) => { + const { t } = useTranslate(); let value = props.value ?? 0; const isRTL = value < 0; if (isRTL) { @@ -50,9 +52,15 @@ export const TickSpacingEditor = (props: StandardEditorProps) => { {value !== 0 && ( - +
- +
)} diff --git a/public/app/plugins/panel/canvas/components/CanvasContextMenu.tsx b/public/app/plugins/panel/canvas/components/CanvasContextMenu.tsx index ea0dffe4c2a..bc37fed0d8f 100644 --- a/public/app/plugins/panel/canvas/components/CanvasContextMenu.tsx +++ b/public/app/plugins/panel/canvas/components/CanvasContextMenu.tsx @@ -4,6 +4,7 @@ import * as React from 'react'; import { first } from 'rxjs/operators'; import { SelectableValue } from '@grafana/data'; +import { useTranslate } from '@grafana/i18n'; import { ContextMenu, MenuItem, MenuItemProps } from '@grafana/ui'; import { ElementState } from 'app/features/canvas/runtime/element'; import { FrameState } from 'app/features/canvas/runtime/frame'; @@ -21,6 +22,7 @@ type Props = { }; export const CanvasContextMenu = ({ scene, panel, onVisibilityChange }: Props) => { + const { t } = useTranslate(); const inlineEditorOpen = panel.state.openInlineEdit; const [isMenuVisible, setIsMenuVisible] = useState(false); const [anchorPoint, setAnchorPoint] = useState({ x: 0, y: 0 }); @@ -76,7 +78,11 @@ export const CanvasContextMenu = ({ scene, panel, onVisibilityChange }: Props) = // This is disabled when panel is in edit mode because opening inline editor over panel editor is not ideal UX const openCloseEditorMenuItem = !scene.isPanelEditing && ( { if (scene.inlineEditingCallback) { if (inlineEditorOpen) { @@ -102,7 +108,11 @@ export const CanvasContextMenu = ({ scene, panel, onVisibilityChange }: Props) = return ( element && element.item.hasEditMode && ( - + ) ); } @@ -144,7 +154,7 @@ export const CanvasContextMenu = ({ scene, panel, onVisibilityChange }: Props) = const addItemMenuItem = ( { if (scene.setBackgroundCallback) { scene.setBackgroundCallback(anchorPoint); @@ -169,7 +182,7 @@ export const CanvasContextMenu = ({ scene, panel, onVisibilityChange }: Props) = <> {editElementMenuItem()} { contextMenuAction(LayerActionID.Delete); closeContextMenu(); @@ -177,7 +190,7 @@ export const CanvasContextMenu = ({ scene, panel, onVisibilityChange }: Props) = className={styles.menuItem} /> { contextMenuAction(LayerActionID.Duplicate); closeContextMenu(); @@ -185,7 +198,7 @@ export const CanvasContextMenu = ({ scene, panel, onVisibilityChange }: Props) = className={styles.menuItem} /> { contextMenuAction(LayerActionID.MoveTop); closeContextMenu(); @@ -193,7 +206,7 @@ export const CanvasContextMenu = ({ scene, panel, onVisibilityChange }: Props) = className={styles.menuItem} /> { contextMenuAction(LayerActionID.MoveBottom); closeContextMenu(); diff --git a/public/app/plugins/panel/canvas/editor/LineStyleEditor.tsx b/public/app/plugins/panel/canvas/editor/LineStyleEditor.tsx index 58aac8c148a..e76eb7b9680 100644 --- a/public/app/plugins/panel/canvas/editor/LineStyleEditor.tsx +++ b/public/app/plugins/panel/canvas/editor/LineStyleEditor.tsx @@ -1,6 +1,7 @@ import { useCallback } from 'react'; import { SelectableValue, StandardEditorProps } from '@grafana/data'; +import { useTranslate } from '@grafana/i18n'; import { Field, RadioButtonGroup, Switch } from '@grafana/ui'; import { LineStyle } from '../types'; @@ -24,6 +25,7 @@ export const defaultLineStyleConfig: LineStyleConfig = { }; export const LineStyleEditor = ({ value, onChange }: Props) => { + const { t } = useTranslate(); if (!value) { value = defaultLineStyleConfig; } else if (typeof value !== 'object') { @@ -53,7 +55,7 @@ export const LineStyleEditor = ({ value, onChange }: Props) => { {value.style !== LineStyle.Solid && ( <>
- + onAnimateChange(e.currentTarget.checked)} /> diff --git a/public/app/plugins/panel/canvas/editor/element/APIEditor.tsx b/public/app/plugins/panel/canvas/editor/element/APIEditor.tsx index 2aaba7bf09f..fc7f2ec2f11 100644 --- a/public/app/plugins/panel/canvas/editor/element/APIEditor.tsx +++ b/public/app/plugins/panel/canvas/editor/element/APIEditor.tsx @@ -6,6 +6,7 @@ import { StringFieldConfigSettings, SelectableValue, } from '@grafana/data'; +import { useTranslate, Trans } from '@grafana/i18n'; import { Button, Field, InlineField, InlineFieldRow, JSONFormatter, RadioButtonGroup, Select } from '@grafana/ui'; import { StringValueEditor } from 'app/core/components/OptionsUI/string'; import { defaultApiConfig } from 'app/features/canvas/elements/button'; @@ -50,6 +51,7 @@ const contentTypeOptions: SelectableValue[] = [ ]; export function APIEditor({ value, context, onChange }: Props) { + const { t } = useTranslate(); const LABEL_WIDTH = 13; if (!value) { @@ -136,8 +138,11 @@ export function APIEditor({ value, context, onChange }: Props) { const renderTestAPIButton = (api: APIEditorConfig) => { if (api && api.endpoint) { return ( - ); } @@ -148,7 +153,7 @@ export function APIEditor({ value, context, onChange }: Props) { return ( <> - + - + {value?.method !== HttpRequestMethod.GET && ( - + diff --git a/public/app/plugins/panel/canvas/editor/element/ParamsEditor.tsx b/public/app/plugins/panel/canvas/editor/element/ParamsEditor.tsx index c23df5f2348..62864a96326 100644 --- a/public/app/plugins/panel/canvas/editor/element/ParamsEditor.tsx +++ b/public/app/plugins/panel/canvas/editor/element/ParamsEditor.tsx @@ -1,6 +1,7 @@ import { useState } from 'react'; import * as React from 'react'; +import { useTranslate } from '@grafana/i18n'; import { IconButton, Input, Stack } from '@grafana/ui'; interface Props { @@ -9,6 +10,7 @@ interface Props { } export const ParamsEditor = ({ value, onChange }: Props) => { + const { t } = useTranslate(); const [paramName, setParamName] = useState(''); const [paramValue, setParamValue] = useState(''); @@ -46,16 +48,33 @@ export const ParamsEditor = ({ value, onChange }: Props) => { return (
- - - + + + {Array.from(value || []).map((entry) => ( - + ))} diff --git a/public/app/plugins/panel/canvas/editor/element/PlacementEditor.tsx b/public/app/plugins/panel/canvas/editor/element/PlacementEditor.tsx index 9baee2d1d31..a207b1a1f92 100644 --- a/public/app/plugins/panel/canvas/editor/element/PlacementEditor.tsx +++ b/public/app/plugins/panel/canvas/editor/element/PlacementEditor.tsx @@ -2,6 +2,7 @@ import { useObservable } from 'react-use'; import { Subject } from 'rxjs'; import { SelectableValue, StandardEditorProps } from '@grafana/data'; +import { Trans, useTranslate } from '@grafana/i18n'; import { Field, Icon, InlineField, InlineFieldRow, Select, Stack } from '@grafana/ui'; import { NumberInput } from 'app/core/components/OptionsUI/NumberInput'; @@ -32,13 +33,18 @@ const verticalOptions: Array> = [ type Props = StandardEditorProps; export function PlacementEditor({ item }: Props) { + const { t } = useTranslate(); const settings = item.settings; // Will force a rerender whenever the subject changes useObservable(settings?.scene ? settings.scene.moved : new Subject()); if (!settings) { - return
Loading...
; + return ( +
+ Loading... +
+ ); } const element = settings.element; @@ -95,7 +101,7 @@ export function PlacementEditor({ item }: Props) {

- + - + <> {places.map((p) => { const v = placement![p]; diff --git a/public/app/plugins/panel/canvas/editor/element/QuickPositioning.tsx b/public/app/plugins/panel/canvas/editor/element/QuickPositioning.tsx index c63a14aabc6..b8d8da31e09 100644 --- a/public/app/plugins/panel/canvas/editor/element/QuickPositioning.tsx +++ b/public/app/plugins/panel/canvas/editor/element/QuickPositioning.tsx @@ -1,6 +1,7 @@ import { css } from '@emotion/css'; import { GrafanaTheme2 } from '@grafana/data'; +import { useTranslate } from '@grafana/i18n'; import { IconButton, useStyles2 } from '@grafana/ui'; import { ElementState } from 'app/features/canvas/runtime/element'; import { QuickPlacement } from 'app/features/canvas/types'; @@ -16,6 +17,7 @@ type Props = { }; export const QuickPositioning = ({ onPositionChange, element, settings }: Props) => { + const { t } = useTranslate(); const styles = useStyles2(getStyles); const onQuickPositioningChange = (position: QuickPlacement) => { @@ -70,41 +72,41 @@ export const QuickPositioning = ({ onPositionChange, element, settings }: Props) onClick={() => onQuickPositioningChange(QuickPlacement.Left)} className={styles.button} size="lg" - tooltip="Align left" + tooltip={t('canvas.quick-positioning.tooltip-align-left', 'Align left')} /> onQuickPositioningChange(QuickPlacement.HorizontalCenter)} className={styles.button} size="lg" - tooltip="Align horizontal centers" + tooltip={t('canvas.quick-positioning.tooltip-align-horizontal-centers', 'Align horizontal centers')} /> onQuickPositioningChange(QuickPlacement.Right)} className={styles.button} size="lg" - tooltip="Align right" + tooltip={t('canvas.quick-positioning.tooltip-align-right', 'Align right')} /> onQuickPositioningChange(QuickPlacement.Top)} size="lg" - tooltip="Align top" + tooltip={t('canvas.quick-positioning.tooltip-align-top', 'Align top')} /> onQuickPositioningChange(QuickPlacement.VerticalCenter)} className={styles.button} size="lg" - tooltip="Align vertical centers" + tooltip={t('canvas.quick-positioning.tooltip-align-vertical-centers', 'Align vertical centers')} /> onQuickPositioningChange(QuickPlacement.Bottom)} className={styles.button} size="lg" - tooltip="Align bottom" + tooltip={t('canvas.quick-positioning.tooltip-align-bottom', 'Align bottom')} />
); diff --git a/public/app/plugins/panel/canvas/editor/inline/InlineEdit.tsx b/public/app/plugins/panel/canvas/editor/inline/InlineEdit.tsx index 49ff4fe511b..05ec36f2a0c 100644 --- a/public/app/plugins/panel/canvas/editor/inline/InlineEdit.tsx +++ b/public/app/plugins/panel/canvas/editor/inline/InlineEdit.tsx @@ -4,6 +4,7 @@ import Draggable, { DraggableEventHandler } from 'react-draggable'; import { Resizable, ResizeCallbackData } from 'react-resizable'; import { Dimensions2D, GrafanaTheme2 } from '@grafana/data'; +import { Trans, useTranslate } from '@grafana/i18n'; import { IconButton, Portal, useStyles2 } from '@grafana/ui'; import store from 'app/core/store'; import { Scene } from 'app/features/canvas/runtime/scene'; @@ -20,6 +21,7 @@ const OFFSET_X = 10; const OFFSET_Y = 32; export function InlineEdit({ onClose, id, scene }: Props) { + const { t } = useTranslate(); const root = scene.root.div?.getBoundingClientRect(); const windowHeight = window.innerHeight; const windowWidth = window.innerWidth; @@ -83,13 +85,15 @@ export function InlineEdit({ onClose, id, scene }: Props) { >
-
Canvas Inline Editor
+
+ Canvas Inline Editor +
diff --git a/public/app/plugins/panel/canvas/editor/inline/InlineEditBody.tsx b/public/app/plugins/panel/canvas/editor/inline/InlineEditBody.tsx index 8c6a2764035..2ca542b5852 100644 --- a/public/app/plugins/panel/canvas/editor/inline/InlineEditBody.tsx +++ b/public/app/plugins/panel/canvas/editor/inline/InlineEditBody.tsx @@ -5,6 +5,7 @@ import { useObservable } from 'react-use'; import { DataFrame, GrafanaTheme2, PanelOptionsEditorBuilder, StandardEditorContext } from '@grafana/data'; import { NestedValueAccess, PanelOptionsSupplier } from '@grafana/data/internal'; +import { useTranslate, Trans } from '@grafana/i18n'; import { useStyles2 } from '@grafana/ui'; import { AddLayerButton } from 'app/core/components/Layers/AddLayerButton'; import { FrameState } from 'app/features/canvas/runtime/frame'; @@ -25,6 +26,7 @@ import { getLayerEditor } from '../layer/layerEditor'; import { TabsEditor } from './TabsEditor'; export function InlineEditBody() { + const { t } = useTranslate(); const activePanel = useObservable(activePanelSubject); const instanceState = activePanel?.panel.context?.instanceState; const styles = useStyles2(getStyles); @@ -103,12 +105,20 @@ export function InlineEditBody() { <>
{pane.items.map((item) => item.render())}
- onAddItem(sel, rootLayer)} options={typeOptions} label={'Add item'} /> + onAddItem(sel, rootLayer)} + options={typeOptions} + label={t('canvas.inline-edit-body.label-add-item', 'Add item')} + />
{pane.categories.map((p) => renderOptionsPaneCategoryDescriptor(p))} - {noElementSelected &&
Please select an element
} + {noElementSelected && ( +
+ Please select an element +
+ )}
); diff --git a/public/app/plugins/panel/canvas/editor/layer/TreeNavigationEditor.tsx b/public/app/plugins/panel/canvas/editor/layer/TreeNavigationEditor.tsx index b78c1ab9fe6..bc66fc46de5 100644 --- a/public/app/plugins/panel/canvas/editor/layer/TreeNavigationEditor.tsx +++ b/public/app/plugins/panel/canvas/editor/layer/TreeNavigationEditor.tsx @@ -4,6 +4,7 @@ import Tree, { TreeNodeProps } from 'rc-tree'; import { Key, useEffect, useMemo, useState } from 'react'; import { GrafanaTheme2, StandardEditorProps } from '@grafana/data'; +import { Trans, useTranslate } from '@grafana/i18n'; import { config } from '@grafana/runtime'; import { Button, Icon, Stack, useStyles2, useTheme2 } from '@grafana/ui'; import { AddLayerButton } from 'app/core/components/Layers/AddLayerButton'; @@ -22,6 +23,7 @@ import { getTreeData, onNodeDrop, TreeElement } from './tree'; let allowSelection = true; export const TreeNavigationEditor = ({ item }: StandardEditorProps) => { + const { t } = useTranslate(); const [treeData, setTreeData] = useState(getTreeData(item?.settings?.scene.root)); const [autoExpandParent, setAutoExpandParent] = useState(true); const [expandedKeys, setExpandedKeys] = useState([]); @@ -50,12 +52,20 @@ export const TreeNavigationEditor = ({ item }: StandardEditorPropsNo settings
; + return ( +
+ No settings +
+ ); } const layer = settings.layer; if (!layer) { - return
Missing layer?
; + return ( +
+ Missing layer? +
+ ); } const onSelect = (selectedKeys: Key[], info: { node: { dataRef: ElementState } }) => { @@ -95,7 +105,7 @@ export const TreeNavigationEditor = ({ item }: StandardEditorProps
- onAddItem(sel, layer)} options={typeOptions} label={'Add item'} /> + onAddItem(sel, layer)} + options={typeOptions} + label={t('canvas.tree-navigation-editor.label-add-item', 'Add item')} + />
{selection.length > 0 && ( )} {selection.length > 1 && config.featureToggles.canvasPanelNesting && ( )} diff --git a/public/app/plugins/panel/canvas/editor/layer/TreeNodeTitle.tsx b/public/app/plugins/panel/canvas/editor/layer/TreeNodeTitle.tsx index 4995f960fcc..534836a52aa 100644 --- a/public/app/plugins/panel/canvas/editor/layer/TreeNodeTitle.tsx +++ b/public/app/plugins/panel/canvas/editor/layer/TreeNodeTitle.tsx @@ -1,6 +1,7 @@ import { css } from '@emotion/css'; import { GrafanaTheme2 } from '@grafana/data'; +import { useTranslate } from '@grafana/i18n'; import { IconButton, useStyles2 } from '@grafana/ui'; import { LayerName } from 'app/core/components/Layers/LayerName'; import { ElementState } from 'app/features/canvas/runtime/element'; @@ -17,6 +18,7 @@ interface Props { } export const TreeNodeTitle = ({ settings, nodeData, setAllowSelection }: Props) => { + const { t } = useTranslate(); const element = nodeData.dataRef; const name = nodeData.dataRef.getName(); @@ -72,17 +74,17 @@ export const TreeNodeTitle = ({ settings, nodeData, setAllowSelection }: Props)
onDuplicate(element)} - tooltip="Duplicate" + tooltip={t('canvas.tree-node-title.tooltip-duplicate', 'Duplicate')} /> onDelete(element)} - tooltip="Remove" + tooltip={t('canvas.tree-node-title.tooltip-remove', 'Remove')} />
)} diff --git a/public/app/plugins/panel/canvas/editor/panZoomHelp.tsx b/public/app/plugins/panel/canvas/editor/panZoomHelp.tsx index a6e22d1d4e4..fc5be5ff1b7 100644 --- a/public/app/plugins/panel/canvas/editor/panZoomHelp.tsx +++ b/public/app/plugins/panel/canvas/editor/panZoomHelp.tsx @@ -1,18 +1,20 @@ import { css } from '@emotion/css'; import { StandardEditorProps, GrafanaTheme2 } from '@grafana/data'; +import { useTranslate, Trans } from '@grafana/i18n'; import { Alert, Icon, Stack, useStyles2 } from '@grafana/ui'; const helpUrl = 'https://grafana.com/docs/grafana/latest/panels-visualizations/visualizations/canvas/'; export const PanZoomHelp = ({}: StandardEditorProps) => { + const { t } = useTranslate(); const styles = useStyles2(getStyles); return ( <> } className={styles.alert} @@ -26,14 +28,22 @@ export const PanZoomHelp = ({}: StandardEditorProps
  • - Pan: + Pan:
      -
    • Middle mouse
    • -
    • CTRL + right mouse
    • +
    • + Middle mouse +
    • +
    • + CTRL + right mouse +
  • -
  • Zoom: Scroll wheel
  • -
  • Reset: Double click
  • +
  • + Zoom: Scroll wheel +
  • +
  • + Reset: Double click +
diff --git a/public/app/plugins/panel/datagrid/components/AddColumn.tsx b/public/app/plugins/panel/datagrid/components/AddColumn.tsx index 96353fc430e..f4e6deaa6df 100644 --- a/public/app/plugins/panel/datagrid/components/AddColumn.tsx +++ b/public/app/plugins/panel/datagrid/components/AddColumn.tsx @@ -1,6 +1,8 @@ import { useState } from 'react'; import * as React from 'react'; +import { useTranslate } from '@grafana/i18n'; + import { SimpleInput } from './SimpleInput'; interface AddColumnProps { @@ -9,6 +11,7 @@ interface AddColumnProps { } export const AddColumn = ({ divStyle, onColumnInputBlur }: AddColumnProps) => { + const { t } = useTranslate(); const [showInput, setShowInput] = useState(false); const setupColumnInput = () => { @@ -27,7 +30,7 @@ export const AddColumn = ({ divStyle, onColumnInputBlur }: AddColumnProps) => { return (
{showInput ? ( - + ) : ( )} diff --git a/public/app/plugins/panel/datagrid/components/DatagridContextMenu.tsx b/public/app/plugins/panel/datagrid/components/DatagridContextMenu.tsx index 1e06330c88d..1db654bbc0b 100644 --- a/public/app/plugins/panel/datagrid/components/DatagridContextMenu.tsx +++ b/public/app/plugins/panel/datagrid/components/DatagridContextMenu.tsx @@ -4,6 +4,7 @@ import * as React from 'react'; import { DataFrame, FieldType } from '@grafana/data'; import { convertFieldType } from '@grafana/data/internal'; +import { useTranslate } from '@grafana/i18n'; import { reportInteraction } from '@grafana/runtime'; import { ContextMenu, MenuGroup, MenuItem } from '@grafana/ui'; import { MenuDivider } from '@grafana/ui/internal'; @@ -39,6 +40,7 @@ export const DatagridContextMenu = ({ columnFreezeIndex, renameColumnClicked, }: ContextMenuProps) => { + const { t } = useTranslate(); let selectedRows: number[] = []; let selectedColumns: number[] = []; const { row, column, x, y, isHeaderMenu } = menuData; @@ -118,7 +120,7 @@ export const DatagridContextMenu = ({ {showDeleteColumn || showDeleteRow ? : null} {showClearRow ? ( { reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.CONTEXT_MENU_ACTION, @@ -130,7 +132,7 @@ export const DatagridContextMenu = ({ ) : null} {showClearColumn ? ( { const field = data.fields[column]; field.values = field.values.map(() => null); @@ -146,7 +148,7 @@ export const DatagridContextMenu = ({ ) : null} {showClearRow || showClearColumn ? : null} { reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.CONTEXT_MENU_ACTION, @@ -156,7 +158,7 @@ export const DatagridContextMenu = ({ }} /> { reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.CONTEXT_MENU_ACTION, @@ -216,7 +218,9 @@ export const DatagridContextMenu = ({ return ( <> {fieldTypeConversionData.length ? ( - + {fieldTypeConversionData.map((conversionData, index) => ( - + { reportInteraction(INTERACTION_EVENT_NAME, { item: INTERACTION_ITEM.HEADER_MENU_ACTION, @@ -278,7 +285,7 @@ export const DatagridContextMenu = ({ }} /> { const field = data.fields[column]; field.values = field.values.map(() => null); diff --git a/public/app/plugins/panel/debug/CursorView.tsx b/public/app/plugins/panel/debug/CursorView.tsx index 92e2c429d3a..43ea8b39835 100644 --- a/public/app/plugins/panel/debug/CursorView.tsx +++ b/public/app/plugins/panel/debug/CursorView.tsx @@ -9,6 +9,7 @@ import { DataHoverClearEvent, BusEventBase, } from '@grafana/data'; +import { Trans } from '@grafana/i18n'; import { CustomScrollbar } from '@grafana/ui'; import { DataHoverView } from 'app/features/visualization/data-hover/DataHoverView'; @@ -58,13 +59,19 @@ export class CursorView extends Component { render() { const { event } = this.state; if (!event) { - return
no events yet
; + return ( +
+ No events yet +
+ ); } const { type, payload, origin } = event; return ( -

Origin: {(origin as any)?.path}

- Type: {type} + {/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */} +

event.origin: {(origin as any)?.path}

+ {/* eslint-disable-next-line @grafana/i18n/no-untranslated-strings */} + event.type: {type} {Boolean(payload) && ( <>
{JSON.stringify(payload.point, null, '  ')}
diff --git a/public/app/plugins/panel/debug/EventBusLogger.tsx b/public/app/plugins/panel/debug/EventBusLogger.tsx index 60db004e48a..472b451215c 100644 --- a/public/app/plugins/panel/debug/EventBusLogger.tsx +++ b/public/app/plugins/panel/debug/EventBusLogger.tsx @@ -67,6 +67,7 @@ export class EventBusLoggerPanel extends PureComponent { return ( {this.history.map((v, idx) => ( + // eslint-disable-next-line @grafana/i18n/no-untranslated-strings
{JSON.stringify(v.path)} {v.type} / X:{JSON.stringify(v.payload.x)} / Y:{JSON.stringify(v.payload.y)}
diff --git a/public/app/plugins/panel/debug/RenderInfoViewer.tsx b/public/app/plugins/panel/debug/RenderInfoViewer.tsx index 663a7dd7c98..f4d8783a0b1 100644 --- a/public/app/plugins/panel/debug/RenderInfoViewer.tsx +++ b/public/app/plugins/panel/debug/RenderInfoViewer.tsx @@ -9,6 +9,8 @@ import { PanelProps, ReducerID, } from '@grafana/data'; +import { Trans } from '@grafana/i18n'; +import { t } from '@grafana/i18n/internal'; import { IconButton } from '@grafana/ui'; import { Options, UpdateConfig } from './panelcfg.gen'; @@ -74,12 +76,43 @@ export class RenderInfoViewer extends Component { return (
- + - {showCounters.render && Render: {this.counters.render} } - {showCounters.dataChanged && Data: {this.counters.dataChanged} } - {showCounters.schemaChanged && Schema: {this.counters.schemaChanged} } - TIME: {elapsed}ms + {showCounters.render && ( + + + Render: {'{{numRenders}}'}  + + + )} + {showCounters.dataChanged && ( + + + Data: {'{{numDataChanges}}'}  + + + )} + {showCounters.schemaChanged && ( + + + Schema: {'{{numSchemaChanges}}'}  + + + )} + + Time: {{ elapsed }}ms +
@@ -92,9 +125,15 @@ export class RenderInfoViewer extends Component { - - - + + + diff --git a/public/app/plugins/panel/debug/StateView.tsx b/public/app/plugins/panel/debug/StateView.tsx index 1b7309d00fe..e7151a4712f 100644 --- a/public/app/plugins/panel/debug/StateView.tsx +++ b/public/app/plugins/panel/debug/StateView.tsx @@ -1,11 +1,13 @@ import { FormEvent } from 'react'; import { PanelOptionsEditorProps, PanelProps } from '@grafana/data'; +import { Trans, useTranslate } from '@grafana/i18n'; import { Field, Input, usePanelContext } from '@grafana/ui'; import { Options } from './panelcfg.gen'; export function StateView(props: PanelProps) { + const { t } = useTranslate(); const context = usePanelContext(); const onChangeName = (e: FormEvent) => { @@ -16,7 +18,7 @@ export function StateView(props: PanelProps) { return ( <> - + @@ -24,5 +26,11 @@ export function StateView(props: PanelProps) { } export function StateViewEditor({ value, context, onChange, item }: PanelOptionsEditorProps) { - return
Current value: {context.instanceState?.name}
; + return ( +
+ + Current value: {'{{currentValue}}'}{' '} + +
+ ); } diff --git a/public/app/plugins/panel/geomap/GeomapPanel.tsx b/public/app/plugins/panel/geomap/GeomapPanel.tsx index 7f034756160..2b4fc9d021b 100644 --- a/public/app/plugins/panel/geomap/GeomapPanel.tsx +++ b/public/app/plugins/panel/geomap/GeomapPanel.tsx @@ -13,6 +13,7 @@ import * as React from 'react'; import { Subscription } from 'rxjs'; import { DataHoverEvent, PanelData, PanelProps } from '@grafana/data'; +import { t } from '@grafana/i18n/internal'; import { config } from '@grafana/runtime'; import { PanelContext, PanelContextRoot } from '@grafana/ui'; import { appEvents } from 'app/core/app_events'; @@ -423,7 +424,7 @@ export class GeomapPanel extends Component { className={styles.map} // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex tabIndex={0} // Interactivity is added through the ref - aria-label={`Navigable map`} + aria-label={t('geomap.geomap-panel.aria-label-map', 'Navigable map')} ref={this.initMapRef} > {
FieldTypeLast + Field + + Type + + Last +
- + - + diff --git a/public/app/plugins/panel/geomap/components/MarkersLegend.tsx b/public/app/plugins/panel/geomap/components/MarkersLegend.tsx index 34eda649940..df4e83cc800 100644 --- a/public/app/plugins/panel/geomap/components/MarkersLegend.tsx +++ b/public/app/plugins/panel/geomap/components/MarkersLegend.tsx @@ -11,6 +11,7 @@ import { getFieldColorModeForField, GrafanaTheme2, } from '@grafana/data'; +import { useTranslate } from '@grafana/i18n'; import { useStyles2, VizLegendItem } from '@grafana/ui'; import { ColorScale } from 'app/core/components/ColorScale/ColorScale'; import { SanitizedSVG } from 'app/core/components/SVG/SanitizedSVG'; @@ -29,6 +30,7 @@ export interface MarkersLegendProps { } export function MarkersLegend(props: MarkersLegendProps) { + const { t } = useTranslate(); const { layerName, styleConfig, layer } = props; const style = useStyles2(getStyles); @@ -66,7 +68,7 @@ export function MarkersLegend(props: MarkersLegendProps) { diff --git a/public/app/plugins/panel/geomap/components/MeasureOverlay.tsx b/public/app/plugins/panel/geomap/components/MeasureOverlay.tsx index 2502a4786ef..0d775fdbf42 100644 --- a/public/app/plugins/panel/geomap/components/MeasureOverlay.tsx +++ b/public/app/plugins/panel/geomap/components/MeasureOverlay.tsx @@ -3,6 +3,8 @@ import Map from 'ol/Map'; import { useMemo, useRef, useState } from 'react'; import { GrafanaTheme2, SelectableValue } from '@grafana/data'; +import { selectors } from '@grafana/e2e-selectors'; +import { useTranslate } from '@grafana/i18n'; import { Button, IconButton, RadioButtonGroup, Select } from '@grafana/ui'; import { config } from 'app/core/config'; @@ -16,6 +18,7 @@ type Props = { }; export const MeasureOverlay = ({ map, menuActiveState }: Props) => { + const { t } = useTranslate(); const vector = useRef(new MeasureVectorLayer()); const measureStyle = getStyles(config.theme2); @@ -99,8 +102,9 @@ export const MeasureOverlay = ({ map, menuActiveState }: Props) => { ) : ( diff --git a/public/app/plugins/panel/geomap/editor/CoordinatesMapViewEditor.tsx b/public/app/plugins/panel/geomap/editor/CoordinatesMapViewEditor.tsx index 0774d472a9f..d62a3e6ea0e 100644 --- a/public/app/plugins/panel/geomap/editor/CoordinatesMapViewEditor.tsx +++ b/public/app/plugins/panel/geomap/editor/CoordinatesMapViewEditor.tsx @@ -1,3 +1,4 @@ +import { useTranslate } from '@grafana/i18n'; import { InlineFieldRow, InlineField } from '@grafana/ui'; import { NumberInput } from 'app/core/components/OptionsUI/NumberInput'; @@ -10,6 +11,7 @@ type Props = { }; export const CoordinatesMapViewEditor = ({ labelWidth, value, onChange }: Props) => { + const { t } = useTranslate(); const onLatitudeChange = (latitude: number | undefined) => { onChange({ ...value, lat: latitude }); }; @@ -21,12 +23,20 @@ export const CoordinatesMapViewEditor = ({ labelWidth, value, onChange }: Props) return ( <> - + - + diff --git a/public/app/plugins/panel/geomap/editor/FitMapViewEditor.tsx b/public/app/plugins/panel/geomap/editor/FitMapViewEditor.tsx index d0a05b262af..355ba2dcf79 100644 --- a/public/app/plugins/panel/geomap/editor/FitMapViewEditor.tsx +++ b/public/app/plugins/panel/geomap/editor/FitMapViewEditor.tsx @@ -1,6 +1,7 @@ import { useCallback, useMemo } from 'react'; import { SelectableValue, StandardEditorContext } from '@grafana/data'; +import { useTranslate } from '@grafana/i18n'; import { InlineFieldRow, InlineField, RadioButtonGroup, Select } from '@grafana/ui'; import { NumberInput } from 'app/core/components/OptionsUI/NumberInput'; @@ -33,6 +34,7 @@ const DataScopeOptions: Array> = ScopeOptions.m })); export const FitMapViewEditor = ({ labelWidth, value, onChange, context }: Props) => { + const { t } = useTranslate(); const layers = useMemo(() => { if (context.options?.layers) { return context.options.layers.map((layer) => ({ @@ -53,7 +55,11 @@ export const FitMapViewEditor = ({ labelWidth, value, onChange, context }: Props const allLayersEditorFragment = ( - + @@ -77,7 +79,15 @@ export const MapViewEditor = ({ )} - + diff --git a/public/app/plugins/panel/geomap/editor/StyleEditor.tsx b/public/app/plugins/panel/geomap/editor/StyleEditor.tsx index 5ac29dfe977..0e0042b256d 100644 --- a/public/app/plugins/panel/geomap/editor/StyleEditor.tsx +++ b/public/app/plugins/panel/geomap/editor/StyleEditor.tsx @@ -4,6 +4,7 @@ import { useObservable } from 'react-use'; import { Observable, of } from 'rxjs'; import { FieldConfigPropertyItem, StandardEditorProps, StandardEditorsRegistryItem, FrameMatcher } from '@grafana/data'; +import { useTranslate } from '@grafana/i18n'; import { ScaleDimensionConfig, ResourceDimensionConfig, @@ -54,6 +55,7 @@ export interface StyleEditorOptions { type Props = StandardEditorProps; export const StyleEditor = (props: Props) => { + const { t } = useTranslate(); const { value, onChange, item } = props; const context = useMemo(() => { if (!item.settings?.frameMatcher) { @@ -129,7 +131,7 @@ export const StyleEditor = (props: Props) => { {featuresHavePoints && ( <> - + { /> - + { )} - + { - + { return ( <> - + { {!settings?.hideSymbol && ( <> - + { } /> - + { ]} /> - + { )} - + { item={{} as StandardEditorsRegistryItem} /> - + { /> {settings?.displayRotation && ( - + { /> )} - + { {hasTextLabel && ( <> - + { item={{} as FieldConfigPropertyItem} /> - + { item={{} as FieldConfigPropertyItem} /> - + { /> - + { ]} /> - + ; export const StyleRuleEditor = ({ value, onChange, item, context }: Props) => { + const { t } = useTranslate(); const settings = item.settings; if (!settings) { // Shouldn't be possible to hit this block, but just in case @@ -132,13 +134,13 @@ export const StyleRuleEditor = ({ value, onChange, item, context }: Props) => { return (
- + @@ -169,7 +171,7 @@ export const StyleRuleEditor = ({ value, onChange, item, context }: Props) => { )} @@ -180,7 +182,7 @@ export const StyleRuleEditor = ({ value, onChange, item, context }: Props) => { icon="trash-alt" onClick={() => onDelete()} variant="secondary" - aria-label={'Delete style rule'} + aria-label={t('geomap.style-rule-editor.aria-label-delete-style-rule', 'Delete style rule')} className={styles.button} > diff --git a/public/app/plugins/panel/geomap/module.tsx b/public/app/plugins/panel/geomap/module.tsx index 993fda575ba..b5376ea7acf 100644 --- a/public/app/plugins/panel/geomap/module.tsx +++ b/public/app/plugins/panel/geomap/module.tsx @@ -1,4 +1,5 @@ import { PanelPlugin } from '@grafana/data'; +import { Trans } from '@grafana/i18n'; import { config } from '@grafana/runtime'; import { commonOptionsBuilder } from '@grafana/ui'; @@ -72,7 +73,13 @@ export const plugin = new PanelPlugin(GeomapPanel) path: '', name: '', // eslint-disable-next-line react/display-name - editor: () =>
The basemap layer is configured by the server admin.
, + editor: () => ( +
+ + The basemap layer is configured by the server admin. + +
+ ), }); } else if (baselayer) { builder.addNestedOptions( diff --git a/public/app/plugins/panel/gettingstarted/GettingStarted.tsx b/public/app/plugins/panel/gettingstarted/GettingStarted.tsx index 33c27cc9e77..6a5a4f0d20b 100644 --- a/public/app/plugins/panel/gettingstarted/GettingStarted.tsx +++ b/public/app/plugins/panel/gettingstarted/GettingStarted.tsx @@ -3,6 +3,8 @@ import { css, cx } from '@emotion/css'; import { PureComponent } from 'react'; import { PanelProps } from '@grafana/data'; +import { Trans } from '@grafana/i18n'; +import { t } from '@grafana/i18n/internal'; import { config, reportInteraction } from '@grafana/runtime'; import { Button, Spinner, stylesFactory } from '@grafana/ui'; import { contextSrv } from 'app/core/core'; @@ -89,19 +91,23 @@ export class GettingStarted extends PureComponent {
{!checksDone ? (
-
Checking completed setup steps
+
+ + Checking completed setup steps + +
) : ( <> {currentStep === steps.length - 1 && (
@@ -34,7 +38,8 @@ export const DocsCard = ({ card }: Props) => { rel="noreferrer" onClick={() => reportInteraction('grafana_getting_started_docs', { title: card.title, link: card.learnHref })} > - Learn how in the docs + Learn how in the docs{' '} +
); diff --git a/public/app/plugins/panel/gettingstarted/components/TutorialCard.tsx b/public/app/plugins/panel/gettingstarted/components/TutorialCard.tsx index b58279d6c92..4c857ce0659 100644 --- a/public/app/plugins/panel/gettingstarted/components/TutorialCard.tsx +++ b/public/app/plugins/panel/gettingstarted/components/TutorialCard.tsx @@ -2,6 +2,7 @@ import { css } from '@emotion/css'; import { MouseEvent } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; +import { useTranslate } from '@grafana/i18n'; import { reportInteraction } from '@grafana/runtime'; import { useStyles2 } from '@grafana/ui'; import store from 'app/core/store'; @@ -15,6 +16,7 @@ interface Props { } export const TutorialCard = ({ card }: Props) => { + const { t } = useTranslate(); const styles = useStyles2(getStyles, card.done); return ( @@ -27,7 +29,9 @@ export const TutorialCard = ({ card }: Props) => { >
{card.type}
-
{card.done ? 'complete' : card.heading}
+
+ {card.done ? t('gettingstarted.tutorial-card.complete', 'complete') : card.heading} +

{card.title}

{card.info}
diff --git a/public/app/plugins/panel/histogram/HistogramPanel.tsx b/public/app/plugins/panel/histogram/HistogramPanel.tsx index 6ec723bd766..5e2e245997c 100644 --- a/public/app/plugins/panel/histogram/HistogramPanel.tsx +++ b/public/app/plugins/panel/histogram/HistogramPanel.tsx @@ -9,6 +9,7 @@ import { cacheFieldDisplayNames, getHistogramFields, } from '@grafana/data'; +import { Trans } from '@grafana/i18n'; import { TooltipDisplayMode, TooltipPlugin2, useTheme2 } from '@grafana/ui'; import { TooltipHoverMode } from '@grafana/ui/internal'; @@ -64,7 +65,11 @@ export const HistogramPanel = ({ data, options, width, height }: Props) => { if (!histogram || !histogram.fields.length) { return (
-

No histogram found in response

+

+ + No histogram found in response + +

); } diff --git a/public/app/plugins/panel/live/LiveChannelEditor.tsx b/public/app/plugins/panel/live/LiveChannelEditor.tsx index 3276992eb37..6a5fa79337d 100644 --- a/public/app/plugins/panel/live/LiveChannelEditor.tsx +++ b/public/app/plugins/panel/live/LiveChannelEditor.tsx @@ -9,6 +9,7 @@ import { GrafanaTheme2, parseLiveChannelAddress, } from '@grafana/data'; +import { useTranslate, Trans } from '@grafana/i18n'; import { Select, Alert, Label, stylesFactory, Combobox } from '@grafana/ui'; import { config } from 'app/core/config'; import { discoveryResources, getAPIGroupDiscoveryList, GroupDiscoveryResource } from 'app/features/apiserver/discovery'; @@ -27,6 +28,7 @@ const scopes: Array> = [ ]; export function LiveChannelEditor(props: Props) { + const { t } = useTranslate(); const [channels, setChannels] = useState>>([]); const [namespaces, paths] = useMemo(() => { const namespaces: Array> = []; @@ -110,14 +112,18 @@ export function LiveChannelEditor(props: Props) { return ( <> - - This supports real-time event streams in grafana core. This feature is under heavy development. Expect the - intefaces and structures to change as this becomes more production ready. + + + This supports real-time event streams in Grafana core. This feature is under heavy development. Expect the + interfaces and structures to change as this becomes more production ready. +
- + - + - + diff --git a/public/app/plugins/panel/table/table-new/cells/AutoCellOptionsEditor.tsx b/public/app/plugins/panel/table/table-new/cells/AutoCellOptionsEditor.tsx index d45bfeb2d50..09b34daa3d0 100644 --- a/public/app/plugins/panel/table/table-new/cells/AutoCellOptionsEditor.tsx +++ b/public/app/plugins/panel/table/table-new/cells/AutoCellOptionsEditor.tsx @@ -1,3 +1,4 @@ +import { useTranslate } from '@grafana/i18n'; import { TableAutoCellOptions, TableColorTextCellOptions } from '@grafana/schema'; import { Field, Switch } from '@grafana/ui'; @@ -8,13 +9,14 @@ export const AutoCellOptionsEditor = ({ onChange, }: TableCellEditorProps) => { // Handle row coloring changes + const { t } = useTranslate(); const onWrapTextChange = () => { cellOptions.wrapText = !cellOptions.wrapText; onChange(cellOptions); }; return ( - + ); diff --git a/public/app/plugins/panel/table/table-new/cells/BarGaugeCellOptionsEditor.tsx b/public/app/plugins/panel/table/table-new/cells/BarGaugeCellOptionsEditor.tsx index 57e6b9703ee..0600d3fd801 100644 --- a/public/app/plugins/panel/table/table-new/cells/BarGaugeCellOptionsEditor.tsx +++ b/public/app/plugins/panel/table/table-new/cells/BarGaugeCellOptionsEditor.tsx @@ -1,4 +1,5 @@ import { SelectableValue } from '@grafana/data'; +import { useTranslate } from '@grafana/i18n'; import { BarGaugeDisplayMode, BarGaugeValueMode, TableBarGaugeCellOptions } from '@grafana/schema'; import { Field, RadioButtonGroup, Stack } from '@grafana/ui'; @@ -8,6 +9,7 @@ type Props = TableCellEditorProps; export function BarGaugeCellOptionsEditor({ cellOptions, onChange }: Props) { // Set the display mode on change + const { t } = useTranslate(); const onCellOptionsChange = (v: BarGaugeDisplayMode) => { cellOptions.mode = v; onChange(cellOptions); @@ -20,14 +22,14 @@ export function BarGaugeCellOptionsEditor({ cellOptions, onChange }: Props) { return ( - + - + ) => { // Set the display mode on change + const { t } = useTranslate(); const onCellOptionsChange = (v: TableCellBackgroundDisplayMode) => { cellOptions.mode = v; onChange(cellOptions); @@ -31,7 +33,9 @@ export const ColorBackgroundCellOptionsEditor = ({ return ( <> - + - + diff --git a/public/app/plugins/panel/table/table-new/cells/ImageCellOptionsEditor.tsx b/public/app/plugins/panel/table/table-new/cells/ImageCellOptionsEditor.tsx index 51e711cd367..a9920b8f9c9 100644 --- a/public/app/plugins/panel/table/table-new/cells/ImageCellOptionsEditor.tsx +++ b/public/app/plugins/panel/table/table-new/cells/ImageCellOptionsEditor.tsx @@ -1,11 +1,13 @@ import { FormEvent } from 'react'; +import { useTranslate } from '@grafana/i18n'; import { TableImageCellOptions } from '@grafana/schema'; import { Field, Input } from '@grafana/ui'; import { TableCellEditorProps } from '../TableCellOptionEditor'; export const ImageCellOptionsEditor = ({ cellOptions, onChange }: TableCellEditorProps) => { + const { t } = useTranslate(); const onAltChange = (e: FormEvent) => { cellOptions.alt = e.currentTarget.value; onChange(cellOptions); @@ -19,13 +21,22 @@ export const ImageCellOptionsEditor = ({ cellOptions, onChange }: TableCellEdito return ( <> - + diff --git a/public/app/plugins/panel/timeseries/LineStyleEditor.tsx b/public/app/plugins/panel/timeseries/LineStyleEditor.tsx index f5f3d14bc5e..70b961f1bc3 100644 --- a/public/app/plugins/panel/timeseries/LineStyleEditor.tsx +++ b/public/app/plugins/panel/timeseries/LineStyleEditor.tsx @@ -1,6 +1,7 @@ import { useMemo } from 'react'; import { StandardEditorProps, SelectableValue } from '@grafana/data'; +import { useTranslate } from '@grafana/i18n'; import { LineStyle } from '@grafana/schema'; import { HorizontalGroup, IconButton, RadioButtonGroup, Select } from '@grafana/ui'; @@ -55,6 +56,7 @@ const dotOptions: Array> = [ type Props = StandardEditorProps; export const LineStyleEditor = ({ value, onChange }: Props) => { + const { t } = useTranslate(); const options = useMemo(() => (value?.fill === 'dash' ? dashOptions : dotOptions), [value]); const current = useMemo(() => { if (!value?.dash?.length) { @@ -108,12 +110,15 @@ export const LineStyleEditor = ({ value, onChange }: Props) => { diff --git a/public/app/plugins/panel/timeseries/NullsThresholdInput.tsx b/public/app/plugins/panel/timeseries/NullsThresholdInput.tsx index 3e83be1cb25..703cf43b939 100644 --- a/public/app/plugins/panel/timeseries/NullsThresholdInput.tsx +++ b/public/app/plugins/panel/timeseries/NullsThresholdInput.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { rangeUtil } from '@grafana/data'; +import { useTranslate } from '@grafana/i18n'; import { Input } from '@grafana/ui'; export enum InputPrefix { @@ -16,6 +17,7 @@ type Props = { }; export const NullsThresholdInput = ({ value, onChange, inputPrefix, isTime }: Props) => { + const { t } = useTranslate(); let defaultValue = rangeUtil.secondsToHms(value / 1000); if (!isTime) { defaultValue = '10'; @@ -57,7 +59,7 @@ export const NullsThresholdInput = ({ value, onChange, inputPrefix, isTime }: Pr return ( ; export const TimezonesEditor = ({ value, onChange }: Props) => { + const { t } = useTranslate(); const styles = useStyles2(getStyles); if (!value || value.length < 1) { @@ -43,9 +45,17 @@ export const TimezonesEditor = ({ value, onChange }: Props) => { value={tz ?? InternalTimeZones.default} /> {idx === value.length - 1 ? ( - + ) : ( - removeTimezone(idx)} tooltip="Remove timezone" /> + removeTimezone(idx)} + tooltip={t('timeseries.timezones-editor.tooltip-remove-timezone', 'Remove timezone')} + /> )} ))} diff --git a/public/app/plugins/panel/timeseries/plugins/OutsideRangePlugin.tsx b/public/app/plugins/panel/timeseries/plugins/OutsideRangePlugin.tsx index 5dea52b23f8..38d4a677bb4 100644 --- a/public/app/plugins/panel/timeseries/plugins/OutsideRangePlugin.tsx +++ b/public/app/plugins/panel/timeseries/plugins/OutsideRangePlugin.tsx @@ -2,6 +2,7 @@ import { useLayoutEffect, useRef, useState } from 'react'; import uPlot, { TypedArray, Scale } from 'uplot'; import { AbsoluteTimeRange } from '@grafana/data'; +import { Trans } from '@grafana/i18n'; import { UPlotConfigBuilder, Button } from '@grafana/ui'; interface ThresholdControlsPluginProps { @@ -70,13 +71,15 @@ export const OutsideRangePlugin = ({ config, onChangeTimeRange }: ThresholdContr }} >
-
Data outside time range
+
+ Data outside time range +
diff --git a/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationEditor2.tsx b/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationEditor2.tsx index b5b9b960e27..dccc6e2ed0c 100644 --- a/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationEditor2.tsx +++ b/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationEditor2.tsx @@ -4,6 +4,7 @@ import { Controller } from 'react-hook-form'; import { useAsyncFn, useClickAway } from 'react-use'; import { AnnotationEventUIModel, GrafanaTheme2, dateTimeFormat, systemDateFormats } from '@grafana/data'; +import { useTranslate, Trans } from '@grafana/i18n'; import { Button, Field, Stack, TextArea, usePanelContext, useStyles2 } from '@grafana/ui'; import { Form } from 'app/core/components/Form/Form'; import { TagFilter } from 'app/core/components/TagFilter/TagFilter'; @@ -22,6 +23,7 @@ interface AnnotationEditFormDTO { } export const AnnotationEditor2 = ({ annoVals, annoIdx, dismiss, timeZone, ...otherProps }: Props) => { + const { t } = useTranslate(); const styles = useStyles2(getStyles); const { onAnnotationCreate, onAnnotationUpdate } = usePanelContext(); @@ -70,7 +72,11 @@ export const AnnotationEditor2 = ({ annoVals, annoIdx, dismiss, timeZone, ...oth
-
{isUpdatingAnnotation ? 'Edit annotation' : 'Add annotation'}
+
+ {isUpdatingAnnotation + ? t('timeseries.annotation-editor2.edit-annotation', 'Edit annotation') + : t('timeseries.annotation-editor2.add-annotation', 'Add annotation')} +
{time}
@@ -82,7 +88,11 @@ export const AnnotationEditor2 = ({ annoVals, annoIdx, dismiss, timeZone, ...oth return ( <>
- +
Zoom: + Zoom: + {zoom?.toFixed(1)}
Center:  + Center:  + {center[0].toFixed(5)}, {center[1].toFixed(5)}