# General Translation Integrations: Traducir productos de Shopify
URL: https://generaltranslation.com/es/docs/integrations/shopify/guides/translating-products.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: Cómo traducir el contenido de los productos de Shopify con General Translation y almacenarlo en Shopify o incluirlo en el paquete de tu tienda.

Los títulos, las descripciones y las opciones de los productos provienen de Shopify, no de tu código, así que `gt-react` y `gt-next` no los traducen. Tradúcelos una sola vez y sírvelos desde uno de estos dos lugares.

## Qué usar y cuándo [#choosing]

* **Almacena las traducciones en Shopify** si los comerciantes editan el catálogo con frecuencia. Un script registra las traducciones mediante la Admin API, las tiendas las leen con `@inContext(language:)` y los cambios en el catálogo no requieren una nueva compilación de la tienda.
* **Incluye las traducciones en el paquete de la tienda** si no tienes acceso a Shopify Admin o quieres que las traducciones del catálogo se revisen y desplieguen junto con tu código. La CLI traduce un archivo JSON exportado en la misma ejecución que tus textos. La tienda de ejemplo funciona así.

*Nota: El panel de control no ofrece una conexión alojada con Shopify. En ambos casos, tú mismo ejecutas la exportación con tus propias credenciales de Shopify y General Translation.*

## a) Almacenar traducciones en Shopify [#store-in-shopify]

Shopify almacena una traducción por cada campo de un recurso y por cada configuración regional. Un script exporta el texto de origen mediante la Admin API, lo traduce con [`translateMany`](/docs/platform/core/reference/gt-class-methods/translation/translate-many) y vuelve a registrar los resultados en Shopify.

### Antes de empezar

Necesitas:

* Los idiomas de destino añadidos y publicados en el panel de administración de Shopify, en **Settings &gt; Languages**.
* Un token de acceso de la Shopify Admin API de una app instalada en la tienda, con los ámbitos `read_translations`, `write_translations` y `read_locales`. Un token de la Storefront API no puede escribir traducciones.
* `generaltranslation` instalado y una clave de API de proyecto con el permiso **Runtime translation** (`project:translations:generate`). (Consulta el [Inicio rápido](/docs/platform/core/quickstart) de la biblioteca principal).

Guarda el token de Admin y la clave de API en el entorno de tu script. Nunca los añadas al entorno de la tienda ni a los paquetes del navegador.

### Exportar el contenido de origen

Consulta `translatableResources` para cada tipo de recurso que traduzcas. Cada campo devuelve su `key`, el `value` de origen y un `digest` que identifica ese texto de origen concreto.

```graphql title="Admin API"
query CatalogExport($type: TranslatableResourceType!, $after: String) {
  translatableResources(first: 50, after: $after, resourceType: $type) {
    nodes {
      resourceId
      translatableContent { key value digest locale }
      translations(locale: "fr") { key value outdated }
    }
    pageInfo { hasNextPage endCursor }
  }
}
```

Usa tipos de recursos como `PRODUCT`, `PRODUCT_OPTION` y `PRODUCT_OPTION_VALUE`, y recorre los resultados página a página con `endCursor`. Guarda los digests; los necesitarás para registrar las traducciones.

### Traducir con General Translation

