I can't find any programmatic interface to create page translation. All the logics seems being implemented in SubmitTranslationView
in wagtail.contrib.simple_translation.views
.
So the only way to access those programmatically is by simulating the request to access the views. I wrapped this in a function named translate_page()
. To translate a page, we can call this function as:-
page_ja = translate_page(user, page, "ja")
Or we can pass the optional parameter include_subtree
:-
page_ja = translate_page(user, page, "ja", include_subtree=True)
And the function is defined as:-
def translate_page(user, page, lang, include_subtree=False):
locale, created = Locale.objects.get_or_create(language_code=lang)
data = {"locales": [locale.id], "include_subtree": include_subtree}
url = reverse(
"simple_translation:submit_page_translation", kwargs={"page_id": page.id}
)
factory = RequestFactory()
request = factory.post(url)
request.POST = data
request.user = user
get_response = lambda request: None
middleware = SessionMiddleware(get_response)
middleware.process_request(request)
request.session.save()
messages = FallbackStorage(request)
setattr(request, "_messages", messages)
SubmitPageTranslationView.model = type(page)
SubmitPageTranslationView.as_view()(request, page_id=page.pk)
page_translated = page.get_translations()[0].specific
return page_translated
I have another function called translate_snippet()
. The only difference is just the url to submit and no include_subtree
parameter.
Page tree gotchas
For all our sites, we have a setup script that will automatically populating some posts and their translation so that developer can start working right away instead of having to create sample pages manually.
Our page structure is like this:-
HomePage ==> BlogIndexPage ==> BlogPage
And the setup script will do the following:-
- Create the root admin user, let's call it user One.
- Create instance of HomePage
- Attach HomePage as new root page
- Create Japanese translation of HomePage
- Create instance of BlogIndexPage
- Populate BlogPage with sample posts and attach them under BlogIndexPage
- Translate BlogIndexPage with
include_subtree=True
This all works well until we're setting new site where the page structure is:-
BlogIndexPage ==> BlogPage
So we omitted HomePage
(which I think a bad idea now but let's save it for another topic) since this site is mainly a blog. The first thing I notice after running the setup script is that no translation of the blog posts created, despite we already passed include_subtree
when translating BlogIndexPage.
My first gut reaction was it could be some changes in new wagtail versions. Most our sites being created few years ago and still on wagtail 5 but for this new site, we will start with wagtail 6 since it's the latest.
But looking at wagtail's commit logs for simple_translation
views.py
, the code last changes was three years ago. And we can see the code basically the same between wagtail 5 and 6.
The problem with translate_page
function above is that it doesn't check for any errors. Because catching errors mean you have to parse the request's response for some error string. But tracing the code flow lead me to a stage where I can see the code is not executed because the form is not validated.
Printing form.errors
showed error messages related to invalid locale. This is strange because we can see in the translate_page
function above we're creating the locale if it doesn't exists yet.
And printing the form's self.fields["locales"].choices
I can the locale is there in the choice during first call of translate_page()
when translating the root page, but the choices was empty when calling it second time to translate BlogIndexPage
.
Reading the form's code, locales
field's choices is set dynamically in the __init__
method, where locale of the page that already translated will be removed. This could be the reason why the locale was empty in the second call. But the page is not translated yet!
Let's recall back the process:-
- Create BlogIndexPage
- Attach BlogIndexPage to root page
- Translate root page to ja
- Populate BlogPage and attach them to BlogIndexPage
- Translate BlogIndexPage to ja
And this is where the light bulb (💡) came in, after hours of debugging. In the original script, we're translating HomePage to ja first, and then BlogIndexPage with all its children. But in this new script, the root page is BlogIndexPage. So BlogIndexPage already translated the second time we call translate_page
!
So that's the reason locales
choices become empty.
Top comments (0)