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

feat(www): Pull in translated gatsby docs (ENABLE_LOCALIZATIONS env var needed) #20637

Merged
merged 18 commits into from
Jan 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions www/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ ANALYTICS_SERVICE_ACCOUNT="service account@email.com"
ANALYTICS_SERVICE_ACCOUNT_KEY="PEM KEY VALUE"
```

### Enabling localizations

Localizations are currently a work-in-progress and are thus disabled by default. They can be enabled by setting the `ENABLE_LOCALIZATIONS` env variable:

```shell
ENABLE_LOCALIZATIONS=true
```

There is currently no UI to link to the localizations, so you'll have to type in the name of the file you want to go to using the language code (e.g. /es/tutorial/part-one).

## Running slow build? (Screenshots placeholder)

If you are not working on a starter or site showcase, it might be beneficial to use a placeholder image instead of actual screenshots. It will skip downloading screenshots and generating responsive images for all screenshots and replace them with a placeholder image.
Expand Down
15 changes: 15 additions & 0 deletions www/gatsby-config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const path = require(`path`)
const langs = require(`./i18n.json`)
require(`dotenv`).config({
path: `.env.${process.env.NODE_ENV}`,
})
Expand Down Expand Up @@ -52,6 +53,20 @@ if (process.env.AIRTABLE_API_KEY) {
})
}

if (process.env.ENABLE_LOCALIZATIONS) {
dynamicPlugins.push(
...langs.map(({ code }) => ({
resolve: `gatsby-source-git`,
options: {
name: `docs-${code}`,
remote: `https://github.com/gatsbyjs/gatsby-${code}.git`,
branch: `master`,
patterns: `docs/tutorial/**`,
},
}))
)
}

