Slide 1

Slide 1 text

A Gringo’s Guide to Internationalization Going From Green to Experto with Django’s i18n Tools. Jacob Burch @jacobburch jacobb Tuesday, September 4, 12

Slide 2

Slide 2 text

Me llamo Jacob • Engineer at Revolution Systems • Architect of CashStar Inc’s i18n efforts • 3 Years of C-Grade High School Spanish Tuesday, September 4, 12

Slide 3

Slide 3 text

Who is Cashstar? Tuesday, September 4, 12

Slide 4

Slide 4 text

Tuesday, September 4, 12

Slide 5

Slide 5 text

Internationalization 18 other characters i n s[1] + str(len(s[1:-1])) + s[-1] i18n + + Tuesday, September 4, 12

Slide 6

Slide 6 text

gettext example #: constants.py:40 msgid "Hello" msgstr "Hola" #: templates/base.html:41 templates/ login.html:12 msgid "%(username)s’ Account" msgstr "Cuenta de %(username)s" Tuesday, September 4, 12

Slide 7

Slide 7 text

The Life Cycle of a Po File Tuesday, September 4, 12

Slide 8

Slide 8 text

The Life Cycle of a Po File • Wrap text in translation function calls Tuesday, September 4, 12

Slide 9

Slide 9 text

The Life Cycle of a Po File • Wrap text in translation function calls • django-admin.py makemessages Tuesday, September 4, 12

Slide 10

Slide 10 text

The Life Cycle of a Po File • Wrap text in translation function calls • django-admin.py makemessages • Deliver po file to translation service Tuesday, September 4, 12

Slide 11

Slide 11 text

The Life Cycle of a Po File • Wrap text in translation function calls • django-admin.py makemessages • Deliver po file to translation service • Receive file back Tuesday, September 4, 12

Slide 12

Slide 12 text

The Life Cycle of a Po File • Wrap text in translation function calls • django-admin.py makemessages • Deliver po file to translation service • Receive file back • django-admin.py compilemessages Tuesday, September 4, 12

Slide 13

Slide 13 text

The Life Cycle of a Po File • Wrap text in translation function calls • django-admin.py makemessages • Deliver po file to translation service • Receive file back • django-admin.py compilemessages • Fin Tuesday, September 4, 12

Slide 14

Slide 14 text

Batteries Included •LocaleMiddleware •Template tags and python methods •manage.py makemessages Tuesday, September 4, 12

Slide 15

Slide 15 text

gettext vs gettext_lazy >>> lazy_string = gettext_lazy("Hello") >>> normal_string = gettext("Hello") >>> print repr(lazy_string) # >>> print repr(normal-string) # "'Hello'" Tuesday, September 4, 12

Slide 16

Slide 16 text

gettext best practices • Almost always use gettext_lazy • If you see a in HTML or debug code, You’re trying to use a gettext_lazy proxy string too soon. • Import gettext or gettext_lazy as _ • If you need both in the same file, use _ and _lazy Tuesday, September 4, 12

Slide 17

Slide 17 text

template tags • trans for short phrases with no variables • {% trans “Hello there!” %} • blocktrans for longer phrases containing variables • blocktrans for phrases containing variables Tuesday, September 4, 12

Slide 18

Slide 18 text

using template tags • When possible, use trans • Avoid complicated blocktrans signatures • With blocktrans: whitespace matters. Keep it limited. Tuesday, September 4, 12

Slide 19

Slide 19 text

{% blocktrans user=post.comments.recent.user user_post_count=post.comments.recent.user.post s.count %} {{ user }} has {{ user_post count }} posts {% endblocktrans %} BAD Tuesday, September 4, 12

Slide 20

Slide 20 text

{% with user=post.comments.recent.user %} {% blocktrans user_post_count=user.posts.count %} {{ user }} has {{ user_post_count }} posts! {% endblocktrans %} OK {% blocktrans user_post_count=user.posts.count %} {{ user }} has {{ user_post_count }} posts!{% endblocktrans %} GOOD {% blocktrans %} {{ user }} has {{ user_post_count }} posts!{% endblocktrans %} Tuesday, September 4, 12

