【问题标题】:How to query markdown files of a specific language in Gatsby?如何在 Gatsby 中查询特定语言的 markdown 文件?
【发布时间】:2020-04-16 14:38:54
【问题描述】:

我有一个文件夹content/projects,其中包含以下方式的文件:

  • project-a.de.md
  • project-a.en.md
  • project-b.de.md
  • project-b.en.md

现在我如何构建一个组件来显示其中的一些项目,这些项目在其frontmatter 中有featured 标志并且是特定语言的?

我创建了以下组件:

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

这可行,但我必须在 TypeScript 中过滤当前语言(我通过 React 上下文),尽管我认为这是 GraphQL 查询的完美任务,因为它是为选择事物而设计的。

很遗憾,我不能在静态查询中使用变量。您将如何实现这一目标?

Tl;博士

我尝试使用变量创建查询,但 graphql 标记中不允许使用字符串插值。

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

【问题讨论】:

    标签: reactjs typescript graphql gatsby


    【解决方案1】:

    我过去解决这个问题的方法是查询我可能需要的所有数据(在这种情况下,任何语言的所有特色项目),然后使用 JS 根据当前语言环境进行过滤。这有在客户端加载更多数据的缺点,但不会影响静态呈现的 HTML 页面大小。

    我使用的另一种方法是使用createPage API 将每种语言作为上下文传递,然后将其作为变量提供给您的查询,然后以每种语言简单地呈现每个页面并更改 URL在它们之间切换(即使用 Gatsby 的navigate)。这很好用,但您确实需要设计一种方法来确定每种语言的 URL,但无论如何您可能也会将其用于您的 rel="alternate" 链接。

    【讨论】:

    • 感谢您花时间回答我。我理解您描述的方法,但我认为它不太适合我的问题。我正在尝试在页面中显示选定的项目列表。假设页面应该列出最后 5 个项目,这些项目有英文版本。我不确定它是否适用于您描述的方法,或者我不知道如何。
    • @Robin 为此,我真的会使用客户端过滤。唯一的其他策略是使用一组静态查询,然后有条件地渲染特定于语言的组件,或者从构建中提取原始查询结果数据并在选择语言时动态重新注入(这对于场景来说太过分了你在)。
    • 很遗憾,这么简单的事情似乎这么难。用户不会经常更改语言,因此他们中的大多数人会获得太多数据,例如所有可用语言的特色项目以及所有其他类似元素。我将 Gatsby 理解为一个静态页面生成器,通过“客户端过滤”我们摆脱了这一原则。
    • @Robin 有什么替代方案?您正在构建一组静态 HTML 文件,这些文件由 nginx 等典型 Web 服务器提供服务。没有服务器端运行时,因此无法根据前端输入的变化动态执行 GraphQL 查询。
    • 我明白这一点,这就是我想要的。仅包含一种语言内容的静态文件。 Gatsby 应该为特定语言生成一个页面,其中包含一些特定于语言的降价文件,其中包含项目。我不明白为什么我需要客户端过滤。
    【解决方案2】:

    看来string interpolation isn't supported - 太糟糕了!

    您可以使用gatsby-plugin-pathdatalang 字段添加到您的节点。

    gatsby-config,在插件部分添加

    {
      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"
          }
        ]
      }
    },
    

    这会将field.lang 添加到您的所有降价文件中 - 这些字段也可用于过滤。

    有了这个,您可以使用带有变量的查询来选择文件

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

    可能还有其他方法可以得到这个。

    希望对你有帮助!

    【讨论】:

    • 感谢您抽出宝贵时间回答我的问题。这是你建议的一个有趣的插件,但我不明白我为什么需要它。如上所述,我可以使用 RegEx 实现相同的目的。您建议远离静态查询。我不知道如何通过正常查询在一个页面中收集所有特色项目?也许您可以将我指向文档。我真的被困在这里了。
    • 我认为您必须使用带参数的查询才能仅获取具有所需语言的文件 - 我不知道有任何方法可以将参数传递给静态查询。我错过了这应该是一个静态查询的要求。为什么是插件?我不能在正则表达式中使用查询参数。这可能有点过度工程:)
    • 您不需要额外的插件来执行此操作,但 bamse 是正确的,您目前无法将参数传递给静态查询。 Gatsby 无论如何都无法在客户端运行查询,因此它不可能提前知道您的组件需要哪些数据。 @coreyward 已经在他的评论中分享了可能的解决方案stackoverflow.com/questions/59486966/…
    猜你喜欢
    • 2019-06-12
    • 2019-12-14
    • 1970-01-01
    • 2020-07-29
    • 1970-01-01
    • 2018-11-14
    • 2020-10-17
    • 2019-10-15
    • 1970-01-01
    相关资源
    最近更新 更多