Envía los campos de texto sin formato, como los títulos y tipos de producto, los títulos y descripciones SEO, y los nombres y valores de las opciones, a [`translateMany`](/docs/platform/core/reference/gt-class-methods/translation/translate-many). Añade [`metadata.context`](/docs/platform/core/reference/types/entry-metadata#context) para que las etiquetas cortas se traduzcan correctamente.

```ts title="scripts/translate-catalog.ts"
import { GT } from 'generaltranslation';

const gt = new GT({
  apiKey: process.env.GT_API_KEY,
  projectId: process.env.GT_PROJECT_ID,
  sourceLocale: 'en',
});

const results = await gt.translateMany(
  fields.map((field) => ({
    source: field.value,
    metadata: {
      context: `Shopify ${field.resourceType} ${field.key}. Preserve product brand names, measurements, and model numbers.`,
    },
  })),
  { sourceLocale: 'en', targetLocale: 'fr' }
);
```

Los resultados se devuelven en el mismo orden que la entrada, y cada uno indica por separado si se completó correctamente o falló. Vuelve a intentar las entradas fallidas en lugar de registrarlas.

Los campos de texto enriquecido, como el `body_html` de un producto, contienen HTML. La traducción con reconocimiento de formato mediante [`metadata.fileFormat`](/docs/platform/core/reference/types/entry-metadata#file-format) solo admite documentos Markdown y MDX, así que no envíes HTML sin procesar a [`translateMany`](/docs/platform/core/reference/gt-class-methods/translation/translate-many) sin un paso previo que conserve su marcado.

### Registrar traducciones en Shopify

Escribe cada traducción con la mutación [`translationsRegister`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/translationsRegister) de la Admin API. Pasa el digest del contenido de origen como `translatableContentDigest` para que Shopify rechace cualquier traducción cuyo origen haya cambiado después de exportarse.

```graphql title="Admin API"
mutation CatalogRegister($resourceId: ID!, $translations: [TranslationInput!]!) {
  translationsRegister(resourceId: $resourceId, translations: $translations) {
    translations { key locale value outdated }
    userErrors { field code }
  }
}
```

```json title="Variables"
{
  "resourceId": "gid://shopify/Product/123",
  "translations": [
    {
      "locale": "fr",
      "key": "title",
      "value": "Sweat à capuche en coton",
      "translatableContentDigest": "<digest from export>"
    }
  ]
}
```

Usa el código de configuración regional de Shopify para `locale`, que puede no coincidir con tu configuración regional de General Translation. (Consulta [Códigos de configuración regional](/docs/integrations/shopify/reference/locale-handling#locale-codes)).

<Callout type="warn">
  `translationsRegister` reemplaza la traducción existente para esa clave y configuración regional, incluidas las traducciones que un comerciante haya introducido en el panel de administración o que haya escrito otra aplicación. Antes de escribir, compara la traducción actual con el valor que registró tu script la última vez y omite los campos que no hayas escrito tú.
</Callout>

### Leer traducciones en la tienda

Añade `@inContext(language: $language)` a las consultas del catálogo y pasa el `LanguageCode` de Shopify correspondiente a la configuración regional. Shopify devuelve el valor traducido si existe y, si no, el valor de origen. El cliente Storefront de Hydrogen rellena `$language` a partir de su contexto de la solicitud. (Consulta [Localizar Shopify Hydrogen con React Router](/docs/integrations/shopify/guides/localizing-react-router#storefront-language)).

El contenido traducido del catálogo aparece en cuanto se actualizan las cachés de Shopify y de la tienda, sin necesidad de volver a desplegar.

### Mantén las traducciones actualizadas

Cuando un comerciante edita un producto, el digest de sus campos cambia y Shopify marca las traducciones existentes como `outdated`. Vuelve a ejecutar la exportación, traduce solo los campos cuyo digest haya cambiado o que aún no tengan traducción, y registra los resultados.

## b) Incluir las traducciones en el paquete de la tienda [#bundle]

*Nota: Estos ejemplos provienen de la tienda de ejemplo de Next.js, que usa la configuración regional definida en la [guía de Next.js](/docs/integrations/shopify/guides/localizing-nextjs).*

Exporta el texto del catálogo con la Storefront API, usando el propio texto de origen como clave. Guarda las etiquetas cortas (títulos, nombres y valores de opciones, texto alt) y el texto enriquecido (descripciones, cuerpos de páginas) en archivos separados, de modo que solo las etiquetas lleguen al navegador. Sanitiza el texto enriquecido igual que lo renderiza la tienda para que las claves coincidan:

```ts title="scripts/export-catalog.ts"
const labels = new Set<string>();
const content = new Set<string>();
for (const product of catalog.products.nodes) {
  labels.add(product.title).add(product.productType);
  content.add(product.description).add(sanitizeShopifyHtml(product.descriptionHtml));
  for (const image of product.images.nodes) if (image.altText) labels.add(image.altText);
  for (const option of product.options) {
    labels.add(option.name);
    for (const value of option.optionValues) labels.add(value.name);
  }
}

async function writeCatalog(file: string, texts: Set<string>): Promise<number> {
  const entries = [...texts].filter((text) => text.trim()).sort((a, b) => a.localeCompare(b, "en"));
  await writeFile(
    new URL(`../catalog/en/${file}`, import.meta.url),
    `${JSON.stringify(Object.fromEntries(entries.map((text) => [text, text])), null, 2)}\n`,
  );
  return entries.length;
}
```

Añade los archivos exportados en `files.json` dentro de `gt.config.json`, junto a tu entrada `files.gt` existente, para que [`npx gt translate`](/docs/cli/reference/commands/translate) genere `catalog/<locale>/labels.json` y `catalog/<locale>/content.json` en la misma ejecución que tus textos:

```json title="gt.config.json"
{
  "files": {
    "json": { "include": ["catalog/[locale]/labels.json", "catalog/[locale]/content.json"] }
  }
}
```

Busca las traducciones a partir del texto de origen actual y recurre a él como alternativa, para que todo lo que se haya editado en Shopify después de la última exportación muestre su texto actualizado:

```ts title="lib/catalog/index.ts"
/** Busca el texto del comerciante por su texto de origen actual en inglés y lo usa como alternativa cuando no existe traducción. */
export function translateCatalogText(catalog: Catalog, text: string): string;
export function translateCatalogText(catalog: Catalog, text: string | undefined): string | undefined;
export function translateCatalogText(catalog: Catalog, text: string | undefined) {
  return (text && catalog[text]) || text;
}
```

```ts title="lib/catalog/server.ts"
/** Etiquetas breves (títulos, nombres y valores de opciones, texto alt) para componentes de cliente como el carrito. */
export function getCatalogLabels(locale: string): Catalog {
  return catalogs[locale]?.labels ?? {};
}

/** Devuelve un traductor para el texto del comerciante de Shopify en la configuración regional de la solicitud. */
export async function getCatalogText() {
  const catalog = catalogs[await getLocale()];
  const merged: Catalog = catalog ? { ...catalog.content, ...catalog.labels } : {};
  function ct(text: string): string;
  function ct(text: string | undefined): string | undefined;
  function ct(text: string | undefined) {
    return translateCatalogText(merged, text);
  }
  return ct;
}
```

* Pasa el texto traducido a [`<T>`](/docs/react/reference/components/t) mediante [`<Var>`](/docs/react/reference/components/var), no como texto de origen.
* Para componentes de cliente como el carrito y la búsqueda predictiva, pasa `getCatalogLabels(locale)` a un proveedor de contexto en el layout. No envíes al navegador texto enriquecido ni los catálogos de otras configuraciones regionales.
* Mantén los valores de las opciones en su idioma de origen siempre que sirvan para seleccionar una variante, construir una URL o se envíen a Shopify. Traduce solo la etiqueta que se muestra.
* Para orientar la traducción de los nombres de productos (por ejemplo, conservar términos de marca o traducir el nombre de una prenda), añade términos de glosario y prompts personalizados al grupo de contexto del proyecto en el panel de control.

## Next steps

- /docs/integrations/shopify/guides/localizing-react-router
- /docs/integrations/shopify/guides/localizing-nextjs
- /docs/integrations/shopify/guides/selling-in-markets

## Sitemap

See the full [sitemap](https://generaltranslation.com/sitemap.md) for all pages.
