# Extensions and Custom Syntax

Extensible plugin system for adding custom template syntax, processing logic, and integration with external tools. Includes built-in extensions for internationalization, loop controls, expression statements, and debugging.

## Capabilities

### Extension Base Class

Base class for implementing custom template extensions with hooks for preprocessing, parsing, and code generation.

```python { .api }
class Extension:
    def __init__(self, environment):
        """
        Initialize extension.
        
        Parameters:
            environment: Jinja2 environment instance
        """
    
    def bind(self, environment):
        """
        Bind extension to different environment.
        
        Parameters:
            environment: New Jinja2 environment instance
            
        Returns:
            Extension: New extension instance bound to environment
        """
    
    def preprocess(self, source, name, filename=None):
        """
        Preprocess template source before parsing.
        
        Parameters:
            source: Template source code
            name: Template name
            filename: Template filename
            
        Returns:
            str: Preprocessed template source
        """
    
    def filter_stream(self, stream):
        """
        Filter token stream before parsing.
        
        Parameters:
            stream: Token stream iterator
            
        Returns:
            Iterator: Filtered token stream
        """
    
    def parse(self, parser):
        """
        Parse extension tags and return AST nodes.
        
        Parameters:
            parser: Jinja2 parser instance
            
        Returns:
            Node: AST node for extension functionality
        """
    
    def attr(self, name, lineno=None):
        """
        Create extension attribute node.
        
        Parameters:
            name: Attribute name
            lineno: Line number for debugging
            
        Returns:
            Node: Attribute access AST node
        """
    
    def call_method(self, name, args=None, kwargs=None, dyn_args=None, dyn_kwargs=None, lineno=None):
        """
        Create extension method call node.
        
        Parameters:
            name: Method name
            args: Method arguments
            kwargs: Method keyword arguments
            dyn_args: Dynamic arguments
            dyn_kwargs: Dynamic keyword arguments
            lineno: Line number for debugging
            
        Returns:
            Node: Method call AST node
        """
```

### Internationalization Extension

Built-in extension for internationalization and localization support using gettext-style translation functions.

```python { .api }
class InternationalizationExtension(Extension):
    """
    Extension for internationalization support.
    
    Adds:
        - {% trans %}...{% endtrans %} blocks for translatable text
        - {% pluralize %} for plural forms within trans blocks
        - Automatic message extraction for translation tools
    
    Usage:
        env = Environment(extensions=['jinja2.ext.i18n'])
        env.install_gettext_translations(translations)
    """
```

Usage example:

```python
from jinja2 import Environment
import gettext

# Setup translations
translations = gettext.translation('messages', 'locale', languages=['es'])

env = Environment(extensions=['jinja2.ext.i18n'])
env.install_gettext_translations(translations)

template_str = '''
{% trans %}Hello World!{% endtrans %}
{% trans count=items|length %}
There is {{ count }} item.
{% pluralize %}
There are {{ count }} items.
{% endtrans %}
'''
```

### Expression Statement Extension

Extension that adds the `{% do %}` tag for executing expressions without output.

```python { .api }
class ExprStmtExtension(Extension):
    """
    Extension that adds {% do %} tag for expression statements.
    
    Adds:
        - {% do expression %} for executing expressions without output
        - Useful for variable assignments and side effects
    
    Usage:
        env = Environment(extensions=['jinja2.ext.do'])
    """
```

Usage example:

```python
from jinja2 import Environment

env = Environment(extensions=['jinja2.ext.do'])

template_str = '''
{% set items = [] %}
{% do items.append('first') %}
{% do items.extend(['second', 'third']) %}
Items: {{ items | join(', ') }}
'''
```

### Loop Controls Extension

Extension that adds `{% break %}` and `{% continue %}` statements for loop control.

```python { .api }
class LoopControlsExtension(Extension):
    """
    Extension that adds loop control statements.
    
    Adds:
        - {% break %} to exit loops early
        - {% continue %} to skip to next loop iteration
    
    Usage:
        env = Environment(extensions=['jinja2.ext.loopcontrols'])
    """
```

Usage example:

```python
from jinja2 import Environment

env = Environment(extensions=['jinja2.ext.loopcontrols'])

template_str = '''
{% for item in items %}
    {% if item is number and item < 0 %}
        {% continue %}
    {% endif %}
    {% if item is string and item == 'STOP' %}
        {% break %}
    {% endif %}
    Item: {{ item }}
{% endfor %}
'''
```

### Debug Extension

Extension that adds the `{% debug %}` tag for debugging template context and variables.

```python { .api }
class DebugExtension(Extension):
    """
    Extension that adds {% debug %} tag for template debugging.
    
    Adds:
        - {% debug %} to print current template context
        - Useful for development and troubleshooting
    
    Usage:
        env = Environment(extensions=['jinja2.ext.debug'])
    """
```

Usage example:

```python
from jinja2 import Environment

env = Environment(extensions=['jinja2.ext.debug'])

template_str = '''
User: {{ user.name }}
{% debug %}
Age: {{ user.age }}
'''
```

### Extension Loading

Extensions can be loaded by name or class when creating environments.

```python { .api }
# Load by string name
env = Environment(extensions=['jinja2.ext.i18n', 'jinja2.ext.do'])

# Load by class
from jinja2.ext import InternationalizationExtension, ExprStmtExtension
env = Environment(extensions=[InternationalizationExtension, ExprStmtExtension])

# Add after environment creation
env.add_extension('jinja2.ext.loopcontrols')
env.add_extension(DebugExtension)
```

## Custom Extension Development

### Basic Custom Extension

Example of creating a custom extension that adds a `{% cache %}` tag:

```python
from jinja2 import nodes
from jinja2.ext import Extension

class CacheExtension(Extension):
    tags = {'cache'}  # Tags handled by this extension
    
    def parse(self, parser):
        lineno = next(parser.stream).lineno
        
        # Parse cache key
        cache_key = parser.parse_expression()
        
        # Parse optional timeout
        timeout = None
        if parser.stream.current.test('name:for'):
            next(parser.stream)  # consume 'for'
            timeout = parser.parse_expression()
        
        # Parse body
        node = parser.parse_statements(['name:endcache'], drop_needle=True)
        
        # Create cache node
        return self.call_method('_cache_support', 
                              [cache_key, timeout, nodes.List(node)],
                              lineno=lineno)
    
    def _cache_support(self, cache_key, timeout, body):
        """Runtime cache support method."""
        # Implementation would check cache, render if needed, store result
        cache = getattr(self.environment, '_cache', {})
        
        if cache_key in cache:
            return cache[cache_key]
        
        # Render body and cache result
        result = ''.join(body)
        cache[cache_key] = result
        
        if not hasattr(self.environment, '_cache'):
            self.environment._cache = cache
            
        return result

# Usage
env = Environment(extensions=[CacheExtension])
template_str = '''
{% cache 'expensive_computation' for 300 %}
    {{ expensive_function() }}
{% endcache %}
'''
```

### Advanced Extension Features

Extensions can modify parsing behavior, add global functions, and integrate with the compilation process:

```python
class AdvancedExtension(Extension):
    def __init__(self, environment):
        super().__init__(environment)
        # Add global functions
        environment.globals['custom_func'] = self.custom_function
    
    def preprocess(self, source, name, filename=None):
        # Modify source before parsing
        return source.replace('[[', '{%').replace(']]', '%}')
    
    def filter_stream(self, stream):
        # Modify token stream
        for token in stream:
            if token.type == 'name' and token.value == 'old_keyword':
                token = token._replace(value='new_keyword')
            yield token
    
    def custom_function(self, *args, **kwargs):
        """Custom global function available in templates."""
        return f"Custom: {args} {kwargs}"
```

## Utility Functions

```python { .api }
def babel_extract(fileobj, keywords, comment_tags, options):
    """
    Babel message extraction function for i18n extension.
    
    Parameters:
        fileobj: File-like object containing template source
        keywords: Extraction keywords
        comment_tags: Comment tags to extract
        options: Extraction options
        
    Returns:
        Iterator: Extracted messages with line numbers and context
    """
```

## Types

```python { .api }
class ExtensionEnvironment:
    """
    Extension execution environment providing access to parsing and compilation context.
    
    Attributes:
        environment: Jinja2 environment instance
        parser: Current parser instance (during parsing)
        compiler: Current compiler instance (during compilation)
    """

class ExtensionRegistry:
    """
    Registry for managing loaded extensions and their capabilities.
    
    Attributes:
        extensions: Dictionary of loaded extension instances
        tags: Set of all registered tag names
    """
```