Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
@sanity/document-internationalization
Advanced tools
Create unique translations of a document based on its language, joined by a shared reference document.
All new rewrite exclusively for Sanity Studio v3
There are two popular methods of internationalization in Sanity Studio:
translation.metadata
documentThis plugin adds features to the Studio to improve handling document-level translations.
For field-level translations you should use the sanity-plugin-internationalized-array.
An example of document-level translation could be a lesson
schema, the title
, slug
and content
fields would be unique in every language.
A good use of field-level translation could be a person
schema. It could have the same name
and image
in every language, but only the biography
would need translating.
See the upgrade guide for instructions on how to upgrade from the previous version of Document Internationalization.
npm install --save @sanity/document-internationalization
Add it as a plugin in sanity.config.ts
(or .js):
The only required configuration is:
supportedLanguages
array andschemaTypes
array// sanity.config.ts
import {createConfig} from 'sanity'
import {documentInternationalization} from '@sanity/document-internationalization'
export const createConfig({
// ... all other config
plugins: [
// ... all other plugins
documentInternationalization({
// Required configuration
supportedLanguages: [
{id: 'es', title: 'Spanish'},
{id: 'en', title: 'English'}
],
schemaTypes: ['lesson'],
})
]
})
The plugin also supports asynchronously retrieving languages from the dataset, modifying the language field, adding a bulk publishing feature and adding additional fields to the metadata document.
// sanity.config.ts
import {createConfig} from 'sanity'
import {documentInternationalization} from '@sanity/document-internationalization'
export const createConfig({
// ... all other config
plugins: [
// ... all other plugins
documentInternationalization({
// Required
// Either: an array of supported languages...
supportedLanguages: [
{id: 'nb', title: 'Norwegian (Bokmål)'},
{id: 'nn', title: 'Norwegian (Nynorsk)'},
{id: 'en', title: 'English'}
],
// ...or a function that takes the client and returns a promise of an array of supported languages
// MUST return an "id" and "title" as strings
// Note: Async language configuration cannot create templates for new documents
// supportedLanguages: (client) => client.fetch(`*[_type == "language"]{id, title}`),
// Required
// Translations UI will only appear on these schema types
schemaTypes: ['lesson'],
// Optional
// Customizes the name of the language field
languageField: `language` // defauts to "language"
// Optional
// Keep translation.metadata references weak
weakReferences: true // defaults to false
// Optional
// Adds UI for publishing all translations at once. Requires access to the Scheduling API
// https://www.sanity.io/docs/scheduling-api
bulkPublish: true // defaults to false
// Optional
// Adds additional fields to the metadata document
metadataFields: [
defineField({ name: 'slug', type: 'slug' })
],
// Optional
// Define API Version for all queries
// https://www.sanity.io/docs/api-versioning
apiVersion: '2023-05-22',
// Optional
// Enable "manage translations" button without creating a translated version. Helpful if you have
// pre-existing documents that you need to tie together through the metadata document
allowCreateMetaDoc: true // defaults to false
})
]
})
The schema types that use document internationalization must also have a string
field type with the same name configured in the languageField
setting. Unless you want content creators to be able to change the language of a document, you may hide or disable this field since the plugin will handle writing patches to it.
// ./schema/lesson.ts
// ...all other settings
defineField({
// should match 'languageField' plugin configuration setting, if customized
name: 'language',
type: 'string',
readOnly: true,
hidden: true,
})
The default behaviour of this plugin when creating a new translation is to duplicate the originating document, which is useful for then translating the fields directly in the new document - perhaps with Sanity AI Assist. However, sometimes you may want to exclude certain fields from being copied to the new document. You can do this by updating your schema to exclude certain types or fields with options.documentInternationalization.exclude
:
defineField({
name: 'title',
title: 'Title',
type: 'string',
options: {
documentInternationalization: {
exclude: true,
},
},
}),
To query a single document and all its translations, we use the references()
function in GROQ.
// All `lesson` documents of a single language
*[_type == "lesson" && language == $language]{
title,
slug,
language,
// Get the translations metadata
// And resolve the `value` reference field in each array item
"_translations": *[_type == "translation.metadata" && references(^._id)].translations[].value->{
title,
slug,
language
},
}
Fortunately, the Sanity GraphQL API contains a similar filter for document references.
# In this example we retrieve a lesson by its `slug.current` field value
query GetLesson($language: String!, $slug: String!) {
allLesson(
limit: 1
where: {language: {eq: $language}, slug: {current: {eq: $slug}}}
) {
_id
title
language
slug {
current
}
}
}
# And then can run this query to find translation metadata documents that use its ID
query GetTranslations($id: ID!) {
allTranslationMetadata(where: {_: {references: $id}}) {
translations {
_key
value {
title
slug {
current
}
}
}
}
}
In previous versions of this plugin, translations were stored as an array of references on the actual documents. This required a base language, lead to messy transaction histories and made deleting documents difficult.
In this version of the plugin, translations of a document are stored as an array of references in a separate document of the type translation.metadata
, and one is created for every document that has translations. A document with no translations will not have a metadata document.
This means if you have 100 documents and they are all translated into 3 languages, you will have 400 documents. Keep this in mind for extremely high-volume datasets.
For more advanced topics see the documentation. For installation see Usage.
MIT © Sanity.io
This plugin uses @sanity/plugin-kit with default configuration for build & watch scripts.
See Testing a plugin in Sanity Studio on how to run this plugin with hot reload in the studio.
Run "CI & Release" workflow. Make sure to select the main branch and check "Release new version".
Semantic release will only release on configured branches, so it is safe to run the release on any branch.
FAQs
Create unique translations of a document based on its language, joined by a shared reference document.
We found that @sanity/document-internationalization demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.