Translating content with the API

This guide explains how to use the GraphQL Admin API to create and retrieve translated content for Shopify resources. For example, you might add translations of product information and email notification templates so a merchant can send customers email notifications in multiple languages.

Translation access scopes

To use the GraphQL Admin API to create or retrieve translated content, your app needs to request the read_translations and write_translations access scopes for a Shopify store. For more information on requesting access scopes when your app is installed, see OAuth.

Translatable resource types

The following resource types and fields are translatable:

Type Fields
Collection title, body_html, meta_title, meta_description
Email template title, body_html
Link title
Metafields (buyer facing only) value
Online store article title, body_html, summary_html, meta_title, meta_description
Online store blog title, meta_title, meta_description
Online store page title, body_html, meta_title, meta_description
Online store theme dynamic keys based on theme data
Payment gateway name
Product title, body_html, meta_title, meta_description
Product option name
Product variant title, option 1, option 2, option 3
Shop meta_title, meta_description
Shop policy body
SMS template body

Retrieve a list of translatable resource types

TranslatableResourceType contains a list of the resource types that are translatable. You can use the following query to list each of those types:

Query

{
  __type(name: "TranslatableResourceType") {
    enumValues {
      name
    }
  }
}

Response

{
  "data": {
    "__type": {
      "enumValues": [
        {
          "name": "PRODUCT"
        },
        {
          "name": "PRODUCT_VARIANT"
        },
        ...
      ]
    }
  }
}

Retrieving translations

You can use the translateableResources connection to retrieve a list of translatable resources, their translatable content, and their existing translations in various languages. You can also retrieve all translations for a locale, regardless of resource type.

Retrieve a list of translatable resources by their type

The following query retrieves a list of translatable resources that are products. For each product, the query retrieves the content that can be translated in the translatableContent field.

Query

{
  translatableResources(first: 10, resourceType: PRODUCT) {
    edges {
      node {
        resourceId
        translatableContent {
          key
          value
          locale
        }
      }
    }
  }
}

Response

{
  "translatableResources": {
    "edges": [
      {
        "node": {
          "resourceId": "gid://shopify/Product/1",
          "translatableContent": [
            {
              "key": "title",
              "value": "White T-Shirt",
              "locale": "en-US"
            },
            {
                "key": "body_html",
                "value": "A classic white crew neck t-shirt made from 100% cotton.",
                "locale": "en-US"
              },
            ...
          ]
        }
      },
      ...
    ]
  }
}

The response shows that the White T-Shirt product with the ID "gid://shopify/Product/1" has content that can be translated, including its title and body HTML.

The key field associates translatable content with its translations. The value field shows the translatable content itself. When you create a translation, the mutation needs to include the translatableContent field, which needs to match the value field shown here. For more information, see Creating translations

Retrieve translations for a resource type and locale

Like the example above, this query retrieves a list of products and their translatable content. This query also includes the translations field for each product, which retrieves any existing translations.

The field takes the argument locale, which specifies the language of the translations to retrieve. In the following example, the language is Spanish.

Query

{
  translatableResources(first:10, resourceType: PRODUCT) {
    edges {
      node {
        resourceId
        translatableContent {
          key
          value
          locale
        }
        translations(locale: "es-ES"){
          locale
          key
          value
        }
      }
    }
  }
}

Response

{
  "data" {
    "translatableResources": {
      "edges": [
        {
          "node": {
            "resourceId": "gid://shopify/Product/1",
            "translatableContent": [
              {
                "key": "title",
                "value": "White T-Shirt",
                "locale": "en-US"
              },
              ...
            ],
            "translations": [
              {
                "locale": "es-ES",
                "key": "title",
                "value": "Camiseta blanca"
              },
              ...
            ]
          }
        },
        ...
      ]
    }
  }
}

Retrieve a single translatable resource by its ID

The following query retrieves a single translatable resource by passing its ID in the resourceId argument.

Query

{
  translatableResource(resourceId: "gid://shopify/Product/1") {
    resourceId
    translatableContent {
      key
      value
      locale
    }
    translations(locale: "ja") {
      key
      value
      locale
    }
  }
}

Response

{
  "data": {
    "translatableResource": {
       "resourceId": "gid://shopify/Product/1",
       "translatableContent": [
          {
             "key": "title",
             "value": "White T-Shirt",
             "locale": "en-US",
          },
          ...
       ],
       "translations": [
          {
             "key": "title",
             "value": "漢字灯はりらこ不議",
             "locale": "ja",
          },
          ...
       ]
    }
  }
}

Retrieve translations from a resource object

If your app only needs to read translations, then you can query translations directly from a translatable resource object.

Query

query {
  products(first: 1) {
    edges {
      node{
        id,
        title,
        translations(locale: "ja") {
          key,
          locale,
          value
        }
      }
    }
  }
}