Slide 21

Slide 21 text

The Second, Sad Life Of a .po file Tuesday, September 4, 12

Slide 22

Slide 22 text

The Second, Sad Life Of a .po file • Get told by an non-English speaker that certain words aren’t translated Tuesday, September 4, 12

Slide 23

Slide 23 text

The Second, Sad Life Of a .po file • Get told by an non-English speaker that certain words aren’t translated • Wrap missing text in translation function calls Tuesday, September 4, 12

Slide 24

Slide 24 text

The Second, Sad Life Of a .po file • Get told by an non-English speaker that certain words aren’t translated • Wrap missing text in translation function calls • django-admin.py makemessages Tuesday, September 4, 12

Slide 25

Slide 25 text

The Second, Sad Life Of a .po file • Get told by an non-English speaker that certain words aren’t translated • Wrap missing text in translation function calls • django-admin.py makemessages • Dig through translation to find the new ones Tuesday, September 4, 12

Slide 26

Slide 26 text

The Second, Sad Life Of a .po file • Get told by an non-English speaker that certain words aren’t translated • Wrap missing text in translation function calls • django-admin.py makemessages • Dig through translation to find the new ones • Deliver po file to translation service Tuesday, September 4, 12

Slide 27

Slide 27 text

The Second, Sad Life Of a .po file • Get told by an non-English speaker that certain words aren’t translated • Wrap missing text in translation function calls • django-admin.py makemessages • Dig through translation to find the new ones • Deliver po file to translation service • Receive file back, re-compile Tuesday, September 4, 12

Slide 28

Slide 28 text

The Second, Sad Life Of a .po file • Get told by an non-English speaker that certain words aren’t translated • Wrap missing text in translation function calls • django-admin.py makemessages • Dig through translation to find the new ones • Deliver po file to translation service • Receive file back, re-compile • Have marketing ask you to change “just two words” in old translation Tuesday, September 4, 12

Slide 29

Slide 29 text

The Second, Sad Life Of a .po file • Get told by an non-English speaker that certain words aren’t translated • Wrap missing text in translation function calls • django-admin.py makemessages • Dig through translation to find the new ones • Deliver po file to translation service • Receive file back, re-compile • Have marketing ask you to change “just two words” in old translation • Find out those words are located in the database Tuesday, September 4, 12

Slide 30

Slide 30 text

The Second, Sad Life Of a .po file • Get told by an non-English speaker that certain words aren’t translated • Wrap missing text in translation function calls • django-admin.py makemessages • Dig through translation to find the new ones • Deliver po file to translation service • Receive file back, re-compile • Have marketing ask you to change “just two words” in old translation • Find out those words are located in the database • With great sadness, manually add those two words into the django.po file Tuesday, September 4, 12

Slide 31

Slide 31 text

The Second, Sad Life Of a .po file • Get told by an non-English speaker that certain words aren’t translated • Wrap missing text in translation function calls • django-admin.py makemessages • Dig through translation to find the new ones • Deliver po file to translation service • Receive file back, re-compile • Have marketing ask you to change “just two words” in old translation • Find out those words are located in the database • With great sadness, manually add those two words into the django.po file • Get told by an non-English speaker that certain words aren’t translated Tuesday, September 4, 12

Slide 32

Slide 32 text

The Second, Sad Life Of a .po file • Get told by an non-English speaker that certain words aren’t translated • Wrap missing text in translation function calls • django-admin.py makemessages • Dig through translation to find the new ones • Deliver po file to translation service • Receive file back, re-compile • Have marketing ask you to change “just two words” in old translation • Find out those words are located in the database • With great sadness, manually add those two words into the django.po file • Get told by an non-English speaker that certain words aren’t translated Tuesday, September 4, 12

Slide 33

Slide 33 text

