feat: home plugin support i18n
Signed-off-by: mario ma <mario.ma.node@gmail.com>
This commit is contained in:
@@ -23,6 +23,8 @@ import ListItemAvatar from '@material-ui/core/ListItemAvatar';
|
||||
import AddIcon from '@material-ui/icons/Add';
|
||||
import ListItemText from '@material-ui/core/ListItemText';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import { homeTranslationRef } from '../../translation';
|
||||
|
||||
interface AddWidgetDialogProps {
|
||||
widgets: Widget[];
|
||||
@@ -35,9 +37,10 @@ const getTitle = (widget: Widget) => {
|
||||
|
||||
export const AddWidgetDialog = (props: AddWidgetDialogProps) => {
|
||||
const { widgets, handleAdd } = props;
|
||||
const { t } = useTranslationRef(homeTranslationRef);
|
||||
return (
|
||||
<>
|
||||
<DialogTitle>Add new widget to dashboard</DialogTitle>
|
||||
<DialogTitle>{t('addWidgetDialog.title')}</DialogTitle>
|
||||
<DialogContent>
|
||||
<List dense>
|
||||
{widgets.map(widget => {
|
||||
|
||||
@@ -20,6 +20,8 @@ import DeleteIcon from '@material-ui/icons/Delete';
|
||||
import AddIcon from '@material-ui/icons/Add';
|
||||
import EditIcon from '@material-ui/icons/Edit';
|
||||
import CancelIcon from '@material-ui/icons/Cancel';
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import { homeTranslationRef } from '../../translation';
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -55,6 +57,7 @@ export const CustomHomepageButtons = (props: CustomHomepageButtonsProps) => {
|
||||
restoreDefault,
|
||||
} = props;
|
||||
const styles = useStyles();
|
||||
const { t } = useTranslationRef(homeTranslationRef);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -66,7 +69,7 @@ export const CustomHomepageButtons = (props: CustomHomepageButtonsProps) => {
|
||||
size="small"
|
||||
startIcon={<EditIcon />}
|
||||
>
|
||||
Edit
|
||||
{t('customHomepageButtons.edit')}
|
||||
</Button>
|
||||
) : (
|
||||
<>
|
||||
@@ -78,7 +81,7 @@ export const CustomHomepageButtons = (props: CustomHomepageButtonsProps) => {
|
||||
size="small"
|
||||
startIcon={<CancelIcon />}
|
||||
>
|
||||
Restore defaults
|
||||
{t('customHomepageButtons.restoreDefaults')}
|
||||
</Button>
|
||||
)}
|
||||
{numWidgets > 0 && (
|
||||
@@ -90,7 +93,7 @@ export const CustomHomepageButtons = (props: CustomHomepageButtonsProps) => {
|
||||
size="small"
|
||||
startIcon={<DeleteIcon />}
|
||||
>
|
||||
Clear all
|
||||
{t('customHomepageButtons.clearAll')}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
@@ -100,7 +103,7 @@ export const CustomHomepageButtons = (props: CustomHomepageButtonsProps) => {
|
||||
size="small"
|
||||
startIcon={<AddIcon />}
|
||||
>
|
||||
Add widget
|
||||
{t('customHomepageButtons.addWidget')}
|
||||
</Button>
|
||||
{numWidgets > 0 && (
|
||||
<Button
|
||||
@@ -111,7 +114,7 @@ export const CustomHomepageButtons = (props: CustomHomepageButtonsProps) => {
|
||||
size="small"
|
||||
startIcon={<SaveIcon />}
|
||||
>
|
||||
Save
|
||||
{t('customHomepageButtons.save')}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -50,6 +50,8 @@ import {
|
||||
WidgetSchema,
|
||||
} from './types';
|
||||
import { CardConfig } from '@backstage/plugin-home-react';
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import { homeTranslationRef } from '../../translation';
|
||||
|
||||
// eslint-disable-next-line new-cap
|
||||
const ResponsiveGrid = WidthProvider(Responsive);
|
||||
@@ -222,6 +224,7 @@ export const CustomHomepageGrid = (props: CustomHomepageGridProps) => {
|
||||
const getWidgetNameFromKey = (key: string) => {
|
||||
return key.split('__')[0];
|
||||
};
|
||||
const { t } = useTranslationRef(homeTranslationRef);
|
||||
|
||||
const handleAdd = (widget: Widget) => {
|
||||
const widgetId = `${widget.name}__${widgets.length + 1}${Math.random()
|
||||
@@ -340,7 +343,7 @@ export const CustomHomepageGrid = (props: CustomHomepageGridProps) => {
|
||||
</Dialog>
|
||||
{!editMode && widgets.length === 0 && (
|
||||
<Typography variant="h5" align="center">
|
||||
No widgets added. Start by clicking the 'Add widget' button.
|
||||
{t('customHomepage.noWidgets')}
|
||||
</Typography>
|
||||
)}
|
||||
<ResponsiveGrid
|
||||
|
||||
@@ -29,6 +29,8 @@ import { Widget } from './types';
|
||||
import { withTheme } from '@rjsf/core';
|
||||
import { Theme as MuiTheme } from '@rjsf/material-ui';
|
||||
import validator from '@rjsf/validator-ajv8';
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import { homeTranslationRef } from '../../translation';
|
||||
|
||||
const Form = withTheme(MuiTheme);
|
||||
|
||||
@@ -68,6 +70,7 @@ export const WidgetSettingsOverlay = (props: WidgetSettingsOverlayProps) => {
|
||||
const styles = useStyles();
|
||||
|
||||
const onClose = () => setSettingsDialogOpen(false);
|
||||
const { t } = useTranslationRef(homeTranslationRef);
|
||||
|
||||
return (
|
||||
<div className={styles.settingsOverlay}>
|
||||
@@ -98,10 +101,10 @@ export const WidgetSettingsOverlay = (props: WidgetSettingsOverlayProps) => {
|
||||
>
|
||||
<DialogActions>
|
||||
<Button color="primary" variant="contained" type="submit">
|
||||
Submit
|
||||
{t('widgetSettingsOverlay.submitButtonTitle')}
|
||||
</Button>
|
||||
<Button color="secondary" onClick={onClose}>
|
||||
Cancel
|
||||
{t('widgetSettingsOverlay.cancelButtonTitle')}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Form>
|
||||
@@ -116,7 +119,7 @@ export const WidgetSettingsOverlay = (props: WidgetSettingsOverlayProps) => {
|
||||
>
|
||||
{widget.settingsSchema && (
|
||||
<Grid item className="overlayGridItem">
|
||||
<Tooltip title="Edit settings">
|
||||
<Tooltip title={t('widgetSettingsOverlay.editSettingsTooptip')}>
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={() => setSettingsDialogOpen(true)}
|
||||
@@ -128,7 +131,7 @@ export const WidgetSettingsOverlay = (props: WidgetSettingsOverlayProps) => {
|
||||
)}
|
||||
{deletable !== false && (
|
||||
<Grid item className="overlayGridItem">
|
||||
<Tooltip title="Delete widget">
|
||||
<Tooltip title={t('widgetSettingsOverlay.deleteWidgetTooltip')}>
|
||||
<IconButton color="secondary" onClick={() => handleRemove(id)}>
|
||||
<DeleteIcon fontSize="large" />
|
||||
</IconButton>
|
||||
|
||||
@@ -26,6 +26,8 @@ import { entityRouteRef } from '@backstage/plugin-catalog-react';
|
||||
import { useRouteRef } from '@backstage/core-plugin-api';
|
||||
import { FavoriteToggle } from '@backstage/core-components';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import { homeTranslationRef } from '../../translation';
|
||||
|
||||
type EntityListItemProps = {
|
||||
entity: Entity;
|
||||
@@ -50,6 +52,7 @@ export const StarredEntityListItem = ({
|
||||
}: EntityListItemProps) => {
|
||||
const classes = useStyles();
|
||||
const catalogEntityRoute = useRouteRef(entityRouteRef);
|
||||
const { t } = useTranslationRef(homeTranslationRef);
|
||||
|
||||
let secondaryText = '';
|
||||
if (showKind) {
|
||||
@@ -80,7 +83,7 @@ export const StarredEntityListItem = ({
|
||||
>
|
||||
<FavoriteToggle
|
||||
id={`remove-favorite-${entity.metadata.uid}`}
|
||||
title="Remove entity from favorites"
|
||||
title={t('starredEntityListItem.removeFavoriteEntityTitle')}
|
||||
isFavorite
|
||||
onToggle={() => onToggleStarredEntity(entity)}
|
||||
/>
|
||||
|
||||
@@ -14,16 +14,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { homeTranslationRef } from '../../translation';
|
||||
|
||||
export const VisitListEmpty = () => (
|
||||
<>
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
There are no visits to show yet.
|
||||
</Typography>
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
Once you start using Backstage, your visits will appear here as a quick
|
||||
link to carry on where you left off.
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
export const VisitListEmpty = () => {
|
||||
const { t } = useTranslationRef(homeTranslationRef);
|
||||
return (
|
||||
<>
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
{t('visitList.empty.title')}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
{t('visitList.empty.description')}
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -14,12 +14,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { homeTranslationRef } from '../../translation';
|
||||
|
||||
export const VisitListFew = () => (
|
||||
<>
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
The more pages you visit, the more pages will appear here.
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
export const VisitListFew = () => {
|
||||
const { t } = useTranslationRef(homeTranslationRef);
|
||||
return (
|
||||
<>
|
||||
<Typography variant="body2" color="textSecondary">
|
||||
{t('visitList.few.title')}
|
||||
</Typography>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -33,6 +33,8 @@ import { EntityFilterQuery } from '@backstage/catalog-client';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { stringifyEntityRef } from '@backstage/catalog-model';
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import { homeTranslationRef } from '../../translation';
|
||||
|
||||
/**
|
||||
* Props customizing the <FeaturedDocsCard/> component.
|
||||
@@ -88,7 +90,8 @@ const useStyles = makeStyles(
|
||||
export const Content = (props: FeaturedDocsCardProps): JSX.Element => {
|
||||
const { emptyState, filter, linkDestination, responseLimit, subLinkText } =
|
||||
props;
|
||||
const linkText = subLinkText || 'LEARN MORE';
|
||||
const { t } = useTranslationRef(homeTranslationRef);
|
||||
const linkText = subLinkText || t('featuredDocsCard.learnMoreTitle');
|
||||
const styles = useStyles();
|
||||
const catalogApi = useApi(catalogApiRef);
|
||||
const {
|
||||
@@ -153,14 +156,14 @@ export const Content = (props: FeaturedDocsCardProps): JSX.Element => {
|
||||
emptyState || (
|
||||
<EmptyState
|
||||
missing="data"
|
||||
title="No documents to show"
|
||||
description="Create your own document. Check out our Getting Started Information"
|
||||
title={t('featuredDocsCard.empty.title')}
|
||||
description={t('featuredDocsCard.empty.description')}
|
||||
action={
|
||||
<LinkButton
|
||||
to="https://backstage.io/docs/features/techdocs/getting-started"
|
||||
variant="contained"
|
||||
>
|
||||
DOCS
|
||||
{t('featuredDocsCard.empty.learnMoreLinkTitle')}
|
||||
</LinkButton>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -20,6 +20,8 @@ import Typography from '@material-ui/core/Typography';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import { ContentModal } from '@backstage/plugin-home-react';
|
||||
import { useStyles } from './styles';
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import { homeTranslationRef } from '../../translation';
|
||||
|
||||
/**
|
||||
* Props customizing the <QuickStartCard/> component.
|
||||
@@ -54,14 +56,15 @@ export type QuickStartCardProps = {
|
||||
*/
|
||||
export const Content = (props: QuickStartCardProps): JSX.Element => {
|
||||
const styles = useStyles();
|
||||
const { t } = useTranslationRef(homeTranslationRef);
|
||||
return (
|
||||
<>
|
||||
<ContentModal
|
||||
modalContent={props.image}
|
||||
linkContent={props.modalTitle || 'Onboarding'}
|
||||
linkContent={props.modalTitle || t('quickStart.title')}
|
||||
/>
|
||||
<Typography variant="body1" paragraph>
|
||||
{props.cardDescription || 'Get started with Backstage'}
|
||||
{props.cardDescription || t('quickStart.description')}
|
||||
</Typography>
|
||||
<ContentModal modalContent={props.image} linkContent={props.image} />
|
||||
<Grid
|
||||
@@ -78,7 +81,7 @@ export const Content = (props: QuickStartCardProps): JSX.Element => {
|
||||
variant="h6"
|
||||
className={styles.link}
|
||||
>
|
||||
{props.docsLinkTitle || 'Learn more'}
|
||||
{props.docsLinkTitle || t('quickStart.learnMoreLinkTitle')}
|
||||
</Link>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -29,6 +29,8 @@ import { ReactNode, useState } from 'react';
|
||||
import useAsync from 'react-use/esm/useAsync';
|
||||
import { StarredEntityListItem } from '../../components/StarredEntityListItem/StarredEntityListItem';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import { homeTranslationRef } from '../../translation';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
tabs: {
|
||||
@@ -63,6 +65,7 @@ export const Content = ({
|
||||
const catalogApi = useApi(catalogApiRef);
|
||||
const { starredEntities, toggleStarredEntity } = useStarredEntities();
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
const { t } = useTranslationRef(homeTranslationRef);
|
||||
|
||||
// Grab starred entities from catalog to ensure they still exist and also retrieve display titles
|
||||
const entities = useAsync(async () => {
|
||||
@@ -89,7 +92,7 @@ export const Content = ({
|
||||
return (
|
||||
<Typography variant="body1">
|
||||
{noStarredEntitiesMessage ||
|
||||
'Click the star beside an entity name to add it to this list!'}
|
||||
t('starredEntities.noStarredEntitiesMessage')}
|
||||
</Typography>
|
||||
);
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
import { useCallback } from 'react';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import { useContext } from './Context';
|
||||
import { useTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
import { homeTranslationRef } from '../../translation';
|
||||
|
||||
export const Actions = () => {
|
||||
const { collapsed, setCollapsed, visits, numVisitsOpen, loading } =
|
||||
@@ -25,7 +27,10 @@ export const Actions = () => {
|
||||
() => setCollapsed(prevCollapsed => !prevCollapsed),
|
||||
[setCollapsed],
|
||||
);
|
||||
const label = collapsed ? 'View More' : 'View Less';
|
||||
const { t } = useTranslationRef(homeTranslationRef);
|
||||
const label = collapsed
|
||||
? t('visitedByType.action.viewMore')
|
||||
: t('visitedByType.action.viewLess');
|
||||
|
||||
if (!loading && visits.length <= numVisitsOpen) return <></>;
|
||||
|
||||
|
||||
@@ -42,3 +42,4 @@ export * from './assets';
|
||||
export * from './homePageComponents';
|
||||
export * from './deprecated';
|
||||
export * from './api';
|
||||
export { homeTranslationRef } from './translation';
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { createTranslationRef } from '@backstage/frontend-plugin-api';
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const homeTranslationRef = createTranslationRef({
|
||||
id: 'home',
|
||||
messages: {
|
||||
addWidgetDialog: {
|
||||
title: 'Add new widget to dashboard',
|
||||
},
|
||||
customHomepageButtons: {
|
||||
edit: 'Edit',
|
||||
restoreDefaults: 'Restore defaults',
|
||||
clearAll: 'Clear all',
|
||||
addWidget: 'Add widget',
|
||||
save: 'Save',
|
||||
},
|
||||
customHomepage: {
|
||||
noWidgets: "No widgets added. Start by clicking the 'Add widget' button.",
|
||||
},
|
||||
widgetSettingsOverlay: {
|
||||
editSettingsTooptip: 'Edit settings',
|
||||
deleteWidgetTooltip: 'Delete widget',
|
||||
submitButtonTitle: 'Submit',
|
||||
cancelButtonTitle: 'Cancel',
|
||||
},
|
||||
starredEntityListItem: {
|
||||
removeFavoriteEntityTitle: 'Remove entity from favorites',
|
||||
},
|
||||
visitList: {
|
||||
empty: {
|
||||
title: 'There are no visits to show yet.',
|
||||
description:
|
||||
'Once you start using Backstage, your visits will appear here as a quick link to carry on where you left off.',
|
||||
},
|
||||
few: {
|
||||
title: 'The more pages you visit, the more pages will appear here.',
|
||||
},
|
||||
},
|
||||
quickStart: {
|
||||
title: 'Onboarding',
|
||||
description: 'Get started with Backstage',
|
||||
learnMoreLinkTitle: 'Learn more',
|
||||
},
|
||||
starredEntities: {
|
||||
noStarredEntitiesMessage:
|
||||
'Click the star beside an entity name to add it to this list!',
|
||||
},
|
||||
visitedByType: {
|
||||
action: {
|
||||
viewMore: 'View more',
|
||||
viewLess: 'View less',
|
||||
},
|
||||
},
|
||||
featuredDocsCard: {
|
||||
learnMoreTitle: 'LEARN MORE',
|
||||
empty: {
|
||||
title: 'No documents to show',
|
||||
description:
|
||||
'Create your own document. Check out our Getting Started Information',
|
||||
learnMoreLinkTitle: 'DOCS',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user