* 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
pull/105436/head
Hugo Häggmark 4 days ago committed by GitHub
parent d8dd2facdd
commit 119d5897ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 24
      contribute/internationalization.md
  2. 3
      packages/grafana-i18n/src/i18n.tsx
  3. 8
      packages/grafana-i18n/src/internal/index.ts
  4. 2
      public/app/api/clients/provisioning/index.ts
  5. 13
      public/app/app.ts
  6. 3
      public/app/core/components/AccessControl/AddPermission.tsx
  7. 2
      public/app/core/components/AccessControl/PermissionList.tsx
  8. 4
      public/app/core/components/AccessControl/PermissionListItem.tsx
  9. 3
      public/app/core/components/AccessControl/Permissions.tsx
  10. 2
      public/app/core/components/AppChrome/AppChrome.tsx
  11. 2
      public/app/core/components/AppChrome/AppChromeService.tsx
  12. 5
      public/app/core/components/AppChrome/ExtensionSidebar/ExtensionToolbarItem.tsx
  13. 3
      public/app/core/components/AppChrome/History/HistoryContainer.tsx
  14. 4
      public/app/core/components/AppChrome/History/HistoryWrapper.tsx
  15. 4
      public/app/core/components/AppChrome/MegaMenu/MegaMenu.tsx
  16. 3
      public/app/core/components/AppChrome/MegaMenu/MegaMenuHeader.tsx
  17. 3
      public/app/core/components/AppChrome/MegaMenu/MegaMenuItem.tsx
  18. 3
      public/app/core/components/AppChrome/MegaMenu/MegaMenuItemText.tsx
  19. 2
      public/app/core/components/AppChrome/MegaMenu/utils.ts
  20. 4
      public/app/core/components/AppChrome/News/NewsDrawer.tsx
  21. 4
      public/app/core/components/AppChrome/News/NewsWrapper.tsx
  22. 4
      public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSelect.tsx
  23. 5
      public/app/core/components/AppChrome/QuickAdd/QuickAdd.tsx
  24. 4
      public/app/core/components/AppChrome/ReturnToPrevious/DismissableButton.tsx
  25. 4
      public/app/core/components/AppChrome/ReturnToPrevious/ReturnToPrevious.tsx
  26. 4
      public/app/core/components/AppChrome/TopBar/ProfileButton.tsx
  27. 2
      public/app/core/components/AppChrome/TopBar/SignInLink.tsx
  28. 4
      public/app/core/components/AppChrome/TopBar/SingleTopBar.tsx
  29. 6
      public/app/core/components/AppChrome/TopBar/TopSearchBarCommandPaletteTrigger.tsx
  30. 2
      public/app/core/components/AppNotifications/AppNotificationItem.tsx
  31. 5
      public/app/core/components/BouncingLoader/BouncingLoader.tsx
  32. 5
      public/app/core/components/Breadcrumbs/Breadcrumbs.tsx
  33. 5
      public/app/core/components/CloseButton/CloseButton.tsx
  34. 2
      public/app/core/components/EmptyListCTA/EmptyListCTA.tsx
  35. 3
      public/app/core/components/FolderFilter/FolderFilter.tsx
  36. 2
      public/app/core/components/Footer/Footer.tsx
  37. 3
      public/app/core/components/ForgottenPassword/ChangePassword.tsx
  38. 3
      public/app/core/components/ForgottenPassword/ForgottenPassword.tsx
  39. 4
      public/app/core/components/FormPrompt/FormPrompt.tsx
  40. 4
      public/app/core/components/InviteUserButton/InviteUserButton.tsx
  41. 5
      public/app/core/components/Layers/LayerDragDropList.tsx
  42. 4
      public/app/core/components/Layers/LayerName.tsx
  43. 2
      public/app/core/components/Login/LoginCtrl.tsx
  44. 4
      public/app/core/components/Login/LoginForm.tsx
  45. 2
      public/app/core/components/Login/LoginLayout.tsx
  46. 3
      public/app/core/components/Login/LoginPage.tsx
  47. 2
      public/app/core/components/Login/LoginServiceButtons.tsx
  48. 3
      public/app/core/components/Login/PasswordlessConfirmationForm.tsx
  49. 4
      public/app/core/components/Login/PasswordlessLoginForm.tsx
  50. 2
      public/app/core/components/Login/UserSignup.tsx
  51. 4
      public/app/core/components/NestedFolderPicker/FolderRepo.tsx
  52. 2
      public/app/core/components/NestedFolderPicker/NestedFolderList.tsx
  53. 3
      public/app/core/components/NestedFolderPicker/NestedFolderPicker.tsx
  54. 3
      public/app/core/components/NestedFolderPicker/Trigger.tsx
  55. 5
      public/app/core/components/OptionsUI/color.tsx
  56. 4
      public/app/core/components/OptionsUI/fieldColor.tsx
  57. 4
      public/app/core/components/OptionsUI/units.tsx
  58. 4
      public/app/core/components/Page/EditableTitle.tsx
  59. 2
      public/app/core/components/PageNotFound/EntityNotFound.tsx
  60. 4
      public/app/core/components/PanelTypeFilter/PanelTypeFilter.tsx
  61. 5
      public/app/core/components/PasswordField/PasswordField.tsx
  62. 4
      public/app/core/components/PluginHelp/PluginHelp.tsx
  63. 4
      public/app/core/components/QueryOperationRow/QueryOperationRowHeader.tsx
  64. 2
      public/app/core/components/RolePicker/BuiltinRoleSelector.tsx
  65. 5
      public/app/core/components/RolePicker/RoleMenuGroupOption.tsx
  66. 4
      public/app/core/components/RolePicker/RoleMenuOption.tsx
  67. 3
      public/app/core/components/RolePicker/RolePickerInput.tsx
  68. 4
      public/app/core/components/RolePicker/RolePickerMenu.tsx
  69. 4
      public/app/core/components/RolePicker/RolePickerSubMenu.tsx
  70. 4
      public/app/core/components/RolePickerDrawer/RolePickerBadges.tsx
  71. 4
      public/app/core/components/RolePickerDrawer/RolePickerDrawer.tsx
  72. 4
      public/app/core/components/Select/OldFolderPicker.tsx
  73. 4
      public/app/core/components/Select/OrgPicker.tsx
  74. 3
      public/app/core/components/Select/ServiceAccountPicker.tsx
  75. 4
      public/app/core/components/Select/SortPicker.tsx
  76. 3
      public/app/core/components/Select/TeamPicker.tsx
  77. 3
      public/app/core/components/Select/UserPicker.tsx
  78. 4
      public/app/core/components/SharedPreferences/SharedPreferences.tsx
  79. 4
      public/app/core/components/Signup/SignupPage.tsx
  80. 4
      public/app/core/components/Signup/VerifyEmail.tsx
  81. 4
      public/app/core/components/TagFilter/TagFilter.tsx
  82. 5
      public/app/core/components/TagFilter/TagOption.tsx
  83. 2
      public/app/core/components/Theme/ThemePreview.tsx
  84. 10
      public/app/core/components/ThemeSelector/ThemeSelectorDrawer.tsx
  85. 4
      public/app/core/components/TimePicker/TimePickerWithHistory.tsx
  86. 4
      public/app/core/components/Upgrade/UpgradeBox.tsx
  87. 2
      public/app/core/components/ValidationLabels/ValidationLabels.tsx
  88. 4
      public/app/core/components/VersionHistory/VersionHistoryComparison.tsx
  89. 8
      public/app/core/components/help/HelpModal.tsx
  90. 35
      public/app/core/internationalization/index.tsx
  91. 3
      public/app/core/navigation/GrafanaRouteError.tsx
  92. 2
      public/app/core/utils/navBarItem-translations.ts
  93. 2
      public/app/core/utils/richHistory.ts
  94. 2
      public/app/core/utils/shortLinks.ts
  95. 4
      public/app/features/actions/ActionEditor.tsx
  96. 2
      public/app/features/actions/ActionEditorModalContent.tsx
  97. 3
      public/app/features/actions/ParamsEditor.tsx
  98. 4
      public/app/features/admin/AdminEditOrgPage.tsx
  99. 4
      public/app/features/admin/AdminFeatureTogglesPage.tsx
  100. 3
      public/app/features/admin/AdminFeatureTogglesTable.tsx
  101. Some files were not shown because too many files have changed in this diff Show More

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -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);

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

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

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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save