Skip to content

Commit

Permalink
feat(www): Pull in translated gatsby docs (ENABLE_LOCALIZATIONS env v…
Browse files Browse the repository at this point in the history
…ar needed) (#20637)

* add spanish files to source

* disable spanish for now

* add spanish again

* aksldjasdf

* get everything working

* display spanish and portuguese pages

* get all the links working!

* a few more fixes

* simplify

* whats gatsby-cli doing here

* i18n util file

* update site metadata

* disable translations by default

* explain how to enable localizations in readme

* add more languages
  • Loading branch information
tesseralis authored Jan 22, 2020
1 parent 3815740 commit 56bc2b1
Show file tree
Hide file tree
Showing 16 changed files with 139 additions and 30 deletions.
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 [email protected]"
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
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 }) => {
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

0 comments on commit 56bc2b1

Please sign in to comment.