Skip to content
This repository has been archived by the owner on Dec 27, 2024. It is now read-only.

Commit

Permalink
feat(Internationalization): adds support for internationalization (#497)
Browse files Browse the repository at this point in the history
* feat(Translation): adds translation hook. applies translation on all hardcoded text

Signed-off-by: Lucas Temponi <[email protected]>

* feat(Translation): changeset

Signed-off-by: Lucas Temponi <[email protected]>

* feat(Translation): fix types

Signed-off-by: Lucas Temponi <[email protected]>

---------

Signed-off-by: Lucas Temponi <[email protected]>
Co-authored-by: Lucas Temponi <[email protected]>
Co-authored-by: Kurt King <[email protected]>
  • Loading branch information
3 people authored Dec 6, 2024
1 parent 21228b4 commit e44fb0c
Show file tree
Hide file tree
Showing 21 changed files with 396 additions and 84 deletions.
6 changes: 6 additions & 0 deletions .changeset/three-sloths-argue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@procore-oss/backstage-plugin-announcements-react': minor
'@procore-oss/backstage-plugin-announcements': minor
---

Adds internacionalization following Backstage's guidelines
1 change: 1 addition & 0 deletions plugins/announcements-react/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { useAnnouncements } from './useAnnouncements';
export { useCategories } from './useCategories';
export { useAnnouncementsTranslation } from './useAnnouncementsTranslation';
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
import { translationRef } from '../translation';

export const useAnnouncementsTranslation = () => {
return useTranslationRef(translationRef);
};
150 changes: 150 additions & 0 deletions plugins/announcements-react/src/translation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* Copyright 2024 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/core-plugin-api/alpha';

/** @public */
export const translationRef = createTranslationRef({
id: 'announcements',
messages: {
announcementForm: {
title: 'Title',
excerpt: 'Excerpt',
active: 'Active',
submit: 'Submit',
editAnnouncement: 'Edit announcement',
newAnnouncement: 'New announcement',
categoryInput: {
create: 'Create',
label: 'Category',
},
},
announcementsPage: {
newAnnouncement: 'New announcement',
genericNew: 'New',
card: {
by: 'By',
in: 'in',
edit: 'EDIT',
delete: 'DELETE',
},
grid: {
announcementDeleted: 'Announcement deleted.',
},
contextMenu: {
admin: 'Admin',
categories: 'Categories',
},
},
deleteDialog: {
title: 'Are you sure you want to delete this announcement?',
cancel: 'Cancel',
delete: 'Delete',
},
announcementsCard: {
seeAll: 'See all',
announcements: 'Announcements',
new: 'New',
in: 'in',
noAnnouncements: 'No announcements yet, want to',
addOne: 'add one',
},
announcementSearchResultListItem: {
published: 'Published',
announcement: 'Announcement',
},
announcementsTimeline: {
noAnnouncements: 'No announcements',
error: 'Error',
},
categoriesForm: {
newCategory: 'New category',
editCategory: 'Edit category',
titleLabel: 'Title',
submit: 'Submit',
},
categoriesTable: {
categoryDeleted: 'Category deleted.',
slug: 'Slug',
title: 'Title',
actions: 'Actions',
addTooltip: 'Add',
noCategoriesFound: 'No categories found.',
},
categoriesPage: {
title: 'Categories',
subtitle: 'Manage announcement categories',
},
createAnnouncementPage: {
alertMessage: 'Announcement created.',
alertMessageWithNewCategory: 'with new category',
},
editAnnouncementPage: {
updatedMessage: 'Announcement updated.',
notFoundMessage: 'Unable to find announcement',
edit: 'Edit',
},
newAnnouncementBanner: {
markAsSeen: 'Mark as seen',
},
newCategoryDialog: {
createdMessage: 'Category created.',
newCategory: 'New category',
title: 'Title',
cancelButton: 'Cancel',
createButton: 'Create',
},
admin: {
adminPortal: {
announcementsLabels: 'Announcements',
categoriesLabel: 'Categories',
title: 'Admin Portal for Announcements',
subtitle: 'Manage announcements and categories',
},
announecementsContent: {
alertMessage: 'Announcement created.',
alertMessageWithNewCategory: 'with new category',
cancelButton: 'Cancel',
createButton: 'Create Announcement',
announcements: 'Announcements',
noAnnouncementsFound: 'No announcements found',
table: {
title: 'Title',
body: 'Body',
publisher: 'Publisher',
category: 'Category',
status: 'Status',
actions: 'Actions',
active: 'Active',
inactive: 'Inactive',
},
},
categoriesContent: {
createdMessage: 'created',
deletedMessage: 'Category deleted.',
cancelButton: 'Cancel',
createButton: 'Create category',
table: {
categoryDeleted: 'Category deleted.',
slug: 'Slug',
title: 'Title',
actions: 'Actions',
addTooltip: 'Add',
noCategoriesFound: 'No categories found.',
},
},
},
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import TabList from '@mui/lab/TabList';
import TabPanel from '@mui/lab/TabPanel';
import { RequirePermission } from '@backstage/plugin-permission-react';
import { announcementCreatePermission } from '@procore-oss/backstage-plugin-announcements-common';
import { useAnnouncementsTranslation } from '@procore-oss/backstage-plugin-announcements-react';

const useStyles = makeStyles(() => ({
tabPanel: {
Expand All @@ -26,15 +27,22 @@ type AdminPortalProps = {
const AdminPortalContent = () => {
const classes = useStyles();
const [tab, setTab] = useState('announcements');
const { t } = useAnnouncementsTranslation();
const handleChange = (_event: React.ChangeEvent<{}>, tabValue: string) => {
setTab(tabValue);
};

return (
<TabContext value={tab}>
<TabList onChange={handleChange}>
<Tab label="Announcements" value="announcements" />
<Tab label="Categories" value="categories" />
<Tab
label={t('admin.adminPortal.announcementsLabels')}
value="announcements"
/>
<Tab
label={t('admin.adminPortal.categoriesLabel')}
value="categories"
/>
</TabList>
<TabPanel value="announcements" className={classes.tabPanel}>
<AnnouncementsContent />
Expand All @@ -49,12 +57,13 @@ const AdminPortalContent = () => {
/** @public */
export const AdminPortal = (props?: AdminPortalProps) => {
const { title, subtitle, themeId } = props ?? {};
const { t } = useAnnouncementsTranslation();

return (
<Page themeId={themeId ?? 'tool'}>
<Header
title={title ?? 'Admin Portal for Announcements'}
subtitle={subtitle ?? 'Manage announcements and categories'}
title={title ?? t('admin.adminPortal.title')}
subtitle={subtitle ?? t('admin.adminPortal.title')}
/>
<RequirePermission permission={announcementCreatePermission}>
<Content>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import PreviewIcon from '@mui/icons-material/Preview';
import {
announcementsApiRef,
CreateAnnouncementRequest,
useAnnouncementsTranslation,
useCategories,
} from '@procore-oss/backstage-plugin-announcements-react';
import {
Expand Down Expand Up @@ -41,6 +42,7 @@ export const AnnouncementsContent = () => {
const announcementsApi = useApi(announcementsApiRef);
const navigate = useNavigate();
const { categories } = useCategories();
const { t } = useAnnouncementsTranslation();

const { loading: loadingCreatePermission, allowed: canCreateAnnouncement } =
usePermission({
Expand Down Expand Up @@ -107,7 +109,7 @@ export const AnnouncementsContent = () => {
const { category } = request;

const slugs = categories.map((c: Category) => c.slug);
let alertMsg = 'Announcement created.';
let alertMsg = t('admin.announecementsContent.alertMessage') as string;

try {
if (category) {
Expand All @@ -116,7 +118,9 @@ export const AnnouncementsContent = () => {
});
if (slugs.indexOf(categorySlug) === -1) {
alertMsg = alertMsg.replace('.', '');
alertMsg = `${alertMsg} with new category ${category}.`;
alertMsg = `${alertMsg} ${t(
'admin.announecementsContent.alertMessage',
)} ${category}.`;

await announcementsApi.createCategory({
title: category,
Expand Down Expand Up @@ -146,37 +150,58 @@ export const AnnouncementsContent = () => {

const columns: TableColumn<Announcement>[] = [
{
title: <Typography>Title</Typography>,
title: (
<Typography>{t('admin.announecementsContent.table.title')}</Typography>
),
sorting: true,
field: 'title',
render: rowData => rowData.title,
},
{
title: <Typography>Body</Typography>,
title: (
<Typography>{t('admin.announecementsContent.table.body')}</Typography>
),
sorting: true,
field: 'body',
render: rowData => rowData.body,
},
{
title: <Typography>Publisher</Typography>,
title: (
<Typography>
{t('admin.announecementsContent.table.publisher')}
</Typography>
),
sorting: true,
field: 'publisher',
render: rowData => rowData.publisher,
},
{
title: <Typography>Category</Typography>,
title: (
<Typography>
{t('admin.announecementsContent.table.category')}
</Typography>
),
sorting: true,
field: 'category',
render: rowData => rowData.category?.title ?? '',
},
{
title: <Typography>Status</Typography>,
title: (
<Typography>{t('admin.announecementsContent.table.status')}</Typography>
),
sorting: true,
field: 'category',
render: rowData => (rowData.active ? 'Active' : 'Inactive'),
render: rowData =>
rowData.active
? t('admin.announecementsContent.table.active')
: t('admin.announecementsContent.table.inactive'),
},
{
title: <Typography>Actions</Typography>,
title: (
<Typography>
{t('admin.announecementsContent.table.actions')}
</Typography>
),
render: rowData => {
return (
<>
Expand Down Expand Up @@ -217,7 +242,9 @@ export const AnnouncementsContent = () => {
variant="contained"
onClick={() => onCreateButtonClick()}
>
{showCreateAnnouncementForm ? 'Cancel' : 'Create Announcement'}
{showCreateAnnouncementForm
? t('admin.announecementsContent.cancelButton')
: t('admin.announecementsContent.createButton')}
</Button>
</Grid>

Expand All @@ -232,11 +259,15 @@ export const AnnouncementsContent = () => {

<Grid item xs={12}>
<Table
title="Announcements"
title={t('admin.announecementsContent.announcements')}
options={{ pageSize: 20, search: true }}
columns={columns}
data={announcements?.results ?? []}
emptyContent={<Typography p={2}>No announcements found</Typography>}
emptyContent={
<Typography p={2}>
{t('admin.announecementsContent.noAnnouncementsFound')}
</Typography>
}
/>

<DeleteAnnouncementDialog
Expand Down
Loading

0 comments on commit e44fb0c

Please sign in to comment.