feat: I18n (#1653)

* feat: i18n

* Changing language single source of truth from TEAM to USER

* Changes according to @tommoor comments on PR

* Changed package.json for build:i18n and translation label

* Finished 1st MVP of i18n for outline

* new translation labels & Portuguese from Portugal translation

* Fixes from PR request

* Described language dropdown as an experimental feature

* Set keySeparator to false in order to cowork with html keys

* Added useTranslation to Breadcrumb

* Repositioned <strong> element

* Removed extra space from TemplatesMenu

* Fortified the test suite for i18n

* Fixed trans component problematic

* Check if selected language is available

* Update yarn.lock

* Removed unused Trans

* Removing debug variable from i18n init

* Removed debug variable

* test: update snapshots

* flow: Remove decorator usage to get proper flow typing
It's a shame, but hopefully we'll move to Typescript in the next 6 months and we can forget this whole Flow mistake ever happened

* translate: Drafts

* More translatable strings

* Mo translation strings

* translation: Search

* async translations loading

* cache translations in client

* Revert "cache translations in client"

This reverts commit 08fb61ce36384ff90a704faffe4761eccfb76da1.

* Revert localStorage cache for cache headers

* Update Crowdin configuration file

* Moved translation files to locales folder and fixed english text

* Added CONTRIBUTING File for CrowdIn

* chore: Move translations again to please CrowdIn

* fix: loading paths
chore: Add strings for editor

* fix: Improve validation on documents.import endpoint

* test: mock bull

* fix: Unknown mimetype should fallback to Markdown parsing if markdown extension (#1678)

* closes #1675

* Update CONTRIBUTING

* chore: Add link to translation portal from app UI

* refactor: Centralize language config

* fix: Ensure creation of i18n directory in build

* feat: Add language prompt

* chore: Improve contributing guidelines, add link from README

* chore: Normalize tab header casing

* chore: More string externalization

* fix: Language prompt in dark mode

Co-authored-by: André Glatzl <andreglatzl@gmail.com>
This commit is contained in:
Tom Moor
2020-11-29 20:04:58 -08:00
committed by GitHub
parent 63c73c9a51
commit 1285efc49a
85 changed files with 6432 additions and 2613 deletions

View File

@@ -4,6 +4,7 @@ import { observer, inject } from "mobx-react";
import { NewDocumentIcon, PlusIcon, PinIcon } from "outline-icons";
import * as React from "react";
import { withTranslation, Trans, type TFunction } from "react-i18next";
import { Redirect, Link, Switch, Route, type Match } from "react-router-dom";
import styled, { withTheme } from "styled-components";
@@ -47,6 +48,7 @@ type Props = {
policies: PoliciesStore,
match: Match,
theme: Theme,
t: TFunction,
};
@observer
@@ -64,7 +66,7 @@ class CollectionScene extends React.Component<Props> {
}
}
componentDidUpdate(prevProps) {
componentDidUpdate(prevProps: Props) {
const { id } = this.props.match.params;
if (this.collection) {
@@ -132,7 +134,7 @@ class CollectionScene extends React.Component<Props> {
};
renderActions() {
const { match, policies } = this.props;
const { match, policies, t } = this.props;
const can = policies.abilities(match.params.id || "");
return (
@@ -142,19 +144,19 @@ class CollectionScene extends React.Component<Props> {
<Action>
<InputSearch
source="collection"
placeholder="Search in collection…"
placeholder={t("Search in collection…")}
collectionId={match.params.id}
/>
</Action>
<Action>
<Tooltip
tooltip="New document"
tooltip={t("New document")}
shortcut="n"
delay={500}
placement="bottom"
>
<Button onClick={this.onNewDocument} icon={<PlusIcon />}>
New doc
{t("New doc")}
</Button>
</Tooltip>
</Action>
@@ -169,7 +171,7 @@ class CollectionScene extends React.Component<Props> {
}
render() {
const { documents, theme } = this.props;
const { documents, theme, t } = this.props;
if (this.redirectTo) return <Redirect to={this.redirectTo} push />;
if (!this.isFetching && !this.collection) return <Search notFound />;
@@ -179,6 +181,7 @@ class CollectionScene extends React.Component<Props> {
: [];
const hasPinnedDocuments = !!pinnedDocuments.length;
const collection = this.collection;
const collectionName = collection ? collection.name : "";
return (
<CenteredContent>
@@ -188,26 +191,28 @@ class CollectionScene extends React.Component<Props> {
{collection.isEmpty ? (
<Centered column>
<HelpText>
<strong>{collection.name}</strong> doesnt contain any
documents yet.
<Trans>
<strong>{{ collectionName }}</strong> doesnt contain any
documents yet.
</Trans>
<br />
Get started by creating a new one!
<Trans>Get started by creating a new one!</Trans>
</HelpText>
<Wrapper>
<Link to={newDocumentUrl(collection.id)}>
<Button icon={<NewDocumentIcon color={theme.buttonText} />}>
Create a document
{t("Create a document")}
</Button>
</Link>
&nbsp;&nbsp;
{collection.private && (
<Button onClick={this.onPermissions} neutral>
Manage members
{t("Manage members…")}
</Button>
)}
</Wrapper>
<Modal
title="Collection permissions"
title={t("Collection permissions")}
onRequestClose={this.handlePermissionsModalClose}
isOpen={this.permissionsModalOpen}
>
@@ -218,7 +223,7 @@ class CollectionScene extends React.Component<Props> {
/>
</Modal>
<Modal
title="Edit collection"
title={t("Edit collection")}
onRequestClose={this.handleEditModalClose}
isOpen={this.editModalOpen}
>
@@ -249,7 +254,7 @@ class CollectionScene extends React.Component<Props> {
{hasPinnedDocuments && (
<>
<Subheading>
<TinyPinIcon size={18} /> Pinned
<TinyPinIcon size={18} /> {t("Pinned")}
</Subheading>
<DocumentList documents={pinnedDocuments} showPin />
</>
@@ -257,16 +262,16 @@ class CollectionScene extends React.Component<Props> {
<Tabs>
<Tab to={collectionUrl(collection.id)} exact>
Recently updated
{t("Recently updated")}
</Tab>
<Tab to={collectionUrl(collection.id, "recent")} exact>
Recently published
{t("Recently published")}
</Tab>
<Tab to={collectionUrl(collection.id, "old")} exact>
Least recently updated
{t("Least recently updated")}
</Tab>
<Tab to={collectionUrl(collection.id, "alphabetical")} exact>
AZ
{t("AZ")}
</Tab>
</Tabs>
<Switch>
@@ -351,9 +356,11 @@ const Wrapper = styled(Flex)`
margin: 10px 0;
`;
export default inject(
"collections",
"policies",
"documents",
"ui"
)(withTheme(CollectionScene));
export default withTranslation()<CollectionScene>(
inject(
"collections",
"policies",
"documents",
"ui"
)(withTheme(CollectionScene))
);