Robin
Robin

Reputation: 8498

How to query markdown files of a specific language in Gatsby?

I've a folder content/projects with files in the following manner:

Now how could I build a component which display some of this projects, who have the featured flag in their frontmatter and are of a specific language?

I've created the following component:

import React from 'react'
import { FormattedMessage } from 'react-intl'
import { useStaticQuery, graphql } from 'gatsby'
import Content from '../Content'
import { FeaturedProjectsQuery } from '../../../graphql-types'

const FeaturedProjects: React.FC = () => {
  const projects = useStaticQuery<FeaturedProjectsQuery>(graphql`
    query FeaturedProjects {
      allMarkdownRemark(filter: { fileAbsolutePath: { regex: "/(content/projects)/" }, frontmatter: { featured: { eq: true } } }) {
        nodes {
          frontmatter {
            title
          }
        }
      }
    }
  `)

  return (
    <Content>
      <h2>
        <FormattedMessage id="navigation.projects" />
      </h2>
      {projects.allMarkdownRemark.nodes.map(p => {
        return <div>{p.frontmatter?.title}</div>
      })}
    </Content>
  )
}

export default FeaturedProjects

This works, but I would have to filter for the current language (which I get over a React context) within TypeScript, even though I think it's the perfect task for the GraphQL query, because it's made for selecting things.

Unfortunately I cannot use variables in the static query. How would you achieve that?

Tl;dr

I've tried to create the query with a variable, but string interpolation is not allowed in graphql tag.

... 
allMarkdownRemark(filter: { fileAbsolutePath: {
 regex: `/(content/projects).*\\.${lang}\\.md$/` ...
}
...

String interpolation is forbidden

Upvotes: 3

Views: 1323

Answers (2)

coreyward
coreyward

Reputation: 80041

The way I've tackled this in the past is to query for all of the data that I might need (in this case, all featured projects of any language), and then use JS to filter based on the current locale. This has the downside of loading a bit more data client-side, but it won't impact the statically rendered HTML page size.

Another approach I've used is to use the createPage API to pass in each language as context, which is then available to your query as a variable, then to simply render each page in each language and to change the URL to switch between them (i.e. using Gatsby's navigate). This works well, but you do need to devise a way to determine the URL for each language, but you probably will use that for your rel="alternate" links as well anyways.

Upvotes: 2

bamse
bamse

Reputation: 4373

It seems string interpolation isn't supported - too bad!

You could use gatsby-plugin-pathdata to add a lang field to your nodes.

In gatsby-config, in the plugins section add

{
  resolve: "gatsby-plugin-pathdata",
  options: {
    matchNodeType: "MarkdownRemark",
    extract: [
      {
        name: "lang",
         // Regex isn't my strong suit so the `selector` might need some work
         // This matches any 2 lower case letter, between 2 dots, followed by 
         // the `md` extension 
         // ====================
         // ex:  for `/path/to/the/file/project-b.de.md`, the `lang` field
         // will be `de`
        selector: /.+\/.*([a-z][a-z])+\.md$/, 
        replacer: "$1"
      }
    ]
  }
},

This adds a field.lang to all your markdown files - and the fields can also be used for filtering.

With that in place you can use a query with a variable to select the files

query MyQuery($lang: String) {
  allMarkdownRemark(filter: {fields: {lang: {eq: $lang}}}) {
    nodes {
      frontmatter {
        title
      }
    }
  }
}

There are probably other ways to get this.

Hope it helps!

Upvotes: 4

Related Questions