title |
---|
Localization |
We use Phrase to manage translations of both "generic" form strings and content specific to each form. There are a couple of different workflows to be aware of:
- Translate generic strings
- Update generic string translations
- Translate a specific form
- Manually adding translations
But first, it's important to understand how the whole thing works!
There are a bunch of moving pieces involved in coordinating translations between form.io, Phrase, and our theme:
-
The formio.js library that we extend and patch with this theme uses a localization tool called [i18next], and passes most of the "strings" (individual chunks of text content, like the text of the "Next" and "Previous" buttons, or the label of each form component) through its translation function,
t()
. -
Formio.js accepts an
i18n
option that can include translations. Its shape is an object with language codes at the top level, and translations below. To translate the "Next" button text in page navigation to Spanish, we would pass:{ es: { Next: 'Siguiente' } }
-
In our templates we call the
t()
function with automatically generated IDs ("keys") for each unique string. The naming scheme is the component's key and the "path" of the string within the component, separated by.
. For instance, the string ID for the label of a component with the keyemail
would beemail.label
. Thecontent
field of an HTML elementintro
could be localized with theintro.content
string. -
We patch several of the third-party libraries that formio.js uses to render more complex components:
-
We import the Spanish and Chinese translations of Flatpickr directly to localize date and time pickers. These are not customizable right now.
-
We patch the
customOptions
of each autocomplete component to translate UI strings in Choices.js.
-
- Translate the strings in the generic strings Phrase project
- Ask somebody with access to this repo to pull the new translations (see below)
- Install the Phrase CLI tools
- Check out this repo
- Set
PHRASE_ACCESS_TOKEN
in your local environment (i.e. in.env
) - Run
script/phrase pull
to get the new strings - If
git diff src/i18n
shows a diff, then commit the changes and publish a new release
Before you can translate a form, you'll need to do some one-time setup in both Phrase and the form.io portal:
-
Create a new Phrase project in the SF Digital Services workspace
-
Open the More ⌄ menu in the project navigation and select Project Settings
-
Select the API menu item on the left, and copy the Project ID:
-
Edit your form in the form.io portal, and
-
Click the gear icon in the form navigation to edit its settings:
-
In the Custom Properties section, add a new entry with
phraseProjectId
in the "Key" field and the Phrase project ID that you copied in the "Value" field: -
Visit /api/strings?formUrl=
<URL>
where<URL>
is your form.io data source URL -
Save the JSON to your computer
-
Upload the JSON to your Phrase project:
-
Under the More ⌄ menu, select Upload file
-
Click Choose file and find the JSON file that you just saved
-
Choose
i18next (.json)
from the Format menu -
Under Language, type
en
in the field under Use existing language -
Click the Upload button
-
Confirm that strings were loaded and click on Translate imported keys to view them:
- Visit
https://formio-sfds.herokuapp.com/api/translate?url=<URL>
, where<URL>
is the URL of your form on sf.gov - When the form loads, you should see a modal dialog to log in to Phrase
Once you've logged in, you should see a blue bar across the bottom and pencil icon markers above each piece of translatable form content:
Translation updates can be packaged up in a "release" by adding or updating the form's phraseProjectVersion
custom property (in the same place that you added phraseProjectId
above):
Please use semantic versioning conventions to track the types of changes:
- Patch versions (
1.0.0
→1.0.1
) for translation updates and other "fixes", like spelling - Minor versions (
1.0.1
→1.1.0
) when new keys and/or translations are added - Major versions (
1.0.0
→2.0.0
) when keys are deleted
Because of how automatically generated translation keys (the unique IDs of each translatable string) are generated automatically and how the API that "extracts" strings from each form works, there may be some situations that call for manually adding strings in Phrase. Here are some tips:
-
First, try adding a string with a key in the form
{component}.{path}
, where{component}
is the component key and{path}
is the "path" of the component field that you're trying to translate:label
,description
, etc. -
If that doesn't work, please file an issue!
-
If your form has been heavily modified on form.io, it's possible that string keys no longer map to the right components. Try re-generating the form strings and importing the JSON into Phrase again.
-
If all else fails, you should still be able to add keys for the English string and translate those. For instance, if a bug is preventing the label of a field with the label "Your address" from translating, you should still be able to target it by adding translations for a "Your address" Phrase key.
When in doubt, drop into #topic-translations on Slack and ask for help! 💪