When translating content into 80+ languages, not every field needs to be translated. Recently, we ran into this issue with wagtail-localize, and here is how we implemented a way to mark fields as "intentionally blank" in a Wagtail project.
Background
- we were working on a Wagtail project using wagtail-localize for translations
- the project has translation support for 80+ languages
The Problem
For most fields, being able to add translations through the Wagtail interface was exactly what we needed, but for a few fields, CMS users were looking for a different experience. One example is a link field, which has an editing interface with button text and a URL:

Most of the time, we would want to only edit the button text in a translation, and keep the link the same, which means that the editing interface for a translation might look like this:

Notice, that we translated the button text ("Learn More" to "Aprender más"), so wagtail-localize marked that field as green, and internally considered it as translated. We haven't translated the link URL field, so it's marked as yellow and considered as not translated.
At this point we'd like to keep the URL the same as in the original language (https://example.com/learn_more), so we have 2 options, neither of which is exactly what CMS users are looking for:
-
We could copy and paste the URL and save the translation. This would mark it as translated by
wagtail-localize, and it would appear green to editors. However, this approach has downsides:- The URL is not really "translated" text
- If the original URL changes (e.g., to https://example.com/more), we would need to manually update all translations, and having to update 80+ languages would be error-prone and time-consuming
-
Alternatively, we could leave the URL field blank, which means that in translated pages the URL will fall back to the original (https://example.com/learn_more) value. If the original URL changes (for example, to https://example.com/more), all translations will fall back to the new updated value. However,
-
this means that we get used to a workflow where some fields are purposely left blank,
wagtail-localizethinks they need to be translated, gives us a warning when we publish the translation, and we get used to ignoring the warning. This makes it less likely that we would pay attention when a field was actually missed.
- we also keep track of the number of fields that are translated for each language, and this scenario makes those statistics less accurate, as "80% translated" might mean 80% on one page, but actually 100% on another page, depending on the number of fields intentionally left blank.
-
this means that we get used to a workflow where some fields are purposely left blank,
Instead, we wanted a way to:
- use the URL from the original page, and
- have
wagtail-localizeconsider the link URL field as not needing translation
After checking the wagtail-localize documentation, GitHub issues, and pull requests, and not finding support for this feature, we built wagtail-localize-intentional-blanks as a library that can be used with wagtail-localize to allow a field to be not translated, but to be considered translated by wagtail-localize.
Our Solution
User Experience
For users, wagtail-localize-intentional-blanks aims to work alongside the regular wagtail-localize workflow:
- when a page is translated, users will now see a "Mark 'Do Not Translate'" checkbox next to the "Translate" button (look in the bottom right-hand corner)

- checking the checkbox gives the field a green background, indicating that it is considered translated

- unchecking the checkbox returns it to its previous state (green if it was previously translated or yellow if it was previously untranslated)

Under The Hood
The library consists of several components working together:
Frontend (JavaScript)
- Adds "Mark 'Do Not Translate'" checkboxes next to translate buttons
- Handles API calls to the backend
- Updates field appearance based on user actions
Backend API
Two main endpoints:
- GET
/translations/{id}/status/- Check which fields are marked as 'Do Not Translate' - POST
/translations/{id}/segment/{segment_id}/do-not-translate/- Mark/unmark a field as 'Do Not Translate' - POST
/translations/{id}/toggle-all-do-not-translate/- Mark/unmark all fields for a page as 'Do Not Translate'
Core Logic
- Utility functions store a marker value (
__DO_NOT_TRANSLATE__) when marking fields - A patch to
TranslationSource._get_segments_for_translation()replaces markers with source values, so that the field's value in the original language is displayed in the template
As a result, the previously-mentioned link field can be considered translated by checking the 'Do Not Translate' checkbox.

and if the URL changes in the original language (for example, to https://example.com/more) and the user syncs the translated pages, the field will still be marked as 'Do Not Translate' and will display the new URL (https://example.com/more).

Contributing
Have questions, or want to contribute? Check out the GitHub repository: https://github.com/lincolnloop/wagtail-localize-intentional-blanks.