feat: translations (#2275)
Co-authored-by: Tom Moor <tom.moor@gmail.com>
This commit is contained in:
@ -149,12 +149,6 @@ export default class Document extends BaseModel {
|
|||||||
get isFromTemplate(): boolean {
|
get isFromTemplate(): boolean {
|
||||||
return !!this.templateId;
|
return !!this.templateId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed
|
|
||||||
get placeholder(): ?string {
|
|
||||||
return this.isTemplate ? "Start your template…" : "Start with a title…";
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
share = async () => {
|
share = async () => {
|
||||||
return this.store.rootStore.shares.create({ documentId: this.id });
|
return this.store.rootStore.shares.create({ documentId: this.id });
|
||||||
|
@ -4,6 +4,7 @@ import { observable } from "mobx";
|
|||||||
import { observer, inject } from "mobx-react";
|
import { observer, inject } from "mobx-react";
|
||||||
import { InputIcon } from "outline-icons";
|
import { InputIcon } from "outline-icons";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import { type TFunction, Trans, withTranslation } from "react-i18next";
|
||||||
import keydown from "react-keydown";
|
import keydown from "react-keydown";
|
||||||
import { Prompt, Route, withRouter } from "react-router-dom";
|
import { Prompt, Route, withRouter } from "react-router-dom";
|
||||||
import type { RouterHistory, Match } from "react-router-dom";
|
import type { RouterHistory, Match } from "react-router-dom";
|
||||||
@ -44,15 +45,6 @@ import {
|
|||||||
|
|
||||||
const AUTOSAVE_DELAY = 3000;
|
const AUTOSAVE_DELAY = 3000;
|
||||||
const IS_DIRTY_DELAY = 500;
|
const IS_DIRTY_DELAY = 500;
|
||||||
const DISCARD_CHANGES = `
|
|
||||||
You have unsaved changes.
|
|
||||||
Are you sure you want to discard them?
|
|
||||||
`;
|
|
||||||
const UPLOADING_WARNING = `
|
|
||||||
Images are still uploading.
|
|
||||||
Are you sure you want to discard them?
|
|
||||||
`;
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
match: Match,
|
match: Match,
|
||||||
history: RouterHistory,
|
history: RouterHistory,
|
||||||
@ -67,6 +59,7 @@ type Props = {
|
|||||||
theme: Theme,
|
theme: Theme,
|
||||||
auth: AuthStore,
|
auth: AuthStore,
|
||||||
ui: UiStore,
|
ui: UiStore,
|
||||||
|
t: TFunction,
|
||||||
};
|
};
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -82,7 +75,7 @@ class DocumentScene extends React.Component<Props> {
|
|||||||
getEditorText: () => string = () => this.props.document.text;
|
getEditorText: () => string = () => this.props.document.text;
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
const { auth, document } = this.props;
|
const { auth, document, t } = this.props;
|
||||||
|
|
||||||
if (prevProps.readOnly && !this.props.readOnly) {
|
if (prevProps.readOnly && !this.props.readOnly) {
|
||||||
this.updateIsDirty();
|
this.updateIsDirty();
|
||||||
@ -97,7 +90,7 @@ class DocumentScene extends React.Component<Props> {
|
|||||||
} else if (prevProps.document.revision !== this.lastRevision) {
|
} else if (prevProps.document.revision !== this.lastRevision) {
|
||||||
if (auth.user && document.updatedBy.id !== auth.user.id) {
|
if (auth.user && document.updatedBy.id !== auth.user.id) {
|
||||||
this.props.ui.showToast(
|
this.props.ui.showToast(
|
||||||
`Document updated by ${document.updatedBy.name}`,
|
t(`Document updated by ${document.updatedBy.name}`),
|
||||||
{
|
{
|
||||||
timeout: 30 * 1000,
|
timeout: 30 * 1000,
|
||||||
type: "warning",
|
type: "warning",
|
||||||
@ -302,6 +295,7 @@ class DocumentScene extends React.Component<Props> {
|
|||||||
auth,
|
auth,
|
||||||
ui,
|
ui,
|
||||||
match,
|
match,
|
||||||
|
t,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const team = auth.team;
|
const team = auth.team;
|
||||||
const { shareId } = match.params;
|
const { shareId } = match.params;
|
||||||
@ -351,11 +345,15 @@ class DocumentScene extends React.Component<Props> {
|
|||||||
<>
|
<>
|
||||||
<Prompt
|
<Prompt
|
||||||
when={this.isDirty && !this.isUploading}
|
when={this.isDirty && !this.isUploading}
|
||||||
message={DISCARD_CHANGES}
|
message={t(
|
||||||
|
`You have unsaved changes.\nAre you sure you want to discard them?`
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
<Prompt
|
<Prompt
|
||||||
when={this.isUploading && !this.isDirty}
|
when={this.isUploading && !this.isDirty}
|
||||||
message={UPLOADING_WARNING}
|
message={t(
|
||||||
|
`Images are still uploading.\nAre you sure you want to discard them?`
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@ -384,28 +382,44 @@ class DocumentScene extends React.Component<Props> {
|
|||||||
>
|
>
|
||||||
{document.isTemplate && !readOnly && (
|
{document.isTemplate && !readOnly && (
|
||||||
<Notice muted>
|
<Notice muted>
|
||||||
You’re editing a template. Highlight some text and use the{" "}
|
<Trans>
|
||||||
<PlaceholderIcon color="currentColor" /> control to add
|
You’re editing a template. Highlight some text and use the{" "}
|
||||||
placeholders that can be filled out when creating new
|
<PlaceholderIcon color="currentColor" /> control to add
|
||||||
documents from this template.
|
placeholders that can be filled out when creating new
|
||||||
|
documents from this template.
|
||||||
|
</Trans>
|
||||||
</Notice>
|
</Notice>
|
||||||
)}
|
)}
|
||||||
{document.archivedAt && !document.deletedAt && (
|
{document.archivedAt && !document.deletedAt && (
|
||||||
<Notice muted>
|
<Notice muted>
|
||||||
Archived by {document.updatedBy.name}{" "}
|
<Trans>
|
||||||
<Time dateTime={document.archivedAt} /> ago
|
Archived by {document.updatedBy.name}{" "}
|
||||||
|
<Time dateTime={document.archivedAt} /> ago
|
||||||
|
</Trans>
|
||||||
</Notice>
|
</Notice>
|
||||||
)}
|
)}
|
||||||
{document.deletedAt && (
|
{document.deletedAt && (
|
||||||
<Notice muted>
|
<Notice muted>
|
||||||
Deleted by {document.updatedBy.name}{" "}
|
<Trans>
|
||||||
<Time dateTime={document.deletedAt} /> ago
|
Deleted by {document.updatedBy.name}{" "}
|
||||||
|
<Time dateTime={document.deletedAt} /> ago
|
||||||
|
</Trans>
|
||||||
{document.permanentlyDeletedAt && (
|
{document.permanentlyDeletedAt && (
|
||||||
<>
|
<>
|
||||||
<br />
|
<br />
|
||||||
This {document.noun} will be permanently deleted in{" "}
|
{document.template ? (
|
||||||
<Time dateTime={document.permanentlyDeletedAt} /> unless
|
<Trans>
|
||||||
restored.
|
This template will be permanently deleted in{" "}
|
||||||
|
<Time dateTime={document.permanentlyDeletedAt} />{" "}
|
||||||
|
unless restored.
|
||||||
|
</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>
|
||||||
|
This document will be permanently deleted in{" "}
|
||||||
|
<Time dateTime={document.permanentlyDeletedAt} />{" "}
|
||||||
|
unless restored.
|
||||||
|
</Trans>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Notice>
|
</Notice>
|
||||||
@ -508,5 +522,7 @@ const MaxWidth = styled(Flex)`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export default withRouter(
|
export default withRouter(
|
||||||
inject("ui", "auth", "policies", "revisions")(DocumentScene)
|
withTranslation()<DocumentScene>(
|
||||||
|
inject("ui", "auth", "policies", "revisions")(DocumentScene)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
@ -3,6 +3,7 @@ import { observable } from "mobx";
|
|||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import Textarea from "react-autosize-textarea";
|
import Textarea from "react-autosize-textarea";
|
||||||
|
import { type TFunction, withTranslation } from "react-i18next";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import breakpoint from "styled-components-breakpoint";
|
import breakpoint from "styled-components-breakpoint";
|
||||||
import { MAX_TITLE_LENGTH } from "shared/constants";
|
import { MAX_TITLE_LENGTH } from "shared/constants";
|
||||||
@ -28,6 +29,7 @@ type Props = {|
|
|||||||
onSave: ({ done?: boolean, autosave?: boolean, publish?: boolean }) => any,
|
onSave: ({ done?: boolean, autosave?: boolean, publish?: boolean }) => any,
|
||||||
innerRef: { current: any },
|
innerRef: { current: any },
|
||||||
children: React.Node,
|
children: React.Node,
|
||||||
|
t: TFunction,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -102,6 +104,7 @@ class DocumentEditor extends React.Component<Props> {
|
|||||||
readOnly,
|
readOnly,
|
||||||
innerRef,
|
innerRef,
|
||||||
children,
|
children,
|
||||||
|
t,
|
||||||
...rest
|
...rest
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@ -129,7 +132,11 @@ class DocumentEditor extends React.Component<Props> {
|
|||||||
ref={this.ref}
|
ref={this.ref}
|
||||||
onChange={onChangeTitle}
|
onChange={onChangeTitle}
|
||||||
onKeyDown={this.handleTitleKeyDown}
|
onKeyDown={this.handleTitleKeyDown}
|
||||||
placeholder={document.placeholder}
|
placeholder={
|
||||||
|
document.isTemplate
|
||||||
|
? t("Start your template…")
|
||||||
|
: t("Start with a title…")
|
||||||
|
}
|
||||||
value={normalizedTitle}
|
value={normalizedTitle}
|
||||||
$startsWithEmojiAndSpace={startsWithEmojiAndSpace}
|
$startsWithEmojiAndSpace={startsWithEmojiAndSpace}
|
||||||
autoFocus={!title}
|
autoFocus={!title}
|
||||||
@ -152,7 +159,7 @@ class DocumentEditor extends React.Component<Props> {
|
|||||||
<Editor
|
<Editor
|
||||||
ref={innerRef}
|
ref={innerRef}
|
||||||
autoFocus={!!title && !this.props.defaultValue}
|
autoFocus={!!title && !this.props.defaultValue}
|
||||||
placeholder="…the rest is up to you"
|
placeholder={t("…the rest is up to you")}
|
||||||
onHoverLink={this.handleLinkActive}
|
onHoverLink={this.handleLinkActive}
|
||||||
scrollTo={window.location.hash}
|
scrollTo={window.location.hash}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
@ -224,4 +231,4 @@ const Title = styled(Textarea)`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default DocumentEditor;
|
export default withTranslation()<DocumentEditor>(DocumentEditor);
|
||||||
|
@ -305,6 +305,16 @@
|
|||||||
"Add specific access for individual groups and team members": "Add specific access for individual groups and team members",
|
"Add specific access for individual groups and team members": "Add specific access for individual groups and team members",
|
||||||
"Add groups to {{ collectionName }}": "Add groups to {{ collectionName }}",
|
"Add groups to {{ collectionName }}": "Add groups to {{ collectionName }}",
|
||||||
"Add people to {{ collectionName }}": "Add people to {{ collectionName }}",
|
"Add people to {{ collectionName }}": "Add people to {{ collectionName }}",
|
||||||
|
"You have unsaved changes.\nAre you sure you want to discard them?": "You have unsaved changes.\nAre you sure you want to discard them?",
|
||||||
|
"Images are still uploading.\nAre you sure you want to discard them?": "Images are still uploading.\nAre you sure you want to discard them?",
|
||||||
|
"You’re editing a template. Highlight some text and use the <2></2> control to add placeholders that can be filled out when creating new documents from this template.": "You’re editing a template. Highlight some text and use the <2></2> control to add placeholders that can be filled out when creating new documents from this template.",
|
||||||
|
"Archived by {document.updatedBy.name} <3></3> ago": "Archived by {document.updatedBy.name} <3></3> ago",
|
||||||
|
"Deleted by {document.updatedBy.name} <3></3> ago": "Deleted by {document.updatedBy.name} <3></3> ago",
|
||||||
|
"This template will be permanently deleted in <2></2> unless restored.": "This template will be permanently deleted in <2></2> unless restored.",
|
||||||
|
"This document will be permanently deleted in <2></2> unless restored.": "This document will be permanently deleted in <2></2> unless restored.",
|
||||||
|
"Start your template…": "Start your template…",
|
||||||
|
"Start with a title…": "Start with a title…",
|
||||||
|
"…the rest is up to you": "…the rest is up to you",
|
||||||
"Hide contents": "Hide contents",
|
"Hide contents": "Hide contents",
|
||||||
"Show contents": "Show contents",
|
"Show contents": "Show contents",
|
||||||
"Edit {{noun}}": "Edit {{noun}}",
|
"Edit {{noun}}": "Edit {{noun}}",
|
||||||
|
Reference in New Issue
Block a user