Internationalization: Mark up more of Dashboard Variables and Browse/Search Dashboards (#63518)

* Extract dirty translations from main

* Translate some variable phrases

* Translate nav bar

* Translate search/browse

* Fix header returning null

* Translate search results type

* fix test
This commit is contained in:
Josh Hunt
2023-02-23 10:46:07 +00:00
committed by GitHub
parent 0abbfbcc59
commit 54aaaf169f
19 changed files with 422 additions and 47 deletions
@@ -3,6 +3,7 @@ import React, { useEffect } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Input, useStyles2, Spinner } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { contextSrv } from 'app/core/services/context_srv';
import { FolderDTO, AccessControlAction } from 'app/types';
@@ -49,7 +50,11 @@ export const ManageDashboardsNew = React.memo(({ folder }: Props) => {
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus
spellCheck={false}
placeholder={state.includePanels ? 'Search for dashboards and panels' : 'Search for dashboards'}
placeholder={
state.includePanels
? t('search.search-input.include-panels-placeholder', 'Search for dashboards and panels')
: t('search.search-input.placeholder', 'Search for dashboards')
}
className={styles.searchInput}
suffix={false ? <Spinner /> : null}
/>
@@ -6,16 +6,25 @@ import { config } from '@grafana/runtime';
import { HorizontalGroup, RadioButtonGroup, useStyles2, Checkbox, Button } from '@grafana/ui';
import { SortPicker } from 'app/core/components/Select/SortPicker';
import { TagFilter, TermCount } from 'app/core/components/TagFilter/TagFilter';
import { t, Trans } from 'app/core/internationalization';
import { SearchLayout, SearchState } from '../../types';
export const layoutOptions = [
{ value: SearchLayout.Folders, icon: 'folder', ariaLabel: 'View by folders' },
{ value: SearchLayout.List, icon: 'list-ul', ariaLabel: 'View as list' },
];
function getLayoutOptions() {
const layoutOptions = [
{ value: SearchLayout.Folders, icon: 'folder', ariaLabel: t('search.actions.view-as-folders', 'View by folders') },
{ value: SearchLayout.List, icon: 'list-ul', ariaLabel: t('search.actions.view-as-list', 'View as list') },
];
if (config.featureToggles.dashboardPreviews) {
layoutOptions.push({ value: SearchLayout.Grid, icon: 'apps', ariaLabel: 'Grid view' });
if (config.featureToggles.dashboardPreviews) {
layoutOptions.push({
value: SearchLayout.Grid,
icon: 'apps',
ariaLabel: t('search.actions.view-as-grid', 'Grid view'),
});
}
return layoutOptions;
}
interface Props {
@@ -80,26 +89,33 @@ export const ActionRow: FC<Props> = ({
disabled={layout === SearchLayout.Folders}
value={state.includePanels}
onChange={() => onSetIncludePanels(!state.includePanels)}
label="Include panels"
label={t('search.actions.include-panels', 'Include panels')}
/>
)}
{showStarredFilter && (
<div className={styles.checkboxWrapper}>
<Checkbox label="Starred" onChange={onStarredFilterChange} value={state.starred} />
<Checkbox
label={t('search.actions.starred', 'Starred')}
onChange={onStarredFilterChange}
value={state.starred}
/>
</div>
)}
{state.datasource && (
<Button icon="times" variant="secondary" onClick={() => onDatasourceChange(undefined)}>
Datasource: {state.datasource}
<Trans i18nKey="search.actions.remove-datasource-filter">
Datasource: {{ datasource: state.datasource }}
</Trans>
</Button>
)}
</HorizontalGroup>
<div className={styles.rowContainer}>
<HorizontalGroup spacing="md" width="auto">
{!hideLayout && (
<RadioButtonGroup
options={layoutOptions}
options={getLayoutOptions()}
disabledOptions={disabledOptions}
onChange={onLayoutChange}
value={layout}
@@ -109,7 +125,7 @@ export const ActionRow: FC<Props> = ({
onChange={(change) => onSortChange(change?.value)}
value={state.sort}
getSortOptions={getSortOptions}
placeholder={sortPlaceholder || 'Sort'}
placeholder={sortPlaceholder || t('search.actions.sort-placeholder', 'Sort')}
isClearable
/>
</HorizontalGroup>
@@ -5,6 +5,7 @@ import { useAsync, useLocalStorage } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Card, Checkbox, CollapsableSection, Icon, IconName, Spinner, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { getSectionStorageKey } from 'app/features/search/utils';
import { useUniqueId } from 'app/plugins/datasource/influxdb/components/useUniqueId';
@@ -174,7 +175,10 @@ export const FolderSection = ({
<>
{selectionToggle && selection && (
<div onClick={onToggleFolder}>
<Checkbox value={selection(section.kind, section.uid)} aria-label="Select folder" />
<Checkbox
value={selection(section.kind, section.uid)}
aria-label={t('search.folder-view.select-folder', 'Select folder')}
/>
</div>
)}
@@ -186,7 +190,8 @@ export const FolderSection = ({
<span id={labelId}>{section.title}</span>
{section.url && section.uid !== 'general' && (
<a href={section.url} className={styles.link}>
<span className={styles.separator}>|</span> <Icon name="folder-upload" /> Go to folder
<span className={styles.separator}>|</span> <Icon name="folder-upload" />{' '}
{t('search.folder-view.go-to-folder', 'Go to folder')}
</a>
)}
</div>
@@ -12,6 +12,7 @@ import {
import { config, getDataSourceSrv } from '@grafana/runtime';
import { Checkbox, Icon, IconButton, IconName, TagList } from '@grafana/ui';
import appEvents from 'app/core/app_events';
import { t } from 'app/core/internationalization';
import { PluginIconName } from 'app/features/plugins/admin/types';
import { ShowModalReactEvent } from 'app/types/events';
@@ -63,7 +64,7 @@ export const generateColumns = (
if (selection('*', '*')) {
return (
<div className={styles.checkboxHeader}>
<IconButton name={'check-square' as any} onClick={clearSelection} />
<IconButton name="check-square" onClick={clearSelection} />
</div>
);
}
@@ -132,9 +133,7 @@ export const generateColumns = (
},
id: `column-name`,
field: access.name!,
Header: () => {
return <div className={styles.headerNameStyle}>Name</div>;
},
Header: () => <div className={styles.headerNameStyle}>{t('search.results-table.name-header', 'Name')}</div>,
width,
});
availableWidth -= width;
@@ -184,7 +183,7 @@ export const generateColumns = (
},
id: `column-location`,
field: access.location ?? access.url,
Header: 'Location',
Header: () => t('search.results-table.location-header', 'Location'),
width,
});
}
@@ -281,7 +280,7 @@ function makeDataSourceColumn(
return {
id: `column-datasource`,
field,
Header: 'Data source',
Header: () => t('search.results-table.datasource-header', 'Data source'),
Cell: (p) => {
const dslist = field.values.get(p.row.index);
if (!dslist?.length) {
@@ -329,7 +328,7 @@ function makeTypeColumn(
return {
id: `column-type`,
field: kindField ?? typeField,
Header: 'Type',
Header: () => t('search.results-table.type-header', 'Type'),
Cell: (p) => {
const i = p.row.index;
const kind = kindField?.values.get(i) ?? 'dashboard';
@@ -339,12 +338,12 @@ function makeTypeColumn(
txt = kind;
switch (txt) {
case 'dashboard':
txt = 'Dashboard';
txt = t('search.results-table.type-dashboard', 'Dashboard');
break;
case 'folder':
icon = 'folder';
txt = 'Folder';
txt = t('search.results-table.type-folder', 'Folder');
break;
case 'panel':
@@ -400,7 +399,7 @@ function makeTagsColumn(
},
id: `column-tags`,
field: field,
Header: 'Tags',
Header: () => t('search.results-table.tags-header', 'Tags'),
width,
};
}