| 16 | | The translation machinery in django uses the standard gettext module that |
|---|
| 17 | | comes as part of your Python installation. It does wrap it in it's own |
|---|
| 18 | | functions and classes to accomplish all of it's goals, but essentially it's |
|---|
| 19 | | just standard gettext machinery. |
|---|
| 20 | | |
|---|
| 21 | | So to translate strings in your source you have to make use of one of the |
|---|
| 22 | | gettext helper functions. There are essentially two ways to make use of them: |
|---|
| 23 | | |
|---|
| 24 | | - you can use the _() function that is available globally. This function will |
|---|
| 25 | | translate any string value it get's as parameter. |
|---|
| 26 | | - you can use django.utils.translation and import gettext or gettext_noop |
|---|
| 27 | | from there. gettext is identical to _() |
|---|
| 28 | | |
|---|
| 29 | | There is one important thing to know about translations: the system can only |
|---|
| 30 | | translate strings it knows about. So to know about those strings you have to |
|---|
| 31 | | mark them for translation. That is done by either calling _(), gettext() or |
|---|
| 32 | | gettext_noop() on those string constants. You can translate variable values |
|---|
| 33 | | or computed values, but the system needs to know those strings beforehand. |
|---|
| 34 | | |
|---|
| 35 | | The usual way is to build your strings by standard string interpolation and |
|---|
| 36 | | to use the gettext functions to do the actual translation of the string |
|---|
| 37 | | itself, like so:: |
|---|
| 38 | | |
|---|
| 39 | | def hello_world(request, name, site): |
|---|
| 40 | | page = _('Hello %(name)s, welcome to %(site)s!') % { |
|---|
| 41 | | 'name': name, |
|---|
| 42 | | 'site': site, |
|---|
| 43 | | } |
|---|
| 44 | | return page |
|---|
| 45 | | |
|---|
| 46 | | This short snippet shows one important thing: you shouldn't use the positional |
|---|
| 47 | | string interpolation (the one that uses %s and %d) but use the named string |
|---|
| 48 | | interpolation (the one that uses %(name)s), instead. The reason is that other |
|---|
| 49 | | languages might require a reordering of text. |
|---|
| 50 | | |
|---|
| 51 | | The other two helper functions are similar in use:: |
|---|
| 52 | | |
|---|
| 53 | | def hello_world(request, name, site): |
|---|
| 54 | | from django.utils.translation import gettext |
|---|
| 55 | | page = gettext('Hello %(name)s, welcome to %(site)s!') % { |
|---|
| 56 | | 'name': name, |
|---|
| 57 | | 'site': site, |
|---|
| 58 | | } |
|---|
| 59 | | return page |
|---|
| 60 | | |
|---|
| 61 | | The difference is, you explicitly import them. There are two important |
|---|
| 62 | | helpers: gettext and gettext_noop. gettext is just like _() - it will |
|---|
| 63 | | translate it's argument. gettext_noop is different in that it does only |
|---|
| 64 | | mark a string for inclusion into the message file but doesn't do translation. |
|---|
| 65 | | Instead the string is later translated from a variable. This comes up if you |
|---|
| 66 | | have constant strings that should be stored in the source language because |
|---|
| 67 | | they are exchanged over systems or users - like strings in a database - but |
|---|
| 68 | | should be translated at the last possible point in time, when the string |
|---|
| 69 | | is presented to the user. |
|---|
| 70 | | |
|---|
| 71 | | One special case that isn't available in other gettext usages are lazily |
|---|
| 72 | | translated strings. This is needed for stuff that you set up in your django |
|---|
| 73 | | model files - those messages are stored internally and translated on access, but |
|---|
| 74 | | not translated on storage (as that would only take the default language into account). |
|---|
| 75 | | To translate a model helptext, do the following:: |
|---|
| | 16 | The translation machinery in Django uses the standard ``gettext`` module that |
|---|
| | 17 | comes with Python. Django uses in its own functions and classes, but it uses |
|---|
| | 18 | standard ``gettext`` machinery under the hood. |
|---|
| | 19 | |
|---|
| | 20 | To translate strings in your code, use one of the ``gettext`` helper functions. |
|---|
| | 21 | There are essentially two ways to use them: |
|---|
| | 22 | |
|---|
| | 23 | * Use the ``_()`` function, which is available globally. This function |
|---|
| | 24 | translates any string value. |
|---|
| | 25 | * Use ``django.utils.translation`` and import ``gettext`` or |
|---|
| | 26 | ``gettext_noop`` from there. ``gettext`` is identical to ``_()``. |
|---|
| | 27 | |
|---|
| | 28 | Note one important thing about translations: The system can only translate |
|---|
| | 29 | strings it knows about. That means you have to mark strings for translation. |
|---|
| | 30 | This is done either by calling ``_()``, ``gettext()`` or ``gettext_noop()`` on |
|---|
| | 31 | string constants. You can translate variable values or computed values, but the |
|---|
| | 32 | system needs to know those strings beforehand. |
|---|
| | 33 | |
|---|
| | 34 | The usual method is to build your strings using string interpolation and using |
|---|
| | 35 | the ``gettext`` functions to do the actual translation. Example:: |
|---|
| | 36 | |
|---|
| | 37 | def hello_world(request, name, site): |
|---|
| | 38 | page = _('Hello %(name)s, welcome to %(site)s!') % { |
|---|
| | 39 | 'name': name, |
|---|
| | 40 | 'site': site, |
|---|
| | 41 | } |
|---|
| | 42 | return HttpResponse(page) |
|---|
| | 43 | |
|---|
| | 44 | This short snippet shows one important thing: You shouldn't use positional |
|---|
| | 45 | string interpolation (e.g., ``%s`` or ``%d``). Use the named string |
|---|
| | 46 | interpolation (e.g., ``%(name)s``), instead. Do this because other languages |
|---|
| | 47 | might require reordering of text. |
|---|
| | 48 | |
|---|
| | 49 | The other two helper functions are similar:: |
|---|
| | 50 | |
|---|
| | 51 | from django.utils.translation import gettext |
|---|
| | 52 | def hello_world(request, name, site): |
|---|
| | 53 | page = gettext('Hello %(name)s, welcome to %(site)s!') % { |
|---|
| | 54 | 'name': name, |
|---|
| | 55 | 'site': site, |
|---|
| | 56 | } |
|---|
| | 57 | return HttpResponse(page) |
|---|
| | 58 | |
|---|
| | 59 | The difference here is that ``gettext`` is explicitly imported. |
|---|
| | 60 | |
|---|
| | 61 | Two important helper functions are available: ``gettext`` and ``gettext_noop``. |
|---|
| | 62 | |
|---|
| | 63 | * ``gettext`` is just like ``_()`` -- it translates its argument. |
|---|
| | 64 | * ``gettext_noop`` is different. It marks a string for inclusion into the |
|---|
| | 65 | message file but doesn't do translation. Instead, the string is later |
|---|
| | 66 | translated from a variable. Use this if you have constant strings that |
|---|
| | 67 | should be stored in the source language because they are exchanged over |
|---|
| | 68 | systems or users -- such as strings in a database -- but should be |
|---|
| | 69 | translated at the last possible point in time, such as when the string is |
|---|
| | 70 | presented to the user. |
|---|
| | 71 | |
|---|
| | 72 | One function, ``django.utils.translation.gettext_lazy()``, isn't available in |
|---|
| | 73 | the standard ``gettext`` module. Use it for lazily translated strings, such as |
|---|
| | 74 | messages in Django models that are stored internally and translated on access |
|---|
| | 75 | -- but not translated on storage, as that would only take the default language |
|---|
| | 76 | into account. |
|---|
| | 77 | |
|---|
| | 78 | For example, to translate a model's ``help_text``, do the following:: |
|---|
| 117 | | Using translations in the templates is much like in python code. There is |
|---|
| 118 | | just a template tag that will allow you to use the same _() helper function |
|---|
| 119 | | as with your source:: |
|---|
| 120 | | |
|---|
| 121 | | <html> |
|---|
| 122 | | <title>{% i18n _('This is the title.') %}</title> |
|---|
| 123 | | <body> |
|---|
| 124 | | <p>{% i18n _('Hello %(name)s, welcome at %(site)s!') %}</p> |
|---|
| 125 | | <p>{% i18n ngettext('There is %(count)d file', 'There are %(count)d files', files|count) %}</p> |
|---|
| 126 | | </body> |
|---|
| 127 | | </html> |
|---|
| 128 | | |
|---|
| 129 | | This short snippet shows you how to do translations. You can just translate |
|---|
| 130 | | strings, but there is one speciality: the strings can contain interpolation |
|---|
| 131 | | parts. Those parts are automatically resolved from the template context, just |
|---|
| 132 | | as they would be if you had used them in {{ ... }}. But this can only resolve |
|---|
| 133 | | variables, not more complex expressions. |
|---|
| 134 | | |
|---|
| 135 | | To translate a variable value, you can just do {% i18n _(variable) %}. This |
|---|
| 136 | | can even include filters like {% i18n _(variable|lower} %}. |
|---|
| 137 | | |
|---|
| 138 | | There is additional support for i18n string constants for other situations |
|---|
| 139 | | as well. All template tags that do variable resolving (with or without filters) |
|---|
| 140 | | will accept string constants, too. Those string constants can now be i18n |
|---|
| 141 | | strings like this:: |
|---|
| 142 | | |
|---|
| 143 | | <html> |
|---|
| 144 | | <title>{{ _('This is the title') }}</title> |
|---|
| 145 | | <body> |
|---|
| 146 | | <p>{{ _('Hello World!') }}</p> |
|---|
| 147 | | </body> |
|---|
| 148 | | </html> |
|---|
| 149 | | |
|---|
| 150 | | This is much shorter, but won't allow you to use gettext_noop or ngettext. |
|---|
| 151 | | |
|---|
| 152 | | Sometimes you might want to give the user a selection of languages. This |
|---|
| 153 | | can be done by accessing the LANGUAGES variable of a DjangoContext. This |
|---|
| 154 | | is a list of tuples where the first element is the language code and the |
|---|
| 155 | | second element is the language name (in that language). The code might |
|---|
| 156 | | look like this:: |
|---|
| | 123 | Using translations in Django templates works much like translations in Python |
|---|
| | 124 | code. The ``{% i18n %}`` template tag lets you use the same ``_()`` helper |
|---|
| | 125 | function as in your Python code:: |
|---|
| | 126 | |
|---|
| | 127 | <html> |
|---|
| | 128 | <title>{% i18n _('This is the title.') %}</title> |
|---|
| | 129 | <body> |
|---|
| | 130 | <p>{% i18n _('Hello %(name)s, welcome at %(site)s!') %}</p> |
|---|
| | 131 | <p>{% i18n ngettext('There is %(count)d file', 'There are %(count)d files', files|count) %}</p> |
|---|
| | 132 | </body> |
|---|
| | 133 | </html> |
|---|
| | 134 | |
|---|
| | 135 | It's not only possible to translate hard-coded strings, but the strings can |
|---|
| | 136 | contain interpolated parts, e.g. ``%(name)s``. Those parts are automatically |
|---|
| | 137 | resolved from the template context, just as they would be if you had used them |
|---|
| | 138 | in ``{{ ... }}``. But this can only resolve variables, not more complex |
|---|
| | 139 | expressions. |
|---|
| | 140 | |
|---|
| | 141 | To translate a variable value, do this:: |
|---|
| | 142 | |
|---|
| | 143 | {% i18n _(variable) %} |
|---|
| | 144 | |
|---|
| | 145 | Filters are allowed, too:: |
|---|
| | 146 | |
|---|
| | 147 | {% i18n _(variable|lower) %} |
|---|
| | 148 | |
|---|
| | 149 | Any template tag that resolves variables accepts i18n-string constants, too. |
|---|
| | 150 | |
|---|
| | 151 | Also, note you can use ``_()`` around variable names, like so:: |
|---|
| | 152 | |
|---|
| | 153 | <html> |
|---|
| | 154 | <title>{{ _('This is the title') }}</title> |
|---|
| | 155 | <body> |
|---|
| | 156 | <p>{{ _('Hello, world!') }}</p> |
|---|
| | 157 | </body> |
|---|
| | 158 | </html> |
|---|
| | 159 | |
|---|
| | 160 | This syntax is much shorter, but it doesn't allow you to use ``gettext_noop`` |
|---|
| | 161 | or ``ngettext``. |
|---|
| | 162 | |
|---|
| | 163 | Each ``DjangoContext`` has access to two translation-specific variables: |
|---|
| | 164 | |
|---|
| | 165 | * ``LANGUAGES`` is a list of tuples in which the first element is the |
|---|
| | 166 | language code and the second is the language name (in that language). |
|---|
| | 167 | * ``LANGUAGE_CODE`` is the current user's preferred language, as a string. |
|---|
| | 168 | Example: ``en-us``. (See "How language preference is discovered", below.) |
|---|
| | 169 | |
|---|
| | 170 | The ``setlang`` redirect view |
|---|
| | 171 | ----------------------------- |
|---|
| | 172 | |
|---|
| | 173 | Django comes with a view, ``django.views.i18n.set_language`` that sets a user's |
|---|
| | 174 | language preference and redirects back to the previous page. For example, put |
|---|
| | 175 | this HTML code in your template:: |
|---|
| 167 | | This would jump to a language switcher and then be redirected back to the |
|---|
| 168 | | page it came from. The switcher page will just store the language in either |
|---|
| 169 | | the users session or a special cookie for use in the language discovery. |
|---|
| 170 | | |
|---|
| 171 | | You can leave out the "next" field. In that case the /i18n/setlang/ view |
|---|
| 172 | | will redirect to the URL that is in the "Referer" header. Please keep in mind |
|---|
| 173 | | that people might suppress that header, so in those cases there won't be a |
|---|
| 174 | | URL to redirect to - in those cases the view function will redirect to "/" |
|---|
| 175 | | as a fallback. |
|---|
| 176 | | |
|---|
| 177 | | The /i18n/setlang/ url can be set up by including the following in your |
|---|
| 178 | | ROOT_URLCONF:: |
|---|
| 179 | | |
|---|
| 180 | | urlpatterns = patterns('', |
|---|
| 181 | | (r'^i18n/', include('django.conf.urls.i18n'), |
|---|
| 182 | | ) |
|---|
| 183 | | |
|---|
| 184 | | This adds the setlang handler to your urlspace and hooks up a standard view |
|---|
| 185 | | function to it. |
|---|
| 186 | | |
|---|
| 187 | | How the Language is Discovered |
|---|
| 188 | | ============================== |
|---|
| 189 | | |
|---|
| 190 | | Django has a very flexible model of deciding what language is to be used. |
|---|
| 191 | | The first line in choice is the LANGUAGE_CODE setting in your config file. |
|---|
| 192 | | This is used as the default translation - the last try if none of the other |
|---|
| 193 | | translattors find a translation. Actually if youre requirement is just to |
|---|
| 194 | | run django with your native language, you only need to set LANGUAGE_CODE |
|---|
| 195 | | and that's it - if there is a language file for django for your language. |
|---|
| 196 | | |
|---|
| 197 | | But with web applications, users come from all over the world. So you don't |
|---|
| 198 | | want to have a single translation active, you want to decide what language to |
|---|
| 199 | | present to each and every user. This is where the LocaleMiddleware comes |
|---|
| 200 | | into the picture. You need to add it to your middleware setting. It should |
|---|
| 201 | | be one of the first middlewares installed, but it should come after the |
|---|
| 202 | | session middleware - that's because it makes uses of the session data. And |
|---|
| 203 | | it must be installed before the AdminUserRequired middleware, as that will |
|---|
| 204 | | do redirects based on not-logged-in state and so the LocaleMiddleware won't |
|---|
| 205 | | ever see the login page (and so not initialize the language correctly). |
|---|
| 206 | | |
|---|
| 207 | | So your middleware settings might look like this:: |
|---|
| | 187 | When a user submits the form, his chosen language will be saved in a cookie, |
|---|
| | 188 | and he'll be redirected either to the URL specified in the ``next`` field, or, |
|---|
| | 189 | if ``next`` is empty, to the URL in the ``Referer`` header. If the ``Referer`` |
|---|
| | 190 | is blank -- say, if a user's browser suppresses that header -- then the user |
|---|
| | 191 | will be redirected to ``/`` (the site root) as a fallback. |
|---|
| | 192 | |
|---|
| | 193 | Activate the ``setlang`` redirect view by adding the following line to your |
|---|
| | 194 | URLconf:: |
|---|
| | 195 | |
|---|
| | 196 | (r'^i18n/', include('django.conf.urls.i18n'), |
|---|
| | 197 | |
|---|
| | 198 | Note that this example makes the view available at ``/i18n/setlang/``. |
|---|
| | 199 | |
|---|
| | 200 | How language preference is discovered |
|---|
| | 201 | ===================================== |
|---|
| | 202 | |
|---|
| | 203 | Django has a very flexible model of deciding which language should be used -- |
|---|
| | 204 | installation-wide, for a particular user, or both. |
|---|
| | 205 | |
|---|
| | 206 | To set an installation-wide language preference, set ``LANGUAGE_CODE`` in your |
|---|
| | 207 | settings file. Django uses this language as the default translation -- the |
|---|
| | 208 | final attempt if no other translator finds a translation. |
|---|
| | 209 | |
|---|
| | 210 | If all you want to do is run Django with your native language, and a language |
|---|
| | 211 | file is available for your language, all you need to do is set |
|---|
| | 212 | ``LANGUAGE_CODE``. |
|---|
| | 213 | |
|---|
| | 214 | If you want to let each individual user specify which language he or she |
|---|
| | 215 | prefers, use ``LocaleMiddleware``. ``LocaleMiddleware`` enables language |
|---|
| | 216 | selection based on data from the request. It lets each user have his or her own |
|---|
| | 217 | setting. |
|---|
| | 218 | |
|---|
| | 219 | To use ``LocaleMiddleware``, add ``'django.middleware.locale.LocaleMiddleware'`` |
|---|
| | 220 | to your ``MIDDLEWARE_CLASSES`` setting. Because middleware order matters, you |
|---|
| | 221 | should follow these guidelines: |
|---|
| | 222 | |
|---|
| | 223 | * Make sure it's one of the first middlewares installed. |
|---|
| | 224 | * It should come after ``SessionMiddleware``, because ``LocaleMiddleware`` |
|---|
| | 225 | makes use of session data. |
|---|
| | 226 | |
|---|
| | 227 | For example, your ``MIDDLEWARE_CLASSES`` might look like this:: |
|---|
| 216 | | This activates the LocalMiddlware in your server (in this case it was taken |
|---|
| 217 | | from the admin.py settings file). |
|---|
| 218 | | |
|---|
| 219 | | The LocaleMiddleware allows a selection of the language based on data from |
|---|
| 220 | | the request - every user can have her own settings. |
|---|
| 221 | | |
|---|
| 222 | | The first thing the LocaleMiddleware does, it looks at the session data for the |
|---|
| 223 | | user. If that carries a key django_language, it's contents will be used as the |
|---|
| 224 | | language code. If the session doesn't contain a language setting, the |
|---|
| 225 | | middleware will look at the cookies for a django_language cookie. If that is |
|---|
| 226 | | found, it gives the language code. |
|---|
| 227 | | |
|---|
| 228 | | The format for the explicit django_language parameters is allways the |
|---|
| 229 | | language to use - for example it's pt-br for Brazilian. If a base language |
|---|
| 230 | | is available, but the sublanguage specified is not, the base language is used. |
|---|
| 231 | | For example if you specify de-at (Austrian German), but there is only a |
|---|
| 232 | | language de available, that language is used. |
|---|
| 233 | | |
|---|
| 234 | | If neither the session nor the cookie carry a language code, the middleware |
|---|
| 235 | | will look at the HTTP header Accept-Language. This header is sent by your |
|---|
| 236 | | browser and tells the server what languages you prefer. Languages are ordered |
|---|
| 237 | | by some choice value - the higher, the more you prefer the language. |
|---|
| 238 | | |
|---|
| 239 | | So the middleware will iterate over that header, ordered by the preference |
|---|
| 240 | | value. The language with the highest preference that is in the django base |
|---|
| 241 | | message file directory will be used as the language to present to the user. |
|---|
| 242 | | |
|---|
| 243 | | Since the middlware discovers the language based on the request, your app |
|---|
| 244 | | might need to know what language is selected (if only to show the flag of |
|---|
| 245 | | that language). The selected language is stored by the middleware in the |
|---|
| 246 | | request as the LANGUAGE_CODE attribute. So with static translation (when |
|---|
| 247 | | you don't use the middlware) the language is in settings.LANGUAGE_CODE, while |
|---|
| 248 | | with dynamic translations (when you do use the middleware) it's in |
|---|
| 249 | | request.LANGUAGE_CODE. And if your application builds on DjangoContext |
|---|
| 250 | | instances for template rendering, it will be automatically be available |
|---|
| 251 | | as LANGUAGE_CODE in your template (with automatic determination where to |
|---|
| 252 | | pull it from). |
|---|
| 253 | | |
|---|
| 254 | | Creating Language Files |
|---|
| | 235 | ``LocaleMiddleware`` tries to determine the user's language preference by |
|---|
| | 236 | following this algorithm: |
|---|
| | 237 | |
|---|
| | 238 | * First, it looks for a ``django_language`` key in the the current user's |
|---|
| | 239 | session. |
|---|
| | 240 | * Failing that, it looks for a cookie called ``django_language``. |
|---|
| | 241 | * Failing that, it looks at the ``Accept-Language`` HTTP header. This |
|---|
| | 242 | header is sent by your browser and tells the server which language(s) you |
|---|
| | 243 | prefer, in order by priority. Django tries each language in the header |
|---|
| | 244 | until it finds one with available translations. |
|---|
| | 245 | * Failing that, it uses the global ``LANGUAGE_CODE`` setting. |
|---|
| | 246 | |
|---|
| | 247 | Notes: |
|---|
| | 248 | |
|---|
| | 249 | * In each of these places, the language preference is expected to be in the |
|---|
| | 250 | standard language format, as a string. For example, Brazilian is |
|---|
| | 251 | ``pt-br``. |
|---|
| | 252 | * If a base language is available but the sublanguage specified is not, |
|---|
| | 253 | Django uses the base language. For example, if a user specifies ``de-at`` |
|---|
| | 254 | (Austrian German) but Django only has ``de`` available, Django uses |
|---|
| | 255 | ``de``. |
|---|
| | 256 | |
|---|
| | 257 | Once ``LocaleMiddleware`` determines the user's preference, it makes this |
|---|
| | 258 | preference available as ``request.LANGUAGE_CODE`` for each `request object`_. |
|---|
| | 259 | Feel free to read this value in your view code. Here's a simple example:: |
|---|
| | 260 | |
|---|
| | 261 | def hello_world(request, count): |
|---|
| | 262 | if request.LANGUAGE_CODE == 'de-at': |
|---|
| | 263 | return HttpResponse("You prefer to read Austrian German.") |
|---|
| | 264 | else: |
|---|
| | 265 | return HttpResponse("You prefer to read another language.") |
|---|
| | 266 | |
|---|
| | 267 | Note that, with static (middleware-less) translation, the language is in |
|---|
| | 268 | ``settings.LANGUAGE_CODE``, while with dynamic (middleware) translation, it's |
|---|
| | 269 | in ``request.LANGUAGE_CODE``. |
|---|
| | 270 | |
|---|
| | 271 | .. _request object: http://www.djangoproject.com/documentation/request_response/#httprequest-objects |
|---|
| | 272 | |
|---|
| | 273 | Creating language files |
|---|
| 257 | | So now you have tagged all your strings for later translation. But you need |
|---|
| 258 | | to write the translations themselves. They need to be in a format grokable |
|---|
| 259 | | by gettext. You need to update them. You may need to create new ones for new |
|---|
| 260 | | languages. This will show you how to do it. |
|---|
| 261 | | |
|---|
| 262 | | The first step is to create a message file for a new language. This can |
|---|
| 263 | | be created with a tool delivered with django. To run it on the django |
|---|
| 264 | | source tree (best from a subversion checkout), just go to the django-Directory |
|---|
| 265 | | itself. Not the one you checked out, but the one you linked to your |
|---|
| 266 | | $PYTHONPATH or the one that's localted somewhere on that path. |
|---|
| 267 | | |
|---|
| 268 | | That directory includes a subdirectory conf, and that a directory locale. The |
|---|
| 269 | | tools to do translations are in the django/bin directory. The first tool |
|---|
| 270 | | to use is make-messages.py - this tool will run over the whole source tree |
|---|
| 271 | | and pull out all strings marked for translation. |
|---|
| 272 | | |
|---|
| 273 | | To run it, just do the following:: |
|---|
| 274 | | |
|---|
| 275 | | bin/make-messages.py -l de |
|---|
| 276 | | |
|---|
| 277 | | This will create or update the german message file. This file is located |
|---|
| 278 | | at conf/locale/de/LC_MESSAGES/django.po - this file can be directly edited |
|---|
| 279 | | with your favorite editor. You need to first edit the charset line - search |
|---|
| 280 | | for CHARSET and set it to the charset you will use to edit the content. It |
|---|
| 281 | | might be that it is utf-8 - if you prefer another encoding, you can use some |
|---|
| 282 | | tools like recode or iconv to change the charset of the file and then change |
|---|
| 283 | | the charset definition in the file (it's in the Content-Type: line). |
|---|
| 284 | | |
|---|
| 285 | | The language code for storage is in locale format - so it is pt_BR for |
|---|
| 286 | | Brazilian or de_AT for Austrian German. |
|---|
| 287 | | |
|---|
| 288 | | If you don't have the gettext utilities installed, make-messages.py will create |
|---|
| 289 | | empty files. If that is the case, either install the gettext utilities, or |
|---|
| 290 | | just copy the conf/locale/en/LC_MESSAGES/django.po and start with that - it's just |
|---|
| 291 | | an empty translation file. |
|---|
| 292 | | |
|---|
| 293 | | Every message in the message file is of the same format. One line is the msgid. |
|---|
| 294 | | This is the actual string in the source - you don't change it. The other line |
|---|
| 295 | | is msgstr - this is the translation. It starts out empty. You change it. |
|---|
| 296 | | |
|---|
| 297 | | There is one speciality for long messages: there the first string directly |
|---|
| 298 | | after the msgstr (or msgid) is an emtpy string. Then the content itself will |
|---|
| 299 | | be written over the next few lines as one string per line. Those strings |
|---|
| 300 | | are directly concatenated - don't forget trailing spaces within the strings, |
|---|
| 301 | | otherwise they will be tacked together without whitespace! |
|---|
| 302 | | |
|---|
| 303 | | After you created your message file you need to transform it into some more |
|---|
| 304 | | efficient form to read by gettext. This is done with the second tool, that's |
|---|
| 305 | | compile-messages.py. This tool just runs over all available .po files and |
|---|
| 306 | | turns them into .mo files. Run it as follows:: |
|---|
| | 276 | So, you've tagged all of your strings for later translation. But you need to |
|---|
| | 277 | write the translations themselves. |
|---|
| | 278 | |
|---|
| | 279 | They need to be in a format grokable by ``gettext``. You need to update them. |
|---|
| | 280 | You may need to create new ones for new languages. This section shows you how |
|---|
| | 281 | to do it. |
|---|
| | 282 | |
|---|
| | 283 | Creating message files |
|---|
| | 284 | ---------------------- |
|---|
| | 285 | |
|---|
| | 286 | The first step is to create a message file for a new language. Django comes |
|---|
| | 287 | with a tool, ``make-messages.py``, that automates this. |
|---|
| | 288 | |
|---|
| | 289 | To run it on the Django source tree, navigate to the ``django`` directory |
|---|
| | 290 | itself -- not a Subversion check out, but the one linked to via ``$PYTHONPATH`` |
|---|
| | 291 | or located somewhere on that path. |
|---|
| | 292 | |
|---|
| | 293 | Then run this command:: |
|---|
| | 294 | |
|---|
| | 295 | bin/make-messages.py -l de |
|---|
| | 296 | |
|---|
| | 297 | ...where ``de`` is the language code for the message file you want to create. |
|---|
| | 298 | |
|---|
| | 299 | This script runs over the entire Django source tree and pulls out all strings |
|---|
| | 300 | marked for translation, creating or updating the language's message file. |
|---|
| | 301 | |
|---|
| | 302 | When it's done, it will have created (or updated) a message file under the |
|---|
| | 303 | directory ``conf/locale``. In this example, the file will be |
|---|
| | 304 | ``conf/locale/de/LC_MESSAGES/django.po``. |
|---|
| | 305 | |
|---|
| | 306 | If you don't have the ``gettext`` utilities installed, ``make-messages.py`` |
|---|
| | 307 | will create empty files. If that's the case, either install the ``gettext`` |
|---|
| | 308 | utilities or just copy the English message file |
|---|
| | 309 | (``conf/locale/en/LC_MESSAGES/django.po``) and use it as a starting point; it's |
|---|
| | 310 | just an empty translation file. |
|---|
| | 311 | |
|---|
| | 312 | Once you've created the ``.po`` file, edit the file with your favorite text |
|---|
| | 313 | editor. First, edit the charset line (search for ``"CHARSET"``) and set it to |
|---|
| | 314 | the charset you'll be using to edit the content. Then, proceed to write your |
|---|
| | 315 | translations. |
|---|
| | 316 | |
|---|
| | 317 | The language code for storage is in locale format -- so it's ``pt_BR`` for |
|---|
| | 318 | Brazilian and ``de_AT`` for Austrian German. |
|---|
| | 319 | |
|---|
| | 320 | Every message in the message file is in the same format: |
|---|
| | 321 | |
|---|
| | 322 | * One line is the msgid. This is the actual string in the source. Don't |
|---|
| | 323 | change it. |
|---|
| | 324 | * The other line is msgstr. This is the translation. It starts out empty. |
|---|
| | 325 | You change it. |
|---|
| | 326 | |
|---|
| | 327 | Long messages are a special case. There, the first string directly after the |
|---|
| | 328 | msgstr (or msgid) is an empty string. Then the content itself will be written |
|---|
| | 329 | over the next few lines as one string per line. Those strings are directly |
|---|
| | 330 | concatenated. Don't forget trailing spaces within the strings; otherwise, |
|---|
| | 331 | they'll be tacked together without whitespace! |
|---|
| | 332 | |
|---|
| | 333 | Compiling message files |
|---|
| | 334 | ----------------------- |
|---|
| | 335 | |
|---|
| | 336 | After you create your message file, you'll need to transform it into a more |
|---|
| | 337 | efficient form to be read by ``gettext``. Do this with the |
|---|
| | 338 | ``compile-messages.py`` utility. This tool runs over all available ``.po`` |
|---|
| | 339 | files and creates ``.mo`` files. Run it like this:: |
|---|
| 321 | | Of course you want to make use of the translations in your own projects, too. |
|---|
| 322 | | This is very simple with django, as django looks in several locations for |
|---|
| 323 | | message files. The base path in your django distribution is only the last |
|---|
| 324 | | place to look for translations. Before that, django looks first into your |
|---|
| 325 | | application directory (actually in the application directory of the view |
|---|
| 326 | | function that is about to be called!) for message files. If there is one for |
|---|
| 327 | | the selected language, it will be installed. After that django looks into the |
|---|
| 328 | | project directory for message files. If there is one for the selected language, |
|---|
| 329 | | it will be installed after the app-specific one. And only then comes the |
|---|
| 330 | | base translation. |
|---|
| 331 | | |
|---|
| 332 | | That way you can write applications that bring their own translations with |
|---|
| 333 | | them and you can override base translations in your project path if you |
|---|
| 334 | | want to do that. Or you can just build a big project out of several apps |
|---|
| 335 | | and put all translations into one big project message file. The choice is |
|---|
| 336 | | yours. All message file repositories are structured the same. They are: |
|---|
| 337 | | |
|---|
| 338 | | - $APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo) |
|---|
| 339 | | - $PROJECTPATH/locale/<language>/LC_MESSAGES/django.(po|mo) |
|---|
| 340 | | - all paths listed in LOCALE_PATHS in your settings file are |
|---|
| 341 | | searched in that order for <language>/LC_MESSAGES/django.(po|mo) |
|---|
| 342 | | - $PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo) |
|---|
| 343 | | |
|---|
| 344 | | Actually the appliaction doesn't need to be stored below the project path - |
|---|
| 345 | | django uses module introspection to find the right place where your application |
|---|
| 346 | | is stored. It only needs to be listed in your INSTALLED_APPS setting. |
|---|
| 347 | | |
|---|
| 348 | | To create message files, you use the same make-messages.py tool as with the |
|---|
| 349 | | django message files. You only need to be in the right place - in the directory |
|---|
| 350 | | where either the conf/locale (in case of the source tree) or the locale/ |
|---|
| | 354 | Of course, your own projects should make use of translations. Django makes this |
|---|
| | 355 | simple, because it looks for message files in several locations. |
|---|
| | 356 | |
|---|
| | 357 | Django looks for translations by following this algorithm: |
|---|
| | 358 | |
|---|
| | 359 | * First, it looks for a ``locale`` directory in the application directory |
|---|
| | 360 | of the view that's being called. If it finds a translation for the |
|---|
| | 361 | selected language, the translation will be installed. |
|---|
| | 362 | * Next, it looks for a ``locale`` directory in the project directory. If it |
|---|
| | 363 | finds a translation, the translation will be installed. |
|---|
| | 364 | * Finally, it checks the base translation in ``django/conf/locale``. |
|---|
| | 365 | |
|---|
| | 366 | This way, you can write applications that include their own translations, and |
|---|
| | 367 | you can override base translations in your project path if you want to do that. |
|---|
| | 368 | Or, you can just build a big project out of several apps and put all |
|---|
| | 369 | translations into one big project message file. The choice is yours. |
|---|
| | 370 | |
|---|
| | 371 | All message file repositories are structured the same way. They are: |
|---|
| | 372 | |
|---|
| | 373 | * ``$APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)`` |
|---|
| | 374 | * ``$PROJECTPATH/locale/<language>/LC_MESSAGES/django.(po|mo)`` |
|---|
| | 375 | * all paths listed in ``LOCALE_PATHS`` in your settings file are |
|---|
| | 376 | searched in that order for ``<language>/LC_MESSAGES/django.(po|mo)`` |
|---|
| | 377 | * ``$PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)`` |
|---|
| | 378 | |
|---|
| | 379 | To create message files, you use the same ``make-messages.py`` tool as with the |
|---|
| | 380 | Django message files. You only need to be in the right place -- in the directory |
|---|
| | 381 | where either the ``conf/locale`` (in case of the source tree) or the ``locale/`` |
|---|
| 374 | | If you know gettext, you might see some specialities with the way django does |
|---|
| 375 | | translations. For one, the string domain is allways django. The string domain |
|---|
| 376 | | is used to differentiate between different programs that store their stuff |
|---|
| 377 | | in a common messagefile library (usually /usr/share/locale/). In our case there |
|---|
| 378 | | are django-specific locale libraries and so the domain itself isn't used. We |
|---|
| 379 | | could store app message files with different names and put them for example |
|---|
| 380 | | in the project library, but decided against this: with message files in the |
|---|
| 381 | | application tree, they can more easily be distributed. |
|---|
| 382 | | |
|---|
| 383 | | Another speciality is that we only use gettext and gettext_noop - that's |
|---|
| 384 | | because django uses allways DEFAULT_CHARSET strings internally. There isn't |
|---|
| 385 | | much use in using ugettext or something like that, as you allways will need to |
|---|
| 386 | | produce utf-8 anyway. |
|---|
| 387 | | |
|---|
| 388 | | And last we don't use xgettext alone and some makefiles but use python |
|---|
| 389 | | wrappers around xgettext and msgfmt. That's mostly for convenience. |
|---|
| 390 | | |
|---|
| | 407 | If you know ``gettext``, you might note these specialities in the way Django |
|---|
| | 408 | does translation: |
|---|
| | 409 | |
|---|
| | 410 | * The string domain is always ``django``. The string domain is used to |
|---|
| | 411 | differentiate between different programs that store their data in a |
|---|
| | 412 | common messagefile library (usually ``/usr/share/locale/``). In Django's |
|---|
| | 413 | case, there are Django-specific locale libraries, so the domain itself |
|---|
| | 414 | isn't used. We could store app message files with different names and put |
|---|
| | 415 | them, say, in the project library, but we decided against this. With |
|---|
| | 416 | message files in the application tree, apps can be distributed more |
|---|
| | 417 | easily. |
|---|
| | 418 | * Django only uses ``gettext`` and ``gettext_noop``. That's because Django |
|---|
| | 419 | always uses ``DEFAULT_CHARSET`` strings internally. There isn't much use |
|---|
| | 420 | in using ``ugettext``, because you'll always need to produce utf-8 |
|---|
| | 421 | anyway. |
|---|
| | 422 | * Django doesn't use ``xgettext`` alone. It uses Python wrappers around |
|---|
| | 423 | ``xgettext`` and ``msgfmt``. That's mostly for convenience. |
|---|