CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-django-rosetta

A Django application that facilitates the translation process of your Django projects

Pending
Overview
Eval results
Files

template-integration.mddocs/

Template Integration

Django template tags and filters for integrating Rosetta functionality into custom templates and extending the web interface. These template utilities provide access to translation permissions, formatting functions, and UI enhancements directly within Django templates.

Capabilities

Template Filters

Filters for processing and displaying translation-related data in templates.

def can_translate(user) -> bool:
    """
    Check user translation permissions in templates.
    
    Template filter that checks if a user has permission to access
    Rosetta translation functionality. Uses the same permission logic
    as the programmatic can_translate() function.
    
    Usage in templates:
    {% if user|can_translate %}
        <a href="{% url 'rosetta-file-list' %}">Translations</a>
    {% endif %}
    
    Parameters:
    - user: Django User instance
    
    Returns:
    Boolean indicating translation access permission
    """

def format_message(message: str) -> str:
    """
    Format message text with HTML escaping and line break handling.
    
    Processes translation message text for safe display in HTML templates,
    handling special characters, line breaks, and preserving formatting.
    
    Usage in templates:
    {{ message.msgstr|format_message|safe }}
    
    Parameters:
    - message: Raw message string from .po file
    
    Returns:
    HTML-safe formatted string with proper escaping and line breaks
    """

def lines_count(message: str) -> int:
    """
    Count number of lines in message text.
    
    Utility filter for determining text area sizing and layout
    decisions based on message content length.
    
    Usage in templates:
    {% if message.msgstr|lines_count > 3 %}
        <textarea rows="5">{{ message.msgstr }}</textarea>
    {% else %}
        <input type="text" value="{{ message.msgstr }}">
    {% endif %}
    
    Parameters:
    - message: Message string to count lines in
    
    Returns:
    Integer number of lines in the message
    """

def mult(value: int, multiplier: int) -> int:
    """
    Multiply two numbers in templates.
    
    Mathematical filter for template calculations where multiplication
    is needed (pagination, sizing, calculations, etc.).
    
    Usage in templates:
    {{ page_size|mult:page_number }}
    
    Parameters:
    - value: First number (base value)
    - multiplier: Second number (multiplier)
    
    Returns:
    Result of value * multiplier
    """

def minus(value: int, subtrahend: int) -> int:
    """
    Subtract two numbers in templates.
    
    Mathematical filter for template calculations where subtraction
    is needed (counting, offsets, calculations, etc.).
    
    Usage in templates:
    {{ total_entries|minus:translated_entries }}
    
    Parameters:
    - value: First number (minuend)
    - subtrahend: Second number (subtrahend)
    
    Returns:
    Result of value - subtrahend
    """

def gt(value: int, comparison: int) -> bool:
    """
    Greater than comparison in templates.
    
    Comparison filter for template conditional logic where
    greater than comparison is needed.
    
    Usage in templates:
    {% if entries_count|gt:10 %}
        <div class="pagination">...</div>
    {% endif %}
    
    Parameters:
    - value: First number to compare
    - comparison: Second number to compare against
    
    Returns:
    Boolean result of value > comparison
    """

def is_fuzzy(entry) -> bool:
    """
    Check if translation entry is marked as fuzzy.
    
    Filter for checking the fuzzy flag status of translation entries,
    used for styling and conditional display in templates.
    
    Usage in templates:
    {% if entry|is_fuzzy %}
        <span class="fuzzy-indicator">Fuzzy</span>
    {% endif %}
    
    Parameters:
    - entry: Translation entry object from .po file
    
    Returns:
    Boolean indicating whether entry is marked as fuzzy
    """

Template Tags

Custom template tags for enhanced functionality and UI components.

def increment(context, counter_name: str) -> str:
    """
    Counter increment template tag.
    
    Provides a counter that increments each time it's called within
    a template context. Useful for numbering items, generating IDs,
    or tracking iterations.
    
    Usage in templates:
    {% load rosetta %}
    {% for item in items %}
        <div id="item-{% increment 'item_counter' %}">{{ item }}</div>
    {% endfor %}
    
    Parameters:
    - context: Template context dictionary
    - counter_name: Name/key for the counter variable
    
    Returns:
    String representation of current counter value
    
    Side effects:
    - Increments counter in template context
    - Creates counter if it doesn't exist (starts at 1)
    """

