Angular makemessages

Registered by Thai Tran on 2015-05-29

This blueprint has been superseded. See the newer blueprint "Angular translation makemessages" for updated plans.

Summary:
An approach to i18n for Angular HTML templates.

Motivation:
We currently have a robust translation layer provided by Django for python, HTML templates, and javascript but none for plain HTML. As we move toward Angular templates (aka plain HTML), we need Django’s makemessages command to pick up this as well.

Description:
Before we talk about what approaches are available to us, we need to understand the currently state of things.

Translation client-side today entails listing translatable strings in the gettext function or the i18n angular module. Even using the module requires us to explicitly use the gettext keyword or equivalent in order for Django’s makemessages to pick it up.

Why do we need to explicitly use the gettext function? Django’s makemessages command basically does the following:
Search all files containing JS, HTML, or PY extensions
Passes these files to GNU gettext with options
GNU xgettext then looks for keywords and generates a PO file

So if the keyword does not match what GNU xgettext is looking for, it does not get extracted into the PO file. The next logical question is, can we specify our own keywords? The answer is YES but it may not help us. First lets take a look at our options and then we’ll come back and answer this question.

Approach 1:
<html>{$ gettext(“ singular”) $} </html>
This is the easiest approach, we treat this html file like it is a javascript and let xgettext do its work. Not sure how line breaks will factor in though. This solution requires angular to evaluate this expression each time the template gets fetch (or in the worse case, each digest cycle). This also pollutes the global space, which is something we want to avoid in Angular.

Approach 2:
<html>{% trans “string” %}</html>
This uses the existing Django template tags, but it would require this file to be a Django template, which means it requires pre-processing, not something we want. It also does not work in the static folder, as it is not a static resource. We are grouping files based on feature, which means we group HTML, JS, CSS, etc.. into the same folder. Long story short, this approach will not work for us.

Approach 3:
<trans>string</trans>
We use a trans directive to do the translation. This is essentially the same approach as angular-gettext. In fact, we can even emulate the same format as angular-gettext, but will require us to extra the texts via a different mechanism. We still require angular to evaluate this, but its confined and controlled.

Approach 4:
<html>{$ ”string” | trans $}</html>
We use trans as a filter. This approach is similar to Approach 3 with the same benefits and drawbacks. The only real difference is that one is a directive while the other is a filter. I personally prefer this syntax because its cleaner but also fine with Approach 3 since its a format that another opensource project is currently supporting.

Depending on what approach we pick, we still need a way to extract the translatable texts. As mentioned before, Django already provides a command for doing this, but it only works for JS, Django templates, and PY files. However, we can subclass this command and intercept it so it will extract other things for us. Lets examine the options we have for extracting:

Option 1:
Use the angular-gettext grunt job, this requires us to go with Approach 3. This approach will not use Django’s translation workflow, it is completely independent. Not sure if this can be hook into Django’s catalog object for client-side at all. This is also going to be a problem in the short term because the tool chain requires npm, which is something packagers are reluctant to include. Long story short, this is not going to be a viable strategy.

Option 2:
Use another python tool to extract the strings and generate an independent PO file. The advantage here is that the tool would be python based, but we would still need it to go through infra and requirements. Again, this does not use Django’s translation workflow and not guarantee to support legacy code. You can say, lets just leave the legacy stuff with legacy code and maintain 2 ways for translating client-side, but that is far from desirable.

Option 3:
Pre-process plain HTMLs and generate a temporary JS file to hold translatable texts. Before we run the makemessages command, we look for a certain pattern in our static HTML and extract the translatable texts. We then write it into a JS file wrapped by gettext so that the Django makemessages command will mark it for translation. The advantage is that we continue to use Django’s translation workflow which is guarantee to work. The down-side is that we will have to maintain this pre-processing code ourselves. Doing it this way ensures that the Django catalog object will get populated and merged correctly. Yes, merging is something we are doing at the moment. The catalog object you get today is a merged object between horizon and dashboard domain.

Option 4:
Investigate how Django is doing it using the trans and blocktrans tag. This doesn’t sound as bad if you think about it. Template tags eventually invoke some python function somewhere. Since we are intercepting the makemessages command (which is in python), we might be able to use the template tags function to do the dirty work for us. This requires further investigation but something to consider.

I have listed an exhaustive list of approaches for translation format and options for extracting them. For the record, I am not a Django or xgettext expert, so if I missed something, feel free to correct me in the comments below. The primary goal of this blueprint was to educate and inform others in the community so that we can all be on the same page. Lets have a meaningful discussion and decide on a course of action, looking forward to hearing feedback, thanks!

UX:
N/A

Outside Dependencies:
N/A

Doc Impact:
Need to update Angular translation section.

Blueprint information

Status:
Complete
Approver:
None
Priority:
High
Drafter:
Thai Tran
Direction:
Needs approval
Assignee:
Thai Tran
Definition:
Superseded
Series goal:
Accepted for liberty
Implementation:
Started
Milestone target:
None
Started by
Thai Tran on 2015-05-29
Completed by
Thai Tran on 2015-05-29

Related branches

Sprints

Whiteboard

(?)

Work Items

This blueprint contains Public information 
Everyone can see this information.

Subscribers

No subscribers.