Locale Handling

You can specify a locale via the locale argument on collections, single entities, and entry fields:

1query {
2 germanUser: friendlyUser(id: "hans", locale: "de-DE") {
3 name
4 }
5
6 americanUser: friendlyUser(id: "joe", locale: "en-US")
7}

If you don’t specify a locale, the default locale of the space is used.

Unlike the CDA, the GraphQL Content API does not support the locale wildcard.

This argument cascades, meaning that all the references resolved from a resource with locale: "de-DE" will also show German content unless explicitly overridden. So for example the root level could use a different locale than a sub resource. When changing the locale on references, only the referenced entities are resolved with this locale. The reference field value itself is still resolved with the locale of the parent:

1query {
2 germanUser: friendlyUser(id: "hans", locale: "de-DE") {
3 name
4 germanPetsInFrench: petsCollection(locale: "fr-FR") {
5 items {
6 name
7 }
8 }
9 }
10}

Individual fields can also have a locale specified, giving the ability to fetch the same field in multiple locales using query aliases:

1query {
2 germanUser: friendlyUser(id: "hans", locale: "de-DE") {
3 name
4 petsCollection {
5 items {
6 name
7 nameInFrench: name(locale: "fr-FR")
8 }
9 }
10 }
11}

If the requested locale does not exist, an UNKNOWN_LOCALE error is returned for this path.

Locale-based publishing

Use the X-Contentful-Locale-Based-Publishing request header to opt in to locale-based publishing.

$curl -g \
> -X POST \
> -H "Authorization: Bearer $TOKEN" \
> -H "Content-Type: application/json" \
> -H "X-Contentful-Locale-Based-Publishing: true" \
> -d '{"query":"{ entryCollection(locale: \"de-DE\") { items { sys { id } } } }"}' \
> "https://graphql.contentful.com/content/v1/spaces/$SPACE/environments/$ENV"

When this header is present, only locales that are published will be returned. Publishing status is determined from entry.sys.fieldStatus in the Content Management API.

The header doesn’t apply to Content Preview API. The CPA silently ignores it and returns content regardless of locale publishing status.

Behavior

  • Entries that were published before locale-based publishing was introduced are returned regardless of this header.

  • For entry-level publishing, enabling this header doesn’t change the existing response behavior — the content will be returned as previously without the header.

  • Fallback locales are not used to determine publishing status, but only for content resolution. If a requested locale is unpublished, a published fallback locale doesn’t make it visible in the response.

  • When a locale is added to a space, affected entries must be republished before that locale appears in CDA responses. Republish the locale where locale-based publishing is available, or republish the entry for entry-level publishing.

Locale-based publishing behavior is opt-in during rollout. Contentful plans to enable it by default, so we recommend adopting and testing this header before the default behavior changes.

Example: query unpublished and published locales

The following examples assume a space with a blog content type. The content type generates the single resource field blog in the GraphQL schema and has slug and title fields. In this space, entry1 is not published in de-DE, and entry2 is published in en-US.

Fetching an unpublished locale for entry1 returns null:

$curl -g \
> -X POST \
> -H "Content-Type: application/json" \
> -H "Authorization: Bearer {access_token}" \
> -H "X-Contentful-Locale-Based-Publishing: true" \
> -d '{"query":"query { blog(id: \"entry1\", locale: \"de-DE\") { slug title } }"}' \
> "https://graphql.contentful.com/content/v1/spaces/{space_id}/environments/{environment_id}"
1HTTP/1.1 200 OK
1{
2 "data": {
3 "blog": null
4 }
5}

Fetching a published locale for entry2 returns the entry:

$curl -g \
> -X POST \
> -H "Content-Type: application/json" \
> -H "Authorization: Bearer {access_token}" \
> -H "X-Contentful-Locale-Based-Publishing: true" \
> -d '{"query":"query { blog(id: \"entry2\", locale: \"en-US\") { slug title } }"}' \
> "https://graphql.contentful.com/content/v1/spaces/{space_id}/environments/{environment_id}"
1HTTP/1.1 200 OK
1{
2 "data": {
3 "blog": {
4 "slug": "category-page",
5 "title": "Category page"
6 }
7 }
8}

Disabling locale fallback

By default, when you request content for a specific locale and a field value isn’t available in that locale, the GraphQL API returns the value from the fallback locale, if one exists.

You can control this behavior with the useFallbackLocale argument, available on collections, single entities, and entry fields:

1query {
2 blogPostCollection(locale: "de-DE", useFallbackLocale: false) {
3 items {
4 title
5 description
6 }
7 }
8}

Set useFallbackLocale to false to return null for fields without a value in the requested locale, instead of defaulting to the fallback locale.

The argument can be applied at different levels:

Collection level:

1query {
2 blogPostCollection(locale: "fr-FR", useFallbackLocale: false) {
3 items {
4 title
5 slug
6 }
7 }
8}

Single entity level:

1query {
2 blogPost(id: "123", locale: "es-ES", useFallbackLocale: false) {
3 title
4 description
5 }
6}

Field level:

1query {
2 blogPost(id: "123", locale: "de-DE") {
3 title(useFallbackLocale: false)
4 description
5 }
6}

Note: If not specified, useFallbackLocale defaults to true, maintaining the standard fallback behavior.