Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions .github/skills/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
name: i18n-array-groq-query-migration
description: Detect and update legacy GROQ patterns where language is read from _key for sanity-plugin-internationalized-array when users mention v4 to v5 migration, or @sanity/document-internationalization from v5 to v6. GROQ query updates, localized arrays, or patterns like `_key == "en"` and `_key == $language`.
---

# Internationalized Array GROQ Migration

## Goal

Help users find GROQ queries that still read locale from `_key` and rewrite them safely for v5.

## When To Use

Use this skill when a user asks to:

- migrate `sanity-plugin-internationalized-array` from v4 to v5
- migrate `@sanity/document-internationalization` from v5 to v6 alongside `sanity-plugin-internationalized-array` language field changes
- find queries that still use `_key` for language lookup
<!-- - update GROQ filters like `_key == "en"` or `_key == $language` -->

## Detection Workflow

Detection commands below use `grep`. If your environment differs, use your editor's global search with equivalent patterns.

1. Search for direct language comparisons on `_key`:

```bash
grep -REn --exclude-dir=node_modules "_key[[:space:]]*==[[:space:]]*(\"[^\"]+\"|'[^']+'|\\$[A-Za-z_][A-Za-z0-9_]*)" .
```

1. Search for any localized-array filters that mention `_key`:

```bash
grep -REn --exclude-dir=node_modules "\[[^]]*_key[^]]*\]" .
```

1. Prioritize matches that look like localized-value reads, for example:

- `field[_key == ...][0].value`
- `select(...)` branches that compare `_key` to a language value

1. Check for uses of `groq` and verify if they use `_key` as the language, if it is using it, update them.

1. Explicitly check for template-interpolated language expressions and keep the same operand, for example:
- `_key == "${language}"`
- `_key == "${locale}"`

1. Review each match to avoid false positives where `_key` is used for unrelated array item identity.

## Rewrite Rules

Use the same language operand from the original query. The language operand can be a string literal (for example `"en"`), a variable (for example `$language`), or a template-interpolated expression (for example `"${language}"`).

- **Before data migration is executed (backwards compatible):**
- `_key == <languageExpr>` -> `language == <languageExpr> || _key == <languageExpr>`
- **After migration is complete:**
- `language == <languageExpr> || _key == <languageExpr>` -> `language == <languageExpr>`

## Examples

Legacy:

```groq
*[_type == "person"]{
"greeting": greeting[_key == $language][0].value
}
```

Backwards compatible:

```groq
*[_type == "person"]{
"greeting": greeting[language == $language || _key == $language][0].value
}
```

Post-migration final form:

```groq
*[_type == "person"]{
"greeting": greeting[language == $language][0].value
}
```

## Response Template

When reporting findings to a user:

1. List each query location that still uses `_key` as language source.
2. Show the exact replacement using the same language expression.
3. Label each replacement as:
- `backwards-compatible` (pre-migration), or
- `final` (post-migration complete).
4. Label each match category as `runtime`, `docs/example`, or `ambiguous`.
5. Call out any ambiguous `_key` usage that needs manual review.
16 changes: 16 additions & 0 deletions studio/migrations/i18n-doc-v6/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { migrateToLanguageField } from 'sanity-plugin-internationalized-array/migrations'

// Migrates translation.metadata documents from the old format where language
// was stored in `_key` to the new format with a dedicated `language` field.
// Required for @sanity/document-internationalization v6 compatibility.
//
// Steps:
// 1. Backup: pnpm sanity dataset export <dataset>
// 2. Dry run: pnpm sanity migration run i18n-doc-v6 --project=<PROJECT_ID> --dataset=<DATASET>
// 3. Migrate: pnpm sanity migration run i18n-doc-v6 --project=<PROJECT_ID> --dataset=<DATASET> --no-dry-run
// 4. After confirming data is correct, simplify GROQ queries:
// Remove `|| _key == $lang` fallbacks from translations[] filters.

const DOCUMENT_TYPES: string[] = ['translation.metadata']

export default migrateToLanguageField(DOCUMENT_TYPES)
53 changes: 27 additions & 26 deletions studio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,48 +16,49 @@
"sanity"
],
"dependencies": {
"@energyvision/shared": "workspace:*",
"@equinor/eds-icons": "^0.17.0",
"@portabletext/react": "^5.0.0",
"@reach/auto-id": "^0.18.0",
"@sindresorhus/slugify": "^3.0.0",
"@sanity/asset-utils": "^2.3.0",
"@sanity/dashboard": "^5.0.1",
"@sanity/document-internationalization": "4.1.0",
"@sanity/client": "^7.16.0",
"@sanity/client": "^7.23.1",
"@sanity/cross-dataset-duplicator": "^1.5.1",
"@sanity/icons": "^3.7.4",
"@sanity/ui": "^3.1.13",
"@sanity/uuid": "^3.0.2",
"@sanity/dashboard": "^5.0.1",
"@sanity/document-internationalization": "6.2.19",
"@sanity/icons": "^3.8.0",
"@sanity/ui": "^3.3.5",
"@sanity/uuid": "^3.0.3",
"@sanity/vision": "5.12.0",
"@portabletext/react": "^5.0.0",
"@sindresorhus/slugify": "^3.0.0",
"blob-util": "^2.0.2",
"buffer": "^6.0.3",
"date-fns": "^4.1.0",
"hls.js": "^1.6.13",
"date-fns": "^4.4.0",
"hls.js": "^1.6.16",
"mime": "^4.1.0",
"papaparse": "^5.5.3",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-icons": "^5.5.0",
"react-is": "^19.2.4",
"recharts": "^3.3.0",
"rxjs": "^7.8.0",
"papaparse": "^5.5.4",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"react-icons": "^5.7.0",
"react-is": "^19.2.7",
"recharts": "^3.9.2",
"rxjs": "^7.8.2",
"sanity": "5.12.0",
"sanity-plugin-documents-pane": "^3.0.2",
"sanity-plugin-iframe-pane": "^5.0.6",
"sanity-plugin-media": "^4.1.1",
"sanity-plugin-iframe-pane": "^5.0.25",
"sanity-plugin-media": "^4.3.6",
"sanity-plugin-utils": "^1.8.0",
"styled-components": "^6.3.11",
"styled-components": "^6.4.3",
"vite-plugin-svgr": "^4.5.0",
"@energyvision/shared": "workspace:*"
"sanity-plugin-internationalized-array": "^5.1.19"
},
"devDependencies": {
"@repo/typescript-config": "workspace:*",
"@sanity/eslint-config-studio": "^6.0.0",
"@types/react": "^19.2.14",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@types/styled-components": "^5.1.34",
"nanoid": "^5.0.9",
"@types/styled-components": "^5.1.36",
"nanoid": "^5.1.16",
"typescript": "^5.9.3",
"vite-tsconfig-paths": "^5.1.4",
"@repo/typescript-config": "workspace:*"
"vite-tsconfig-paths": "^5.1.4"
}
}
Loading