i18n: Fix all remaining alerting translation markup (#104103)

* alerting markup

* fix typo

* Fix remaining Alerting issues 🎉

* Enable no-untranslated-strings rule for alerting

* Fix i18n eslint rule for "fixed" areas of code

* Remove auto fixing

* kick CI

---------

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
This commit is contained in:
Tom Ratcliffe
2025-04-16 17:45:12 +01:00
committed by GitHub
co-authored by Ashley Harrison
parent fd830759ab
commit 0860867b84
47 changed files with 571 additions and 342 deletions
+4 -160
View File
@@ -967,10 +967,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
],
"public/app/features/alerting/unified/RedirectToRuleViewer.tsx:5381": [
[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/alerting/unified/components/AnnotationDetailsField.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
@@ -988,18 +984,6 @@ exports[`better eslint`] = {
"public/app/features/alerting/unified/components/alert-groups/GroupBy.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/features/alerting/unified/components/alert-groups/MatcherFilter.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/export/FileExportPreview.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/alerting/unified/components/receivers/TemplateDataDocs.tsx:5381": [
[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/alerting/unified/components/receivers/form/ChannelOptions.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
@@ -1029,158 +1013,23 @@ exports[`better eslint`] = {
"public/app/features/alerting/unified/components/rule-editor/AnnotationKeyInput.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/features/alerting/unified/components/rule-editor/DashboardAnnotationField.tsx:5381": [
[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/alerting/unified/components/rule-editor/DashboardPicker.tsx:5381": [
[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/alerting/unified/components/rule-editor/ExpressionEditor.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/features/alerting/unified/components/rule-editor/PreviewRule.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"public/app/features/alerting/unified/components/rule-editor/PreviewRuleResult.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/alerting/unified/components/rule-editor/QueryOptions.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/alerting/unified/components/rule-editor/QueryRows.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"]
],
"public/app/features/alerting/unified/components/rule-editor/QueryWrapper.tsx:5381": [
[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/alerting/unified/components/rule-editor/RecordingRuleEditor.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/features/alerting/unified/components/rule-editor/RuleInspector.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"]
],
"public/app/features/alerting/unified/components/rule-editor/alert-rule-form/AlertRuleForm.tsx:5381": [
[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/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteSettings.tsx:5381": [
[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/alerting/unified/components/rule-editor/notificaton-preview/NotificationRoute.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRouteDetailsModal.tsx:5381": [
[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/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx:5381": [
[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/alerting/unified/components/rule-editor/query-and-alert-condition/SmartAlertTypeDetector.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"],
[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/alerting/unified/components/rule-editor/rule-types/GrafanaManagedAlert.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/rule-editor/rule-types/MimirOrLokiAlert.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/rule-editor/rule-types/MimirOrLokiRecordingRule.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/rule-editor/rule-types/RuleTypePicker.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/rule-viewer/FederatedRuleWarning.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/rule-viewer/PausedBadge.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/rules/AlertStateTag.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/rules/CloneRule.tsx:5381": [
[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/alerting/unified/components/rules/Filter/RulesFilter.v1.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/alerting/unified/components/rules/RuleConfigStatus.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/rules/RuleDetailsMatchingInstances.tsx:5381": [
[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/alerting/unified/components/rules/RuleListErrors.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"],
[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/alerting/unified/components/rules/RuleState.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/rules/RulesGroup.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/rules/state-history/LokiStateHistory.tsx:5381": [
[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/alerting/unified/components/rules/state-history/StateHistory.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/silences/SilencedAlertsTableRow.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/components/silences/SilencedInstancesPreview.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/features/alerting/unified/components/silences/SilencesEditor.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/features/alerting/unified/components/silences/SilencesFilter.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"]
],
"public/app/features/alerting/unified/components/silences/SilencesTable.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
],
"public/app/features/alerting/unified/home/Insights.tsx:5381": [
[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/alerting/unified/home/PluginIntegrations.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/features/alerting/unified/hooks/useAlertmanagerConfig.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
@@ -1189,12 +1038,7 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"public/app/features/alerting/unified/insights/InsightsMenuButton.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"]
],
"public/app/features/alerting/unified/rule-list/RuleList.v1.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, "Do not use any type assertions.", "0"]
],
"public/app/features/alerting/unified/types/receiver-form.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
+13
View File
@@ -256,6 +256,7 @@ module.exports = [
plugins: {
unicorn: unicornPlugin,
react: reactPlugin,
'@grafana': grafanaPlugin,
},
files: ['public/app/features/alerting/**/*.{ts,tsx,js,jsx}'],
rules: {
@@ -268,6 +269,18 @@ module.exports = [
'unicorn/no-unused-properties': 'error',
},
},
{
// Sections of codebase that have all translation markup issues fixed
name: 'grafana/i18n-overrides',
plugins: {
'@grafana': grafanaPlugin,
},
files: ['public/app/features/alerting/**/*.{ts,tsx,js,jsx}'],
ignores: ['**/*.{spec,test}.tsx'],
rules: {
'@grafana/no-untranslated-strings': 'error',
},
},
{
name: 'grafana/alerting-test-overrides',
plugins: {
@@ -6,7 +6,7 @@ import { useLocation } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
import { config, isFetchError } from '@grafana/runtime';
import { Alert, Card, Icon, LoadingPlaceholder, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import { AlertLabels } from './components/AlertLabels';
import { RuleViewerLayout } from './components/rule-viewer/RuleViewerLayout';
@@ -110,8 +110,10 @@ export function RedirectToRuleViewer(): JSX.Element | null {
return (
<RuleViewerLayout title={pageTitle}>
<div data-testid="no-rules">
No rules in <span className={styles.param}>{sourceName}</span> matched the name{' '}
<span className={styles.param}>{name}</span>
<Trans i18nKey="alerting.redirect-to-rule-viewer.no-rules-found" values={{ sourceName, name }}>
No rules in <span className={styles.param}>{'{{sourceName}}'}</span> matched the name{' '}
<span className={styles.param}>{'{{name}}'}</span>
</Trans>
</div>
</RuleViewerLayout>
);
@@ -120,8 +122,10 @@ export function RedirectToRuleViewer(): JSX.Element | null {
return (
<RuleViewerLayout title={pageTitle}>
<div>
Several rules in <span className={styles.param}>{sourceName}</span> matched the name{' '}
<span className={styles.param}>{name}</span>, please select the rule you want to view.
<Trans i18nKey="alerting.redirect-to-rule-viewer.several-rules-found" values={{ sourceName, name }}>
Several rules in <span className={styles.param}>{'{{sourceName}}'}</span> matched the name{' '}
<span className={styles.param}>{'{{name}}'}</span>, please select the rule you want to view.
</Trans>
</div>
<div className={styles.rules}>
{rules.map((rule, index) => {
@@ -54,14 +54,18 @@ export const MatcherFilter = ({ onFilterChange, defaultQueryString }: Props) =>
<Tooltip
content={
<div>
Filter alerts using label querying without spaces, ex:
<Trans i18nKey="alerting.matcher-filter.filter-alerts-using-label-querying-without-spaces">
Filter alerts using label querying without spaces, ex:
</Trans>
<pre>{`{severity="critical", instance=~"cluster-us-.+"}`}</pre>
Invalid use of spaces:
<Trans i18nKey="alerting.matcher-filter.invalid-use-of-spaces">Invalid use of spaces:</Trans>
<pre>{`{severity= "critical"}`}</pre>
<pre>{`{severity ="critical"}`}</pre>
Valid use of spaces:
<Trans i18nKey="alerting.matcher-filter.valid-use-of-spaces">Valid use of spaces:</Trans>
<pre>{`{severity=" critical"}`}</pre>
Filter alerts using label querying without braces, ex:
<Trans i18nKey="alerting.matcher-filter.filter-alerts-using-label-querying-without-braces">
Filter alerts using label querying without braces, ex:
</Trans>
<pre>{`severity="critical", instance=~"cluster-us-.+"`}</pre>
</div>
}
@@ -98,43 +98,43 @@ function FileExportInlineDocumentation({ exportProvider }: { exportProvider: Exp
file: {
title: 'File-provisioning format',
component: (
<>
{name} format is only valid for File Provisioning.{' '}
<Trans i18nKey="alerting.file-export-inline-documentation.file-provisioning">
{{ name }} format is only valid for File Provisioning.{' '}
<TextLink
href="https://grafana.com/docs/grafana/latest/alerting/set-up/provision-alerting-resources/file-provisioning/"
external
>
Read more in the docs.
</TextLink>
</>
</Trans>
),
},
api: {
title: 'API-provisioning format',
component: (
<>
{name} format is only valid for API Provisioning.{' '}
<Trans i18nKey="alerting.file-export-inline-documentation.api-provisioning">
{{ name }} format is only valid for API Provisioning.{' '}
<TextLink
href="https://grafana.com/docs/grafana/latest/alerting/set-up/provision-alerting-resources/http-api-provisioning/"
external
>
Read more in the docs.
</TextLink>
</>
</Trans>
),
},
terraform: {
title: 'Terraform-provisioning format',
component: (
<>
{name} format is only valid for Terraform Provisioning.{' '}
<Trans i18nKey="alerting.file-export-inline-documentation.terraform-provisioning">
{{ name }} format is only valid for Terraform Provisioning.{' '}
<TextLink
href="https://grafana.com/docs/grafana/latest/alerting/set-up/provision-alerting-resources/terraform-provisioning/"
external
>
Read more in the docs.
</TextLink>
</>
</Trans>
),
},
};
@@ -2,7 +2,7 @@ import { css } from '@emotion/css';
import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Stack, useStyles2 } from '@grafana/ui';
import { Stack, Text, useStyles2 } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { PopupCard } from '../HoverCard';
@@ -21,9 +21,18 @@ export function TemplateDataDocs() {
const AlertTemplateDataTable = (
<TemplateDataTable
caption={
<h4 className={styles.header}>
Alert template data <span>Available only when in the context of an Alert (e.g. inside .Alerts loop)</span>
</h4>
<>
<Text variant="h4" element="h4" color="primary">
<Trans i18nKey="alerting.template-data-docs.alert-template-data-table.alert-template-data">
Alert template data
</Trans>
</Text>
<Text variant="bodySmall">
<Trans i18nKey="alerting.template-data-docs.alert-template-data-table.only-in-alert">
Available only when in the context of an Alert (e.g. inside .Alerts loop)
</Trans>
</Text>
</>
}
dataItems={AlertTemplateData}
/>
@@ -33,9 +42,16 @@ export function TemplateDataDocs() {
<Stack gap={2}>
<TemplateDataTable
caption={
<h4 className={styles.header}>
Notification template data <span>Available in the context of a notification.</span>{' '}
</h4>
<>
<Text variant="h4" element="h4" color="primary">
<Trans i18nKey="alerting.template-data-docs.notification-template-data">Notification template data</Trans>
</Text>
<Text variant="bodySmall">
<Trans i18nKey="alerting.template-data-docs.available-context-notification">
Available in the context of a notification.
</Trans>
</Text>
</>
}
dataItems={GlobalTemplateData}
typeRenderer={(type) =>
@@ -56,15 +72,7 @@ export function TemplateDataDocs() {
);
}
export const getTemplateDataDocsStyles = (theme: GrafanaTheme2) => ({
header: css({
color: theme.colors.text.primary,
span: {
color: theme.colors.text.secondary,
fontSize: theme.typography.bodySmall.fontSize,
},
}),
const getTemplateDataDocsStyles = (theme: GrafanaTheme2) => ({
interactiveType: css({
color: theme.colors.text.link,
}),
@@ -1,7 +1,8 @@
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, useStyles2 } from '@grafana/ui';
import { Icon, Text, useStyles2 } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { DashboardDataDTO } from 'app/types';
import { makeDashboardLink, makePanelLink } from '../../utils/misc';
@@ -41,7 +42,13 @@ const DashboardAnnotationField = ({
</a>
)}
{!dashboard && <span className={styles.noLink}>Dashboard {dashboardUid} </span>}
{!dashboard && (
<Text color="secondary">
<Trans i18nKey="alerting.annotations.dashboard-annotation-field.dashboard" values={{ dashboardUid }}>
Dashboard {{ dashboardUid }}
</Trans>
</Text>
)}
{panel && (
<a href={panelLink} className={styles.link} target="_blank" rel="noreferrer" data-testid="panel-annotation">
@@ -49,7 +56,16 @@ const DashboardAnnotationField = ({
</a>
)}
{!panel && <span className={styles.noLink}> - Panel {panelId}</span>}
{!panel && (
<>
<span> - </span>
<Text color="secondary">
<Trans i18nKey="alerting.annotations.dashboard-annotation-field.panel" values={{ panelId }}>
Panel {{ panelId }}
</Trans>
</Text>
</>
)}
{(dashboard || panel) && (
<>
@@ -166,6 +166,8 @@ export const DashboardPicker = ({ dashboardUid, panelId, isOpen, onChange, onDis
);
};
const fallbackDashboardsString = t('alerting.dashboard-picker.fallback-dashboards-string', 'Dashboards');
return (
<Modal
title={t('alerting.dashboard-picker.title-select-dashboard-and-panel', 'Select dashboard and panel')}
@@ -185,12 +187,25 @@ export const DashboardPicker = ({ dashboardUid, panelId, isOpen, onChange, onDis
className={styles.modalAlert}
>
<div>
Dashboard: {dashboardModel.title} ({dashboardModel.uid}) in folder{' '}
{dashboardModel.meta?.folderTitle ?? 'Dashboards'}
<Trans
i18nKey="alerting.dashboard-picker.current-selection-dashboard"
values={{
dashboardTitle: dashboardModel.title,
dashboardUid: dashboardModel.uid,
folderTitle: dashboardModel.meta?.folderTitle ?? fallbackDashboardsString,
}}
>
Dashboard: {'{{dashboardTitle}}'} ({'{{ dashboardUid }}'}) in folder {'{{ folderTitle }}'}
</Trans>
</div>
{currentPanel && (
<div>
Panel: {currentPanel.title} ({currentPanel.id})
<Trans
i18nKey="alerting.dashboard-picker.current-selection-panel"
values={{ panelTitle: currentPanel.title, panelId: currentPanel.id }}
>
Panel: {'{{ panelTitle }}'} ({'{{ panelId }}'})
</Trans>
</div>
)}
</Alert>
@@ -5,7 +5,7 @@ import AutoSizer from 'react-virtualized-auto-sizer';
import { FieldConfigSource, FieldMatcherID, GrafanaTheme2, LoadingState } from '@grafana/data';
import { PanelRenderer } from '@grafana/runtime';
import { TableCellDisplayMode, useStyles2 } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import { PreviewRuleResponse } from '../../types/preview';
import { RuleFormType } from '../../types/rule-form';
@@ -47,16 +47,23 @@ export function PreviewRuleResult(props: Props): React.ReactElement | null {
if (data.state === LoadingState.Error) {
return (
<div className={styles.container}>
{data.error ? messageFromError(data.error) : 'Failed to preview alert rule'}
{data.error
? messageFromError(data.error)
: t('alerting.preview-rule-result.preview-failed', 'Failed to preview alert rule')}
</div>
);
}
return (
<div className={styles.container}>
<span>
Preview based on the result of running the query, for this moment.{' '}
{ruleType === RuleFormType.grafana ? 'Configuration for `no data` and `error handling` is not applied.' : null}
</span>
<Trans i18nKey="alerting.preview-rule-result.preview-based-on-query-result">
Preview based on the result of running the query, for this moment.
</Trans>
{ruleType === RuleFormType.grafana && (
<Trans i18nKey="alerting.preview-rule-result.no-data-error-handling-not-applied">
Configuration for `no data` and `error handling` is not applied.
</Trans>
)}
<div className={styles.table}>
<AutoSizer>
{({ width, height }) => (
@@ -3,7 +3,7 @@ import { useState } from 'react';
import { GrafanaTheme2, RelativeTimeRange, dateTime, getDefaultRelativeTimeRange, rangeUtil } from '@grafana/data';
import { Icon, InlineField, RelativeTimeRangePicker, Toggletip, clearButtonStyles, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import { AlertQuery } from 'app/types/unified-alerting-dto';
import { AlertQueryOptions, MaxDataPointsOption, MinIntervalOption } from './QueryWrapper';
@@ -29,6 +29,8 @@ export const QueryOptions = ({
const timeRange = query.relativeTimeRange ? rangeUtil.relativeToTimeRange(query.relativeTimeRange) : undefined;
const separator = <span>, </span>;
return (
<>
<Toggletip
@@ -50,14 +52,33 @@ export const QueryOptions = ({
placement="bottom-start"
>
<button type="button" className={styles.actionLink} onClick={() => setShowOptions(!showOptions)}>
Options {showOptions ? <Icon name="angle-right" /> : <Icon name="angle-down" />}
<Trans i18nKey="alerting.query-options.button-options">Options</Trans>{' '}
{showOptions ? <Icon name="angle-right" /> : <Icon name="angle-down" />}
</button>
</Toggletip>
<div className={styles.staticValues}>
<span>{dateTime(timeRange?.from).locale('en').fromNow(true)}</span>
{queryOptions.maxDataPoints && <span>, MD = {queryOptions.maxDataPoints}</span>}
{queryOptions.minInterval && <span>, Min. Interval = {queryOptions.minInterval}</span>}
{queryOptions.maxDataPoints && (
<>
{separator}
<Trans
i18nKey="alerting.query-options.max-data-points"
values={{ maxDataPoints: queryOptions.maxDataPoints }}
>
MD = {'{{maxDataPoints}}'}
</Trans>
</>
)}
{queryOptions.minInterval && (
<>
{separator}
<Trans i18nKey="alerting.query-options.min-interval" values={{ minInterval: queryOptions.minInterval }}>
Min. Interval = {'{{minInterval}}'}
</Trans>
</>
)}
</div>
</>
);
@@ -290,7 +290,9 @@ const DatasourceNotFound = ({ index, onUpdateDatasource, onRemoveQuery, model }:
</Trans>
</Card.Heading>
<Card.Description>
The datasource for this query was not found, it was either removed or is not installed correctly.
<Trans i18nKey="alerting.datasource-not-found.card-description">
The datasource for this query was not found, it was either removed or is not installed correctly.
</Trans>
</Card.Description>
<Card.Figure>
<Icon name="question-circle" />
@@ -19,7 +19,7 @@ import {
import { config } from '@grafana/runtime';
import { DataQuery } from '@grafana/schema';
import { GraphThresholdsStyleMode, Icon, InlineField, Input, Stack, Tooltip, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import { logInfo } from 'app/features/alerting/unified/Analytics';
import { QueryEditorRow } from 'app/features/query/components/QueryEditorRow';
import { AlertDataQuery, AlertQuery } from 'app/types/unified-alerting-dto';
@@ -123,10 +123,10 @@ export const QueryWrapper = ({
<div className={styles.dsTooltip}>
<Tooltip
content={
<>
<Trans i18nKey="alerting.selecting-data-source-tooltip.tooltip-content">
Not finding the data source you want? Some data sources are not supported for alerting. Click on the icon
for more information.
</>
</Trans>
}
>
<Icon
@@ -297,10 +297,10 @@ export function MinIntervalOption({
label={t('alerting.min-interval-option.label-interval', 'Interval')}
labelWidth={24}
tooltip={
<>
<Trans i18nKey="alerting.min-interval-option.tooltip-interval">
Interval sent to the data source. Recommended to be set to write frequency, for example <code>1m</code> if
your data is written every minute.
</>
</Trans>
}
>
<Input
@@ -12,6 +12,7 @@ import { QueryErrorAlert } from 'app/features/query/components/QueryErrorAlert';
import { LokiQueryType } from 'app/plugins/datasource/loki/dataquery.gen';
import { AlertQuery } from 'app/types/unified-alerting-dto';
import { Trans } from '../../../../../core/internationalization';
import { isPromOrLokiQuery } from '../../utils/rule-form';
import { VizWrapper } from './VizWrapper';
@@ -96,7 +97,13 @@ export const RecordingRuleEditor: FC<RecordingRuleEditorProps> = ({
if (error || !dataSource || !dataSource?.components?.QueryEditor || !dsi) {
const errorMessage = error?.message || 'Data source plugin does not export any Query Editor component';
return <div>Could not load query editor due to: {errorMessage}</div>;
return (
<div>
<Trans i18nKey="alerting.recording-rule-editor.error-no-query-editor">
Could not load query editor due to: {{ errorMessage }}
</Trans>
</div>
);
}
const QueryEditor = dataSource.components.QueryEditor;
@@ -5,7 +5,7 @@ import { useFormContext } from 'react-hook-form';
import AutoSizer from 'react-virtualized-auto-sizer';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, CodeEditor, Drawer, Icon, Tab, TabsBar, Tooltip, useStyles2 } from '@grafana/ui';
import { Button, CodeEditor, Drawer, Icon, Tab, TabsBar, TextLink, Tooltip, useStyles2 } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
import { RulerRuleDTO } from '../../../../../types/unified-alerting-dto';
@@ -132,15 +132,13 @@ const InspectorYamlTab = ({ onSubmit }: YamlTabProps) => {
function YamlContentInfo() {
return (
<div>
The YAML content in the editor only contains alert rule configuration <br />
To configure Prometheus, you need to provide the rest of the{' '}
<a
href="https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/"
target="_blank"
rel="noreferrer"
>
configuration file content.
</a>
<Trans i18nKey="alerting.yaml-content-info.body">
The YAML content in the editor only contains alert rule configuration <br />
To configure Prometheus, you need to provide the rest of the{' '}
<TextLink href="https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/" external>
configuration file content.
</TextLink>
</Trans>
</div>
);
}
@@ -278,7 +278,7 @@ export const AlertRuleForm = ({ existing, prefill, isManualRestore }: Props) =>
disabled={isSubmitting}
>
{isSubmitting && <Spinner className={styles.buttonSpinner} inline={true} />}
Save rule
<Trans i18nKey="alerting.alert-rule-form.action-buttons.save">Save rule</Trans>
</Button>
)}
<Button
@@ -290,7 +290,7 @@ export const AlertRuleForm = ({ existing, prefill, isManualRestore }: Props) =>
disabled={isSubmitting}
>
{isSubmitting && <Spinner className={styles.buttonSpinner} inline={true} />}
Save rule and exit
<Trans i18nKey="alerting.alert-rule-form.action-buttons.save-exit">Save rule and exit</Trans>
</Button>
<Button variant="secondary" disabled={isSubmitting} type="button" onClick={cancelRuleCreation} size="sm">
<Trans i18nKey="alerting.common.cancel">Cancel</Trans>
@@ -6,7 +6,7 @@ import { Controller, useFormContext } from 'react-hook-form';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Field, FieldValidationMessage, InlineField, MultiSelect, Stack, Switch, Text, useStyles2 } from '@grafana/ui';
import { MultiValueRemove, MultiValueRemoveProps } from '@grafana/ui/internal';
import { t } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import { RuleFormValues } from 'app/features/alerting/unified/types/rule-form';
import {
commonGroupByOptions,
@@ -54,6 +54,8 @@ export const RoutingSettings = ({ alertManager }: RoutingSettingsProps) => {
}
}, [overrideGrouping, setValue, alertManager, groupByCount]);
const separator = <span>, </span>;
return (
<Stack direction="column">
<Stack direction="row" gap={1} alignItems="center" justifyContent="space-between">
@@ -66,7 +68,12 @@ export const RoutingSettings = ({ alertManager }: RoutingSettingsProps) => {
</InlineField>
{!overrideGrouping && (
<Text variant="body" color="secondary">
Grouping: <strong>{REQUIRED_FIELDS_IN_GROUPBY.join(', ')}</strong>
<Trans
i18nKey="alerting.routing-settings.grouping"
values={{ fields: REQUIRED_FIELDS_IN_GROUPBY.join(', ') }}
>
Grouping: <strong>{'{{fields}}'}</strong>
</Trans>
</Text>
)}
</Stack>
@@ -154,9 +161,17 @@ export const RoutingSettings = ({ alertManager }: RoutingSettingsProps) => {
</InlineField>
{!overrideTimings && (
<Text variant="body" color="secondary">
Group wait: <strong>{groupWaitValue}, </strong>
Group interval: <strong>{groupIntervalValue}, </strong>
Repeat interval: <strong>{repeatIntervalValue}</strong>
<Trans i18nKey="alerting.routing-settings.group-wait" values={{ groupWaitValue }}>
Group wait: <strong>{'{{groupWaitValue}}'}</strong>
</Trans>
{separator}
<Trans i18nKey="alerting.routing-settings.group-interval" values={{ groupIntervalValue }}>
Group interval: <strong>{'{{groupIntervalValue}}'}</strong>
</Trans>
{separator}
<Trans i18nKey="alerting.routing-settings.repeat-interval" values={{ repeatIntervalValue }}>
Repeat interval: <strong>{'{{repeatIntervalValue}}'}</strong>
</Trans>
</Text>
)}
</Stack>
@@ -59,7 +59,7 @@ function NotificationRouteHeader({
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */}
<div onClick={() => onExpandRouteClick(!expandRoute)} className={styles.expandable}>
<Stack gap={1} direction="row" alignItems="center">
Notification policy
<Trans i18nKey="alerting.notification-route-header.notification-policy">Notification policy</Trans>
<NotificationPolicyMatchers
route={route}
matcherFormatter={getAmMatcherFormatter(alertManagerSourceName)}
@@ -2,7 +2,7 @@ import { css, cx } from '@emotion/css';
import { compact } from 'lodash';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, Icon, Modal, Stack, useStyles2 } from '@grafana/ui';
import { Button, Modal, Stack, TextLink, useStyles2 } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
import { Receiver } from '../../../../../../plugins/datasource/alertmanager/types';
@@ -104,20 +104,16 @@ export function NotificationRouteDetailsModal({
)}
<div className={styles.separator(4)} />
<div className={styles.contactPoint}>
<Stack gap={1} direction="row" alignItems="center">
Contact point:
<Stack gap={1} direction="column">
<Trans i18nKey="alerting.notification-route-details-modal.contact-point">Contact point</Trans>
<span className={styles.textMuted}>{receiver.name}</span>
</Stack>
<Authorize actions={[AlertmanagerAction.UpdateContactPoint]}>
<Stack gap={1} direction="row" alignItems="center">
<a
href={createContactPointSearchLink(receiver.name, alertManagerSourceName)}
className={styles.link}
target="_blank"
rel="noreferrer"
>
See details <Icon name="external-link-alt" />
</a>
<TextLink href={createContactPointSearchLink(receiver.name, alertManagerSourceName)} external>
<Trans i18nKey="alerting.notification-route-details-modal.see-details-link">See details</Trans>
</TextLink>
</Stack>
</Authorize>
</div>
@@ -661,7 +661,9 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange, mod
)}
severity="warning"
>
Create at least one query or expression to be alerted on
<Trans i18nKey="alerting.query-and-expressions-step.body-queries-expressions-configured">
Create at least one query or expression to be alerted on
</Trans>
</Alert>
)}
</Stack>
@@ -716,7 +718,7 @@ function TypeSelectorButton({ onClickType }: { onClickType: (type: ExpressionQue
return (
<Dropdown overlay={newMenu}>
<Button variant="secondary" data-testid={'add-expression-button'}>
Add expression
<Trans i18nKey="alerting.type-selector-button.add-expression">Add expression</Trans>
<Icon name="angle-down" />
</Button>
</Dropdown>
@@ -115,9 +115,12 @@ export function SmartAlertTypeDetector({
</Trans>
</Text>
<p>
Grafana-managed alert rules allow you to create alerts that can act on data from any of our supported
data sources, including having multiple data sources in the same rule. You can also add expressions to
transform your data and set alert conditions. Using images in alert notifications is also supported.
<Trans i18nKey="alerting.smart-alert-type-detector.grafanamanaged-alert-rules-description">
Grafana-managed alert rules allow you to create alerts that can act on data from any of our
supported data sources, including having multiple data sources in the same rule. You can also add
expressions to transform your data and set alert conditions. Using images in alert notifications is
also supported.
</Trans>
</p>
<Text color="primary" variant="h6">
<Trans i18nKey="alerting.smart-alert-type-detector.data-sourcemanaged-alert-rules">
@@ -125,8 +128,11 @@ export function SmartAlertTypeDetector({
</Trans>
</Text>
<p>
Data source-managed alert rules can be used for Grafana Mimir or Grafana Loki data sources which have
been configured to support rule creation. The use of expressions or multiple queries is not supported.
<Trans i18nKey="alerting.smart-alert-type-detector.data-sourcemanaged-alert-rules-description">
Data source-managed alert rules can be used for Grafana Mimir or Grafana Loki data sources which
have been configured to support rule creation. The use of expressions or multiple queries is not
supported.
</Trans>
</p>
</>
}
@@ -146,7 +152,11 @@ export function SmartAlertTypeDetector({
/>
{/* editing an existing rule, we just show "cannot be changed" */}
{editingExistingRule && (
<Text color="secondary">The alert rule type cannot be changed for an existing rule.</Text>
<Text color="secondary">
<Trans i18nKey="alerting.smart-alert-type-detector.rule-type-cannot-be-changed">
The alert rule type cannot be changed for an existing rule.
</Trans>
</Text>
)}
{/* in regular alert creation we tell the user what options they have when using a cloud data source */}
{!editingExistingRule && (
@@ -154,11 +164,21 @@ export function SmartAlertTypeDetector({
{canSwitch ? (
<Text color="secondary">
{ruleFormType === RuleFormType.grafana
? 'The data source selected in your query supports alert rule management. Switch to data source-managed if you want the alert rule to be managed by the data source instead of Grafana.'
: 'Switch to Grafana-managed to use expressions, multiple queries, images in notifications and various other features.'}
? t(
'alerting.smart-alert-type-detector.switch-to-data-source-managed',
'The data source selected in your query supports alert rule management. Switch to data source-managed if you want the alert rule to be managed by the data source instead of Grafana.'
)
: t(
'alerting.smart-alert-type-detector.switch-to-grafana-managed',
'Switch to Grafana-managed to use expressions, multiple queries, images in notifications and various other features.'
)}
</Text>
) : (
<Text color="secondary">Based on the selected data sources this alert rule will be Grafana-managed.</Text>
<Text color="secondary">
<Trans i18nKey="alerting.smart-alert-type-detector.rule-type-grafana-managed">
Based on the selected data sources this alert rule will be Grafana-managed.
</Trans>
</Text>
)}
</>
)}
@@ -1,3 +1,4 @@
import { Trans } from '../../../../../../core/internationalization';
import { RuleFormType } from '../../../types/rule-form';
import { RuleType, SharedProps } from './RuleType';
@@ -8,9 +9,11 @@ const GrafanaManagedRuleType = ({ selected = false, disabled, onClick }: SharedP
name="Grafana managed alert"
description={
<span>
Supports multiple data sources of any kind.
<br />
Transform data with expressions.
<Trans i18nKey="alerting.grafana-managed-rule-type.description">
Supports multiple data sources of any kind.
<br />
Transform data with expressions.
</Trans>
</span>
}
image="public/img/grafana_icon.svg"
@@ -1,3 +1,4 @@
import { Trans } from '../../../../../../core/internationalization';
import { RuleFormType } from '../../../types/rule-form';
import { DisabledTooltip } from './DisabledTooltip';
@@ -14,9 +15,11 @@ const MimirFlavoredType = ({ selected = false, disabled = false, onClick }: Prop
name="Mimir or Loki alert"
description={
<span>
Use a Mimir, Loki or Cortex datasource.
<br />
Expressions are not supported.
<Trans i18nKey="alerting.mimir-flavored-type.description">
Use a Mimir, Loki or Cortex datasource.
<br />
Expressions are not supported.
</Trans>
</span>
}
image="public/img/alerting/mimir_logo.svg"
@@ -1,3 +1,4 @@
import { Trans } from '../../../../../../core/internationalization';
import { RuleFormType } from '../../../types/rule-form';
import { DisabledTooltip } from './DisabledTooltip';
@@ -10,9 +11,11 @@ const RecordingRuleType = ({ selected = false, disabled = false, onClick }: Shar
name="Mimir or Loki recording rule"
description={
<span>
Precompute expressions.
<br />
Should be combined with an alert rule.
<Trans i18nKey="alerting.recording-rule-type.description">
Precompute expressions.
<br />
Should be combined with an alert rule.
</Trans>
</span>
}
image="public/img/alerting/mimir_logo_recording.svg"
@@ -4,6 +4,7 @@ import { isEmpty } from 'lodash';
import { GrafanaTheme2 } from '@grafana/data';
import { Stack, useStyles2 } from '@grafana/ui';
import { Trans } from '../../../../../../core/internationalization';
import { useRulesSourcesWithRuler } from '../../../hooks/useRuleSourcesWithRuler';
import { RuleFormType } from '../../../types/rule-form';
@@ -41,8 +42,10 @@ const RuleTypePicker = ({ selected, onChange, enabledTypes }: RuleTypePickerProp
</Stack>
{enabledTypes.includes(RuleFormType.grafana) && (
<small className={styles.meta}>
Select &ldquo;Grafana managed&rdquo; unless you have a Mimir, Loki or Cortex data source with the Ruler API
enabled.
<Trans i18nKey="alerting.rule-type-picker.grafana-managed">
Select &ldquo;Grafana managed&rdquo; unless you have a Mimir, Loki or Cortex data source with the Ruler API
enabled.
</Trans>
</small>
)}
</>
@@ -10,7 +10,9 @@ export function FederatedRuleWarning() {
topSpacing={2}
>
<Stack direction="column">
Federated rule groups are currently an experimental feature.
<Trans i18nKey="alerting.federated-rule-warning.experimental">
Federated rule groups are currently an experimental feature.
</Trans>
<Button fill="text" icon="book">
<a href="https://grafana.com/docs/metrics-enterprise/latest/tenant-management/tenant-federation/#cross-tenant-alerting-and-recording-rule-federation">
<Trans i18nKey="alerting.federated-rule-warning.read-documentation">Read documentation</Trans>
@@ -1,10 +1,12 @@
import { Icon, Stack, Text } from '@grafana/ui';
import { Trans } from '../../../../../core/internationalization';
export default function PausedBadge() {
return (
<Text variant="bodySmall" color="warning">
<Stack direction="row" alignItems={'center'} gap={0.25} wrap={'nowrap'} flex={'0 0 auto'}>
<Icon name="pause" size="xs" /> Paused
<Icon name="pause" size="xs" /> <Trans i18nKey="alerting.paused-badge.paused">Paused</Trans>
</Stack>
</Text>
);
@@ -248,7 +248,11 @@ const createMetadata = (rule: CombinedRule): PageInfoItem[] => {
if (interval) {
metadata.push({
label: 'Evaluation interval',
value: <Text color="primary">Every {interval}</Text>,
value: (
<Text color="primary">
<Trans i18nKey="alerting.rule-viewer.evaluation-interval">Every {{ interval }}</Trans>
</Text>
),
});
}
@@ -4,6 +4,7 @@ import { AlertState } from '@grafana/data';
import { Icon, Tooltip } from '@grafana/ui';
import { GrafanaAlertState, GrafanaAlertStateWithReason, PromAlertingRuleState } from 'app/types/unified-alerting-dto';
import { Trans } from '../../../../../core/internationalization';
import { alertStateToReadable, alertStateToState } from '../../utils/rules';
import { StateTag } from '../StateTag';
interface Props {
@@ -18,7 +19,7 @@ export const AlertStateTag = memo(({ state, isPaused = false, size = 'md', muted
return (
<Tooltip content={'Alert evaluation is currently paused'} placement="top">
<StateTag state="warning" size={size} muted={muted}>
<Icon name="pause" size="xs" /> Paused
<Icon name="pause" size="xs" /> <Trans i18nKey="alerting.alert-state-tag.paused">Paused</Trans>
</StateTag>
</Tooltip>
);
@@ -2,7 +2,7 @@ import { forwardRef, useState } from 'react';
import { Navigate, useLocation } from 'react-router-dom-v5-compat';
import { Button, ConfirmModal } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import { RuleIdentifier } from 'app/types/unified-alerting';
import * as ruleId from '../../utils/rule-id';
@@ -44,11 +44,15 @@ export function RedirectToCloneRule({
body={
<div>
<p>
The new rule will <strong>not</strong> be marked as a provisioned rule.
<Trans i18nKey="alerting.redirect-to-clone-rule.body-not-provisioned">
The new rule will <strong>not</strong> be marked as a provisioned rule.
</Trans>
</p>
<p>
You will need to set a new evaluation group for the copied rule because the original one has been
provisioned and cannot be used for rules created in the UI.
<Trans i18nKey="alerting.redirect-to-clone-rule.body-evaluation-group">
You will need to set a new evaluation group for the copied rule because the original one has been
provisioned and cannot be used for rules created in the UI.
</Trans>
</p>
</div>
}
@@ -147,12 +147,16 @@ const RulesFilter = ({ onClear = () => undefined }: RulesFilerProps) => {
content={
<div>
<p>
Data sources containing configured alert rules are Mimir or Loki data sources where alert rules
are stored and evaluated in the data source itself.
<Trans i18nKey="alerting.rules-filter.configured-alert-rules">
Data sources containing configured alert rules are Mimir or Loki data sources where alert
rules are stored and evaluated in the data source itself.
</Trans>
</p>
<p>
In these data sources, you can select Manage alerts via Alerting UI to be able to manage these
alert rules in the Grafana UI as well as in the data source where they were configured.
<Trans i18nKey="alerting.rules-filter.manage-alerts">
In these data sources, you can select Manage alerts via Alerting UI to be able to manage these
alert rules in the Grafana UI as well as in the data source where they were configured.
</Trans>
</p>
</div>
}
@@ -355,7 +359,11 @@ function SearchQueryHelp() {
return (
<div>
<div>Search syntax allows to query alert rules by the parameters defined below.</div>
<div>
<Trans i18nKey="alerting.search-query-help.search-syntax">
Search syntax allows to query alert rules by the parameters defined below.
</Trans>
</div>
<hr />
<div className={styles.grid}>
<div>
@@ -5,6 +5,7 @@ import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
import { Icon, Tooltip, useStyles2 } from '@grafana/ui';
import { Trans } from '../../../../../core/internationalization';
import { CombinedRule } from '../../../../../types/unified-alerting';
import { checkEvaluationIntervalGlobalLimit } from '../../utils/config';
import { rulerRuleType } from '../../utils/rules';
@@ -30,9 +31,14 @@ export function RuleConfigStatus({ rule }: RuleConfigStatusProps) {
theme="error"
content={
<div>
A minimum evaluation interval of{' '}
<span className={styles.globalLimitValue}>{config.unifiedAlerting.minInterval}</span> has been configured in
Grafana and will be used instead of the {rule.group.interval} interval configured for the Rule Group.
<Trans
i18nKey="alerting.rule-config-status.tooltip-min-interval"
values={{ minInterval: config.unifiedAlerting.minInterval, ruleInterval: rule.group.interval }}
>
A minimum evaluation interval of <span className={styles.globalLimitValue}>{'{{minInterval}}'}</span> has
been configured in Grafana and will be used instead of the {'{{ruleInterval}}'} interval configured for the
Rule Group.
</Trans>
</div>
}
>
@@ -16,6 +16,7 @@ import { SortOrder } from 'app/plugins/panel/alertlist/types';
import { Alert, CombinedRule, PaginationProps } from 'app/types/unified-alerting';
import { mapStateWithReasonToBaseState } from 'app/types/unified-alerting-dto';
import { Trans } from '../../../../../core/internationalization';
import { GRAFANA_RULES_SOURCE_NAME, isGrafanaRulesSource } from '../../utils/datasource';
import { parsePromQLStyleMatcherLooseSafe } from '../../utils/matchers';
import { prometheusRuleType } from '../../utils/rules';
@@ -47,10 +48,17 @@ function ShowMoreInstances({ stats, onClick, href }: ShowMoreInstancesProps) {
return (
<div className={styles.footerRow}>
<div>
Showing {stats.visibleItemsCount} out of {stats.totalItemsCount} instances
<Trans
i18nKey="alerting.rule-details-matching-instances.showing-count"
values={{ visibleItems: stats.visibleItemsCount, totalItems: stats.totalItemsCount }}
>
Showing {'{{visibleItems}}'} out of {'{{totalItems}}'} instances
</Trans>
</div>
<LinkButton size="sm" variant="secondary" data-testid="show-all" onClick={onClick} href={href}>
Show all {stats.totalItemsCount} alert instances
<Trans i18nKey="alerting.rule-details-matching-instances.button-show-all" count={stats.totalItemsCount}>
Show all {'{{totalItems}}'} alert instances
</Trans>
</LinkButton>
</div>
);
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { SerializedError } from '@reduxjs/toolkit';
import pluralize from 'pluralize';
import { FC, ReactElement, useMemo, useState } from 'react';
import { useLocalStorage } from 'react-use';
@@ -38,21 +37,42 @@ export function RuleListErrors(): ReactElement {
const result: JSX.Element[] = [];
const unknownError = t('alerting.rule-list-errors.unknown-error', 'Unknown error.');
if (grafanaPromError) {
result.push(<>Failed to load Grafana rules state: {grafanaPromError.message || 'Unknown error.'}</>);
result.push(
<>
<Trans i18nKey="alerting.rule-list-errors.failed-to-load-grafana-rules-state">
Failed to load Grafana rules state:
</Trans>{' '}
{grafanaPromError.message || unknownError}
</>
);
}
if (grafanaRulerError) {
result.push(<>Failed to load Grafana rules config: {grafanaRulerError.message || 'Unknown error.'}</>);
if (true) {
result.push(
<>
<Trans i18nKey="alerting.rule-list-errors.failed-to-load-grafana-rules-config">
Failed to load Grafana rules config:
</Trans>{' '}
{grafanaRulerError?.message || unknownError}
</>
);
}
promRequestErrors.forEach(({ dataSource, error }) =>
result.push(
<>
Failed to load rules state from{' '}
<a href={makeDataSourceLink(dataSource.uid)} className={styles.dsLink}>
{dataSource.name}
</a>
: {error.message || 'Unknown error.'}
<Trans
i18nKey="alerting.rule-list-errors.failed-to-load-rules-state"
values={{ dataSource: dataSource.name }}
>
Failed to load rules state from{' '}
<a href={makeDataSourceLink(dataSource.uid)} className={styles.dsLink}>
{'{{dataSource}}'}
</a>
</Trans>
: {error.message || unknownError}
</>
)
);
@@ -60,11 +80,16 @@ export function RuleListErrors(): ReactElement {
rulerRequestErrors.forEach(({ dataSource, error }) =>
result.push(
<>
Failed to load rules config from{' '}
<a href={makeDataSourceLink(dataSource.uid)} className={styles.dsLink}>
{dataSource.name}
</a>
: {error.message || 'Unknown error.'}
<Trans
i18nKey="alerting.rule-list-errors.failed-to-load-rules-config"
values={{ dataSource: dataSource.name }}
>
Failed to load rules config from{' '}
<a href={makeDataSourceLink(dataSource.uid)} className={styles.dsLink}>
{'{{dataSource}}'}
</a>
</Trans>
: {error.message || unknownError}
</>
)
);
@@ -99,7 +124,9 @@ export function RuleListErrors(): ReactElement {
size="sm"
onClick={() => setExpanded(true)}
>
{errors.length - 1} more {pluralize('error', errors.length - 1)}
<Trans i18nKey="alerting.rule-list-errors.more-errors" count={errors.length - 1}>
{'{{count}}'} more errors
</Trans>
</Button>
)}
</>
@@ -122,7 +149,9 @@ const ErrorSummaryButton: FC<ErrorSummaryProps> = ({ count, onClick }) => {
<div className={styles.floatRight}>
<Tooltip content="Show all errors" placement="bottom">
<Button fill="text" variant="destructive" icon="exclamation-triangle" onClick={onClick}>
{count > 1 ? <>{count} errors</> : <Trans i18nKey="alerting.error-summary-button.error">1 error</Trans>}
<Trans i18nKey="alerting.rule-list-errors.button-errors" count={count}>
{'{{count}}'} errors
</Trans>
</Button>
</Tooltip>
</div>
@@ -139,5 +168,6 @@ const getStyles = (theme: GrafanaTheme2) => ({
}),
dsLink: css({
fontWeight: theme.typography.fontWeightBold,
color: theme.colors.text.link,
}),
});
@@ -50,14 +50,20 @@ export const RuleState = ({ rule, isDeleting, isCreating, isPaused }: Props) =>
if (firstActiveAt) {
return (
<span title={String(firstActiveAt)} className={style.for}>
for{' '}
{intervalToAbbreviatedDurationString(
{
start: firstActiveAt,
end: new Date(),
},
false
)}
<Trans
i18nKey="alerting.rule-state.for"
values={{
duration: intervalToAbbreviatedDurationString(
{
start: firstActiveAt,
end: new Date(),
},
false
),
}}
>
for {'{{duration}}'}
</Trans>{' '}
</span>
);
}
@@ -4,7 +4,7 @@ import React, { useEffect, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Badge, Icon, Spinner, Stack, Tooltip, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import { CombinedRuleGroup, CombinedRuleNamespace, RulesSource } from 'app/types/unified-alerting';
import { useFolder } from '../../hooks/useFolder';
@@ -78,7 +78,7 @@ export const RulesGroup = React.memo(({ group, namespace, expandAll, viewMode }:
actionIcons.push(
<Stack key="is-deleting">
<Spinner />
deleting
<Trans i18nKey="alerting.rules-group.deleting">Deleting</Trans>
</Stack>
);
} else if (rulesSource === GRAFANA_RULES_SOURCE_NAME) {
@@ -5,7 +5,7 @@ import { Fragment, memo, useEffect } from 'react';
import { GrafanaTheme2, dateTimeFormat } from '@grafana/data';
import { Icon, Stack, TagList, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import { Label } from '../../Label';
import { AlertStateTag } from '../AlertStateTag';
@@ -151,7 +151,11 @@ const Timestamp = ({ time }: TimestampProps) => {
<Stack alignItems="center" gap={1}>
<Icon name="clock-nine" size="sm" />
<span className={styles.timestampText}>{dateTimeFormat(dateTime)}</span>
<small>({formatDistanceToNowStrict(dateTime)} ago)</small>
<small>
<Trans i18nKey="alerting.timestamp.time-ago" values={{ time: formatDistanceToNowStrict(dateTime) }}>
({'{{time}}'} ago)
</Trans>
</small>
</Stack>
</div>
);
@@ -92,7 +92,9 @@ const LokiStateHistory = ({ ruleUID }: Props) => {
)}
severity="error"
>
{error instanceof Error ? error.message : 'Unable to fetch alert state history'}
{error instanceof Error
? error.message
: t('alerting.loki-state-history.error-unable-to-fetch', 'Unable to fetch alert state history')}
</Alert>
);
}
@@ -202,8 +204,12 @@ const SearchFieldInput = React.forwardRef<HTMLInputElement, SearchFieldInputProp
<PopupCard
content={
<>
Use label matcher expression (like <code>{'{foo=bar}'}</code>) or click on an instance label to
filter instances
<Trans i18nKey="alerting.search-field-input.filter-instances-tooltip">
Use label matcher expression or click on an instance label to filter instances, for example:
</Trans>
<div>
<code>{'{foo=bar}'}</code>
</div>
</>
}
>
@@ -100,8 +100,13 @@ const StateHistory = ({ ruleUID }: Props) => {
<Tooltip
content={
<div>
Filter each state history group either by exact match or a regular expression, ex:{' '}
<code>{`region=eu-west-1`}</code> or <code>{`/region=us-.+/`}</code>
<Trans i18nKey="alerting.state-history.filter-group-tooltip">
Filter each state history group either by exact match or a regular expression, for example:
</Trans>
<div>
<code>{`region=eu-west-1`}</code>
<code>{`/region=us-.+/`}</code>
</div>
</div>
}
>
@@ -3,6 +3,7 @@ import { useState } from 'react';
import { intervalToAbbreviatedDurationString } from '@grafana/data';
import { AlertmanagerAlert } from 'app/plugins/datasource/alertmanager/types';
import { Trans } from '../../../../../core/internationalization';
import { AlertLabels } from '../AlertLabels';
import { CollapseToggle } from '../CollapseToggle';
@@ -35,7 +36,9 @@ export const SilencedAlertsTableRow = ({ alert, className }: Props) => {
<td>
<AmAlertStateTag state={alert.status.state} />
</td>
<td>for {duration}</td>
<td>
<Trans i18nKey="alerting.silenced-alerts-table-row.silenced-for">for {{ duration }}</Trans>
</td>
<td>{alertName}</td>
</tr>
{!isCollapsed && (
@@ -70,7 +70,9 @@ export const SilencedInstancesPreview = ({ amSourceName, matchers: inputMatchers
title={t('alerting.silenced-instances-preview.title-preview-not-available', 'Preview not available')}
severity="error"
>
Error occurred when generating preview of affected alerts. Are your matchers valid?
<Trans i18nKey="alerting.silenced-instances-preview.error-generating-preview">
Error occurred when generating preview of affected alerts. Are your matchers valid?
</Trans>
</Alert>
);
}
@@ -52,10 +52,16 @@ export const SilencesFilter = () => {
<Trans i18nKey="alerting.common.search-by-matchers">Search by matchers</Trans>
<Tooltip
content={
<div>
Filter silences by using a comma separated list of matchers, e.g.:
<>
<div>
<Trans i18nKey="alerting.silences-filter.search-by-matchers-tooltip">
Filter silences by using a comma separated list of matchers, e.g.
</Trans>
</div>
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
<pre>severity=critical, env=production</pre>
</div>
</>
}
>
<Icon name="info-circle" size="sm" />
@@ -326,7 +326,14 @@ function useColumns(alertManagerSourceName: string) {
id: 'alerts',
label: 'Alerts silenced',
renderCell: function renderSilencedAlerts({ data: { silencedAlerts } }) {
return <span data-testid="alerts">{Array.isArray(silencedAlerts) ? silencedAlerts.length : '-'}</span>;
return (
<span data-testid="alerts">
{Array.isArray(silencedAlerts)
? silencedAlerts.length
: // eslint-disable-next-line @grafana/no-untranslated-strings
'-'}
</span>
);
},
size: 2,
},
@@ -15,6 +15,7 @@ import {
VariableValueSelectors,
} from '@grafana/scenes';
import { Icon, Text, Tooltip } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { getAPINamespace } from '../../../../api/utils';
import { SectionFooter } from '../insights/SectionFooter';
@@ -178,15 +179,19 @@ export function getInsightsScenes() {
props: {
children: (
<Text>
Monitor the status of your system{' '}
<Trans i18nKey="alerting.insights.monitor-status-of-system">Monitor the status of your system</Trans>{' '}
<Tooltip
content={
<div>
Alerting insights provides pre-built dashboards to monitor your alerting data.
<Trans i18nKey="alerting.insights.monitor-status-system-tooltip">
Alerting insights provides pre-built dashboards to monitor your alerting data.
</Trans>
<br />
<br />
You can identify patterns in why things go wrong and discover trends in alerting performance within
your organization.
<Trans i18nKey="alerting.insights.monitor-status-system-tooltip-identify">
You can identify patterns in why things go wrong and discover trends in alerting performance
within your organization.
</Trans>
</div>
}
>
@@ -3,6 +3,7 @@ import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { Stack, Text, useStyles2 } from '@grafana/ui';
import { Trans } from '../../../../core/internationalization';
import { useAlertingHomePageExtensions } from '../plugins/useAlertingHomePageExtensions';
export function PluginIntegrations() {
@@ -17,7 +18,9 @@ export function PluginIntegrations() {
return (
<Stack direction="column" gap={2}>
<Text element="h3" variant="h4">
Speed up your alerts creation now by using one of our tailored apps
<Trans i18nKey="alerting.plugin-integrations.tailored-apps">
Speed up your alerts creation now by using one of our tailored apps
</Trans>
</Text>
<Stack gap={2} wrap="wrap" direction="row">
{components.map((Component, i) => (
@@ -85,7 +85,11 @@ const InsightsMenuButtonRenderer = ({ model }: SceneComponentProps<InsightsMenuB
className={styles.container}
>
<div>
<p>Help us improve this page by telling us whether this panel is useful to you!</p>
<p>
<Trans i18nKey="alerting.insights-menu-button-renderer.help-us">
Help us improve this page by telling us whether this panel is useful to you!
</Trans>
</p>
<div className={styles.buttonsContainer}>
<Button variant="secondary" className={styles.buttonContainer} onClick={() => onButtonClick(false)}>
<div className={styles.button}>
@@ -142,7 +142,9 @@ const RuleListV1 = () => {
variant="secondary"
onClick={() => setExpandAll(!expandAll)}
>
{expandAll ? 'Collapse all' : 'Expand all'}
{expandAll
? t('alerting.rule-list-v1.collapse-all', 'Collapse all')
: t('alerting.rule-list-v1.expand-all', 'Expand all')}
</Button>
)}
</Stack>
+137 -10
View File
@@ -410,7 +410,9 @@
"alert-rule-form": {
"action-buttons": {
"delete": "Delete",
"edit-yaml": "Edit YAML"
"edit-yaml": "Edit YAML",
"save": "Save rule",
"save-exit": "Save rule and exit"
},
"title-delete-rule": "Delete rule"
},
@@ -443,6 +445,9 @@
"suppressed-the-alert-has-been-silenced": "Suppressed: The alert has been silenced.",
"unprocessed-the-alert-is-received": "Unprocessed: The alert is received but its notification has not been processed yet."
},
"alert-state-tag": {
"paused": "Paused"
},
"alert-warning": {
"to-rule-list": "To rule list"
},
@@ -578,6 +583,10 @@
"tooltip-remove-matcher": "Remove matcher"
},
"annotations": {
"dashboard-annotation-field": {
"dashboard": "Dashboard {{dashboardUid}}",
"panel": "Panel {{panelId}}"
},
"description": "Add more context to your alert notifications.",
"title": "Configure notification message"
},
@@ -796,6 +805,9 @@
},
"dashboard-picker": {
"confirm": "Confirm",
"current-selection-dashboard": "Dashboard: {{dashboardTitle}} ({{ dashboardUid }}) in folder {{ folderTitle }}",
"current-selection-panel": "Panel: {{ panelTitle }} ({{ panelId }})",
"fallback-dashboards-string": "Dashboards",
"placeholder-search-dashboard": "Search dashboard",
"placeholder-search-panel": "Search panel",
"select-dashboard-available-panels": "Select a dashboard to get a list of available panels",
@@ -810,6 +822,7 @@
"import-to-grafana": "Import to Grafana rules"
},
"datasource-not-found": {
"card-description": "The datasource for this query was not found, it was either removed or is not installed correctly.",
"remove-query": "Remove query",
"show-details": "Show details",
"this-datasource-has-been-removed": "This datasource has been removed",
@@ -888,9 +901,6 @@
"failed-to-update-your-configuration": "Failed to update your configuration:",
"title-something-went-wrong": "Something went wrong"
},
"error-summary-button": {
"error": "1 error"
},
"evaluation-behavior-summary": {
"evaluate": "Every {{every}}",
"label-evaluate": "Evaluate",
@@ -962,9 +972,15 @@
"no-data": "No data"
},
"federated-rule-warning": {
"experimental": "Federated rule groups are currently an experimental feature.",
"read-documentation": "Read documentation",
"title-federated-group": "This rule is part of a federated rule group."
},
"file-export-inline-documentation": {
"api-provisioning": "{{name}} format is only valid for API Provisioning. <3>Read more in the docs.</3>",
"file-provisioning": "{{name}} format is only valid for File Provisioning. <3>Read more in the docs.</3>",
"terraform-provisioning": "{{name}} format is only valid for Terraform Provisioning. <3>Read more in the docs.</3>"
},
"file-export-preview": {
"copy-code": "Copy code",
"download": "Download"
@@ -1047,6 +1063,9 @@
"grafana-folder-and-labels-step": {
"title-add-folder-and-labels": "Add folder and labels"
},
"grafana-managed-rule-type": {
"description": "Supports multiple data sources of any kind.<1></1>Transform data with expressions."
},
"grafana-modify-export": {
"body-invalid-rule-id": "The rule UID in the page URL is invalid. Please check the URL and try again.",
"title-invalid-rule-id": "Invalid rule ID"
@@ -1217,8 +1236,14 @@
"label": "Target folder"
}
},
"insights": {
"monitor-status-of-system": "Monitor the status of your system",
"monitor-status-system-tooltip": "Alerting insights provides pre-built dashboards to monitor your alerting data.",
"monitor-status-system-tooltip-identify": "You can identify patterns in why things go wrong and discover trends in alerting performance within your organization."
},
"insights-menu-button-renderer": {
"aria-label-rate-this-panel": "Rate this panel",
"help-us": "Help us improve this page by telling us whether this panel is useful to you!",
"menu": {
"label-explore": "Explore",
"label-rate-this-panel": "Rate this panel"
@@ -1323,6 +1348,7 @@
"loki-state-history": {
"clear-filters": "Clear filters",
"common-labels": "Common labels",
"error-unable-to-fetch": "Unable to fetch alert state history",
"loading": "Loading...",
"title-error-fetching-the-state-history": "Error fetching the state history"
},
@@ -1331,8 +1357,12 @@
"title": "Manage permissions"
},
"matcher-filter": {
"filter-alerts-using-label-querying-without-braces": "Filter alerts using label querying without braces, ex:",
"filter-alerts-using-label-querying-without-spaces": "Filter alerts using label querying without spaces, ex:",
"invalid-use-of-spaces": "Invalid use of spaces:",
"search-by-label": "Search by label",
"search-query-input-placeholder-search": "Search"
"search-query-input-placeholder-search": "Search",
"valid-use-of-spaces": "Valid use of spaces:"
},
"matchers-field": {
"add-matcher": "Add matcher",
@@ -1358,8 +1388,12 @@
"migrate-to-gmabutton": {
"aria-label-new": "new"
},
"mimir-flavored-type": {
"description": "Use a Mimir, Loki or Cortex datasource.<1></1>Expressions are not supported."
},
"min-interval-option": {
"label-interval": "Interval"
"label-interval": "Interval",
"tooltip-interval": "Interval sent to the data source. Recommended to be set to write frequency, for example <1>1m</1> if your data is written every minute."
},
"modify-export-rule-form": {
"action-buttons": {
@@ -1499,13 +1533,16 @@
"notification-route-details-modal": {
"alert-instances-routed-follows": "Your alert instances are routed as follows.",
"close": "Close",
"contact-point": "Contact point",
"default-policy": "Default policy",
"notification-policy-path": "Notification policy path",
"see-details-link": "See details",
"title-routing-details": "Routing details"
},
"notification-route-header": {
"aria-label-expand-policy-route": "Expand policy route",
"delivered-to": "@ Delivered to",
"notification-policy": "Notification policy",
"see-details": "See details"
},
"notification-templates": {
@@ -1548,6 +1585,9 @@
"text-loading-rules": "Loading rules...",
"title-dashboard-not-saved": "Dashboard not saved"
},
"paused-badge": {
"paused": "Paused"
},
"payload-editor": {
"edit-payload": "Edit payload",
"label-add-custom-alert-instance": "Add custom alert instance",
@@ -1555,6 +1595,9 @@
"label-use-existing-alert-instances": "Use existing alert instances",
"reference": "Reference"
},
"plugin-integrations": {
"tailored-apps": "Speed up your alerts creation now by using one of our tailored apps"
},
"policies": {
"aria-label-collapse": "Collapse",
"aria-label-expand": "Expand",
@@ -1635,7 +1678,10 @@
"title-preview-is-not-available": "Preview is not available"
},
"preview-rule-result": {
"loading-preview": "Loading preview..."
"loading-preview": "Loading preview...",
"no-data-error-handling-not-applied": "Configuration for `no data` and `error handling` is not applied.",
"preview-based-on-query-result": "Preview based on the result of running the query, for this moment.",
"preview-failed": "Failed to preview alert rule"
},
"preview-summary": {
"no-series": "No series"
@@ -1664,6 +1710,7 @@
},
"query-and-expressions-step": {
"add-query": "Add query",
"body-queries-expressions-configured": "Create at least one query or expression to be alerted on",
"expressions": "Expressions",
"manipulate-returned-queries-other-operations": "Manipulate data returned from queries with math and other operations.",
"title-deactivate-advanced-options": "Deactivate advanced options",
@@ -1674,7 +1721,10 @@
"view-in-explore": "View in Explore"
},
"query-options": {
"label-time-range": "Time Range"
"button-options": "Options",
"label-time-range": "Time Range",
"max-data-points": "MD = {{maxDataPoints}}",
"min-interval": "Min. Interval = {{minInterval}}"
},
"query-preview": {
"relative-time-range": "{{from}} to now"
@@ -1705,6 +1755,12 @@
"label-export-all": "Export all"
}
},
"recording-rule-editor": {
"error-no-query-editor": "Could not load query editor due to: {{errorMessage}}"
},
"recording-rule-type": {
"description": "Precompute expressions.<1></1>Should be combined with an alert rule."
},
"recording-rules": {
"description-target-data-source": "The Prometheus data source to store recording rules in",
"label-target-data-source": "Target data source"
@@ -1714,9 +1770,13 @@
"title-add-namespace-and-group": "Add namespace and group"
},
"redirect-to-clone-rule": {
"body-evaluation-group": "You will need to set a new evaluation group for the copied rule because the original one has been provisioned and cannot be used for rules created in the UI.",
"body-not-provisioned": "The new rule will <1>not</1> be marked as a provisioned rule.",
"title-copy-provisioned-alert-rule": "Copy provisioned alert rule"
},
"redirect-to-rule-viewer": {
"no-rules-found": "No rules in <1>{{sourceName}}</1> matched the name <4>{{name}}</4>",
"several-rules-found": "Several rules in <1>{{sourceName}}</1> matched the name <4>{{name}}</4>, please select the rule you want to view.",
"text-loading-rule": "Loading rule...",
"title-could-not-view-rule": "Could not view rule",
"title-failed-to-load": "Failed to load rules from {{sourceName}}"
@@ -1745,14 +1805,21 @@
"routing-settings": {
"aria-label-group-by": "Group by",
"description-group-by": "Combine multiple alerts into a single notification by grouping them by the same label values. If empty, it is inherited from the default notification policy.",
"group-interval": "Group interval: <1>{{groupIntervalValue}}</1>",
"group-wait": "Group wait: <1>{{groupWaitValue}}</1>",
"grouping": "Grouping: <1>{{fields}}</1>",
"label-group-by": "Group by",
"label-override-grouping": "Override grouping",
"label-override-timings": "Override timings"
"label-override-timings": "Override timings",
"repeat-interval": "Repeat interval: <1>{{repeatIntervalValue}}</1>"
},
"rule-actions-buttons": {
"title-edit": "Edit",
"title-view": "View"
},
"rule-config-status": {
"tooltip-min-interval": "A minimum evaluation interval of <1>{{minInterval}}</1> has been configured in Grafana and will be used instead of the {{ruleInterval}} interval configured for the Rule Group."
},
"rule-details": {
"keep-firing-for": "Keep firing for",
"label-instances": "Instances",
@@ -1775,6 +1842,11 @@
"rule-details-federated-sources": {
"label-tenant-sources": "Tenant sources"
},
"rule-details-matching-instances": {
"button-show-all_one": "Show all {{totalItems}} alert instances",
"button-show-all_other": "Show all {{totalItems}} alert instances",
"showing-count": "Showing {{visibleItems}} out of {{totalItems}} instances"
},
"rule-editor": {
"get-content": {
"sorry-allowed-create-rules": "Sorry! You are not allowed to create rules.",
@@ -1933,7 +2005,20 @@
"unknown-rule-type": "Unknown rule type"
},
"rule-list-errors": {
"cloud-rulessource-errors-title-errors-loading-rules": "Errors loading rules"
"button-errors_one": "{{count}} error",
"button-errors_other": "{{count}} errors",
"cloud-rulessource-errors-title-errors-loading-rules": "Errors loading rules",
"failed-to-load-grafana-rules-config": "Failed to load Grafana rules config:",
"failed-to-load-grafana-rules-state": "Failed to load Grafana rules state:",
"failed-to-load-rules-config": "Failed to load rules config from <2>{{dataSource}}</2>",
"failed-to-load-rules-state": "Failed to load rules state from <2>{{dataSource}}</2>",
"more-errors_one": "{{count}} more error",
"more-errors_other": "{{count}} more errors",
"unknown-error": "Unknown error."
},
"rule-list-v1": {
"collapse-all": "Collapse all",
"expand-all": "Expand all"
},
"rule-modify-export": {
"text-loading-the-rule": "Loading the rule...",
@@ -1945,6 +2030,7 @@
"rule-state": {
"creating": "Creating",
"deleting": "Deleting",
"for": "for {{duration}}",
"na": "n/a",
"paused": "Paused",
"recording-rule": "Recording rule"
@@ -1960,6 +2046,9 @@
"recording": "{{recordingStats}} recording",
"recovering": "{{recoveringStats}} recovering"
},
"rule-type-picker": {
"grafana-managed": "Select &ldquo;Grafana managed&rdquo; unless you have a Mimir, Loki or Cortex data source with the Ruler API enabled."
},
"rule-view": {
"query": {
"datasources-na": {
@@ -1970,6 +2059,7 @@
},
"rule-viewer": {
"error-loading": "Something went wrong loading the rule",
"evaluation-interval": "Every {{interval}}",
"prometheus-consistency-check": {
"alert-message": "Alert rule has been added or updated. Changes may take up to a minute to appear on the Alert rules list view.",
"alert-title": "Update in progress"
@@ -1995,6 +2085,7 @@
},
"rules-filter": {
"clear-filters": "Clear filters",
"configured-alert-rules": "Data sources containing configured alert rules are Mimir or Loki data sources where alert rules are stored and evaluated in the data source itself.",
"dashboard": "Dashboard",
"data-source-picker-inline-help-title-search-by-data-sources-help": "Search by data sources help",
"filter-options": {
@@ -2003,6 +2094,7 @@
"label-saved-searches": "Saved searches"
},
"health": "Health",
"manage-alerts": "In these data sources, you can select Manage alerts via Alerting UI to be able to manage these alert rules in the Grafana UI as well as in the data source where they were configured.",
"placeholder-all-data-sources": "All data sources",
"plugin-rules": "Plugin rules",
"rule-type": "Rule type",
@@ -2014,6 +2106,7 @@
"view-as": "View as"
},
"rules-group": {
"deleting": "Deleting",
"text-federated": "Federated",
"text-provisioned": "Provisioned"
},
@@ -2036,11 +2129,13 @@
"search-field-input": {
"clear": "Clear",
"filter-instances": "Filter instances",
"filter-instances-tooltip": "Use label matcher expression or click on an instance label to filter instances, for example:",
"instancesSearchInput-placeholder-filter-instances": "Filter instances"
},
"search-query-help": {
"expression": "Expression",
"filter-type": "Filter type",
"search-syntax": "Search syntax allows to query alert rules by the parameters defined below.",
"title-contact-point": "Contact point",
"title-dashboard-uid": "Dashboard UID",
"title-datasources": "Datasources",
@@ -2052,6 +2147,9 @@
"title-state": "State",
"title-type": "Type"
},
"selecting-data-source-tooltip": {
"tooltip-content": "Not finding the data source you want? Some data sources are not supported for alerting. Click on the icon for more information."
},
"settings-content": {
"add-new-alertmanager": "Add new Alertmanager",
"builtin-alertmanager": "Built-in Alertmanager",
@@ -2072,7 +2170,11 @@
"label-silence-start-and-end": "Silence start and end",
"placeholder-select-time-range": "Select time range"
},
"silenced-alerts-table-row": {
"silenced-for": "for {{duration}}"
},
"silenced-instances-preview": {
"error-generating-preview": "Error occurred when generating preview of affected alerts. Are your matchers valid?",
"no-firing-alert-instances-found": "No firing alert instances found",
"text-loading-affected-alert-rule-instances": "Loading affected alert rule instances...",
"title-preview-not-available": "Preview not available",
@@ -2093,6 +2195,7 @@
"saving": "Saving..."
},
"silences-filter": {
"search-by-matchers-tooltip": "Filter silences by using a comma separated list of matchers, e.g.",
"search-query-input-placeholder-search": "Search"
},
"silences-table": {
@@ -2111,13 +2214,20 @@
},
"smart-alert-type-detector": {
"data-sourcemanaged-alert-rules": "Data source-managed alert rules",
"data-sourcemanaged-alert-rules-description": "Data source-managed alert rules can be used for Grafana Mimir or Grafana Loki data sources which have been configured to support rule creation. The use of expressions or multiple queries is not supported.",
"grafanamanaged-alert-rules": "Grafana-managed alert rules",
"grafanamanaged-alert-rules-description": "Grafana-managed alert rules allow you to create alerts that can act on data from any of our supported data sources, including having multiple data sources in the same rule. You can also add expressions to transform your data and set alert conditions. Using images in alert notifications is also supported.",
"rule-type": "Rule type",
"rule-type-cannot-be-changed": "The alert rule type cannot be changed for an existing rule.",
"rule-type-grafana-managed": "Based on the selected data sources this alert rule will be Grafana-managed.",
"select-where-alert-managed": "Select where the alert rule will be managed.",
"switch-to-data-source-managed": "The data source selected in your query supports alert rule management. Switch to data source-managed if you want the alert rule to be managed by the data source instead of Grafana.",
"switch-to-grafana-managed": "Switch to Grafana-managed to use expressions, multiple queries, images in notifications and various other features.",
"title-alert-rule-types": "Alert rule types"
},
"state-history": {
"filter-group": "Filter group",
"filter-group-tooltip": "Filter each state history group either by exact match or a regular expression, for example:",
"placeholder-search": "Search",
"text-loading-history": "Loading history...",
"title-failed-to-fetch-alert-state-history": "Failed to fetch alert state history"
@@ -2137,6 +2247,14 @@
"template-content-and-preview": {
"label-template-content": "Template content"
},
"template-data-docs": {
"alert-template-data-table": {
"alert-template-data": "Alert template data",
"only-in-alert": "Available only when in the context of an Alert (e.g. inside .Alerts loop)"
},
"available-context-notification": "Available in the context of a notification.",
"notification-template-data": "Notification template data"
},
"template-data-table": {
"name": "Name",
"notes": "Notes",
@@ -2212,6 +2330,9 @@
"timestamp": "Timestamp",
"value": "Value"
},
"timestamp": {
"time-ago": "({{time}} ago)"
},
"to-gma": {
"confirm-modal": {
"body": "The target folder is not empty, some rules may be overwritten or removed. Are you sure you want to import these alert rules to Grafana-managed rules?",
@@ -2219,6 +2340,9 @@
"title-warning": "Warning"
}
},
"type-selector-button": {
"add-expression": "Add expression"
},
"unknown-rule-list-item": {
"title-unknown-rule-type": "Unknown rule type"
},
@@ -2285,6 +2409,9 @@
"title-alert-rules": "Alert rules",
"title-contact-points": "Contact points",
"title-notification-policies": "Notification policies"
},
"yaml-content-info": {
"body": "The YAML content in the editor only contains alert rule configuration <1></1>To configure Prometheus, you need to provide the rest of the <4>configuration file content.</4>"
}
},
"annotations": {