some documentation updates
authorArmin Ronacher <armin.ronacher@active-4.com>
Wed, 7 May 2008 06:42:11 +0000 (08:42 +0200)
committerArmin Ronacher <armin.ronacher@active-4.com>
Wed, 7 May 2008 06:42:11 +0000 (08:42 +0200)
--HG--
branch : trunk

12 files changed:
docs/_static/style.css
docs/_templates/layout.html
docs/_templates/search.html
docs/api.rst
docs/extensions.rst [new file with mode: 0644]
docs/index.rst
docs/integration.rst [new file with mode: 0644]
docs/intro.rst
docs/templates.rst
jinja2/environment.py
jinja2/ext.py
tests/test_i18n.py

index 41877f705ccc6052d1fd847d9903f817540251eb..3cce344962c2885accae6e8a1700c611ac13cbd0 100644 (file)
@@ -81,17 +81,6 @@ h1.heading span {
     display: none;
 }
 
-h2.subheading {
-    margin: -55px 0 35px 200px;
-    font-weight: normal;
-    font-size: 30px;
-    color: #444;
-}
-
-h2.plain {
-    margin: 0;
-}
-
 #jinjalogo {
     background-image: url(jinjalogo.png);
     background-repeat: no-repeat;
@@ -108,15 +97,15 @@ h2.plain {
     background: url(watermark_blur.png) -120px -114px;
 }
 
-#contentwrapper h3,
-#contentwrapper h3 a {
-    color: #b41717;
-    font-size: 26px;
-    margin: 20px 0 0 -5px;
+#contentwrapper h2,
+#contentwrapper h2 a {
+    color: #222;
+    font-size: 24px;
+    margin: 20px 0 0 0;
 }
 
-#contentwrapper h4,
-#contentwrapper h4 a {
+#contentwrapper h3,
+#contentwrapper h3 a {
     color: #b41717;
     font-size: 20px;
     margin: 20px 0 0 0;