Response

{
  "data": {
    "products": {
      "edges": [
        {
          "node": {
            "id": "gid://shopify/Product/355272313",
            "title": "Aiguisoir à crayon en métal cuivré, avion bi-plane, hélice mobile. Hong Kong SAR China",
            "translations": [
              {
                "key": "title",
                "locale": "ja",
                "value": "is a Chang 深 漢 漢 点 語 議 議 議 議 非 非, 非Hili Okore core -. of the Kyoragi, Oh é Honsukyoko et al. Kyo思A this Akarikori思non-Tomo"
              }
            ]
          }
        }
      ]
    }
  }
}

Creating translations

GraphQL uses mutations to create, update, or delete data in a database. Mutations do the equivalent function of the REST data-modifying action verbs, such as POST, PUT, and DELETE.

You can use the translationsRegister mutation to create new translations for a resource. When you create a translation, you need to include the original content in the translatableContent field. For example, to create a translation for the title of the White T-Shirt product from the queries above, the mutation would need to include translatableContent: "White T-Shirt". The translated content is provided in the value field.

Variables

{
  "id": "gid://shopify/Product/1",
  "translations": [
    {
      "key": "title",
      "value": "Camiseta blanca",
      "locale": "es-ES",
      "translatableContent": "White T-Shirt"
    }
  ]
}

Mutation

mutation CreateTranslation($id: ID!, $translations: [TranslationInput!]!) {
  translationsRegister(resourceId: $id, translations: $translations) {
    userErrors {
      message
      field
    }
    translations {
      locale
      key
      value
    }
  }
}

Response

{
  "data": {
    "translationsRegister": {
      "userErrors": [],
      "translations": [
        {
          "locale": "es-ES",
          "key": "title",
          "value": "Camiseta buena"
        }
      ]
    }
  }
}

If the untranslated content doesn't match the original content on the resource, then the mutation fails. In the following example, the mutation sets the value of translatableContent to "White tee shirt" instead of "White T-Shirt", so the mutation fails.

{
  "id": "gid://shopify/Product/1",
  "translations": [
    {
      "key": "title",
      "value": "Camiseta blanca",
      "locale": "es-ES",
      "translatableContent": "White tee shirt"
    }
  ]
}

Mutation

mutation CreateTranslation($id: ID!, $translations: [TranslationInput!]!) {
  translationsRegister(resourceId: $id, translations: $translations) {
    userErrors {
      message
      field
    }
    translations {
      locale
      key
      value
    }
  }
}

Response

{
  "data": {
    "translationsRegister": {
      "userErrors": [
        {
          "message": "Translatable content hash is invalid",
          "field": [
            "translations",
            "0",
            "translatableContent"
          ]
        }
      ],
      "translations": null
    }
  }
}

Mutation errors

The following table shows codes and descriptions for errors that you might see when you create translations:

Error message Description
RESOURCE_NOT_FOUND A resource with the specified ID doesn't exist.
TOO_MANY_KEYS_FOR_RESOURCE There are too many translation keys for the resource. You can include up to 100 translation keys per mutation.
INVALID_KEY_FOR_MODEL The key provided for the translation is invalid.
FAILS_RESOURCE_VALIDATION The value for the translation is invalid.
INVALID_TRANSLATABLE_CONTENT The translatable content doesn't match the original content on the resource.
INVALID_CODE The language code is invalid.
INVALID_FORMAT The locale code is invalid.

Removing translations

You can use the translationsRemove mutation to remove translations from a resource. In the following example, the Spanish and Japanese title translations are removed from the product with the ID "gid://shopify/Product/1".

Variables

{
    "id": "gid://shopify/Product/1",
    "keys": [
        "title"
    ],
    "locales": [
        "es-ES",
        "ja-JP"
    ]
}

Mutation

mutation RemoveTranslations($id: ID!, $keys: [String!]!, $locales: [String!]!) {
  translationsRemove(
    resourceId: $id,
    translationKeys: $keys,
    locales: $locales
  ) {
    userErrors {
      message
      field
    }
    translations {
      locale
      key
      value
    }
  }
}

Response

{
  "data": {
    "translationsRemove": {
      "userErrors": [],
      "translations": [
        {
          "locale": "es-ES",
          "key": "title",
          "value": "Camiseta blanca",
        },
        {
          "locale": "es-ES",
          "key": "body_html",
          "value": "Camiseta blanca",
        },
      ]
    }
  }
}

Limitations

The following are known translation limitations:

  • A resource's tags field cannot be translated. For example, you can't translate a product's tags.
  • Email and SMS notification template fields cannot be translated (unless you edit the default template content).
  • The handle field is not returned in the translation response for menu links and templates for email and SMS notifications.
  • You can translate metafields only if they are publicly accessible.

Sign up for a Partner account to get started.

Sign up