datocms / gatsby-source-datocms

Official GatsbyJS source plugin to pull content from DatoCMS
MIT License
140 stars 50 forks source link

Fetching all locales of the record #221

Closed hrumhurum closed 1 year ago

hrumhurum commented 1 year ago

Currently there is a way to fetch all locales of the field:

query {
  allBlogPosts {
    _allTitleLocales {
      locale
      value
    }
  }
}

But how to fetch all locales of the record? Something like this would be helpful:

query {
  _allBlogPostLocales {
      locale
      title
      slug
      ...
  }
}

With gatsby-source-datocms version 4.x it was possible to achieve this with:

query {
  allDatoCmsBlogPosts {
    nodes {
      locale
      title
      slug
      ...
    }
  }
}

but this approach no longer works in gatsby-source-datocms 5.x.

stefanoverna commented 1 year ago

On our native CDA we have _locales. We should add it to the Gatsby plugin as well!

hrumhurum commented 1 year ago

I am aware of _locales. But what I'm trying to achieve is to avoid manual iteration through locales one by one. Instead, I want to retrieve all localized records in bulk with a single GraphQL query.

I am porting an existing project and that functionality no longer works in gatsby-source-datocms 5.x, but it worked in gatsby-source-datocms 4.x:

const data = useStaticQuery(graphql`
  query LanguageSwitcherData {
    allSitePage {
      pageNodes: nodes {
        path
        pageContext
      }
    }

    allDatoCmsBlogRoot {
      nodes {
        slug
        chiefEditor {
           lastActionDate
        }
        locale
      }
    }

    allDatoCmsLocalization {
      nodes {
        displayName
        urlPrefix
        locale
      }
    }
  }
`);

For example, allDatoCmsBlogRoot returned all records and their locales without filtering in 4.x. In 5.x, it only returns records for the default locale. 5.x also does not understand locale field.

To me, it looks like a regression because the code should be changed to an unknown alternative.

Is there any way to achieve that with gatsby-source-datocms 5.x?

stefanoverna commented 1 year ago

In 5.x, it only returns records for the default locale

It actually returns one node per record, instead of one node per record per locale. That was a needed change because on big Gatsby projects, the performance losses were huge.

For overall clarity, we also decided to align what the Gatsby plugin offers to our CDA, so let's put it this way:

  1. Given what our CDA offers in terms of querying capabilities, would you be able to achieve what you need? https://www.datocms.com/docs/content-delivery-api/localization
  2. Is something you need available in CDA, but it's not available in Gatsby?
hrumhurum commented 1 year ago

I don't see a way to achieve the desired result using a single GraphQL query given the existing capabilities of CDA. Only by manual iteration or by manual composition of the resulting objects from the field pieces retrieved by https://www.datocms.com/docs/content-delivery-api/localization#fetching-all-localizations, which is quite a challenge to be honest.

stefanoverna commented 1 year ago

With CDA, this would work right?

query {
  itBlogPosts: allBlogPosts(filter: {_locales: {allIn: [it]}}, locale: it) {
    title
  }
  enBlogPosts: allBlogPosts(filter: {_locales: {allIn: [en]}}, locale: en) {
    title
  }
  ...
}
hrumhurum commented 1 year ago

Right, that would work if one hardcodes the locales beforehand. However, this approach is only a hacky workaround. For the time being, I reverted the project to gatsby-source-datocms v4.0.5 to avoid the situation altogether until something better becomes available.

souljuse commented 1 year ago

But how to fetch all locales of the record?

As Stefano was pointing out. You can fetch all locales in a record by this by using locale. It returns an array of locales used in the record. For example if you run this query

query {
  localesQuery: allDatoCmsBlogPosts {
    nodes {
      locales
    }
  }
}

Will result in

  "data": {
    "localesQuery": {
      "nodes": [
        {
          "locales": [
            "en",
          ],
        },
      ],
    },

You can also get all localized content for a certain locale by using filters.

query {
  itBlogPosts: allBlogPosts(filter: {locales: {in: ["it"]}}, locale: "it") {
    title
  }
}
  "data": {
    "itResults": {
      "nodes": [
        {
          "title": "Italian title",
        },
      ],
    },
  },
}

this approach is only a hacky workaround

We know it is not ideal, but for the moment we prefer to keep it coherent with the CDA :) Sorry for the inconvenience.