Skip to content
Permalink
Browse files

feat: add multi-language post support

  • Loading branch information
kitos committed Oct 3, 2019
1 parent e2cb8c0 commit 14c638032e74fda2d9893cb16225861837d90b80
@@ -27,7 +27,7 @@ module.exports = {
'gatsby-plugin-twitter',
{
resolve: 'gatsby-plugin-netlify-cache',
options: { extraDirsToCache: ['./public/images'] },
options: { extraDirsToCache: ['public/static'] },
},
rssPlugin,
{
@@ -11,3 +11,9 @@
from = "/game-of-life/"
to = "https://kitos.github.io/game-of-life/"
status = 200


[[redirects]]
from = "/blog/*"
to = "/en/blog/:splat"
status = 200

Some generated files are not rendered by default. Learn more.

@@ -36,15 +36,15 @@
"intersection-observer": "^0.5.1",
"lodash.intersection": "^4.4.0",
"netlify-cms-app": "^2.9.7",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react": "^16.10.1",
"react-dom": "^16.10.1",
"react-helmet": "^5.2.1",
"react-popper": "^1.3.4",
"react-spring": "^7.2.11",
"react-typography": "^0.16.19",
"reason-react": "^0.7.0",
"sanitize-html": "^1.20.1",
"styled-components": "^5.0.0-beta.8-groupsizefix",
"styled-components": "^5.0.0-beta.9",
"typography": "^0.16.19",
"typography-theme-github": "^0.15.10"
},
@@ -83,6 +83,7 @@
"gatsby-remark-responsive-iframe": "^2.2.16",
"gatsby-transformer-remark": "^2.6.22",
"gh-pages": "^2.1.1",
"lodash.groupby": "^4.6.0",
"prettier": "^1.18.2",
"prismjs": "^1.17.1",
"standard-version": "^4.4.0"
@@ -1,4 +1,4 @@
import React, { useContext, useEffect, useState } from 'react'
import React, { useContext, useState } from 'react'
import styled from 'styled-components/macro'
import { Flex } from '@rebass/grid'
import { Manager } from 'react-popper'
@@ -6,6 +6,7 @@ import { format } from 'date-fns/fp'

import BlogTags from './blog-tags'
import { media } from '../../utils'
import { buildPostLink, langToEmoji } from './utils'

let DateWithTimeline = styled.small`
position: relative;
@@ -41,27 +42,37 @@ let DateWithTimeline = styled.small`
let formatDate = d => format('MMMM dd, yyyy', new Date(d))

let BlogPostSnippet = ({
post: { slug, title, lang, date, preface, timeToRead, tags },
post: { slug, title, lang, date, preface, timeToRead, tags, translations },
selectedTag,
}) => (
<Flex as="section" alignItems="stretch">
<DateWithTimeline>{formatDate(date)}</DateWithTimeline>

<Box pl={[0, 20]}>
<h2>
<Link to={`/blog/${slug}/`}>{title}</Link>
<Link to={buildPostLink({ slug, lang })}>{title}</Link>
</h2>

<small>
<span
role="img"
title={
lang === 'en' ? 'Available in English' : 'Available in Russian'
}
>
{lang === 'en' ? '🇬🇧' : '🇷🇺'}
</span>
{timeToRead} min read{' '}
<Flex alignItems="center">
{translations.map(lang => (
<Link
to={buildPostLink({ slug, lang })}
style={{ textDecoration: 'none', fontSize: 16 }}
>
<span
key={lang}
role="img"
title={lang === 'en' ? 'Read in English' : 'Read in Russian'}
>
{langToEmoji(lang)}
</span>
</Link>
))}

<Box ml={2}>{timeToRead} min read </Box>
</Flex>

<span css={media.tablet`display: none;`}>{formatDate(date)}</span>
</small>

@@ -0,0 +1,3 @@
export let langToEmoji = lang => (lang === 'en' ? '🇬🇧' : '🇷🇺')

export let buildPostLink = ({ slug, lang }) => `/${lang}/blog/${slug}/`
@@ -1,5 +1,6 @@
const path = require('path')
const intersection = require('lodash.intersection')
const groupBy = require('lodash.groupby')

let groupPostsByTag = posts =>
posts.reduce(
@@ -24,7 +25,7 @@ let getSimilarPost = ({ slug, tags }, posts) =>
.slice(0, 3)
.map(({ id }) => id)

module.exports = ({ graphql, actions: { createPage } }) =>
module.exports = ({ graphql, actions: { createPage, createRedirect } }) =>
graphql(`
{
posts: allMarkdownRemark(
@@ -35,6 +36,7 @@ module.exports = ({ graphql, actions: { createPage } }) =>
id
frontmatter {
slug
lang
date
tags
}
@@ -57,20 +59,28 @@ module.exports = ({ graphql, actions: { createPage } }) =>
)

// create blog post pages
posts.forEach(post =>
posts.forEach(post => {
let { id, lang, slug } = post

createPage({
path: `/blog/${post.slug}/`,
path: `/${lang}/blog/${slug}/`,
component: path.resolve('./src/templates/blog-post.js'),
context: {
id: post.id,
id,
slug,
similarPosts: getSimilarPost(post, posts),
},
})
)
})

let postMapsByLang = Object.values(groupBy(posts, 'slug')).map(posts => ({
...(posts.find(({ lang }) => lang === 'en') || posts[0]),
tags: [...new Set(posts.flatMap(({ tags }) => tags))],
}))

let postsByTag = groupPostsByTag(posts)
let postsByTag = groupPostsByTag(postMapsByLang)

postsByTag.set('', posts)
postsByTag.set('', postMapsByLang)

// create blog tag root pages
postsByTag.forEach((posts, tag) =>
@@ -79,7 +89,7 @@ module.exports = ({ graphql, actions: { createPage } }) =>
component: path.resolve('./src/templates/blog-post-list.js'),
context: {
tag,
ids: posts.map(({ id }) => id),
slugs: posts.map(({ slug }) => slug),
},
})
)
@@ -1,44 +1,54 @@
import React from 'react'
import { graphql } from 'gatsby'
import groupBy from 'lodash.groupby'
import { Box } from '@rebass/grid'
import VisuallyHidden from '@reach/visually-hidden'

import { BlogPostSnippet } from '../components/blog'
import { SEO } from '../components'

let BlogPage = ({ pageContext: { tag }, data: { posts } }) => (
<>
<SEO title="Blog" />

<VisuallyHidden>
<h2>Blog</h2>
</VisuallyHidden>

<Box mt={10}>
{posts.edges.length === 0 ? (
<Box as="b" style={{ display: 'block', textAlign: 'center' }}>
Some posts might be here...
</Box>
) : (
posts.edges
.map(({ node: { id, frontmatter, ...post } }) => ({
...frontmatter,
...post,
}))
.map(post => (
let BlogPage = ({ pageContext: { tag }, data: { posts } }) => {
posts = posts.edges.map(({ node: { frontmatter, ...post } }) => ({
...frontmatter,
...post,
}))

let unknowns = Object.values(groupBy(posts, 'slug'))

let gropedPosts = unknowns.map(posts => ({
...(posts.find(({ lang }) => lang === 'en') || posts[0]),
translations: posts.map(({ lang }) => lang),
}))

return (
<>
<SEO title="Blog" />

<VisuallyHidden>
<h2>Blog</h2>
</VisuallyHidden>

<Box mt={10}>
{posts.length === 0 ? (
<Box as="b" style={{ display: 'block', textAlign: 'center' }}>
Some posts might be here...
</Box>
) : (
gropedPosts.map(post => (
<BlogPostSnippet key={post.slug} post={post} selectedTag={tag} />
))
)}
</Box>
</>
)
)}
</Box>
</>
)
}

export default BlogPage

export const pageQuery = graphql`
query BlogPostList($ids: [String!]!) {
query BlogPostList($slugs: [String!]!) {
posts: allMarkdownRemark(
filter: { id: { in: $ids } }
filter: { frontmatter: { slug: { in: $slugs } } }
sort: { fields: frontmatter___date, order: DESC }
) {
edges {

0 comments on commit 14c6380

Please sign in to comment.
You can’t perform that action at this time.