We're proud to be partnered with Smartling and their official connector makes it quick and easy to get your studio content into your Smartling project.
This is a separate plugin, and differs in that it provides editors a visual progress bar for ongoing translations and a way to import translations back into your content at either the document or field level. Feel free to try it out and see which solution works for you!
This plugin comes with (and exposes to the developer) the following items:
- An
Adapter
that connects to the Smartling API with methods to create a new translation job, upload and assign a file to that translation job, check the progress of an ongoing translation, and retrieve a translated file. - A
Serializer
that transforms your content into HTML (we found this was the most efficient way to maintain your document structure, no matter how deeply nested, while remaining readable to translators in Smartling). TheSerializer
takes in optional arguments:stopTypes
, which prevents certain types from being sent to your translatiors andcustomSerializers
, which are rules you can use to have full control over how individual fields on your document get serialized. - A
Deserializer
that deserializes translated text back to Sanity's format. - A
Patcher
which determines how your content gets patched back into its destination document or field. - A
TranslationsTab
, a React element that allows a non-technical user to import, export, and monitor Smartling progress.
To make life easier, we also include defaultFieldLevelConfig
and defaultDocumentLevelConfig
, which bundles all of the above up to get you up and running quickly.
To use the default config mentioned above, we assume that you are following the conventions we outline in our documentation on localization.
If you are using field-level translation, we assume any fields you want translated exist in the multi-locale object form we recommend.
For example, on a document you don't want to be translated, you may have a "title" field that's a flat string: title: 'My title is here.'
For a field you want to include many languages for, your title may look like
{ title: { en: 'My title is here.', es: 'Mi título está aquí.', etc... } }
Important: Smartling's locale representation includes hyphens, like fr-FR
. These aren't valid as Sanity field names, so ensure that on your fields you change the hyphens to underscores (like fr_FR
).
Since we often find users want to use the Internationalization input plugin if they're using document-level translations, we assume that any documents you want in different languages will follow the pattern i18n.{id-of-base-language-document}.{locale}
It's okay if your data doesn't follow these patterns and you don't want to change them! You will simply have to override how the plugin gets and patches back information from your documents. Please see Overriding defaults.
-
Install this plugin with
npm install sanity-plugin-studio-smartling
-
Because of Smartling CORS restrictions, you will need to set up a proxy endpoint to funnel requests to Smartling. We've provided a tiny Next.js app you can set up here. If that's not useful, the important thing to pay attention to is that this endpoint handles requests with an
X-URL
header that contains the Smartling URL configured by the plugin, and can parse a data file to an HTML string and send it back to the adapter. -
Once your proxy is set up, ensure that endpoint is available to your Sanity studio by placing it in the appropriate
.env
file (if you're developing locally, that's.env.development
). That file should look like this:
#any other environment variables...
SANITY_STUDIO_SMARTLING_PROXY=http://your-proxy-url.com
- Ensure the plugin has access to your Smartling token secret. You'll want to create a document that includes your project name and a token secret with appropriate access. Please refer to the Smartling documentation on creating a token if you don't have one already.
- In your studio, create a file called
populateSmartlingSecrets.js
. - Place the following in the file and fill out the correct values (those in all-caps).
- In your studio, create a file called
import sanityClient from 'part:@sanity/base/client'
const client = sanityClient.withConfig({ apiVersion: '2021-03-25' })
client.createOrReplace({
_id: 'translationService.secrets',
_type: 'smartlingSettings',
organization: 'YOUR_ORG_HERE',
project: 'YOUR_PROJECT_HERE',
secret: 'YOUR_TOKEN_SECRET_HERE',
})
- On the command line, run the file with
sanity exec populateSmartlingSecrets.js --with-user-token
. Verify that everything went well by using Vision in the studio to query*[_id == 'translationService.secrets']
. (NOTE: If you have multiple datasets, you'll have to do this across all of them, since it's a document!) - If everything looks good, go ahead and delete
populateSmartlingSecrets.js
so you don't commit it. Because the document's_id
is on a path (translationService
), it won't be exposed to the outside world, even in a public dataset. If you have concerns about this being exposed to authenticated users of your studio, you can control access to this path with role-based access control.
- Now it's time to get the Smartling tab on your desired document type, using whatever pattern you like. You'll use the desk structure for this. The options for translation will be nested under this desired document type's views. Here's an example:
import S from '@sanity/desk-tool/structure-builder'
//...your other desk structure imports...
import { TranslationsTab, defaultDocumentLevelConfig } from 'sanity-plugin-studio-smartling'
export const getDefaultDocumentNode = (props) => {
if (props.schemaType === 'myTranslatableDocumentType') {
return S.document().views([
S.view.form(),
//...my other views -- for example, live preview, the i18n plugin, etc.,
S.view.component(TranslationsTab).title('Smartling').options(
defaultDocumentLevelConfig
)
])
}
return S.document();
};
And that should do it!
By adding the TranslationsTab
to your desk structure, your users should now have an additional view. The boxes at the top of the tab can be used to send translations off to Smartling, and once those jobs are started, they should see progress bars monitoring the progress of the jobs. They can import a partial or complete job back.
To personalize this configuration it's useful to know what arguments go into TranslationsTab
as options (the defaultConfigs
are just wrappers for these):
exportForTranslation
: a function that takes your document id and returns an object withname
: the field you want to use identify your doc in Smartling (by default this is_id
andcontent
: a serialized HTML string of all the fields in your document to be translated.importTranslation
: a function that takes inid
(your document id)localeId
(the locale of the imported language) anddocument
the translated HTML from Smartling. It will deserialize your document back into an object that can be patched into your Sanity data, and then executes that patch.Adapter
: An interface with methods to send things over to Smartling. You likely don't want to override this!
There are a number of reasons to override these functions. More general cases are often around ensuring documents serialize and deserialize correctly. Since the serialization fucntions are used across all our translation plugins currently, you can find some frequently encountered scenarios at their repository here, along with code examples for new config.
This plugin is in early stages. We plan on improving some of the user-facing Chrome, sorting out some quiet bugs, figuring out where things don't fail elegantly, etc. Please be a part of our development process!