class IncrNode(template.Node):
    """
    Template node implementation for increment tag.
    
    Internal implementation class for the increment template tag,
    handling counter state management and value rendering.
    """
    
    def __init__(self, counter_name: str):
        """Initialize with counter name."""
        self.counter_name = counter_name
    
    def render(self, context) -> str:
        """
        Render the current counter value and increment.
        
        Parameters:
        - context: Template context
        
        Returns:
        String representation of counter value
        """

Template Library Registration

Template library instance and variable pattern matching.

register
"""
Django template library instance for Rosetta template tags and filters.

This is the standard Django template library registration object that
makes all Rosetta template tags and filters available when you use:
{% load rosetta %}

Provides access to:
- All template filters (can_translate, format_message, etc.)
- All template tags (increment)
- Custom template functionality
"""

rx
"""
Compiled regular expression for matching Django template variables.

Used internally for processing Django template variable patterns
in translation strings, such as:
- %(variable_name)s patterns
- {variable_name} patterns
- Template-specific variable syntax

Pattern matching helps preserve variable names during translation
processing and formatting operations.
"""

Usage Examples

Basic Template Integration

<!-- Load Rosetta template tags -->
{% load rosetta %}

<!-- Check user permissions -->
{% if user|can_translate %}
    <div class="admin-tools">
        <a href="{% url 'rosetta-file-list' %}" class="btn btn-primary">
            Manage Translations
        </a>
    </div>
{% endif %}

<!-- Display translation statistics -->
<div class="translation-stats">
    <p>Translated: {{ stats.translated }}</p>
    <p>Untranslated: {{ stats.untranslated }}</p>
    <p>Remaining: {{ stats.total|minus:stats.translated }}</p>
</div>

Message Formatting in Templates

{% load rosetta %}

<!-- Format translation messages -->
<div class="translation-entry">
    <div class="original-text">
        {{ entry.msgid|format_message|safe }}
    </div>
    
    <div class="translated-text {% if entry|is_fuzzy %}fuzzy{% endif %}">
        {{ entry.msgstr|format_message|safe }}
    </div>
    
    <!-- Conditional display based on message length -->
    {% if entry.msgstr|lines_count > 3 %}
        <textarea class="translation-input" rows="{% if entry.msgstr|lines_count|gt:5 %}10{% else %}5{% endif %}">
            {{ entry.msgstr }}
        </textarea>
    {% else %}
        <input type="text" class="translation-input" value="{{ entry.msgstr }}">
    {% endif %}
</div>

Pagination with Template Filters

{% load rosetta %}

<div class="pagination">
    {% if page_obj.has_previous %}
        <a href="?page={{ page_obj.previous_page_number }}" class="page-link">Previous</a>
    {% endif %}
    
    <!-- Show page numbers with calculations -->
    {% for page_num in page_obj.paginator.page_range %}
        {% if page_num|minus:page_obj.number|abs <= 2 %}
            {% if page_num == page_obj.number %}
                <span class="current-page">{{ page_num }}</span>
            {% else %}
                <a href="?page={{ page_num }}" class="page-link">{{ page_num }}</a>
            {% endif %}
        {% endif %}
    {% endfor %}
    
    {% if page_obj.has_next %}
        <a href="?page={{ page_obj.next_page_number }}" class="page-link">Next</a>
    {% endif %}
    
    <!-- Show entry range -->
    <div class="entry-info">
        Showing {{ page_obj.start_index }} - {{ page_obj.end_index }} 
        of {{ page_obj.paginator.count }} entries
    </div>
</div>

Counter Usage with Increment Tag

{% load rosetta %}

<!-- Number items in a list -->
<div class="translation-entries">
    {% for entry in entries %}
        <div class="entry" id="entry-{% increment 'entry_counter' %}">
            <div class="entry-number">
                #{% increment 'display_counter' %}
            </div>
            <div class="entry-content">
                <label for="input-{% increment 'input_counter' %}">
                    {{ entry.msgid|format_message|safe }}
                </label>
                <input type="text" 
                       id="input-{{ input_counter }}" 
                       name="msgstr_{{ entry.id }}"
                       value="{{ entry.msgstr }}">
            </div>
        </div>
    {% endfor %}
</div>

<!-- Generate unique form elements -->
<form class="batch-operations">
    {% for lang in languages %}
        <div class="language-section">
            <h3>{{ lang.name }}</h3>
            {% for file in lang.files %}
                <label>
                    <input type="checkbox" 
                           name="selected_files" 
                           value="{{ file.id }}"
                           id="file-{% increment 'file_counter' %}">
                    {{ file.name }}
                </label>
            {% endfor %}
        </div>
    {% endfor %}
