i18n: imports use @grafana/i18n (#105177)

* i18n: everything should target @grafana/i18n

* wip

* chore: updates after PR feedback

* Trigger build

* Trigger build

* Trigger build

* chore: skip flaky tests

* chore: skip flaky tests

* chore: skip flaky tests

* chore: skip flaky tests

* chore: skip flaky tests

* chore: skip flaky tests

* chore: revert all flaky tests

* chore: some incorrect usages of useTranslate
This commit is contained in:
Hugo Häggmark 2025-05-15 09:17:14 +02:00 committed by GitHub
parent d8dd2facdd
commit 119d5897ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1112 changed files with 2910 additions and 1877 deletions

View File

@ -17,10 +17,10 @@ Grafana uses the [i18next](https://www.i18next.com/) framework for managing tran
### JSX
1. For JSX children, use the `<Trans />` component from `app/core/internationalization` with the `i18nKey`, ensuring it conforms to the following guidelines, with the default English translation. For example:
1. For JSX children, use the `<Trans />` component from `@grafana/i18n` with the `i18nKey`, ensuring it conforms to the following guidelines, with the default English translation. For example:
```jsx
import { Trans } from 'app/core/internationalization';
import { Trans } from '@grafana/i18n';
const SearchTitle = ({ term }) => <Trans i18nKey="search-page.results-title">Results for {{ term }}</Trans>;
```
@ -32,7 +32,7 @@ There may be cases where you need to interpolate variables inside other componen
If the nested component is displaying the variable only (e.g. to add emphasis or color), the best solution is to create a new wrapping component:
```jsx
import { Trans } from 'app/core/internationalization';
import { Trans } from '@grafana/i18n';
import { Text } from '@grafana/ui';
const SearchTerm = ({ term }) => <Text color="success">{term}</Text>;
@ -47,7 +47,7 @@ const SearchTitle = ({ term }) => (
However there are also cases where the nested component might be displaying additional text which also needs to be translated. In this case, you can use the `values` prop to explicitly pass variables to the translation, and reference them as templated strings in the markup. For example:
```jsx
import { Trans } from 'app/core/internationalization';
import { Trans } from '@grafana/i18n';
import { Text } from '@grafana/ui';
const SearchTitle = ({ term }) => (
@ -75,8 +75,9 @@ const ErrorMessage = ({ id, message }) => <Trans i18nKey={`errors.${id}`}>There
Sometimes you may need to translate a string cannot be represented in JSX, such as `placeholder` props. Use the `t` macro for this.
```jsx
import { t } from "app/core/internationalization"
import { useTranslate } from "@grafana/i18n"
const { t } = useTranslate();
const placeholder = t('form.username-placeholder','Username');
return <input type="value" placeholder={placeholder}>
@ -146,7 +147,7 @@ Refer to the [i18next](https://www.i18next.com/) and [react-i18next](https://rea
For fixed phrases:
```jsx
import { Trans } from 'app/core/internationalization';
import { Trans } from '@grafana/i18n';
<Trans i18nKey="page.greeting">Hello user!</Trans>;
```
@ -154,7 +155,7 @@ import { Trans } from 'app/core/internationalization';
To interpolate a variable, include it as an object child. It's a weird syntax, but `Trans` will do its magic to make it work:
```jsx
import { Trans } from 'app/core/internationalization';
import { Trans } from '@grafana/i18n';
<Trans i18nKey="page.greeting">Hello {{ name: user.name }}!</Trans>;
@ -165,7 +166,7 @@ const userName = user.name;
Variables must be strings (or, must support calling `.toString()`, which we almost never want). For example:
```jsx
import { Trans } from 'app/core/internationalization';
import { Trans } from '@grafana/i18n';
// This will not work
const userName = <strong>user.name</strong>;
@ -183,7 +184,7 @@ const userName = user.name;
Both HTML tags and React components can be included in a phase. The `Trans` function handles interpolating for its children.
```js
import { Trans } from "app/core/internationalization"
import { Trans } from "@grafana/i18n"
<Trans i18nKey="page.explainer">
Click <button>here</button> to <a href="https://grafana.com">learn more.</a>
@ -202,7 +203,7 @@ import { Trans } from "app/core/internationalization"
Plurals require special handling to make sure they can be translated according to the rules of each locale (which may be more complex than you think). Use either the `<Trans />` component or the `t` function, with the `count` prop to provide a singular form. For example:
```js
import { Trans } from 'app/core/internationalization';
import { Trans } from '@grafana/i18n';
<Trans i18nKey="inbox.heading" count={messages.length}>
You got {{ count: messages.length }} messages
@ -210,8 +211,9 @@ import { Trans } from 'app/core/internationalization';
```
```js
import { t } from 'app/core/internationalization';
import { useTranslate } from '@grafana/i18n';
const { t } = useTranslate();
const translatedString = t('inbox.heading', 'You got {{count}} messages', { count: messages.length });
```

View File

@ -119,7 +119,8 @@ export function getNamespaces() {
}
export async function changeLanguage(language?: string) {
await getI18nInstance().changeLanguage(language ?? DEFAULT_LANGUAGE);
const validLanguage = LANGUAGES.find((lang) => lang.code === language)?.code ?? DEFAULT_LANGUAGE;
await getI18nInstance().changeLanguage(validLanguage);
}
type ResourceKey = string;

View File

@ -9,6 +9,13 @@
* preventing the code from being importable by plugins or other npm packages making it truly "internal".
*
*/
import { t } from '../i18n';
type TFunction = typeof t;
export type { TFunction };
export { t };
export {
addResourceBundle,
changeLanguage,
@ -16,5 +23,4 @@ export {
getLanguage,
getResolvedLanguage,
initTranslations,
t,
} from '../i18n';

View File

@ -1,7 +1,7 @@
import { t } from '@grafana/i18n/internal';
import { isFetchError } from '@grafana/runtime';
import { notifyApp } from 'app/core/actions';
import { createSuccessNotification, createErrorNotification } from 'app/core/copy/appNotification';
import { t } from 'app/core/internationalization';
import {
generatedAPI,

View File

@ -18,6 +18,7 @@ import {
standardFieldConfigEditorRegistry,
standardTransformersRegistry,
} from '@grafana/data';
import { initTranslations } from '@grafana/i18n/internal';
import {
locationService,
registerEchoBackend,
@ -61,7 +62,8 @@ import { getAllOptionEditors, getAllStandardFieldConfigs } from './core/componen
import { PluginPage } from './core/components/Page/PluginPage';
import { GrafanaContextType, useReturnToPreviousInternal } from './core/context/GrafanaContext';
import { initializeCrashDetection } from './core/crash';
import { initializeI18n } from './core/internationalization';
import { NAMESPACES } from './core/internationalization/constants';
import { loadTranslations } from './core/internationalization/loadTranslations';
import { postInitTasks, preInitTasks } from './core/lifecycle-hooks';
import { setMonacoEnv } from './core/monacoEnv';
import { interceptLinkClicks } from './core/navigation/patch/interceptLinkClicks';
@ -124,7 +126,14 @@ export class GrafanaApp {
// Let iframe container know grafana has started loading
window.parent.postMessage('GrafanaAppInit', '*');
const initI18nPromise = initializeI18n(config.bootData.user.language);
// This is a placeholder so we can put a 'comment' in the message json files.
// Starts with an underscore so it's sorted to the top of the file. Even though it is in a comment the following line is still extracted
// t('_comment', 'The code is the source of truth for English phrases. They should be updated in the components directly, and additional plurals specified in this file.');
const initI18nPromise = initTranslations({
language: config.bootData.user.language,
ns: NAMESPACES,
module: loadTranslations,
});
initI18nPromise.then(({ language }) => updateConfig({ language }));
setBackendSrv(backendSrv);

View File

@ -1,11 +1,12 @@
import { useEffect, useMemo, useState } from 'react';
import { Trans } from '@grafana/i18n';
import { t } from '@grafana/i18n/internal';
import { Button, Select, Stack } from '@grafana/ui';
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
import { ServiceAccountPicker } from 'app/core/components/Select/ServiceAccountPicker';
import { TeamPicker } from 'app/core/components/Select/TeamPicker';
import { UserPicker } from 'app/core/components/Select/UserPicker';
import { Trans, t } from 'app/core/internationalization';
import { OrgRole } from 'app/types/acl';
import { Assignments, PermissionTarget, SetPermission } from './types';

View File

@ -1,6 +1,6 @@
import { useMemo } from 'react';
import { Trans } from 'app/core/internationalization';
import { Trans } from '@grafana/i18n';
import { PermissionListItem } from './PermissionListItem';
import { ResourcePermission } from './types';

View File

@ -1,8 +1,8 @@
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { Box, Button, Icon, Select, Tooltip, useStyles2 } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { ResourcePermission } from './types';
@ -16,7 +16,7 @@ interface Props {
export const PermissionListItem = ({ item, permissionLevels, canSet, onRemove, onChange }: Props) => {
const styles = useStyles2(getStyles);
const { t } = useTranslate();
return (
<tr>
<td>{getAvatar(item)}</td>

View File

@ -4,9 +4,10 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { t } from '@grafana/i18n/internal';
import { Text, Box, Button, useStyles2, Space } from '@grafana/ui';
import { SlideDown } from 'app/core/components/Animations/SlideDown';
import { Trans, t } from 'app/core/internationalization';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { DescendantCount } from 'app/features/browse-dashboards/components/BrowseActions/DescendantCount';

View File

@ -4,11 +4,11 @@ import { Resizable } from 're-resizable';
import { PropsWithChildren, useEffect } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { locationSearchToObject, locationService, useScopes } from '@grafana/runtime';
import { ErrorBoundaryAlert, getDragStyles, LinkButton, useStyles2 } from '@grafana/ui';
import { useGrafana } from 'app/core/context/GrafanaContext';
import { useMediaQueryMinWidth } from 'app/core/hooks/useMediaQueryMinWidth';
import { Trans } from 'app/core/internationalization';
import store from 'app/core/store';
import { CommandPalette } from 'app/features/commandPalette/CommandPalette';
import { ScopesDashboards } from 'app/features/scopes/dashboards/ScopesDashboards';

View File

@ -2,9 +2,9 @@ import { useObservable } from 'react-use';
import { BehaviorSubject } from 'rxjs';
import { AppEvents, NavModel, NavModelItem, PageLayoutType, UrlQueryValue } from '@grafana/data';
import { t } from '@grafana/i18n/internal';
import { config, locationService, reportInteraction } from '@grafana/runtime';
import appEvents from 'app/core/app_events';
import { t } from 'app/core/internationalization';
import store from 'app/core/store';
import { isShallowEqual } from 'app/core/utils/isShallowEqual';
import { KioskMode } from 'app/types';

View File

@ -2,8 +2,8 @@ import { css, cx } from '@emotion/css';
import { useCallback } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { Dropdown, Menu, ToolbarButton, useTheme2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { NavToolbarSeparator } from '../NavToolbar/NavToolbarSeparator';
@ -17,6 +17,7 @@ export function ExtensionToolbarItem() {
const styles = getStyles(useTheme2());
const { availableComponents, dockedComponentId, setDockedComponentId, isOpen, isEnabled } =
useExtensionSidebarContext();
const { t } = useTranslate();
let dockedComponentTitle = '';
if (dockedComponentId) {
@ -72,7 +73,7 @@ export function ExtensionToolbarItem() {
/>
);
},
[setDockedComponentId, styles.button, styles.buttonActive]
[setDockedComponentId, styles.button, styles.buttonActive, t]
);
if (components.length === 1) {

View File

@ -3,9 +3,9 @@ import { useEffect } from 'react';
import { useToggle } from 'react-use';
import { GrafanaTheme2, store } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { Drawer, ToolbarButton, useStyles2 } from '@grafana/ui';
import { appEvents } from 'app/core/app_events';
import { t } from 'app/core/internationalization';
import { RecordHistoryEntryEvent } from 'app/types/events';
import { HISTORY_LOCAL_STORAGE_KEY } from '../AppChromeService';
@ -47,6 +47,7 @@ export function HistoryContainer() {
};
});
}, []);
const { t } = useTranslate();
return (
<>

View File

@ -3,8 +3,8 @@ import moment from 'moment';
import { useState } from 'react';
import { FieldType, GrafanaTheme2, store } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { Button, Card, IconButton, Space, Stack, Text, useStyles2, Box, Sparkline, useTheme2, Icon } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { formatDate } from 'app/core/internationalization/dates';
import { HISTORY_LOCAL_STORAGE_KEY } from '../AppChromeService';
@ -13,6 +13,7 @@ import { HistoryEntry } from '../types';
import { logClickUnifiedHistoryEntryEvent, logUnifiedHistoryShowMoreEvent } from './eventsTracking';
export function HistoryWrapper({ onClose }: { onClose: () => void }) {
const { t } = useTranslate();
const history = store.getObject<HistoryEntry[]>(HISTORY_LOCAL_STORAGE_KEY, []).filter((entry) => {
return moment(entry.time).isAfter(moment().subtract(2, 'day').startOf('day'));
});
@ -88,6 +89,7 @@ function HistoryEntryAppView({ entry, isSelected, onClick }: ItemProps) {
const styles = useStyles2(getStyles);
const theme = useTheme2();
const [isExpanded, setIsExpanded] = useState(isSelected && entry.views.length > 0);
const { t } = useTranslate();
const { breadcrumbs, views, time, url, sparklineData } = entry;
const expandedLabel = isExpanded
? t('nav.history-wrapper.collapse', 'Collapse')

View File

@ -5,10 +5,10 @@ import { useLocation } from 'react-router-dom-v5-compat';
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useTranslate } from '@grafana/i18n';
import { config, reportInteraction } from '@grafana/runtime';
import { ScrollContainer, useStyles2 } from '@grafana/ui';
import { useGrafana } from 'app/core/context/GrafanaContext';
import { t } from 'app/core/internationalization';
import { setBookmark } from 'app/core/reducers/navBarTree';
import { usePatchUserPreferencesMutation } from 'app/features/preferences/api/index';
import { useDispatch, useSelector } from 'app/types';
@ -37,7 +37,7 @@ export const MegaMenu = memo(
const state = chrome.useState();
const [patchPreferences] = usePatchUserPreferencesMutation();
const pinnedItems = usePinnedItems();
const { t } = useTranslate();
// Remove profile + help from tree
const navItems = navTree
.filter((item) => item.id !== 'profile' && item.id !== 'help')

View File

@ -1,9 +1,9 @@
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { IconButton, Stack, ToolbarButton, useTheme2 } from '@grafana/ui';
import { useGrafana } from 'app/core/context/GrafanaContext';
import { t } from 'app/core/internationalization';
import { Branding } from '../../Branding/Branding';
import { OrganizationSwitcher } from '../OrganizationSwitcher/OrganizationSwitcher';
@ -22,6 +22,7 @@ export function MegaMenuHeader({ handleMegaMenu, handleDockedMenu, onClose }: Pr
const theme = useTheme2();
const { chrome } = useGrafana();
const state = chrome.useState();
const { t } = useTranslate();
const styles = getStyles(theme);
return (

View File

@ -5,10 +5,10 @@ import { useLocation } from 'react-router-dom-v5-compat';
import { useLocalStorage } from 'react-use';
import { FeatureState, GrafanaTheme2, NavModelItem, toIconName } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { useStyles2, Text, IconButton, Icon, Stack, FeatureBadge } from '@grafana/ui';
import { useGrafana } from 'app/core/context/GrafanaContext';
import { t } from '../../../internationalization';
import { Indent } from '../../Indent/Indent';
import { FeatureHighlight } from './FeatureHighlight';
@ -58,6 +58,7 @@ export function MegaMenuItem({ link, activeItem, level = 0, onClick, onPin, isPi
});
}
}, [isActive]);
const { t } = useTranslate();
if (!link.url) {
return null;

View File

@ -3,9 +3,9 @@ import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useTranslate } from '@grafana/i18n';
import { config } from '@grafana/runtime';
import { Icon, IconButton, Link, useTheme2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { contextSrv } from 'app/core/services/context_srv';
export interface Props {
@ -20,6 +20,7 @@ export interface Props {
export function MegaMenuItemText({ children, isActive, onClick, target, url, onPin, isPinned }: Props) {
const theme = useTheme2();
const { t } = useTranslate();
const styles = getStyles(theme, isActive);
const LinkComponent = !target && url.startsWith('/') ? Link : 'a';

View File

@ -1,9 +1,9 @@
import { useEffect } from 'react';
import { NavModelItem } from '@grafana/data';
import { t } from '@grafana/i18n/internal';
import { config, reportInteraction } from '@grafana/runtime';
import { MEGA_MENU_TOGGLE_ID } from 'app/core/constants';
import { t } from 'app/core/internationalization';
import { HOME_NAV_ID } from 'app/core/reducers/navModel';
import { ShowModalReactEvent } from '../../../../types/events';

View File

@ -2,8 +2,8 @@ import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useTranslate } from '@grafana/i18n';
import { IconButton, Drawer, useStyles2, Text } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { DEFAULT_FEED_URL } from 'app/plugins/panel/news/constants';
import grotNewsSvg from 'img/grot-news.svg';
@ -16,7 +16,7 @@ interface NewsContainerProps {
export function NewsContainer({ onClose }: NewsContainerProps) {
const styles = useStyles2(getStyles);
const { t } = useTranslate();
return (
<Drawer
title={

View File

@ -3,13 +3,12 @@ import { useEffect } from 'react';
import { useMeasure } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { useStyles2 } from '@grafana/ui';
import { News } from 'app/plugins/panel/news/component/News';
import { useNewsFeed } from 'app/plugins/panel/news/useNewsFeed';
import grotNewsSvg from 'img/grot-news.svg';
import { t } from '../../../internationalization';
interface NewsWrapperProps {
feedUrl: string;
}
@ -21,6 +20,7 @@ export function NewsWrapper({ feedUrl }: NewsWrapperProps) {
useEffect(() => {
getNews();
}, [getNews]);
const { t } = useTranslate();
if (state.error) {
return <div className={styles.innerWrapper}>{state.error && state.error.message}</div>;

View File

@ -2,16 +2,16 @@ import { css } from '@emotion/css';
import { useMemo, useState } from 'react';
import { SelectableValue, GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { Icon, Select, useStyles2 } from '@grafana/ui';
import { contextSrv } from 'app/core/services/context_srv';
import { UserOrg } from 'app/types';
import { t } from '../../../internationalization';
import { OrganizationBaseProps } from './types';
export function OrganizationSelect({ orgs, onSelectChange }: OrganizationBaseProps) {
const styles = useStyles2(getStyles);
const { t } = useTranslate();
const { orgId } = contextSrv.user;
const options = useMemo(

View File

@ -1,11 +1,11 @@
import { useMemo, useState } from 'react';
import { useTranslate } from '@grafana/i18n';
import { reportInteraction } from '@grafana/runtime';
import { Menu, Dropdown, ToolbarButton } from '@grafana/ui';
import { getExternalUserMngLinkUrl } from 'app/features/users/utils';
import { useSelector } from 'app/types';
import { t } from '../../../internationalization';
import { performInviteUserClick, shouldRenderInviteUserButton } from '../../InviteUserButton/utils';
import { NavToolbarSeparator } from '../NavToolbar/NavToolbarSeparator';
@ -16,6 +16,7 @@ export interface Props {}
export const QuickAdd = ({}: Props) => {
const navBarTree = useSelector((state) => state.navBarTree);
const [isOpen, setIsOpen] = useState(false);
const { t } = useTranslate();
const createActions = useMemo(() => {
const actions = findCreateActions(navBarTree);
@ -32,7 +33,7 @@ export const QuickAdd = ({}: Props) => {
}
return actions;
}, [navBarTree]);
}, [navBarTree, t]);
const showQuickAdd = createActions.length > 0;
if (!showQuickAdd) {

View File

@ -2,8 +2,8 @@ import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useTranslate } from '@grafana/i18n';
import { Button, ButtonGroup, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
export interface DismissableButtonProps {
label: string;
@ -13,7 +13,7 @@ export interface DismissableButtonProps {
export const DismissableButton = ({ label, onClick, onDismiss }: DismissableButtonProps) => {
const styles = useStyles2(getStyles);
const { t } = useTranslate();
return (
<ButtonGroup className={styles.buttonGroup}>
<Button

View File

@ -3,10 +3,10 @@ import { useCallback } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useTranslate } from '@grafana/i18n';
import { locationService } from '@grafana/runtime';
import { useStyles2 } from '@grafana/ui';
import { useGrafana } from 'app/core/context/GrafanaContext';
import { t } from 'app/core/internationalization';
import { DismissableButton } from './DismissableButton';
@ -27,7 +27,7 @@ export const ReturnToPrevious = ({ href, title }: ReturnToPreviousProps) => {
const handleOnDismiss = useCallback(() => {
chrome.clearReturnToPrevious('dismissed');
}, [chrome]);
const { t } = useTranslate();
return (
<div className={styles.returnToPrevious} data-testid={selectors.components.ReturnToPrevious.buttonGroup}>
<DismissableButton

View File

@ -3,10 +3,10 @@ import { cloneDeep } from 'lodash';
import { useToggle } from 'react-use';
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { config } from '@grafana/runtime';
import { Dropdown, Menu, MenuItem, ToolbarButton, useStyles2 } from '@grafana/ui';
import { contextSrv } from 'app/core/core';
import { t } from 'app/core/internationalization';
import { ThemeSelectorDrawer } from '../../ThemeSelector/ThemeSelectorDrawer';
import { enrichWithInteractionTracking } from '../MegaMenu/utils';
@ -24,7 +24,7 @@ export function ProfileButton({ profileNode, onToggleKioskMode }: Props) {
const node = enrichWithInteractionTracking(cloneDeep(profileNode), false);
const [showNewsDrawer, onToggleShowNewsDrawer] = useToggle(false);
const [showThemeDrawer, onToggleThemeDrawer] = useToggle(false);
const { t } = useTranslate();
if (!node) {
return null;
}

View File

@ -2,8 +2,8 @@ import { css } from '@emotion/css';
import { useLocation } from 'react-router-dom-v5-compat';
import { GrafanaTheme2, locationUtil, textUtil } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { useStyles2 } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
export function SignInLink() {
const location = useLocation();

View File

@ -4,6 +4,7 @@ import { memo } from 'react';
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { Components } from '@grafana/e2e-selectors';
import { useTranslate } from '@grafana/i18n';
import { ScopesContextValue } from '@grafana/runtime';
import { Dropdown, Icon, Stack, ToolbarButton, useStyles2 } from '@grafana/ui';
import { config } from 'app/core/config';
@ -11,7 +12,6 @@ import { MEGA_MENU_TOGGLE_ID } from 'app/core/constants';
import { useGrafana } from 'app/core/context/GrafanaContext';
import { contextSrv } from 'app/core/core';
import { useMediaQueryMinWidth } from 'app/core/hooks/useMediaQueryMinWidth';
import { t } from 'app/core/internationalization';
import { HOME_NAV_ID } from 'app/core/reducers/navModel';
import { useSelector } from 'app/types';
@ -64,7 +64,7 @@ export const SingleTopBar = memo(function SingleTopBar({
const breadcrumbs = buildBreadcrumbs(sectionNav, pageNav, homeNav);
const unifiedHistoryEnabled = config.featureToggles.unifiedHistory;
const isSmallScreen = !useMediaQueryMinWidth('sm');
const { t } = useTranslate();
return (
<>
<div className={styles.layout}>

View File

@ -4,10 +4,10 @@ import React, { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useTranslate } from '@grafana/i18n';
import { getInputStyles, Icon, Text, ToolbarButton, useStyles2 } from '@grafana/ui';
import { getFocusStyles } from '@grafana/ui/internal';
import { useMediaQueryMinWidth } from 'app/core/hooks/useMediaQueryMinWidth';
import { t } from 'app/core/internationalization';
import { getModKey } from 'app/core/utils/browser';
import { NavToolbarSeparator } from '../NavToolbar/NavToolbarSeparator';
@ -19,7 +19,7 @@ export const TopSearchBarCommandPaletteTrigger = React.memo(() => {
}));
const isLargeScreen = useMediaQueryMinWidth('lg');
const { t } = useTranslate();
const onOpenSearch = () => {
kbar.toggle();
};
@ -48,7 +48,7 @@ interface PretendTextInputProps {
function PretendTextInput({ onClick }: PretendTextInputProps) {
const styles = useStyles2(getStyles);
const modKey = useMemo(() => getModKey(), []);
const { t } = useTranslate();
// We want the desktop command palette trigger to look like a search box,
// but it actually behaves like a button - you active it and it performs an
// action. You don't actually type into it.

View File

@ -2,8 +2,8 @@ import { css } from '@emotion/css';
import { useEffectOnce } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { Alert, useStyles2 } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { AppNotification, timeoutMap } from 'app/types';
interface Props {

View File

@ -1,14 +1,13 @@
import { css, keyframes } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { useStyles2 } from '@grafana/ui';
import grafanaIconSvg from 'img/grafana_icon.svg';
import { t } from '../../internationalization';
export function BouncingLoader() {
const styles = useStyles2(getStyles);
const { t } = useTranslate();
return (
<div
className={styles.container}

View File

@ -1,10 +1,9 @@
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { useStyles2 } from '@grafana/ui';
import { t } from '../../internationalization';
import { BreadcrumbItem } from './BreadcrumbItem';
import { Breadcrumb } from './types';
@ -15,7 +14,7 @@ export interface Props {
export function Breadcrumbs({ breadcrumbs, className }: Props) {
const styles = useStyles2(getStyles);
const { t } = useTranslate();
return (
<nav aria-label={t('navigation.breadcrumbs.aria-label', 'Breadcrumbs')} className={className}>
<ol className={styles.breadcrumbs}>

View File

@ -2,10 +2,9 @@ import { css } from '@emotion/css';
import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { IconButton, useStyles2 } from '@grafana/ui';
import { t } from '../../internationalization';
type Props = {
onClick: () => void;
'aria-label'?: string;
@ -14,6 +13,8 @@ type Props = {
export const CloseButton = ({ onClick, 'aria-label': ariaLabel, style }: Props) => {
const styles = useStyles2(getStyles);
const { t } = useTranslate();
return (
<IconButton
aria-label={ariaLabel ?? 'Close'}

View File

@ -2,8 +2,8 @@ import { css } from '@emotion/css';
import { MouseEvent } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { Trans } from '@grafana/i18n';
import { Alert, Button, CallToActionCard, Icon, IconName, LinkButton } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
export interface Props {
title: string;

View File

@ -3,9 +3,9 @@ import debounce from 'debounce-promise';
import { useCallback, useMemo, useState } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { AsyncMultiSelect, Icon, Button, useStyles2 } from '@grafana/ui';
import { config } from 'app/core/config';
import { t, Trans } from 'app/core/internationalization';
import { getBackendSrv } from 'app/core/services/backend_srv';
import { getGrafanaSearcher } from 'app/features/search/service/searcher';
import { DashboardSearchItemType } from 'app/features/search/types';
@ -21,6 +21,7 @@ export function FolderFilter({ onChange, maxMenuHeight }: FolderFilterProps): JS
const [loading, setLoading] = useState(false);
const getOptions = useCallback((searchString: string) => getFoldersAsOptions(searchString, setLoading), []);
const debouncedLoadOptions = useMemo(() => debounce(getOptions, 300), [getOptions]);
const { t } = useTranslate();
const [value, setValue] = useState<Array<SelectableValue<FolderInfo>>>([]);
const onSelectOptionChange = useCallback(

View File

@ -2,9 +2,9 @@ import { css } from '@emotion/css';
import { memo } from 'react';
import { GrafanaTheme2, LinkTarget } from '@grafana/data';
import { t } from '@grafana/i18n/internal';
import { config } from '@grafana/runtime';
import { Icon, IconName, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
export interface FooterLink {
target: LinkTarget;

View File

@ -2,9 +2,9 @@ import { SyntheticEvent, useState } from 'react';
import { useForm } from 'react-hook-form';
import { selectors } from '@grafana/e2e-selectors';
import { Trans, useTranslate } from '@grafana/i18n';
import { config } from '@grafana/runtime';
import { Tooltip, Field, Button, Alert, useStyles2, Stack } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { getStyles } from '../Login/LoginForm';
import { PasswordField } from '../PasswordField/PasswordField';
@ -27,6 +27,7 @@ interface PasswordDTO {
export const ChangePassword = ({ onSubmit, onSkip, showDefaultPasswordWarning }: Props) => {
const styles = useStyles2(getStyles);
const { t } = useTranslate();
const [displayValidationLabels, setDisplayValidationLabels] = useState(false);
const [pristine, setPristine] = useState(true);

View File

@ -3,10 +3,10 @@ import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { getBackendSrv } from '@grafana/runtime';
import { Field, Input, Button, Legend, Container, useStyles2, LinkButton, Stack } from '@grafana/ui';
import config from 'app/core/config';
import { t, Trans } from 'app/core/internationalization';
interface EmailDTO {
userOrEmail: string;
@ -30,6 +30,7 @@ export const ForgottenPassword = () => {
register,
formState: { errors },
} = useForm<EmailDTO>();
const { t } = useTranslate();
const sendEmail = async (formModel: EmailDTO) => {
const res = await getBackendSrv().post('/api/user/password/send-reset-email', formModel);

View File

@ -3,8 +3,8 @@ import history from 'history';
import { useEffect, useState } from 'react';
import { Navigate } from 'react-router-dom-v5-compat';
import { Trans, useTranslate } from '@grafana/i18n';
import { Button, Modal } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { Prompt } from './Prompt';
@ -96,6 +96,8 @@ interface UnsavedChangesModalProps {
}
const UnsavedChangesModal = ({ onDiscard, onBackToForm, isOpen }: UnsavedChangesModalProps) => {
const { t } = useTranslate();
return (
<Modal
isOpen={isOpen}

View File

@ -1,9 +1,11 @@
import { useTranslate } from '@grafana/i18n';
import { Button } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { performInviteUserClick } from './utils';
export function InviteUserButton() {
const { t } = useTranslate();
return (
<Button
icon="add-user"

View File

@ -2,10 +2,9 @@ import { css, cx } from '@emotion/css';
import { DragDropContext, Draggable, Droppable, DropResult } from '@hello-pangea/dnd';
import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { Icon, IconButton, useStyles2 } from '@grafana/ui';
import { t } from '../../internationalization';
import { LayerName } from './LayerName';
import { LayerElement } from './types';
@ -39,7 +38,7 @@ export const LayerDragDropList = <T extends LayerElement>({
verifyLayerNameUniqueness,
}: LayerDragDropListProps<T>) => {
const style = useStyles2(getStyles);
const { t } = useTranslate();
const getRowStyle = (isSelected: boolean) => {
return isSelected ? `${style.row} ${style.sel}` : style.row;
};

View File

@ -3,10 +3,9 @@ import { useState } from 'react';
import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { Icon, Input, FieldValidationMessage, useStyles2 } from '@grafana/ui';
import { t } from '../../internationalization';
export interface LayerNameProps {
name: string;
onChange: (v: string) => void;
@ -19,6 +18,7 @@ export const LayerName = ({ name, onChange, verifyLayerNameUniqueness, overrideS
const [isEditing, setIsEditing] = useState<boolean>(false);
const [validationError, setValidationError] = useState<string | null>(null);
const { t } = useTranslate();
const onEditLayer = (event: React.SyntheticEvent) => {
setIsEditing(true);

View File

@ -1,8 +1,8 @@
import { PureComponent } from 'react';
import { t } from '@grafana/i18n/internal';
import { FetchError, getBackendSrv, isFetchError, locationService } from '@grafana/runtime';
import config from 'app/core/config';
import { t } from 'app/core/internationalization';
import { LoginDTO, AuthNRedirectDTO } from './types';

View File

@ -4,8 +4,8 @@ import { useForm } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useTranslate } from '@grafana/i18n';
import { Button, Input, Field, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { PasswordField } from '../PasswordField/PasswordField';
@ -28,7 +28,7 @@ export const LoginForm = ({ children, onSubmit, isLoggingIn, passwordHint, login
register,
formState: { errors },
} = useForm<FormModel>({ mode: 'onChange' });
const { t } = useTranslate();
return (
<div className={styles.wrapper}>
<form onSubmit={handleSubmit(onSubmit)}>

View File

@ -3,8 +3,8 @@ import { useEffect, useState } from 'react';
import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { useStyles2 } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { Branding } from '../Branding/Branding';
import { BrandingSettings } from '../Branding/types';

View File

@ -3,10 +3,10 @@ import { css } from '@emotion/css';
// Components
import { GrafanaTheme2 } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { config } from '@grafana/runtime';
import { Alert, LinkButton, Stack, useStyles2 } from '@grafana/ui';
import { Branding } from 'app/core/components/Branding/Branding';
import { t, Trans } from 'app/core/internationalization';
import { ChangePassword } from '../ForgottenPassword/ChangePassword';
@ -20,6 +20,7 @@ import { UserSignup } from './UserSignup';
const LoginPage = () => {
const styles = useStyles2(getStyles);
const { t } = useTranslate();
document.title = Branding.AppTitle;
return (

View File

@ -2,9 +2,9 @@ import { css, cx } from '@emotion/css';
import { pickBy } from 'lodash';
import { GrafanaTheme2, DEFAULT_SAML_NAME } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { Icon, IconName, LinkButton, Stack, useStyles2, useTheme2 } from '@grafana/ui';
import config from 'app/core/config';
import { Trans } from 'app/core/internationalization';
export interface LoginService {
bgColor: string;

View File

@ -4,10 +4,10 @@ import { useForm } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useTranslate } from '@grafana/i18n';
import { locationService } from '@grafana/runtime';
import { Button, Input, Field, useStyles2 } from '@grafana/ui';
import { Branding } from 'app/core/components/Branding/Branding';
import { t } from 'app/core/internationalization';
import { PasswordlessConfirmationFormModel } from './LoginCtrl';
@ -55,6 +55,7 @@ export const PasswordlessConfirmation = ({ onSubmit, isLoggingIn }: Props) => {
setValue('name', queryValues.get('name') || '');
}
}, [setValue, handleSubmit, onSubmit, setSignup]);
const { t } = useTranslate();
return (
<div className={styles.wrapper}>

View File

@ -4,8 +4,8 @@ import { useForm } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useTranslate } from '@grafana/i18n';
import { Button, Input, Field, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { PasswordlessFormModel } from './LoginCtrl';
@ -22,7 +22,7 @@ export const PasswordlessLoginForm = ({ onSubmit, isLoggingIn }: Props) => {
register,
formState: { errors },
} = useForm<PasswordlessFormModel>({ mode: 'onChange' });
const { t } = useTranslate();
return (
<div className={styles.wrapper}>
<form onSubmit={handleSubmit(onSubmit)}>

View File

@ -1,8 +1,8 @@
import { css } from '@emotion/css';
import { Trans } from '@grafana/i18n';
import { LinkButton, Stack } from '@grafana/ui';
import { getConfig } from 'app/core/config';
import { Trans } from 'app/core/internationalization';
export const UserSignup = () => {
const href = getConfig().verifyEmailEnabled ? `${getConfig().appSubUrl}/verify` : `${getConfig().appSubUrl}/signup`;

View File

@ -1,5 +1,5 @@
import { useTranslate } from '@grafana/i18n';
import { Badge } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { useIsProvisionedInstance } from 'app/features/provisioning/hooks/useIsProvisionedInstance';
import { NestedFolderDTO } from 'app/features/search/service/types';
import { FolderDTO, FolderListItemDTO } from 'app/types';
@ -10,6 +10,8 @@ export interface Props {
export function FolderRepo({ folder }: Props) {
const isProvisionedInstance = useIsProvisionedInstance();
const { t } = useTranslate();
if (!folder || ('parentUID' in folder && folder.parentUID) || !folder.managedBy || isProvisionedInstance) {
return null;
}

View File

@ -6,9 +6,9 @@ import { FixedSizeList as List } from 'react-window';
import InfiniteLoader from 'react-window-infinite-loader';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { IconButton, useStyles2, Text } from '@grafana/ui';
import { Indent } from 'app/core/components/Indent/Indent';
import { Trans } from 'app/core/internationalization';
import { childrenByParentUIDSelector, rootItemsSelector } from 'app/features/browse-dashboards/state';
import { DashboardsTreeItem } from 'app/features/browse-dashboards/types';
import { DashboardViewItem } from 'app/features/search/types';

View File

@ -6,9 +6,9 @@ import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react'
import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { config } from '@grafana/runtime';
import { Alert, Icon, Input, LoadingBar, Stack, Text, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { useGetFolderQuery } from 'app/features/browse-dashboards/api/browseDashboardsAPI';
import { DashboardViewItemWithUIItems, DashboardsTreeItem } from 'app/features/browse-dashboards/types';
import { getGrafanaSearcher } from 'app/features/search/service/searcher';
@ -250,6 +250,7 @@ export function NestedFolderPicker({
},
[flatTree]
);
const { t } = useTranslate();
const isLoading = isBrowseLoading || isFetchingSearchResults;

View File

@ -3,9 +3,9 @@ import { forwardRef, ReactNode, ButtonHTMLAttributes } from 'react';
import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { Icon, getInputStyles, useTheme2, Text } from '@grafana/ui';
import { getFocusStyles, getMouseFocusStyles } from '@grafana/ui/internal';
import { Trans, t } from 'app/core/internationalization';
import { FolderPickerSkeleton } from './Skeleton';
@ -21,6 +21,7 @@ function Trigger(
ref: React.ForwardedRef<HTMLButtonElement>
) {
const theme = useTheme2();
const { t } = useTranslate();
const styles = getStyles(theme, invalid);
const handleKeyDown = (event: React.KeyboardEvent<SVGElement>) => {

View File

@ -1,11 +1,10 @@
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { useTheme2, useStyles2, ColorPicker, IconButton } from '@grafana/ui';
import { ColorSwatch } from '@grafana/ui/internal';
import { t } from '../../internationalization';
export interface ColorValueEditorSettings {
placeholder?: string;
/** defaults to true */
@ -29,7 +28,7 @@ interface Props {
export const ColorValueEditor = ({ value, settings, onChange, details }: Props) => {
const theme = useTheme2();
const styles = useStyles2(getStyles);
const { t } = useTranslate();
return (
<ColorPicker color={value ?? ''} onChange={onChange} enableNamedColors={settings?.enableNamedColors !== false}>
{({ ref, showColorPicker, hideColorPicker }) => {

View File

@ -13,10 +13,9 @@ import {
FieldColorSeriesByMode,
getFieldColorMode,
} from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { useStyles2, useTheme2, Field, RadioButtonGroup, Select } from '@grafana/ui';
import { t } from '../../internationalization';
import { ColorValueEditor } from './color';
type Props = StandardEditorProps<FieldColor | undefined, FieldColorConfigSettings>;
@ -24,6 +23,7 @@ type Props = StandardEditorProps<FieldColor | undefined, FieldColorConfigSetting
export const FieldColorEditor = ({ value, onChange, item, id }: Props) => {
const theme = useTheme2();
const styles = useStyles2(getStyles);
const { t } = useTranslate();
const colorMode = getFieldColorMode(value?.mode);
const availableOptions = item.settings?.byValueSupport

View File

@ -1,14 +1,14 @@
import { css } from '@emotion/css';
import { StandardEditorProps, GrafanaTheme2, UnitFieldConfigSettings } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { IconButton, UnitPicker, useStyles2 } from '@grafana/ui';
import { t } from '../../internationalization';
type Props = StandardEditorProps<string, UnitFieldConfigSettings>;
export function UnitValueEditor({ value, onChange, item }: Props) {
const styles = useStyles2(getStyles);
const { t } = useTranslate();
if (item?.settings?.isClearable && value != null) {
return (
<div className={styles.wrapper}>

View File

@ -3,11 +3,10 @@ import { useCallback, useEffect, useState } from 'react';
import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { isFetchError } from '@grafana/runtime';
import { Field, IconButton, Input, useStyles2, Text } from '@grafana/ui';
import { t } from '../../internationalization';
export interface Props {
value: string;
onEdit: (newValue: string) => Promise<void>;
@ -54,6 +53,7 @@ export const EditableTitle = ({ value, onEdit }: Props) => {
},
[onEdit, value]
);
const { t } = useTranslate();
return !isEditing ? (
<div className={styles.textContainer}>

View File

@ -2,8 +2,8 @@ import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Trans } from '@grafana/i18n';
import { EmptyState, TextLink, useStyles2 } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
export interface Props {
/**

View File

@ -2,8 +2,8 @@ import { css } from '@emotion/css';
import { useCallback, useMemo, useState } from 'react';
import { GrafanaTheme2, PanelPluginMeta, SelectableValue } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { Icon, Button, MultiSelect, useStyles2 } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { getAllPanelPluginMeta } from 'app/features/panel/state/util';
export interface Props {
@ -30,7 +30,7 @@ export const PanelTypeFilter = ({ onChange: propsOnChange, maxMenuHeight }: Prop
[propsOnChange]
);
const styles = useStyles2(getStyles);
const { t } = useTranslate();
const selectOptions = {
defaultOptions: true,
getOptionLabel: (i: SelectableValue<PanelPluginMeta>) => i.label,

View File

@ -1,16 +1,15 @@
import { forwardRef, useState } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { useTranslate } from '@grafana/i18n';
import { Input, IconButton } from '@grafana/ui';
import { InputProps } from '@grafana/ui/internal';
import { t } from '../../internationalization';
interface Props extends Omit<InputProps, 'type'> {}
export const PasswordField = forwardRef<HTMLInputElement, Props>((props, ref) => {
const [showPassword, setShowPassword] = useState(false);
const { t } = useTranslate();
return (
<Input
{...props}

View File

@ -1,15 +1,17 @@
import { useAsync } from 'react-use';
import { renderMarkdown } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { getBackendSrv } from '@grafana/runtime';
import { LoadingPlaceholder } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
interface Props {
pluginId: string;
}
export function PluginHelp({ pluginId }: Props) {
const { t } = useTranslate();
const { value, loading, error } = useAsync(async () => {
return getBackendSrv().get(`/api/plugins/${pluginId}/markdown/query_help`);
}, []);

View File

@ -4,8 +4,8 @@ import { MouseEventHandler } from 'react';
import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { Icon, IconButton, useStyles2, Stack } from '@grafana/ui';
import { t } from 'app/core/internationalization';
export interface QueryOperationRowHeaderProps {
actionsElement?: React.ReactNode;
@ -42,7 +42,7 @@ export const QueryOperationRowHeader = ({
expanderMessages,
}: QueryOperationRowHeaderProps) => {
const styles = useStyles2(getStyles);
const { t } = useTranslate();
let tooltipMessage = isContentVisible
? t('query-operation.header.collapse-row', 'Collapse query row')
: t('query-operation.header.expand-row', 'Expand query row');

View File

@ -1,6 +1,6 @@
import { SelectableValue } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { Icon, RadioButtonList, Tooltip, useStyles2, useTheme2, PopoverContent } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { OrgRole } from 'app/types';
import { getStyles } from './styles';

View File

@ -2,11 +2,10 @@ import { cx } from '@emotion/css';
import { FormEvent, memo } from 'react';
import * as React from 'react';
import { useTranslate } from '@grafana/i18n';
import { Checkbox, Portal, useStyles2, useTheme2 } from '@grafana/ui';
import { getSelectStyles } from '@grafana/ui/internal';
import { t } from '../../internationalization';
import { getStyles } from './styles';
interface RoleMenuGroupsOptionProps {
@ -48,7 +47,7 @@ export const RoleMenuGroupOption = memo(
const theme = useTheme2();
const styles = getSelectStyles(theme);
const customStyles = useStyles2(getStyles);
const { t } = useTranslate();
const wrapperClassName = cx(
styles.option,
isFocused && styles.optionFocused,

View File

@ -1,12 +1,11 @@
import { cx } from '@emotion/css';
import { forwardRef, FormEvent } from 'react';
import { useTranslate } from '@grafana/i18n';
import { Checkbox, Icon, Tooltip, useStyles2, useTheme2 } from '@grafana/ui';
import { getSelectStyles } from '@grafana/ui/internal';
import { Role } from 'app/types';
import { t } from '../../internationalization';
import { getStyles } from './styles';
interface RoleMenuOptionProps {
@ -25,6 +24,7 @@ export const RoleMenuOption = forwardRef<HTMLDivElement, React.PropsWithChildren
const theme = useTheme2();
const styles = getSelectStyles(theme);
const customStyles = useStyles2(getStyles);
const { t } = useTranslate();
disabled = disabled || mapped;
let disabledMessage = '';
if (disabled) {

View File

@ -3,9 +3,9 @@ import { FormEvent, HTMLProps, useEffect, useRef } from 'react';
import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { useStyles2, getInputStyles, sharedInputStyle, Tooltip, Icon, Spinner } from '@grafana/ui';
import { getFocusStyles } from '@grafana/ui/internal';
import { t, Trans } from 'app/core/internationalization';
import { Role } from '../../../types';
@ -44,6 +44,7 @@ export const RolePickerInput = ({
}: InputProps): JSX.Element => {
const styles = useStyles2(getRolePickerInputStyles, false, !!isFocused, !!disabled, false, width);
const inputRef = useRef<HTMLInputElement | null>(null);
const { t } = useTranslate();
useEffect(() => {
if (isFocused) {

View File

@ -1,9 +1,9 @@
import { css, cx } from '@emotion/css';
import { useEffect, useRef, useState } from 'react';
import { Trans, useTranslate } from '@grafana/i18n';
import { Button, ScrollContainer, Stack, TextLink, useStyles2, useTheme2 } from '@grafana/ui';
import { getSelectStyles } from '@grafana/ui/internal';
import { t, Trans } from 'app/core/internationalization';
import { OrgRole, Role } from 'app/types';
import { BuiltinRoleSelector } from './BuiltinRoleSelector';
@ -138,6 +138,8 @@ export const RolePickerMenu = ({
});
}, [options]);
const { t } = useTranslate();
const getSelectedGroupOptions = (group: string) => {
const selectedGroupOptions = [];
for (const role of selectedOptions) {

View File

@ -1,8 +1,8 @@
import { cx } from '@emotion/css';
import { Trans, useTranslate } from '@grafana/i18n';
import { Button, ScrollContainer, Stack, useStyles2, useTheme2 } from '@grafana/ui';
import { getSelectStyles } from '@grafana/ui/internal';
import { t, Trans } from 'app/core/internationalization';
import { Role } from 'app/types';
import { RoleMenuOption } from './RoleMenuOption';
@ -30,7 +30,7 @@ export const RolePickerSubMenu = ({
const theme = useTheme2();
const styles = getSelectStyles(theme);
const customStyles = useStyles2(getStyles);
const { t } = useTranslate();
const onClearInternal = async () => {
if (onClear) {
onClear();

View File

@ -3,11 +3,10 @@ import { useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { useStyles2, Badge, Stack } from '@grafana/ui';
import { OrgUser } from 'app/types';
import { t } from '../../internationalization';
import { RolePickerDrawer } from './RolePickerDrawer';
export interface Props {
@ -28,6 +27,7 @@ export const RolePickerBadges = ({ disabled, user }: Props) => {
roles: user.roles,
},
});
const { t } = useTranslate();
const { watch } = methods;
const drawerControl = () => {

View File

@ -1,8 +1,8 @@
import { Controller, useFormContext } from 'react-hook-form';
import { toOption } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { Drawer, Field, RadioButtonGroup, TextLink } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { OrgRole } from 'app/types';
const roleOptions = Object.keys(OrgRole).map(toOption);
@ -29,6 +29,8 @@ export const RolePickerDrawer = ({ onClose }: Props) => {
const methods = useFormContext();
const { control, getValues, setValue } = methods;
const [name, roles] = getValues(['name', 'roles']);
const { t } = useTranslate();
return (
<Drawer title={name} subtitle={drawerSubtitle} onClose={onClose}>
<Field label={t('role-picker-drawer.basic-roles.label', 'Basic Roles')}>

View File

@ -6,10 +6,10 @@ import { useAsync } from 'react-use';
import { AppEvents, GrafanaTheme2, SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Trans, useTranslate } from '@grafana/i18n';
import { reportInteraction } from '@grafana/runtime';
import { ActionMeta, AsyncVirtualizedSelect, Input, InputActionMeta, useStyles2 } from '@grafana/ui';
import appEvents from 'app/core/app_events';
import { t, Trans } from 'app/core/internationalization';
import { contextSrv } from 'app/core/services/context_srv';
import { createFolder, getFolderByUid, searchFolders } from 'app/features/manage-dashboards/state/actions';
import { DashboardSearchHit } from 'app/features/search/types';
@ -281,6 +281,8 @@ export function OldFolderPicker(props: Props) {
[customAdd?.disallowValues, customAdd?.isAllowedValue, newFolderValue, createNewFolder, folder?.title, rootName]
);
const { t } = useTranslate();
const onNewFolderChange = (e: FormEvent<HTMLInputElement>) => {
const value = e.currentTarget.value;
setNewFolderValue(value);

View File

@ -2,12 +2,11 @@ import { useEffect, useState } from 'react';
import { useAsyncFn } from 'react-use';
import { SelectableValue } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { getBackendSrv } from '@grafana/runtime';
import { AsyncSelect } from '@grafana/ui';
import { Organization, UserOrg } from 'app/types';
import { t } from '../../internationalization';
export type OrgSelectItem = SelectableValue<Organization>;
export interface Props {
@ -50,6 +49,7 @@ export function OrgPicker({ onSelected, className, inputId, autoFocus, excludeOr
return allOrgs;
}
});
const { t } = useTranslate();
return (
<AsyncSelect

View File

@ -3,12 +3,11 @@ import { isNil } from 'lodash';
import { Component } from 'react';
import { SelectableValue } from '@grafana/data';
import { t } from '@grafana/i18n/internal';
import { getBackendSrv } from '@grafana/runtime';
import { AsyncSelect } from '@grafana/ui';
import { ServiceAccountDTO, ServiceAccountsState } from 'app/types';
import { t } from '../../internationalization';
export interface Props {
onSelected: (user: SelectableValue<ServiceAccountDTO>) => void;
className?: string;

View File

@ -1,12 +1,11 @@
import { useAsync } from 'react-use';
import { SelectableValue } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { Icon, Select } from '@grafana/ui';
import { DEFAULT_SORT } from 'app/features/search/constants';
import { getGrafanaSearcher } from 'app/features/search/service/searcher';
import { t } from '../../internationalization';
export interface Props {
onChange: (sortValue: SelectableValue) => void;
value?: string;
@ -29,6 +28,7 @@ export function SortPicker({ onChange, value, placeholder, filter, getSortOption
}
return vals;
}, [getSortOptions, filter]);
const { t } = useTranslate();
if (options.loading) {
return null;

View File

@ -3,12 +3,11 @@ import { isNil } from 'lodash';
import { Component } from 'react';
import { SelectableValue } from '@grafana/data';
import { t } from '@grafana/i18n/internal';
import { getBackendSrv } from '@grafana/runtime';
import { AsyncSelect } from '@grafana/ui';
import { Team } from 'app/types';
import { t } from '../../internationalization';
export interface Props {
onSelected: (team: SelectableValue<Team>) => void;
className?: string;

View File

@ -3,12 +3,11 @@ import { isNil } from 'lodash';
import { Component } from 'react';
import { SelectableValue } from '@grafana/data';
import { t } from '@grafana/i18n/internal';
import { getBackendSrv } from '@grafana/runtime';
import { AsyncSelect } from '@grafana/ui';
import { OrgUser } from 'app/types';
import { t } from '../../internationalization';
export interface Props {
onSelected: (user: SelectableValue<OrgUser>) => void;
className?: string;

View File

@ -4,7 +4,8 @@ import * as React from 'react';
import { FeatureState, ThemeRegistryItem } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { PSEUDO_LOCALE } from '@grafana/i18n';
import { PSEUDO_LOCALE, Trans } from '@grafana/i18n';
import { t } from '@grafana/i18n/internal';
import { config, reportInteraction } from '@grafana/runtime';
import { Preferences as UserPreferencesDTO } from '@grafana/schema/src/raw/preferences/x/preferences_types.gen';
import {
@ -23,7 +24,6 @@ import {
isWeekStart,
} from '@grafana/ui';
import { DashboardPicker } from 'app/core/components/Select/DashboardPicker';
import { t, Trans } from 'app/core/internationalization';
import { LANGUAGES } from 'app/core/internationalization/constants';
import { LOCALES } from 'app/core/internationalization/locales';
import { PreferencesService } from 'app/core/services/PreferencesService';

View File

@ -1,10 +1,10 @@
import { useForm } from 'react-hook-form';
import { Trans, useTranslate } from '@grafana/i18n';
import { getBackendSrv } from '@grafana/runtime';
import { Field, Input, Button, LinkButton, Stack } from '@grafana/ui';
import { getConfig } from 'app/core/config';
import { useAppNotification } from 'app/core/copy/appNotification';
import { t, Trans } from 'app/core/internationalization';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { w3cStandardEmailValidator } from 'app/features/admin/utils';
@ -36,7 +36,7 @@ export const SignupPage = ({ queryParams }: Props) => {
register,
getValues,
} = useForm<SignupDTO>({ defaultValues: { email: queryParams.email, code: queryParams.code } });
const { t } = useTranslate();
const onSubmit = async (formData: SignupDTO) => {
if (formData.name === '') {
delete formData.name;

View File

@ -1,11 +1,11 @@
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { Trans, useTranslate } from '@grafana/i18n';
import { getBackendSrv } from '@grafana/runtime';
import { Field, Input, Button, Legend, Container, LinkButton, Stack } from '@grafana/ui';
import { getConfig } from 'app/core/config';
import { useAppNotification } from 'app/core/copy/appNotification';
import { t, Trans } from 'app/core/internationalization';
import { w3cStandardEmailValidator } from 'app/features/admin/utils';
interface EmailDTO {
@ -20,7 +20,7 @@ export const VerifyEmail = () => {
formState: { errors },
} = useForm<EmailDTO>();
const [emailSent, setEmailSent] = useState(false);
const { t } = useTranslate();
const onSubmit = (formModel: EmailDTO) => {
getBackendSrv()
.post('/api/user/signup', formModel)

View File

@ -3,8 +3,8 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import { components, MultiValueRemoveProps } from 'react-select';
import { escapeStringForRegex, GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { Icon, MultiSelect, useStyles2 } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { TagBadge, getStyles as getTagBadgeStyles } from './TagBadge';
import { TagOption, TagSelectOption } from './TagOption';
@ -55,7 +55,7 @@ export const TagFilter = ({
// Necessary to force re-render to keep tag options up to date / relevant
const selectKey = useMemo(() => tags.join(), [tags]);
const { t } = useTranslate();
const onLoadOptions = useCallback(async () => {
const options = await tagOptions();
return options.map((option) => {

View File

@ -2,10 +2,9 @@ import { css, cx } from '@emotion/css';
import { OptionProps } from 'react-select';
import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { useStyles2 } from '@grafana/ui';
import { t } from '../../internationalization';
import { TagBadge } from './TagBadge';
export interface TagSelectOption {
@ -16,7 +15,7 @@ export interface TagSelectOption {
export const TagOption = ({ data, className, label, isFocused, innerProps }: OptionProps<TagSelectOption>) => {
const styles = useStyles2(getStyles);
const { t } = useTranslate();
return (
<div
className={cx(styles.option, isFocused && styles.optionFocused)}

View File

@ -1,9 +1,9 @@
import { css, cx } from '@emotion/css';
import { GrafanaTheme2, ThemeContext } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { Box, Divider, Icon, Stack, useStyles2 } from '@grafana/ui';
import { Trans } from '../../internationalization';
import { Branding } from '../Branding/Branding';
interface ThemePreviewProps {

View File

@ -1,9 +1,10 @@
import { css } from '@emotion/css';
import { FeatureState, GrafanaTheme2, ThemeRegistryItem } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { TFunction } from '@grafana/i18n/internal';
import { config, reportInteraction } from '@grafana/runtime';
import { Drawer, FeatureBadge, RadioButtonDot, TextLink, useStyles2, useTheme2 } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { changeTheme } from 'app/core/services/theme';
import { ThemePreview } from '../Theme/ThemePreview';
@ -18,7 +19,7 @@ export function ThemeSelectorDrawer({ onClose }: Props) {
const styles = useStyles2(getStyles);
const themes = getSelectableThemes();
const currentTheme = useTheme2();
const { t } = useTranslate();
const onChange = (theme: ThemeRegistryItem) => {
reportInteraction('grafana_preferences_theme_changed', {
toTheme: theme.id,
@ -70,8 +71,9 @@ interface ThemeCardProps {
}
function ThemeCard({ themeOption, isExperimental, isSelected, onSelect }: ThemeCardProps) {
const { t } = useTranslate();
const theme = themeOption.build();
const label = getTranslatedThemeName(themeOption);
const label = getTranslatedThemeName(themeOption, t);
const styles = useStyles2(getStyles);
return (
@ -126,7 +128,7 @@ const getStyles = (theme: GrafanaTheme2) => {
};
};
function getTranslatedThemeName(theme: ThemeRegistryItem) {
function getTranslatedThemeName(theme: ThemeRegistryItem, t: TFunction) {
switch (theme.id) {
case 'dark':
return t('shared.preferences.theme.dark-label', 'Dark');

View File

@ -1,9 +1,9 @@
import { uniqBy } from 'lodash';
import { AppEvents, TimeRange, isDateTime, rangeUtil } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { TimeRangePickerProps, TimeRangePicker } from '@grafana/ui';
import appEvents from 'app/core/app_events';
import { t } from 'app/core/internationalization';
import { LocalStorageValueProvider } from '../LocalStorageValueProvider';
@ -21,6 +21,8 @@ interface TimePickerHistoryItem {
type LSTimePickerHistoryItem = TimePickerHistoryItem | TimeRange;
export const TimePickerWithHistory = (props: Props) => {
const { t } = useTranslate();
return (
<LocalStorageValueProvider<LSTimePickerHistoryItem[]> storageKey={LOCAL_STORAGE_KEY} defaultValue={[]}>
{(rawValues, onSaveToStore) => {

View File

@ -2,9 +2,9 @@ import { css, cx } from '@emotion/css';
import { HTMLAttributes, useEffect } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { reportExperimentView } from '@grafana/runtime';
import { Button, Icon, LinkButton, useStyles2 } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
type ComponentSize = 'sm' | 'md';
@ -32,6 +32,8 @@ export const UpgradeBox = ({
reportExperimentView(`feature-highlights-${featureId}`, 'test', eventVariant);
}, [eventVariant, featureId]);
const { t } = useTranslate();
return (
<div className={cx(styles.box, className)} {...htmlProps}>
<Icon name={'rocket'} className={styles.icon} />

View File

@ -1,9 +1,9 @@
import { css, cx } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { t } from '@grafana/i18n/internal';
import { Box, Icon, Text, useStyles2 } from '@grafana/ui';
import config from 'app/core/config';
import { t } from 'app/core/internationalization';
interface StrongPasswordValidation {
message: string;

View File

@ -2,8 +2,8 @@ import { identity } from 'lodash';
import { useState } from 'react';
import { dateTimeFormatTimeAgo } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { Box, Button, Divider, EmptyState, Icon, Stack, Text } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { DiffGroup } from 'app/features/dashboard-scene/settings/version-history/DiffGroup';
import { DiffViewer } from 'app/features/dashboard-scene/settings/version-history/DiffViewer';
import { jsonDiff } from 'app/features/dashboard-scene/settings/version-history/utils';
@ -66,7 +66,7 @@ export const VersionHistoryComparison = <T extends DiffArgument>({
const diff = jsonDiff(preprocessVersion(oldVersion), preprocessVersion(newVersion));
const noHumanReadableDiffs = Object.entries(diff).length === 0;
const [showJsonDiff, setShowJsonDiff] = useState(noHumanReadableDiffs);
const { t } = useTranslate();
return (
<Stack gap={2} direction="column">
<Box>

View File

@ -2,11 +2,12 @@ import { css } from '@emotion/css';
import { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { TFunction } from '@grafana/i18n/internal';
import { Grid, Modal, useStyles2, Text } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { getModKey } from 'app/core/utils/browser';
const getShortcuts = (modKey: string) => {
const getShortcuts = (modKey: string, t: TFunction) => {
return [
{
category: t('help-modal.shortcuts-category.global', 'Global'),
@ -149,9 +150,10 @@ export interface HelpModalProps {
export const HelpModal = ({ onDismiss }: HelpModalProps): JSX.Element => {
const styles = useStyles2(getStyles);
const { t } = useTranslate();
const modKey = useMemo(() => getModKey(), []);
const shortcuts = useMemo(() => getShortcuts(modKey), [modKey]);
const shortcuts = useMemo(() => getShortcuts(modKey, t), [modKey, t]);
return (
<Modal title={t('help-modal.title', 'Shortcuts')} isOpen onDismiss={onDismiss} onClickBackdrop={onDismiss}>
<Grid columns={{ xs: 1, sm: 2 }} gap={3} tabIndex={0}>

View File

@ -1,35 +0,0 @@
import { ReactElement } from 'react';
import { Trans as TransCore, TransProps } from '@grafana/i18n';
import { changeLanguage as changeLanguageCore, initTranslations, t as tCore } from '@grafana/i18n/internal';
import { NAMESPACES, VALID_LANGUAGES } from './constants';
import { loadTranslations } from './loadTranslations';
// This is a placeholder so we can put a 'comment' in the message json files.
// Starts with an underscore so it's sorted to the top of the file. Even though it is in a comment the following line is still extracted
// t('_comment', 'The code is the source of truth for English phrases. They should be updated in the components directly, and additional plurals specified in this file.');
export async function initializeI18n(language: string): Promise<{ language: string | undefined }> {
return initTranslations({ language, ns: NAMESPACES, module: loadTranslations });
}
export function changeLanguage(locale: string) {
const validLocale = VALID_LANGUAGES.includes(locale) ? locale : undefined;
return changeLanguageCore(validLocale);
}
export const Trans = (props: TransProps): ReactElement => <TransCore {...props} />;
/**
* This is a simple wrapper over i18n.t() to provide default namespaces and enforce a consistent API.
* Note: Don't use this in the top level module scope. This wrapper needs initialization, which is done during Grafana
* startup, and it will throw if used before.
*
* This will soon be deprecated in favor of useTranslate()
* @param id ID of the translation string
* @param defaultMessage Default message to use if the translation is missing
* @param values Values to be interpolated into the string
*/
export const t = (id: string, defaultMessage: string, values?: Record<string, unknown>) =>
tCore(id, defaultMessage, values);

View File

@ -3,10 +3,10 @@ import { ErrorInfo, useEffect } from 'react';
import { useLocation } from 'react-router-dom-v5-compat';
import { GrafanaTheme2, locationUtil, PageLayoutType } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { Button, ErrorWithStack, useStyles2 } from '@grafana/ui';
import { Page } from '../components/Page/Page';
import { t, Trans } from '../internationalization';
interface Props {
error: Error | null;
@ -24,6 +24,7 @@ export function GrafanaRouteError({ error, errorInfo }: Props) {
window.location.href = locationUtil.getUrlForPartial(location, { chunkNotFound: true });
}
}, [location, isChunkLoadingError]);
const { t } = useTranslate();
// Would be good to know the page navId here but needs a pretty big refactoring

View File

@ -1,5 +1,5 @@
import { t } from '@grafana/i18n/internal';
import { config } from '@grafana/runtime';
import { t } from 'app/core/internationalization';
// Maps the ID of the nav item to a translated phrase to later pass to <Trans />
// Because the navigation content is dynamic (defined in the backend), we can not use

View File

@ -8,10 +8,10 @@ import {
urlUtil,
serializeStateToUrlParam,
} from '@grafana/data';
import { t } from '@grafana/i18n/internal';
import { getDataSourceSrv } from '@grafana/runtime';
import { notifyApp } from 'app/core/actions';
import { createErrorNotification, createWarningNotification } from 'app/core/copy/appNotification';
import { t } from 'app/core/internationalization';
import { dispatch } from 'app/store/store';
import { RichHistoryQuery } from 'app/types/explore';

View File

@ -1,6 +1,7 @@
import memoizeOne from 'memoize-one';
import { AbsoluteTimeRange, LogRowModel, UrlQueryMap } from '@grafana/data';
import { t } from '@grafana/i18n/internal';
import { getBackendSrv, config, locationService } from '@grafana/runtime';
import { sceneGraph, SceneTimeRangeLike, VizPanel } from '@grafana/scenes';
import { notifyApp } from 'app/core/actions';
@ -10,7 +11,6 @@ import { getDashboardUrl } from 'app/features/dashboard-scene/utils/getDashboard
import { dispatch } from 'app/store/store';
import { ShareLinkConfiguration } from '../../features/dashboard-scene/sharing/ShareButton/utils';
import { t } from '../internationalization';
import { copyStringToClipboard } from './explore';

View File

@ -2,6 +2,7 @@ import { css } from '@emotion/css';
import { memo } from 'react';
import { Action, GrafanaTheme2, httpMethodOptions, HttpRequestMethod, VariableSuggestion } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import {
Switch,
Field,
@ -13,7 +14,6 @@ import {
ColorPicker,
useTheme2,
} from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { HTMLElementType, SuggestionsInput } from '../transformers/suggestionsInput/SuggestionsInput';
@ -32,7 +32,7 @@ const LABEL_WIDTH = 13;
export const ActionEditor = memo(({ index, value, onChange, suggestions, showOneClick }: ActionEditorProps) => {
const styles = useStyles2(getStyles);
const theme = useTheme2();
const { t } = useTranslate();
const onTitleChange = (title: string) => {
onChange(index, { ...value, title });
};

View File

@ -1,8 +1,8 @@
import { useState } from 'react';
import { Action, DataFrame, VariableSuggestion } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { Button, Modal } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
import { ActionEditor } from './ActionEditor';

View File

@ -2,8 +2,8 @@ import { css } from '@emotion/css';
import { useEffect, useState } from 'react';
import { contentTypeOptions, GrafanaTheme2, VariableSuggestion } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { IconButton, Input, Stack, Select, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { SuggestionsInput } from '../transformers/suggestionsInput/SuggestionsInput';
@ -33,6 +33,7 @@ export const ParamsEditor = ({ value, onChange, suggestions, contentTypeHeader =
// forces re-init of first SuggestionsInput(s), since they are stateful and don't respond to 'value' prop changes to be able to clear them :(
const [entryKey, setEntryKey] = useState(Math.random().toString());
const { t } = useTranslate();
const changeParamValue = (paramValue: string) => {
setParamValue(paramValue);

View File

@ -4,10 +4,10 @@ import { useParams } from 'react-router-dom-v5-compat';
import { useAsyncFn } from 'react-use';
import { NavModelItem } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { Field, Input, Button, Legend, Alert } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
import { contextSrv } from 'app/core/core';
import { Trans, t } from 'app/core/internationalization';
import { OrgUser, AccessControlAction, OrgRole } from 'app/types';
import { OrgUsersTable } from './Users/OrgUsersTable';
@ -51,6 +51,8 @@ const AdminEditOrgPage = () => {
fetchOrgUsers(page);
}, [fetchOrg, fetchOrgUsers, page]);
const { t } = useTranslate();
const onUpdateOrgName = async ({ orgName }: OrgNameDTO) => {
await updateOrgName(orgName, orgId);
};

View File

@ -3,9 +3,9 @@ import { useState } from 'react';
import { useAsync } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { useStyles2, Icon } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
import { t, Trans } from 'app/core/internationalization';
import { getTogglesAPI } from './AdminFeatureTogglesAPI';
import { AdminFeatureTogglesTable } from './AdminFeatureTogglesTable';
@ -15,7 +15,7 @@ export default function AdminFeatureTogglesPage() {
const togglesApi = getTogglesAPI();
const featureState = useAsync(() => togglesApi.getFeatureToggles(), [reload]);
const styles = useStyles2(getStyles);
const { t } = useTranslate();
const handleUpdateSuccess = () => {
setReload(reload + 1);
};

View File

@ -1,7 +1,7 @@
import { useState, useRef } from 'react';
import { Trans, useTranslate } from '@grafana/i18n';
import { Switch, InteractiveTable, Tooltip, type CellProps, Button, ConfirmModal, type SortByFn } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
import { FeatureToggle, getTogglesAPI } from './AdminFeatureTogglesAPI';
@ -37,6 +37,7 @@ export function AdminFeatureTogglesTable({ featureToggles, allowEditing, onUpdat
const [localToggles, setLocalToggles] = useState<FeatureToggle[]>(featureToggles);
const [isSaving, setIsSaving] = useState(false);
const [showSaveModel, setShowSaveModal] = useState(false);
const { t } = useTranslate();
const togglesApi = getTogglesAPI();
const handleToggleChange = (toggle: FeatureToggle, newValue: boolean) => {

Some files were not shown because too many files have changed in this diff Show More