From d3a7a76a8678a4051d5b7c11c3e5a0fc86cd256f Mon Sep 17 00:00:00 2001 From: Soichiro Miki Date: Wed, 25 Oct 2023 17:26:17 +0900 Subject: [PATCH 1/8] Add new article "Translations" --- src/components/Layout/Page.tsx | 17 +++++++++++-- src/components/MDX/LanguagesContext.tsx | 14 +++++++++++ src/components/MDX/MDXComponents.tsx | 33 +++++++++++++++++++++++++ src/components/Seo.tsx | 13 +++------- src/content/community/translations.md | 25 +++++++++++++++++++ src/pages/[[...markdownPath]].js | 26 ++++++++++++++++--- src/sidebarCommunity.json | 4 +++ src/utils/deployedTranslations.ts | 7 ++++++ 8 files changed, 124 insertions(+), 15 deletions(-) create mode 100644 src/components/MDX/LanguagesContext.tsx create mode 100644 src/content/community/translations.md create mode 100644 src/utils/deployedTranslations.ts diff --git a/src/components/Layout/Page.tsx b/src/components/Layout/Page.tsx index fb771f90144..4f278b85707 100644 --- a/src/components/Layout/Page.tsx +++ b/src/components/Layout/Page.tsx @@ -16,6 +16,7 @@ import {IconNavArrow} from 'components/Icon/IconNavArrow'; import PageHeading from 'components/PageHeading'; import {getRouteMeta} from './getRouteMeta'; import {TocContext} from '../MDX/TocContext'; +import {Languages, LanguagesContext} from '../MDX/LanguagesContext'; import type {TocItem} from 'components/MDX/TocContext'; import type {RouteItem} from 'components/Layout/getRouteMeta'; import {HomeContent} from './HomeContent'; @@ -30,9 +31,17 @@ interface PageProps { routeTree: RouteItem; meta: {title?: string; canary?: boolean; description?: string}; section: 'learn' | 'reference' | 'community' | 'blog' | 'home' | 'unknown'; + languages: Languages | null; } -export function Page({children, toc, routeTree, meta, section}: PageProps) { +export function Page({ + children, + toc, + routeTree, + meta, + section, + languages, +}: PageProps) { const {asPath} = useRouter(); const cleanedPath = asPath.split(/[\?\#]/)[0]; const {route, nextRoute, prevRoute, breadcrumbs, order} = getRouteMeta( @@ -69,7 +78,11 @@ export function Page({children, toc, routeTree, meta, section}: PageProps) { 'max-w-7xl mx-auto', section === 'blog' && 'lg:flex lg:flex-col lg:items-center' )}> - {children} + + + {children} + + {!isBlogIndex && ( ; + +export const LanguagesContext = createContext(null); diff --git a/src/components/MDX/MDXComponents.tsx b/src/components/MDX/MDXComponents.tsx index 8344f97701e..dbdd984aeed 100644 --- a/src/components/MDX/MDXComponents.tsx +++ b/src/components/MDX/MDXComponents.tsx @@ -30,6 +30,8 @@ import ButtonLink from 'components/ButtonLink'; import {TocContext} from './TocContext'; import type {Toc, TocItem} from './TocContext'; import {TeamMember} from './TeamMember'; +import {LanguagesContext} from './LanguagesContext'; +import {deployedTranslations} from 'utils/deployedTranslations'; function CodeStep({children, step}: {children: any; step: number}) { return ( @@ -357,6 +359,36 @@ function InlineTocItem({items}: {items: Array}) { ); } +function LanguageList({showTranslated}: {showTranslated: boolean}) { + const allLanguages = React.useContext(LanguagesContext) ?? []; + const languages = allLanguages + .filter( + ({code}) => + code !== 'en' && + (showTranslated + ? deployedTranslations.includes(code) + : !deployedTranslations.includes(code)) + ) + .sort((a, b) => a.enName.localeCompare(b.enName)); + return ( +
    + {languages.map(({code, name, enName}) => { + return ( +
  • + + {enName} ({name}) + {' '} + —{' '} + + Contribute + +
  • + ); + })} +
+ ); +} + function YouTubeIframe(props: any) { return (
@@ -417,6 +449,7 @@ export const MDXComponents = { IllustrationBlock, Intro, InlineToc, + LanguageList, LearnMore, Math, MathI, diff --git a/src/components/Seo.tsx b/src/components/Seo.tsx index 79f19f87cc4..3d85b029ce7 100644 --- a/src/components/Seo.tsx +++ b/src/components/Seo.tsx @@ -6,6 +6,7 @@ import * as React from 'react'; import Head from 'next/head'; import {withRouter, Router} from 'next/router'; import {siteConfig} from '../siteConfig'; +import {deployedTranslations} from 'utils/deployedTranslations'; export interface SeoProps { title: string; @@ -17,16 +18,8 @@ export interface SeoProps { searchOrder?: number; } -const deployedTranslations = [ - 'en', - 'zh-hans', - 'es', - 'fr', - 'ja', - // We'll add more languages when they have enough content. - // Please DO NOT edit this list without a discussion in the reactjs/react.dev repo. - // It must be the same between all translations. -]; +// If you are a maintainer of a language fork, +// deployedTranslations has been moved to src/utils/deployedTranslations.ts. function getDomain(languageCode: string): string { const subdomain = languageCode === 'en' ? '' : languageCode + '.'; diff --git a/src/content/community/translations.md b/src/content/community/translations.md new file mode 100644 index 00000000000..8b9431348d3 --- /dev/null +++ b/src/content/community/translations.md @@ -0,0 +1,25 @@ +--- +title: Translations +--- + + + +React docs are translated by the global community into many languages all over the world. + + + +## Translated languages {/*translated-languages*/} + +{/* If you are a language maintainer and want to add your language here, finish the "Core" translations and edit `deployedTranslations` under `src/utils`. */} + + + +## Languages undergoing translation work {/*languages-undergoing-translation-work*/} + +The list below includes languages with a significant amount of completed translation as well as those with little to no progress. The translation progress for each language is being tracked in [Is React Translated Yet?](https://translations.react.dev/) + + + +## How to contribute {/*how-to-contribute*/} + +You can contribute to the translation efforts! The community conducts the translation work for the React docs on each language-specific fork of react.dev. Typical translation work involves directly translating a Markdown file and creating a pull request. Visit the GitHub repository for your language, and follow the instructions there or contact one of the maintainers. \ No newline at end of file diff --git a/src/pages/[[...markdownPath]].js b/src/pages/[[...markdownPath]].js index d1df93d3c98..62bcf9efc0a 100644 --- a/src/pages/[[...markdownPath]].js +++ b/src/pages/[[...markdownPath]].js @@ -11,8 +11,9 @@ import sidebarLearn from '../sidebarLearn.json'; import sidebarReference from '../sidebarReference.json'; import sidebarCommunity from '../sidebarCommunity.json'; import sidebarBlog from '../sidebarBlog.json'; +import {deployedTranslations} from '../utils/deployedTranslations'; -export default function Layout({content, toc, meta}) { +export default function Layout({content, toc, meta, languages}) { const parsedContent = useMemo( () => JSON.parse(content, reviveNodeOnClient), [content] @@ -39,7 +40,12 @@ export default function Layout({content, toc, meta}) { break; } return ( - + {parsedContent} ); @@ -96,7 +102,7 @@ function reviveNodeOnClient(key, val) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~ IMPORTANT: BUMP THIS IF YOU CHANGE ANY CODE BELOW ~~~ -const DISK_CACHE_BREAKER = 7; +const DISK_CACHE_BREAKER = 8; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Put MDX output into JSON for client. @@ -118,6 +124,17 @@ export async function getStaticProps(context) { mdx = fs.readFileSync(rootDir + path + '/index.md', 'utf8'); } + // Conditionally retrieve deployed languages from GitHub. + let languages = null; + if (path.endsWith('/translations')) { + console.log('Retrieving list of languages from GitHub'); + languages = await ( + await fetch( + 'https://raw.githubusercontent.com/reactjs/translations.react.dev/main/langs/langs.json' + ) + ).json(); // { code: string; name: string; enName: string}[] + } + // See if we have a cached output first. const {FileStore, stableHash} = require('metro-cache'); const store = new FileStore({ @@ -130,6 +147,8 @@ export async function getStaticProps(context) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ mdx, mdxComponentNames, + languages, + deployedTranslations: languages ? deployedTranslations : {}, DISK_CACHE_BREAKER, PREPARE_MDX_CACHE_BREAKER, lockfile: fs.readFileSync(process.cwd() + '/yarn.lock', 'utf8'), @@ -221,6 +240,7 @@ export async function getStaticProps(context) { content: JSON.stringify(children, stringifyNodeOnServer), toc: JSON.stringify(toc, stringifyNodeOnServer), meta, + languages, }, }; diff --git a/src/sidebarCommunity.json b/src/sidebarCommunity.json index 6b3e4eca35c..ac8a172d5f3 100644 --- a/src/sidebarCommunity.json +++ b/src/sidebarCommunity.json @@ -31,6 +31,10 @@ "title": "Docs Contributors", "path": "/community/docs-contributors" }, + { + "title": "Translations", + "path": "/community/translations" + }, { "title": "Acknowledgements", "path": "/community/acknowledgements" diff --git a/src/utils/deployedTranslations.ts b/src/utils/deployedTranslations.ts new file mode 100644 index 00000000000..7bb48ef0be1 --- /dev/null +++ b/src/utils/deployedTranslations.ts @@ -0,0 +1,7 @@ +// This is a list of languages with enough translated content. +// Add more languages here when they have enough content. +// Please DO NOT edit this list without a discussion in the reactjs/react.dev repo. +// It must be the same between all translations. +// This will also affect the 'Translations' article. + +export const deployedTranslations = ['en', 'zh-hans', 'es', 'fr', 'ja']; From 6c5f9132dc3aa0aad1c5552b4af58c17c8a45867 Mon Sep 17 00:00:00 2001 From: Soichiro Miki Date: Wed, 25 Oct 2023 17:26:47 +0900 Subject: [PATCH 2/8] Add "languages" button in TopNav --- src/components/Layout/TopNav/TopNav.tsx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/components/Layout/TopNav/TopNav.tsx b/src/components/Layout/TopNav/TopNav.tsx index 75995957082..bdef4d2cfc0 100644 --- a/src/components/Layout/TopNav/TopNav.tsx +++ b/src/components/Layout/TopNav/TopNav.tsx @@ -77,6 +77,19 @@ const lightIcon = ( ); +const languageIcon = ( + + + +); + const githubIcon = (
+
+ + {languageIcon} + +
Date: Wed, 25 Oct 2023 18:27:13 +0900 Subject: [PATCH 3/8] Add link to English (main) site --- src/content/community/translations.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/content/community/translations.md b/src/content/community/translations.md index 8b9431348d3..57fd8b1edf0 100644 --- a/src/content/community/translations.md +++ b/src/content/community/translations.md @@ -8,6 +8,10 @@ React docs are translated by the global community into many languages all over t +## Main site {/*main-site*/} + +- [English](https://react.dev/) — [Contribute](https://github.com/reactjs/react.dev/) + ## Translated languages {/*translated-languages*/} {/* If you are a language maintainer and want to add your language here, finish the "Core" translations and edit `deployedTranslations` under `src/utils`. */} From 4853f7b14d3ae5c98f9e384bb28f95e1b298ae82 Mon Sep 17 00:00:00 2001 From: Soichiro Miki Date: Wed, 25 Oct 2023 22:02:40 +0900 Subject: [PATCH 4/8] Split deployedTranslations into multiple lines --- src/utils/deployedTranslations.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/utils/deployedTranslations.ts b/src/utils/deployedTranslations.ts index 7bb48ef0be1..26ad4eea280 100644 --- a/src/utils/deployedTranslations.ts +++ b/src/utils/deployedTranslations.ts @@ -4,4 +4,11 @@ // It must be the same between all translations. // This will also affect the 'Translations' article. -export const deployedTranslations = ['en', 'zh-hans', 'es', 'fr', 'ja']; +// prettier-ignore +export const deployedTranslations = [ + 'en', + 'zh-hans', + 'es', + 'fr', + 'ja', +]; From 6c69b702a090df3871046f9bad2b3af1c1815157 Mon Sep 17 00:00:00 2001 From: Soichiro Miki Date: Wed, 17 Apr 2024 12:17:27 +0900 Subject: [PATCH 5/8] Fix build error regarding types --- src/components/Layout/Page.tsx | 4 ++-- src/utils/compileMDX.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Layout/Page.tsx b/src/components/Layout/Page.tsx index 24c43065de9..9f81c7a4178 100644 --- a/src/components/Layout/Page.tsx +++ b/src/components/Layout/Page.tsx @@ -36,7 +36,7 @@ interface PageProps { description?: string; }; section: 'learn' | 'reference' | 'community' | 'blog' | 'home' | 'unknown'; - languages: Languages | null; + languages?: Languages | null; } export function Page({ @@ -45,7 +45,7 @@ export function Page({ routeTree, meta, section, - languages, + languages = null, }: PageProps) { const {asPath} = useRouter(); const cleanedPath = asPath.split(/[\?\#]/)[0]; diff --git a/src/utils/compileMDX.ts b/src/utils/compileMDX.ts index 2ebe1f2c9df..4c5ee15b72a 100644 --- a/src/utils/compileMDX.ts +++ b/src/utils/compileMDX.ts @@ -1,3 +1,4 @@ +import {LanguageItem} from 'components/MDX/LanguagesContext'; import {MDXComponents} from 'components/MDX/MDXComponents'; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -125,14 +126,13 @@ export default async function compileMDX( const meta = fm(mdx).data; // Load the list of translated languages conditionally. - let languages: Array<{code: string; name: string; enName: string}> = []; + let languages: Array | null = null; if (typeof path === 'string' && path.endsWith('/translations')) { languages = await ( await fetch( 'https://raw.githubusercontent.com/reactjs/translations.react.dev/main/langs/langs.json' ) ).json(); // { code: string; name: string; enName: string}[] - meta.languages = languages; } const output = { From 85004260d09a52729ea1a3022027328482f51d09 Mon Sep 17 00:00:00 2001 From: Soichiro Miki Date: Thu, 2 May 2024 00:50:22 +0900 Subject: [PATCH 6/8] Address some review comments - deployedTranslations => finishedTranslations - showTranslated => progress - English fixes --- src/components/MDX/MDXComponents.tsx | 12 +++++++----- src/components/Seo.tsx | 6 +++--- src/content/community/translations.md | 12 ++++++------ ...ployedTranslations.ts => finishedTranslations.ts} | 2 +- 4 files changed, 17 insertions(+), 15 deletions(-) rename src/utils/{deployedTranslations.ts => finishedTranslations.ts} (90%) diff --git a/src/components/MDX/MDXComponents.tsx b/src/components/MDX/MDXComponents.tsx index b68f923e8ea..6f99121f7f8 100644 --- a/src/components/MDX/MDXComponents.tsx +++ b/src/components/MDX/MDXComponents.tsx @@ -32,7 +32,7 @@ import {TocContext} from './TocContext'; import type {Toc, TocItem} from './TocContext'; import {TeamMember} from './TeamMember'; import {LanguagesContext} from './LanguagesContext'; -import {deployedTranslations} from 'utils/deployedTranslations'; +import {finishedTranslations} from 'utils/finishedTranslations'; import ErrorDecoder from './ErrorDecoder'; import {IconCanary} from '../Icon/IconCanary'; @@ -382,15 +382,17 @@ function InlineTocItem({items}: {items: Array}) { ); } -function LanguageList({showTranslated}: {showTranslated: boolean}) { +type TranslationProgress = 'complete' | 'in-progress'; + +function LanguageList({progress}: {progress: TranslationProgress}) { const allLanguages = React.useContext(LanguagesContext) ?? []; const languages = allLanguages .filter( ({code}) => code !== 'en' && - (showTranslated - ? deployedTranslations.includes(code) - : !deployedTranslations.includes(code)) + (progress === 'complete' + ? finishedTranslations.includes(code) + : !finishedTranslations.includes(code)) ) .sort((a, b) => a.enName.localeCompare(b.enName)); return ( diff --git a/src/components/Seo.tsx b/src/components/Seo.tsx index 6f4bd32d5e9..628085744d7 100644 --- a/src/components/Seo.tsx +++ b/src/components/Seo.tsx @@ -6,7 +6,7 @@ import * as React from 'react'; import Head from 'next/head'; import {withRouter, Router} from 'next/router'; import {siteConfig} from '../siteConfig'; -import {deployedTranslations} from 'utils/deployedTranslations'; +import {finishedTranslations} from 'utils/finishedTranslations'; export interface SeoProps { title: string; @@ -20,7 +20,7 @@ export interface SeoProps { } // If you are a maintainer of a language fork, -// deployedTranslations has been moved to src/utils/deployedTranslations.ts. +// deployedTranslations has been moved to src/utils/finishedTranslations.ts. function getDomain(languageCode: string): string { const subdomain = languageCode === 'en' ? '' : languageCode + '.'; @@ -63,7 +63,7 @@ export const Seo = withRouter( href={canonicalUrl.replace(siteDomain, getDomain('en'))} hrefLang="x-default" /> - {deployedTranslations.map((languageCode) => ( + {finishedTranslations.map((languageCode) => ( + -## Languages undergoing translation work {/*languages-undergoing-translation-work*/} +## In-progress translations {/*in-progress-translations*/} -The list below includes languages with a significant amount of completed translation as well as those with little to no progress. The translation progress for each language is being tracked in [Is React Translated Yet?](https://translations.react.dev/) +For the progress of each translation, see: [Is React Translated Yet?](https://translations.react.dev/) - + ## How to contribute {/*how-to-contribute*/} -You can contribute to the translation efforts! The community conducts the translation work for the React docs on each language-specific fork of react.dev. Typical translation work involves directly translating a Markdown file and creating a pull request. Visit the GitHub repository for your language, and follow the instructions there or contact one of the maintainers. \ No newline at end of file +You can contribute to the translation efforts! The community conducts the translation work for the React docs on each language-specific fork of react.dev. Typical translation work involves directly translating a Markdown file and creating a pull request. Visit the GitHub repository for your language, and follow the instructions there or contact one of the maintainers. If you want to start a new translation for your language, visit: [translations.react.dev](https://github.com/reactjs/translations.react.dev) \ No newline at end of file diff --git a/src/utils/deployedTranslations.ts b/src/utils/finishedTranslations.ts similarity index 90% rename from src/utils/deployedTranslations.ts rename to src/utils/finishedTranslations.ts index 3c713f6b7bb..b2aceb17273 100644 --- a/src/utils/deployedTranslations.ts +++ b/src/utils/finishedTranslations.ts @@ -5,7 +5,7 @@ // This will also affect the 'Translations' article. // prettier-ignore -export const deployedTranslations = [ +export const finishedTranslations = [ 'en', 'zh-hans', 'es', From 139bedf914ed91cbb0b5037318a4e4ce1695ddab Mon Sep 17 00:00:00 2001 From: Soichiro Miki Date: Thu, 2 May 2024 01:10:28 +0900 Subject: [PATCH 7/8] Update src/content/community/translations.md Co-authored-by: Ricky --- src/content/community/translations.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/content/community/translations.md b/src/content/community/translations.md index 2a34cc46ad2..a94e7dbec3a 100644 --- a/src/content/community/translations.md +++ b/src/content/community/translations.md @@ -26,4 +26,8 @@ For the progress of each translation, see: [Is React Translated Yet?](https://tr ## How to contribute {/*how-to-contribute*/} -You can contribute to the translation efforts! The community conducts the translation work for the React docs on each language-specific fork of react.dev. Typical translation work involves directly translating a Markdown file and creating a pull request. Visit the GitHub repository for your language, and follow the instructions there or contact one of the maintainers. If you want to start a new translation for your language, visit: [translations.react.dev](https://github.com/reactjs/translations.react.dev) \ No newline at end of file +You can contribute to the translation efforts! + +The community conducts the translation work for the React docs on each language-specific fork of react.dev. Typical translation work involves directly translating a Markdown file and creating a pull request. Click the "contribute" link above to the GitHub repository for your language, and follow the instructions there to help with the translation effort. + +If you want to start a new translation for your language, visit: [translations.react.dev](https://github.com/reactjs/translations.react.dev) \ No newline at end of file From 437776bca0ea03c620d5f6ff1a2566f854205baf Mon Sep 17 00:00:00 2001 From: Ricky Date: Wed, 1 May 2024 12:28:35 -0400 Subject: [PATCH 8/8] Update src/content/community/translations.md --- src/content/community/translations.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/content/community/translations.md b/src/content/community/translations.md index a94e7dbec3a..4c07e6a1ea2 100644 --- a/src/content/community/translations.md +++ b/src/content/community/translations.md @@ -8,7 +8,9 @@ React docs are translated by the global community into many languages all over t -## Main site {/*main-site*/} +## Source site {/*main-site*/} + +All translations are provided from the canonical source docs: - [English](https://react.dev/) — [Contribute](https://github.com/reactjs/react.dev/)