The Second, Sad Life Of a .po file • Get told by an non-English speaker that certain words aren’t translated • Wrap missing text in translation function calls • django-admin.py makemessages • Dig through translation to find the new ones • Deliver po file to translation service • Receive file back, re-compile • Have marketing ask you to change “just two words” in old translation • Find out those words are located in the database • With great sadness, manually add those two words into the django.po file • Get told by an non-English speaker that certain words aren’t translated Tuesday, September 4, 12

Slide 34

Slide 34 text

poxx • poxx.py location/of/locale/django.po • Munges Translation to easily tell what’s been translated (and what hasn’t) • “your photo” becomes “ẏǿŭř ƥħǿŧǿ” speaker project plug time! Tuesday, September 4, 12

Slide 35

Slide 35 text

poxx and ‘canonical’ translations • poxx.py location/of/locale/django.po -c location/of/locale/canon.po • Munges all translations not found in canon.po • poxx.py location/of/locale/django.po -c location/of/locale/canon.po --diff • Creates location/of/locale/django_diff.po file, containing all translations not found in canon.po Tuesday, September 4, 12

Slide 36

Slide 36 text

django-dbgettext •python manage.py dbgettext_export • Creates new .po files containing text found in db in pre-defined model+fields Tuesday, September 4, 12

Slide 37

Slide 37 text

Let’s Dive In Deeper Tuesday, September 4, 12

Slide 38

Slide 38 text

LocaleMiddleware • The main engine behind translation. • Very “simple”: figures out which language to use, activates that language, and sets the appropriate request variables. Tuesday, September 4, 12

Slide 39

Slide 39 text

LocaleMiddleware • Language is determined by: • URL Path (new in 1.4) , then • Session code, then • User’s cookie, then • Accept-Language header, then finally • Your project’s LANGUAGE_CODE setting django.utils.translation.trans_real.get_language_from_request Tuesday, September 4, 12

Slide 40

Slide 40 text

• django.utils.translation.trans_real And You • DjangoTranslation • Utility functions: • to_language (en-us) and to_locale (en_US) Tuesday, September 4, 12

Slide 41

Slide 41 text

Advanced i18n: Multi-Tenancy class SiteSpecificLocaleMiddleware(LocaleMiddleware): """ Replaces LocaleMiddleware. Only use i18n infrastructure if our site is in settings.TRANSLATED_SITES request.site.url is set in an earlier middleware """ def process_request(self, request): site_url = request.site.url if site_url in settings.TRANSLATED_SITES: super(SiteSpecificLocaleMiddleware, self).process_request(request) else: request.LANGUAGE_CODE = settings.LANGUAGE_CODE Tuesday, September 4, 12

Slide 42

Slide 42 text

Advanced i18n: Site-specific translations class SiteSpecificLocaleMiddleware(LocaleMiddleware): """ Replaces LocaleMiddleware. Only use i18n infrastructure if our site is in settings.TRANSLATED_SITES request.site.url is set in an earlier middleware """ def process_request(self, request): site_url = request.site.url site_locale = os.path.join(SOME_PO_FILE_PATH, site_url) if os.path.isdir(site_specific_locale): site_specific_trans = _translation( site_specific_locale, request.LANGUAGE_CODE) if brand_specific_trans: curr_trans = getattr(_active, 'value', None) if curr_trans: curr_trans.merge(site_specific_trans) else: curr_trans = site_specific_trans _active.value = curr_trans Tuesday, September 4, 12

Slide 43

Slide 43 text

Why Django i18n isn’t as pleasant as it could be and perhaps we could think of improvements “sucks” sounds so mean! Tuesday, September 4, 12

Slide 44

Slide 44 text

The Future of i18n • USE_I18N? • Ability to add other non-gettext backends • Handling of dynamic translations • All contained within ticket #14974 Tuesday, September 4, 12

Slide 45

Slide 45 text

Questions? • https://github.com/jacobb/django_i18n_examples • https://github.com/jacobb/poxx • https://bitbucket.org/drmeers/django-dbgettext Tuesday, September 4, 12