module.exports = {
siteMetadata: {
title: `GatsbyJS`,
Expand Down
49 changes: 34 additions & 15 deletions www/gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ const parseGHUrl = require(`parse-github-url`)
const { GraphQLClient } = require(`@jamo/graphql-request`)
const moment = require(`moment`)
const startersRedirects = require(`./starter-redirects.json`)
const langs = require("./i18n.json")
const {
generateComparisonPageSet,
} = require(`./src/utils/generate-comparison-page-set.js`)
const { localizedPath } = require(`./src/utils/i18n.js`)
const yaml = require(`js-yaml`)
const docLinksData = yaml.load(
fs.readFileSync(`./src/data/sidebars/doc-links.yaml`)
Expand Down Expand Up @@ -58,6 +60,16 @@ const slugToAnchor = slug =>
.filter(item => item !== ``) // remove empty values
.pop() // take last item

const docSlugFromPath = parsedFilePath => {
if (parsedFilePath.name !== `index` && parsedFilePath.dir !== ``) {
return `/${parsedFilePath.dir}/${parsedFilePath.name}/`
} else if (parsedFilePath.dir === ``) {
return `/${parsedFilePath.name}/`
} else {
return `/${parsedFilePath.dir}/`
}
}

exports.createPages = ({ graphql, actions, reporter }) => {
const { createPage, createRedirect } = actions

Expand Down Expand Up @@ -109,6 +121,7 @@ exports.createPages = ({ graphql, actions, reporter }) => {
node {
fields {
slug
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might end up causing confusion since here, "slug = path without locale".

Copy link
Contributor

@LekoArts LekoArts Jan 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess in the interim phase we have to live with that, once we have all parts of the site we could make a localizedSlug or localize the slug

locale
package
released
}
Expand Down Expand Up @@ -399,6 +412,7 @@ exports.createPages = ({ graphql, actions, reporter }) => {

docPages.forEach(({ node }) => {
const slug = _.get(node, `fields.slug`)
const locale = _.get(node, `fields.locale`)
if (!slug) return

if (!_.includes(slug, `/blog/`)) {
Expand Down Expand Up @@ -444,12 +458,13 @@ exports.createPages = ({ graphql, actions, reporter }) => {
}

createPage({
path: `${node.fields.slug}`, // required
path: localizedPath(locale, node.fields.slug),
component: slash(
node.fields.package ? localPackageTemplate : docsTemplate
),
context: {
slug: node.fields.slug,
locale,
...nextAndPrev,
},
})
Expand Down Expand Up @@ -509,16 +524,12 @@ exports.createPages = ({ graphql, actions, reporter }) => {
exports.onCreateNode = ({ node, actions, getNode, reporter }) => {
const { createNodeField } = actions
let slug
let locale
if (node.internal.type === `File`) {
const parsedFilePath = path.parse(node.relativePath)
// TODO add locale data for non-MDX files
if (node.sourceInstanceName === `docs`) {
if (parsedFilePath.name !== `index` && parsedFilePath.dir !== ``) {
slug = `/${parsedFilePath.dir}/${parsedFilePath.name}/`
} else if (parsedFilePath.dir === ``) {
slug = `/${parsedFilePath.name}/`
} else {
slug = `/${parsedFilePath.dir}/`
}
slug = docSlugFromPath(parsedFilePath)
}
if (slug) {
createNodeField({ node, name: `slug`, value: slug })
Expand All @@ -531,13 +542,8 @@ exports.onCreateNode = ({ node, actions, getNode, reporter }) => {
const parsedFilePath = path.parse(fileNode.relativePath)
// Add slugs for docs pages
if (fileNode.sourceInstanceName === `docs`) {
if (parsedFilePath.name !== `index` && parsedFilePath.dir !== ``) {
slug = `/${parsedFilePath.dir}/${parsedFilePath.name}/`
} else if (parsedFilePath.dir === ``) {
slug = `/${parsedFilePath.name}/`
} else {
slug = `/${parsedFilePath.dir}/`
}
slug = docSlugFromPath(parsedFilePath)
locale = "en"

// Set released status and `published at` for blog posts.
if (_.includes(parsedFilePath.dir, `blog`)) {
Expand All @@ -560,6 +566,16 @@ exports.onCreateNode = ({ node, actions, getNode, reporter }) => {
})
}
}

for (let { code } of langs) {
if (fileNode.sourceInstanceName === `docs-${code}`) {
// have to remove the beginning "/docs" path because of the way
// gatsby-source-filesystem and gatsby-source-git differ
slug = docSlugFromPath(path.parse(fileNode.relativePath.substring(5)))
locale = code
}
}

// Add slugs for package READMEs.
if (
fileNode.sourceInstanceName === `packages` &&
Expand All @@ -577,6 +593,9 @@ exports.onCreateNode = ({ node, actions, getNode, reporter }) => {
createNodeField({ node, name: `anchor`, value: slugToAnchor(slug) })
createNodeField({ node, name: `slug`, value: slug })
}
if (locale) {
createNodeField({ node, name: `locale`, value: locale })
}
} else if (node.internal.type === `AuthorYaml`) {
slug = `/contributors/${slugify(node.id, {
lower: true,
Expand Down
7 changes: 7 additions & 0 deletions www/i18n.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{ "code": "es", "name": "Spanish" },
{ "code": "id", "name": "Indonesian" },
{ "code": "pl", "name": "Polish" },
{ "code": "pt-BR", "name": "Brazilian Portuguese" },
{ "code": "zh-Hans", "name": "Simplified Chinese" }
]
1 change: 1 addition & 0 deletions www/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"gatsby-remark-smartypants": "^2.1.17",
"gatsby-source-airtable": "^2.0.12",
"gatsby-source-filesystem": "^2.1.40",
"gatsby-source-git": "^1.0.2",
"gatsby-source-npm-package-search": "^2.1.19",
"gatsby-transformer-csv": "^2.1.19",
"gatsby-transformer-documentationjs": "^4.1.20",
Expand Down
2 changes: 1 addition & 1 deletion www/src/components/docs-breadcrumb.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @jsx jsx */
import { jsx } from "theme-ui"
import React from "react"
import { Link } from "gatsby"
import Link from "./localized-link"
import ChevronRight from "react-icons/lib/md/chevron-right"
import ChevronLeft from "react-icons/lib/md/chevron-left"
import getActiveItem from "../utils/sidebar/get-active-item"
Expand Down
12 changes: 9 additions & 3 deletions www/src/components/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ import SiteMetadata from "../components/site-metadata"
import SkipNavLink from "../components/skip-nav-link"
import "../assets/fonts/futura"
import LazyModal from "./lazy-modal"
import { defaultLang } from "../utils/i18n"

let windowWidth

export const LocaleContext = React.createContext(defaultLang)

class DefaultLayout extends React.Component {
constructor() {
super()
Expand Down Expand Up @@ -165,9 +168,12 @@ class DefaultLayout extends React.Component {
}

return (
<>
<LocaleContext.Provider value={this.props.locale || defaultLang}>
<Global styles={globalStyles} />
<SiteMetadata pathname={this.props.location.pathname} />
<SiteMetadata
pathname={this.props.location.pathname}
locale={this.props.locale}
/>
<SkipNavLink />
<Banner />
<Navigation pathname={this.props.location.pathname} />
Expand All @@ -194,7 +200,7 @@ class DefaultLayout extends React.Component {
/>
</div>
<MobileNavigation />
</>
</LocaleContext.Provider>
)
}
}
Expand Down
13 changes: 13 additions & 0 deletions www/src/components/localized-link.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from "react"
import { Link } from "gatsby"
import { LocaleContext } from "./layout"
import { localizedPath } from "../utils/i18n"

// Use the globally available context to choose the right path
const LocalizedLink = ({ to, ...props }) => {
const locale = React.useContext(LocaleContext)

return <Link {...props} to={localizedPath(locale, to)} />
}

export default LocalizedLink
15 changes: 15 additions & 0 deletions www/src/components/mdx-link.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react"
import LocalizedLink from "./localized-link"

const isHash = str => /^#/.test(str)
const isInternal = to => /^\/(?!\/)/.test(to)

// Only use <LocalizedLink /> for internal links
const MdxLink = ({ href, ...props }) =>
isHash(href) || !isInternal(href) ? (
<a {...props} href={href} />
) : (
<LocalizedLink {...props} to={href} />
)

export default MdxLink
2 changes: 1 addition & 1 deletion www/src/components/navigation.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/** @jsx jsx */
import { jsx } from "theme-ui"
import { useColorMode } from "theme-ui"
import { Link } from "gatsby"
import GithubIcon from "react-icons/lib/go/mark-github"
import TwitterIcon from "react-icons/lib/fa/twitter"

import Link from "../components/localized-link"
import SearchForm from "../components/search-form"
import DiscordIcon from "../components/discord"
import logo from "../assets/logo.svg"
Expand Down
2 changes: 1 addition & 1 deletion www/src/components/prev-and-next.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** @jsx jsx */
import { jsx } from "theme-ui"
import { Link } from "gatsby"
import Link from "./localized-link"
import ArrowForwardIcon from "react-icons/lib/md/arrow-forward"
import ArrowBackIcon from "react-icons/lib/md/arrow-back"

Expand Down
6 changes: 3 additions & 3 deletions www/src/components/site-metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { graphql, useStaticQuery } from "gatsby"

import gatsbyIcon from "../assets/gatsby-icon.png"

const SiteMetadata = ({ pathname }) => {
const SiteMetadata = ({ pathname, locale }) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it better to pull in context or pass the locale down? SiteMetadata is so far only used in Layout

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the current setup I don't think it'll make a difference. I would consider using Context if the component e.g. would be used in MDX (for ease of use).

const {
site: {
siteMetadata: { siteUrl, title, twitter },
Expand All @@ -23,7 +23,7 @@ const SiteMetadata = ({ pathname }) => {

return (
<Helmet defer={false} defaultTitle={title} titleTemplate={`%s | ${title}`}>
<html lang="en" />
<html lang={locale} />
<link rel="canonical" href={`${siteUrl}${pathname}`} />
<meta name="docsearch:version" content="2.0" />
<meta
Expand All @@ -33,7 +33,7 @@ const SiteMetadata = ({ pathname }) => {

<meta property="og:url" content={siteUrl} />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en" />
<meta property="og:locale" content={locale} />
<meta property="og:site_name" content={title} />
<meta property="og:image" content={`${siteUrl}${gatsbyIcon}`} />
<meta property="og:image:width" content="512" />
Expand Down
2 changes: 2 additions & 0 deletions www/src/gatsby-plugin-theme-ui/components.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import LayerModel from "../components/layer-model"
import EmailCaptureForm from "../components/email-capture-form"
import HorizontalNavList from "../components/horizontal-nav-list"
import CodeBlock from "../components/code-block"
import MdxLink from "../components/mdx-link"

export default {
GuideList,
Expand All @@ -19,5 +20,6 @@ export default {
LayerModel,
EmailCaptureForm,
HorizontalNavList,
a: MdxLink,
pre: ({ children }) => <CodeBlock>{children}</CodeBlock>,
}
12 changes: 7 additions & 5 deletions www/src/templates/template-docs-markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ const containerStyles = {
px: 9,
}

const getDocsData = location => {
const [urlSegment] = location.pathname.split(`/`).slice(1)
const getDocsData = slug => {
const [urlSegment] = slug.split(`/`).slice(1)
const itemListLookup = {
docs: itemListDocs,
contributing: itemListContributing,
Expand All @@ -44,7 +44,7 @@ const getDocsData = location => {

function DocsTemplate({ data, location, pageContext: { next, prev } }) {
const page = data.mdx
const [urlSegment, itemList] = getDocsData(location)
const [urlSegment, itemList] = getDocsData(page.fields.slug)
const toc =
!page.frontmatter.disableTableOfContents && page.tableOfContents.items

Expand All @@ -62,6 +62,7 @@ function DocsTemplate({ data, location, pageContext: { next, prev } }) {
</Helmet>
<Layout
location={location}
locale={page.fields.locale}
itemList={itemList}
enableScrollSync={urlSegment === `docs` ? false : true}
>
Expand Down Expand Up @@ -149,14 +150,15 @@ function DocsTemplate({ data, location, pageContext: { next, prev } }) {
export default DocsTemplate

export const pageQuery = graphql`
query($path: String!) {
mdx(fields: { slug: { eq: $path } }) {
query($slug: String!, $locale: String!) {
mdx(fields: { slug: { eq: $slug }, locale: { eq: $locale } }) {
body
excerpt
timeToRead
tableOfContents
fields {
slug
locale
anchor
}
frontmatter {
Expand Down
19 changes: 19 additions & 0 deletions www/src/utils/i18n.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const defaultLang = "en"

function isDefaultLang(locale) {
return locale === defaultLang
}

function localizedPath(locale, path) {
const isIndex = path === `/`

// TODO generalize this to other paths
const isLocalized = !isDefaultLang(locale) && path.startsWith("/tutorial/")
// If it's the default language, don't do anything
// If it's another language, add the "path"
// However, if the homepage/index page is linked don't add the "to"
// Because otherwise this would add a trailing slash
return isLocalized ? `${locale}${isIndex ? `` : `${path}`}` : path
}

module.exports = { defaultLang, localizedPath }
2 changes: 1 addition & 1 deletion www/src/utils/sidebar/create-link.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** @jsx jsx */
import { jsx } from "theme-ui"
import { Link } from "gatsby"
import Link from "../../components/localized-link"

import indention from "../../utils/sidebar/indention"

Expand Down