@@ -324,3 +313,24 @@ dt .descclassname {
 dl dt big {
     font-size: 100%;
 }
+
+ul.search {
+    margin: 10px 0 0 30px;
+    padding: 0;
+}
+
+ul.search li {
+    margin: 10px 0 0 0;
+    padding: 0;
+}
+
+ul.search div.context {
+    font-size: 12px;
+    padding: 4px 0 0 20px;
+    color: #888;
+}
+
+span.highlight {
+    background-color: #eee;
+    border: 1px solid #ccc;
+}
index 0e803083477ce71c1008a1208ed290309c0ef008..c2add7d8624b02c3948cccbdb10b5d73ab2e5e09 100644 (file)
@@ -41,6 +41,7 @@
     {%- if prev %}
     <link rel="prev" title="{{ prev.title|striptags }}" href="{{ prev.link|e }}">
     {%- endif %}
+    {% block extrahead %}{% endblock %}
   </head>
   <body>
     <div id="content">
index 82a78d04dc006415582ff6b8226b029afcb45f5a..ab93b75c2ac6a1de01e603e7daf7db278ebd0c6f 100644 (file)
     function will automatically search for all of the words. Pages
     containing less words won't appear in the result list.
   </p>
-  <form action="" method="get">
-    <input type="text" name="q" value="" />
-    <input type="submit" value="search" />
-  </form>
+  <form action="" method="get"><p>
+    <input type="text" name="q" value="">
+    <input type="submit" value="search">
+  </p></form>
   {% if search_performed %}
     <h2>Search Results</h2>
     {% if not search_results %}
index 0b33a43ff1b6fa6864f0be237955aaadd1918a20..24e27103c75eaaa72d61d2ece51104b9d6fa054d 100644 (file)
@@ -47,8 +47,8 @@ To render it with some variables, just call the :meth:`render` method::
 High Level API
 --------------
 
-.. autoclass:: jinja2.environment.Environment
-    :members: from_string, get_template, join_path, overlay
+.. autoclass:: jinja2.environment.Environment([options])
+    :members: from_string, get_template, join_path, parse
 
     .. attribute:: shared
 
@@ -83,17 +83,28 @@ High Level API
         overridden by templates.  As long as no template was loaded it's safe
         to modify this dict.  For more details see :ref:`global-namespace`.
 
+    .. automethod:: overlay([options])
+
 
 .. autoclass:: jinja2.Template
-    :members: render, stream, generate, make_module, module
+    :members: make_module, module, new_context
 
     .. attribute:: globals
 
-        foo
+        The dict with the globals of that template.  It's unsafe to modify
+        this dict as it may be shared with other templates or the environment
+        that loaded the template.
 
     .. attribute:: name
 
-        foo
+        The loading name of the template.  If the template was loaded from a
+        string this is `None`.
+
+    .. automethod:: render([context])
+
+    .. automethod:: generate([context])
+
+    .. automethod:: stream([context])
 
 
 .. autoclass:: jinja2.environment.TemplateStream
diff --git a/docs/extensions.rst b/docs/extensions.rst
new file mode 100644 (file)
index 0000000..3ad4914
--- /dev/null
@@ -0,0 +1,88 @@
+.. _jinja-extensions:
+
+Extensions
+==========
+
+.. module:: jinja2.ext
+
+Jinja2 supports extensions that can add extra filters, tests, globals or even
+extend the parser.  The main motivation of extensions is it to move often used
+code into a reusable class like adding support for internationalization.
+
+
+Adding Extensions
+-----------------
+
+Extensions are added to the Jinja2 environment at creation time.  Once the
+environment is created additional extensions cannot be added.  To add an
+extension pass a list of extension classes or import paths to the
+`environment` parameter of the :class:`Environment` constructor.  The following
+example creates a Jinja2 environment with the i18n extension loaded::
+
+    jinja_env = Environment(extensions=['jinja.ext.i18n'])
+
+
+Built-in Extensions
+-------------------
+
+.. _i18n-extension:
+
+i18n
+~~~~
+
+The i18n extension can be used in combination with `gettext`_ or `babel`_.
+If the i18n extension is enabled Jinja2 provides a `trans` statement that
+marks the wrapped string as translatable and calls `gettext`.
+
+After enabling dummy `_`, `gettext` and `ngettext` functions are added to
+the template globals.  A internationalized application has to override those
+methods with more useful versions.
+
+For a web application that is available in multiple languages but gives all
+the users the same language (for example a multilingual forum software
+installed for a French community) may load the translations once and add the
+translation methods to the environment at environment generation time::
+
+    translations = get_gettext_translations()
+    env = Environment(extensions=['jinja.ext.i18n'])
+    env.globals.update(
+        gettext=translations.ugettext,
+        ngettext=translations.ungettext
+    )
+
+The `get_gettext_translations` function would return the translator for the
+current configuration.  Keep in mind that Jinja2 uses unicode internally so
+you must pass the `ugettext` and `ungettext` functions to the template.
+
+The default `_` function injected by the extension calls `gettext`
+automatically.
+
+If you want to pass the gettext function into the context at render time
+because you don't know the language/translations earlier and the optimizer
+is enabled (which it is per default), you have to unregister the `gettext`
+and `ugettext` functions first::
+
+    del env.globals['gettext'], env.globals['ugettext']
+
+Jinja2 also provides a way to extract recognized strings.  For one the
+`jinja.ext` module provides a function that can return all the occurences
+of gettext calls in a node (as returned by :meth:`Environment.parse`):
+
+.. autofunction:: extract_from_ast
+
+If `babel`_ is installed :ref:`the babel integration <babel-integration>`
+can be used to.
+
+The usage of the `i18n` extension for template designers is covered as part
+:ref:`of the template documentation <i18n-in-templates>`.
+
+
+.. _gettext: http://docs.python.org/dev/library/gettext
+.. _babel: http://babel.edgewall.org/
+
+.. _writing-extensions:
+
+Writing Extensions
+------------------
+
+TODO
index a6c8bf88794cd1291e49f3e3823fd15918fbe7c9..eb442cbfd18b877d41315cc69ed70ad3a677fc8d 100644 (file)
@@ -11,7 +11,13 @@ fast and secure.
    intro
    api
    templates
+   extensions
+   integration
 
    changelog
 
+If you can't find the information you're looking for, have a look at the
+index of try to find it using the search function:
+
 * :ref:`genindex`
+* :ref:`search`
diff --git a/docs/integration.rst b/docs/integration.rst
new file mode 100644 (file)
index 0000000..e5c2cb7
--- /dev/null
@@ -0,0 +1,68 @@
+Integration
+===========
+
+Jinja2 provides some code for integration into other tools such as frameworks,
+the `Babel`_ library or your favourite editor for fancy code highlighting.
+This is a brief description of whats included.
+
+.. _babel-integration:
+
+Babel Integration
+-----------------
+
+Jinja provides support for extracting gettext messages from templates via a
+`Babel`_ extractor entry point called `jinja2.ext.babel_extract`.  The Babel
+support is implemented as part of the :ref:`i18n-extension` extension.
+
+Gettext messages extracted from both `trans` tags and code expressions.
+
+To extract gettext messages from templates, the project needs a Jinja2 section
+in its Babel extraction method `mapping file`_:
+
+.. sourcecode:: ini
+
+    [jinja: **/templates/**.html]
+    encoding = utf-8
+
+The syntax related options of the :class:`Environment` are also available as
+configuration values in the mapping file.  For example to tell the extraction
+that templates use ``%`` as `line_statement_prefix` you can use this code:
+
+.. sourcecode:: ini
+
+    [jinja: **/templates/**.html]
+    encoding = utf-8
+    line_statement_prefix = %
+
+:ref:`jinja-extensions` may also be defined by passing a comma separated list
+of import paths as `extensions` value.  The i18n extension is added
+automatically.
+
+.. _mapping file: http://babel.edgewall.org/wiki/Documentation/messages.html#extraction-method-mapping-and-configuration
+
+Django
+------
+
+TODO
+
+Pylons
+------
+
+TODO
+
+WSGI
+----
+
+TODO
+
+TextMate
+--------
+
+TODO
+
+Vim
+---
+
+TODO
+
+.. _Babel: http://babel.edgewall.org/
index 981401c9aa22eb3f2a04ee91de1a38ba07809c2d..e1d07eb7dd9b186a1e1c1e046caeb5eed5cf4aef 100644 (file)
@@ -13,7 +13,7 @@ useful for templating environments.
 The key-features are...
 
 -   ... **configurable syntax**.  If you are generating LaTeX or other formats
-    with Jinja you can change the delimiters to something that integrates better
+    with Jinja2 you can change the delimiters to something that integrates better
     into the LaTeX markup.
 
 -   ... **fast**.  While performance is not the primarily target of Jinja2 it's
@@ -21,7 +21,7 @@ The key-features are...
     to the very minimum.
 
 -   ... **easy to debug**.  Jinja2 integrates directly into the python traceback
-    system which allows you to debug Jinja templates with regular python
+    system which allows you to debug Jinja2 templates with regular python
     debugging helpers.
 
 -   ... **secure**.  It's possible to evaluate untrusted template code if the
@@ -39,10 +39,62 @@ C-compiler is available the `ctypes`_ module should be installed.
 .. _ctypes: http://python.net/crew/theller/ctypes/
 
 
+Installation
+------------
+
+You have multiple ways to install Jinja2.  If you are unsure what to do, go
+with the Python egg or tarball.
+
+As a Python egg (via easy_install)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can install the most recent Jinja2 version using `easy_install`_::
+
+    sudo easy_install Jinja2
+
+This will install a Jinja2 egg in your Python installation's site-packages
+directory.
+
+From the tarball release
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1.  Download the most recent tarball from the `download page`_
+2.  Unpack the tarball
+3.  ``sudo python setup.py install``
+
+Note that the last command will automatically download and install
+`setuptools`_ if you don't already have it installed. This requires a working
+internet connection.
+
+This will install Jinja2 into your Python installation's site-packages directory.
+
+Installing the development version
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1.  Install `mercurial`_
+2.  ``svn co http://dev.pocoo.org/hg/jinja2-main jinja2``
+3.  ``cd jinja2``
+4.  ``ln -s jinja2 /usr/lib/python2.X/site-packages``
+
+As an alternative to steps 4 you can also do ``python setup.py develop``
+which will install the package via setuptools in development mode.  This also
+has the advantage that the C extensions are compiled.
+
+Alternative you can use `easy_install`_ to install the current development
+snapshot::
+
+    sudo easy_install Jinja2==dev
+
+.. _download page: http://jinja.pocoo.org/2/download
+.. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools
+.. _easy_install: http://peak.telecommunity.com/DevCenter/EasyInstall
+.. _mercurial: http://www.selenic.com/mercurial/
+
+
 Basic API Usage
 ---------------
 
-This section gives you a brief introduction to the Python API for Jinja templates.
+This section gives you a brief introduction to the Python API for Jinja2 templates.
 
 The most basic way to create a template and render it is through
 :class:`Template`.  This however is not the recommended way to work with it,
index 615884a2d553aba7eb8e558d9b2457ee83f6b0d7..d7a0f914487229bf7ecdac55083e384c43533023 100644 (file)
@@ -928,7 +928,77 @@ The following functions are available in the global scope by default:
     is disabled regular text is returned.  This is useful to generate simple
     contents for layout testing.
 
-.. function:: dict(**items)
+.. function:: dict(\**items)
 
     A convenient alternative to dict literals.  ``{'foo': 'bar'}`` is the same
     as ``dict(foo='bar')``.
+
+
+Extensions
+----------
+
+The following sections cover the built-in Jinja2 extensions that may be
+enabled by the application.  The application could also provide further
+extensions not covered by this documentation.  In that case there should
+be a separate document explaining the extensions.
+
+.. _i18n-in-templates:
+
+i18n
+~~~~
+
+If the i18n extension is enabled it's possible to mark parts in the template
+as translatable.  To mark a section as translatable you can use `trans`::
+
+    <p>{% trans %}Hello {{ user }}!{% endtrans %}</p>
+
+To translate a template expression --- say, using template filters or just
+accessing an attribute of an object --- you need to bind the expression to a
+name for use within the translation block::
+
+    <p>{% trans user=user.username %}Hello {{ user }}!{% endtrans %}</p>
+
+If you need to bind more than one expression inside a `trans` tag, separate
+the pieces with a comma (``,``)::
+
+    {% trans book_title=book.title, author=author.name %}
+    This is {{ book_title }} by {{ author }}
+    {% endtrans %}
+
+Inside trans tags no statements are allowed, only variable tags are.
+
+To pluralize, specify both the singular and plural forms with the `pluralize`
+tag, which appears between `trans` and `endtrans`::
+
+    {% trans count=list|length %}
+    There is {{ count }} {{ name }} object.
+    {% pluralize %}
+    There are {{ count }} {{ name }} objects.
+    {% endtrans %}
+
+Per default the first variable in a block is used to determine the correct
+singular or plural form.  If that doesn't work out you can specify the name
+which should be used for pluralizing by adding it as parameter to `pluralize`::
+
+    {% trans ..., user_count=users|length %}...
+    {% pluralize user_count %}...{% endtrans %}
+
+It's also possible to translate strings in expressions.  For that purpose
+three functions exist:
+
+_   `gettext`: translate a single string
+-   `ngettext`: translate a pluralizable string
+-   `_`: alias for `gettext`
+
+For example you can print a translated string easily this way::
+
+    {{ _('Hello World!') }}
+
+To use placeholders you can use the `format` filter::
+
+    {{ _('Hello %(user)s!')|format(user=user.username) }}
+        or
+    {{ _('Hello %s')|format(user.username) }}
+
+For multiple placeholders always use keyword arguments to `format` as other
+languages may not use the words in the same order.
index 92ab578d395fdfb63f57586462e51ad209931fc6..23e77b6dac2323d455cf267591110e80f4aa0254 100644 (file)
@@ -112,7 +112,8 @@ class Environment(object):
 
         `extensions`
             List of Jinja extensions to use.  This can either be import paths
-            as strings or extension classes.
+            as strings or extension classes.  For more information have a
+            look at :ref:`the extensions documentation <jinja-extensions>`.
 
         `optimized`
             should the optimizer be enabled?  Default is `True`.
@@ -282,6 +283,9 @@ class Environment(object):
         tree of nodes is used by the compiler to convert the template into
         executable source- or bytecode.  This is useful for debugging or to
         extract information from templates.
+
+        If you are :ref:`developing Jinja2 extensions <writing-extensions>`
+        this gives you a good overview of the node tree generated.
         """
         try:
             return Parser(self, source, filename).parse()
index c35a9c28d68f2a2ab0b0dccb340d7f52ad7b6474..5d2251d09387c40ef7b2fcb4d050d528832fe3aa 100644 (file)
@@ -15,7 +15,7 @@ from jinja2 import nodes
 from jinja2.environment import get_spontaneous_environment
 from jinja2.runtime import Undefined, concat
 from jinja2.exceptions import TemplateAssertionError, TemplateSyntaxError
-from jinja2.utils import import_string, Markup
+from jinja2.utils import contextfunction, import_string, Markup
 
 
 # the only real useful gettext functions for a Jinja template.  Note
@@ -74,14 +74,14 @@ class CacheExtension(Extension):
         )
 
 
-class TransExtension(Extension):
+class InternationalizationExtension(Extension):
     """This extension adds gettext support to Jinja."""
     tags = set(['trans'])
 
     def __init__(self, environment):
         Extension.__init__(self, environment)
         environment.globals.update({
-            '_':        lambda x: x,
+            '_':        contextfunction(lambda c, x: c['gettext'](x)),
             'gettext':  lambda x: x,
             'ngettext': lambda s, p, n: (s, p)[n != 1]
         })
@@ -284,11 +284,11 @@ def babel_extract(fileobj, keywords, comment_tags, options):
         if not extension:
             continue
         extension = import_string(extension)
-        if extension is TransExtension:
+        if extension is InternationalizationExtension:
             have_trans_extension = True
         extensions.append(extension)
     if not have_trans_extension:
-        extensions.append(TransExtension)
+        extensions.append(InternationalizationExtension)
 
     environment = get_spontaneous_environment(
         options.get('block_start_string', '{%'),
@@ -310,3 +310,8 @@ def babel_extract(fileobj, keywords, comment_tags, options):
     node = environment.parse(fileobj.read().decode(encoding))
     for lineno, func, message in extract_from_ast(node, keywords):
         yield lineno, func, message, []
+
+
+#: nicer import names
+i18n = InternationalizationExtension
+cache = CacheExtension
index d405c9c75a62a2f1506dde53c0bd6a069a92a881..3b722835c9df54dc086282ca37e91d9910518fce 100644 (file)
@@ -46,7 +46,7 @@ def ngettext(context, s, p, n):
 
 i18n_env = Environment(
     loader=DictLoader(templates),
-    extensions=['jinja2.ext.TransExtension']
+    extensions=['jinja2.ext.i18n']
 )
 i18n_env.globals.update({
     '_':            gettext,