GithubHelp home page GithubHelp logo

Comments (6)

sgulseth avatar sgulseth commented on May 27, 2024 1

Hi! This is is a tricky feature because of the dynamic nature of GROQ. Given the look up attribute[$param] it's impossible to parse the query correctly without knowing the type of $param. If $param is a string it's an attribute access(object), if it's a number it's an element access(array), and by default it's a filter. Since we rely on the GROQ javascript parser we would need to know the value of $param while parsing, which we don't at the moment

from sanity.

obrassard avatar obrassard commented on May 27, 2024

I have the same issue, this could be very useful for field level translations !

from sanity.

Qocotzxin avatar Qocotzxin commented on May 27, 2024

Similar to this, the following query generates isCurrentLanguage: unknown:
"toasts": toasts[]->{"isCurrentLanguage": language == $language, code, title, content},

While if I use a string literal instead, the type is correctly generated as isCurrentLanguage: string:
"toasts": toasts[]->{"isCurrentLanguage": language == "en", code, title, content},

I also noticed while debugging this query that when using the parent accessor, the type results in Array<never>:
"toasts": *[_type == "toast" && language == $language && _id in ^.toasts[]{_ref}._ref]{code, heading, content, language}

In all these cases queries correctly work and bring the expected results.

from sanity.

obrassard avatar obrassard commented on May 27, 2024

One workaround I tried was to take my initial query with $lang parameters and create a new "localized query" by replacing all references to [$lang] with .en. I thought this would work and then I'd be able to use the type generated for the localized query in the code.

import groq from 'groq';

const fullWidthTextBlockFragment = `
_type == 'module.fullWidthTextBlock' => {
    _key,
    _type,
    "title": title[$lang],
    "body": body[$lang],
}
`;

const SanityProductModulesQuery = groq`
*[_type == 'product' && store.slug.current == $handle][0] {
  modules[] {
    ${fullWidthTextBlockFragment},
  }
}`;

const LocalizedProductModulesQuery = groq`
${SanityProductModulesQuery.replaceAll('[$lang]', '.en')}
`;

⚠️ However it seems the Groq parser does not (yet?) allow those kind of expressions :

✖ Unsupported expression type: MemberExpression in ../app/groq/product.localized.ts:22:4
 ⚠ Encountered errors in 1 files while generating types


  • I think it would be nice to allow membreExpression and other function calls to be used with sanity codegen
  • Even better, it would be awesome if we could pass parameters directly when defining the query (parameters that would be use only for code generation. Something like :
groq(`
*[_type == 'product' && store.slug.current == $handle][0] {
  _type == 'module.fullWidthTextBlock' => {
    "title": title[$lang],
    "body": body[$lang],
  }
}`,
  {
    lang: 'en',
  },
);
  • Else if we know that all fields of a given objet are the same type, for instance body : { fr: string; en: string } I think it would be safe to assume that body[$something] returns a string (or null)

from sanity.

Qocotzxin avatar Qocotzxin commented on May 27, 2024

It would be nice being able to at least define parameters in JSDoc (or similar) format for this feature work:

/**
* @param language {string}
*/
const someQuery = groq`
*[_type == 'someType' && language == $language] {...}
`;

This approach might not be enough to unblock the usage of typed fragments though, which would be ideal.

from sanity.

maxijonson avatar maxijonson commented on May 27, 2024

As a workaround, you could try to use select instead of body[$locale]

export const testQuery = groq`
  *[_type == "localizedDocument"][0] {
    "body": select(
        $locale == "en" => body.en,
        $locale == "fr" => body.fr,
    )
  }
`;

The resulting type of body is as you expected:

export type TestQueryResult = {
  body: string | null;
} | null;

However, this is inconvenient, because you always need to specify this selection. You could create a simple utility that reduces the burden of writing it. However, do not map over your supportedLanguges to generate these selections. I've found that TypeGen throws an error when you do: ✖ Unsupported expression type: MemberExpression in sanity/schemas/documents/test.ts:48:6 in "sanity/schemas/documents/test.ts"

export const selectLocalizedString = (field: string) =>
  `select(
    $locale == "en" => ${field}.en,
    $locale == "fr" => ${field}.fr,
)`;

// ⚠ Does not work with TypeGen
// export const selectLocalizedString = (field: string) =>
//   `select(
//     ${supportedLanguages.map((lang) => `$locale == "${lang}" => ${field}.${lang},`).join("\n")}
// )`;

export const testQuery = groq`
  *[_type == "localizedDocument"][0] {
    "body": ${selectLocalizedString("body")}
  }
`;

Here's the full final file I used to reproduce your issue and find a working solution:

import { groq } from "next-sanity";
import { defineField, defineType } from "sanity";

const supportedLanguages = ["en", "fr"] as const;

export const localizedString = defineType({
  title: "Localized string",
  name: "localizedString",
  type: "object",
  fields: supportedLanguages.map((lang) => ({
    title: lang,
    name: lang,
    type: "string",
  })),
});

export default defineType({
  name: "localizedDocument",
  title: "Localized Document",
  type: "document",
  fields: [
    defineField({
      name: "body",
      title: "Body",
      type: localizedString.name,
      validation: (rule) => rule.required(),
    }),
  ],
});

// export const testQuery = groq`
//   *[_type == "localizedDocument"][0] {
//     "body": select(
//         $locale == "en" => body.en,
//         $locale == "fr" => body.fr,
//     )
//   }
// `;

export const selectLocalizedString = (field: string) =>
  `select(
    $locale == "en" => ${field}.en,
    $locale == "fr" => ${field}.fr,
)`;

// ⚠ Does not work with TypeGen
// export const selectLocalizedString = (field: string) =>
//   `select(
//     ${supportedLanguages.map((lang) => `$locale == "${lang}" => ${field}.${lang},`).join("\n")}
// )`;

export const testQuery = groq`
  *[_type == "localizedDocument"][0] {
    "body": ${selectLocalizedString("body")}
  }
`;

from sanity.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.