Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I18n: Translate phrases for new Browse Dashboards #70654

Merged
@@ -1,8 +1,9 @@
import React, { useState } from 'react';
import React, { useState, useMemo } from 'react';

import { Space } from '@grafana/experimental';
import { ConfirmModal } from '@grafana/ui';
import { P } from '@grafana/ui/src/unstable';
import { Trans, t } from 'app/core/internationalization';

import { DashboardTreeSelection } from '../../types';

Expand All @@ -17,6 +18,13 @@ export interface Props {

export const DeleteModal = ({ onConfirm, onDismiss, selectedItems, ...props }: Props) => {
const [isDeleting, setIsDeleting] = useState(false);
const confirmButtonText = useMemo(
() =>
isDeleting
? t('browse-dashboards.action.deleting', 'Deleting...')
: t('browse-dashboards.action.delete-button', 'Delete'),
[isDeleting]
);
const onDelete = async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the useMemo hook is necessary in this case, you can just use the t() function inside the ternary directly

setIsDeleting(true);
try {
Expand All @@ -32,16 +40,20 @@ export const DeleteModal = ({ onConfirm, onDismiss, selectedItems, ...props }: P
<ConfirmModal
body={
<>
<P>This action will delete the following content:</P>
<P>
<Trans i18nKey="browse-dashboards.action.delete-modal-text">
This action will delete the following content:
</Trans>
</P>
<DescendantCount selectedItems={selectedItems} />
<Space v={2} />
</>
}
confirmationText="Delete"
confirmText={isDeleting ? 'Deleting...' : 'Delete'}
confirmText={confirmButtonText}
onDismiss={onDismiss}
onConfirm={onDelete}
title="Delete"
title={t('browse-dashboards.action.delete-modal-title', 'Delete')}
{...props}
/>
);
Expand Down
@@ -1,9 +1,10 @@
import React, { useState } from 'react';
import React, { useState, useMemo } from 'react';

import { Space } from '@grafana/experimental';
import { Alert, Button, Field, Modal } from '@grafana/ui';
import { P } from '@grafana/ui/src/unstable';
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
import { t, Trans } from 'app/core/internationalization';

import { DashboardTreeSelection } from '../../types';

Expand All @@ -19,6 +20,11 @@ export interface Props {
export const MoveModal = ({ onConfirm, onDismiss, selectedItems, ...props }: Props) => {
const [moveTarget, setMoveTarget] = useState<string>();
const [isMoving, setIsMoving] = useState(false);
const moveButtonText = useMemo(
() =>
isMoving ? t('browse-dashboards.action.moving', 'Moving...') : t('browse-dashboards.action.move-button', 'Move'),
[isMoving]
);
const selectedFolders = Object.keys(selectedItems.folder).filter((uid) => selectedItems.folder[uid]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above comment about useMemo hook.


const onMove = async () => {
Expand All @@ -35,25 +41,32 @@ export const MoveModal = ({ onConfirm, onDismiss, selectedItems, ...props }: Pro
};

return (
<Modal title="Move" onDismiss={onDismiss} {...props}>
{selectedFolders.length > 0 && <Alert severity="info" title="Moving this item may change its permissions." />}
<Modal title={t('browse-dashboards.action.move-modal-title', 'Move')} onDismiss={onDismiss} {...props}>
{selectedFolders.length > 0 && (
<Alert
severity="info"
title={t('browse-dashboards.action.move-modal-alert', 'Moving this item may change its permissions.')}
/>
)}

<P>This action will move the following content:</P>
<P>
<Trans i18nKey="browse-dashboards.action.move-modal-text">This action will move the following content:</Trans>
</P>

<DescendantCount selectedItems={selectedItems} />

<Space v={3} />

<Field label="Folder name">
<Field label={t('browse-dashboards.action.move-modal-field-label', 'Folder name')}>
<FolderPicker allowEmpty onChange={({ uid }) => setMoveTarget(uid)} />
</Field>

<Modal.ButtonRow>
<Button onClick={onDismiss} variant="secondary" fill="outline">
Cancel
<Trans i18nKey="browse-dashboards.action.cancel-button">Cancel</Trans>
</Button>
<Button disabled={moveTarget === undefined || isMoving} onClick={onMove} variant="primary">
{isMoving ? 'Moving...' : 'Move'}
{moveButtonText}
</Button>
</Modal.ButtonRow>
</Modal>
Expand Down
Expand Up @@ -94,7 +94,7 @@ describe('browse-dashboards FolderActionsButton', () => {

await userEvent.click(screen.getByRole('button', { name: 'Folder actions' }));
await userEvent.click(screen.getByRole('menuitem', { name: 'Manage permissions' }));
expect(screen.getByRole('dialog', { name: 'Drawer title Permissions' })).toBeInTheDocument();
expect(screen.getByRole('dialog', { name: 'Drawer title Manage permissions' })).toBeInTheDocument();
});

it('clicking the "Move" option opens the move modal', async () => {
Expand Down
Expand Up @@ -4,6 +4,7 @@ import { locationService, reportInteraction } from '@grafana/runtime';
import { Button, Drawer, Dropdown, Icon, Menu, MenuItem } from '@grafana/ui';
import { Permissions } from 'app/core/components/AccessControl';
import { appEvents, contextSrv } from 'app/core/core';
import { Trans, t } from 'app/core/internationalization';
import { AccessControlAction, FolderDTO } from 'app/types';
import { ShowModalReactEvent } from 'app/types/events';

Expand Down Expand Up @@ -87,9 +88,16 @@ export function FolderActionsButton({ folder }: Props) {

const menu = (
<Menu>
{canViewPermissions && <MenuItem onClick={() => setShowPermissionsDrawer(true)} label="Manage permissions" />}
{canMoveFolder && <MenuItem onClick={showMoveModal} label="Move" />}
{canDeleteFolder && <MenuItem destructive onClick={showDeleteModal} label="Delete" />}
{canViewPermissions && (
<MenuItem
onClick={() => setShowPermissionsDrawer(true)}
label={t('browse-dashboards.action.manage-permissions-button', 'Manage permissions')}
/>
)}
{canMoveFolder && <MenuItem onClick={showMoveModal} label={t('browse-dashboards.action.move-button', 'Move')} />}
{canDeleteFolder && (
<MenuItem destructive onClick={showDeleteModal} label={t('browse-dashboards.action.delete-button', 'Delete')} />
)}
</Menu>
);

Expand All @@ -101,13 +109,13 @@ export function FolderActionsButton({ folder }: Props) {
<>
<Dropdown overlay={menu} onVisibleChange={setIsOpen}>
<Button variant="secondary">
Folder actions
<Trans i18nKey="browse-dashboards.action.folder-actions-button">Folder actions</Trans>
<Icon name={isOpen ? 'angle-up' : 'angle-down'} />
</Button>
</Dropdown>
{showPermissionsDrawer && (
<Drawer
title="Permissions"
title={t('browse-dashboards.action.manage-permissions-button', 'Manage permissions')}
subtitle={folder.title}
scrollableContent
onClose={() => setShowPermissionsDrawer(false)}
Expand Down
@@ -1,6 +1,7 @@
import React from 'react';

import { Button, Input, Form, Field, HorizontalGroup } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';

import { validationSrv } from '../../manage-dashboards/services/ValidationSrv';

Expand All @@ -16,6 +17,11 @@ interface FormModel {
const initialFormModel: FormModel = { folderName: '' };

export function NewFolderForm({ onCancel, onConfirm }: Props) {
const translatedFoldername = t('browse-dashboards.action.new-folder-label', 'Folder name');
const translatedFolderNameRequiredPhrase = t(
'browse-dashboards.action.new-folder-name-required-phrase',
'Folder name is required.'
);
const validateFolderName = async (folderName: string) => {
try {
await validationSrv.validateNewFolderName(folderName);
Expand All @@ -34,23 +40,25 @@ export function NewFolderForm({ onCancel, onConfirm }: Props) {
{({ register, errors }) => (
<>
<Field
label="Folder name"
label={translatedFoldername}
invalid={!!errors.folderName}
error={errors.folderName && errors.folderName.message}
>
<Input
id="folder-name-input"
{...register('folderName', {
required: 'Folder name is required.',
required: translatedFolderNameRequiredPhrase,
validate: async (v) => await validateFolderName(v),
})}
/>
</Field>
<HorizontalGroup>
<Button variant="secondary" fill="outline" onClick={onCancel}>
Cancel
<Trans i18nKey="browse-dashboards.action.cancel-button">Cancel</Trans>
</Button>
<Button type="submit">
<Trans i18nKey="browse-dashboards.action.create-button">Create</Trans>
</Button>
<Button type="submit">Create</Button>
</HorizontalGroup>
</>
)}
Expand Down
14 changes: 8 additions & 6 deletions public/app/features/folders/state/navModel.ts
@@ -1,5 +1,7 @@
import { NavModel, NavModelItem } from '@grafana/data';
import { config } from '@grafana/runtime';
import { getNavSubTitle } from 'app/core/components/AppChrome/MegaMenu/navBarItem-translations';
import { t } from 'app/core/internationalization';
import { contextSrv } from 'app/core/services/context_srv';
import { AccessControlAction, FolderDTO } from 'app/types';

Expand All @@ -15,15 +17,15 @@ export function buildNavModel(folder: FolderDTO, parents = folder.parents): NavM
const model: NavModelItem = {
icon: 'folder',
id: FOLDER_ID,
subTitle: 'Manage folder dashboards and permissions',
subTitle: getNavSubTitle('manage-folder'),
url: folder.url,
text: folder.title,
children: [
{
active: false,
icon: 'apps',
id: getDashboardsTabID(folder.uid),
text: 'Dashboards',
text: t('browse-dashboards.manage-folder-nav.dashboards', 'Dashboards'),
url: folder.url,
},
],
Expand All @@ -39,7 +41,7 @@ export function buildNavModel(folder: FolderDTO, parents = folder.parents): NavM
active: false,
icon: 'library-panel',
id: getLibraryPanelsTabID(folder.uid),
text: 'Panels',
text: t('browse-dashboards.manage-folder-nav.panels', 'Panels'),
url: `${folder.url}/library-panels`,
});

Expand All @@ -48,7 +50,7 @@ export function buildNavModel(folder: FolderDTO, parents = folder.parents): NavM
active: false,
icon: 'bell',
id: getAlertingTabID(folder.uid),
text: 'Alert rules',
text: t('browse-dashboards.manage-folder-nav.alert-rules', 'Alert rules'),
url: `${folder.url}/alerting`,
});
}
Expand All @@ -59,7 +61,7 @@ export function buildNavModel(folder: FolderDTO, parents = folder.parents): NavM
active: false,
icon: 'lock',
id: getPermissionsTabID(folder.uid),
text: 'Permissions',
text: t('browse-dashboards.manage-folder-nav.permissions', 'Permissions'),
url: `${folder.url}/permissions`,
});
}
Expand All @@ -69,7 +71,7 @@ export function buildNavModel(folder: FolderDTO, parents = folder.parents): NavM
active: false,
icon: 'cog',
id: getSettingsTabID(folder.uid),
text: 'Settings',
text: t('browse-dashboards.manage-folder-nav.settings', 'Settings'),
url: `${folder.url}/settings`,
});
}
Expand Down
23 changes: 22 additions & 1 deletion public/locales/de-DE/grafana.json
Expand Up @@ -2,14 +2,35 @@
"_comment": "Do not manually edit this file. Translations must be made in Crowdin which will sync them back into this file",
"browse-dashboards": {
"action": {
"cancel-button": "",
"create-button": "",
"delete-button": "",
"move-button": ""
"delete-modal-text": "",
"delete-modal-title": "",
"deleting": "",
"folder-actions-button": "",
"manage-permissions-button": "",
"move-button": "",
"move-modal-alert": "",
"move-modal-field-label": "",
"move-modal-text": "",
"move-modal-title": "",
"moving": "",
"new-folder-label": "",
"new-folder-name-required-phrase": ""
},
"dashboards-tree": {
"name-column": "",
"tags-column": "",
"type-column": ""
},
"manage-folder-nav": {
"alert-rules": "",
"dashboards": "",
"panels": "",
"permissions": "",
"settings": ""
},
"no-results": {
"clear": "",
"text": ""
Expand Down
23 changes: 22 additions & 1 deletion public/locales/en-US/grafana.json
Expand Up @@ -2,14 +2,35 @@
"_comment": "Do not manually edit this file, or update these source phrases in Crowdin. The source of truth for English strings are in the code source",
"browse-dashboards": {
"action": {
"cancel-button": "Cancel",
"create-button": "Create",
"delete-button": "Delete",
"move-button": "Move"
"delete-modal-text": "This action will delete the following content:",
"delete-modal-title": "Delete",
"deleting": "Deleting...",
"folder-actions-button": "Folder actions",
"manage-permissions-button": "Manage permissions",
"move-button": "Move",
"move-modal-alert": "Moving this item may change its permissions.",
"move-modal-field-label": "Folder name",
"move-modal-text": "This action will move the following content:",
"move-modal-title": "Move",
"moving": "Moving...",
"new-folder-label": "Folder name",
"new-folder-name-required-phrase": "Folder name is required."
},
"dashboards-tree": {
"name-column": "Name",
"tags-column": "Tags",
"type-column": "Type"
},
"manage-folder-nav": {
"alert-rules": "Alert rules",
"dashboards": "Dashboards",
"panels": "Panels",
"permissions": "Permissions",
"settings": "Settings"
},
"no-results": {
"clear": "Clear search and filters",
"text": "No results found for your query."
Expand Down
23 changes: 22 additions & 1 deletion public/locales/es-ES/grafana.json
Expand Up @@ -2,14 +2,35 @@
"_comment": "Do not manually edit this file, or update these source phrases in Crowdin. The source of truth for English strings are in the code source",
"browse-dashboards": {
"action": {
"cancel-button": "",
"create-button": "",
"delete-button": "",
"move-button": ""
"delete-modal-text": "",
"delete-modal-title": "",
"deleting": "",
"folder-actions-button": "",
"manage-permissions-button": "",
"move-button": "",
"move-modal-alert": "",
"move-modal-field-label": "",
"move-modal-text": "",
"move-modal-title": "",
"moving": "",
"new-folder-label": "",
"new-folder-name-required-phrase": ""
},
"dashboards-tree": {
"name-column": "",
"tags-column": "",
"type-column": ""
},
"manage-folder-nav": {
"alert-rules": "",
"dashboards": "",
"panels": "",
"permissions": "",
"settings": ""
},
"no-results": {
"clear": "",
"text": ""
Expand Down