From 3e88ee748716a5fea5d514d0db4151f6c9a7b318 Mon Sep 17 00:00:00 2001 From: slorber Date: Wed, 3 Feb 2021 19:26:10 +0100 Subject: [PATCH 1/2] Translate theme hardcoded strings --- .../src/theme/BlogListPaginator/index.tsx | 19 ++++++++++++-- .../src/theme/BlogPostItem/index.tsx | 10 ++++++-- .../src/theme/BlogPostPage/index.tsx | 12 ++------- .../src/theme/BlogPostPaginator/index.tsx | 17 +++++++++++-- .../src/theme/BlogTagsListPage/index.tsx | 1 + .../src/theme/BlogTagsPostsPage/index.tsx | 1 + .../src/theme/CodeBlock/index.tsx | 21 +++++++++++++--- .../src/theme/DocItem/index.tsx | 13 ++-------- .../src/theme/DocPaginator/index.tsx | 17 +++++++++++-- .../src/theme/EditThisPage/index.tsx | 25 +++++++++++++++++++ .../src/theme/NotFound.tsx | 25 ++++++++++++++++--- .../src/theme/SkipToContent/index.tsx | 8 ++++-- .../docusaurus-theme-classic/src/types.d.ts | 8 ++++++ .../src/theme/Playground/index.js | 17 +++++++++---- .../translations/translationsExtractor.ts | 19 +++++++++++--- website/package.json | 1 + 16 files changed, 167 insertions(+), 47 deletions(-) create mode 100644 packages/docusaurus-theme-classic/src/theme/EditThisPage/index.tsx diff --git a/packages/docusaurus-theme-classic/src/theme/BlogListPaginator/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogListPaginator/index.tsx index 8792c3a84cec..ab708bd076a8 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogListPaginator/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogListPaginator/index.tsx @@ -7,6 +7,7 @@ import React from 'react'; import Link from '@docusaurus/Link'; +import Translate from '@docusaurus/Translate'; import type {Metadata} from '@theme/BlogListPage'; function BlogListPaginator(props: {readonly metadata: Metadata}): JSX.Element { @@ -18,14 +19,28 @@ function BlogListPaginator(props: {readonly metadata: Metadata}): JSX.Element {
{previousPage && ( -
« Newer Entries
+
+ «{' '} + + Newer Entries + +
)}
{nextPage && ( -
Older Entries »
+
+ + Older Entries + {' '} + » +
)}
diff --git a/packages/docusaurus-theme-classic/src/theme/BlogPostItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogPostItem/index.tsx index 4c7588c802bd..5727f60a6467 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogPostItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogPostItem/index.tsx @@ -8,7 +8,7 @@ import React from 'react'; import clsx from 'clsx'; import {MDXProvider} from '@mdx-js/react'; - +import Translate from '@docusaurus/Translate'; import Head from '@docusaurus/Head'; import Link from '@docusaurus/Link'; import MDXComponents from '@theme/MDXComponents'; @@ -133,7 +133,13 @@ function BlogPostItem(props: Props): JSX.Element { - Read More + + + Read More + + )} diff --git a/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx index 3e1b030e3ae4..f78986875094 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx @@ -6,14 +6,13 @@ */ import React from 'react'; - import Layout from '@theme/Layout'; import BlogPostItem from '@theme/BlogPostItem'; import BlogPostPaginator from '@theme/BlogPostPaginator'; import type {Props} from '@theme/BlogPostPage'; import BlogSidebar from '@theme/BlogSidebar'; import TOC from '@theme/TOC'; -import IconEdit from '@theme/IconEdit'; +import EditThisPage from '@theme/EditThisPage'; function BlogPostPage(props: Props): JSX.Element { const {content: BlogPostContents, sidebar} = props; @@ -39,14 +38,7 @@ function BlogPostPage(props: Props): JSX.Element { isBlogPostPage> -
- {editUrl && ( - - - Edit this page - - )} -
+
{editUrl && }
{(nextItem || prevItem) && (
diff --git a/packages/docusaurus-theme-classic/src/theme/BlogPostPaginator/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogPostPaginator/index.tsx index 2d4741bd94ac..484ba67e7cae 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogPostPaginator/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogPostPaginator/index.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import Translate from '@docusaurus/Translate'; import Link from '@docusaurus/Link'; import type {Props} from '@theme/BlogPostPaginator'; @@ -17,7 +18,13 @@ function BlogPostPaginator(props: Props): JSX.Element {
{prevItem && ( -
Newer Post
+
+ + Newer Post + +
« {prevItem.title}
@@ -27,7 +34,13 @@ function BlogPostPaginator(props: Props): JSX.Element {
{nextItem && ( -
Older Post
+
+ + Older Post + +
{nextItem.title} »
diff --git a/packages/docusaurus-theme-classic/src/theme/BlogTagsListPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogTagsListPage/index.tsx index b5967712433c..2174580dba63 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogTagsListPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogTagsListPage/index.tsx @@ -49,6 +49,7 @@ function BlogTagsListPage(props: Props): JSX.Element { )) .filter((item) => item != null); + // TODO soon: translate hardcoded labels, but factorize them (blog + docs will both have tags) return ( { }; const codeBlockTitleRegex = /(?:title=")(.*)(?:")/; -export default ({ +export default function CodeBlock({ children, className: languageClassName, metastring, -}: Props): JSX.Element => { +}: Props): JSX.Element { const {prism} = useThemeConfig(); const [showCopied, setShowCopied] = useState(false); @@ -242,11 +243,23 @@ export default ({ aria-label="Copy code to clipboard" className={clsx(styles.copyButton)} onClick={handleCopyCode}> - {showCopied ? 'Copied' : 'Copy'} + {showCopied ? ( + + Copied + + ) : ( + + Copy + + )}
)} ); -}; +} diff --git a/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx index 9b4a243a074e..154b2bfcf85f 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx @@ -6,7 +6,6 @@ */ import React from 'react'; - import Head from '@docusaurus/Head'; import {useTitleFormatter} from '@docusaurus/theme-common'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; @@ -15,7 +14,7 @@ import DocPaginator from '@theme/DocPaginator'; import DocVersionSuggestions from '@theme/DocVersionSuggestions'; import type {Props} from '@theme/DocItem'; import TOC from '@theme/TOC'; -import IconEdit from '@theme/IconEdit'; +import EditThisPage from '@theme/EditThisPage'; import clsx from 'clsx'; import styles from './styles.module.css'; @@ -107,15 +106,7 @@ function DocItem(props: Props): JSX.Element {
- {editUrl && ( - - - Edit this page - - )} + {editUrl && }
{(lastUpdatedAt || lastUpdatedBy) && (
diff --git a/packages/docusaurus-theme-classic/src/theme/DocPaginator/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocPaginator/index.tsx index a9d10027b586..05c490b40966 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocPaginator/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocPaginator/index.tsx @@ -7,6 +7,7 @@ import React from 'react'; import Link from '@docusaurus/Link'; +import Translate from '@docusaurus/Translate'; import type {Props} from '@theme/DocPaginator'; function DocPaginator(props: Props): JSX.Element { @@ -19,7 +20,13 @@ function DocPaginator(props: Props): JSX.Element { -
Previous
+
+ + Previous + +
« {metadata.previous.title}
@@ -29,7 +36,13 @@ function DocPaginator(props: Props): JSX.Element {
{metadata.next && ( -
Next
+
+ + Next + +
{metadata.next.title} »
diff --git a/packages/docusaurus-theme-classic/src/theme/EditThisPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/EditThisPage/index.tsx new file mode 100644 index 000000000000..c437a54d0a29 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/EditThisPage/index.tsx @@ -0,0 +1,25 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import Translate from '@docusaurus/Translate'; + +import type {Props} from '@theme/EditThisPage'; +import IconEdit from '@theme/IconEdit'; + +export default function EditThisPage({editUrl}: Props): JSX.Element { + return ( + + + + Edit this page + + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/NotFound.tsx b/packages/docusaurus-theme-classic/src/theme/NotFound.tsx index caa509ab849b..bbd776d30204 100644 --- a/packages/docusaurus-theme-classic/src/theme/NotFound.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NotFound.tsx @@ -7,6 +7,7 @@ import React from 'react'; import Layout from '@theme/Layout'; +import Translate from '@docusaurus/Translate'; function NotFound(): JSX.Element { return ( @@ -14,11 +15,27 @@ function NotFound(): JSX.Element {
-

Page Not Found

-

We could not find what you were looking for.

+

+ + Page Not Found + +

- Please contact the owner of the site that linked you to the - original URL and let them know their link is broken. + + We could not find what you were looking for. + +

+

+ + Please contact the owner of the site that linked you to the + original URL and let them know their link is broken. +

diff --git a/packages/docusaurus-theme-classic/src/theme/SkipToContent/index.tsx b/packages/docusaurus-theme-classic/src/theme/SkipToContent/index.tsx index 32883e1b37e1..bd46017ae379 100644 --- a/packages/docusaurus-theme-classic/src/theme/SkipToContent/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/SkipToContent/index.tsx @@ -6,8 +6,8 @@ */ import React, {useRef, useEffect} from 'react'; +import Translate from '@docusaurus/Translate'; import {useLocation} from '@docusaurus/router'; - import styles from './styles.module.css'; function programmaticFocus(el) { @@ -39,7 +39,11 @@ function SkipToContent(): JSX.Element { return ( ); diff --git a/packages/docusaurus-theme-classic/src/types.d.ts b/packages/docusaurus-theme-classic/src/types.d.ts index 5355db8b886a..84b7c53a9eea 100644 --- a/packages/docusaurus-theme-classic/src/types.d.ts +++ b/packages/docusaurus-theme-classic/src/types.d.ts @@ -92,6 +92,14 @@ declare module '@theme/DocVersionSuggestions' { export default DocVersionSuggestions; } +declare module '@theme/EditThisPage' { + export type Props = { + readonly editUrl: string; + }; + const EditThisPage: (props: Props) => JSX.Element; + export default EditThisPage; +} + declare module '@theme/Footer' { const Footer: () => JSX.Element | null; export default Footer; diff --git a/packages/docusaurus-theme-live-codeblock/src/theme/Playground/index.js b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/index.js index 1a62fa0fba98..16f4eb3a9704 100644 --- a/packages/docusaurus-theme-live-codeblock/src/theme/Playground/index.js +++ b/packages/docusaurus-theme-live-codeblock/src/theme/Playground/index.js @@ -8,10 +8,11 @@ import * as React from 'react'; import {LiveProvider, LiveEditor, LiveError, LivePreview} from 'react-live'; import clsx from 'clsx'; +import Translate from '@docusaurus/Translate'; import styles from './styles.module.css'; -function Playground({children, theme, transformCode, ...props}) { +export default function Playground({children, theme, transformCode, ...props}) { return ( - Live Editor + + Live Editor +
- Result + + Result +
@@ -40,5 +49,3 @@ function Playground({children, theme, transformCode, ...props}) { ); } - -export default Playground; diff --git a/packages/docusaurus/src/server/translations/translationsExtractor.ts b/packages/docusaurus/src/server/translations/translationsExtractor.ts index e4a581f0173f..2b90d4246e88 100644 --- a/packages/docusaurus/src/server/translations/translationsExtractor.ts +++ b/packages/docusaurus/src/server/translations/translationsExtractor.ts @@ -31,15 +31,28 @@ function isTranslatableSourceCodePath(filePath: string): boolean { return TranslatableSourceCodeExtension.has(nodePath.extname(filePath)); } +function getPluginSourceCodeFilePaths(plugin: InitPlugin): string[] { + // The getPathsToWatch() generally returns the js/jsx/ts/tsx/md/mdx file paths + // We can use this method as well to know which folders we should try to extract translations from + // Hacky/implicit, but do we want to introduce a new lifecycle method just for that??? + const codePaths: string[] = plugin.getPathsToWatch?.() ?? []; + + // We also include theme code + const themePath = plugin.getThemePath?.(); + if (themePath) { + codePaths.push(themePath); + } + + return codePaths; +} + async function getSourceCodeFilePaths( plugins: InitPlugin[], ): Promise { // The getPathsToWatch() generally returns the js/jsx/ts/tsx/md/mdx file paths // We can use this method as well to know which folders we should try to extract translations from // Hacky/implicit, but do we want to introduce a new lifecycle method for that??? - const allPathsToWatch = flatten( - plugins.map((plugin) => plugin.getPathsToWatch?.() ?? []), - ); + const allPathsToWatch = flatten(plugins.map(getPluginSourceCodeFilePaths)); // Required for Windows support, as paths using \ should not be used by globby // (also using the windows hard drive prefix like c: is not a good idea) diff --git a/website/package.json b/website/package.json index bff99a9562cf..281e45b12793 100644 --- a/website/package.json +++ b/website/package.json @@ -10,6 +10,7 @@ "deploy": "docusaurus deploy", "clear": "docusaurus clear", "serve": "docusaurus serve", + "write-translations": "docusaurus write-translations", "start:baseUrl": "cross-env BASE_URL='/build/' yarn start", "build:baseUrl": "cross-env BASE_URL='/build/' yarn build", "start:bootstrap": "cross-env DOCUSAURUS_PRESET=bootstrap yarn start", From defd176e7923397bb4ec74e4ee7a65d11d6433df Mon Sep 17 00:00:00 2001 From: slorber Date: Wed, 3 Feb 2021 19:45:43 +0100 Subject: [PATCH 2/2] improve test --- .../__tests__/translationsExtractor.test.ts | 63 +++++++++++++++---- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts b/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts index e85a1c93ec94..043f04f4bb35 100644 --- a/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts +++ b/packages/docusaurus/src/server/translations/__tests__/translationsExtractor.test.ts @@ -238,21 +238,54 @@ describe('extractPluginsSourceCodeTranslations', () => { return { name: 'abc', getPathsToWatch() { - return [path.join(pluginDir, '**/*.{js,jsx,ts,tsx}')]; + return [path.join(pluginDir, 'subpath', '**/*.{js,jsx,ts,tsx}')]; + }, + getThemePath() { + return path.join(pluginDir, 'src', 'theme'); }, }; } const plugin1Dir = await createTmpDir(); - const plugin1File = path.join(plugin1Dir, 'file.jsx'); - await fs.ensureDir(path.dirname(plugin1File)); + const plugin1File1 = path.join(plugin1Dir, 'subpath', 'file1.jsx'); + await fs.ensureDir(path.dirname(plugin1File1)); + await fs.writeFile( + plugin1File1, + ` +export default function MyComponent() { + return ( +
+ +
+ ); +} +`, + ); + const plugin1File2 = path.join(plugin1Dir, 'src', 'theme', 'file2.jsx'); + await fs.ensureDir(path.dirname(plugin1File2)); await fs.writeFile( - plugin1File, + plugin1File2, ` export default function MyComponent() { return (
- + +
+ ); +} +`, + ); + + // This one should not be found! On purpose! + const plugin1File3 = path.join(plugin1Dir, 'unscannedFolder', 'file3.jsx'); + await fs.ensureDir(path.dirname(plugin1File3)); + await fs.writeFile( + plugin1File3, + ` +export default function MyComponent() { + return ( +
+
); } @@ -261,7 +294,7 @@ export default function MyComponent() { const plugin1 = createTestPlugin(plugin1Dir); const plugin2Dir = await createTmpDir(); - const plugin2File = path.join(plugin1Dir, 'sub', 'path', 'file.tsx'); + const plugin2File = path.join(plugin1Dir, 'subpath', 'file.tsx'); await fs.ensureDir(path.dirname(plugin2File)); await fs.writeFile( plugin2File, @@ -271,7 +304,7 @@ type Props = {hey: string}; export default function MyComponent(props: Props) { return (
- +