Internationalisation: Check and mark up tooltip content prop (#104536)

* make lint rule check for "content"

* undo unnecessary translation
pull/104776/head
Ashley Harrison 3 weeks ago committed by GitHub
parent 439df585e0
commit 1c5545da04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      packages/grafana-eslint-rules/rules/no-untranslated-strings.cjs
  2. 6
      packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeContent.tsx
  3. 3
      packages/grafana-ui/src/components/PanelChrome/LoadingIndicator.tsx
  4. 10
      packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx
  5. 8
      public/app/core/components/AccessControl/PermissionListItem.tsx
  6. 5
      public/app/core/components/ForgottenPassword/ChangePassword.tsx
  7. 7
      public/app/features/admin/AdminFeatureTogglesTable.tsx
  8. 13
      public/app/features/admin/Users/UsersTable.tsx
  9. 14
      public/app/features/admin/ldap/LdapConnectionStatus.tsx
  10. 9
      public/app/features/admin/ldap/LdapUserGroups.tsx
  11. 14
      public/app/features/alerting/unified/components/bridges/DeclareIncidentButton.tsx
  12. 8
      public/app/features/alerting/unified/components/mute-timings/MuteTimingTimeRange.tsx
  13. 24
      public/app/features/alerting/unified/components/notification-policies/Policy.tsx
  14. 6
      public/app/features/alerting/unified/components/receivers/TemplatesTable.tsx
  15. 14
      public/app/features/alerting/unified/components/rule-editor/DashboardPicker.tsx
  16. 9
      public/app/features/alerting/unified/components/rule-editor/rule-types/DisabledTooltip.tsx
  17. 9
      public/app/features/alerting/unified/components/rules/AlertStateTag.tsx
  18. 8
      public/app/features/alerting/unified/components/rules/RuleDetails.tsx
  19. 5
      public/app/features/alerting/unified/components/rules/RuleListErrors.tsx
  20. 10
      public/app/features/alerting/unified/components/rules/RuleState.tsx
  21. 7
      public/app/features/alerting/unified/components/rules/RulesTable.tsx
  22. 4
      public/app/features/alerting/unified/components/rules/central-state-history/CentralAlertHistoryScene.tsx
  23. 7
      public/app/features/alerting/unified/components/rules/state-history/LokiStateHistory.tsx
  24. 13
      public/app/features/alerting/unified/plugins/PluginOriginBadge.tsx
  25. 3
      public/app/features/alerting/unified/rule-list/components/GroupStatus.tsx
  26. 7
      public/app/features/api-keys/ApiKeysTable.tsx
  27. 14
      public/app/features/dashboard-scene/settings/variables/VariableEditorListRow.tsx
  28. 9
      public/app/features/dashboard-scene/settings/variables/VariablesUnknownTable.tsx
  29. 10
      public/app/features/dashboard-scene/settings/version-history/VersionHistoryButtons.tsx
  30. 9
      public/app/features/explore/CorrelationEditorModeBar.tsx
  31. 3
      public/app/features/explore/Logs/LogsVolumePanel.tsx
  32. 5
      public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx
  33. 12
      public/app/features/explore/TraceView/components/TracePageHeader/TracePageHeader.tsx
  34. 4
      public/app/features/explore/TraceView/components/common/CopyIcon.tsx
  35. 8
      public/app/features/logs/components/LogRow.tsx
  36. 4
      public/app/features/plugins/admin/components/UpdateAllModalBody.tsx
  37. 5
      public/app/features/plugins/admin/pages/Browse.tsx
  38. 7
      public/app/features/profile/UserProfileEditForm.tsx
  39. 11
      public/app/features/serviceaccounts/components/ServiceAccountTokensTable.tsx
  40. 101
      public/locales/en-US/grafana.json

@ -21,7 +21,7 @@ const createRule = ESLintUtils.RuleCreator(
);
/** @type {string[]} */
const propsToCheck = ['label', 'description', 'placeholder', 'aria-label', 'title', 'text', 'tooltip'];
const propsToCheck = ['content', 'label', 'description', 'placeholder', 'aria-label', 'title', 'text', 'tooltip'];
/** @type {RuleDefinition} */
const noUntranslatedStrings = createRule({

@ -136,13 +136,15 @@ export const TimeRangeContent = (props: Props) => {
};
const fiscalYear = rangeUtil.convertRawToRange({ from: 'now/fy', to: 'now/fy' }, timeZone, fiscalYearStartMonth);
const fiscalYearMessage = t('time-picker.range-content.fiscal-year', 'Fiscal year');
const fyTooltip = (
<div className={style.tooltip}>
{rangeUtil.isFiscal(value) ? (
<Tooltip
content={`${fiscalYearMessage}: ${fiscalYear.from.format('MMM-DD')} - ${fiscalYear.to.format('MMM-DD')}`}
content={t('time-picker.range-content.fiscal-year', 'Fiscal year: {{from}} - {{to}}', {
from: fiscalYear.from.format('MMM-DD'),
to: fiscalYear.to.format('MMM-DD'),
})}
>
<Icon name="info-circle" />
</Tooltip>

@ -4,6 +4,7 @@ import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useStyles2 } from '../../themes';
import { t } from '../../utils/i18n';
import { Icon } from '../Icon/Icon';
import { Tooltip } from '../Tooltip/Tooltip';
@ -27,7 +28,7 @@ export const LoadingIndicator = ({ onCancel, loading }: LoadingIndicatorProps) =
}
return (
<Tooltip content="Cancel query">
<Tooltip content={t('grafana-ui.panel-chrome.tooltip-cancel-loading', 'Cancel query')}>
<Icon
className={cx(styles.spin, { [styles.clickable]: !!onCancel })}
name={prefersReducedMotion ? 'hourglass' : 'sync'}

@ -293,7 +293,13 @@ export function PanelChrome({
{titleItems}
</div>
{loadingState === LoadingState.Streaming && (
<Tooltip content={onCancelQuery ? 'Stop streaming' : 'Streaming'}>
<Tooltip
content={
onCancelQuery
? t('grafana-ui.panel-chrome.tooltip-stop-streaming', 'Stop streaming')
: t('grafana-ui.panel-chrome.tooltip-streaming', 'Streaming')
}
>
<TitleItem className={dragClassCancel} data-testid="panel-streaming" onClick={onCancelQuery}>
<Icon name="circle-mono" size="md" className={styles.streaming} />
</TitleItem>
@ -301,7 +307,7 @@ export function PanelChrome({
)}
{loadingState === LoadingState.Loading && onCancelQuery && (
<DelayRender delay={2000}>
<Tooltip content="Cancel query">
<Tooltip content={t('grafana-ui.panel-chrome.tooltip-cancel', 'Cancel query')}>
<TitleItem
className={cx(dragClassCancel, styles.pointer)}
data-testid="panel-cancel-query"

@ -71,7 +71,13 @@ export const PermissionListItem = ({ item, permissionLevels, canSet, onRemove, o
)}
/>
) : (
<Tooltip content={item.isInherited ? 'Inherited Permission' : 'Provisioned Permission'}>
<Tooltip
content={
item.isInherited
? t('access-control.permission-list-item.tooltip-inherited-permission', 'Inherited permission')
: t('access-control.permission-list-item.tooltip-provisioned-permission', 'Provisioned permission')
}
>
<Button
size="sm"
icon="lock"

@ -103,7 +103,10 @@ export const ChangePassword = ({ onSubmit, onSkip, showDefaultPasswordWarning }:
{!config.auth.basicAuthStrongPasswordPolicy && onSkip && (
<Tooltip
content="If you skip you will be prompted to change password next time you log in."
content={t(
'forgot-password.change-password.tooltip-skip-button',
'If you skip you will be prompted to change password next time you log in.'
)}
placement="bottom"
>
<Button

@ -91,7 +91,12 @@ export function AdminFeatureTogglesTable({ featureToggles, allowEditing, onUpdat
switch (stage) {
case 'GA':
return (
<Tooltip content={'General availability'}>
<Tooltip
content={t(
'admin.admin-feature-toggles-table.get-stage-cell.content-general-availability',
'General availability'
)}
>
<div>
<Trans i18nKey="admin.admin-feature-toggles-table.get-stage-cell.ga">GA</Trans>
</div>

@ -89,7 +89,10 @@ export const UsersTable = ({
<Stack alignItems={'center'}>
<OrgUnits units={value} icon={'building'} />
{row.original.isAdmin && (
<Tooltip placement="top" content="Grafana Admin">
<Tooltip
placement="top"
content={t('admin.users-table.columns.content-grafana-admin', 'Grafana Admin')}
>
<Icon name="shield" />
</Tooltip>
)}
@ -108,7 +111,13 @@ export const UsersTable = ({
return value === 'None' ? (
<Text color={'disabled'}>
<Trans i18nKey="admin.users-table.no-licensed-roles">Not assigned</Trans>
<Tooltip placement="top" content="A licensed role will be assigned when this user signs in">
<Tooltip
placement="top"
content={t(
'admin.users-table.tooltip-assigned-role',
'A licensed role will be assigned when this user signs in'
)}
>
<Icon name="question-circle" style={{ margin: '0 0 4 4' }} />
</Tooltip>
</Text>

@ -32,13 +32,23 @@ export const LdapConnectionStatus = ({ ldapConnectionInfo }: Props) => {
cell: (serverInfo: CellProps<ServerInfo>) => {
return serverInfo.cell.value ? (
<Stack justifyContent="end">
<Tooltip content="Connection is available">
<Tooltip
content={t(
'admin.ldap-connection-status.columns.content-connection-is-available',
'Connection is available'
)}
>
<Icon name="check" />
</Tooltip>
</Stack>
) : (
<Stack justifyContent="end">
<Tooltip content="Connection is not available">
<Tooltip
content={t(
'admin.ldap-connection-status.columns.content-connection-is-not-available',
'Connection is not available'
)}
>
<Icon name="exclamation-triangle" />
</Tooltip>
</Stack>

@ -1,7 +1,7 @@
import { useMemo } from 'react';
import { Tooltip, Icon, InteractiveTable, type CellProps, Column, Stack } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import { LdapRole } from 'app/types';
interface Props {
@ -30,7 +30,12 @@ export const LdapUserGroups = ({ groups }: Props) => {
props.value || (
<Stack alignItems="center" wrap>
<Trans i18nKey="admin.ldap-user-groups.no-org-found">No match</Trans>
<Tooltip content="No matching organizations found">
<Tooltip
content={t(
'admin.ldap-user-groups.columns.content-no-matching-organizations-found',
'No matching organizations found'
)}
>
<Icon name="info-circle" />
</Tooltip>
</Stack>

@ -30,7 +30,12 @@ export const DeclareIncidentButton = ({ title = '', severity = '', url = '' }: P
</Button>
)}
{installed === false && (
<Tooltip content={'Grafana Incident is not installed or is not configured correctly'}>
<Tooltip
content={t(
'alerting.declare-incident-button.content-grafana-incident-installed-configured-correctly',
'Grafana Incident is not installed or is not configured correctly'
)}
>
<Button icon="fire" size="sm" type="button" disabled>
<Trans i18nKey="alerting.declare-incident-button.declare-incident">Declare Incident</Trans>
</Button>
@ -64,7 +69,12 @@ export const DeclareIncidentMenuItem = ({ title = '', severity = '', url = '' }:
/>
)}
{installed === false && (
<Tooltip content={'Grafana Incident is not installed or is not configured correctly'}>
<Tooltip
content={t(
'alerting.declare-incident-menu-item.content-grafana-incident-installed-configured-correctly',
'Grafana Incident is not installed or is not configured correctly'
)}
>
<Menu.Item
label={t('alerting.declare-incident-menu-item.label-declare-incident', 'Declare incident')}
icon="fire"

@ -145,7 +145,13 @@ export const MuteTimingTimeRange = ({ intervalIndex }: Props) => {
<ConditionalWrap
shouldWrap={isDisabled}
wrap={(children) => (
<Tooltip content="This time interval is disabled" placement="right-start">
<Tooltip
content={t(
'alerting.mute-timing-time-range.content-this-time-interval-is-disabled',
'This time interval is disabled'
)}
placement="right-start"
>
{children}
</Tooltip>
)}

@ -623,7 +623,13 @@ export function isAutoGeneratedRootAndSimplifiedEnabled(route: RouteWithID) {
}
const ProvisionedTooltip = (children: ReactNode) => (
<Tooltip content="Provisioned items cannot be edited in the UI" placement="top">
<Tooltip
content={t(
'alerting.provisioned-tooltip.content-provisioned-items-cannot-edited',
'Provisioned items cannot be edited in the UI'
)}
placement="top"
>
<span>{children}</span>
</Tooltip>
);
@ -649,7 +655,13 @@ const Errors: FC<{ errors: React.ReactNode[] }> = ({ errors }) => (
const ContinueMatchingIndicator: FC = () => {
const styles = useStyles2(getStyles);
return (
<Tooltip placement="top" content="This route will continue matching other policies">
<Tooltip
placement="top"
content={t(
'alerting.continue-matching-indicator.content-route-continue-matching-other-policies',
'This route will continue matching other policies'
)}
>
<div className={styles.gutterIcon} data-testid="continue-matching">
<Icon name="arrow-down" />
</div>
@ -660,7 +672,13 @@ const ContinueMatchingIndicator: FC = () => {
const AllMatchesIndicator: FC = () => {
const styles = useStyles2(getStyles);
return (
<Tooltip placement="top" content="This policy matches all labels">
<Tooltip
placement="top"
content={t(
'alerting.all-matches-indicator.content-this-policy-matches-all-labels',
'This policy matches all labels'
)}
>
<div className={styles.gutterIcon} data-testid="matches-all">
<Icon name="exclamation-triangle" />
</div>

@ -143,8 +143,10 @@ function TemplateRow({ notificationTemplate, idx, alertManagerName, onDeleteClic
<Trans i18nKey="alerting.templates.misconfigured-warning">This template is misconfigured.</Trans>
<br />
<Trans i18nKey="alerting.templates.misconfigured-warning-details">
Templates must be defined in both the <CodeText content="template_files" /> and{' '}
<CodeText content="templates" /> sections of your alertmanager configuration.
Templates must be defined in both the{' '}
<CodeText content={t('alerting.template-row.content-templatefiles', 'template_files')} /> and{' '}
<CodeText content={t('alerting.template-row.content-templates', 'templates')} /> sections of your
alertmanager configuration.
</Trans>
</>
}

@ -153,12 +153,22 @@ export const DashboardPicker = ({ dashboardUid, panelId, isOpen, onChange, onDis
{panelTitle}
</div>
{!isAlertingCompatible && !disabled && (
<Tooltip content="The alert tab and alert annotations are only supported on graph and timeseries panels.">
<Tooltip
content={t(
'alerting.dashboard-picker.panel-row.tooltip-alert-tab-support',
'The alert tab and alert annotations are only supported on graph and timeseries panels.'
)}
>
<Icon name="exclamation-triangle" className={styles.warnIcon} data-testid="warning-icon" />
</Tooltip>
)}
{disabled && (
<Tooltip content="This panel does not have a valid identifier.">
<Tooltip
content={t(
'alerting.dashboard-picker.panel-row.content-panel-valid-identifier',
'This panel does not have a valid identifier.'
)}
>
<Icon name="info-circle" data-testid="info-icon" />
</Tooltip>
)}

@ -1,6 +1,7 @@
import * as React from 'react';
import { Tooltip } from '@grafana/ui';
import { t } from 'app/core/internationalization';
type Props = {
visible: boolean;
@ -12,7 +13,13 @@ const DisabledTooltip = ({ children, visible = false }: React.PropsWithChildren<
}
return (
<Tooltip content="You do not appear to have any compatible datasources." placement="top">
<Tooltip
content={t(
'alerting.disabled-tooltip.content-appear-compatible-datasources',
'You do not appear to have any compatible datasources.'
)}
placement="top"
>
<div>{children}</div>
</Tooltip>
);

@ -2,6 +2,7 @@ import { memo } from 'react';
import { AlertState } from '@grafana/data';
import { Icon, Tooltip } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { GrafanaAlertState, GrafanaAlertStateWithReason, PromAlertingRuleState } from 'app/types/unified-alerting-dto';
import { Trans } from '../../../../../core/internationalization';
@ -17,7 +18,13 @@ interface Props {
export const AlertStateTag = memo(({ state, isPaused = false, size = 'md', muted = false }: Props) => {
if (isPaused) {
return (
<Tooltip content={'Alert evaluation is currently paused'} placement="top">
<Tooltip
content={t(
'alerting.alert-state-tag.content-alert-evaluation-is-currently-paused',
'Alert evaluation is currently paused'
)}
placement="top"
>
<StateTag state="warning" size={size} muted={muted}>
<Icon name="pause" size="xs" /> <Trans i18nKey="alerting.alert-state-tag.paused">Paused</Trans>
</StateTag>

@ -116,6 +116,7 @@ const EvaluationBehaviorSummary = ({ rule }: EvaluationBehaviorSummaryProps) =>
>
<Tooltip
placement="top"
// eslint-disable-next-line @grafana/no-untranslated-strings
content={`${dateTimeFormat(lastEvaluation, { format: 'YYYY-MM-DD HH:mm:ss' })}`}
theme="info"
>
@ -133,7 +134,12 @@ const EvaluationBehaviorSummary = ({ rule }: EvaluationBehaviorSummaryProps) =>
label={t('alerting.evaluation-behavior-summary.label-evaluation-time', 'Evaluation time')}
horizontal={true}
>
<Tooltip placement="top" content={`${lastEvaluationDuration}s`} theme="info">
<Tooltip
placement="top"
// eslint-disable-next-line @grafana/no-untranslated-strings
content={`${lastEvaluationDuration}s`}
theme="info"
>
<span>{Time({ timeInMs: lastEvaluationDuration * 1000, humanize: true })}</span>
</Tooltip>
</DetailsField>

@ -147,7 +147,10 @@ const ErrorSummaryButton: FC<ErrorSummaryProps> = ({ count, onClick }) => {
return (
<div className={styles.floatRight}>
<Tooltip content="Show all errors" placement="bottom">
<Tooltip
content={t('alerting.error-summary-button.content-show-all-errors', 'Show all errors')}
placement="bottom"
>
<Button fill="text" variant="destructive" icon="exclamation-triangle" onClick={onClick}>
<Trans i18nKey="alerting.rule-list-errors.button-errors" count={count}>
{'{{count}}'} errors

@ -3,7 +3,7 @@ import { useMemo } from 'react';
import { GrafanaTheme2, intervalToAbbreviatedDurationString } from '@grafana/data';
import { Icon, Spinner, Stack, Tooltip, useStyles2 } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import { CombinedRule } from 'app/types/unified-alerting';
import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
@ -26,7 +26,13 @@ export const RuleState = ({ rule, isDeleting, isCreating, isPaused }: Props) =>
const RecordingRuleState = () => {
if (isPaused && rulerRuleType.grafana.recordingRule(rulerRule)) {
return (
<Tooltip content={'Recording rule evaluation is currently paused'} placement="top">
<Tooltip
content={t(
'alerting.rule-state.recording-rule-state.content-recording-rule-evaluation-is-currently-paused',
'Recording rule evaluation is currently paused'
)}
placement="top"
>
<StateTag state="warning">
<Icon name="pause" size="xs" />
<Trans i18nKey="alerting.rule-state.paused">Paused</Trans>

@ -264,7 +264,12 @@ function useColumns(
return (
nextEvalInfo && (
<Tooltip placement="top" content={`${nextEvalInfo?.fullDate}`} theme="info">
<Tooltip
placement="top"
// eslint-disable-next-line @grafana/no-untranslated-strings
content={`${nextEvalInfo?.fullDate}`}
theme="info"
>
<span>{nextEvalInfo?.humanized}</span>
</Tooltip>
)

@ -37,7 +37,7 @@ import {
TooltipDisplayMode,
useStyles2,
} from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import { LogMessages, logInfo } from '../../../Analytics';
@ -236,7 +236,7 @@ export function ClearFilterButtonObjectRenderer({ model }: SceneComponentProps<C
};
return (
<Tooltip content="Clear filter">
<Tooltip content={t('alerting.clear-filter-button-object-renderer.content-clear-filter', 'Clear filter')}>
<Button variant={'secondary'} icon="times" onClick={onClearFilter}>
<Trans i18nKey="alerting.central-alert-history.filter.clear">Clear filters</Trans>
</Button>

@ -121,7 +121,12 @@ const LokiStateHistory = ({ ruleUID }: Props) => {
<Text variant="bodySmall">
<Trans i18nKey="alerting.loki-state-history.common-labels">Common labels</Trans>
</Text>
<Tooltip content="Common labels are the ones attached to all of the alert instances">
<Tooltip
content={t(
'alerting.loki-state-history.tooltip-common-labels',
'Common labels are the ones attached to all of the alert instances'
)}
>
<Icon name="info-circle" size="sm" />
</Tooltip>
</Stack>

@ -3,6 +3,7 @@ import { useAsync } from 'react-use';
import { Badge, IconSize, Tooltip } from '@grafana/ui';
import { getSvgSize } from '@grafana/ui/internal';
import { t } from '../../../../core/internationalization';
import { getPluginSettings } from '../../../plugins/pluginSettings';
interface PluginOriginBadgeProps {
@ -31,5 +32,15 @@ export function PluginOriginBadge({ pluginId, size = 'md' }: PluginOriginBadgePr
<Badge text={pluginId} color="orange" />
);
return <Tooltip content={`This rule is managed by the ${pluginName} plugin`}>{badgeIcon}</Tooltip>;
return (
<Tooltip
content={t(
'alerting.plugin-origin-badge.tooltip-managed-by-plugin',
'This rule is managed by the {{pluginName}} plugin',
{ pluginName }
)}
>
{badgeIcon}
</Tooltip>
);
}

@ -2,6 +2,7 @@ import { css, keyframes } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, Tooltip, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
interface GroupStatusProps {
status: 'deleting'; // We don't support other statuses yet
@ -14,7 +15,7 @@ export function GroupStatus({ status }: GroupStatusProps) {
<div className={styles.container}>
<div className={styles.loader} />
{status === 'deleting' && (
<Tooltip content="The group is being deleted">
<Tooltip content={t('alerting.group-status.content-the-group-is-being-deleted', 'The group is being deleted')}>
<div className={styles.iconWrapper}>
<Icon name="trash-alt" size="sm" />
</div>

@ -50,7 +50,12 @@ export const ApiKeysTable = ({ apiKeys, timeZone, onDelete, onMigrate }: Props)
{formatDate(key.expiration, timeZone)}
{isExpired && (
<span className={styles.tooltipContainer}>
<Tooltip content="This API key has expired.">
<Tooltip
content={t(
'api-keys.api-keys-table.content-this-api-key-has-expired',
'This API key has expired.'
)}
>
<Icon name="exclamation-triangle" />
</Tooltip>
</span>

@ -146,7 +146,12 @@ function VariableCheckIndicator({ passed }: VariableCheckIndicatorProps): ReactE
const styles = useStyles2(getStyles);
if (passed) {
return (
<Tooltip content="This variable is referenced by other variables or dashboard.">
<Tooltip
content={t(
'dashboard-scene.variable-check-indicator.content-variable-referenced-other-variables-dashboard',
'This variable is referenced by other variables or dashboard.'
)}
>
<Icon
name="check"
className={styles.iconPassed}
@ -160,7 +165,12 @@ function VariableCheckIndicator({ passed }: VariableCheckIndicatorProps): ReactE
}
return (
<Tooltip content="This variable is not referenced by other variables or dashboard.">
<Tooltip
content={t(
'dashboard-scene.variable-check-indicator.content-variable-not-referenced-other-variables-dashboard',
'This variable is not referenced by other variables or dashboard.'
)}
>
<Icon
name="exclamation-triangle"
className={styles.iconFailed}

@ -7,7 +7,7 @@ import { reportInteraction } from '@grafana/runtime';
import { SceneVariable, SceneVariableState } from '@grafana/scenes';
import { Dashboard } from '@grafana/schema/dist/esm/index.gen';
import { CollapsableSection, Icon, Spinner, Stack, Tooltip, useStyles2 } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { t, Trans } from 'app/core/internationalization';
import { VariableUsagesButton } from '../../variables/VariableUsagesButton';
import { getUnknownsNetwork, UsagesToNetwork } from '../../variables/utils';
@ -79,7 +79,12 @@ function CollapseLabel(): ReactElement {
return (
<h5>
<Trans i18nKey="variables.unknown-table.renamed-or-missing-variables">Renamed or missing variables</Trans>
<Tooltip content="Click to expand a list with all variable references that have been renamed or are missing from the dashboard.">
<Tooltip
content={t(
'variables.unknown-table.tooltip-renamed-or-missing-variables',
'Click to expand a list with all variable references that have been renamed or are missing from the dashboard.'
)}
>
<Icon name="info-circle" className={style.infoIcon} />
</Tooltip>
</h5>

@ -1,5 +1,5 @@
import { Tooltip, Button, Stack } 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';
type VersionsButtonsType = {
@ -30,7 +30,13 @@ export const VersionsHistoryButtons = ({
<Trans i18nKey="dashboard-scene.versions-history-buttons.show-more-versions">Show more versions</Trans>
</Button>
)}
<Tooltip content="Select two versions to start comparing" placement="bottom">
<Tooltip
content={t(
'dashboard-scene.versions-history-buttons.content-select-two-versions-to-start-comparing',
'Select two versions to start comparing'
)}
placement="bottom"
>
<Button type="button" disabled={!canCompare} onClick={getDiff} icon="code-branch">
<Trans i18nKey="dashboard-scene.versions-history-buttons.compare-versions">Compare versions</Trans>
</Button>

@ -6,7 +6,7 @@ import { GrafanaTheme2, colorManipulator } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
import { Button, Icon, Stack, Tooltip, useStyles2 } from '@grafana/ui';
import { Prompt } from 'app/core/components/FormPrompt/Prompt';
import { Trans } from 'app/core/internationalization';
import { Trans, t } from 'app/core/internationalization';
import { CORRELATION_EDITOR_POST_CONFIRM_ACTION, ExploreItemState, useDispatch, useSelector } from 'app/types';
import { CorrelationUnsavedChangesModal } from './CorrelationUnsavedChangesModal';
@ -231,7 +231,12 @@ export const CorrelationEditorModeBar = ({ panes }: { panes: Array<[string, Expl
)}
<div className={styles.correlationEditorTop}>
<Stack gap={2} justifyContent="flex-end" alignItems="center">
<Tooltip content="Correlations editor in Explore is an experimental feature.">
<Tooltip
content={t(
'explore.correlation-editor-mode-bar.content-correlations-editor-explore-experimental-feature',
'Correlations editor in Explore is an experimental feature.'
)}
>
<Icon className={styles.iconColor} name="info-circle" size="xl" />
</Tooltip>
<Button

@ -14,6 +14,7 @@ import {
} from '@grafana/data';
import { TimeZone } from '@grafana/schema';
import { Icon, SeriesVisibilityChangeMode, Tooltip, TooltipDisplayMode, useStyles2, useTheme2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { getLogsVolumeDataSourceInfo, isLogsVolumeLimited } from '../../logs/utils';
import { ExploreGraph } from '../Graph/ExploreGraph';
@ -68,7 +69,7 @@ export function LogsVolumePanel(props: Props) {
extraInfoComponent = (
<>
{extraInfoComponent}
<Tooltip content="Streaming">
<Tooltip content={t('explore.logs-volume-panel.content-streaming', 'Streaming')}>
<Icon name="circle-mono" size="md" className={styles.streaming} data-testid="logs-volume-streaming" />
</Tooltip>
</>

@ -111,7 +111,10 @@ export const SpanFilters = memo((props: SpanFilterProps) => {
const collapseLabel = (
<>
<Tooltip
content="Filter your spans below. You can continue to apply filters until you have narrowed down your resulting spans to the select few you are most interested in."
content={t(
'explore.span-filters.tooltip-collapse',
'Filter your spans below. You can continue to apply filters until you have narrowed down your resulting spans to the select few you are most interested in.'
)}
placement="right"
>
<span className={styles.collapseLabel}>

@ -154,14 +154,22 @@ export const TracePageHeader = memo((props: TracePageHeaderProps) => {
</Tooltip>
)}
{method && method.length > 0 && (
<Tooltip content={'http.method'} interactive={true}>
<Tooltip
// eslint-disable-next-line @grafana/no-untranslated-strings
content="http.method"
interactive={true}
>
<span className={styles.tag}>
<Badge text={method[0].value} color="blue" />
</span>
</Tooltip>
)}
{status && status.length > 0 && (
<Tooltip content={'http.status_code'} interactive={true}>
<Tooltip
// eslint-disable-next-line @grafana/no-untranslated-strings
content="http.status_code"
interactive={true}
>
<span className={styles.tag}>
<Badge text={status[0].value} color={statusColor} />
</span>

@ -18,6 +18,8 @@ import { useState } from 'react';
import { Button, IconName, Tooltip, useStyles2 } from '@grafana/ui';
import { t } from '../../../../../core/internationalization';
const getStyles = () => ({
CopyIcon: css({
backgroundColor: 'transparent',
@ -50,7 +52,7 @@ export default function CopyIcon({ copyText, icon = 'copy', tooltipTitle }: Prop
};
return (
<Tooltip content={hasCopied ? 'Copied' : tooltipTitle}>
<Tooltip content={hasCopied ? t('explore.trace-view.tooltip-copy-icon', 'Copied') : tooltipTitle}>
<Button className={cx(styles.CopyIcon)} type="button" icon={icon} onClick={handleClick} />
</Tooltip>
);

@ -222,12 +222,16 @@ export const LogRow = ({
}
>
{hasError && (
<Tooltip content={`Error: ${errorMessage}`} placement="right" theme="error">
<Tooltip
content={t('logs.log-row-message.tooltip-error', 'Error: {{errorMessage}}', { errorMessage })}
placement="right"
theme="error"
>
<Icon className={styles.logIconError} name="exclamation-triangle" size="xs" />
</Tooltip>
)}
{isSampled && (
<Tooltip content={`${sampleMessage}`} placement="right" theme="info">
<Tooltip content={sampleMessage} placement="right" theme="info">
<Icon className={styles.logIconInfo} name="info-circle" size="xs" />
</Tooltip>
)}

@ -87,7 +87,9 @@ const StatusIcon = ({
if (errorMap && errorMap.has(id)) {
return (
<Tooltip
content={`${t('plugins.catalog.update-all.error', 'Error updating plugin:')} ${errorMap.get(id)?.message}`}
content={t('plugins.catalog.update-all.error', 'Error updating plugin: {{errorMessage}}', {
errorMessage: errorMap.get(id)?.message,
})}
>
<Icon className={styles.errorIcon} size="xl" name="exclamation-triangle" />
</Tooltip>

@ -124,7 +124,10 @@ export default function Browse() {
</Field>
) : (
<Tooltip
content="This filter has been disabled because the Grafana server cannot access grafana.com"
content={t(
'plugins.browse.tooltip-filter-disabled',
'This filter has been disabled because the Grafana server cannot access grafana.com'
)}
placement="top"
>
<div>

@ -94,7 +94,12 @@ export default UserProfileEditForm;
const InputSuffix = () => {
return disableLoginForm ? (
<Tooltip content="Login details locked because they are managed in another system.">
<Tooltip
content={t(
'profile.input-suffix.content-login-details-locked-because-managed-another',
'Login details locked because they are managed in another system.'
)}
>
<Icon name="lock" />
</Tooltip>
) : null;

@ -93,7 +93,12 @@ const TokenRevoked = () => {
<span className={styles.hasExpired}>
<Trans i18nKey="serviceaccounts.token-revoked.revoked-label">Revoked</Trans>
<span className={styles.tooltipContainer}>
<Tooltip content="This token has been publicly exposed. Please rotate this token">
<Tooltip
content={t(
'serviceaccounts.token-revoked.content-token-publicly-exposed-please-rotate',
'This token has been publicly exposed. Please rotate this token'
)}
>
<Icon name="exclamation-triangle" className={styles.toolTipIcon} />
</Tooltip>
</span>
@ -127,7 +132,9 @@ const TokenExpiration = ({ timeZone, token }: TokenExpirationProps) => {
<span className={styles.hasExpired}>
<Trans i18nKey="serviceaccounts.token-expiration.expired-label">Expired</Trans>
<span className={styles.tooltipContainer}>
<Tooltip content="This token has expired">
<Tooltip
content={t('serviceaccounts.token-expiration.content-this-token-has-expired', 'This token has expired')}
>
<Icon name="exclamation-triangle" className={styles.toolTipIcon} />
</Tooltip>
</span>

@ -21,7 +21,9 @@
"permission-list-item": {
"inherited": "Inherited from folder",
"locked-aria-label": "Locked permission indicator",
"remove-aria-label": "Remove permission for {{identifier}}"
"remove-aria-label": "Remove permission for {{identifier}}",
"tooltip-inherited-permission": "Inherited permission",
"tooltip-provisioned-permission": "Provisioned permission"
},
"permissions": {
"add-label": "Add a permission",
@ -70,6 +72,7 @@
"confirm-modal-body-2": "We advise understanding the implications of each feature change before making modifications.",
"get-stage-cell": {
"beta": "Beta",
"content-general-availability": "General availability",
"deprecated": "Deprecated",
"ga": "GA"
},
@ -128,6 +131,12 @@
"test-mapping-heading": "Test user mapping",
"test-mapping-run-button": "Run"
},
"ldap-connection-status": {
"columns": {
"content-connection-is-available": "Connection is available",
"content-connection-is-not-available": "Connection is not available"
}
},
"ldap-error-box": {
"title-connection-error": "Connection error"
},
@ -161,6 +170,9 @@
"title": "LDAP Synchronization"
},
"ldap-user-groups": {
"columns": {
"content-no-matching-organizations-found": "No matching organizations found"
},
"no-org-found": "No match"
},
"ldap-user-info": {
@ -284,12 +296,14 @@
},
"users-table": {
"columns": {
"content-grafana-admin": "Grafana Admin",
"title-edit-user": "Edit user"
},
"edit-aria-label": "Edit user: {{name}}",
"edit-tooltip": "Edit user",
"last-seen-never": "Never",
"no-licensed-roles": "Not assigned"
"no-licensed-roles": "Not assigned",
"tooltip-assigned-role": "A licensed role will be assigned when this user signs in"
}
},
"alert-labels": {
@ -442,6 +456,7 @@
"unprocessed-the-alert-is-received": "Unprocessed: The alert is received but its notification has not been processed yet."
},
"alert-state-tag": {
"content-alert-evaluation-is-currently-paused": "Alert evaluation is currently paused",
"paused": "Paused"
},
"alert-warning": {
@ -538,6 +553,9 @@
"warning-restore-manually": "You are manually restoring an old version of this alert rule. Please review the changes carefully before saving the rule definition.",
"warning-restore-manually-title": "Restoring rule manually"
},
"all-matches-indicator": {
"content-this-policy-matches-all-labels": "This policy matches all labels"
},
"am-root-route-form": {
"am-group-description-label": "The waiting time before sending the first notification for a new group of alerts. Default 30 seconds.",
"am-group-interval-description": "The wait time before sending a notification about changes in the alert group after the first notification has been sent. Default is 5 minutes.",
@ -650,6 +668,9 @@
"of": "OF",
"when": "WHEN"
},
"clear-filter-button-object-renderer": {
"content-clear-filter": "Clear filter"
},
"clone-rule-button": {
"title-copy": "Copy"
},
@ -776,6 +797,9 @@
"contactPointFilter": {
"label": "Contact point"
},
"continue-matching-indicator": {
"content-route-continue-matching-other-policies": "This route will continue matching other policies"
},
"copy-to-clipboard": "Copy \"{{label}}\" to clipboard",
"create-metadata": {
"view-dashboard": "View dashboard",
@ -804,6 +828,10 @@
"current-selection-dashboard": "Dashboard: {{dashboardTitle}} ({{ dashboardUid }}) in folder {{ folderTitle }}",
"current-selection-panel": "Panel: {{ panelTitle }} ({{ panelId }})",
"fallback-dashboards-string": "Dashboards",
"panel-row": {
"content-panel-valid-identifier": "This panel does not have a valid identifier.",
"tooltip-alert-tab-support": "The alert tab and alert annotations are only supported on graph and timeseries panels."
},
"placeholder-search-dashboard": "Search dashboard",
"placeholder-search-panel": "Search panel",
"select-dashboard-available-panels": "Select a dashboard to get a list of available panels",
@ -825,9 +853,11 @@
"update-datasource": "Update datasource"
},
"declare-incident-button": {
"content-grafana-incident-installed-configured-correctly": "Grafana Incident is not installed or is not configured correctly",
"declare-incident": "Declare Incident"
},
"declare-incident-menu-item": {
"content-grafana-incident-installed-configured-correctly": "Grafana Incident is not installed or is not configured correctly",
"label-declare-incident": "Declare incident"
},
"delete-rule-modal": {
@ -863,6 +893,9 @@
},
"unknown": "Unknown"
},
"disabled-tooltip": {
"content-appear-compatible-datasources": "You do not appear to have any compatible datasources."
},
"draggable-rules-table": {
"evals-to-start-alerting": "Evaluations to start alerting",
"pending-period": "Pending period",
@ -903,6 +936,9 @@
"failed-to-update-your-configuration": "Failed to update your configuration:",
"title-something-went-wrong": "Something went wrong"
},
"error-summary-button": {
"content-show-all-errors": "Show all errors"
},
"evaluation-behavior-summary": {
"evaluate": "Every {{interval}}",
"label-evaluate": "Evaluate",
@ -1183,6 +1219,9 @@
"group-loader": {
"group-load-failed": "Failed to load rules from group {{ groupName }} in {{ namespaceName }}"
},
"group-status": {
"content-the-group-is-being-deleted": "The group is being deleted"
},
"header": {
"tooltip-remove": "Remove expression \"{{refId}}\""
},
@ -1352,7 +1391,8 @@
"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"
"title-error-fetching-the-state-history": "Error fetching the state history",
"tooltip-common-labels": "Common labels are the ones attached to all of the alert instances"
},
"manage-permissions": {
"button": "Manage permissions",
@ -1445,6 +1485,7 @@
},
"mute-timing-time-range": {
"add-another-time-range": "Add another time range",
"content-this-time-interval-is-disabled": "This time interval is disabled",
"description-time-range": "The time inclusive of the start and exclusive of the end time (in UTC if no location has been selected, otherwise local time)",
"label-end-time": "End time",
"label-start-time": "Start time",
@ -1600,6 +1641,9 @@
"plugin-integrations": {
"tailored-apps": "Speed up your alerts creation now by using one of our tailored apps"
},
"plugin-origin-badge": {
"tooltip-managed-by-plugin": "This rule is managed by the {{pluginName}} plugin"
},
"policies": {
"aria-label-collapse": "Collapse",
"aria-label-expand": "Expand",
@ -1699,6 +1743,9 @@
"prometheus-consistency-check": {
"title-unable-to-check-the-rule-status": "Unable to check the rule status"
},
"provisioned-tooltip": {
"content-provisioned-items-cannot-edited": "Provisioned items cannot be edited in the UI"
},
"provisioning": {
"badge-tooltip-provenance": "This resource has been provisioned via {{provenance}} and cannot be edited through the UI",
"badge-tooltip-standard": "This resource has been provisioned and cannot be edited through the UI",
@ -2041,7 +2088,10 @@
"for": "for {{duration}}",
"na": "n/a",
"paused": "Paused",
"recording-rule": "Recording rule"
"recording-rule": "Recording rule",
"recording-rule-state": {
"content-recording-rule-evaluation-is-currently-paused": "Recording rule evaluation is currently paused"
}
},
"rule-stats": {
"error_one": "{{count}} error",
@ -2285,6 +2335,8 @@
"refresh": "Refresh"
},
"template-row": {
"content-templatefiles": "template_files",
"content-templates": "templates",
"tooltip-copy-template-group": "Copy template group",
"tooltip-delete-template-group": "Delete template group",
"tooltip-edit-template-group": "Edit template group",
@ -2308,7 +2360,7 @@
},
"misconfigured-badge-text": "Misconfigured",
"misconfigured-warning": "This template is misconfigured.",
"misconfigured-warning-details": "Templates must be defined in both the <1></1> and <4></4> sections of your alertmanager configuration."
"misconfigured-warning-details": "Templates must be defined in both the <2></2> and <5></5> sections of your alertmanager configuration."
},
"templates-picker": {
"button-edit": "Edit {{name}}",
@ -2457,6 +2509,7 @@
},
"api-keys-table": {
"aria-label-delete-api-key": "Delete API key",
"content-this-api-key-has-expired": "This API key has expired.",
"expires": "Expires",
"last-used-at": "Last used at",
"migrate-to-service-account": "Migrate to service account",
@ -4161,7 +4214,9 @@
},
"variable-check-indicator": {
"aria-label-variable-referenced-dashboard": "This variable is not referenced by any variable or dashboard.",
"aria-label-variable-referenced-other-variables-dashboard": "This variable is referenced by other variables or dashboard."
"aria-label-variable-referenced-other-variables-dashboard": "This variable is referenced by other variables or dashboard.",
"content-variable-not-referenced-other-variables-dashboard": "This variable is not referenced by other variables or dashboard.",
"content-variable-referenced-other-variables-dashboard": "This variable is referenced by other variables or dashboard."
},
"variable-editor-form": {
"aria-label-variable-editor-form": "Variable editor form",
@ -4221,6 +4276,7 @@
},
"versions-history-buttons": {
"compare-versions": "Compare versions",
"content-select-two-versions-to-start-comparing": "Select two versions to start comparing",
"show-more-versions": "Show more versions"
},
"visualization-button": {
@ -4574,6 +4630,7 @@
}
},
"correlation-editor-mode-bar": {
"content-correlations-editor-explore-experimental-feature": "Correlations editor in Explore is an experimental feature.",
"exit-correlation-editor": "Exit correlation editor",
"save": "Save"
},
@ -4731,6 +4788,9 @@
"label-select-query": "Select query",
"tooltip-select-query-visualize-table": "Select a query to visualize in the table"
},
"logs-volume-panel": {
"content-streaming": "Streaming"
},
"logs-volume-panel-list": {
"label-reload-log-volume": "Reload log volume",
"loading": "Loading...",
@ -4930,6 +4990,7 @@
"label-tags": "Tags",
"placeholder-all-service-names": "All service names",
"placeholder-all-span-names": "All span names",
"tooltip-collapse": "Filter your spans below. You can continue to apply filters until you have narrowed down your resulting spans to the select few you are most interested in.",
"tooltip-duration": "Filter by duration. Accepted units are {{units}}",
"tooltip-tags": "Filter by tags, process tags or log fields in your spans."
},
@ -5008,7 +5069,8 @@
"label-show-paths": "Show critical path only switch"
},
"trace-view": {
"no-data": "No data"
"no-data": "No data",
"tooltip-copy-icon": "Copied"
},
"trace-view-container": {
"title-trace": "Trace"
@ -5122,7 +5184,8 @@
"default-password-alert": "Continuing to use the default password exposes you to security risks.",
"new-password-label": "New password",
"skip-button": "Skip",
"submit-button": "Submit"
"submit-button": "Submit",
"tooltip-skip-button": "If you skip you will be prompted to change password next time you log in."
},
"contact-admin": "Did you forget your username or email? Contact your Grafana administrator.",
"email-sent": "An email with a reset link has been sent to the email address. You should receive it shortly.",
@ -5386,7 +5449,11 @@
"previous-page": "previous page"
},
"panel-chrome": {
"aria-label-toggle-collapse": "toggle collapse panel"
"aria-label-toggle-collapse": "toggle collapse panel",
"tooltip-cancel": "Cancel query",
"tooltip-cancel-loading": "Cancel query",
"tooltip-stop-streaming": "Stop streaming",
"tooltip-streaming": "Streaming"
},
"panel-menu": {
"label": "Menu for panel {{ title }}",
@ -5968,7 +6035,8 @@
"log-row-message": {
"ellipsis": "… ",
"more": "more",
"see-details": "See log details"
"see-details": "See log details",
"tooltip-error": "Error: {{errorMessage}}"
},
"log-rows": {
"disable-popover": {
@ -6945,7 +7013,8 @@
"label-search": "Search",
"label-state": "State",
"label-type": "Type",
"subtitle": "Extend the Grafana experience with panel plugins and apps. To find more data sources go to <2>Connections</2>."
"subtitle": "Extend the Grafana experience with panel plugins and apps. To find more data sources go to <2>Connections</2>.",
"tooltip-filter-disabled": "This filter has been disabled because the Grafana server cannot access grafana.com"
},
"catalog": {
"no-updates-available": "No updates available",
@ -6954,7 +7023,7 @@
"available-header": "Available",
"button": "Update all ({{length}})",
"cloud-update-message": "* It may take a few minutes for the plugins to be available for usage.",
"error": "Error updating plugin:",
"error": "Error updating plugin: {{errorMessage}}",
"error-status-text": "failed - see error messages",
"header": "The following plugins have update available",
"installed-header": "Installed",
@ -7164,6 +7233,9 @@
"feature-toggles-age": {
"enable-in-config": "Enable profile in the Grafana config file."
},
"input-suffix": {
"content-login-details-locked-because-managed-another": "Login details locked because they are managed in another system."
},
"user-organizations": {
"text-loading-organizations": "Loading organizations..."
},
@ -8097,10 +8169,12 @@
"title-disable-service-account": "Disable service account"
},
"token-expiration": {
"content-this-token-has-expired": "This token has expired",
"expired-label": "Expired",
"never": "Never"
},
"token-revoked": {
"content-token-publicly-exposed-please-rotate": "This token has been publicly exposed. Please rotate this token",
"revoked-label": "Revoked"
}
},
@ -8506,7 +8580,7 @@
"range-content": {
"apply-button": "Apply time range",
"default-error": "Please enter a past date or \"{{now}}\"",
"fiscal-year": "Fiscal year",
"fiscal-year": "Fiscal year: {{from}} - {{to}}",
"from-input": "From",
"open-input-calendar": "Open calendar",
"range-error": "\"From\" can't be after \"To\"",
@ -8958,6 +9032,7 @@
"loading": "Loading...",
"no-unknowns": "No renamed or missing variables found.",
"renamed-or-missing-variables": "Renamed or missing variables",
"tooltip-renamed-or-missing-variables": "Click to expand a list with all variable references that have been renamed or are missing from the dashboard.",
"variable": "Variable"
},
"variable-check-indicator": {

Loading…
Cancel
Save