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 ### 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 ```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>; 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: 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 ```jsx
import { Trans } from 'app/core/internationalization'; import { Trans } from '@grafana/i18n';
import { Text } from '@grafana/ui'; import { Text } from '@grafana/ui';
const SearchTerm = ({ term }) => <Text color="success">{term}</Text>; 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: 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 ```jsx
import { Trans } from 'app/core/internationalization'; import { Trans } from '@grafana/i18n';
import { Text } from '@grafana/ui'; import { Text } from '@grafana/ui';
const SearchTitle = ({ term }) => ( 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. Sometimes you may need to translate a string cannot be represented in JSX, such as `placeholder` props. Use the `t` macro for this.
```jsx ```jsx
import { t } from "app/core/internationalization" import { useTranslate } from "@grafana/i18n"
const { t } = useTranslate();
const placeholder = t('form.username-placeholder','Username'); const placeholder = t('form.username-placeholder','Username');
return <input type="value" placeholder={placeholder}> 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: For fixed phrases:
```jsx ```jsx
import { Trans } from 'app/core/internationalization'; import { Trans } from '@grafana/i18n';
<Trans i18nKey="page.greeting">Hello user!</Trans>; <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: 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 ```jsx
import { Trans } from 'app/core/internationalization'; import { Trans } from '@grafana/i18n';
<Trans i18nKey="page.greeting">Hello {{ name: user.name }}!</Trans>; <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: Variables must be strings (or, must support calling `.toString()`, which we almost never want). For example:
```jsx ```jsx
import { Trans } from 'app/core/internationalization'; import { Trans } from '@grafana/i18n';
// This will not work // This will not work
const userName = <strong>user.name</strong>; 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. Both HTML tags and React components can be included in a phase. The `Trans` function handles interpolating for its children.
```js ```js
import { Trans } from "app/core/internationalization" import { Trans } from "@grafana/i18n"
<Trans i18nKey="page.explainer"> <Trans i18nKey="page.explainer">
Click <button>here</button> to <a href="https://grafana.com">learn more.</a> 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: 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 ```js
import { Trans } from 'app/core/internationalization'; import { Trans } from '@grafana/i18n';
<Trans i18nKey="inbox.heading" count={messages.length}> <Trans i18nKey="inbox.heading" count={messages.length}>
You got {{ count: messages.length }} messages You got {{ count: messages.length }} messages
@ -210,8 +211,9 @@ import { Trans } from 'app/core/internationalization';
``` ```
```js ```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 }); 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) { 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; 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". * 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 { export {
addResourceBundle, addResourceBundle,
changeLanguage, changeLanguage,
@ -16,5 +23,4 @@ export {
getLanguage, getLanguage,
getResolvedLanguage, getResolvedLanguage,
initTranslations, initTranslations,
t,
} from '../i18n'; } from '../i18n';

View File

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

View File

@ -18,6 +18,7 @@ import {
standardFieldConfigEditorRegistry, standardFieldConfigEditorRegistry,
standardTransformersRegistry, standardTransformersRegistry,
} from '@grafana/data'; } from '@grafana/data';
import { initTranslations } from '@grafana/i18n/internal';
import { import {
locationService, locationService,
registerEchoBackend, registerEchoBackend,
@ -61,7 +62,8 @@ import { getAllOptionEditors, getAllStandardFieldConfigs } from './core/componen
import { PluginPage } from './core/components/Page/PluginPage'; import { PluginPage } from './core/components/Page/PluginPage';
import { GrafanaContextType, useReturnToPreviousInternal } from './core/context/GrafanaContext'; import { GrafanaContextType, useReturnToPreviousInternal } from './core/context/GrafanaContext';
import { initializeCrashDetection } from './core/crash'; 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 { postInitTasks, preInitTasks } from './core/lifecycle-hooks';
import { setMonacoEnv } from './core/monacoEnv'; import { setMonacoEnv } from './core/monacoEnv';
import { interceptLinkClicks } from './core/navigation/patch/interceptLinkClicks'; import { interceptLinkClicks } from './core/navigation/patch/interceptLinkClicks';
@ -124,7 +126,14 @@ export class GrafanaApp {
// Let iframe container know grafana has started loading // Let iframe container know grafana has started loading
window.parent.postMessage('GrafanaAppInit', '*'); 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 })); initI18nPromise.then(({ language }) => updateConfig({ language }));
setBackendSrv(backendSrv); setBackendSrv(backendSrv);

View File

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

View File

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

View File

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

View File

@ -4,9 +4,10 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
import * as React from 'react'; import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data'; 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 { Text, Box, Button, useStyles2, Space } from '@grafana/ui';
import { SlideDown } from 'app/core/components/Animations/SlideDown'; import { SlideDown } from 'app/core/components/Animations/SlideDown';
import { Trans, t } from 'app/core/internationalization';
import { getBackendSrv } from 'app/core/services/backend_srv'; import { getBackendSrv } from 'app/core/services/backend_srv';
import { DescendantCount } from 'app/features/browse-dashboards/components/BrowseActions/DescendantCount'; 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 { PropsWithChildren, useEffect } from 'react';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { locationSearchToObject, locationService, useScopes } from '@grafana/runtime'; import { locationSearchToObject, locationService, useScopes } from '@grafana/runtime';
import { ErrorBoundaryAlert, getDragStyles, LinkButton, useStyles2 } from '@grafana/ui'; import { ErrorBoundaryAlert, getDragStyles, LinkButton, useStyles2 } from '@grafana/ui';
import { useGrafana } from 'app/core/context/GrafanaContext'; import { useGrafana } from 'app/core/context/GrafanaContext';
import { useMediaQueryMinWidth } from 'app/core/hooks/useMediaQueryMinWidth'; import { useMediaQueryMinWidth } from 'app/core/hooks/useMediaQueryMinWidth';
import { Trans } from 'app/core/internationalization';
import store from 'app/core/store'; import store from 'app/core/store';
import { CommandPalette } from 'app/features/commandPalette/CommandPalette'; import { CommandPalette } from 'app/features/commandPalette/CommandPalette';
import { ScopesDashboards } from 'app/features/scopes/dashboards/ScopesDashboards'; import { ScopesDashboards } from 'app/features/scopes/dashboards/ScopesDashboards';

View File

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

View File

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

View File

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

View File

@ -3,8 +3,8 @@ import moment from 'moment';
import { useState } from 'react'; import { useState } from 'react';
import { FieldType, GrafanaTheme2, store } from '@grafana/data'; 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 { 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 { formatDate } from 'app/core/internationalization/dates';
import { HISTORY_LOCAL_STORAGE_KEY } from '../AppChromeService'; import { HISTORY_LOCAL_STORAGE_KEY } from '../AppChromeService';
@ -13,6 +13,7 @@ import { HistoryEntry } from '../types';
import { logClickUnifiedHistoryEntryEvent, logUnifiedHistoryShowMoreEvent } from './eventsTracking'; import { logClickUnifiedHistoryEntryEvent, logUnifiedHistoryShowMoreEvent } from './eventsTracking';
export function HistoryWrapper({ onClose }: { onClose: () => void }) { export function HistoryWrapper({ onClose }: { onClose: () => void }) {
const { t } = useTranslate();
const history = store.getObject<HistoryEntry[]>(HISTORY_LOCAL_STORAGE_KEY, []).filter((entry) => { const history = store.getObject<HistoryEntry[]>(HISTORY_LOCAL_STORAGE_KEY, []).filter((entry) => {
return moment(entry.time).isAfter(moment().subtract(2, 'day').startOf('day')); 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 styles = useStyles2(getStyles);
const theme = useTheme2(); const theme = useTheme2();
const [isExpanded, setIsExpanded] = useState(isSelected && entry.views.length > 0); const [isExpanded, setIsExpanded] = useState(isSelected && entry.views.length > 0);
const { t } = useTranslate();
const { breadcrumbs, views, time, url, sparklineData } = entry; const { breadcrumbs, views, time, url, sparklineData } = entry;
const expandedLabel = isExpanded const expandedLabel = isExpanded
? t('nav.history-wrapper.collapse', 'Collapse') ? 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 { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
import { useTranslate } from '@grafana/i18n';
import { config, reportInteraction } from '@grafana/runtime'; import { config, reportInteraction } from '@grafana/runtime';
import { ScrollContainer, useStyles2 } from '@grafana/ui'; import { ScrollContainer, useStyles2 } from '@grafana/ui';
import { useGrafana } from 'app/core/context/GrafanaContext'; import { useGrafana } from 'app/core/context/GrafanaContext';
import { t } from 'app/core/internationalization';
import { setBookmark } from 'app/core/reducers/navBarTree'; import { setBookmark } from 'app/core/reducers/navBarTree';
import { usePatchUserPreferencesMutation } from 'app/features/preferences/api/index'; import { usePatchUserPreferencesMutation } from 'app/features/preferences/api/index';
import { useDispatch, useSelector } from 'app/types'; import { useDispatch, useSelector } from 'app/types';
@ -37,7 +37,7 @@ export const MegaMenu = memo(
const state = chrome.useState(); const state = chrome.useState();
const [patchPreferences] = usePatchUserPreferencesMutation(); const [patchPreferences] = usePatchUserPreferencesMutation();
const pinnedItems = usePinnedItems(); const pinnedItems = usePinnedItems();
const { t } = useTranslate();
// Remove profile + help from tree // Remove profile + help from tree
const navItems = navTree const navItems = navTree
.filter((item) => item.id !== 'profile' && item.id !== 'help') .filter((item) => item.id !== 'profile' && item.id !== 'help')

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,13 +3,12 @@ import { useEffect } from 'react';
import { useMeasure } from 'react-use'; import { useMeasure } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { useStyles2 } from '@grafana/ui'; import { useStyles2 } from '@grafana/ui';
import { News } from 'app/plugins/panel/news/component/News'; import { News } from 'app/plugins/panel/news/component/News';
import { useNewsFeed } from 'app/plugins/panel/news/useNewsFeed'; import { useNewsFeed } from 'app/plugins/panel/news/useNewsFeed';
import grotNewsSvg from 'img/grot-news.svg'; import grotNewsSvg from 'img/grot-news.svg';
import { t } from '../../../internationalization';
interface NewsWrapperProps { interface NewsWrapperProps {
feedUrl: string; feedUrl: string;
} }
@ -21,6 +20,7 @@ export function NewsWrapper({ feedUrl }: NewsWrapperProps) {
useEffect(() => { useEffect(() => {
getNews(); getNews();
}, [getNews]); }, [getNews]);
const { t } = useTranslate();
if (state.error) { if (state.error) {
return <div className={styles.innerWrapper}>{state.error && state.error.message}</div>; 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 { useMemo, useState } from 'react';
import { SelectableValue, GrafanaTheme2 } from '@grafana/data'; import { SelectableValue, GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { Icon, Select, useStyles2 } from '@grafana/ui'; import { Icon, Select, useStyles2 } from '@grafana/ui';
import { contextSrv } from 'app/core/services/context_srv'; import { contextSrv } from 'app/core/services/context_srv';
import { UserOrg } from 'app/types'; import { UserOrg } from 'app/types';
import { t } from '../../../internationalization';
import { OrganizationBaseProps } from './types'; import { OrganizationBaseProps } from './types';
export function OrganizationSelect({ orgs, onSelectChange }: OrganizationBaseProps) { export function OrganizationSelect({ orgs, onSelectChange }: OrganizationBaseProps) {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const { t } = useTranslate();
const { orgId } = contextSrv.user; const { orgId } = contextSrv.user;
const options = useMemo( const options = useMemo(

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,10 +3,10 @@ import { useState } from 'react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { getBackendSrv } from '@grafana/runtime'; import { getBackendSrv } from '@grafana/runtime';
import { Field, Input, Button, Legend, Container, useStyles2, LinkButton, Stack } from '@grafana/ui'; import { Field, Input, Button, Legend, Container, useStyles2, LinkButton, Stack } from '@grafana/ui';
import config from 'app/core/config'; import config from 'app/core/config';
import { t, Trans } from 'app/core/internationalization';
interface EmailDTO { interface EmailDTO {
userOrEmail: string; userOrEmail: string;
@ -30,6 +30,7 @@ export const ForgottenPassword = () => {
register, register,
formState: { errors }, formState: { errors },
} = useForm<EmailDTO>(); } = useForm<EmailDTO>();
const { t } = useTranslate();
const sendEmail = async (formModel: EmailDTO) => { const sendEmail = async (formModel: EmailDTO) => {
const res = await getBackendSrv().post('/api/user/password/send-reset-email', formModel); 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 { useEffect, useState } from 'react';
import { Navigate } from 'react-router-dom-v5-compat'; import { Navigate } from 'react-router-dom-v5-compat';
import { Trans, useTranslate } from '@grafana/i18n';
import { Button, Modal } from '@grafana/ui'; import { Button, Modal } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { Prompt } from './Prompt'; import { Prompt } from './Prompt';
@ -96,6 +96,8 @@ interface UnsavedChangesModalProps {
} }
const UnsavedChangesModal = ({ onDiscard, onBackToForm, isOpen }: UnsavedChangesModalProps) => { const UnsavedChangesModal = ({ onDiscard, onBackToForm, isOpen }: UnsavedChangesModalProps) => {
const { t } = useTranslate();
return ( return (
<Modal <Modal
isOpen={isOpen} isOpen={isOpen}

View File

@ -1,9 +1,11 @@
import { useTranslate } from '@grafana/i18n';
import { Button } from '@grafana/ui'; import { Button } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { performInviteUserClick } from './utils'; import { performInviteUserClick } from './utils';
export function InviteUserButton() { export function InviteUserButton() {
const { t } = useTranslate();
return ( return (
<Button <Button
icon="add-user" 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 { DragDropContext, Draggable, Droppable, DropResult } from '@hello-pangea/dnd';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { Icon, IconButton, useStyles2 } from '@grafana/ui'; import { Icon, IconButton, useStyles2 } from '@grafana/ui';
import { t } from '../../internationalization';
import { LayerName } from './LayerName'; import { LayerName } from './LayerName';
import { LayerElement } from './types'; import { LayerElement } from './types';
@ -39,7 +38,7 @@ export const LayerDragDropList = <T extends LayerElement>({
verifyLayerNameUniqueness, verifyLayerNameUniqueness,
}: LayerDragDropListProps<T>) => { }: LayerDragDropListProps<T>) => {
const style = useStyles2(getStyles); const style = useStyles2(getStyles);
const { t } = useTranslate();
const getRowStyle = (isSelected: boolean) => { const getRowStyle = (isSelected: boolean) => {
return isSelected ? `${style.row} ${style.sel}` : style.row; return isSelected ? `${style.row} ${style.sel}` : style.row;
}; };

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,8 +1,8 @@
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { Trans } from '@grafana/i18n';
import { LinkButton, Stack } from '@grafana/ui'; import { LinkButton, Stack } from '@grafana/ui';
import { getConfig } from 'app/core/config'; import { getConfig } from 'app/core/config';
import { Trans } from 'app/core/internationalization';
export const UserSignup = () => { export const UserSignup = () => {
const href = getConfig().verifyEmailEnabled ? `${getConfig().appSubUrl}/verify` : `${getConfig().appSubUrl}/signup`; 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 { Badge } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { useIsProvisionedInstance } from 'app/features/provisioning/hooks/useIsProvisionedInstance'; import { useIsProvisionedInstance } from 'app/features/provisioning/hooks/useIsProvisionedInstance';
import { NestedFolderDTO } from 'app/features/search/service/types'; import { NestedFolderDTO } from 'app/features/search/service/types';
import { FolderDTO, FolderListItemDTO } from 'app/types'; import { FolderDTO, FolderListItemDTO } from 'app/types';
@ -10,6 +10,8 @@ export interface Props {
export function FolderRepo({ folder }: Props) { export function FolderRepo({ folder }: Props) {
const isProvisionedInstance = useIsProvisionedInstance(); const isProvisionedInstance = useIsProvisionedInstance();
const { t } = useTranslate();
if (!folder || ('parentUID' in folder && folder.parentUID) || !folder.managedBy || isProvisionedInstance) { if (!folder || ('parentUID' in folder && folder.parentUID) || !folder.managedBy || isProvisionedInstance) {
return null; return null;
} }

View File

@ -6,9 +6,9 @@ import { FixedSizeList as List } from 'react-window';
import InfiniteLoader from 'react-window-infinite-loader'; import InfiniteLoader from 'react-window-infinite-loader';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { Trans } from '@grafana/i18n';
import { IconButton, useStyles2, Text } from '@grafana/ui'; import { IconButton, useStyles2, Text } from '@grafana/ui';
import { Indent } from 'app/core/components/Indent/Indent'; import { Indent } from 'app/core/components/Indent/Indent';
import { Trans } from 'app/core/internationalization';
import { childrenByParentUIDSelector, rootItemsSelector } from 'app/features/browse-dashboards/state'; import { childrenByParentUIDSelector, rootItemsSelector } from 'app/features/browse-dashboards/state';
import { DashboardsTreeItem } from 'app/features/browse-dashboards/types'; import { DashboardsTreeItem } from 'app/features/browse-dashboards/types';
import { DashboardViewItem } from 'app/features/search/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 * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { config } from '@grafana/runtime'; import { config } from '@grafana/runtime';
import { Alert, Icon, Input, LoadingBar, Stack, Text, useStyles2 } from '@grafana/ui'; 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 { useGetFolderQuery } from 'app/features/browse-dashboards/api/browseDashboardsAPI';
import { DashboardViewItemWithUIItems, DashboardsTreeItem } from 'app/features/browse-dashboards/types'; import { DashboardViewItemWithUIItems, DashboardsTreeItem } from 'app/features/browse-dashboards/types';
import { getGrafanaSearcher } from 'app/features/search/service/searcher'; import { getGrafanaSearcher } from 'app/features/search/service/searcher';
@ -250,6 +250,7 @@ export function NestedFolderPicker({
}, },
[flatTree] [flatTree]
); );
const { t } = useTranslate();
const isLoading = isBrowseLoading || isFetchingSearchResults; const isLoading = isBrowseLoading || isFetchingSearchResults;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,15 +1,17 @@
import { useAsync } from 'react-use'; import { useAsync } from 'react-use';
import { renderMarkdown } from '@grafana/data'; import { renderMarkdown } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { getBackendSrv } from '@grafana/runtime'; import { getBackendSrv } from '@grafana/runtime';
import { LoadingPlaceholder } from '@grafana/ui'; import { LoadingPlaceholder } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
interface Props { interface Props {
pluginId: string; pluginId: string;
} }
export function PluginHelp({ pluginId }: Props) { export function PluginHelp({ pluginId }: Props) {
const { t } = useTranslate();
const { value, loading, error } = useAsync(async () => { const { value, loading, error } = useAsync(async () => {
return getBackendSrv().get(`/api/plugins/${pluginId}/markdown/query_help`); 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 * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { Icon, IconButton, useStyles2, Stack } from '@grafana/ui'; import { Icon, IconButton, useStyles2, Stack } from '@grafana/ui';
import { t } from 'app/core/internationalization';
export interface QueryOperationRowHeaderProps { export interface QueryOperationRowHeaderProps {
actionsElement?: React.ReactNode; actionsElement?: React.ReactNode;
@ -42,7 +42,7 @@ export const QueryOperationRowHeader = ({
expanderMessages, expanderMessages,
}: QueryOperationRowHeaderProps) => { }: QueryOperationRowHeaderProps) => {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const { t } = useTranslate();
let tooltipMessage = isContentVisible let tooltipMessage = isContentVisible
? t('query-operation.header.collapse-row', 'Collapse query row') ? t('query-operation.header.collapse-row', 'Collapse query row')
: t('query-operation.header.expand-row', 'Expand query row'); : t('query-operation.header.expand-row', 'Expand query row');

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,8 +1,8 @@
import { Controller, useFormContext } from 'react-hook-form'; import { Controller, useFormContext } from 'react-hook-form';
import { toOption } from '@grafana/data'; import { toOption } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { Drawer, Field, RadioButtonGroup, TextLink } from '@grafana/ui'; import { Drawer, Field, RadioButtonGroup, TextLink } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { OrgRole } from 'app/types'; import { OrgRole } from 'app/types';
const roleOptions = Object.keys(OrgRole).map(toOption); const roleOptions = Object.keys(OrgRole).map(toOption);
@ -29,6 +29,8 @@ export const RolePickerDrawer = ({ onClose }: Props) => {
const methods = useFormContext(); const methods = useFormContext();
const { control, getValues, setValue } = methods; const { control, getValues, setValue } = methods;
const [name, roles] = getValues(['name', 'roles']); const [name, roles] = getValues(['name', 'roles']);
const { t } = useTranslate();
return ( return (
<Drawer title={name} subtitle={drawerSubtitle} onClose={onClose}> <Drawer title={name} subtitle={drawerSubtitle} onClose={onClose}>
<Field label={t('role-picker-drawer.basic-roles.label', 'Basic Roles')}> <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 { AppEvents, GrafanaTheme2, SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
import { Trans, useTranslate } from '@grafana/i18n';
import { reportInteraction } from '@grafana/runtime'; import { reportInteraction } from '@grafana/runtime';
import { ActionMeta, AsyncVirtualizedSelect, Input, InputActionMeta, useStyles2 } from '@grafana/ui'; import { ActionMeta, AsyncVirtualizedSelect, Input, InputActionMeta, useStyles2 } from '@grafana/ui';
import appEvents from 'app/core/app_events'; import appEvents from 'app/core/app_events';
import { t, Trans } from 'app/core/internationalization';
import { contextSrv } from 'app/core/services/context_srv'; import { contextSrv } from 'app/core/services/context_srv';
import { createFolder, getFolderByUid, searchFolders } from 'app/features/manage-dashboards/state/actions'; import { createFolder, getFolderByUid, searchFolders } from 'app/features/manage-dashboards/state/actions';
import { DashboardSearchHit } from 'app/features/search/types'; 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] [customAdd?.disallowValues, customAdd?.isAllowedValue, newFolderValue, createNewFolder, folder?.title, rootName]
); );
const { t } = useTranslate();
const onNewFolderChange = (e: FormEvent<HTMLInputElement>) => { const onNewFolderChange = (e: FormEvent<HTMLInputElement>) => {
const value = e.currentTarget.value; const value = e.currentTarget.value;
setNewFolderValue(value); setNewFolderValue(value);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,11 +1,11 @@
import { useState } from 'react'; import { useState } from 'react';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { Trans, useTranslate } from '@grafana/i18n';
import { getBackendSrv } from '@grafana/runtime'; import { getBackendSrv } from '@grafana/runtime';
import { Field, Input, Button, Legend, Container, LinkButton, Stack } from '@grafana/ui'; import { Field, Input, Button, Legend, Container, LinkButton, Stack } from '@grafana/ui';
import { getConfig } from 'app/core/config'; import { getConfig } from 'app/core/config';
import { useAppNotification } from 'app/core/copy/appNotification'; import { useAppNotification } from 'app/core/copy/appNotification';
import { t, Trans } from 'app/core/internationalization';
import { w3cStandardEmailValidator } from 'app/features/admin/utils'; import { w3cStandardEmailValidator } from 'app/features/admin/utils';
interface EmailDTO { interface EmailDTO {
@ -20,7 +20,7 @@ export const VerifyEmail = () => {
formState: { errors }, formState: { errors },
} = useForm<EmailDTO>(); } = useForm<EmailDTO>();
const [emailSent, setEmailSent] = useState(false); const [emailSent, setEmailSent] = useState(false);
const { t } = useTranslate();
const onSubmit = (formModel: EmailDTO) => { const onSubmit = (formModel: EmailDTO) => {
getBackendSrv() getBackendSrv()
.post('/api/user/signup', formModel) .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 { components, MultiValueRemoveProps } from 'react-select';
import { escapeStringForRegex, GrafanaTheme2, SelectableValue } from '@grafana/data'; import { escapeStringForRegex, GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { Icon, MultiSelect, useStyles2 } from '@grafana/ui'; import { Icon, MultiSelect, useStyles2 } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { TagBadge, getStyles as getTagBadgeStyles } from './TagBadge'; import { TagBadge, getStyles as getTagBadgeStyles } from './TagBadge';
import { TagOption, TagSelectOption } from './TagOption'; 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 // Necessary to force re-render to keep tag options up to date / relevant
const selectKey = useMemo(() => tags.join(), [tags]); const selectKey = useMemo(() => tags.join(), [tags]);
const { t } = useTranslate();
const onLoadOptions = useCallback(async () => { const onLoadOptions = useCallback(async () => {
const options = await tagOptions(); const options = await tagOptions();
return options.map((option) => { return options.map((option) => {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,11 +2,12 @@ import { css } from '@emotion/css';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data'; 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 { Grid, Modal, useStyles2, Text } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
import { getModKey } from 'app/core/utils/browser'; import { getModKey } from 'app/core/utils/browser';
const getShortcuts = (modKey: string) => { const getShortcuts = (modKey: string, t: TFunction) => {
return [ return [
{ {
category: t('help-modal.shortcuts-category.global', 'Global'), category: t('help-modal.shortcuts-category.global', 'Global'),
@ -149,9 +150,10 @@ export interface HelpModalProps {
export const HelpModal = ({ onDismiss }: HelpModalProps): JSX.Element => { export const HelpModal = ({ onDismiss }: HelpModalProps): JSX.Element => {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const { t } = useTranslate();
const modKey = useMemo(() => getModKey(), []); const modKey = useMemo(() => getModKey(), []);
const shortcuts = useMemo(() => getShortcuts(modKey), [modKey]); const shortcuts = useMemo(() => getShortcuts(modKey, t), [modKey, t]);
return ( return (
<Modal title={t('help-modal.title', 'Shortcuts')} isOpen onDismiss={onDismiss} onClickBackdrop={onDismiss}> <Modal title={t('help-modal.title', 'Shortcuts')} isOpen onDismiss={onDismiss} onClickBackdrop={onDismiss}>
<Grid columns={{ xs: 1, sm: 2 }} gap={3} tabIndex={0}> <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 { useLocation } from 'react-router-dom-v5-compat';
import { GrafanaTheme2, locationUtil, PageLayoutType } from '@grafana/data'; import { GrafanaTheme2, locationUtil, PageLayoutType } from '@grafana/data';
import { Trans, useTranslate } from '@grafana/i18n';
import { Button, ErrorWithStack, useStyles2 } from '@grafana/ui'; import { Button, ErrorWithStack, useStyles2 } from '@grafana/ui';
import { Page } from '../components/Page/Page'; import { Page } from '../components/Page/Page';
import { t, Trans } from '../internationalization';
interface Props { interface Props {
error: Error | null; error: Error | null;
@ -24,6 +24,7 @@ export function GrafanaRouteError({ error, errorInfo }: Props) {
window.location.href = locationUtil.getUrlForPartial(location, { chunkNotFound: true }); window.location.href = locationUtil.getUrlForPartial(location, { chunkNotFound: true });
} }
}, [location, isChunkLoadingError]); }, [location, isChunkLoadingError]);
const { t } = useTranslate();
// Would be good to know the page navId here but needs a pretty big refactoring // 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 { 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 /> // 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 // Because the navigation content is dynamic (defined in the backend), we can not use

View File

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

View File

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

View File

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

View File

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

View File

@ -2,8 +2,8 @@ import { css } from '@emotion/css';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { contentTypeOptions, GrafanaTheme2, VariableSuggestion } from '@grafana/data'; import { contentTypeOptions, GrafanaTheme2, VariableSuggestion } from '@grafana/data';
import { useTranslate } from '@grafana/i18n';
import { IconButton, Input, Stack, Select, useStyles2 } from '@grafana/ui'; import { IconButton, Input, Stack, Select, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { SuggestionsInput } from '../transformers/suggestionsInput/SuggestionsInput'; 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 :( // 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 [entryKey, setEntryKey] = useState(Math.random().toString());
const { t } = useTranslate();
const changeParamValue = (paramValue: string) => { const changeParamValue = (paramValue: string) => {
setParamValue(paramValue); setParamValue(paramValue);

View File

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

View File

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

View File

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

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