</form>

Custom Template for Translation Interface

<!-- custom_translation_interface.html -->
{% extends "admin/base_site.html" %}
{% load rosetta %}

{% block title %}Translation Management{% endblock %}

{% block content %}
    {% if user|can_translate %}
        <div class="translation-interface">
            <header class="interface-header">
                <h1>Translation Management</h1>
                <div class="stats">
                    <span class="stat">
                        Total: {{ total_entries }}
                    </span>
                    <span class="stat">
                        Translated: {{ translated_entries }}
                    </span>
                    <span class="stat">
                        Progress: {{ translated_entries|mult:100|div:total_entries }}%
                    </span>
                </div>
            </header>
            
            <div class="entries-container">
                {% for entry in entries %}
                    <div class="entry-row {% if entry|is_fuzzy %}fuzzy{% endif %}">
                        <div class="entry-number">
                            {% increment 'row_counter' %}
                        </div>
                        
                        <div class="entry-original">
                            <strong>Original:</strong>
                            {{ entry.msgid|format_message|safe }}
                        </div>
                        
                        <div class="entry-translation">
                            <label for="trans-{% increment 'trans_counter' %}">
                                Translation:
                            </label>
                            
                            {% if entry.msgstr|lines_count|gt:2 %}
                                <textarea id="trans-{{ trans_counter }}" 
                                          name="msgstr_{{ entry.id }}"
                                          rows="{{ entry.msgstr|lines_count|add:1 }}">{{ entry.msgstr }}</textarea>
                            {% else %}
                                <input type="text" 
                                       id="trans-{{ trans_counter }}"
                                       name="msgstr_{{ entry.id }}"
                                       value="{{ entry.msgstr }}">
                            {% endif %}
                        </div>
                        
                        {% if entry|is_fuzzy %}
                            <div class="fuzzy-indicator">
                                <input type="checkbox" 
                                       name="fuzzy_{{ entry.id }}" 
                                       checked>
                                <label>Fuzzy</label>
                            </div>
                        {% endif %}
                    </div>
                {% endfor %}
            </div>
            
            <div class="interface-footer">
                <button type="submit" class="save-button">Save Translations</button>
                <div class="pagination-info">
                    Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
                    ({{ page_obj.paginator.count }} total entries)
                </div>
            </div>
        </div>
    {% else %}
        <div class="access-denied">
            <h2>Access Denied</h2>
            <p>You don't have permission to access the translation interface.</p>
        </div>
    {% endif %}
{% endblock %}

Template Integration with JavaScript

{% load rosetta %}

<script>
// Use template filters to provide data to JavaScript
const translationData = {
    userCanTranslate: {% if user|can_translate %}true{% else %}false{% endif %},
    totalEntries: {{ total_entries|default:0 }},
    translatedEntries: {{ translated_entries|default:0 }},
    completionPercentage: {{ translated_entries|mult:100|div:total_entries|default:0 }},
    entriesPerPage: {{ entries_per_page|default:10 }}
};

// Update progress indicators
function updateProgressBar() {
    const progressBar = document.getElementById('progress-bar');
    if (progressBar) {
        progressBar.style.width = translationData.completionPercentage + '%';
        progressBar.textContent = Math.round(translationData.completionPercentage) + '%';
    }
}

// Auto-resize textareas based on content
document.addEventListener('DOMContentLoaded', function() {
    const textareas = document.querySelectorAll('.translation-input[data-lines]');
    textareas.forEach(textarea => {
        const lines = parseInt(textarea.dataset.lines);
        if (lines > 3) {
            textarea.rows = Math.min(lines + 1, 10);
        }
    });
});
</script>

<!-- Template with JavaScript integration -->
{% for entry in entries %}
    <textarea class="translation-input" 
              data-lines="{{ entry.msgstr|lines_count }}"
              data-entry-id="{{ entry.id }}"
              data-is-fuzzy="{% if entry|is_fuzzy %}true{% else %}false{% endif %}">
        {{ entry.msgstr }}
    </textarea>
{% endfor %}

Install with Tessl CLI

npx tessl i tessl/pypi-django-rosetta

docs

access-control.md

configuration.md

django-signals.md

file-operations.md

index.md

storage-backends.md

template-integration.md

translation-services.md

web-interface.md

tile.json