|
| 1 | +# Tools for using Babel with Django |
| 2 | + |
| 3 | +This package contains various utilities for integration of [Babel][] into the |
| 4 | +[Django][] web framework: |
| 5 | + |
| 6 | + * A message extraction plugin for Django templates. |
| 7 | + * A middleware class that adds the Babel `Locale` object to requests. |
| 8 | + * A set of template tags for date and number formatting. |
| 9 | + |
| 10 | + |
| 11 | +## Extracting Messages |
| 12 | + |
| 13 | +Babel provides a message extraction framework similar to GNU `xgettext`, but |
| 14 | +more extensible and geared towards Python applications. While Django does |
| 15 | +provide [wrapper scripts][Django_i18n] for making the use of `xgettext` more |
| 16 | +convenient, the extraction functionality is rather limited. For example, you |
| 17 | +can't use template files with an extension other than `.html`, and everything |
| 18 | +needs to be in your project package directory. |
| 19 | + |
| 20 | +### Extraction Method Mapping |
| 21 | + |
| 22 | +So BabelDjango comes with an extraction method plugin that can extract |
| 23 | +localizable messages from Django template files. Python is supported out of the |
| 24 | +box by Babel. To use this extraction functionality, create a file called |
| 25 | +`babel.cfg` in your project directory (the directory above your project |
| 26 | +package), with the content: |
| 27 | + |
| 28 | +```ini |
| 29 | +[django: templates/**.*] |
| 30 | +[django: mypkg/*/templates/**.*] |
| 31 | +[python: mypkg/**.py] |
| 32 | +``` |
| 33 | + |
| 34 | +This instructs Babel to look for any files in the top-level `templates` |
| 35 | +directory, or any files in application `templates` directories, and use the |
| 36 | +extraction method named “django” to extract messages from those template files. |
| 37 | +You'll need to adjust those glob patterns to wherever you my be storing your |
| 38 | +templates. |
| 39 | + |
| 40 | +Also, any files with the extension `.py` inside your package directory (replace |
| 41 | +“mypkg” with the actual name of your Django project package) are processed by |
| 42 | +the “python” extraction method. |
| 43 | + |
| 44 | +If you don't use setuptools, or for some reason haven't installed BabelDjango |
| 45 | +using setuptools/pip, you'll need to define what function the extraction method |
| 46 | +“django” maps to. This is done in an extra section at the top of the |
| 47 | +configuration file: |
| 48 | + |
| 49 | +```ini |
| 50 | +[extractors] |
| 51 | +django = babeldjango.extract:extract_django |
| 52 | +``` |
| 53 | + |
| 54 | +The encoding of the templates is assumed to be UTF-8. If you are using a |
| 55 | +different encoding, you will need to specify it in the configuration. For |
| 56 | +example: |
| 57 | + |
| 58 | +```ini |
| 59 | +[django: templates/**.*] |
| 60 | +encoding = iso-8859-1 |
| 61 | +``` |
| 62 | + |
| 63 | +### Running the Extraction Process |
| 64 | + |
| 65 | +Once you've set up the configuration file, the actual extraction is performed |
| 66 | +by executing the command-line program `pybabel` which is installed alongside |
| 67 | +the Babel package: |
| 68 | + |
| 69 | +```bash |
| 70 | +$ cd projectdir |
| 71 | +$ pybabel extract -F babel.cfg -o mypkg/locale/django.pot . |
| 72 | +``` |
| 73 | + |
| 74 | +This creates the PO file template in `mypkg/locale/django.pot`. |
| 75 | + |
| 76 | +### Creating and Updating Translations Catalogs |
| 77 | + |
| 78 | +If you don't already have translation catalogs, you need to create them. This |
| 79 | +is done using the `pybabel init` command: |
| 80 | + |
| 81 | +```bash |
| 82 | +$ pybabel init -D django -i mypkg/locale/django.pot -d mypkg/locale -l en_US |
| 83 | +$ pybabel init -D django -i mypkg/locale/django.pot -d mypkg/locale -l de_DE |
| 84 | +``` |
| 85 | + |
| 86 | +This should create two files: `mypkg/locale/en_US/django.po` and |
| 87 | +`mypkg/locale/de_DE/django.po`. These files are where you put the actual |
| 88 | +translations. |
| 89 | + |
| 90 | +When you modify your Python source files or your templates, you genereally need |
| 91 | +to sync the translation catalogs. For that, you first perform a fresh |
| 92 | +extraction as described in the previous section, so that the `django.pot` file |
| 93 | +gets updated. |
| 94 | + |
| 95 | +Then, you run the `pybabel update` command to merge the changes into the |
| 96 | +translation catalogs: |
| 97 | + |
| 98 | +```bash |
| 99 | +$ pybabel update -D django -i mypkg/locale/django.pot -d mypkg/locale |
| 100 | +``` |
| 101 | + |
| 102 | +This will update all the `.po` files found in the `mypkg/locale` directory. |
| 103 | + |
| 104 | +### Compiling Translations Catalogs |
| 105 | + |
| 106 | +Finally, you need to compile those `.po` files to binary `.mo` files. Use the |
| 107 | +`pybabel compile` command for that: |
| 108 | + |
| 109 | +```bash |
| 110 | +$ pybabel compile -D django -d mypkg/locale |
| 111 | +``` |
| 112 | + |
| 113 | +Add the `--statistics` option to get information about the completeness of your |
| 114 | +translations: |
| 115 | + |
| 116 | +```bash |
| 117 | +$ pybabel compile -D django -d mypkg/locale --statistics |
| 118 | +``` |
| 119 | + |
| 120 | +### Using `setup.py` |
| 121 | + |
| 122 | +Much of the above process can be automated if you add a `setup.py` script to |
| 123 | +your project and use the distutils/setuptools commands that come with Babel. |
| 124 | +This is described at [Distutils/Setuptools Integration][setup]. |
| 125 | + |
| 126 | + |
| 127 | +## Using the Middleware |
| 128 | + |
| 129 | +To use the Babel middleware, add it to the list of `MIDDLEWARE_CLASSES` in your |
| 130 | +settings module. If you're also using Django's own `LocaleMiddleware` to vary |
| 131 | +the locale based on user preference, the Babel middleware must be inserted |
| 132 | +after the Django one: |
| 133 | + |
| 134 | +```python |
| 135 | +MIDDLEWARE_CLASSES = ( |
| 136 | + ... |
| 137 | + 'django.middleware.locale.LocaleMiddleware', |
| 138 | + 'babeldjango.middleware.LocaleMiddleware', |
| 139 | + ... |
| 140 | +) |
| 141 | +``` |
| 142 | + |
| 143 | +This adds a `locale` attribute to the request object, which is an instance of |
| 144 | +the Babel `Locale` class. You can access the locale via `request.locale` when |
| 145 | +the request object is available, or otherwise use the |
| 146 | +`babeldjango.middleware.get_current_locale()` function to get the current |
| 147 | +locale from a thread-local cache. |
| 148 | + |
| 149 | + |
| 150 | +## Using the Template Tags |
| 151 | + |
| 152 | +The template filters provided by BabelDjango allow formatting of date/time and |
| 153 | +number values in a locale-sensitive manner, providing much more powerful |
| 154 | +alternatives to the `date`, `time`, and `floatformat` filters that come with |
| 155 | +Django. |
| 156 | + |
| 157 | +To make the template filters/tags available, you need to add BabelDjango to |
| 158 | +the list of `INSTALLED_APPS` in your settings module: |
| 159 | + |
| 160 | +```python |
| 161 | +INSTALLED_APPS = ( |
| 162 | + ... |
| 163 | + 'babeldjango', |
| 164 | + ... |
| 165 | +) |
| 166 | +``` |
| 167 | + |
| 168 | +And in every template you want to use the filters, you need to explicitly load |
| 169 | +the BabelDjango library: |
| 170 | + |
| 171 | +```jinja |
| 172 | +{% load babel %} |
| 173 | +``` |
| 174 | + |
| 175 | +General information on date/time and number formatting can be found at |
| 176 | +[Date Formatting][Dates] and [Number Formatting][Numbers]. |
| 177 | + |
| 178 | +The following filters are made available. The examples assume a locale of |
| 179 | +`en_US`. |
| 180 | + |
| 181 | +### `datefmt` |
| 182 | + |
| 183 | +Renders a string representation of a date. |
| 184 | + |
| 185 | +* __Input__: `datetime.date`, `datetime.datetime`, or a float/int timestamp |
| 186 | +* __Parameters__: the format name or pattern (optional) |
| 187 | + |
| 188 | +Assuming that `book.pubdate` returns a `datetime.date` or `datetime.datetime` |
| 189 | +object: |
| 190 | + |
| 191 | +```jinja |
| 192 | +{{ book.pubdate|datefmt:"short" }} |
| 193 | +``` |
| 194 | + |
| 195 | +would render: **4/1/07**, and |
| 196 | + |
| 197 | +```jinja |
| 198 | +{{ book.pubdate|datefmt:"E, MMM dd yyyy GGG" }} |
| 199 | +``` |
| 200 | + |
| 201 | +would render: **Sun, Apr 01 2007 AD** |
| 202 | + |
| 203 | +### `datetimefmt` |
| 204 | + |
| 205 | +Renders a string representation of a date and time. |
| 206 | + |
| 207 | +* __Input__: `datetime.datetime`, or a float/int timestamp |
| 208 | +* __Parameters__: the format name or pattern (optional) |
| 209 | + |
| 210 | +Examples: |
| 211 | +```jinja |
| 212 | +{{ book.pubdate|datetimefmt:"short" }} |
| 213 | +``` |
| 214 | + |
| 215 | +would render: **4/1/07 3:30 PM**, and |
| 216 | + |
| 217 | +```jinja |
| 218 | +{{ book.pubdate|datetimefmt:"E, MMM dd yyyy GGG' - 'HH:mm:ss'" }} |
| 219 | +``` |
| 220 | + |
| 221 | +would render: **Sun, Apr 01 2007 AD - 15:30:00** |
| 222 | + |
| 223 | +### `timefmt` |
| 224 | + |
| 225 | +Renders a string representation of a time. |
| 226 | + |
| 227 | +* __Input__: `datetime.datetime`, `datetime.time`, or a float/int timestamp |
| 228 | +* __Parameters__: the format name or pattern (optional) |
| 229 | + |
| 230 | +Examples: |
| 231 | + |
| 232 | +```jinja |
| 233 | +{{ book.pubdate|timefmt:"short" }} |
| 234 | +``` |
| 235 | + |
| 236 | +would render: **3:30 PM**, and |
| 237 | + |
| 238 | +```jinja |
| 239 | +{{ book.pubdate|timefmt:"h 'o''clock' a'" }} |
| 240 | +``` |
| 241 | + |
| 242 | +would render: **3 o'clock PM** |
| 243 | + |
| 244 | +### `decimalfmt` |
| 245 | + |
| 246 | +Renders a string representation of a decimal number. |
| 247 | + |
| 248 | +* __Input__: a `Decimal` object, or a float/int/long value |
| 249 | +* __Parameters__: the format name or pattern (optional) |
| 250 | + |
| 251 | +Examples: |
| 252 | + |
| 253 | +```jinja |
| 254 | +{{ book.pagecount|decimalfmt }} |
| 255 | +``` |
| 256 | + |
| 257 | +would render: **1,234**, and |
| 258 | + |
| 259 | +```jinja |
| 260 | +{{ book.pagecount|decimalfmt:"#,##0.00" }} |
| 261 | +``` |
| 262 | + |
| 263 | +would render: **1,234.00** |
| 264 | + |
| 265 | +### `currencyfmt` |
| 266 | + |
| 267 | +Renders a number formatted as a currency value. |
| 268 | + |
| 269 | +* __Input__: a `Decimal` object, or a float/int/long value |
| 270 | +* __Parameters__: the currency code |
| 271 | + |
| 272 | +Examples: |
| 273 | + |
| 274 | +```jinja |
| 275 | +{{ book.price|currencyfmt:"USD" }} |
| 276 | +``` |
| 277 | + |
| 278 | +would render: **$49.90** |
| 279 | + |
| 280 | +### `percentfmt` |
| 281 | + |
| 282 | +Renders a string representation of a number as a percentage. |
| 283 | + |
| 284 | +* __Input__: a `Decimal` object, or a float/int/long value |
| 285 | +* __Parameters__: the format name or pattern (optional) |
| 286 | + |
| 287 | +Examples: |
| 288 | + |
| 289 | +Assuming `book.rebate` would return `0.15`, |
| 290 | + |
| 291 | +```jinja |
| 292 | +{{ book.rebate|percentfmt }} |
| 293 | +``` |
| 294 | + |
| 295 | +would render **15%**, and |
| 296 | + |
| 297 | +```jinja |
| 298 | +{{ book.rebate|percentfmt:"#,##0.00%" }} |
| 299 | +``` |
| 300 | + |
| 301 | +would render **15.00%**. |
| 302 | + |
| 303 | +### `scientificfmt` |
| 304 | + |
| 305 | +Renders a string representation of a number using scientific notation. |
| 306 | + |
| 307 | +* __Input__: a `Decimal` object, or a float/int/long value |
| 308 | +* __Parameters__: none |
| 309 | + |
| 310 | +Examples: |
| 311 | + |
| 312 | +Assuming `book.numsold` would return 1.000.000, |
| 313 | + |
| 314 | +```jinja |
| 315 | +{{ book.numsold|scientificfmt }} |
| 316 | +``` |
| 317 | + |
| 318 | +would render **10E5**. |
| 319 | + |
| 320 | + |
| 321 | + |
| 322 | +[Babel]: http://babel.pocoo.org/ |
| 323 | +[Django]: https://www.djangoproject.com/ |
| 324 | +[Django_i18n]: https://docs.djangoproject.com/en/dev/topics/i18n/translation/#localization-how-to-create-language-files |
| 325 | +[Setup]: http://babel.pocoo.org/docs/setup/ |
| 326 | +[Dates]: http://babel.pocoo.org/docs/dates/ |
| 327 | +[Numbers]: http://babel.pocoo.org/docs/numbers/ |
0 commit comments