hygraph / gatsby-source-graphcms

The official Gatsby source plugin for GraphCMS projects
https://graphcms.com
MIT License
145 stars 41 forks source link

Localization should enable passing a default/fallback language #164

Closed irenama closed 3 years ago

irenama commented 3 years ago

I ran into this problem when querying images for my localized project, though I think it is a general issue with how gatsby-source-graphcms queries localized content.

On GraphCMS images are localized per default, although it doesn't often make sense to actually upload two images (en/de). This brings me to my current issue:

As English is the default language I would like to fall back to the English content, if there is no translated content for de. As far as I can see, it's not possible to pass an array of locales: [de, en] like in the general GraphCMS documentation (and like I did before) but only filter by one distinct language. Through this, I am missing a lot of e.g images on the queries for the German translation.

de en
Bildschirmfoto 2021-02-10 um 09 11 39 Bildschirmfoto 2021-02-10 um 09 11 52

Am I missing something here or is this not possible to fallback/query the default language with the package yet? If so is there a way around it? Thanks in advance for clarifying! 🙂

ynnoj commented 3 years ago

@irenama Thanks for trying out the library.

Unfortunately the behaviour you're seeing is indeed expected. The nature of Gatsby's GraphQL layer makes it difficult for the library to implement the fallback pattern you see with your GraphCMS API.

However there are ways to achieve what you're looking to do using Gatsby APIs. You can add a custom resolver for the image field on the crossLinks type to add a locale field argument. Something like:

exports.createResolvers = ({ createResolvers }) => {
  const resolvers = {
    GraphCMS_CrossLink: {
      images: {
        args: {
          locale: {
            type: 'GraphCMS_Locale!',
            defaultValue: 'en',
          },
        },
        resolve: async ({ remoteTypeName, remoteId }, args, context, _) => {
          const toGatsbyId = (remoteId) => Object.values(remoteId).join(`:`)

         // Find the `en` node for this `CrossLink` entry
          const enCrossLinkNode = context.nodeModel.getNodeById({
            id: toGatsbyId({ remoteTypeName, remoteId, locale: args.locale }),
          })

         // Map over the related images on the `en` node to build an array of ids
          const imageGatsbyIds = enCrossLinkNode.images.map(
            (remoteImageIdFields) => toGatsbyId(remoteImageIdFields)
          )

          // Lookup localised nodes for `images`
          return context.nodeModel.getNodesByIds({ ids: imageGatsbyIds })
        },
      },
    },
  }

  createResolvers(resolvers)
}

This can be then used in queries:

{
  allGraphCmsPage(filter: { locale: { eq: de } }) {
    nodes {
      id
      locale
      sections {
        ... on GraphCMS_ServicesSection {
          id
          crossLink {
            images(locale: en) {
              id
            }
          }
        }      
      }
    }
  }
}

This example works where images is an array (multiple values), but can be easily adapted to fit a single relation.

Hope this helps!

irenama commented 3 years ago

Thanks for the detailed answer! Unfortunately, introducing custom resolvers would be an overhead for this project having a lot of nested 'sections' with images and the like. If it may help someone searching in a similar direction: I think I need to keep using gatsby-source-graphl for that specific localized project. Still, I'm happy to use this package in another upcoming project with currently no localization. Thank you for your work!

ynnoj commented 3 years ago

There are both trade offs and benefits to using this library over gatsby-source-graphql. It's just about determining the right fit for your project. Unfortunately there's no 'one size fits all' because of the nature of Gatsby's GraphQL layer.

There might be some future API/product improvements which making working with localised assets better. Right now it's not a great experience to have to re-upload the actual asset for any localised versions. I'll relay your feedback.

Will close this issue, but feel free to re-open if you need 👍

TarekMowafy commented 3 years ago

Hello @irenama , i came across a similar challenge and i was wondering how did grasby-source-graphql resolve the null assets issue?

irenama commented 3 years ago

Hi @TarekMowafy ! The project, that I tested gatsby-source-graphcms for, was already using gatsby-source-graphql: with that all queries could fall back to a provided default locale, like so

page(locales: [$locale, en]) {
    ...PageFields
}

So that's convenient/straightforward: No missing content (though maybe mixed language). :) The reason why I checked out gatsby-source-graphcms though, is that the Gatsby image magic (local, static/fluid images) does not come out of the box that way round. One would need to write a custom resolver for the assets to make use of that. Hope this helps!