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

Incorporate i18n into UI elements #1471

Merged
merged 29 commits into from
Jun 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0ba1ec1
Update zh-tw string table (till 975343d2)
Still34 Jun 1, 2021
d577823
Prepare localization table
Still34 Jun 2, 2021
737c0f5
Implement i18n for Performers & Tags
Still34 Jun 2, 2021
9fd9584
Add "add" action strings
Still34 Jun 3, 2021
99bb066
Replace triple dots with ellipsis
Still34 Jun 3, 2021
290843c
Revert performer_bio refactor
Still34 Jun 3, 2021
ba491ed
Use Lodash merge for deep merging language JSONs
Still34 Jun 3, 2021
f38ab38
Localize pagination strings
Still34 Jun 3, 2021
0617a1f
Use Field name value as null id fallback
Still34 Jun 3, 2021
ee7dc34
Use localized "Path" string for all instances
Still34 Jun 3, 2021
029dc6e
Localize the "Interface" tab under settings
Still34 Jun 3, 2021
cf11f5b
Fix linting errors
Still34 Jun 3, 2021
597da79
Update more buttons
Still34 Jun 3, 2021
a0148ff
Localize scene & performer cards
Still34 Jun 4, 2021
0c173f1
Rename locale folder for better compatibility with i18n-ally
Still34 Jun 4, 2021
15087c4
Localize majority of the categories and features
Still34 Jun 4, 2021
36c83c5
Post-edit linting
Still34 Jun 4, 2021
62439f1
Fix typo
Still34 Jun 5, 2021
895d47f
Finish localization
Still34 Jun 5, 2021
711557b
Fix accidental "path" property add in en-US.json
Still34 Jun 8, 2021
5a401d4
Remove redundant ternary statement & unnecessary undefined property
Still34 Jun 8, 2021
01e2acf
Remove redundant name attributes
Still34 Jun 8, 2021
9019d15
Implement missing localization for MovieDetailsPanel
Still34 Jun 8, 2021
d85859d
Add missing localization for DetailsEditNavbar
Still34 Jun 8, 2021
869116f
Fix linting
Still34 Jun 8, 2021
7dbdd30
Add missing localization strings
Still34 Jun 8, 2021
26ff3b6
Merge remote-tracking branch 'upstream/develop' into prs/1471
WithoutPants Jun 14, 2021
13135e1
Add changelog entry
WithoutPants Jun 14, 2021
fef68df
Format
WithoutPants Jun 14, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion ui/v2.5/.vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,12 @@
"javascript.preferences.importModuleSpecifier": "relative",
"typescript.preferences.importModuleSpecifier": "relative",
"editor.wordWrapColumn": 120,
"editor.rulers": [120]
"editor.rulers": [
120
],
"i18n-ally.localesPaths": [
"src/locales"
],
"i18n-ally.keystyle": "nested",
"i18n-ally.sourceLanguage": "en-GB"
}
11 changes: 6 additions & 5 deletions ui/v2.5/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React, { useEffect } from "react";
import { Route, Switch, useRouteMatch } from "react-router-dom";
import { IntlProvider } from "react-intl";
import { merge } from "lodash";
import { ToastProvider } from "src/hooks/Toast";
import LightboxProvider from "src/hooks/Lightbox/context";
import { library } from "@fortawesome/fontawesome-svg-core";
import { fas } from "@fortawesome/free-solid-svg-icons";
import { initPolyfills } from "src/polyfills";

