Skip to content

Commit ddb82aa

Browse files
authored
chore(i18n): add docs and scripts folders, update readme links (#866)
1 parent 971ccd6 commit ddb82aa

17 files changed

Lines changed: 939 additions & 22 deletions

plugins/@sanity/document-internationalization/README.md

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -55,31 +55,31 @@ This plugin uses [sanity-plugin-internationalized-array](https://github.com/sani
5555

5656
**Important:** When configuring the migration, include `'translation.metadata'` in the document types so that your translation metadata documents are migrated:
5757

58-
### 1. Backup your data.
58+
### 1. Backup your data
5959

6060
You can manually backup your data using the sanity CLI.
6161

62-
```
62+
```bash
6363
sanity dataset export production
6464
```
6565

6666
This creates a production.tar.gz file in your current directory containing all your documents and assets.
6767

6868
You can also specify a custom filename and location:
6969

70-
```
70+
```bash
7171
sanity dataset export production ./backups/backup-2026-02-16.tar.gz
7272
```
7373

7474
If you ever need to restore, use the import command:
7575

76-
```
76+
```bash
7777
sanity dataset import backup-2026-02-16.tar.gz production
7878
```
7979

80-
Or you can use the backup service, read more at https://www.sanity.io/docs/content-lake/backups
80+
Or you can use the backup service, read more in the [Content Lake backups documentation](https://www.sanity.io/docs/content-lake/backups).
8181

82-
### 2. Update your GROQ queries.
82+
### 2. Update your GROQ queries
8383

8484
Use a backwards compatible query until your migration is ready and has been executed.
8585

@@ -128,14 +128,7 @@ Previously we updated the GROQ queries to support both locations for the languag
128128

129129
## Upgrade from V1
130130

131-
If upgrading from a previous version (v1), please see the [upgrade documentation](https://github.com/sanity-io/document-internationalization/blob/main/docs/00-upgrade-from-v1.md) in the original repository.
132-
And change `_key: doc[LANGUAGE_FIELD]` to `language: doc[LANGUAGE_FIELD]` in https://github.com/sanity-io/document-internationalization/blob/main/scripts/createMetadata.ts#L80
133-
134-
```diff
135-
// https://github.com/sanity-io/document-internationalization/blob/main/scripts/createMetadata.ts#L80
136-
- _key: doc[LANGUAGE_FIELD]
137-
+ language: doc[LANGUAGE_FIELD]
138-
```
131+
If upgrading from a previous version (v1), please see the [upgrade documentation](https://github.com/sanity-io/plugins/blob/main/plugins/%40sanity/document-internationalization/docs/00-upgrade-from-v1.md) in this repository.
139132

140133
## Install
141134

@@ -392,15 +385,16 @@ This means if you have 100 documents and they are all translated into 3 language
392385

393386
## Documentation
394387

395-
For more advanced topics see the [original repository documentation](https://github.com/sanity-io/document-internationalization/tree/main/docs).
388+
For more advanced topics see the [repository documentation](https://github.com/sanity-io/plugins/tree/main/plugins/%40sanity/document-internationalization/docs).
396389

397-
- [Upgrade from v1](https://github.com/sanity-io/document-internationalization/blob/main/docs/00-upgrade-from-v1.md)
398-
- [Creating translations of singleton documents](https://github.com/sanity-io/document-internationalization/blob/main/docs/01-singleton-documents.md)
399-
- [Importing and creating documents](https://github.com/sanity-io/document-internationalization/blob/main/docs/02-importing-and-creating-documents.md)
400-
- [Deleting translated documents](https://github.com/sanity-io/document-internationalization/blob/main/docs/03-deleting-translated-documents.md)
401-
- [Importing plugin components](https://github.com/sanity-io/document-internationalization/blob/main/docs/04-importing-plugin-components.md)
402-
- [Allowing the same slug on different language versions](https://github.com/sanity-io/document-internationalization/blob/main/docs/05-allowing-the-same-slug-for-translations.md)
403-
- [Remove default new document template](https://github.com/sanity-io/document-internationalization/blob/main/docs/06-remove-default-new-document-template.md)
390+
- [Upgrade from v1](https://github.com/sanity-io/plugins/blob/main/plugins/%40sanity/document-internationalization/docs/00-upgrade-from-v1.md)
391+
- [Creating translations of singleton documents](https://github.com/sanity-io/plugins/blob/main/plugins/%40sanity/document-internationalization/docs/01-singleton-documents.md)
392+
- [Importing and creating documents](https://github.com/sanity-io/plugins/blob/main/plugins/%40sanity/document-internationalization/docs/02-importing-and-creating-documents.md)
393+
- [Deleting translated documents](https://github.com/sanity-io/plugins/blob/main/plugins/%40sanity/document-internationalization/docs/03-deleting-translated-documents.md)
394+
- [Importing plugin components](https://github.com/sanity-io/plugins/blob/main/plugins/%40sanity/document-internationalization/docs/04-importing-plugin-components.md)
395+
- [Allowing the same slug on different language versions](https://github.com/sanity-io/plugins/blob/main/plugins/%40sanity/document-internationalization/docs/05-allowing-the-same-slug-for-translations.md)
396+
- [Remove default new document template](https://github.com/sanity-io/plugins/blob/main/plugins/%40sanity/document-internationalization/docs/06-remove-default-new-document-template.md)
397+
- [Duplicating translated documents](https://github.com/sanity-io/plugins/blob/main/plugins/%40sanity/document-internationalization/docs/07-duplicating-translated-documents.md)
404398

405399
## License
406400

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# Upgrading from v1 of @sanity/document-internationalization
2+
3+
## Where you are now:
4+
5+
**I'm on Sanity Studio v3 and upgrading from plugin v1.0.0 and above**
6+
7+
- You will need to perform a content migration to upgrade. See ["Upgrading from v1 to v2"](#upgrading-from-v1-to-v2)
8+
- Your queries will also need to change, as translation references have moved. See ["Upgrading from v1 to v2"](#upgrading-from-v1-to-v2) below for migration guidance, including query updates.
9+
10+
**I'm on Sanity Studio v3 but will stay with the older plugin for now**
11+
12+
- Please refer to the [v1 branch](https://github.com/sanity-io/document-internationalization/tree/v1)
13+
- Install from `v1.0.0` and above
14+
- This version of the plugin will not be updated with new features
15+
16+
**I'm on Sanity Studio v2**
17+
18+
- Please refer to the [studio-v2 branch](https://github.com/sanity-io/document-internationalization/tree/studio-v2)
19+
- Install from `v0.0.0` and above
20+
- This version of the plugin will not be updated with new features
21+
- You will not need to perform a content migration to move to Sanity Studio v3, if you install the v1 plugin.
22+
23+
### Upgrading from v1 to v2
24+
25+
Upgrading from v1 to v2 of this plugin will require:
26+
27+
1. Migrations of internationalized documents in your dataset
28+
2. Updates to your `sanity.config.ts` plugins array
29+
3. Updated queries in your front-end application(s)
30+
31+
We have provided migration scripts and guidance on this page. Please submit an issue if anything is unclear.
32+
33+
### How v2 is different from v1
34+
35+
A complete rewrite of the original Document Internationalization plugin, exclusively for Sanity Studio v3. Major **benefits** from the previous versions include:
36+
37+
- Create new documents in any language and link translated references later
38+
- Translation references are written to a separate "meta" document
39+
- Updates to one translation no longer affect the change history of others
40+
- Does not require custom - nor modify the built-in - [Document Actions](https://www.sanity.io/docs/document-actions)
41+
- Changes made to one translation do not patch changes to other documents
42+
- Configurable "language" field on documents
43+
- Built-in static and parameterized initial value templates for new documents
44+
45+
## 1. Migrating content
46+
47+
In this repository are two scripts to help migrate content. One is required, the other is not.
48+
49+
### 1.1 Required: `createMetadata.ts`
50+
51+
Please backup your dataset before running migration scripts.
52+
53+
Instructions for how to perform this migration are written in the script itself: [scripts/createMetadata.ts](../scripts/createMetadata.ts)
54+
55+
The [createMetadata.ts](../scripts/createMetadata.ts) script will look for all documents of a specific `_type` that contain the previous plugin's `__i18n_refs` array of references. Those arrays were written by the plugin and should look like this:
56+
57+
```json
58+
"__i18n_refs": [
59+
{
60+
"_key": "en_GB",
61+
"_ref": "32cb7277-1cfb-4ab1-ae1e-ab844dc8ab72__i18n_en_GB",
62+
"_type": "reference",
63+
},
64+
{
65+
"_key": "no",
66+
"_ref": "32cb7277-1cfb-4ab1-ae1e-ab844dc8ab72__i18n_nl",
67+
"_type": "reference",
68+
},
69+
],
70+
```
71+
72+
The script will create a new `translation.metadata` document which contains the `__i18n_refs` array of references in a field named `translations`.
73+
74+
(This is the new way to query for translations of a document – to find the `translation.metadata` document that references it, and then look through the `translations` array.)
75+
76+
The benefits of this method include no longer needing document actions to write changes to content documents – and being able to start documents in any language and attach translations.
77+
78+
The resultant document looks like this:
79+
80+
```json
81+
{
82+
"_id": "b4ed5f0b-8e01-44b7-ac4c-09f2fb233b26",
83+
"_type": "translation.metadata",
84+
"translations": [
85+
{
86+
"_key": "kjjNvZHK8Y2QpTEf3K5jc",
87+
"_type": "internationalizedArrayReferenceValue",
88+
"language": "en",
89+
"value": {
90+
"_ref": "32cb7277-1cfb-4ab1-ae1e-ab844dc8ab72__i18n_en_GB",
91+
"_type": "reference"
92+
}
93+
},
94+
{
95+
"_key": "9Hw3I5BNXZ72mCfJW6Pq1",
96+
"_type": "internationalizedArrayReferenceValue",
97+
"language": "no",
98+
"value": {
99+
"_ref": "32cb7277-1cfb-4ab1-ae1e-ab844dc8ab72__i18n_nl",
100+
"_type": "reference"
101+
}
102+
}
103+
]
104+
}
105+
```
106+
107+
The previous `__i18n_refs` and `__i18n_base` fields will be removed from the document.
108+
109+
Make sure to configure the new plugin with your existing `languageField` setting, or run the script below to rewrite the name of that field.
110+
111+
### 1.2 Optional: `renameLanguageField.ts`
112+
113+
Please backup your dataset before running migration scripts.
114+
115+
Instructions for how to perform this migration are written in the script itself: [scripts/renameLanguageField.ts](../scripts/renameLanguageField.ts)
116+
117+
The previous plugin by default would write fields with double underscore prefixes (example: `__lang`) which did not work with GraphQL deployments.
118+
119+
For data hygiene, you may prefer to have a normalized field name for the language field in your translated documents. The default field name for a document's language in the new plugin is `language`.
120+
121+
[This script will update the field name](../scripts/renameLanguageField.ts) `__i18n_lang` to `language` or can be customized to use the field name you used in the previous version of the plugin.
122+
123+
## 2. Updating `sanity.config.ts`
124+
125+
### 2.1 Install the new version of the plugin
126+
127+
```sh
128+
npm install @sanity/document-internationalization@latest
129+
```
130+
131+
### 2.2 Update your plugins array
132+
133+
The previous version of the plugin recommended you wrap your plugins array and modify your desk structure using the `withDocumentI18nPlugin()` function. This is no longer required.
134+
135+
Update your plugins array to load the plugin like you would any other. For configuration options see the [plugin README](../README.md).:
136+
137+
>
138+
139+
```ts
140+
// ./sanity.config.ts
141+
142+
import {createSchema} from '@sanity/schema'
143+
import {documentInternationalization} from '@sanity/document-internationalization'
144+
// ...all other imports
145+
146+
export default defineConfig({
147+
// ... all other settings
148+
plugins: [
149+
// ... all other plugins
150+
// Remove `withDocumentI18nPlugin` wrapper function
151+
deskTool(),
152+
documentInternationalization({
153+
// See the README and notes below for configuration options
154+
}),
155+
],
156+
})
157+
```
158+
159+
Your existing plugin configuration might look something like this. See comments below for which field names require updates and which are no longer necessary or relevant.
160+
161+
```js
162+
// Old plugin configuration
163+
164+
documentI18n({
165+
// Change to `supportedLanguages`
166+
"languages": [
167+
{ "title": "English (US)", "id": "en-us" },
168+
{ "title": "Dutch (NL)", "id": "nl-nl" }
169+
],
170+
// Change to `weakReferences`, example:
171+
// weakReferences: true | false (default false)
172+
"referenceBehavior": "strong",
173+
// Change to `languageField`, example:
174+
// languageField: 'language' (default 'language')
175+
"fieldNames": {
176+
"lang": "__i18n_lang",
177+
"references": "__i18n_refs",
178+
"baseReference": "__i18n_base"
179+
}
180+
// Remove: There is no enforced "base language" in this new version
181+
"base": "en-us",
182+
// Remove: Deterministic _id strings are no longer supported
183+
// as documents could be created in any language first
184+
// and querying by _id strings is unreliable and slow
185+
"idStructure": "delimiter",
186+
// Remove: No longer necessary
187+
"withTranslationsMaintenance": false,
188+
})
189+
```
190+
191+
The new config would look like this:
192+
193+
```js
194+
// New plugin configuration
195+
196+
documentInternationalization({
197+
// Required:
198+
supportedLanguages: [
199+
{title: 'English (US)', id: 'en-us'},
200+
{title: 'Dutch (NL)', id: 'nl-nl'},
201+
],
202+
schemaTypes: ['page'],
203+
// Optional:
204+
weakReferences: false, // default false
205+
languageField: 'language', // default "language"
206+
})
207+
```
208+
209+
### 2.3 Cleanup schema
210+
211+
You can now remove the `i18n` key from all document schemas, as the schema types the plugin is enabled on are now configured in the plugin function.
212+
213+
## 3. Updating queries
214+
215+
The previous version of the plugin wrote language details to document `_id`s. This behavior was changed in a previous version of the plugin. Matching against the string `_id` of a document is an unreliable and slow way to query for documents.
216+
217+
See the [GROQ examples in the README](../README.md#querying-with-groq) and [GraphQL examples in the README](../README.md#querying-with-graphql) for how to query for translations.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Creating translations of singleton documents
2+
3+
![Singleton documents](./img/singletons-list.png)
4+
5+
Singleton documents in Sanity are usually created with the [Structure Builder](https://www.sanity.io/docs/structure-builder-reference) by creating a `S.documentListItem()` with a predetermined ID.
6+
7+
This isn't enough when it comes to translated documents as you need to create an ID for each document and bind them together with a translations metadata document.
8+
9+
For translated singletons you will need to:
10+
11+
1. Run a script to create the documents in advance
12+
2. Update your Desk Structure to use a list of documents that know these created IDs
13+
14+
## 1. Create the documents
15+
16+
Instructions for how to perform this migration are written in the script itself: [scripts/createSingletons.ts](../scripts/createSingletons.ts)
17+
18+
This script will create a document for each singleton you need, and a translations document that will be used to bind them together.
19+
20+
If you add more languages later you may need to adapt this script to check first for the existence of the translations metadata document and append the new translations to it.
21+
22+
## 2. Update your Desk Structure
23+
24+
At this time it's not possible to re-use the `supportedLanguages` array passed into the plugin configuration for this step, so this will not work for languages called from an async function.
25+
26+
In the example below, we re-use the same arrays of SINGLETONS and LANGUAGES as the creation script to render a new list for every "singleton" and a new item inside it for every "language" version.
27+
28+
This will render list items as shown in the screenshot above.
29+
30+
```ts
31+
const SINGLETONS = [
32+
{id: 'home', _type: 'page', title: 'Home'},
33+
{id: 'login', _type: 'page', title: 'Login'},
34+
]
35+
const LANGUAGES = [
36+
{id: `en`, title: `English`},
37+
{id: `fr`, title: `French`},
38+
]
39+
40+
export const structure: StructureResolver = (S) =>
41+
S.list()
42+
.title('Content')
43+
.items([
44+
...SINGLETONS.map((singleton) =>
45+
S.listItem()
46+
.title(singleton.title)
47+
.id(singleton.id)
48+
.child(
49+
S.list()
50+
.title(singleton.title)
51+
.id(singleton.id)
52+
.items(
53+
LANGUAGES.map((language) =>
54+
S.documentListItem()
55+
.schemaType(singleton._type)
56+
.id(`${singleton.id}-${language.id}`)
57+
.title(`${singleton.title} (${language.id.toLocaleUpperCase()})`)
58+
)
59+
)
60+
.canHandleIntent(
61+
(intentName, params) => intentName === 'edit' && params.id.startsWith(singleton.id)
62+
)
63+
)
64+
),
65+
// ...other list items
66+
```

0 commit comments

Comments
 (0)