Skip to content

Instantly share code, notes, and snippets.

@SimeonGriggs
Last active July 16, 2024 08:44
Show Gist options
  • Save SimeonGriggs/d8306e2caf1567196893dd6aecdd223c to your computer and use it in GitHub Desktop.
Save SimeonGriggs/d8306e2caf1567196893dd6aecdd223c to your computer and use it in GitHub Desktop.
This migration will duplicate a "base document" and all its translations
import {uuid} from '@sanity/uuid'
import {SanityDocumentLike} from 'sanity'
import {defineMigration, create} from 'sanity/migrate'
// Update these constants to match your Document Internationalization Plugin configuration
const BASE_FIELD = `__i18n_base`
const REFS_FIELD = `__i18n_refs`
const LANGUAGE_FIELD = `_lang`
const ID_SUFFIX = '__i18n'
/**
* Script for i18n duplications that exceed the max request size of a single transaction
* The shape of the documents created in this script only work with Sanity Document Internationalization v1
*
* This migration will duplicate a "base document" and all its translations
* The base document's ID must be provided as an argument when running the script
*
* Place this at the base of your Sanity Studio project in
* ./migrations/i18n-duplicate/index.ts
*
* Dry run:
* npx sanity@latest migration run i18n-duplicate --id=<documentId>
*
* Execute:
* npx sanity@latest migration exec i18n-duplicate --no-dry-run --id=<documentId>
*/
export default defineMigration({
title: 'i18n-duplicate',
async *migrate(documents, context) {
// Get ID from args
const id = process.argv.find((arg) => arg.startsWith('--id='))?.split('=')[1]
if (!id) {
throw new Error('Missing ID argument')
}
// Query for base document
let baseDocument = await context.client.fetch<SanityDocumentLike>(`*[_id == $id][0]`, {id})
if (!baseDocument) {
throw new Error('Base document not found')
} else if (!Array.isArray(baseDocument?.[REFS_FIELD])) {
throw new Error('Base document has no translation references')
}
let translationDocuments = await context.client.fetch<SanityDocumentLike[]>(`*[_id in $ids]`, {
ids: baseDocument[REFS_FIELD].map((ref) => ref._ref),
})
if (!translationDocuments.length) {
throw new Error('No translations found')
}
// Create new ID's in every document, preserving draft status
baseDocument._id = baseDocument._id.startsWith('drafts.') ? `drafts.${uuid()}` : uuid()
translationDocuments.forEach((doc) => {
// translations have ID's like "4b344817-22e6-4e28-9c59-5dda1a313a75__i18n_fr"
// where the ID begins with the base document's ID
// retrieve the everything after the suffix on this translation's ID, eg "_fr"
const idSuffix = doc._id.split(ID_SUFFIX)[1]
// don't reference draft documents
const publishedBaseId = baseDocument._id.replace('drafts.', '')
const newId = publishedBaseId + ID_SUFFIX + idSuffix
// set new ID on translation, keeping draft status
doc._id = doc._id.startsWith('drafts.') ? `drafts.${newId}` : newId
})
// Update refs in base document
baseDocument[REFS_FIELD] = translationDocuments.map((doc) => ({
_key: doc[LANGUAGE_FIELD],
// don't reference draft documents
_ref: doc._id.replace('drafts.', ''),
_type: 'reference',
}))
// Update base document ref in translations
translationDocuments.forEach((doc) => {
doc[BASE_FIELD] = {
// don't reference draft documents
_ref: baseDocument._id.replace('drafts.', ''),
_type: 'reference',
}
})
const payload: SanityDocumentLike[] = [baseDocument, ...translationDocuments]
yield payload.map((doc) => create(doc))
},
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment