Internationalisation: More automatic markup (#103260)

* easy markup

* final tweaks, betterer + translations

* fix unit test
pull/103332/head
Ashley Harrison 3 months ago committed by GitHub
parent a96f80312f
commit 0fbb51ab08
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 244
      .betterer.results
  2. 9
      public/app/features/dashboard/components/AddLibraryPanelWidget/AddLibraryPanelWidget.tsx
  3. 52
      public/app/features/dashboard/components/AnnotationSettings/AnnotationSettingsEdit.tsx
  4. 24
      public/app/features/dashboard/components/AnnotationSettings/AnnotationSettingsList.tsx
  5. 2
      public/app/features/dashboard/components/DashNav/DashNav.tsx
  6. 3
      public/app/features/dashboard/components/DashboardLoading/DashboardLoading.tsx
  7. 10
      public/app/features/dashboard/components/DashboardRow/DashboardRow.tsx
  8. 10
      public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx
  9. 1
      public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx
  10. 8
      public/app/features/dashboard/components/GenAI/GenAIHistory.tsx
  11. 5
      public/app/features/dashboard/components/GenAI/MinimalisticPagination.tsx
  12. 24
      public/app/features/dashboard/components/HelpWizard/HelpWizard.tsx
  13. 10
      public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx
  14. 8
      public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.tsx
  15. 5
      public/app/features/dashboard/components/PanelEditor/OverrideCategoryTitle.tsx
  16. 32
      public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx
  17. 3
      public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.tsx
  18. 3
      public/app/features/dashboard/components/PanelEditor/PanelNotSupported.tsx
  19. 8
      public/app/features/dashboard/components/PanelEditor/VisualizationButton.tsx
  20. 5
      public/app/features/dashboard/components/PanelEditor/VisualizationSelectPane.tsx
  21. 8
      public/app/features/dashboard/components/PanelEditor/getFieldOverrideElements.tsx
  22. 3
      public/app/features/dashboard/components/PublicDashboardNotAvailable/PublicDashboardNotAvailable.tsx
  23. 3
      public/app/features/dashboard/components/RowOptions/RowOptionsButton.tsx
  24. 11
      public/app/features/dashboard/components/RowOptions/RowOptionsForm.tsx
  25. 9
      public/app/features/dashboard/components/RowOptions/RowOptionsModal.tsx
  26. 24
      public/app/features/dashboard/components/SaveDashboard/DashboardValidation.tsx
  27. 5
      public/app/features/dashboard/components/SaveDashboard/SaveDashboardButton.tsx
  28. 11
      public/app/features/dashboard/components/SaveDashboard/SaveDashboardDiff.tsx
  29. 16
      public/app/features/dashboard/components/SaveDashboard/SaveDashboardErrorProxy.tsx
  30. 11
      public/app/features/dashboard/components/SaveDashboard/UnsavedChangesModal.tsx
  31. 34
      public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx
  32. 2
      public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.test.tsx
  33. 25
      public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx
  34. 9
      public/app/features/dashboard/components/SaveDashboard/forms/SaveProvisionedDashboardForm.tsx
  35. 3
      public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/EmailSharingConfiguration.tsx
  36. 9
      public/app/features/dashboard/components/ShareModal/ViewJsonModal.tsx
  37. 7
      public/app/features/dashboard/components/SubMenu/SubMenu.tsx
  38. 15
      public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.tsx
  39. 3
      public/app/features/dashboard/components/TransformationsEditor/TransformationFilter.tsx
  40. 17
      public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx
  41. 10
      public/app/features/dashboard/components/TransformationsEditor/TransformationPicker.tsx
  42. 12
      public/app/features/dashboard/components/TransformationsEditor/TransformationPickerNg.tsx
  43. 18
      public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx
  44. 3
      public/app/features/dashboard/components/VersionHistory/RevertDashboardModal.tsx
  45. 6
      public/app/features/dashboard/components/VersionHistory/VersionHistoryComparison.tsx
  46. 19
      public/app/features/dashboard/components/VersionHistory/VersionHistoryTable.tsx
  47. 7
      public/app/features/dashboard/containers/SoloPanelPage.tsx
  48. 8
      public/app/features/dashboard/dashgrid/PanelLinks.tsx
  49. 237
      public/locales/en-US/grafana.json

@ -2782,40 +2782,17 @@ exports[`better eslint`] = {
"public/app/features/dashboard/api/v1.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/features/dashboard/components/AddLibraryPanelWidget/AddLibraryPanelWidget.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"]
],
"public/app/features/dashboard/components/AddLibraryPanelWidget/index.ts:5381": [
[0, 0, 0, "Do not re-export imported variable (\`./AddLibraryPanelWidget\`)", "0"]
],
"public/app/features/dashboard/components/AnnotationSettings/AnnotationSettingsEdit.tsx:5381": [
[0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "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, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "3"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "4"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "5"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "6"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "7"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "8"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "9"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "10"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "11"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "12"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "13"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "14"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "15"]
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"]
],
"public/app/features/dashboard/components/AnnotationSettings/AnnotationSettingsList.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"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "4"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "5"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "6"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "7"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"]
],
"public/app/features/dashboard/components/AnnotationSettings/index.tsx:5381": [
[0, 0, 0, "Do not re-export imported variable (\`./AnnotationSettingsEdit\`)", "0"],
@ -2845,16 +2822,14 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not re-export imported variable (\`./DashboardExporter\`)", "0"]
],
"public/app/features/dashboard/components/DashNav/DashNav.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()", "0"]
],
"public/app/features/dashboard/components/DashNav/index.ts:5381": [
[0, 0, 0, "Do not re-export imported variable (\`DashNav\`)", "0"]
],
"public/app/features/dashboard/components/DashboardLoading/DashboardLoading.tsx:5381": [
[0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"],
[0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "1"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"]
[0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "1"]
],
"public/app/features/dashboard/components/DashboardPrompt/DashboardPrompt.test.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
@ -2874,22 +2849,12 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"public/app/features/dashboard/components/DashboardRow/DashboardRow.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. Wrap text with <Trans />", "1"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"]
],
"public/app/features/dashboard/components/DashboardRow/index.ts:5381": [
[0, 0, 0, "Do not re-export imported variable (\`./DashboardRow\`)", "0"]
],
"public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"]
],
"public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"public/app/features/dashboard/components/DashboardSettings/VersionsSettings.tsx:5381": [
[0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"]
],
@ -2897,31 +2862,18 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not re-export imported variable (\`./DashboardSettings\`)", "0"]
],
"public/app/features/dashboard/components/GenAI/GenAIHistory.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"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/dashboard/components/GenAI/MinimalisticPagination.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. Wrap text with <Trans />", "2"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/dashboard/components/HelpWizard/HelpWizard.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"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "3"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "4"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "5"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "6"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "7"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "8"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "9"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "10"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "11"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "12"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "13"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "4"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "5"]
],
"public/app/features/dashboard/components/Inspector/PanelInspector.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
@ -2931,8 +2883,7 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not re-export imported variable (\`./LinkSettingsList\`)", "1"]
],
"public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx:5381": [
[0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"]
[0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"]
],
"public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
@ -2941,47 +2892,18 @@ exports[`better eslint`] = {
"public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.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"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"]
],
"public/app/features/dashboard/components/PanelEditor/OverrideCategoryTitle.tsx:5381": [
[0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "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, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"]
],
"public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx:5381": [
[0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "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, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "4"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "5"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "6"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "7"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "8"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "9"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "10"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "11"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "12"]
],
"public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"public/app/features/dashboard/components/PanelEditor/PanelNotSupported.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/dashboard/components/PanelEditor/VisualizationButton.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"]
],
"public/app/features/dashboard/components/PanelEditor/VisualizationSelectPane.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, "Use data-testid for E2E selectors instead of aria-label", "2"]
],
"public/app/features/dashboard/components/PanelEditor/getFieldOverrideElements.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, "Use data-testid for E2E selectors instead of aria-label", "0"]
],
"public/app/features/dashboard/components/PanelEditor/getVisualizationOptions.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
@ -2994,86 +2916,34 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
[0, 0, 0, "Unexpected any. Specify a different type.", "4"]
],
"public/app/features/dashboard/components/PublicDashboardNotAvailable/PublicDashboardNotAvailable.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/dashboard/components/RowOptions/RowOptionsButton.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"public/app/features/dashboard/components/RowOptions/RowOptionsForm.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. Wrap text with <Trans />", "2"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"]
],
"public/app/features/dashboard/components/RowOptions/RowOptionsModal.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"public/app/features/dashboard/components/SaveDashboard/DashboardValidation.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"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/dashboard/components/SaveDashboard/SaveDashboardButton.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"],
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "2"],
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "3"]
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"],
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "1"]
],
"public/app/features/dashboard/components/SaveDashboard/SaveDashboardDiff.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. Wrap text with <Trans />", "2"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"]
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"]
],
"public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.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"]
],
"public/app/features/dashboard/components/SaveDashboard/SaveDashboardErrorProxy.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"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "4"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "5"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "6"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "7"]
],
"public/app/features/dashboard/components/SaveDashboard/UnsavedChangesModal.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. Wrap text with <Trans />", "0"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"]
],
"public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.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"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "3"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "4"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "5"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "6"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "7"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"]
],
"public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.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"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "3"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "4"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "5"],
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "6"],
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "7"],
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "8"]
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"],
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "1"],
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "2"]
],
"public/app/features/dashboard/components/SaveDashboard/forms/SaveProvisionedDashboardForm.tsx:5381": [
[0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "4"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"]
],
"public/app/features/dashboard/components/SaveDashboard/useDashboardSave.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
@ -3087,9 +2957,6 @@ exports[`better eslint`] = {
"public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/Configuration.tsx:5381": [
[0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"]
],
"public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/EmailSharingConfiguration.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/AcknowledgeCheckboxes.tsx:5381": [
[0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"],
[0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "1"]
@ -3097,73 +2964,34 @@ exports[`better eslint`] = {
"public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/dashboard/components/ShareModal/ViewJsonModal.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.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, "Unexpected any. Specify a different type.", "2"]
],
"public/app/features/dashboard/components/SubMenu/SubMenu.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.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. Wrap text with <Trans />", "1"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"]
],
"public/app/features/dashboard/components/TransformationsEditor/TransformationFilter.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.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"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "3"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "4"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "5"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "6"]
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"]
],
"public/app/features/dashboard/components/TransformationsEditor/TransformationPicker.tsx:5381": [
[0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "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, "No untranslated strings. Wrap text with <Trans />", "3"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "4"]
],
"public/app/features/dashboard/components/TransformationsEditor/TransformationPickerNg.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. Wrap text with <Trans />", "2"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"]
],
"public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.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, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "4"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "5"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "6"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "7"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"]
],
"public/app/features/dashboard/components/VersionHistory/RevertDashboardModal.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. Wrap text with <Trans />", "1"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/dashboard/components/VersionHistory/VersionHistoryComparison.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. Wrap text with <Trans />", "0"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"]
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"]
],
"public/app/features/dashboard/components/VersionHistory/VersionHistoryTable.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. Wrap text with <Trans />", "1"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "3"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "4"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "5"]
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"public/app/features/dashboard/components/VersionHistory/useDashboardRestore.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
@ -3187,10 +3015,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/features/dashboard/containers/SoloPanelPage.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. Wrap text with <Trans />", "1"]
],
"public/app/features/dashboard/dashgrid/PanelLinks.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
],
"public/app/features/dashboard/dashgrid/SeriesVisibilityConfigFactory.ts:5381": [

@ -5,7 +5,7 @@ import tinycolor from 'tinycolor2';
import { GrafanaTheme2 } from '@grafana/data';
import { LibraryPanel } from '@grafana/schema';
import { IconButton, useStyles2 } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import {
LibraryPanelsSearch,
@ -49,10 +49,13 @@ export const AddLibraryPanelWidget = ({ panel, dashboard }: Props) => {
</span>
<div className="flex-grow-1" />
<IconButton
aria-label="Close 'Add Panel' widget"
aria-label={t(
'dashboard.add-library-panel-widget.aria-label-close-add-panel-widget',
"Close 'Add Panel' widget"
)}
name="times"
onClick={onCancelAddPanel}
tooltip="Close widget"
tooltip={t('dashboard.add-library-panel-widget.tooltip-close-widget', 'Close widget')}
/>
</div>
<LibraryPanelsSearch onClick={onAddLibraryPanel} variant={LibraryPanelsSearchVariant.Tight} showPanelFilter />

@ -28,7 +28,7 @@ import {
} from '@grafana/ui';
import { ColorValueEditor } from 'app/core/components/OptionsUI/color';
import config from 'app/core/config';
import { Trans } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import StandardAnnotationQueryEditor from 'app/features/annotations/components/StandardAnnotationQueryEditor';
import { AngularEditorLoader } from 'app/features/dashboard-scene/settings/annotations/AngularEditorLoader';
import { DataSourcePicker } from 'app/features/datasources/components/picker/DataSourcePicker';
@ -178,7 +178,7 @@ export const AnnotationSettingsEdit = ({ editIdx, dashboard }: Props) => {
return (
<div>
<FieldSet className={styles.settingsForm}>
<Field label="Name">
<Field label={t('dashboard.annotation-settings-edit.label-name', 'Name')}>
<Input
data-testid={selectors.pages.Dashboard.Settings.Annotations.Settings.name}
name="name"
@ -188,31 +188,55 @@ export const AnnotationSettingsEdit = ({ editIdx, dashboard }: Props) => {
onChange={onNameChange}
/>
</Field>
<Field label="Data source" htmlFor="data-source-picker">
<Field
label={t('dashboard.annotation-settings-edit.label-data-source', 'Data source')}
htmlFor="data-source-picker"
>
<DataSourcePicker annotations variables current={annotation.datasource} onChange={onDataSourceChange} />
</Field>
{!ds?.meta.annotations && (
<Alert title="No annotation support for this data source" severity="error">
<Alert
title={t(
'dashboard.annotation-settings-edit.title-annotation-support-source',
'No annotation support for this data source'
)}
severity="error"
>
<Trans i18nKey="errors.dashboard-settings.annotations.datasource">
The selected data source does not support annotations. Please select a different data source.
</Trans>
</Alert>
)}
<Field label="Enabled" description="When enabled the annotation query is issued every dashboard refresh">
<Field
label={t('dashboard.annotation-settings-edit.label-enabled', 'Enabled')}
description={t(
'dashboard.annotation-settings-edit.description-enabled-annotation-query-issued-every-dashboard',
'When enabled the annotation query is issued every dashboard refresh'
)}
>
<Checkbox name="enable" id="enable" value={annotation.enable} onChange={onChange} />
</Field>
<Field
label="Hidden"
label={t('dashboard.annotation-settings-edit.label-hidden', 'Hidden')}
description="Annotation queries can be toggled on or off at the top of the dashboard. With this option checked this toggle will be hidden."
>
<Checkbox name="hide" id="hide" value={annotation.hide} onChange={onChange} />
</Field>
<Field label="Color" description="Color to use for the annotation event markers">
<Field
label={t('dashboard.annotation-settings-edit.label-color', 'Color')}
description={t(
'dashboard.annotation-settings-edit.description-color-annotation-event-markers',
'Color to use for the annotation event markers'
)}
>
<HorizontalGroup>
<ColorValueEditor value={annotation?.iconColor} onChange={onColorChange} />
</HorizontalGroup>
</Field>
<Field label="Show in" data-testid={selectors.pages.Dashboard.Settings.Annotations.NewAnnotation.showInLabel}>
<Field
label={t('dashboard.annotation-settings-edit.label-show-in', 'Show in')}
data-testid={selectors.pages.Dashboard.Settings.Annotations.NewAnnotation.showInLabel}
>
<>
<Select
options={panelFilters}
@ -226,7 +250,7 @@ export const AnnotationSettingsEdit = ({ editIdx, dashboard }: Props) => {
value={panels.filter((panel) => annotation.filter?.ids.includes(panel.value!))}
onChange={onAddFilterPanelID}
isClearable={true}
placeholder="Choose panels"
placeholder={t('dashboard.annotation-settings-edit.placeholder-choose-panels', 'Choose panels')}
width={100}
closeMenuOnSelect={false}
className={styles.select}
@ -237,7 +261,9 @@ export const AnnotationSettingsEdit = ({ editIdx, dashboard }: Props) => {
</Field>
</FieldSet>
<FieldSet>
<h3 className="page-heading">Query</h3>
<h3 className="page-heading">
<Trans i18nKey="dashboard.annotation-settings-edit.query">Query</Trans>
</h3>
{ds?.annotations && dsi && (
<StandardAnnotationQueryEditor
datasource={ds}
@ -251,7 +277,7 @@ export const AnnotationSettingsEdit = ({ editIdx, dashboard }: Props) => {
<Stack>
{!annotation.builtIn && (
<Button variant="destructive" onClick={onDelete}>
Delete
<Trans i18nKey="dashboard.annotation-settings-edit.delete">Delete</Trans>
</Button>
)}
<Button
@ -259,10 +285,10 @@ export const AnnotationSettingsEdit = ({ editIdx, dashboard }: Props) => {
onClick={onPreview}
data-testid={selectors.pages.Dashboard.Settings.Annotations.NewAnnotation.previewInDashboard}
>
Preview in dashboard
<Trans i18nKey="dashboard.annotation-settings-edit.preview-in-dashboard">Preview in dashboard</Trans>
</Button>
<Button variant="primary" onClick={onApply}>
Apply
<Trans i18nKey="dashboard.annotation-settings-edit.apply">Apply</Trans>
</Button>
</Stack>
</div>

@ -60,8 +60,12 @@ export const AnnotationSettingsList = ({ dashboard, onNew, onEdit }: Props) => {
<table role="grid" className="filter-table filter-table--hover">
<thead>
<tr>
<th>Query name</th>
<th>Data source</th>
<th>
<Trans i18nKey="dashboard.annotation-settings-list.query-name">Query name</Trans>
</th>
<th>
<Trans i18nKey="dashboard.annotation-settings-list.data-source">Data source</Trans>
</th>
<th colSpan={3}></th>
</tr>
</thead>
@ -85,11 +89,21 @@ export const AnnotationSettingsList = ({ dashboard, onNew, onEdit }: Props) => {
{dataSourceSrv.getInstanceSettings(annotation.datasource)?.name || annotation.datasource?.uid}
</td>
<td role="gridcell" style={{ width: '1%' }}>
{idx !== 0 && <IconButton name="arrow-up" onClick={() => onMove(idx, -1)} tooltip="Move up" />}
{idx !== 0 && (
<IconButton
name="arrow-up"
onClick={() => onMove(idx, -1)}
tooltip={t('dashboard.annotation-settings-list.tooltip-move-up', 'Move up')}
/>
)}
</td>
<td role="gridcell" style={{ width: '1%' }}>
{dashboard.annotations.list.length > 1 && idx !== dashboard.annotations.list.length - 1 ? (
<IconButton name="arrow-down" onClick={() => onMove(idx, 1)} tooltip="Move down" />
<IconButton
name="arrow-down"
onClick={() => onMove(idx, 1)}
tooltip={t('dashboard.annotation-settings-list.tooltip-move-down', 'Move down')}
/>
) : null}
</td>
<td role="gridcell" style={{ width: '1%' }}>
@ -146,7 +160,7 @@ export const AnnotationSettingsList = ({ dashboard, onNew, onEdit }: Props) => {
data-testid={selectors.pages.Dashboard.Settings.Annotations.List.addAnnotationCTAV2}
onClick={onNew}
>
New query
<Trans i18nKey="dashboard.annotation-settings-list.new-query">New query</Trans>
</ListNewButton>
)}
</Stack>

@ -216,7 +216,7 @@ export const DashNav = memo<Props>((props) => {
buttons.push(
<Badge
color="blue"
text="Public"
text={t('dashboard.dash-nav.render-left-actions.text-public', 'Public')}
key="public-dashboard-button-badge"
className={publicBadgeStyle}
data-testid={selectors.publicDashboardTag}

@ -3,6 +3,7 @@ import { css, keyframes } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { locationService } from '@grafana/runtime';
import { Button, HorizontalGroup, Spinner, useStyles2, VerticalGroup } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { DashboardInitPhase } from 'app/types';
export interface Props {
@ -24,7 +25,7 @@ export const DashboardLoading = ({ initPhase }: Props) => {
</HorizontalGroup>{' '}
<HorizontalGroup align="center" justify="center">
<Button variant="secondary" size="md" icon="repeat" onClick={cancelVariables}>
Cancel loading dashboard
<Trans i18nKey="dashboard.dashboard-loading.cancel-loading-dashboard">Cancel loading dashboard</Trans>
</Button>
</HorizontalGroup>
</VerticalGroup>

@ -8,6 +8,7 @@ import { selectors } from '@grafana/e2e-selectors';
import { getTemplateSrv, RefreshEvent } from '@grafana/runtime';
import { Icon, TextLink, Themeable2, withTheme2 } from '@grafana/ui';
import appEvents from 'app/core/app_events';
import { Trans, t } from 'app/core/internationalization';
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard/constants';
import { ShowConfirmModalEvent } from '../../../../types/events';
@ -59,7 +60,7 @@ export class UnthemedDashboardRow extends Component<DashboardRowProps> {
'https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/create-dashboard/#configure-repeating-rows'
}
>
Learn more
<Trans i18nKey="dashboard.unthemed-dashboard-row.learn-more">Learn more</Trans>
</TextLink>
</div>
);
@ -133,7 +134,12 @@ export class UnthemedDashboardRow extends Component<DashboardRowProps> {
onUpdate={this.onUpdate}
warning={this.getWarning()}
/>
<button type="button" className="pointer" onClick={this.onDelete} aria-label="Delete row">
<button
type="button"
className="pointer"
onClick={this.onDelete}
aria-label={t('dashboard.unthemed-dashboard-row.aria-label-delete-row', 'Delete row')}
>
<Icon name="trash-alt" />
</button>
</div>

@ -8,7 +8,7 @@ import { locationService } from '@grafana/runtime';
import { Button, Stack, Text, ToolbarButtonRow } from '@grafana/ui';
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
import { Page } from 'app/core/components/Page/Page';
import { t } from 'app/core/internationalization';
import { t, Trans } from 'app/core/internationalization';
import { contextSrv } from 'app/core/services/context_srv';
import { AccessControlAction } from 'app/types';
import { DashboardMetaChangedEvent } from 'app/types/events';
@ -65,7 +65,7 @@ export function DashboardSettings({ dashboard, editview, pageNav, sectionNav }:
size={size}
onClick={onClose}
>
Close
<Trans i18nKey="dashboard.dashboard-settings.actions.close">Close</Trans>
</Button>,
canSaveAs && (
<SaveDashboardAsButton
@ -213,9 +213,11 @@ function MakeEditable({ dashboard, sectionNav }: SettingsPageProps) {
return (
<Page navModel={sectionNav}>
<Stack direction="column" gap={2} alignItems="flex-start">
<Text variant="h3">Dashboard not editable</Text>
<Text variant="h3">
<Trans i18nKey="dashboard.make-editable.dashboard-not-editable">Dashboard not editable</Trans>
</Text>
<Button type="submit" onClick={() => dashboard.makeEditable()}>
Make editable
<Trans i18nKey="dashboard.make-editable.make-editable">Make editable</Trans>
</Button>
</Stack>
</Page>

@ -106,6 +106,7 @@ export class TimePickerSettings extends PureComponent<Props, State> {
<Input
id="now-delay-input"
invalid={!this.state.isNowDelayValid}
// eslint-disable-next-line @grafana/no-untranslated-strings
placeholder="0m"
onChange={this.onNowDelayChange}
defaultValue={this.props.nowDelay}

@ -3,7 +3,7 @@ import { useState, useCallback } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, Button, Icon, Input, Stack, Text, TextLink, useStyles2 } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import { STOP_GENERATION_TEXT } from './GenAIButton';
import { GenerationHistoryCarousel } from './GenerationHistoryCarousel';
@ -110,13 +110,13 @@ export const GenAIHistory = ({
</div>
<Input
placeholder="Tell AI what to do next..."
placeholder={t('dashboard.gen-aihistory.placeholder-tell-ai-what-to-do-next', 'Tell AI what to do next...')}
suffix={
<Button
icon="enter"
variant="secondary"
fill="text"
aria-label="Send custom feedback"
aria-label={t('dashboard.gen-aihistory.aria-label-send-custom-feedback', 'Send custom feedback')}
onClick={onClickSubmitCustomFeedback}
disabled={!customFeedback}
>
@ -143,7 +143,7 @@ export const GenAIHistory = ({
</div>
<div className={styles.footer}>
<Icon name="exclamation-circle" aria-label="exclamation-circle" className={styles.infoColor} />
<Icon name="exclamation-circle" className={styles.infoColor} />
<Text variant="bodySmall" color="secondary">
This content is AI-generated using the{' '}
<TextLink

@ -2,6 +2,7 @@ import { css, cx } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { IconButton, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
export interface MinimalisticPaginationProps {
currentPage: number;
@ -29,7 +30,7 @@ export const MinimalisticPagination = ({
<IconButton
name="angle-left"
size="md"
tooltip="Previous"
tooltip={t('dashboard.minimalistic-pagination.tooltip-previous', 'Previous')}
onClick={() => onNavigate(currentPage - 1)}
disabled={currentPage === 1}
/>
@ -37,7 +38,7 @@ export const MinimalisticPagination = ({
<IconButton
name="angle-right"
size="md"
tooltip="Next"
tooltip={t('dashboard.minimalistic-pagination.tooltip-next', 'Next')}
onClick={() => onNavigate(currentPage + 1)}
disabled={currentPage === numberOfPages}
/>

@ -20,7 +20,7 @@ import {
Icon,
Stack,
} from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import { contextSrv } from 'app/core/services/context_srv';
import { PanelModel } from 'app/features/dashboard/state/PanelModel';
import { AccessControlAction } from 'app/types';
@ -119,13 +119,13 @@ export function HelpWizard({ panel, plugin, onClose }: Props) {
{currentTab === SnapshotTab.Data && (
<div className={styles.code}>
<div className={styles.opts}>
<Field label="Template" className={styles.field}>
<Field label={t('dashboard.help-wizard.label-template', 'Template')} className={styles.field}>
<Select options={options} value={showMessage} onChange={service.onShowMessageChange} />
</Field>
{showMessage === ShowMessage.GithubComment ? (
<ClipboardButton icon="copy" getText={service.onGetMarkdownForClipboard}>
Copy to clipboard
<Trans i18nKey="dashboard.help-wizard.copy-to-clipboard">Copy to clipboard</Trans>
</ClipboardButton>
) : (
<Button icon="download-alt" onClick={service.onDownloadDashboard}>
@ -152,26 +152,26 @@ export function HelpWizard({ panel, plugin, onClose }: Props) {
{currentTab === SnapshotTab.Support && (
<>
<Field
label="Obfuscate data"
label={t('dashboard.help-wizard.label-obfuscate-data', 'Obfuscate data')}
description="Modify the original data to hide sensitve information. Note the lengths will stay the same, and duplicate values will be equal."
>
<Stack direction="row" gap={1}>
<InlineSwitch
label="Labels"
label={t('dashboard.help-wizard.randomize-labels-label-labels', 'Labels')}
id="randomize-labels"
showLabel={true}
value={Boolean(randomize.labels)}
onChange={() => service.onToggleRandomize('labels')}
/>
<InlineSwitch
label="Field names"
label={t('dashboard.help-wizard.randomize-field-names-label-field-names', 'Field names')}
id="randomize-field-names"
showLabel={true}
value={Boolean(randomize.names)}
onChange={() => service.onToggleRandomize('names')}
/>
<InlineSwitch
label="String values"
label={t('dashboard.help-wizard.randomize-string-values-label-string-values', 'String values')}
id="randomize-string-values"
showLabel={true}
value={Boolean(randomize.values)}
@ -180,7 +180,10 @@ export function HelpWizard({ panel, plugin, onClose }: Props) {
</Stack>
</Field>
<Field label="Support snapshot" description={`Panel: ${panelTitle}`}>
<Field
label={t('dashboard.help-wizard.label-support-snapshot', 'Support snapshot')}
description={`Panel: ${panelTitle}`}
>
<Stack>
<Button icon="download-alt" onClick={service.onDownloadDashboard}>
<Trans i18nKey="help-wizard.download-snapshot">Download snapshot</Trans> ({snapshotSize})
@ -188,7 +191,10 @@ export function HelpWizard({ panel, plugin, onClose }: Props) {
<ClipboardButton
icon="github"
getText={service.onGetMarkdownForClipboard}
title="Copy a complete GitHub comment to the clipboard"
title={t(
'dashboard.help-wizard.title-complete-git-hub-comment-clipboard',
'Copy a complete GitHub comment to the clipboard'
)}
>
<Trans i18nKey="help-wizard.github-comment">Copy Github comment</Trans>
</ClipboardButton>

@ -10,6 +10,7 @@ import {
GrafanaTheme2,
} from '@grafana/data';
import { Counter, Field, HorizontalGroup, IconButton, Label, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { OptionsPaneCategory } from './OptionsPaneCategory';
@ -71,7 +72,14 @@ export const DynamicConfigValueEditor = ({
</Label>
{!isSystemOverride && (
<div>
<IconButton name="times" onClick={onRemove} tooltip="Remove property" />
<IconButton
name="times"
onClick={onRemove}
tooltip={t(
'dashboard.dynamic-config-value-editor.render-label.tooltip-remove-property',
'Remove property'
)}
/>
</div>
)}
</HorizontalGroup>

@ -5,6 +5,7 @@ import * as React from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { config } from '@grafana/runtime';
import { FilterInput, RadioButtonGroup, ScrollContainer, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { AngularDeprecationPluginNotice } from 'app/features/plugins/angularDeprecation/AngularDeprecationPluginNotice';
import { isPanelModelLibraryPanel } from '../../../library-panels/guard';
@ -96,7 +97,12 @@ export const OptionsPaneOptions = (props: OptionPaneRenderProps) => {
break;
case OptionFilter.Recent:
mainBoxElements.push(
<OptionsPaneCategory id="Recent options" title="Recent options" key="Recent options" forceOpen={true}>
<OptionsPaneCategory
id="Recent options"
title={t('dashboard.options-pane-options.Recent options-title-recent-options', 'Recent options')}
key="Recent options"
forceOpen={true}
>
{getRecentOptions(allOptions).map((item) => item.render())}
</OptionsPaneCategory>
);

@ -3,6 +3,7 @@ import { css } from '@emotion/css';
import { FieldConfigOptionsRegistry, GrafanaTheme2, ConfigOverrideRule } from '@grafana/data';
import { Button, HorizontalGroup, Icon, useStyles2 } from '@grafana/ui';
import { FieldMatcherUIRegistryItem } from '@grafana/ui/internal';
import { t } from 'app/core/internationalization';
interface Props {
isExpanded: boolean;
@ -34,8 +35,8 @@ export const OverrideCategoryTitle = ({
fill="text"
icon="trash-alt"
onClick={onOverrideRemove}
tooltip="Remove override"
aria-label="Remove override"
tooltip={t('dashboard.override-category-title.tooltip-remove-override', 'Remove override')}
aria-label={t('dashboard.override-category-title.aria-label-remove-override', 'Remove override')}
/>
</HorizontalGroup>
{!isExpanded && (

@ -24,6 +24,7 @@ import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
import { Page } from 'app/core/components/Page/Page';
import { SplitPaneWrapper } from 'app/core/components/SplitPaneWrapper/SplitPaneWrapper';
import { appEvents } from 'app/core/core';
import { t, Trans } from 'app/core/internationalization';
import { SubMenuItems } from 'app/features/dashboard/components/SubMenu/SubMenuItems';
import { SaveLibraryPanelModal } from 'app/features/library-panels/components/SaveLibraryPanelModal/SaveLibraryPanelModal';
import { PanelModelWithLibraryPanel } from 'app/features/library-panels/types';
@ -305,7 +306,7 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
{this.renderTemplateVariables(styles)}
<Stack gap={1}>
<InlineSwitch
label="Table view"
label={t('dashboard.panel-editor-unconnected.table-view-label-table-view', 'Table view')}
showLabel={true}
id="table-view"
value={tableViewEnabled}
@ -326,13 +327,13 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
let editorActions = [
<Button
onClick={this.onDiscard}
title="Undo all changes"
title={t('dashboard.panel-editor-unconnected.editor-actions.title-undo-all-changes', 'Undo all changes')}
key="discard"
size={size}
variant="destructive"
fill="outline"
>
Discard
<Trans i18nKey="dashboard.panel-editor-unconnected.editor-actions.discard">Discard</Trans>
</Button>,
this.props.dashboard.meta.canSave &&
(this.props.panel.libraryPanel ? (
@ -340,31 +341,42 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
onClick={this.onSaveLibraryPanel}
variant="primary"
size={size}
title="Apply changes and save library panel"
title={t(
'dashboard.panel-editor-unconnected.editor-actions.title-apply-changes-and-save-library-panel',
'Apply changes and save library panel'
)}
key="save-panel"
>
Save library panel
<Trans i18nKey="dashboard.panel-editor-unconnected.editor-actions.save-library-panel">
Save library panel
</Trans>
</Button>
) : (
<Button
onClick={this.onSaveDashboard}
title="Apply changes and save dashboard"
title={t(
'dashboard.panel-editor-unconnected.editor-actions.title-apply-changes-and-save-dashboard',
'Apply changes and save dashboard'
)}
key="save"
size={size}
variant="secondary"
>
Save
<Trans i18nKey="dashboard.panel-editor-unconnected.editor-actions.save">Save</Trans>
</Button>
)),
<Button
onClick={this.onBack}
variant="primary"
title="Apply changes and go back to dashboard"
title={t(
'dashboard.panel-editor-unconnected.editor-actions.title-apply-changes-dashboard',
'Apply changes and go back to dashboard'
)}
data-testid={selectors.components.PanelEditor.applyButton}
key="apply"
size={size}
>
Apply
<Trans i18nKey="dashboard.panel-editor-unconnected.editor-actions.apply">Apply</Trans>
</Button>,
];
@ -389,7 +401,7 @@ export class PanelEditorUnconnected extends PureComponent<Props> {
title="Disconnects this panel from the library panel so that you can edit it regularly."
key="unlink"
>
Unlink
<Trans i18nKey="dashboard.panel-editor-unconnected.unlink">Unlink</Trans>
</ToolbarButton>
);
}}

@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
import { RefreshEvent } from '@grafana/runtime';
import { PanelChrome } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel';
import { PanelRenderer } from 'app/features/panel/components/PanelRenderer';
import { Options } from 'app/plugins/panel/table/panelcfg.gen';
@ -61,7 +62,7 @@ export function PanelEditorTableView({ width, height, panel, dashboard }: Props)
<>
<PanelHeaderCorner panel={panel} error={errorMessage} />
<PanelRenderer
title="Raw data"
title={t('dashboard.panel-editor-table-view.title-raw-data', 'Raw data')}
pluginId="table"
width={innerWidth}
height={innerHeight}

@ -2,6 +2,7 @@ import { useCallback } from 'react';
import { locationService } from '@grafana/runtime';
import { Button, Stack } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { PanelEditorTabId } from './types';
@ -21,7 +22,7 @@ export function PanelNotSupported({ message }: Props): JSX.Element {
<h2>{message}</h2>
<div>
<Button size="md" variant="secondary" icon="arrow-left" onClick={onBackToQueries}>
Go back to Queries
<Trans i18nKey="dashboard.panel-not-supported.go-back-to-queries">Go back to Queries</Trans>
</Button>
</div>
</Stack>

@ -2,6 +2,7 @@ import { css } from '@emotion/css';
import { selectors } from '@grafana/e2e-selectors';
import { ToolbarButton, ButtonGroup } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { useDispatch, useSelector } from 'app/types';
import { PanelModel } from '../../state/PanelModel';
@ -37,12 +38,15 @@ export const VisualizationButton = ({ panel }: Props) => {
<ButtonGroup>
<ToolbarButton
className={styles.vizButton}
tooltip="Click to change visualization"
tooltip={t(
'dashboard.visualization-button.tooltip-click-to-change-visualization',
'Click to change visualization'
)}
imgSrc={plugin.meta.info.logos.small}
isOpen={isVizPickerOpen}
onClick={onToggleOpen}
data-testid={selectors.components.PanelEditor.toggleVizPicker}
aria-label="Change Visualization"
aria-label={t('dashboard.visualization-button.aria-label-change-visualization', 'Change visualization')}
variant="canvas"
fullWidth
>

@ -6,6 +6,7 @@ import { GrafanaTheme2, PanelData, SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Button, Field, FilterInput, RadioButtonGroup, ScrollContainer, useStyles2 } from '@grafana/ui';
import { LS_VISUALIZATION_SELECT_TAB_KEY } from 'app/core/constants';
import { t } from 'app/core/internationalization';
import { PanelLibraryOptionsGroup } from 'app/features/library-panels/components/PanelLibraryOptionsGroup/PanelLibraryOptionsGroup';
import { VisualizationSuggestions } from 'app/features/panel/components/VizTypePicker/VisualizationSuggestions';
import { VizTypeChangeDetails } from 'app/features/panel/components/VizTypePicker/types';
@ -76,10 +77,10 @@ export const VisualizationSelectPane = ({ panel, data }: Props) => {
onChange={setSearchQuery}
ref={searchRef}
autoFocus={true}
placeholder="Search for..."
placeholder={t('dashboard.visualization-select-pane.placeholder-search-for', 'Search for...')}
/>
<Button
title="Close"
title={t('dashboard.visualization-select-pane.title-close', 'Close')}
variant="secondary"
icon="angle-up"
className={styles.closeButton}

@ -15,6 +15,7 @@ import {
DataFrame,
} from '@grafana/data';
import { fieldMatchersUI, useStyles2, ValuePicker } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { getDataLinksVariableSuggestions } from 'app/features/panel/panellinks/link_srv';
import { DynamicConfigValueEditor } from './DynamicConfigValueEditor';
@ -213,7 +214,10 @@ export function getFieldOverrideCategories(
return (
<ValuePicker
key="Add override property"
label="Add override property"
label={t(
'dashboard.get-field-override-categories.label-add-override-property',
'Add override property'
)}
variant="secondary"
isFullWidth={true}
icon="plus"
@ -239,7 +243,7 @@ export function getFieldOverrideCategories(
<AddOverrideButtonContainer key="Add override">
<ValuePicker
icon="plus"
label="Add field override"
label={t('dashboard.get-field-override-categories.label-add-field-override', 'Add field override')}
variant="secondary"
menuPlacement="auto"
isFullWidth={true}

@ -3,6 +3,7 @@ import { css, cx } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
import { useStyles2 } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { Branding } from '../../../../core/components/Branding/Branding';
import { getLoginStyles } from '../../../../core/components/Login/LoginLayout';
@ -25,7 +26,7 @@ export const PublicDashboardNotAvailable = ({ paused }: { paused?: boolean }) =>
</p>
{paused && (
<p className={styles.description} data-testid={selectors.pausedDescription}>
Try again later
<Trans i18nKey="dashboard.public-dashboard-not-available.try-again-later">Try again later</Trans>
</p>
)}
</div>

@ -1,6 +1,7 @@
import * as React from 'react';
import { Icon, ModalsController } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { OnRowOptionsUpdate } from './RowOptionsForm';
import { RowOptionsModal } from './RowOptionsModal';
@ -25,7 +26,7 @@ export const RowOptionsButton = ({ repeat, title, onUpdate, warning }: RowOption
<button
type="button"
className="pointer"
aria-label="Row options"
aria-label={t('dashboard.row-options-button.aria-label-row-options', 'Row options')}
onClick={() => {
showModal(RowOptionsModal, {
title,

@ -4,6 +4,7 @@ import * as React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { Button, Field, Modal, Input, Alert } from '@grafana/ui';
import { Form } from 'app/core/components/Form/Form';
import { t, Trans } from 'app/core/internationalization';
import { RepeatRowSelect } from '../RepeatRowSelect/RepeatRowSelect';
@ -30,10 +31,10 @@ export const RowOptionsForm = ({ repeat, title, warning, onUpdate, onCancel }: P
>
{({ register }) => (
<>
<Field label="Title">
<Field label={t('dashboard.row-options-form.label-title', 'Title')}>
<Input {...register('title')} type="text" />
</Field>
<Field label="Repeat for">
<Field label={t('dashboard.row-options-form.label-repeat-for', 'Repeat for')}>
<RepeatRowSelect repeat={newRepeat} onChange={onChangeRepeat} />
</Field>
{warning && (
@ -49,9 +50,11 @@ export const RowOptionsForm = ({ repeat, title, warning, onUpdate, onCancel }: P
)}
<Modal.ButtonRow>
<Button type="button" variant="secondary" onClick={onCancel} fill="outline">
Cancel
<Trans i18nKey="dashboard.row-options-form.cancel">Cancel</Trans>
</Button>
<Button type="submit">
<Trans i18nKey="dashboard.row-options-form.update">Update</Trans>
</Button>
<Button type="submit">Update</Button>
</Modal.ButtonRow>
</>
)}

@ -2,6 +2,7 @@ import { css } from '@emotion/css';
import * as React from 'react';
import { Modal, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { OnRowOptionsUpdate, RowOptionsForm } from './RowOptionsForm';
@ -17,7 +18,13 @@ export const RowOptionsModal = ({ repeat, title, onDismiss, onUpdate, warning }:
const styles = useStyles2(getStyles);
return (
<Modal isOpen={true} title="Row options" icon="copy" onDismiss={onDismiss} className={styles.modal}>
<Modal
isOpen={true}
title={t('dashboard.row-options-modal.title-row-options', 'Row options')}
icon="copy"
onDismiss={onDismiss}
className={styles.modal}
>
<RowOptionsForm repeat={repeat} title={title} onCancel={onDismiss} onUpdate={onUpdate} warning={warning} />
</Modal>
);

@ -5,6 +5,7 @@ import { useAsync } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
import { FetchError } from '@grafana/runtime';
import { Alert, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { backendSrv } from 'app/core/services/backend_srv';
import { DashboardModel } from '../../state/DashboardModel';
@ -36,11 +37,22 @@ function DashboardValidation({ dashboard }: DashboardValidationProps) {
let alert: React.ReactNode;
if (loading) {
alert = <Alert severity="info" title="Checking dashboard validity" />;
alert = (
<Alert
severity="info"
title={t('dashboard.dashboard-validation.title-checking-dashboard-validity', 'Checking dashboard validity')}
/>
);
} else if (value) {
if (!value.isValid) {
alert = (
<Alert severity="warning" title="Dashboard failed schema validation">
<Alert
severity="warning"
title={t(
'dashboard.dashboard-validation.title-dashboard-failed-schema-validation',
'Dashboard failed schema validation'
)}
>
<p>
Validation is provided for development purposes and should be safe to ignore. If you are a Grafana
developer, consider checking and updating the dashboard schema
@ -52,7 +64,13 @@ function DashboardValidation({ dashboard }: DashboardValidationProps) {
} else {
const errorMessage = error?.message ?? 'Unknown error';
alert = (
<Alert severity="info" title="Error checking dashboard validity">
<Alert
severity="info"
title={t(
'dashboard.dashboard-validation.title-error-checking-dashboard-validity',
'Error checking dashboard validity'
)}
>
<p className={styles.error}>{errorMessage}</p>
</Alert>
);

@ -1,6 +1,7 @@
import { selectors } from '@grafana/e2e-selectors';
import { reportInteraction } from '@grafana/runtime';
import { Button, ButtonVariant, ComponentSize, ModalsController } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
import { SaveDashboardDrawer } from './SaveDashboardDrawer';
@ -28,7 +29,7 @@ export const SaveDashboardButton = ({ dashboard, onSaveSuccess, size }: SaveDash
}}
aria-label={selectors.pages.Dashboard.Settings.General.saveDashBoard}
>
Save dashboard
<Trans i18nKey="dashboard.save-dashboard-button.save-dashboard">Save dashboard</Trans>
</Button>
);
}}
@ -58,7 +59,7 @@ export const SaveDashboardAsButton = ({ dashboard, onClick, onSaveSuccess, varia
variant={variant}
aria-label={selectors.pages.Dashboard.Settings.General.saveAsDashBoard}
>
Save as
<Trans i18nKey="dashboard.save-dashboard-as-button.save-as">Save as</Trans>
</Button>
);
}}

@ -2,6 +2,7 @@ import { ReactElement } from 'react';
import { useAsync } from 'react-use';
import { Alert, Box, Spinner, Stack } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { Diffs } from 'app/features/dashboard-scene/settings/version-history/utils';
import { DiffGroup } from '../../../dashboard-scene/settings/version-history/DiffGroup';
@ -95,12 +96,18 @@ export const SaveDashboardDiff = ({
{!hasMigratedToV2 && value && value.schemaChange && value.schemaChange}
{value && value.showDiffs && value.diffs}
<Box paddingTop={1}>
<h4>Full JSON diff</h4>
<h4>
<Trans i18nKey="dashboard.save-dashboard-diff.full-json-diff">Full JSON diff</Trans>
</h4>
{value.jsonView}
</Box>
</>
) : (
<Box paddingTop={1}>No changes in the dashboard JSON</Box>
<Box paddingTop={1}>
<Trans i18nKey="dashboard.save-dashboard-diff.no-changes-in-the-dashboard-json">
No changes in the dashboard JSON
</Trans>
</Box>
)}
</Stack>
);

@ -37,7 +37,7 @@ export const SaveDashboardErrorProxy = ({
{error.data && error.data.status === 'version-mismatch' && (
<ConfirmModal
isOpen={true}
title="Conflict"
title={t('dashboard.save-dashboard-error-proxy.title-conflict', 'Conflict')}
body={
<div>
Someone else has updated this dashboard <br /> <small>Would you still like to save this dashboard?</small>
@ -74,7 +74,7 @@ export const SaveDashboardErrorProxy = ({
) : (
<ConfirmModal
isOpen={true}
title="Conflict"
title={t('dashboard.save-dashboard-error-proxy.title-conflict', 'Conflict')}
body={
<div>
A dashboard with the same name in selected folder already exists. <br />
@ -109,7 +109,13 @@ const ConfirmPluginDashboardSaveModal = ({ onDismiss, dashboard }: SaveDashboard
const styles = useStyles2(getConfirmPluginDashboardSaveModalStyles);
return (
<Modal className={styles.modal} title="Plugin dashboard" icon="copy" isOpen={true} onDismiss={onDismiss}>
<Modal
className={styles.modal}
title={t('dashboard.confirm-plugin-dashboard-save-modal.title-plugin-dashboard', 'Plugin dashboard')}
icon="copy"
isOpen={true}
onDismiss={onDismiss}
>
<div className={styles.modalText}>
Your changes will be lost when you update the plugin.
<br />
@ -119,7 +125,7 @@ const ConfirmPluginDashboardSaveModal = ({ onDismiss, dashboard }: SaveDashboard
</div>
<Modal.ButtonRow>
<Button variant="secondary" onClick={onDismiss} fill="outline">
Cancel
<Trans i18nKey="dashboard.confirm-plugin-dashboard-save-modal.cancel">Cancel</Trans>
</Button>
<SaveDashboardAsButton onClick={onDismiss} dashboard={dashboard} onSaveSuccess={onDismiss} />
<Button
@ -129,7 +135,7 @@ const ConfirmPluginDashboardSaveModal = ({ onDismiss, dashboard }: SaveDashboard
onDismiss();
}}
>
Overwrite
<Trans i18nKey="dashboard.confirm-plugin-dashboard-save-modal.overwrite">Overwrite</Trans>
</Button>
</Modal.ButtonRow>
</Modal>

@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { Button, Modal } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { DashboardModel } from '../../state/DashboardModel';
@ -17,20 +18,22 @@ export const UnsavedChangesModal = ({ dashboard, onSaveSuccess, onDiscard, onDis
return (
<Modal
isOpen={true}
title="Unsaved changes"
title={t('dashboard.unsaved-changes-modal.title-unsaved-changes', 'Unsaved changes')}
onDismiss={onDismiss}
icon="exclamation-triangle"
className={css({
width: '500px',
})}
>
<h5>Do you want to save your changes?</h5>
<h5>
<Trans i18nKey="dashboard.unsaved-changes-modal.changes">Do you want to save your changes?</Trans>
</h5>
<Modal.ButtonRow>
<Button variant="secondary" onClick={onDismiss} fill="outline">
Cancel
<Trans i18nKey="dashboard.unsaved-changes-modal.cancel">Cancel</Trans>
</Button>
<Button variant="destructive" onClick={onDiscard}>
Discard
<Trans i18nKey="dashboard.unsaved-changes-modal.discard">Discard</Trans>
</Button>
<SaveDashboardButton dashboard={dashboard} onSaveSuccess={onSaveSuccess} />
</Modal.ButtonRow>

@ -3,6 +3,7 @@ import { ChangeEvent } from 'react';
import { config } from '@grafana/runtime';
import { Button, Input, Switch, Form, Field, InputControl, Label, TextArea, Stack } from '@grafana/ui';
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
import { Trans, t } from 'app/core/internationalization';
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv';
@ -111,7 +112,9 @@ export const SaveDashboardAsForm = ({
<Field
label={
<Stack justifyContent="space-between">
<Label htmlFor="title">Title</Label>
<Label htmlFor="title">
<Trans i18nKey="dashboard.save-dashboard-as-form.title">Title</Trans>
</Label>
{config.featureToggles.dashgpt && isNew && (
<GenAIDashTitleButton onGenerate={(title) => field.onChange(title)} />
)}
@ -123,7 +126,10 @@ export const SaveDashboardAsForm = ({
<Input
{...field}
onChange={(e: ChangeEvent<HTMLInputElement>) => field.onChange(e.target.value)}
aria-label="Save dashboard title field"
aria-label={t(
'dashboard.save-dashboard-as-form.aria-label-save-dashboard-title-field',
'Save dashboard title field'
)}
autoFocus
/>
</Field>
@ -139,7 +145,9 @@ export const SaveDashboardAsForm = ({
<Field
label={
<Stack justifyContent="space-between">
<Label htmlFor="description">Description</Label>
<Label htmlFor="description">
<Trans i18nKey="dashboard.save-dashboard-as-form.description">Description</Trans>
</Label>
{config.featureToggles.dashgpt && isNew && (
<GenAIDashDescriptionButton onGenerate={(description) => field.onChange(description)} />
)}
@ -151,7 +159,10 @@ export const SaveDashboardAsForm = ({
<TextArea
{...field}
onChange={(e: ChangeEvent<HTMLTextAreaElement>) => field.onChange(e.target.value)}
aria-label="Save dashboard description field"
aria-label={t(
'dashboard.save-dashboard-as-form.aria-label-save-dashboard-description-field',
'Save dashboard description field'
)}
autoFocus
/>
</Field>
@ -159,7 +170,7 @@ export const SaveDashboardAsForm = ({
control={control}
name="description"
/>
<Field label="Folder">
<Field label={t('dashboard.save-dashboard-as-form.label-folder', 'Folder')}>
<InputControl
render={({ field: { ref, ...field } }) => (
<FolderPicker
@ -177,15 +188,22 @@ export const SaveDashboardAsForm = ({
/>
</Field>
{!isNew && (
<Field label="Copy tags">
<Field label={t('dashboard.save-dashboard-as-form.label-copy-tags', 'Copy tags')}>
<Switch {...register('copyTags')} />
</Field>
)}
<Stack>
<Button type="button" variant="secondary" onClick={onCancel} fill="outline">
Cancel
<Trans i18nKey="dashboard.save-dashboard-as-form.cancel">Cancel</Trans>
</Button>
<Button disabled={isLoading} type="submit" aria-label="Save dashboard button">
<Button
disabled={isLoading}
type="submit"
aria-label={t(
'dashboard.save-dashboard-as-form.aria-label-save-dashboard-button',
'Save dashboard button'
)}
>
{isLoading ? 'Saving...' : 'Save'}
</Button>
</Stack>

@ -148,7 +148,7 @@ describe('SaveDashboardAsForm', () => {
/>
);
const messageTextArea = screen.getByLabelText('message');
const messageTextArea = screen.getByPlaceholderText('Add a note to describe your changes.');
expect(messageTextArea).toBeInTheDocument();
expect(messageTextArea).toHaveTextContent('Saved draft');

@ -6,6 +6,7 @@ import { selectors } from '@grafana/e2e-selectors';
import { config } from '@grafana/runtime';
import { Dashboard } from '@grafana/schema';
import { Button, Checkbox, TextArea, useStyles2, Stack } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
import { SaveDashboardResponseDTO } from 'app/types';
@ -72,7 +73,10 @@ export const SaveDashboardForm = ({
saveTimerange: !options.saveTimerange,
})
}
label="Save current time range as dashboard default"
label={t(
'dashboard.save-dashboard-form.label-current-range-dashboard-default',
'Save current time range as dashboard default'
)}
aria-label={selectors.pages.SaveDashboardModal.saveTimerange}
/>
)}
@ -85,7 +89,10 @@ export const SaveDashboardForm = ({
saveVariables: !options.saveVariables,
})
}
label="Save current variable values as dashboard default"
label={t(
'dashboard.save-dashboard-form.label-current-variable-values-dashboard-default',
'Save current variable values as dashboard default'
)}
aria-label={selectors.pages.SaveDashboardModal.saveVariables}
/>
)}
@ -104,7 +111,6 @@ export const SaveDashboardForm = ({
/>
)}
<TextArea
aria-label="message"
value={message}
onChange={(e) => {
onOptionsChange({
@ -113,7 +119,10 @@ export const SaveDashboardForm = ({
});
setMessage(e.currentTarget.value);
}}
placeholder="Add a note to describe your changes."
placeholder={t(
'dashboard.save-dashboard-form.placeholder-describe-changes',
'Add a note to describe your changes.'
)}
autoFocus
rows={5}
/>
@ -121,7 +130,7 @@ export const SaveDashboardForm = ({
<Stack alignItems="center">
<Button variant="secondary" onClick={onCancel} fill="outline">
Cancel
<Trans i18nKey="dashboard.save-dashboard-form.cancel">Cancel</Trans>
</Button>
<Button
type="submit"
@ -131,7 +140,11 @@ export const SaveDashboardForm = ({
>
{isLoading ? 'Saving...' : 'Save'}
</Button>
{!saveModel.hasChanges && <div>No changes to save</div>}
{!saveModel.hasChanges && (
<div>
<Trans i18nKey="dashboard.save-dashboard-form.no-changes-to-save">No changes to save</Trans>
</div>
)}
</Stack>
</Stack>
</form>

@ -3,6 +3,7 @@ import { saveAs } from 'file-saver';
import { useCallback, useState } from 'react';
import { Button, ClipboardButton, HorizontalGroup, TextArea, Stack } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { SaveDashboardFormProps } from '../types';
@ -52,13 +53,15 @@ export const SaveProvisionedDashboardForm = ({ dashboard, onCancel }: Omit<SaveD
/>
<HorizontalGroup>
<Button variant="secondary" onClick={onCancel} fill="outline">
Cancel
<Trans i18nKey="dashboard.save-provisioned-dashboard-form.cancel">Cancel</Trans>
</Button>
<ClipboardButton icon="copy" getText={() => dashboardJSON}>
Copy JSON to clipboard
<Trans i18nKey="dashboard.save-provisioned-dashboard-form.copy-json-to-clipboard">
Copy JSON to clipboard
</Trans>
</ClipboardButton>
<Button type="submit" onClick={saveToFile}>
Save JSON to file
<Trans i18nKey="dashboard.save-provisioned-dashboard-form.save-json-to-file">Save JSON to file</Trans>
</Button>
</HorizontalGroup>
</Stack>

@ -190,7 +190,8 @@ export const EmailSharingConfiguration = ({ dashboard }: { dashboard: DashboardM
<div className={styles.emailContainer}>
<Input
className={styles.emailInput}
placeholder="email"
// eslint-disable-next-line @grafana/no-untranslated-strings
placeholder="me@example.com"
autoCapitalize="none"
{...register('email', {
required: t('public-dashboard.email-sharing.input-required-email-text', 'Email is required'),

@ -2,7 +2,7 @@ import { useCallback } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { ClipboardButton, CodeEditor, Modal } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions';
export interface ViewJsonModalProps {
@ -13,7 +13,12 @@ export interface ViewJsonModalProps {
export function ViewJsonModal({ json, onDismiss }: ViewJsonModalProps): JSX.Element {
const getClipboardText = useCallback(() => json, [json]);
return (
<Modal title="JSON" onDismiss={onDismiss} onClickBackdrop={onDismiss} isOpen>
<Modal
title={t('dashboard.view-json-modal.title-json', 'JSON')}
onDismiss={onDismiss}
onClickBackdrop={onDismiss}
isOpen
>
<AutoSizer disableHeight>
{({ width }) => <CodeEditor value={json} language="json" showMiniMap={false} height="500px" width={width} />}
</AutoSizer>

@ -6,6 +6,7 @@ import { connect, MapStateToProps } from 'react-redux';
import { AnnotationQuery, DataQuery, TypedVariableModel, GrafanaTheme2 } from '@grafana/data';
import { DashboardLink } from '@grafana/schema';
import { stylesFactory, Themeable2, withTheme2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { StoreState } from '../../../../types';
import { getSubMenuVariables, getVariablesState } from '../../../variables/state/selectors';
@ -56,7 +57,11 @@ class SubMenuUnConnected extends PureComponent<Props> {
return (
<div className={styles.submenu}>
<form aria-label="Template variables" className={styles.formStyles} onSubmit={this.disableSubmitOnEnter}>
<form
aria-label={t('dashboard.sub-menu-un-connected.aria-label-template-variables', 'Template variables')}
className={styles.formStyles}
onSubmit={this.disableSubmitOnEnter}
>
<SubMenuItems variables={variables} readOnly={readOnlyVariables} />
</form>
<Annotations

@ -4,6 +4,7 @@ import { createElement, useMemo } from 'react';
import { DataFrame, DataTransformerConfig, GrafanaTheme2, TransformerRegistryItem } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Icon, JSONFormatter, useStyles2, Drawer } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { TransformationsEditorTransformation } from './types';
@ -50,13 +51,19 @@ export const TransformationEditor = ({
<div data-testid={selectors.components.TransformTab.transformationEditor(uiConfig.name)}>
{editor}
{debugMode && (
<Drawer title="Debug transformation" subtitle={uiConfig.name} onClose={toggleShowDebug}>
<Drawer
title={t('dashboard.transformation-editor.title-debug-transformation', 'Debug transformation')}
subtitle={uiConfig.name}
onClose={toggleShowDebug}
>
<div
className={styles.debugWrapper}
data-testid={selectors.components.TransformTab.transformationEditorDebugger(uiConfig.name)}
>
<div className={styles.debug}>
<div className={styles.debugTitle}>Input data</div>
<div className={styles.debugTitle}>
<Trans i18nKey="dashboard.transformation-editor.input-data">Input data</Trans>
</div>
<div className={styles.debugJson}>
<JSONFormatter json={input} />
</div>
@ -65,7 +72,9 @@ export const TransformationEditor = ({
<Icon name="arrow-right" />
</div>
<div className={styles.debug}>
<div className={styles.debugTitle}>Output data</div>
<div className={styles.debugTitle}>
<Trans i18nKey="dashboard.transformation-editor.output-data">Output data</Trans>
</div>
<div className={styles.debugJson}>{output && <JSONFormatter json={output} />}</div>
</div>
</div>

@ -4,6 +4,7 @@ import { useMemo } from 'react';
import { DataFrame, DataTransformerConfig, GrafanaTheme2 } from '@grafana/data';
import { DataTopic } from '@grafana/schema';
import { Field, Select, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { FrameMultiSelectionEditor } from 'app/plugins/panel/geomap/editor/FrameSelectionEditor';
interface TransformationFilterProps {
@ -33,7 +34,7 @@ export const TransformationFilter = ({ index, annotations, config, onChange, dat
return (
<div className={styles.wrapper}>
<Field label="Apply transformation to">
<Field label={t('dashboard.transformation-filter.label-apply-transformation-to', 'Apply transformation to')}>
<>
{opts.showTopic && (
<Select

@ -20,6 +20,7 @@ import {
} from 'app/core/components/QueryOperationRow/QueryOperationAction';
import { QueryOperationRow } from 'app/core/components/QueryOperationRow/QueryOperationRow';
import config from 'app/core/config';
import { t } from 'app/core/internationalization';
import { PluginStateInfo } from 'app/features/plugins/components/PluginStateInfo';
import { TransformationEditor } from './TransformationEditor';
@ -151,7 +152,10 @@ export const TransformationOperationRow = ({
<>
{uiConfig.state && <PluginStateInfo state={uiConfig.state} />}
<QueryOperationToggleAction
title="Show transform help"
title={t(
'dashboard.transformation-operation-row.render-actions.title-show-transform-help',
'Show transform help'
)}
icon="info-circle"
// `instrumentToggleCallback` expects a function that takes a MouseEvent, is unused in the state setter. Instead, we simply toggle the state.
onClick={instrumentToggleCallback(toggleShowHelp, 'help', showHelp)}
@ -159,27 +163,30 @@ export const TransformationOperationRow = ({
/>
{showFilterToggle && (
<QueryOperationToggleAction
title="Filter"
title={t('dashboard.transformation-operation-row.render-actions.title-filter', 'Filter')}
icon="filter"
onClick={instrumentToggleCallback(toggleFilter, 'filter', showFilterEditor)}
active={showFilterEditor}
/>
)}
<QueryOperationToggleAction
title="Debug"
title={t('dashboard.transformation-operation-row.render-actions.title-debug', 'Debug')}
icon="bug"
onClick={instrumentToggleCallback(toggleShowDebug, 'debug', showDebug)}
active={showDebug}
/>
<QueryOperationToggleAction
title="Disable transformation"
title={t(
'dashboard.transformation-operation-row.render-actions.title-disable-transformation',
'Disable transformation'
)}
icon={disabled ? 'eye-slash' : 'eye'}
onClick={instrumentToggleCallback(() => onDisableToggle(index), 'disabled', disabled)}
active={disabled}
dataTestId={selectors.components.Transforms.disableTransformationButton}
/>
<QueryOperationAction
title="Remove"
title={t('dashboard.transformation-operation-row.render-actions.title-remove', 'Remove')}
icon="trash-alt"
onClick={() => (config.featureToggles.transformationsRedesign ? setShowDeleteModal(true) : onRemove(index))}
/>

@ -5,6 +5,7 @@ import { DocsId, GrafanaTheme2, TransformerRegistryItem } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Card, Container, VerticalGroup, Alert, Input, useStyles2 } from '@grafana/ui';
import { LocalStorageValueProvider } from 'app/core/components/LocalStorageValueProvider';
import { t, Trans } from 'app/core/internationalization';
import { getDocsLink } from 'app/core/utils/docsLinks';
import { PluginStateInfo } from 'app/features/plugins/components/PluginStateInfo';
@ -35,7 +36,7 @@ export function TransformationPicker(props: TransformationPickerProps) {
return (
<Alert
title="Transformations"
title={t('dashboard.transformation-picker.title-transformations', 'Transformations')}
severity="info"
onRemove={() => {
onDismiss(true);
@ -54,7 +55,7 @@ export function TransformationPicker(props: TransformationPickerProps) {
target="_blank"
rel="noreferrer"
>
Read more
<Trans i18nKey="dashboard.transformation-picker.read-more">Read more</Trans>
</a>
</Alert>
);
@ -66,7 +67,10 @@ export function TransformationPicker(props: TransformationPickerProps) {
data-testid={selectors.components.Transforms.searchInput}
value={search ?? ''}
autoFocus={!noTransforms}
placeholder="Search for transformation"
placeholder={t(
'dashboard.transformation-picker.placeholder-search-for-transformation',
'Search for transformation'
)}
onChange={onSearchChange}
onKeyDown={onSearchKeyDown}
suffix={suffix}

@ -13,6 +13,7 @@ import {
import { selectors } from '@grafana/e2e-selectors';
import { Card, Drawer, FilterPill, IconButton, Input, Switch, useStyles2 } from '@grafana/ui';
import config from 'app/core/config';
import { t, Trans } from 'app/core/internationalization';
import { PluginStateInfo } from 'app/features/plugins/components/PluginStateInfo';
import { categoriesLabels } from 'app/features/transformers/utils';
@ -71,14 +72,17 @@ export function TransformationPickerNg(props: TransformationPickerNgProps) {
onClose={() => {
onClose && onClose();
}}
title="Add another transformation"
title={t('dashboard.transformation-picker-ng.title-add-another-transformation', 'Add another transformation')}
>
<div className={styles.searchWrapper}>
<Input
data-testid={selectors.components.Transforms.searchInput}
className={styles.searchInput}
value={search ?? ''}
placeholder="Search for transformation"
placeholder={t(
'dashboard.transformation-picker-ng.placeholder-search-for-transformation',
'Search for transformation'
)}
onChange={onSearchChange}
onKeyDown={onSearchKeyDown}
suffix={suffix}
@ -86,7 +90,9 @@ export function TransformationPickerNg(props: TransformationPickerNgProps) {
autoFocus={true}
/>
<div className={styles.showImages}>
<span className={styles.illustationSwitchLabel}>Show images</span>{' '}
<span className={styles.illustationSwitchLabel}>
<Trans i18nKey="dashboard.transformation-picker-ng.show-images">Show images</Trans>
</span>{' '}
<Switch
value={showIllustrations}
onChange={() => onShowIllustrationsChange && onShowIllustrationsChange(!showIllustrations)}

@ -24,6 +24,7 @@ import {
ScrollContainer,
} from '@grafana/ui';
import config from 'app/core/config';
import { t, Trans } from 'app/core/internationalization';
import { EmptyTransformationsMessage } from 'app/features/dashboard-scene/panel-edit/PanelDataPane/EmptyTransformationsMessage';
import { PanelModel } from '../../state/PanelModel';
@ -334,7 +335,7 @@ class UnThemedTransformationsEditor extends React.PureComponent<TransformationsE
onClick={() => {
this.setState({ search: '' });
}}
tooltip="Clear search"
tooltip={t('dashboard.un-themed-transformations-editor.tooltip-clear-search', 'Clear search')}
/>
</>
);
@ -349,7 +350,7 @@ class UnThemedTransformationsEditor extends React.PureComponent<TransformationsE
onClick={() => {
this.setState({ showPicker: false });
}}
tooltip="Close picker"
tooltip={t('dashboard.un-themed-transformations-editor.tooltip-close-picker', 'Close picker')}
/>
);
}
@ -386,11 +387,16 @@ class UnThemedTransformationsEditor extends React.PureComponent<TransformationsE
onClick={() => this.setState({ showRemoveAllModal: true })}
style={{ marginLeft: this.props.theme.spacing.md }}
>
Delete all transformations
<Trans i18nKey="dashboard.un-themed-transformations-editor.delete-all-transformations">
Delete all transformations
</Trans>
</Button>
<ConfirmModal
isOpen={Boolean(this.state.showRemoveAllModal)}
title="Delete all transformations?"
title={t(
'dashboard.un-themed-transformations-editor.title-delete-all-transformations',
'Delete all transformations?'
)}
body="By deleting all transformations, you will go back to the main selection screen."
confirmText="Delete all"
onConfirm={() => this.onTransformationRemoveAll()}
@ -427,7 +433,9 @@ class UnThemedTransformationsEditor extends React.PureComponent<TransformationsE
}}
data-testid={selectors.components.Transforms.addTransformationButton}
>
Add another transformation
<Trans i18nKey="dashboard.un-themed-transformations-editor.actions.add-another-transformation">
Add another transformation
</Trans>
</Button>
{deleteAll}
</ButtonGroup>

@ -1,6 +1,7 @@
import { useEffect } from 'react';
import { ConfirmModal } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { useDashboardRestore } from './useDashboardRestore';
export interface RevertDashboardModalProps {
@ -22,7 +23,7 @@ export const RevertDashboardModal = ({ hideModal, id, version }: RevertDashboard
return (
<ConfirmModal
isOpen={true}
title="Restore Version"
title={t('dashboard.revert-dashboard-modal.title-restore-version', 'Restore version')}
icon="history"
onDismiss={hideModal}
onConfirm={onRestoreDashboard}

@ -2,6 +2,7 @@ import { css, cx } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, ModalsController, CollapsableSection, useStyles2, Stack, Icon, Box } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { DiffGroup } from 'app/features/dashboard-scene/settings/version-history/DiffGroup';
import { DiffViewer } from 'app/features/dashboard-scene/settings/version-history/DiffViewer';
import { jsonDiff } from 'app/features/dashboard-scene/settings/version-history/utils';
@ -61,7 +62,10 @@ export const VersionHistoryComparison = ({ baseInfo, newInfo, diffData, isNewLat
))}
<Box paddingTop={2}>
<CollapsableSection isOpen={false} label="View JSON Diff">
<CollapsableSection
isOpen={false}
label={t('dashboard.version-history-comparison.label-view-json-diff', 'View JSON diff')}
>
<DiffViewer
oldValue={JSON.stringify(diffData.lhs, null, 2)}
newValue={JSON.stringify(diffData.rhs, null, 2)}

@ -3,6 +3,7 @@ import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Checkbox, Button, Tag, ModalsController, useStyles2 } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { DecoratedRevisionModel } from '../DashboardSettings/VersionsSettings';
@ -23,10 +24,18 @@ export const VersionHistoryTable = ({ versions, canCompare, onCheck }: VersionsT
<thead>
<tr>
<th className="width-4"></th>
<th className="width-4">Version</th>
<th className="width-14">Date</th>
<th className="width-10">Updated by</th>
<th>Notes</th>
<th className="width-4">
<Trans i18nKey="dashboard.version-history-table.version">Version</Trans>
</th>
<th className="width-14">
<Trans i18nKey="dashboard.version-history-table.date">Date</Trans>
</th>
<th className="width-10">
<Trans i18nKey="dashboard.version-history-table.updated-by">Updated by</Trans>
</th>
<th>
<Trans i18nKey="dashboard.version-history-table.notes">Notes</Trans>
</th>
<th></th>
</tr>
</thead>
@ -66,7 +75,7 @@ export const VersionHistoryTable = ({ versions, canCompare, onCheck }: VersionsT
});
}}
>
Restore
<Trans i18nKey="dashboard.version-history-table.restore">Restore</Trans>
</Button>
)}
</ModalsController>

@ -6,6 +6,7 @@ import AutoSizer from 'react-virtualized-auto-sizer';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, useStyles2 } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
import { PanelModel } from 'app/features/dashboard/state/PanelModel';
@ -102,7 +103,11 @@ export const SoloPanel = ({ dashboard, notFound, panel, panelId, timezone }: Sol
}
if (!panel || !dashboard) {
return <div>Loading & initializing dashboard</div>;
return (
<div>
<Trans i18nKey="dashboard.solo-panel.loading-initializing-dashboard">Loading & initializing dashboard</Trans>
</div>
);
}
return (

@ -2,6 +2,7 @@ import { css } from '@emotion/css';
import { DataLink, GrafanaTheme2, LinkModel } from '@grafana/data';
import { Dropdown, Icon, Menu, ToolbarButton, useStyles2, PanelChrome } from '@grafana/ui';
import { t } from 'app/core/internationalization';
interface Props {
panelLinks: DataLink[];
@ -37,7 +38,12 @@ export function PanelLinks({ panelLinks, onShowPanelLinks }: Props) {
} else {
return (
<Dropdown overlay={getLinksContent}>
<ToolbarButton icon="external-link-alt" iconSize="md" aria-label="panel links" className={styles.menuTrigger} />
<ToolbarButton
icon="external-link-alt"
iconSize="md"
aria-label={t('dashboard.panel-links.aria-label-panel-links', 'Panel links')}
className={styles.menuTrigger}
/>
</Dropdown>
);
}

@ -1371,6 +1371,10 @@
"actions": {
"open-settings": "Settings"
},
"add-library-panel-widget": {
"aria-label-close-add-panel-widget": "Close 'Add Panel' widget",
"tooltip-close-widget": "Close widget"
},
"add-menu": {
"import": "Import from library",
"paste-panel": "Paste panel",
@ -1381,6 +1385,29 @@
"redirect-link": "List in Grafana Alerting",
"subtitle": "Alert rules related to this dashboard"
},
"annotation-settings-edit": {
"apply": "Apply",
"delete": "Delete",
"description-color-annotation-event-markers": "Color to use for the annotation event markers",
"description-enabled-annotation-query-issued-every-dashboard": "When enabled the annotation query is issued every dashboard refresh",
"label-color": "Color",
"label-data-source": "Data source",
"label-enabled": "Enabled",
"label-hidden": "Hidden",
"label-name": "Name",
"label-show-in": "Show in",
"placeholder-choose-panels": "Choose panels",
"preview-in-dashboard": "Preview in dashboard",
"query": "Query",
"title-annotation-support-source": "No annotation support for this data source"
},
"annotation-settings-list": {
"data-source": "Data source",
"new-query": "New query",
"query-name": "Query name",
"tooltip-move-down": "Move down",
"tooltip-move-up": "Move up"
},
"auto-grid": {
"description": "Panels resize to fit and form uniform grids",
"item-options": {
@ -1486,6 +1513,29 @@
"title": "Show / hide rules"
}
},
"confirm-plugin-dashboard-save-modal": {
"cancel": "Cancel",
"overwrite": "Overwrite",
"title-plugin-dashboard": "Plugin dashboard"
},
"dash-nav": {
"render-left-actions": {
"text-public": "Public"
}
},
"dashboard-loading": {
"cancel-loading-dashboard": "Cancel loading dashboard"
},
"dashboard-settings": {
"actions": {
"close": "Close"
}
},
"dashboard-validation": {
"title-checking-dashboard-validity": "Checking dashboard validity",
"title-dashboard-failed-schema-validation": "Dashboard failed schema validation",
"title-error-checking-dashboard-validity": "Error checking dashboard validity"
},
"default-layout": {
"description": "Position and size each panel individually",
"item-options": {
@ -1540,6 +1590,11 @@
"title": "Row options"
}
},
"dynamic-config-value-editor": {
"render-label": {
"tooltip-remove-property": "Remove property"
}
},
"edit-pane": {
"elements": {
"dashboard": "Dashboard",
@ -1573,6 +1628,24 @@
"errors": {
"failed-to-load": "Failed to load dashboard"
},
"gen-aihistory": {
"aria-label-send-custom-feedback": "Send custom feedback",
"placeholder-tell-ai-what-to-do-next": "Tell AI what to do next..."
},
"get-field-override-categories": {
"label-add-field-override": "Add field override",
"label-add-override-property": "Add override property"
},
"help-wizard": {
"copy-to-clipboard": "Copy to clipboard",
"label-obfuscate-data": "Obfuscate data",
"label-support-snapshot": "Support snapshot",
"label-template": "Template",
"randomize-field-names-label-field-names": "Field names",
"randomize-labels-label-labels": "Labels",
"randomize-string-values-label-string-values": "String values",
"title-complete-git-hub-comment-clipboard": "Copy a complete GitHub comment to the clipboard"
},
"inspect": {
"data-tab": "Data",
"error-tab": "Error",
@ -1635,6 +1708,14 @@
"layout": "Layout"
}
},
"make-editable": {
"dashboard-not-editable": "Dashboard not editable",
"make-editable": "Make editable"
},
"minimalistic-pagination": {
"tooltip-next": "Next",
"tooltip-previous": "Previous"
},
"new-panel": {
"configure-button": "Configure",
"menu-open-panel-editor": "Configure",
@ -1645,6 +1726,9 @@
"description": "Description",
"title-option": "Title"
},
"options-pane-options": {
"Recent options-title-recent-options": "Recent options"
},
"outline": {
"tree": {
"item": {
@ -1652,12 +1736,57 @@
}
}
},
"override-category-title": {
"aria-label-remove-override": "Remove override",
"tooltip-remove-override": "Remove override"
},
"panel-edit": {
"alerting-tab": {
"dashboard-not-saved": "Dashboard must be saved before alerts can be added.",
"no-rules": "There are no alert rules linked to this panel."
}
},
"panel-editor-table-view": {
"title-raw-data": "Raw data"
},
"panel-editor-unconnected": {
"editor-actions": {
"apply": "Apply",
"discard": "Discard",
"save": "Save",
"save-library-panel": "Save library panel",
"title-apply-changes-and-save-dashboard": "Apply changes and save dashboard",
"title-apply-changes-and-save-library-panel": "Apply changes and save library panel",
"title-apply-changes-dashboard": "Apply changes and go back to dashboard",
"title-undo-all-changes": "Undo all changes"
},
"table-view-label-table-view": "Table view",
"unlink": "Unlink"
},
"panel-links": {
"aria-label-panel-links": "Panel links"
},
"panel-not-supported": {
"go-back-to-queries": "Go back to Queries"
},
"public-dashboard-not-available": {
"try-again-later": "Try again later"
},
"revert-dashboard-modal": {
"title-restore-version": "Restore version"
},
"row-options-button": {
"aria-label-row-options": "Row options"
},
"row-options-form": {
"cancel": "Cancel",
"label-repeat-for": "Repeat for",
"label-title": "Title",
"update": "Update"
},
"row-options-modal": {
"title-row-options": "Row options"
},
"rows-layout": {
"description": "Collapsable panel groups with headings",
"header-hidden-tooltip": "Row header only visible in edit mode",
@ -1687,6 +1816,47 @@
"title-option": "Title"
}
},
"save-dashboard-as-button": {
"save-as": "Save as"
},
"save-dashboard-as-form": {
"aria-label-save-dashboard-button": "Save dashboard button",
"aria-label-save-dashboard-description-field": "Save dashboard description field",
"aria-label-save-dashboard-title-field": "Save dashboard title field",
"cancel": "Cancel",
"description": "Description",
"label-copy-tags": "Copy tags",
"label-folder": "Folder",
"title": "Title"
},
"save-dashboard-button": {
"save-dashboard": "Save dashboard"
},
"save-dashboard-diff": {
"full-json-diff": "Full JSON diff",
"no-changes-in-the-dashboard-json": "No changes in the dashboard JSON"
},
"save-dashboard-error-proxy": {
"title-conflict": "Conflict"
},
"save-dashboard-form": {
"cancel": "Cancel",
"label-current-range-dashboard-default": "Save current time range as dashboard default",
"label-current-variable-values-dashboard-default": "Save current variable values as dashboard default",
"no-changes-to-save": "No changes to save",
"placeholder-describe-changes": "Add a note to describe your changes."
},
"save-provisioned-dashboard-form": {
"cancel": "Cancel",
"copy-json-to-clipboard": "Copy JSON to clipboard",
"save-json-to-file": "Save JSON to file"
},
"solo-panel": {
"loading-initializing-dashboard": "Loading & initializing dashboard"
},
"sub-menu-un-connected": {
"aria-label-template-variables": "Template variables"
},
"tabs-layout": {
"description": "Organize panels into horizontal tabs",
"name": "Tabs",
@ -1821,12 +1991,79 @@
"unlink-library-panel": "Unlink library panel",
"unmark-favorite": "Unmark as favorite"
},
"transformation-editor": {
"input-data": "Input data",
"output-data": "Output data",
"title-debug-transformation": "Debug transformation"
},
"transformation-filter": {
"label-apply-transformation-to": "Apply transformation to"
},
"transformation-operation-row": {
"render-actions": {
"title-debug": "Debug",
"title-disable-transformation": "Disable transformation",
"title-filter": "Filter",
"title-remove": "Remove",
"title-show-transform-help": "Show transform help"
}
},
"transformation-picker": {
"placeholder-search-for-transformation": "Search for transformation",
"read-more": "Read more",
"title-transformations": "Transformations"
},
"transformation-picker-ng": {
"placeholder-search-for-transformation": "Search for transformation",
"show-images": "Show images",
"title-add-another-transformation": "Add another transformation"
},
"un-themed-transformations-editor": {
"actions": {
"add-another-transformation": "Add another transformation"
},
"delete-all-transformations": "Delete all transformations",
"title-delete-all-transformations": "Delete all transformations?",
"tooltip-clear-search": "Clear search",
"tooltip-close-picker": "Close picker"
},
"unsaved-changes-modal": {
"cancel": "Cancel",
"changes": "Do you want to save your changes?",
"discard": "Discard",
"title-unsaved-changes": "Unsaved changes"
},
"unthemed-dashboard-row": {
"aria-label-delete-row": "Delete row",
"learn-more": "Learn more"
},
"validation": {
"invalid-dashboard-id": "Could not find a valid Grafana.com ID",
"invalid-json": "Not valid JSON",
"tags-expected-array": "tags expected array",
"tags-expected-strings": "tags expected array of strings"
},
"version-history-comparison": {
"label-view-json-diff": "View JSON diff"
},
"version-history-table": {
"date": "Date",
"notes": "Notes",
"restore": "Restore",
"updated-by": "Updated by",
"version": "Version"
},
"view-json-modal": {
"title-json": "JSON"
},
"visualization-button": {
"aria-label-change-visualization": "Change visualization",
"tooltip-click-to-change-visualization": "Click to change visualization"
},
"visualization-select-pane": {
"placeholder-search-for": "Search for...",
"title-close": "Close"
},
"viz-panel": {
"options": {
"configure-button-tooltip": "Edit queries and visualization options",

Loading…
Cancel
Save