8

I want to use django i18n support to translate my javascript files. I have the following javascript file:

var test_text = gettext('example');

@withStyles(styles)
export default class HomePage {
  static contextTypes = {
    i18n: PropTypes.object
  }

  constructor() {
    this.componentDidMount.bind(this);
    this.handleCitySearch.bind(this);
  }

  render() {
    return (
      <Grid className="HomePage">
        <Row className="HomePage-hero">
          <Col md={8} style={{ textAlign: 'center' }}>
            <Input ref="city" bsSize="large" type="text" />
            <Button bsSize="large" bsStyle="default" onClick={this.handleCitySearch}>{gettext('button text')}</Button>
          </Col>
          <Col md={4}>
            <ul>
              <li>{gettext('SOME TEXT')}</li>
              <li>{gettext('MORE TEXT')}</li>
            </ul>
          </Col>
        </Row>
      </Grid>
      );
  }
}

Now I run djangos makemessages command:

python manage.py makemessages -l de -d djangojs -v 3 -s

I would expect that the created translation file has four entries ('example', 'button text', 'SOME TEXT', and 'MORE TEXT'), because gettext appears three times in the js file. But the created locale file has only two entry for "example":

#: ../HomePage.js:1
msgid "example"
msgstr ""

#: ../HomePage.js:25
msgid "MORE TEXT"
msgstr ""

I also get this warning. But have no clue what it means (the file has only 32 lines)

HomePage.js:33: warning: RegExp literal terminated too early

Does anyone know why django ignores the other entries? Maybe it's because I use the jsx syntax or because I use es6 classes?

UPDATE:

I found out that this is not a problem of django but of xgettext. Django calls xgettext with the following command:

xgettext  --language=JavaScript --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=pgettext:1c,2 --keyword=npgettext:1c,2,3 --output=- --from-code=UTF-8 --add-comments=Translators  ../HomePage.js

So is there any xgettext expert who can help me?

ilse2005
  • 11,189
  • 5
  • 51
  • 75

3 Answers3

1

I tried this with the latest version of Django (1.10.3). It seemed to work just fine. Can you upgrade your Django version?

The code that worked for me is here: https://github.com/guitarmanvt/stackoverflow-question-32403632

Also, bear in mind that your JavaScript function gettext needs to be defined somewhere. When last I looked, there were several JavaScript i18n libraries out there, but not many played well with xgettext and Django. You may have to roll your own.

Alternatively, take a look at how Sentry does i18n with JSX. https://blog.sentry.io/2016/01/07/react-i18n.html

Happy translating!

John Anderson
  • 484
  • 4
  • 7
0

The django version I used previously is 1.5.6, it can extract keywords from .js perfectly. But it throw errors after upgrading to 1.11.15. E.g warning: unterminated string literal, warning: RegExp literal terminated too early

After much time I dig out the fact: The makemessages.py changed after upgrading. The file is located in /usr/lib/python2.7/site-packages/django/core/management/commands/makemessages.py, both 1.5.6 and 1.11.15.

In 1.5.6, the flow of makemessage is : 1. use prepare_js_for_gettext form django.utils.jslex to pre-processing js files into content that conforms to C language syntax 2. write content to .c file 3. use xgettext extract keywords from .c file and specify language to C

But in 1.11.15, it is: 1. detect xgettext version, if greater than 1.18.3, use xgettext process js file directly, or process like 1.5.6

The error I got is caused by a bug in xgettext processing js files.

So I just return True line: 77 and all working as before

    # django/core/management/commands/makemessages.py
    def is_templatized(self):
        if self.domain == 'djangojs':
            return True
            # return self.command.gettext_version < (0, 18, 3)
        elif self.domain == 'django':
            file_ext = os.path.splitext(self.translatable.file)[1]
            return file_ext != '.py'
        return False

Maybe you can try this tick or rewrite an script

user10475870
  • 91
  • 2
  • 5
0

I'm few years late to the party, but in case anyone finds this helpful...

You are correct, xgettext --language=JavaScript doesn't seem to like ES6/JSX.

Using a simple utility such as the one shown in this article rather than letting makemessages/xgettext parse your ES6/JSX files directly might help.

Alternatively there are node packages such as gettext-extractor which can be used to write a .pot file to msgmerge into your djangojs.po files... I run a node script using that library (and gettext-extractor-vue for my particular use case) to write frontend/messages.pot, then this:

./manage.py makemessages $LANGUAGE_FLAGS $IGNORE_FLAGS
./manage.py makemessages -d djangojs $LANGUAGE_FLAGS $IGNORE_FLAGS
for LANGUAGE in ${LANGUAGES[*]}
do
  PO_PATH=locale/${LANGUAGE}/LC_MESSAGES/djangojs.po
  touch $PO_PATH
  msgmerge -q --previous --update $PO_PATH frontend/messages.pot
done
./manage.py compilemessages

And compilemessages then generates the appropriate .mo files including the node-extracted strings, and Django correctly serves them in /jsi18n/ catalogue requests.

DrMeers
  • 4,117
  • 2
  • 36
  • 38