import locales from "src/locale";
import locales from "src/locales";
import { useConfiguration, useSystemStatus } from "src/core/StashService";
import { flattenMessages } from "src/utils";
import Mousetrap from "mousetrap";
Expand Down Expand Up @@ -58,12 +59,12 @@ export const App: React.FC = () => {
const messageLanguage = languageMessageString(language);

// use en-GB as default messages if any messages aren't found in the chosen language
const mergedMessages = {
const mergedMessages = merge(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
...(locales as any)[defaultMessageLanguage],
(locales as any)[defaultMessageLanguage],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
...(locales as any)[messageLanguage],
};
(locales as any)[messageLanguage]
);
const messages = flattenMessages(mergedMessages);

const setupMatch = useRouteMatch(["/setup", "/migrate"]);
Expand Down
1 change: 1 addition & 0 deletions ui/v2.5/src/components/Changelog/versions/v080.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* Added [DLNA server](/settings?tab=dlna). ([#1364](https://github.com/stashapp/stash/pull/1364))

### 🎨 Improvements
* Added internationalisation for all UI pages and added zh-TW language option. ([#1471](https://github.com/stashapp/stash/pull/1471))
* Add option to disable audio for generated previews. ([#1454](https://github.com/stashapp/stash/pull/1454))
* Prompt when leaving scene edit page with unsaved changes. ([#1429](https://github.com/stashapp/stash/pull/1429))
* Make multi-set mode buttons more obvious in multi-edit dialog. ([#1435](https://github.com/stashapp/stash/pull/1435))
Expand Down
46 changes: 26 additions & 20 deletions ui/v2.5/src/components/Galleries/DeleteGalleriesDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useGalleryDestroy } from "src/core/StashService";
import * as GQL from "src/core/generated-graphql";
import { Modal } from "src/components/Shared";
import { useToast } from "src/hooks";
import { FormattedMessage } from "react-intl";
import { useIntl } from "react-intl";

interface IDeleteGalleryDialogProps {
selected: Pick<GQL.Gallery, "id">[];
Expand All @@ -14,20 +14,22 @@ interface IDeleteGalleryDialogProps {
export const DeleteGalleriesDialog: React.FC<IDeleteGalleryDialogProps> = (
props: IDeleteGalleryDialogProps
) => {
const plural = props.selected.length > 1;
const intl = useIntl();
const singularEntity = intl.formatMessage({ id: "gallery" });
const pluralEntity = intl.formatMessage({ id: "galleries" });

const singleMessageId = "deleteGalleryText";
const pluralMessageId = "deleteGallerysText";

const singleMessage =
"Are you sure you want to delete this gallery? Galleries for zip files will be re-added during the next scan unless the zip file is also deleted.";
const pluralMessage =
"Are you sure you want to delete these galleries? Galleries for zip files will be re-added during the next scan unless the zip files are also deleted.";

const header = plural ? "Delete Galleries" : "Delete Gallery";
const toastMessage = plural ? "Deleted galleries" : "Deleted gallery";
const messageId = plural ? pluralMessageId : singleMessageId;
const message = plural ? pluralMessage : singleMessage;
const header = intl.formatMessage(
{ id: "dialogs.delete_entity_title" },
{ count: props.selected.length, singularEntity, pluralEntity }
);
const toastMessage = intl.formatMessage(
{ id: "toast.delete_entity" },
{ count: props.selected.length, singularEntity, pluralEntity }
);
const message = intl.formatMessage(
{ id: "dialogs.delete_entity_desc" },
{ count: props.selected.length, singularEntity, pluralEntity }
);

const [deleteFile, setDeleteFile] = useState<boolean>(false);
const [deleteGenerated, setDeleteGenerated] = useState<boolean>(true);
Expand Down Expand Up @@ -63,17 +65,19 @@ export const DeleteGalleriesDialog: React.FC<IDeleteGalleryDialogProps> = (
show
icon="trash-alt"
header={header}
accept={{ variant: "danger", onClick: onDelete, text: "Delete" }}
accept={{
variant: "danger",
onClick: onDelete,
text: intl.formatMessage({ id: "actions.delete" }),
}}
cancel={{
onClick: () => props.onClose(false),
text: "Cancel",
text: intl.formatMessage({ id: "actions.cancel" }),
variant: "secondary",
}}
isRunning={isDeleting}
>
<p>
<FormattedMessage id={messageId} defaultMessage={message} />
</p>
<p>{message}</p>
<Form>
<Form.Check
id="delete-file"
Expand All @@ -84,7 +88,9 @@ export const DeleteGalleriesDialog: React.FC<IDeleteGalleryDialogProps> = (
<Form.Check
id="delete-generated"
checked={deleteGenerated}
label="Delete generated supporting files"
label={intl.formatMessage({
id: "actions.delete_generated_supporting_files",
})}
onChange={() => setDeleteGenerated(!deleteGenerated)}
/>
</Form>
Expand Down
41 changes: 32 additions & 9 deletions ui/v2.5/src/components/Galleries/EditGalleriesDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useEffect, useState } from "react";
import { Form, Col, Row } from "react-bootstrap";
import { FormattedMessage, useIntl } from "react-intl";
import _ from "lodash";
import { useBulkGalleryUpdate } from "src/core/StashService";
import * as GQL from "src/core/generated-graphql";
Expand All @@ -17,6 +18,7 @@ interface IListOperationProps {
export const EditGalleriesDialog: React.FC<IListOperationProps> = (
props: IListOperationProps
) => {
const intl = useIntl();
const Toast = useToast();
const [rating, setRating] = useState<number>();
const [studioId, setStudioId] = useState<string>();
Expand Down Expand Up @@ -138,7 +140,14 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (
input: getGalleryInput(),
},
});
Toast.success({ content: "Updated galleries" });
Toast.success({
content: intl.formatMessage(
{ id: "toast.updated_entity" },
{
entity: intl.formatMessage({ id: "galleries" }).toLocaleLowerCase(),
}
),
});
props.onClose(true);
} catch (e) {
Toast.error(e);
Expand Down Expand Up @@ -347,19 +356,29 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (
<Modal
show
icon="pencil-alt"
header="Edit Galleries"
accept={{ onClick: onSave, text: "Apply" }}
header={intl.formatMessage(
{ id: "dialogs.edit_entity_title" },
{
count: props?.selected?.length ?? 1,
singularEntity: intl.formatMessage({ id: "gallery" }),
pluralEntity: intl.formatMessage({ id: "galleries" }),
}
)}
accept={{
onClick: onSave,
text: intl.formatMessage({ id: "actions.apply" }),
}}
cancel={{
onClick: () => props.onClose(false),
text: "Cancel",
text: intl.formatMessage({ id: "actions.cancel" }),
variant: "secondary",
}}
isRunning={isUpdating}
>
<Form>
<Form.Group controlId="rating" as={Row}>
{FormUtils.renderLabel({
title: "Rating",
title: intl.formatMessage({ id: "rating" }),
})}
<Col xs={9}>
<RatingStars
Expand All @@ -372,7 +391,7 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (

<Form.Group controlId="studio" as={Row}>
{FormUtils.renderLabel({
title: "Studio",
title: intl.formatMessage({ id: "studio" }),
})}
<Col xs={9}>
<StudioSelect
Expand All @@ -386,19 +405,23 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (
</Form.Group>

<Form.Group controlId="performers">
<Form.Label>Performers</Form.Label>
<Form.Label>
<FormattedMessage id="performers" />
</Form.Label>
{renderMultiSelect("performers", performerIds)}
</Form.Group>

<Form.Group controlId="tags">
<Form.Label>Tags</Form.Label>
<Form.Label>
<FormattedMessage id="tags" />
</Form.Label>
{renderMultiSelect("tags", tagIds)}
</Form.Group>

<Form.Group controlId="organized">
<Form.Check
type="checkbox"
label="Organized"
label={intl.formatMessage({ id: "organized" })}
checked={organized}
ref={checkboxRef}
onChange={() => cycleOrganized()}
Expand Down
50 changes: 39 additions & 11 deletions ui/v2.5/src/components/Galleries/GalleryDetails/Gallery.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Tab, Nav, Dropdown } from "react-bootstrap";
import React, { useEffect, useState } from "react";
import { useParams, useHistory, Link } from "react-router-dom";
import { FormattedMessage, useIntl } from "react-intl";
import {
mutateMetadataScan,
useFindGallery,
Expand Down Expand Up @@ -28,6 +29,7 @@ export const Gallery: React.FC = () => {
const { tab = "images", id = "new" } = useParams<IGalleryParams>();
const history = useHistory();
const Toast = useToast();
const intl = useIntl();
const isNew = id === "new";

const { data, error, loading } = useFindGallery(id);
Expand Down Expand Up @@ -73,7 +75,15 @@ export const Gallery: React.FC = () => {
paths: [gallery.path],
});

Toast.success({ content: "Rescanning image" });
Toast.success({
content: intl.formatMessage(
{ id: "toast.rescanning_entity" },
{
count: 1,
singularEntity: intl.formatMessage({ id: "gallery" }),
}
),
});
}

const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState<boolean>(false);
Expand Down Expand Up @@ -103,7 +113,7 @@ export const Gallery: React.FC = () => {
variant="secondary"
id="operation-menu"
className="minimal"
title="Operations"
title={intl.formatMessage({ id: "operations" })}
>
<Icon icon="ellipsis-v" />
</Dropdown.Toggle>
Expand All @@ -114,15 +124,18 @@ export const Gallery: React.FC = () => {
className="bg-secondary text-white"
onClick={() => onRescan()}
>
Rescan
<FormattedMessage id="actions.rescan" />
</Dropdown.Item>
) : undefined}
<Dropdown.Item
key="delete-gallery"
className="bg-secondary text-white"
onClick={() => setIsDeleteAlertOpen(true)}
>
Delete Gallery
<FormattedMessage
id="actions.delete_entity"
values={{ entityType: intl.formatMessage({ id: "gallery" }) }}
/>
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
Expand All @@ -142,22 +155,28 @@ export const Gallery: React.FC = () => {
<div>
<Nav variant="tabs" className="mr-auto">
<Nav.Item>
<Nav.Link eventKey="gallery-details-panel">Details</Nav.Link>
<Nav.Link eventKey="gallery-details-panel">
<FormattedMessage id="details" />
</Nav.Link>
</Nav.Item>
{gallery.scenes.length > 0 && (
<Nav.Item>
<Nav.Link eventKey="gallery-scenes-panel">Scenes</Nav.Link>
<Nav.Link eventKey="gallery-scenes-panel">
<FormattedMessage id="scenes" />
</Nav.Link>
</Nav.Item>
)}
{gallery.path ? (
<Nav.Item>
<Nav.Link eventKey="gallery-file-info-panel">
File Info
<FormattedMessage id="file_info" />
</Nav.Link>
</Nav.Item>
) : undefined}
<Nav.Item>
<Nav.Link eventKey="gallery-edit-panel">Edit</Nav.Link>
<Nav.Link eventKey="gallery-edit-panel">
<FormattedMessage id="actions.edit" />
</Nav.Link>
</Nav.Item>
<Nav.Item className="ml-auto">
<OrganizedButton
Expand Down Expand Up @@ -212,10 +231,14 @@ export const Gallery: React.FC = () => {
<div>
<Nav variant="tabs" className="mr-auto">
<Nav.Item>
<Nav.Link eventKey="images">Images</Nav.Link>
<Nav.Link eventKey="images">
<FormattedMessage id="images" />
</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="add">Add</Nav.Link>
<Nav.Link eventKey="add">
<FormattedMessage id="actions.add" />
</Nav.Link>
</Nav.Item>
</Nav>
</div>
Expand Down Expand Up @@ -255,7 +278,12 @@ export const Gallery: React.FC = () => {
return (
<div className="row new-view">
<div className="col-6">
<h2>Create Gallery</h2>
<h2>
<FormattedMessage
id="actions.create_entity"
values={{ entityType: intl.formatMessage({ id: "gallery" }) }}
/>
</h2>
<GalleryEditPanel
isNew
gallery={undefined}
Expand Down
Loading