Convert Zulip to use Jinja2 templates.

This results in a substantial performance improvement for all of
Zulip's backend templates.

Changes in templates:
- Change `block.super` to `super()`.
- Remove `load` tag because Jinja2 doesn't support it.
- Use `minified_js()|safe` instead of `{% minified_js %}`.
- Use `compressed_css()|safe` instead of `{% compressed_css %}`.
- `forloop.first` -> `loop.first`.
- Use `{{ csrf_input }}` instead of `{% csrf_token %}`.
- Use `{# ... #}` instead of `{% comment %}`.
- Use `url()` instead of `{% url %}`.
- Use `_()` instead of `{% trans %}` because in Jinja `trans` is a block tag.
- Use `{% trans %}` instead of `{% blocktrans %}`.
- Use `{% raw %}` instead of `{% verbatim %}`.

Changes in tools:
- Check for `trans` block in `check-templates` instead of `blocktrans`

Changes in backend:
- Create custom `render_to_response` function which takes `request` objects
  instead of `RequestContext` object. There are two reasons to do this:
    1. `RequestContext` is not compatible with Jinja2
    2. `RequestContext` in `render_to_response` is deprecated.
- Add Jinja2 related support files in zproject/jinja2 directory. It
  includes a custom backend and a template renderer, compressors for js
  and css and Jinja2 environment handler.
- Enable `slugify` and `pluralize` filters in Jinja2 environment.

Fixes #620.
This commit is contained in:
Umair Khan 2016-04-21 11:48:33 +05:00 committed by Tim Abbott
parent cec0530fd8
commit 5359e6b0d4
64 changed files with 706 additions and 524 deletions

View File

@ -4,10 +4,9 @@ from typing import Any, Dict, List, Tuple
from django.db import connection from django.db import connection
from django.template import RequestContext, loader from django.template import RequestContext, loader
from django.utils.html import mark_safe
from django.shortcuts import render_to_response
from django.core import urlresolvers from django.core import urlresolvers
from django.http import HttpResponseNotFound from django.http import HttpResponseNotFound
from jinja2 import Markup as mark_safe
from zerver.decorator import has_request_variables, REQ, zulip_internal from zerver.decorator import has_request_variables, REQ, zulip_internal
from zerver.models import get_realm, UserActivity, UserActivityInterval, Realm from zerver.models import get_realm, UserActivity, UserActivityInterval, Realm
@ -25,6 +24,8 @@ from six.moves import range
from six.moves import zip from six.moves import zip
eastern_tz = pytz.timezone('US/Eastern') eastern_tz = pytz.timezone('US/Eastern')
from zproject.jinja2 import render_to_response
def make_table(title, cols, rows, has_row_class=False): def make_table(title, cols, rows, has_row_class=False):
if not has_row_class: if not has_row_class:
@ -569,7 +570,7 @@ def get_activity(request):
return render_to_response( return render_to_response(
'analytics/activity.html', 'analytics/activity.html',
dict(data=data, title=title, is_home=True), dict(data=data, title=title, is_home=True),
context_instance=RequestContext(request) request=request
) )
def get_user_activity_records_for_realm(realm, is_bot): def get_user_activity_records_for_realm(realm, is_bot):
@ -863,7 +864,7 @@ def get_realm_activity(request, realm):
return render_to_response( return render_to_response(
'analytics/activity.html', 'analytics/activity.html',
dict(data=data, realm_link=realm_link, title=title), dict(data=data, realm_link=realm_link, title=title),
context_instance=RequestContext(request) request=request
) )
@zulip_internal @zulip_internal
@ -883,5 +884,5 @@ def get_user_activity(request, email):
return render_to_response( return render_to_response(
'analytics/activity.html', 'analytics/activity.html',
dict(data=data, title=title), dict(data=data, title=title),
context_instance=RequestContext(request) request=request
) )

View File

@ -10,6 +10,7 @@ from django.template import RequestContext
from django.conf import settings from django.conf import settings
from confirmation.models import Confirmation from confirmation.models import Confirmation
from zproject.jinja2 import render_to_response
def confirm(request, confirmation_key): def confirm(request, confirmation_key):
@ -39,5 +40,4 @@ def confirm(request, confirmation_key):
if obj: if obj:
# if we have an object, we can use specific template # if we have an object, we can use specific template
templates.insert(0, 'confirmation/confirm_%s.html' % obj._meta.model_name) templates.insert(0, 'confirmation/confirm_%s.html' % obj._meta.model_name)
return render_to_response(templates, ctx, return render_to_response(templates, ctx, request=request)
context_instance=RequestContext(request))

View File

@ -47,6 +47,18 @@ Views
| ``zerver/views/__init__.py`` | other Django views | | ``zerver/views/__init__.py`` | other Django views |
+--------------------------------+-----------------------------------------+ +--------------------------------+-----------------------------------------+
Jinja2 Compatibility Files
==========================
+-------------------------------------+--------------------------------------------------------------------+
| ``zproject/jinja2/__init__.py`` | Jinja2 environment |
+-------------------------------------+--------------------------------------------------------------------+
| ``zproject/jinja2/backends.py`` | Jinja2 backend |
+-------------------------------------+--------------------------------------------------------------------+
| ``zproject/jinja2/compressors.py`` | Jinja2 compatible functions of Django-Pipeline |
+-------------------------------------+--------------------------------------------------------------------+
Static assets Static assets
============= =============
@ -67,7 +79,7 @@ Templates
========= =========
+--------------------------+--------------------------------------------------------+ +--------------------------+--------------------------------------------------------+
| ``templates/zerver`` | For templates related to zerver views | | ``templates/zerver`` | For Jinja2 templates for the backend (for zerver app) |
+--------------------------+--------------------------------------------------------+ +--------------------------+--------------------------------------------------------+
| ``static/templates`` | Handlebars templates for the frontend | | ``static/templates`` | Handlebars templates for the frontend |
+--------------------------+--------------------------------------------------------+ +--------------------------+--------------------------------------------------------+

View File

@ -55,7 +55,7 @@ new event that is sent to clients, be sure to add a handler for it to
**CSS:** The primary CSS file is ``static/styles/zulip.css``. If your new **CSS:** The primary CSS file is ``static/styles/zulip.css``. If your new
feature requires UI changes, you may need to add additional CSS to this file. feature requires UI changes, you may need to add additional CSS to this file.
**Templates:** The initial page structure is rendered via Django templates **Templates:** The initial page structure is rendered via Jinja2 templates
located in ``templates/zerver``. For JavaScript, Zulip uses Handlebars templates located in located in ``templates/zerver``. For JavaScript, Zulip uses Handlebars templates located in
``static/templates``. Templates are precompiled as part of the build/deploy ``static/templates``. Templates are precompiled as part of the build/deploy
process. process.

View File

@ -13,6 +13,7 @@ class zulip::app_frontend_base {
"python-django-guardian", "python-django-guardian",
"python-django-pipeline", "python-django-pipeline",
"python-django-bitfield", "python-django-bitfield",
"python-jinja2",
# Needed for mock objects in decorators # Needed for mock objects in decorators
"python-mock", "python-mock",
# Tornado dependencies # Tornado dependencies

View File

@ -3,7 +3,7 @@
{% block for_you %} isn't feeling too good. {% endblock %} {% block for_you %} isn't feeling too good. {% endblock %}
{% block customhead %} {% block customhead %}
{{ block.super }} {{ super() }}
<meta http-equiv="refresh" content="60;URL='/'"> <meta http-equiv="refresh" content="60;URL='/'">
{% endblock %} {% endblock %}

View File

@ -1,8 +1,5 @@
{% extends "zerver/base.html" %} {% extends "zerver/base.html" %}
{% load compressed %}
{% load minified_js %}
{# User Activity. #} {# User Activity. #}
{% block title %} {% block title %}
@ -11,9 +8,9 @@
{% block customhead %} {% block customhead %}
{{ block.super }} {{ super() }}
{% minified_js 'activity' %} {{ minified_js('activity')|safe }}
{% compressed_css 'activity' %} {{ compressed_css('activity')|safe }}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
@ -31,7 +28,7 @@
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
{% for name, activity in data %} {% for name, activity in data %}
<li {% if forloop.first %} class="active" {% endif %}> <li {% if loop.first %} class="active" {% endif %}>
<a href="#{{ name|slugify }}" data-toggle="tab">{{ name }}</a> <a href="#{{ name|slugify }}" data-toggle="tab">{{ name }}</a>
</li> </li>
{% endfor %} {% endfor %}
@ -41,8 +38,8 @@
{% for name, activity in data %} {% for name, activity in data %}
<div class="tab-pane {% if forloop.first %} active {% endif %}" id="{{ name|slugify }}"> <div class="tab-pane {% if loop.first %} active {% endif %}" id="{{ name|slugify }}">
{{ activity }} {{ activity|safe }}
</div> </div>
{% endfor %} {% endfor %}

View File

@ -3,7 +3,7 @@
{% block content %} {% block content %}
<form id="register" action="/accounts/register/" method="post"> <form id="register" action="/accounts/register/" method="post">
{% csrf_token %} {{ csrf_input }}
<input type="hidden" value="{{ key }}" name="key"/> <input type="hidden" value="{{ key }}" name="key"/>
<input type="hidden" value="1" name="from_confirmation"/> <input type="hidden" value="1" name="from_confirmation"/>
</form> </form>

View File

@ -2,14 +2,14 @@
{% block content %} {% block content %}
{% comment %} {#
This template is referenced by the confirmation code and does not have the This template is referenced by the confirmation code and does not have the
requisite context to make a useful signup form. Therefore, we immediately requisite context to make a useful signup form. Therefore, we immediately
post to another view which executes in our code to produce the desired form. post to another view which executes in our code to produce the desired form.
{% endcomment %} #}
<form id="register" action="/accounts/register/" method="post"> <form id="register" action="/accounts/register/" method="post">
{% csrf_token %} {{ csrf_input }}
<input type="hidden" value="{{ key }}" name="key"/> <input type="hidden" value="{{ key }}" name="key"/>
<input type="hidden" value="1" name="from_confirmation"/> <input type="hidden" value="1" name="from_confirmation"/>
<input type="hidden" value="{% if full_name %}{{ full_name }}{% endif %}" name="full_name"/> <input type="hidden" value="{% if full_name %}{{ full_name }}{% endif %}" name="full_name"/>

View File

@ -1,7 +1,7 @@
Psst. Word on the street is that you forgot your password, {{ email}}. Psst. Word on the street is that you forgot your password, {{ email}}.
It's all good. Follow the link below and we'll take care of the rest: It's all good. Follow the link below and we'll take care of the rest:
<{{ protocol}}://{{ domain }}{% url 'django.contrib.auth.views.password_reset_confirm' uidb64=uid token=token %}> <{{ protocol}}://{{ domain }}{{ url('django.contrib.auth.views.password_reset_confirm', uidb64=uid, token=token) }}>
Thanks, Thanks,
Your friends at Zulip HQ Your friends at Zulip HQ

View File

@ -1,34 +1,33 @@
{% extends "zerver/portico_signup.html" %} {% extends "zerver/portico_signup.html" %}
{% load i18n %} {#
{% comment %}
Allow the user to accept the terms, creating an email record of that fact. Allow the user to accept the terms, creating an email record of that fact.
{% endcomment %} #}
{% block for_you %}for {% if company_name %} {{company_name}} {% else %} __________ {% endif %} {% endblock %} {% block for_you %}for {% if company_name %} {{company_name}} {% else %} __________ {% endif %} {% endblock %}
{% block portico_content %} {% block portico_content %}
<p>({% trans "Welcome! We think you'll like it here" %}.)</p> <p>({{ _("Welcome! We think you'll like it here") }}.)</p>
<div class="pitch"> <div class="pitch">
<hr/> <hr/>
<p>{% trans "You're almost there. We just need you to do one last thing" %}.</p> <p>{{ _("You're almost there. We just need you to do one last thing") }}.</p>
<h3>{% trans "Accept the Zulip terms of service" %}</h3> <h3>{{ _("Accept the Zulip terms of service") }}</h3>
</div> </div>
<form method="post" class="form-horizontal" id="registration" action="{% url 'zerver.views.accounts_accept_terms' %}"> <form method="post" class="form-horizontal" id="registration" action="{{ url('zerver.views.accounts_accept_terms') }}">
{% csrf_token %} {{ csrf_input }}
<div class="control-group"> <div class="control-group">
<label for="id_email" class="control-label">{% trans "Email" %}</label> <label for="id_email" class="control-label">{{ _("Email") }}</label>
<div class="controls fakecontrol"> <div class="controls fakecontrol">
<p>{{ email }}</p> <p>{{ email }}</p>
</div> </div>
</div> </div>
<div class="control-group"> <div class="control-group">
<label for="id_full_name" class="control-label">{% trans "Your name" %}</label> <label for="id_full_name" class="control-label">{{ _("Your name") }}</label>
<div class="controls"> <div class="controls">
<input id="id_full_name" class="required" type="text" name="full_name" <input id="id_full_name" class="required" type="text" name="full_name"
value="{% if form.full_name.value %}{{ form.full_name.value }}{% endif %}" value="{% if form.full_name.value() %}{{ form.full_name.value() }}{% endif %}"
maxlength="100" /> maxlength="100" />
{% if form.full_name.errors %} {% if form.full_name.errors %}
{% for error in form.full_name.errors %} {% for error in form.full_name.errors %}
@ -41,17 +40,17 @@ Allow the user to accept the terms, creating an email record of that fact.
<div class="control-group"> <div class="control-group">
<div class="controls"> <div class="controls">
<label class="checkbox"> <label class="checkbox">
{% comment %} {#
This is somewhat subtle. This is somewhat subtle.
Checkboxes have a name and value, and when the checkbox is ticked, the form posts Checkboxes have a name and value, and when the checkbox is ticked, the form posts
with name=value. If the checkbox is unticked, the field just isn't present at all. with name=value. If the checkbox is unticked, the field just isn't present at all.
This is distinct from 'checked', which determines whether the checkbox appears This is distinct from 'checked', which determines whether the checkbox appears
at all. (So, it's not symmetric to the code above.) at all. (So, it's not symmetric to the code above.)
{% endcomment %} #}
<input id="id_terms" class="required" type="checkbox" name="terms" <input id="id_terms" class="required" type="checkbox" name="terms"
{% if form.terms.value %}checked="checked"{% endif %} /> {% if form.terms.value() %}checked="checked"{% endif %} />
{% trans "I agree to the" %} <a href="/terms">{% trans "Terms of Service" %}</a>. {{ _("I agree to the") }} <a href="/terms">{{ _("Terms of Service") }}</a>.
</label> </label>
{% if form.terms.errors %} {% if form.terms.errors %}
{% for error in form.terms.errors %} {% for error in form.terms.errors %}

View File

@ -1,5 +1,4 @@
{% extends "zerver/portico_signup.html" %} {% extends "zerver/portico_signup.html" %}
{% load i18n %}
{# Home page for not logged-in users. #} {# Home page for not logged-in users. #}
{# This is where we pitch the app and solicit signups. #} {# This is where we pitch the app and solicit signups. #}
@ -16,14 +15,14 @@ $(function () {
<div class="register-form"> <div class="register-form">
<p class="lead"> <p class="lead">
<div class="register-page-header">{% trans "Let's get started" %}…</div> <div class="register-page-header">{{ _("Let's get started") }}…</div>
</p> </p>
<form class="form-inline" id="send_confirm" name="email_form" <form class="form-inline" id="send_confirm" name="email_form"
action="{{ current_url }}" method="post"> action="{{ current_url() }}" method="post">
{% csrf_token %} {{ csrf_input }}
<input type="text" class="email required" placeholder="{% trans "Enter your work email address" %}" <input type="text" class="email required" placeholder="{{ _("Enter your work email address") }}"
id="email" name="email"/> id="email" name="email"/>
<input type="submit" class="btn btn-primary btn-large register-button" value="{% trans "Sign up" %}"/> <input type="submit" class="btn btn-primary btn-large register-button" value="{{ _("Sign up") }}"/>
</form> </form>
<div id="errors"></div> <div id="errors"></div>
{% if form.email.errors %} {% if form.email.errors %}
@ -32,12 +31,12 @@ $(function () {
{% endfor %} {% endfor %}
{% endif %} {% endif %}
<div class="alert alert-pitch" id="company-email">{% blocktrans %}Please use your <div class="alert alert-pitch" id="company-email">{% trans %}Please use your
company email address to sign up. Otherwise, we wont be able to company email address to sign up. Otherwise, we wont be able to
connect you with your coworkers{% endblocktrans %}.</div> connect you with your coworkers{% endtrans %}.</div>
{% if google_auth_enabled %} {% if google_auth_enabled %}
<div class="register-google"> <div class="register-google">
<a href="{% url 'zerver.views.start_google_oauth2' %}" class="zocial google register-google-button">{% trans "Sign up with Google" %}</a> <a href="{{ url('zerver.views.start_google_oauth2') }}" class="zocial google register-google-button">{{ _("Sign up with Google") }}</a>
</div> </div>
{% endif %} {% endif %}
</div> </div>

View File

@ -1,17 +1,16 @@
{% extends "zerver/portico_signup.html" %} {% extends "zerver/portico_signup.html" %}
{% load i18n %}
{# Displayed after a user attempts to sign up. #} {# Displayed after a user attempts to sign up. #}
{% block portico_content %} {% block portico_content %}
<div class="app portico-page"> <div class="app portico-page">
<div class="app-main portico-page-container"> <div class="app-main portico-page-container">
<h2>{% trans "Thanks for signing up!" %}</h2> <h2>{{ _("Thanks for signing up!") }}</h2>
<p class="lead">{% trans "Check your email so we can get started" %}.</p> <p class="lead">{{ _("Check your email so we can get started") }}.</p>
<p>{% blocktrans %}Still no email? We can <a href="#" id="resend_email_link">resend it</a>{% endblocktrans %}.<br/> <p>{% trans %}Still no email? We can <a href="#" id="resend_email_link">resend it</a>{% endtrans %}.<br/>
<small>({% trans "Just in case, take a look at your Spam folder" %}.)</small></p> <small>({{ _("Just in case, take a look at your Spam folder") }}.)</small></p>
<form id="resend_confirm" action="/accounts/home/" method="post" style="position: absolute;"> <form id="resend_confirm" action="/accounts/home/" method="post" style="position: absolute;">
{% csrf_token %} {{ csrf_input }}
<input type="hidden" class="email" id="email" value="{{ email }}" name="email"/>&nbsp; <input type="hidden" class="email" id="email" value="{{ email }}" name="email"/>&nbsp;
</form> </form>
</div> </div>
@ -19,7 +18,7 @@
{% endblock %} {% endblock %}
{% block customhead %} {% block customhead %}
{{ block.super }} {{ super() }}
<script type="text/javascript"> <script type="text/javascript">
$(function() { $(function() {
$("#resend_email_link").click(function () { $("#resend_email_link").click(function () {

View File

@ -39,11 +39,11 @@
<div class="tab-pane active" id="curl"> <div class="tab-pane active" id="curl">
<p>No download required!</p> <p>No download required!</p>
{% comment %} {#
These code snippets are generated using our very own Zulip tool, by These code snippets are generated using our very own Zulip tool, by
sending them to myself in a code block, and then using the inspector sending them to myself in a code block, and then using the inspector
to pull out the resulting HTML :) to pull out the resulting HTML :)
{% endcomment %} #}
<h4>Stream message</h4> <h4>Stream message</h4>
<div class="codehilite"><pre>curl {{ external_api_uri }}/v1/messages <span class="se">\</span> <div class="codehilite"><pre>curl {{ external_api_uri }}/v1/messages <span class="se">\</span>

View File

@ -2,11 +2,9 @@
{# API information page #} {# API information page #}
{% load minified_js %}
{% block customhead %} {% block customhead %}
{{ block.super }} {{ super() }}
{% minified_js 'api' %} {{ minified_js('api')|safe }}
{% endblock %} {% endblock %}

View File

@ -1,12 +1,11 @@
{% extends "zerver/portico.html" %} {% extends "zerver/portico.html" %}
{% load i18n %}
{# API information page #} {# API information page #}
{% block portico_content %} {% block portico_content %}
<div class="apps-page-header">{% blocktrans %}Do we have apps? Appsolutely.{% endblocktrans %}</div> <div class="apps-page-header">{% trans %}Do we have apps? Appsolutely.{% endtrans %}</div>
<div class="apps-muted">{% blocktrans %}Ok, I take it back, I'm sorry, please don't go.{% endblocktrans %}</div> <div class="apps-muted">{% trans %}Ok, I take it back, I'm sorry, please don't go.{% endtrans %}</div>
<h3 class="apps-instructions-header">{% blocktrans %}Installation instructions{% endblocktrans %}</h3> <h3 class="apps-instructions-header">{% trans %}Installation instructions{% endtrans %}</h3>
<ul class="nav nav-tabs" id="apps-tabs"> <ul class="nav nav-tabs" id="apps-tabs">
{% if not_voyager %} {% if not_voyager %}
<li class="active"><a href="#android" data-toggle="tab">Android</a></li> <li class="active"><a href="#android" data-toggle="tab">Android</a></li>
@ -23,10 +22,10 @@
<div class="tab-pane active" id="android"> <div class="tab-pane active" id="android">
<img class="screenshot android-screenshot pull-left" src="/static/images/app-screenshots/zulip-android.png" alt="screenshot of the Zulip app on Android" /> <img class="screenshot android-screenshot pull-left" src="/static/images/app-screenshots/zulip-android.png" alt="screenshot of the Zulip app on Android" />
<p>{% blocktrans %}Zulip has a free, <strong>100% native app</strong> for Android, <p>{% trans %}Zulip has a free, <strong>100% native app</strong> for Android,
and you can easily grab it from and you can easily grab it from
the <a href="https://play.google.com/store/apps/details?id=com.zulip.android">Google the <a href="https://play.google.com/store/apps/details?id=com.zulip.android">Google
Play Store</a>{% endblocktrans %}.</p> Play Store</a>{% endtrans %}.</p>
<a href="https://play.google.com/store/apps/details?id=com.zulip.android"> <a href="https://play.google.com/store/apps/details?id=com.zulip.android">
<img alt="Get it on Google Play" <img alt="Get it on Google Play"
@ -37,9 +36,9 @@
<div class="tab-pane" id="iphone"> <div class="tab-pane" id="iphone">
<img class="screenshot iphone-screenshot pull-left" src="/static/images/app-screenshots/zulip-iphone.png" alt="screenshot of the Zulip app on iOS" /> <img class="screenshot iphone-screenshot pull-left" src="/static/images/app-screenshots/zulip-iphone.png" alt="screenshot of the Zulip app on iOS" />
<p>{% blocktrans %}Zulip has a free, <strong>100% native app</strong> for iPhone and <p>{% trans %}Zulip has a free, <strong>100% native app</strong> for iPhone and
iPad. Please grab it from iPad. Please grab it from
the <a href="http://itunes.com/apps/zulip">App Store</a>{% endblocktrans %}!</p> the <a href="http://itunes.com/apps/zulip">App Store</a>{% endtrans %}!</p>
<a href="http://itunes.com/apps/zulip"> <a href="http://itunes.com/apps/zulip">
<img alt="Get it in the App Store" src="/static/images/app-screenshots/ios_badge.png" alt="Apple App Store icon for Zulip" /> <img alt="Get it in the App Store" src="/static/images/app-screenshots/ios_badge.png" alt="Apple App Store icon for Zulip" />
@ -48,16 +47,16 @@
</div> </div>
{% endif %} {% endif %}
<div class="tab-pane" id="mac"> <div class="tab-pane" id="mac">
<p>{% blocktrans %}You love your Mac. And you love Zulip. So what could be <p>{% trans %}You love your Mac. And you love Zulip. So what could be
better than a Zulip app for Mac? Enjoy notifications for better than a Zulip app for Mac? Enjoy notifications for
messages and PMs in your dock whether you're in Sublime, messages and PMs in your dock whether you're in Sublime,
emacs, or Photoshop.{% endblocktrans %}</p> emacs, or Photoshop.{% endtrans %}</p>
<p style="text-align: center"> <p style="text-align: center">
{% if only_sso %} {% if only_sso %}
<a href="https://zulip.com/dist/apps/sso/mac/Zulip-latest.dmg" class="btn btn-large btn-primary btn-app-download"><i class="icon-vector-download"></i> {% blocktrans %}Download Zulip for Mac{% endblocktrans %}</a> <a href="https://zulip.com/dist/apps/sso/mac/Zulip-latest.dmg" class="btn btn-large btn-primary btn-app-download"><i class="icon-vector-download"></i> {% trans %}Download Zulip for Mac{% endtrans %}</a>
{% else %} {% else %}
<a href="https://zulip.com/dist/apps/mac/Zulip-latest.dmg" class="btn btn-large btn-primary btn-app-download"><i class="icon-vector-download"></i> {% blocktrans %}Download Zulip for Mac{% endblocktrans %}</a> <a href="https://zulip.com/dist/apps/mac/Zulip-latest.dmg" class="btn btn-large btn-primary btn-app-download"><i class="icon-vector-download"></i> {% trans %}Download Zulip for Mac{% endtrans %}</a>
{% endif %} {% endif %}
</p> </p>
@ -65,12 +64,12 @@
</div> </div>
<div class="tab-pane" id="linux"> <div class="tab-pane" id="linux">
<p>{% blocktrans %}Zulip provides a native Linux app that runs standalone <p>{% trans %}Zulip provides a native Linux app that runs standalone
outside of your browser. How you install it depends on what outside of your browser. How you install it depends on what
you're running:{% endblocktrans %}</p> you're running:{% endtrans %}</p>
<h3>{% blocktrans %}Debian and Ubuntu{% endblocktrans %}</h3> <h3>{% trans %}Debian and Ubuntu{% endtrans %}</h3>
{% blocktrans %}We have an APT repository for Zulip, so adding and installing the app is easy:{% endblocktrans %} {% trans %}We have an APT repository for Zulip, so adding and installing the app is easy:{% endtrans %}
<div class="codehilite"><pre>wget https://zulip.com/dist/keys/user-apt.asc <div class="codehilite"><pre>wget https://zulip.com/dist/keys/user-apt.asc
cat user-apt.asc | sudo apt-key add - cat user-apt.asc | sudo apt-key add -
sudo apt-add-repository http://apt.zulip.com/user/ sudo apt-add-repository http://apt.zulip.com/user/
@ -83,29 +82,29 @@ sudo apt-get install zulip-desktop
<h3>{% trans "Other" %}</h3> <h3>{{ _("Other") }}</h3>
{% if only_sso %} {% if only_sso %}
<p>{% blocktrans %}We provide a <a href="https://zulip.com/dist/apps/sso/linux/zulip-desktop_latest.bin.tar.gz">binary tarball</a> of the Zulip application, built for 64-bit systems.{% endblocktrans %} <p>{% trans %}We provide a <a href="https://zulip.com/dist/apps/sso/linux/zulip-desktop_latest.bin.tar.gz">binary tarball</a> of the Zulip application, built for 64-bit systems.{% endtrans %}
</p> </p>
{% else %} {% else %}
<p>{% blocktrans %}We provide a <a href="https://zulip.com/dist/apps/linux/zulip-desktop_latest.bin.tar.gz">binary tarball</a> of the Zulip application, built for 64-bit systems.{% endblocktrans %} <p>{% trans %}We provide a <a href="https://zulip.com/dist/apps/linux/zulip-desktop_latest.bin.tar.gz">binary tarball</a> of the Zulip application, built for 64-bit systems.{% endtrans %}
</p> </p>
{% endif %} {% endif %}
</div> </div>
<div class="tab-pane" id="windows"> <div class="tab-pane" id="windows">
<p>{% blocktrans %}Windows. It's the best OS for your needs: gaming, <p>{% trans %}Windows. It's the best OS for your needs: gaming,
coding, expense reports. But you always felt that something coding, expense reports. But you always felt that something
was missing... until now.{% endblocktrans %}</p> was missing... until now.{% endtrans %}</p>
<p>{% blocktrans %}We proudly present <b>Zulip for Windows</b>: the second-best app for Windows on the market today (after <p>{% trans %}We proudly present <b>Zulip for Windows</b>: the second-best app for Windows on the market today (after
Solitaire, obviously.){% endblocktrans %}</p> Solitaire, obviously.){% endtrans %}</p>
<p style="text-align: center"> <p style="text-align: center">
{% if only_sso %} {% if only_sso %}
<a href="https://zulip.com/dist/apps/sso/win/zulip-latest.exe" class="btn btn-large btn-primary btn-app-download"><i class="icon-vector-download"></i> {% blocktrans %}Download Zulip for Windows{% endblocktrans %}</a> <a href="https://zulip.com/dist/apps/sso/win/zulip-latest.exe" class="btn btn-large btn-primary btn-app-download"><i class="icon-vector-download"></i> {% trans %}Download Zulip for Windows{% endtrans %}</a>
{% else %} {% else %}
<a href="https://zulip.com/dist/apps/win/zulip-latest.exe" class="btn btn-large btn-primary btn-app-download"><i class="icon-vector-download"></i> {% blocktrans %}Download Zulip for Windows{% endblocktrans %}</a> <a href="https://zulip.com/dist/apps/win/zulip-latest.exe" class="btn btn-large btn-primary btn-app-download"><i class="icon-vector-download"></i> {% trans %}Download Zulip for Windows{% endtrans %}</a>
{% endif %} {% endif %}
</p> </p>
@ -113,10 +112,10 @@ sudo apt-get install zulip-desktop
</div> </div>
<div class="tab-pane" id="plan9"> <div class="tab-pane" id="plan9">
<p>{% blocktrans %}First, connect to our hosted 9P filesystem <p>{% trans %}First, connect to our hosted 9P filesystem
at <code>plan9.zulip.com</code> and then... no, we're at <code>plan9.zulip.com</code> and then... no, we're
totally kidding. There definitely isn't a version of Zulip totally kidding. There definitely isn't a version of Zulip
for Plan 9.{% endblocktrans %}</p> for Plan 9.{% endtrans %}</p>
</div> </div>

View File

@ -1,18 +1,17 @@
{% load i18n %}
<div class="modal hide" id="bankruptcy" tabindex="-1" role="dialog" <div class="modal hide" id="bankruptcy" tabindex="-1" role="dialog"
aria-labelledby="bankruptcy-label" aria-hidden="true"> aria-labelledby="bankruptcy-label" aria-hidden="true">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="bankruptcy-label">{% trans 'Welcome back' %}</h3> <h3 id="bankruptcy-label">{{ _('Welcome back') }}</h3>
</div> </div>
<div id="bankruptcy-unread-count"></div> <div id="bankruptcy-unread-count"></div>
<div class="modal-footer"> <div class="modal-footer">
<button id="yes-bankrupt" class="bankruptcy_button btn btn-primary" <button id="yes-bankrupt" class="bankruptcy_button btn btn-primary"
aria-hidden="true">{% trans 'Yes, please!' %}</button> aria-hidden="true">{{ _('Yes, please!') }}</button>
<button id="no-bankrupt" class="bankruptcy_button btn btn-default" <button id="no-bankrupt" class="bankruptcy_button btn btn-default"
data-dismiss="modal" aria-hidden="true">{% trans "No, I'll catch up" %}.</button> data-dismiss="modal" aria-hidden="true">{{ _("No, I'll catch up") }}.</button>
</div> </div>
</div> </div>

View File

@ -2,8 +2,6 @@
<html> <html>
{# Base template for the whole site. #} {# Base template for the whole site. #}
{% load compressed %}
{% load minified_js %}
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
@ -25,14 +23,14 @@
{% endif %} {% endif %}
{# We need to import jQuery before Bootstrap #} {# We need to import jQuery before Bootstrap #}
{% compressed_css 'common' %} {{ compressed_css('common')|safe }}
{% block page_params %} {% block page_params %}
{# blueslip needs page_params.debug_mode. Set it to false by default. #} {# blueslip needs page_params.debug_mode. Set it to false by default. #}
<script type="text/javascript"> <script type="text/javascript">
var page_params = {debug_mode: false}; var page_params = {debug_mode: false};
</script> </script>
{% endblock %} {% endblock %}
{% minified_js 'common' %} {{ minified_js('common')|safe }}
{% block customhead %} {% block customhead %}
{% endblock %} {% endblock %}
</head> </head>

View File

@ -1,11 +1,10 @@
{% extends "zerver/portico.html" %} {% extends "zerver/portico.html" %}
{% load i18n %}
{% block portico_content %} {% block portico_content %}
<h3>{% trans 'Closed realm' %}</h3> <h3>{{ _('Closed realm') }}</h3>
<p>{% trans 'Hi there! Thank you for your interest in Zulip' %}.</p> <p>{{ _('Hi there! Thank you for your interest in Zulip') }}.</p>
<p>{% blocktrans %}The organization you are trying to join, {{ closed_domain_name }}, only allows users with e-mail addresses within the organization. Please ask for a new invite to an appropriate e-mail address{% endblocktrans %}.</p> <p>{% trans %}The organization you are trying to join, {{ closed_domain_name }}, only allows users with e-mail addresses within the organization. Please ask for a new invite to an appropriate e-mail address{% endtrans %}.</p>
{% endblock %} {% endblock %}

View File

@ -1,4 +1,3 @@
{% load i18n %}
<div id="compose"> <div id="compose">
<div id="compose-notifications" class="notifications above-composebox"> <div id="compose-notifications" class="notifications above-composebox">
</div> </div>
@ -8,14 +7,14 @@
<span class="new_message_button"> <span class="new_message_button">
<button type="button" class="btn btn-default btn-large compose_stream_button" <button type="button" class="btn btn-default btn-large compose_stream_button"
id="left_bar_compose_stream_button_big" title="New stream message (c)"> id="left_bar_compose_stream_button_big" title="New stream message (c)">
<i class="icon-vector-bullhorn"></i><span class="compose_stream_button_label">&nbsp;&nbsp;{% trans 'New stream message' %}</span> <i class="icon-vector-bullhorn"></i><span class="compose_stream_button_label">&nbsp;&nbsp;{{ _('New stream message') }}</span>
</button> </button>
</span> </span>
{% if not embedded %} {% if not embedded %}
<span class="new_message_button"> <span class="new_message_button">
<button type="button" class="btn btn-default btn-large compose_private_button" <button type="button" class="btn btn-default btn-large compose_private_button"
id="left_bar_compose_private_button_big" title="New private message (C)"> id="left_bar_compose_private_button_big" title="New private message (C)">
<i class="icon-vector-user"></i><span class="compose_private_button_label">&nbsp;&nbsp;{% trans 'New private message' %}</span> <i class="icon-vector-user"></i><span class="compose_private_button_label">&nbsp;&nbsp;{{ _('New private message') }}</span>
</button> </button>
</span> </span>
{% endif %} {% endif %}
@ -32,7 +31,7 @@
<div class="composition-area"> <div class="composition-area">
<button type="button" class="close" id='compose_close'>×</button> <button type="button" class="close" id='compose_close'>×</button>
<form id="send_message_form" action="/json/messages" method="post"> <form id="send_message_form" action="/json/messages" method="post">
{% csrf_token %} {{ csrf_input }}
<table class="compose_table"> <table class="compose_table">
<tbody> <tbody>
<tr class="ztable_layout_row"> <tr class="ztable_layout_row">
@ -44,15 +43,15 @@
</td> </td>
<td class="right_part"> <td class="right_part">
<span id="compose-lock-icon"> <span id="compose-lock-icon">
<i class="icon-vector-lock" title="{% trans 'This is an invite-only stream' %}"></i> <i class="icon-vector-lock" title="{{ _('This is an invite-only stream') }}"></i>
</span> </span>
<input type="text" class="recipient_box" name="stream" id="stream" <input type="text" class="recipient_box" name="stream" id="stream"
maxlength="30" maxlength="30"
value="" placeholder="{% trans 'Stream' %}" autocomplete="off" tabindex="120"/> value="" placeholder="{{ _('Stream') }}" autocomplete="off" tabindex="120"/>
<i class="icon-vector-narrow icon-vector-small"></i> <i class="icon-vector-narrow icon-vector-small"></i>
<input type="text" class="recipient_box" name="subject" id="subject" <input type="text" class="recipient_box" name="subject" id="subject"
maxlength="60" maxlength="60"
value="" placeholder="{% trans 'Topic' %}" autocomplete="off" tabindex="130"/> value="" placeholder="{{ _('Topic') }}" autocomplete="off" tabindex="130"/>
</td> </td>
</tr> </tr>
<tr id="private-message"> <tr id="private-message">
@ -61,28 +60,28 @@
</td> </td>
<td class="right_part"> <td class="right_part">
<div class="pm_recipient"> <div class="pm_recipient">
<span class="you_text">{% trans 'You and' %}</span> <span class="you_text">{{ _('You and') }}</span>
<input type="text" class="recipient_box" name="recipient" id="private_message_recipient" <input type="text" class="recipient_box" name="recipient" id="private_message_recipient"
value="" placeholder="{% trans 'one or more people' %}..." autocomplete="off" tabindex="130"/> value="" placeholder="{{ _('one or more people') }}..." autocomplete="off" tabindex="130"/>
</div> </div>
</td> </td>
</tr> </tr>
<tr> <tr>
<td class="messagebox" colspan="2"> <td class="messagebox" colspan="2">
<textarea class="new_message_textarea" name="content" id="new_message_content" <textarea class="new_message_textarea" name="content" id="new_message_content"
value="" placeholder="{% trans 'Compose your message here' %}..." tabindex="140" maxlength="10000"></textarea> value="" placeholder="{{ _('Compose your message here') }}..." tabindex="140" maxlength="10000"></textarea>
<div id="below-compose-content"> <div id="below-compose-content">
<input type="file" id="file_input" class="notvisible pull-left" multiple /> <input type="file" id="file_input" class="notvisible pull-left" multiple />
<a class="message-control-button icon-vector-dropbox notdisplayed" <a class="message-control-button icon-vector-dropbox notdisplayed"
id="attach_dropbox_files" href="#" title="{% trans 'Attach files from Dropbox' %}"></a> id="attach_dropbox_files" href="#" title="{{ _('Attach files from Dropbox') }}"></a>
<a class="message-control-button icon-vector-paper-clip notdisplayed" <a class="message-control-button icon-vector-paper-clip notdisplayed"
id="attach_files" href="#" title="{% trans 'Attach files' %}"></a> id="attach_files" href="#" title="{{ _('Attach files') }}"></a>
<a class="message-control-button icon-vector-font" <a class="message-control-button icon-vector-font"
href="#markdown-help" title="Formatting" data-toggle="modal"></a> href="#markdown-help" title="Formatting" data-toggle="modal"></a>
<a id="restore-draft" onclick="compose.restore_message();">{% trans 'Restore draft' %}</a> <a id="restore-draft" onclick="compose.restore_message();">{{ _('Restore draft') }}</a>
<span id="sending-indicator">{% trans 'Sending' %}...</span> <span id="sending-indicator">{{ _('Sending') }}...</span>
<div id="send_controls"> <div id="send_controls">
<label id="enter-sends-label" class="compose_checkbox_label" for="enter_sends">{% trans 'Press Enter to send' %}&nbsp;</label> <label id="enter-sends-label" class="compose_checkbox_label" for="enter_sends">{{ _('Press Enter to send') }}&nbsp;</label>
<input type="checkbox" id="enter_sends" name="enter_sends" value="enter_sends" /> <input type="checkbox" id="enter_sends" name="enter_sends" value="enter_sends" />
<input type="submit" value="Send" id="compose-send-button" class="btn btn-primary send_message" tabindex="150"/> <input type="submit" value="Send" id="compose-send-button" class="btn btn-primary send_message" tabindex="150"/>
</div> </div>

View File

@ -1,14 +1,13 @@
{% extends "zerver/portico.html" %} {% extends "zerver/portico.html" %}
{% load i18n %}
{% block portico_content %} {% block portico_content %}
<h3>{% trans 'Deactivated organization' %}</h3> <h3>{{ _('Deactivated organization') }}</h3>
<p>{% trans 'Hi there! Thank you for your interest in Zulip' %}.</p> <p>{{ _('Hi there! Thank you for your interest in Zulip') }}.</p>
<p>{% blocktrans %} The organization you are trying to join, {{ deactivated_domain_name }}, has <p>{% trans %} The organization you are trying to join, {{ deactivated_domain_name }}, has
been deactivated. Please been deactivated. Please
contact <a href="mailto:{{ zulip_administrator }}">{{ zulip_administrator }}</a> to reactivate contact <a href="mailto:{{ zulip_administrator }}">{{ zulip_administrator }}</a> to reactivate
this group{% endblocktrans %}.</p> this group{% endtrans %}.</p>
{% endblock %} {% endblock %}

View File

@ -1,9 +1,9 @@
{% comment %} {#
Debug tab of the app. Debug tab of the app.
Included if Django's DEBUG = True and the query Included if Django's DEBUG = True and the query
parameter ?show_debug is present. parameter ?show_debug is present.
{% endcomment %} #}
<style> <style>
/* Hack to make it scrollable */ /* Hack to make it scrollable */

View File

@ -1,7 +1,7 @@
{% load app_filters %} {% load app_filters %}
{% comment %} {#
Mail sent to a user who hasn't logged in for 24 hours. Mail sent to a user who hasn't logged in for 24 hours.
{% endcomment %} #}
Hello {{ name }}, Hello {{ name }},

View File

@ -1,7 +1,7 @@
{% load app_filters %} {% load app_filters %}
{% comment %} {#
Mail sent to a user who hasn't logged in for 24 hours. Mail sent to a user who hasn't logged in for 24 hours.
{% endcomment %} #}
Hello {{ name }}, Hello {{ name }},

View File

@ -1,151 +1,150 @@
{% extends "zerver/portico.html" %} {% extends "zerver/portico.html" %}
{% load i18n %}
{% block portico_content %} {% block portico_content %}
<div class="feature-page-header">{% blocktrans %}Zulip Features{% endblocktrans %}</div> <div class="feature-page-header">{% trans %}Zulip Features{% endtrans %}</div>
<div class="feature-block left"> <div class="feature-block left">
<i class="icon-vector-random icon-vector-3x feature-icon"></i> <i class="icon-vector-random icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}Threaded group conversations{% endblocktrans %}</h4> <h4>{% trans %}Threaded group conversations{% endtrans %}</h4>
<p>{% blocktrans %}Talk about multiple topics at once without getting lost or <p>{% trans %}Talk about multiple topics at once without getting lost or
overwhelmed.{% endblocktrans %}</p> overwhelmed.{% endtrans %}</p>
</div> </div>
<div class="feature-block"> <div class="feature-block">
<i class="icon-vector-comments icon-vector-3x feature-icon"></i> <i class="icon-vector-comments icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}One-on-one and group private conversations{% endblocktrans %}</h4> <h4>{% trans %}One-on-one and group private conversations{% endtrans %}</h4>
<p>{% blocktrans %}Have private conversations with one or as many people as you need.{% endblocktrans %}</p> <p>{% trans %}Have private conversations with one or as many people as you need.{% endtrans %}</p>
</div> </div>
<div class="feature-block left"> <div class="feature-block left">
<i class="icon-vector-home icon-vector-3x feature-icon"></i> <i class="icon-vector-home icon-vector-3x feature-icon"></i>
<h4>{% trans "Persistence" %}</h4> <h4>{{ _("Persistence") }}</h4>
<p>{% blocktrans %}We're always receiving messages for you, even when you're <p>{% trans %}We're always receiving messages for you, even when you're
logged out.{% endblocktrans %}</p> logged out.{% endtrans %}</p>
</div> </div>
<div class="feature-block"> <div class="feature-block">
<i class="icon-vector-road icon-vector-3x feature-icon"></i> <i class="icon-vector-road icon-vector-3x feature-icon"></i>
<h4>{% trans "History" %}</h4> <h4>{{ _("History") }}</h4>
<p>{% blocktrans %}Join a stream and see its history, so even new team <p>{% trans %}Join a stream and see its history, so even new team
members are never out of the loop.{% endblocktrans %}</p> members are never out of the loop.{% endtrans %}</p>
</div> </div>
<div class="feature-block left"> <div class="feature-block left">
<i class="icon-vector-search icon-vector-3x feature-icon"></i> <i class="icon-vector-search icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}Full-history search{% endblocktrans %}</h4> <h4>{% trans %}Full-history search{% endtrans %}</h4>
<p>{% blocktrans %}Search is both snappy and smart, helping you look for text, <p>{% trans %}Search is both snappy and smart, helping you look for text,
people, and threads of conversation, with advanced search people, and threads of conversation, with advanced search
operators for fine-grained control.{% endblocktrans %}</p> operators for fine-grained control.{% endtrans %}</p>
</div> </div>
<div class="feature-block"> <div class="feature-block">
<i class="icon-vector-group icon-vector-3x feature-icon"></i> <i class="icon-vector-group icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}Team presence and buddy list{% endblocktrans %}</h4> <h4>{% trans %}Team presence and buddy list{% endtrans %}</h4>
<p>{% blocktrans %}See who is online at a glance.{% endblocktrans %}</p> <p>{% trans %}See who is online at a glance.{% endtrans %}</p>
</div> </div>
<div class="feature-block left"> <div class="feature-block left">
<i class="icon-vector-picture icon-vector-3x feature-icon"></i> <i class="icon-vector-picture icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}Inline image, video, and tweet previews{% endblocktrans %}</h4> <h4>{% trans %}Inline image, video, and tweet previews{% endtrans %}</h4>
<p>{% blocktrans %}Send a link and we'll automatically generate an inline <p>{% trans %}Send a link and we'll automatically generate an inline
preview.{% endblocktrans %}</p> preview.{% endtrans %}</p>
</div> </div>
<div class="feature-block"> <div class="feature-block">
<i class="icon-vector-paper-clip icon-vector-3x feature-icon"></i> <i class="icon-vector-paper-clip icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}Drag-and-drop file uploads{% endblocktrans %}</h4> <h4>{% trans %}Drag-and-drop file uploads{% endtrans %}</h4>
<p>{% blocktrans %}Drag a file into the compose box and we'll upload and <p>{% trans %}Drag a file into the compose box and we'll upload and
preview it for you. Sharing and discussing work with team preview it for you. Sharing and discussing work with team
mates has never been easier.{% endblocktrans %}</p> mates has never been easier.{% endtrans %}</p>
</div> </div>
<div class="feature-block left"> <div class="feature-block left">
<i class="icon-vector-user icon-vector-3x feature-icon"></i> <i class="icon-vector-user icon-vector-3x feature-icon"></i>
<h4>{% trans "@-notifications" %}</h4> <h4>{{ _("@-notifications") }}</h4>
<p>{% blocktrans %}Want someone's attention in a conversation? @-notify them <p>{% trans %}Want someone's attention in a conversation? @-notify them
and they'll be right over.{% endblocktrans %}</p> and they'll be right over.{% endtrans %}</p>
</div> </div>
<div class="feature-block"> <div class="feature-block">
<i class="icon-vector-bullhorn icon-vector-3x feature-icon"></i> <i class="icon-vector-bullhorn icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}Stream-wide announcements{% endblocktrans %}</h4> <h4>{% trans %}Stream-wide announcements{% endtrans %}</h4>
<p>{% blocktrans %}Use <code>@all</code> or <code>@everyone</code> to get the <p>{% trans %}Use <code>@all</code> or <code>@everyone</code> to get the
attention of everyone in a stream.{% endblocktrans %}</p> attention of everyone in a stream.{% endtrans %}</p>
</div> </div>
<div class="feature-block left"> <div class="feature-block left">
<i class="icon-vector-envelope icon-vector-3x feature-icon"></i> <i class="icon-vector-envelope icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}Emails for important missed messages{% endblocktrans %}</h4> <h4>{% trans %}Emails for important missed messages{% endtrans %}</h4>
<p>{% blocktrans %}If you're missing important conversations when you're away from <p>{% trans %}If you're missing important conversations when you're away from
Zulip, we'll send you an email summary so you're always in the Zulip, we'll send you an email summary so you're always in the
loop.{% endblocktrans %}</p> loop.{% endtrans %}</p>
</div> </div>
<div class="feature-block"> <div class="feature-block">
<i class="icon-vector-info-sign icon-vector-3x feature-icon"></i> <i class="icon-vector-info-sign icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}Desktop notifications{% endblocktrans %}</h4> <h4>{% trans %}Desktop notifications{% endtrans %}</h4>
<p>{% blocktrans %}Configurable for private and stream messages.{% endblocktrans %}</p> <p>{% trans %}Configurable for private and stream messages.{% endtrans %}</p>
</div> </div>
<div class="feature-block left"> <div class="feature-block left">
<i class="icon-vector-bell icon-vector-3x feature-icon"></i> <i class="icon-vector-bell icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}Audible notifications{% endblocktrans %}</h4> <h4>{% trans %}Audible notifications{% endtrans %}</h4>
<p>{% blocktrans %}So you don't miss important messages even when your eyes <p>{% trans %}So you don't miss important messages even when your eyes
are elsewhere.{% endblocktrans %}</p> are elsewhere.{% endtrans %}</p>
</div> </div>
<div class="feature-block"> <div class="feature-block">
<i class="icon-vector-font icon-vector-3x feature-icon"></i> <i class="icon-vector-font icon-vector-3x feature-icon"></i>
<h4>{% trans "Hotkeys" %}</h4> <h4>{{ _("Hotkeys") }}</h4>
<p>{% blocktrans %}Communicate as efficiently as you use your favorite text editor.{% endblocktrans %}</p> <p>{% trans %}Communicate as efficiently as you use your favorite text editor.{% endtrans %}</p>
</div> </div>
<div class="feature-block left"> <div class="feature-block left">
<i class="icon-vector-thumbs-up icon-vector-3x feature-icon"></i> <i class="icon-vector-thumbs-up icon-vector-3x feature-icon"></i>
<h4>{% trans "Emoji" %}</h4> <h4>{{ _("Emoji") }}</h4>
<p>{% blocktrans %}Sometimes it's the simple things in life, like being able <p>{% trans %}Sometimes it's the simple things in life, like being able
to give a <tt>:thumbsup:</tt> while chatting.{% endblocktrans %}</p> to give a <tt>:thumbsup:</tt> while chatting.{% endtrans %}</p>
</div> </div>
<div class="feature-block"> <div class="feature-block">
<i class="icon-vector-edit icon-vector-3x feature-icon"></i> <i class="icon-vector-edit icon-vector-3x feature-icon"></i>
<h4>{% trans "Code" %}</h4> <h4>{{ _("Code") }}</h4>
<p>{% blocktrans %}Discuss code, even multi-line code, with ease, including <p>{% trans %}Discuss code, even multi-line code, with ease, including
syntax-highlighting.{% endblocktrans %}</p> syntax-highlighting.{% endtrans %}</p>
</div> </div>
<div class="feature-block left"> <div class="feature-block left">
<i class="icon-vector-quote-left icon-vector-3x feature-icon"></i> <i class="icon-vector-quote-left icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}Lightweight markup{% endblocktrans %}</h4> <h4>{% trans %}Lightweight markup{% endtrans %}</h4>
<p>{% blocktrans %}Get bulleted lists, clickable links, and nicely-formatted <p>{% trans %}Get bulleted lists, clickable links, and nicely-formatted
e-mail pastes automatically.{% endblocktrans %}</p> e-mail pastes automatically.{% endtrans %}</p>
</div> </div>
<div class="feature-block"> <div class="feature-block">
<i class="icon-vector-eraser icon-vector-3x feature-icon"></i> <i class="icon-vector-eraser icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}Message editing{% endblocktrans %}</h4> <h4>{% trans %}Message editing{% endtrans %}</h4>
<p>{% blocktrans %}Don't worry, you can always fix that typo.{% endblocktrans %}</p> <p>{% trans %}Don't worry, you can always fix that typo.{% endtrans %}</p>
</div> </div>
<div class="feature-block left"> <div class="feature-block left">
<i class="icon-vector-lock icon-vector-3x feature-icon"></i> <i class="icon-vector-lock icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}Invite-only streams{% endblocktrans %}</h4> <h4>{% trans %}Invite-only streams{% endtrans %}</h4>
<p>{% blocktrans %}Enjoy the benefits of threaded conversations while <p>{% trans %}Enjoy the benefits of threaded conversations while
controlling your audience and privacy.{% endblocktrans %}</p> controlling your audience and privacy.{% endtrans %}</p>
</div> </div>
<div class="feature-block"> <div class="feature-block">
<i class="icon-vector-star-empty icon-vector-3x feature-icon"></i> <i class="icon-vector-star-empty icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}Starred messages{% endblocktrans %}</h4> <h4>{% trans %}Starred messages{% endtrans %}</h4>
<p>{% blocktrans %}Keep a todo list or keep track of interesting <p>{% trans %}Keep a todo list or keep track of interesting
conversations.{% endblocktrans %}</p> conversations.{% endtrans %}</p>
</div> </div>
<div class="feature-block left"> <div class="feature-block left">
<i class="icon-vector-github icon-vector-3x feature-icon"></i> <i class="icon-vector-github icon-vector-3x feature-icon"></i>
<h4>{% trans "Integrations" %}</h4> <h4>{{ _("Integrations") }}</h4>
<p>{% blocktrans %}Get alerts and updates from your favorite services with <p>{% trans %}Get alerts and updates from your favorite services with
off-the-shelf <a href="/integrations">integrations</a> for off-the-shelf <a href="/integrations">integrations</a> for
Trac, Nagios, Github, Jenkins, and more.{% endblocktrans %}</p> Trac, Nagios, Github, Jenkins, and more.{% endtrans %}</p>
</div> </div>
<div class="feature-block"> <div class="feature-block">
<i class="icon-vector-sitemap icon-vector-3x feature-icon"></i> <i class="icon-vector-sitemap icon-vector-3x feature-icon"></i>
<h4>{% trans "API" %}</h4> <h4>{{ _("API") }}</h4>
<p>{% blocktrans %}Want to roll your own notifications? We've got a <p>{% trans %}Want to roll your own notifications? We've got a
dead-simple RESTful <a href="/api">API and Python bindings</a> dead-simple RESTful <a href="/api">API and Python bindings</a>
that will make integrations&mdash;both sending and that will make integrations&mdash;both sending and
receiving&mdash;a snap!{% endblocktrans %}</p> receiving&mdash;a snap!{% endtrans %}</p>
</div> </div>
<div class="feature-block left"> <div class="feature-block left">
<i class="icon-vector-mobile-phone icon-vector-3x feature-icon"></i> <i class="icon-vector-mobile-phone icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}Mobile apps{% endblocktrans %}</h4> <h4>{% trans %}Mobile apps{% endtrans %}</h4>
<p>{% blocktrans %}Check Zulip on the go with native <a href="/apps">iOS and <p>{% trans %}Check Zulip on the go with native <a href="/apps">iOS and
Android apps</a>{% endblocktrans %}.</p> Android apps</a>{% endtrans %}.</p>
</div> </div>
<div class="feature-block"> <div class="feature-block">
<i class="icon-vector-desktop icon-vector-3x feature-icon"></i> <i class="icon-vector-desktop icon-vector-3x feature-icon"></i>
<h4>{% blocktrans %}Desktop apps{% endblocktrans %}</h4> <h4>{% trans %}Desktop apps{% endtrans %}</h4>
<p>{% blocktrans %}Prefer Zulip in its own window and rich, OS-level notifications? <p>{% trans %}Prefer Zulip in its own window and rich, OS-level notifications?
Enjoy <a href="/apps">Zulip on your desktop</a>{% endblocktrans %}.</p> Enjoy <a href="/apps">Zulip on your desktop</a>{% endtrans %}.</p>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,5 +1,4 @@
{% extends "zerver/portico.html" %} {% extends "zerver/portico.html" %}
{% load i18n %}
{% block hello_page_container %} hello-main{% endblock %} {% block hello_page_container %} hello-main{% endblock %}
{% block hello_page_footer %} hello-footer{% endblock %} {% block hello_page_footer %} hello-footer{% endblock %}
{% block os_announcement %} {% block os_announcement %}
@ -8,10 +7,10 @@
<img src="/static/images/logo/zballoon.png" class="os-illustration" alt="Zulip balloon" /> <img src="/static/images/logo/zballoon.png" class="os-illustration" alt="Zulip balloon" />
<div class="main-headline-text"> <div class="main-headline-text">
<span class="tagline os-tagline"> <span class="tagline os-tagline">
{% trans 'Zulip has been released as open source software!' %} {{ _('Zulip has been released as open source software!') }}
</span> </span>
<span class="footnote os-footnote"> <span class="footnote os-footnote">
{% blocktrans %}Read the <a href="https://blogs.dropbox.com/tech/2015/09/open-sourcing-zulip-a-dropbox-hack-week-project" target="_blank">announcement</a> or go to <a href="https://www.zulip.org" target="_blank">the Zulip open source project website</a>.{% endblocktrans %} {% trans %}Read the <a href="https://blogs.dropbox.com/tech/2015/09/open-sourcing-zulip-a-dropbox-hack-week-project" target="_blank">announcement</a> or go to <a href="https://www.zulip.org" target="_blank">the Zulip open source project website</a>.{% endtrans %}
</span> </span>
</div> </div>
</div> </div>
@ -24,14 +23,14 @@
<img src="/static/images/logo/textlogo@2x.png" class="main-headline-logo" alt="Zulip logo" /> <img src="/static/images/logo/textlogo@2x.png" class="main-headline-logo" alt="Zulip logo" />
<div class="main-headline-text"> <div class="main-headline-text">
<span class="tagline"> <span class="tagline">
{% trans 'Finally, workplace chat that actually improves your productivity.*' %} {{ _('Finally, workplace chat that actually improves your productivity.*') }}
</span> </span>
<span class="footnote">{% trans "* It's also great for sharing cat pictures" %}.</span> <span class="footnote">{{ _("* It's also great for sharing cat pictures") }}.</span>
{% if not_voyager %} {% if not_voyager %}
{% elif only_sso %} {% elif only_sso %}
<a href="{% url 'login-sso' %}" class="main-signup-button btn btn-large btn-primary">{% trans 'Log in now!' %}</a> <a href="{{ url('login-sso') }}" class="main-signup-button btn btn-large btn-primary">{{ _('Log in now!') }}</a>
{% else %} {% else %}
<a href="{% url 'register' %}" class="main-signup-button btn btn-large btn-primary">{% trans 'Register now!' %}</a> <a href="{{ url('register') }}" class="main-signup-button btn btn-large btn-primary">{{ _('Register now!') }}</a>
{% endif %} {% endif %}
</div> </div>
<img src="/static/images/landing-page/laptop-screenshot.png" class="main-image" alt="Screenshot of Zulip" /> <img src="/static/images/landing-page/laptop-screenshot.png" class="main-image" alt="Screenshot of Zulip" />
@ -42,15 +41,15 @@
<div class="app-main feature-line-container"> <div class="app-main feature-line-container">
<div class="feature-text"> <div class="feature-text">
<span class="tagline"> <span class="tagline">
{% trans 'Conversations, not messages' %}. {{ _('Conversations, not messages') }}.
</span> </span>
<span class="description"> <span class="description">
<p>{% blocktrans %}Every conversation in Zulip has a <em>topic</em>, so it&rsquo;s <p>{% trans %}Every conversation in Zulip has a <em>topic</em>, so it&rsquo;s
easy to keep conversations straight. Are your coworkers discussing easy to keep conversations straight. Are your coworkers discussing
a software bug and the content of your website at the same time? a software bug and the content of your website at the same time?
No problem.{% endblocktrans %} No problem.{% endtrans %}
</p> </p>
<p>{% trans "You wouldnt tolerate email without subject lines or threading, so why do you for chat?" %}</p> <p>{{ _("You wouldnt tolerate email without subject lines or threading, so why do you for chat?") }}</p>
</span> </span>
</div> </div>
<div class="feature-illustration"> <div class="feature-illustration">
@ -63,15 +62,15 @@
<div class="app-main feature-line-container"> <div class="app-main feature-line-container">
<div class="feature-text"> <div class="feature-text">
<span class="tagline"> <span class="tagline">
{% trans 'Easily read just the important things' %}. {{ _('Easily read just the important things') }}.
</span> </span>
<span class="description"> <span class="description">
<p>{% blocktrans %}Sometimes, important things get discussed when you&rsquo;re not <p>{% trans %}Sometimes, important things get discussed when you&rsquo;re not
around. Unfortunately, so do a lot of unimportant things.{% endblocktrans %}</p> around. Unfortunately, so do a lot of unimportant things.{% endtrans %}</p>
<p>{% blocktrans %}<em>Narrowing</em> by stream or topic lets you focus on that important <p>{% trans %}<em>Narrowing</em> by stream or topic lets you focus on that important
customer project without having to read about how Jim&rsquo;s guitar lessons customer project without having to read about how Jim&rsquo;s guitar lessons
are going.{% endblocktrans %}</p> are going.{% endtrans %}</p>
</span> </span>
</div> </div>
<div class="feature-illustration"> <div class="feature-illustration">
@ -84,12 +83,12 @@
<div class="app-main feature-line-container"> <div class="app-main feature-line-container">
<div class="feature-text"> <div class="feature-text">
<span class="tagline"> <span class="tagline">
{% trans "Search that's better than Gmail's" %}. {{ _("Search that's better than Gmail's") }}.
</span> </span>
<span class="description"> <span class="description">
{% blocktrans %}An impressive amount of knowledge lives in your chat system. Zulip&rsquo;s {% trans %}An impressive amount of knowledge lives in your chat system. Zulip&rsquo;s
powerful and fast search will delight you with how quickly you can find powerful and fast search will delight you with how quickly you can find
exactly what you&rsquo;re looking for.{% endblocktrans %} exactly what you&rsquo;re looking for.{% endtrans %}
</span> </span>
</div> </div>
<div class="feature-illustration"> <div class="feature-illustration">
@ -102,14 +101,14 @@
<div class="app-main feature-line-container"> <div class="app-main feature-line-container">
<div class="feature-text"> <div class="feature-text">
<span class="tagline"> <span class="tagline">
{% trans "Integrations that don't intrude" %}. {{ _("Integrations that don't intrude") }}.
</span> </span>
<span class="description"> <span class="description">
<p>{% blocktrans %}Zulip has <a href="/integrations">many integrations</a> and <p>{% trans %}Zulip has <a href="/integrations">many integrations</a> and
a powerful <a href="/api">API</a> to match. But here&rsquo;s a powerful <a href="/api">API</a> to match. But here&rsquo;s
where it gets interesting: thanks to how Zulip categorizes messages, where it gets interesting: thanks to how Zulip categorizes messages,
automated messages never overwhelm you. As with any topic in Zulip, automated messages never overwhelm you. As with any topic in Zulip,
they&rsquo;re easy to focus on, skim, defer to later, or ignore&mdash;as appropriate.{% endblocktrans %}</p> they&rsquo;re easy to focus on, skim, defer to later, or ignore&mdash;as appropriate.{% endtrans %}</p>
</span> </span>
</div> </div>
<div class="feature-illustration"> <div class="feature-illustration">
@ -122,12 +121,12 @@
<div class="app-main feature-line-container"> <div class="app-main feature-line-container">
<div class="feature-text"> <div class="feature-text">
<span class="tagline"> <span class="tagline">
{% trans 'As technical as you want to be' %}. {{ _('As technical as you want to be') }}.
</span> </span>
<span class="description"> <span class="description">
<p>{% trans 'Keyboard shortcuts? Check.' %}<br /> <p>{{ _('Keyboard shortcuts? Check.') }}<br />
{% trans 'Syntax highlighting? Check.' %}<br /> {{ _('Syntax highlighting? Check.') }}<br />
{% trans 'Discuss code and technical topics with ease.' %}</p> {{ _('Discuss code and technical topics with ease.') }}</p>
</span> </span>
</div> </div>
<div class="feature-illustration"> <div class="feature-illustration">
@ -140,12 +139,12 @@
<div class="app-main feature-line-container"> <div class="app-main feature-line-container">
<div class="feature-text"> <div class="feature-text">
<span class="tagline"> <span class="tagline">
&hellip; {% trans 'and all the obvious stuff, too.' %} &hellip; {{ _('and all the obvious stuff, too.') }}
</span> </span>
<span class="description"> <span class="description">
<p>{% blocktrans %}Drag-and-drop file uploads, image pasting, group private messages, <p>{% trans %}Drag-and-drop file uploads, image pasting, group private messages,
audible notifications, missed-message emails, desktop apps, and audible notifications, missed-message emails, desktop apps, and
<a href="/features">everything else you might want</a>. Including emoji, naturally.{% endblocktrans %}</p> <a href="/features">everything else you might want</a>. Including emoji, naturally.{% endtrans %}</p>
</span> </span>
</div> </div>
<div class="feature-illustration"> <div class="feature-illustration">
@ -158,7 +157,7 @@
<div class="app-main feature-line-container"> <div class="app-main feature-line-container">
<div class="platform-text"> <div class="platform-text">
<span class="tagline"> <span class="tagline">
{% trans 'On the platform of your choice.' %} {{ _('On the platform of your choice.') }}
</span> </span>
</div> </div>
<div class="platform-icons"> <div class="platform-icons">
@ -194,9 +193,9 @@
<div class="app-main feature-line-container centered-content"> <div class="app-main feature-line-container centered-content">
{% if not_voyager %} {% if not_voyager %}
{% elif only_sso %} {% elif only_sso %}
<a href="{% url 'login-sso' %}" class="bottom-signup-button btn btn-large btn-primary">{% trans 'Log in now' %}</a> <a href="{{ url('login-sso') }}" class="bottom-signup-button btn btn-large btn-primary">{{ _('Log in now') }}</a>
{% else %} {% else %}
<a href="{% url 'register' %}" class="bottom-signup-button btn btn-large btn-primary">{% trans 'Register now' %}</a> <a href="{{ url('register') }}" class="bottom-signup-button btn btn-large btn-primary">{{ _('Register now') }}</a>
{% endif %} {% endif %}
</div> </div>
</div> </div>

View File

@ -1,55 +1,54 @@
{% load i18n %}
{# Home tab of the app, containing messages. #} {# Home tab of the app, containing messages. #}
<div class="message_area_padder message_list" id="main_div"> <div class="message_area_padder message_list" id="main_div">
<div id="loading_more_messages_indicator"></div> <div id="loading_more_messages_indicator"></div>
<div id="page_loading_indicator"></div> <div id="page_loading_indicator"></div>
<div id="first_run_message" class="empty_feed_notice"> <div id="first_run_message" class="empty_feed_notice">
<h4>{% trans 'Welcome to' %} {{product_name}}</h4> <h4>{{ _('Welcome to') }} {{product_name}}</h4>
<p>{% blocktrans %}See, the thing about it is... there aren't any messages <p>{% trans %}See, the thing about it is... there aren't any messages
here for you right now. I'm sure someone will eventually send here for you right now. I'm sure someone will eventually send
you one.{% endblocktrans %}</p> you one.{% endtrans %}</p>
<p>{% trans 'Or' %}, <strong>{% trans 'take matters into your own hands' %}</strong>, <p>{{ _('Or') }}, <strong>{{ _('take matters into your own hands') }}</strong>,
{% trans 'and' %} <a href="#" class="empty_feed_compose_stream"> {{ _('and') }} <a href="#" class="empty_feed_compose_stream">
{% trans 'compose a new stream message' %}</a>.</p> {{ _('compose a new stream message') }}</a>.</p>
</div> </div>
<div id="empty_narrow_message" class="empty_feed_notice"> <div id="empty_narrow_message" class="empty_feed_notice">
<h4>{% trans "Nothing's been sent here yet!" %}</h4> <h4>{{ _("Nothing's been sent here yet!") }}</h4>
<p>{% trans 'Why not' %} <a href="#" class="empty_feed_compose_stream"> <p>{{ _('Why not') }} <a href="#" class="empty_feed_compose_stream">
{% trans 'start the conversation' %}</a>?</p> {{ _('start the conversation') }}</a>?</p>
</div> </div>
<div id="empty_narrow_all_private_message" class="empty_feed_notice"> <div id="empty_narrow_all_private_message" class="empty_feed_notice">
<h4>{% trans 'You have no private messages yet!' %}</h4> <h4>{{ _('You have no private messages yet!') }}</h4>
<p>{% trans 'Why not' %} <a href="#" class="empty_feed_compose_private"> <p>{{ _('Why not') }} <a href="#" class="empty_feed_compose_private">
{% trans 'start the conversation' %}</a>?</p> {{ _('start the conversation') }}</a>?</p>
</div> </div>
<div id="empty_narrow_private_message" class="empty_feed_notice"> <div id="empty_narrow_private_message" class="empty_feed_notice">
<h4>{% trans 'You have no private messages with this person yet!' %}</h4> <h4>{{ _('You have no private messages with this person yet!') }}</h4>
<p>{% trans 'Why not' %} <a href="#" class="empty_feed_compose_private"> <p>{{ _('Why not') }} <a href="#" class="empty_feed_compose_private">
{% trans 'start the conversation' %}</a>?</p> {{ _('start the conversation') }}</a>?</p>
</div> </div>
<div id="empty_narrow_multi_private_message" class="empty_feed_notice"> <div id="empty_narrow_multi_private_message" class="empty_feed_notice">
<h4>{% trans 'You have no private messages with these people yet!' %}</h4> <h4>{{ _('You have no private messages with these people yet!') }}</h4>
<p>{% trans 'Why not' %} <a href="#" class="empty_feed_compose_private"> <p>{{ _('Why not') }} <a href="#" class="empty_feed_compose_private">
{% trans 'start the conversation' %}</a>?</p> {{ _('start the conversation') }}</a>?</p>
</div> </div>
<div id="nonsubbed_stream_narrow_message" class="empty_feed_notice"> <div id="nonsubbed_stream_narrow_message" class="empty_feed_notice">
<h4>{% trans "You aren't subscribed to this stream!" %}</h4> <h4>{{ _("You aren't subscribed to this stream!") }}</h4>
<p>{% trans 'Want to' %} <a href="#" class="empty_feed_join">{% trans 'join it' %}</a>?</p> <p>{{ _('Want to') }} <a href="#" class="empty_feed_join">{{ _('join it') }}</a>?</p>
</div> </div>
<div id="empty_star_narrow_message" class="empty_feed_notice"> <div id="empty_star_narrow_message" class="empty_feed_notice">
<h4>{% trans "You haven't starred anything yet!" %}</h4> <h4>{{ _("You haven't starred anything yet!") }}</h4>
</div> </div>
<div id="empty_narrow_all_mentioned" class="empty_feed_notice"> <div id="empty_narrow_all_mentioned" class="empty_feed_notice">
<h4>{% trans "You haven't been mentioned yet" %}.</h4> <h4>{{ _("You haven't been mentioned yet") }}.</h4>
</div> </div>
<div id="empty_search_narrow_message" class="empty_feed_notice"> <div id="empty_search_narrow_message" class="empty_feed_notice">
<h4>{% trans 'Nobody has talked about that yet!' %}</h4> <h4>{{ _('Nobody has talked about that yet!') }}</h4>
</div> </div>
<div class="message_table focused_table" id="zhome"> <div class="message_table focused_table" id="zhome">
</div> </div>

View File

@ -1,11 +1,7 @@
{% extends "zerver/base.html" %} {% extends "zerver/base.html" %}
{% load i18n %}
{# The app itself. #} {# The app itself. #}
{# Includes some other templates as tabs. #} {# Includes some other templates as tabs. #}
{% load compressed %}
{% load minified_js %}
{% block page_params %} {% block page_params %}
{# Insert parameters, which have been encoded with JSONEncoderForHTML. #} {# Insert parameters, which have been encoded with JSONEncoderForHTML. #}
<script type="text/javascript"> <script type="text/javascript">
@ -35,25 +31,25 @@ var page_params = {{ page_params }};
{% if nofontface %} {% if nofontface %}
{# We can't use @font-face on qtwebkit, so use differently minified CSS #} {# We can't use @font-face on qtwebkit, so use differently minified CSS #}
{% compressed_css 'app-fontcompat' %} {{ compressed_css('app-fontcompat')|safe }}
{% else %} {% else %}
{% compressed_css 'app' %} {{ compressed_css('app')|safe }}
{% endif %} {% endif %}
{% minified_js 'app' %} {{ minified_js('app')|safe }}
{% if not pipeline %} {% if not pipeline %}
<script type="text/javascript" src="/webpack/bundle.js"></script> <script type="text/javascript" src="/webpack/bundle.js"></script>
{% endif %} {% endif %}
{% if debug %} {% if debug %}
{% minified_js 'app_debug' %} {{ minified_js('app_debug')|safe }}
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div id="css-loading"> <div id="css-loading">
<h3>{% trans 'Loading' %}...</h3> <h3>{{ _('Loading') }}...</h3>
<p>{% trans 'If this message does not go away, please wait a couple seconds and' %} <a href="javascript:location.reload(true)">{% trans 'reload' %}</a> {% trans 'the page' %}.</p> <p>{{ _('If this message does not go away, please wait a couple seconds and') }} <a href="javascript:location.reload(true)">{{ _('reload') }}</a> {{ _('the page') }}.</p>
</div> </div>
<div id="top-screen" class="screen"></div> <div id="top-screen" class="screen"></div>

View File

@ -1,14 +1,12 @@
{% extends "zerver/portico.html" %} {% extends "zerver/portico.html" %}
{% load i18n %}
{% load minified_js %}
{# A landing page for the first user in a realm, prompting her to invite her colleages. #} {# A landing page for the first user in a realm, prompting her to invite her colleages. #}
{% block for_you %}for {{company_name}} {% endblock %} {% block for_you %}for {{company_name}} {% endblock %}
{% block customhead %} {% block customhead %}
{{ block.super }} {{ super() }}
{% minified_js 'initial_invite' %} {{ minified_js('initial_invite')|safe }}
<script type="text/javascript"> <script type="text/javascript">
var invite_suffix = "{{invite_suffix}}"; var invite_suffix = "{{invite_suffix}}";
@ -18,18 +16,18 @@
{% block portico_content %} {% block portico_content %}
<h1 style="margin-top:30px;">{% trans "You're the first one here!" %}</h1> <h1 style="margin-top:30px;">{{ _("You're the first one here!")|safe }}</h1>
<p> <p>
{% trans "Let's invite some folks for you to chat with" %}: {{ _("Let's invite some folks for you to chat with") }}:
</p> </p>
<div id="invite_rows"> <div id="invite_rows">
<form id="invite_form"> <form id="invite_form">
{% csrf_token %} {{ csrf_input }}
<div class="invite_row"><input name="email_1" class="invite_email" type={% if not invite_suffix %}"email"{% else %}"text"{% endif %} /> {% if invite_suffix %}@{{invite_suffix}}{% endif %}</div> <div class="invite_row"><input name="email_1" class="invite_email" type={% if not invite_suffix %}"email"{% else %}"text"{% endif %} /> {% if invite_suffix %}@{{invite_suffix}}{% endif %}</div>
<p id="invite_blurb">({% trans "We'll email invitations to them" %})</p> <p id="invite_blurb">({{ _("We'll email invitations to them") }})</p>
<div class="alert" id="invite_error" style="display: none;"> <div class="alert" id="invite_error" style="display: none;">
</div> </div>
<button id="submit_invitation" class="btn btn-primary" data-loading-text="Next">{% trans 'Next' %} »</button> <button id="submit_invitation" class="btn btn-primary" data-loading-text="Next">{{ _('Next') }} »</button>
</form> </form>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -635,14 +635,14 @@
<p>Let's say you want a notification each time a case is updated. Put <p>Let's say you want a notification each time a case is updated. Put
in a descriptive name like "Announce case update", and copy-paste in a descriptive name like "Announce case update", and copy-paste
this to the "Appended URL path":</p> this to the "Appended URL path":</p>
{% verbatim %} {% raw %}
<p><code>?stream=desk&amp;topic={{case.id}}:+{{case.subject}}</code></p> <p><code>?stream=desk&amp;topic={{case.id}}:+{{case.subject}}</code></p>
{% endverbatim %} {% endraw %}
<p>The "appended URL path" will be the same for every notification — <p>The "appended URL path" will be the same for every notification —
it makes sure the notification goes to the appropriate stream and topic it makes sure the notification goes to the appropriate stream and topic
within Zulip. Next, copy this template Zulip message into "Message to within Zulip. Next, copy this template Zulip message into "Message to
POST":</p> POST":</p>
{% verbatim %} {% raw %}
<pre><code <pre><code
>Case [{{case.id}}, {{case.subject}}]({{case.direct_url}}), was updated. >Case [{{case.id}}, {{case.subject}}]({{case.direct_url}}), was updated.
@ -655,7 +655,7 @@
<code>{{</code> and <code>}}</code> <code>{{</code> and <code>}}</code>
will be filled in by Desk.com for each event. The dialog should look will be filled in by Desk.com for each event. The dialog should look
like this:</p> like this:</p>
{% endverbatim %} {% endraw %}
<img src="/static/images/integrations/desk/004.png" /> <img src="/static/images/integrations/desk/004.png" />
<p>Save it, and then click "On" next to the action to enable it. This <p>Save it, and then click "On" next to the action to enable it. This
@ -1370,7 +1370,7 @@ key = NAGIOS_BOT_API_KEY
there, click "Add a webhook". Fill in the form like this:</p> there, click "Add a webhook". Fill in the form like this:</p>
<ul> <ul>
<li><b>Name</b>: Zulip</li> <li><b>Name</b>: Zulip</li>
<li><b>Endpoint URL</b>: <code>{{ external_api_uri }}{% verbatim %}/v1/external/pagerduty?api_key=abcdefgh&amp;stream=pagerduty{% endverbatim %}</code></li> <li><b>Endpoint URL</b>: <code>{{ external_api_uri }}/v1/external/pagerduty?api_key=abcdefgh&amp;stream=pagerduty</code></li>
</ul> </ul>
<img class="screenshot" src="/static/images/integrations/pagerduty/002.png" /> <img class="screenshot" src="/static/images/integrations/pagerduty/002.png" />
@ -2077,7 +2077,7 @@ access_token_secret =</pre>
<p>From there, click "URL target". Fill in the form like this:</p> <p>From there, click "URL target". Fill in the form like this:</p>
<ul> <ul>
<li><b>Title</b>: Zulip</li> <li><b>Title</b>: Zulip</li>
<li><b>URL</b>: <code>{{ external_api_uri }}{% verbatim %}/v1/external/zendesk?ticket_title={{ticket.title}}&amp;ticket_id={{ticket.id}}&amp;stream=zendesk{% endverbatim %}</code></li> <li><b>URL</b>: <code>{{ external_api_uri }}{% raw %}/v1/external/zendesk?ticket_title={{ticket.title}}&amp;ticket_id={{ticket.id}}&amp;stream=zendesk{% endraw %}</code></li>
<li><b>Method</b>: POST</li> <li><b>Method</b>: POST</li>
<li><b>Attribute Name</b>: message</li> <li><b>Attribute Name</b>: message</li>
<li><b>Username</b>: <em>your bot's user name, e.g.</em> <code>zendesk-bot@yourdomain.com</code></li> <li><b>Username</b>: <em>your bot's user name, e.g.</em> <code>zendesk-bot@yourdomain.com</code></li>
@ -2105,7 +2105,7 @@ access_token_secret =</pre>
<p>Next we need need to enter the message body into Message. You can use <p>Next we need need to enter the message body into Message. You can use
Zulip markdown and the Zendesk placeholders when creating your message. Zulip markdown and the Zendesk placeholders when creating your message.
You can copy this example template:</p> You can copy this example template:</p>
{% verbatim %} {% raw %}
<pre><code>Ticket [#{{ticket.id}}: {{ticket.title}}]({{ticket.link}}), was updated by {{current_user.name}} <pre><code>Ticket [#{{ticket.id}}: {{ticket.title}}]({{ticket.link}}), was updated by {{current_user.name}}
* Status: {{ticket.status}} * Status: {{ticket.status}}
@ -2117,7 +2117,7 @@ access_token_secret =</pre>
``` quote ``` quote
{{ticket.description}} {{ticket.description}}
``` </code></pre> ``` </code></pre>
{% endverbatim %} {% endraw %}
<img src="/static/images/integrations/zendesk/006.png" /> <img src="/static/images/integrations/zendesk/006.png" />
@ -2136,7 +2136,7 @@ access_token_secret =</pre>
{% endblock %} {% endblock %}
{% block customhead %} {% block customhead %}
{{ block.super }} {{ super() }}
<script type="text/javascript"> <script type="text/javascript">
$(function() { $(function() {
$("a.title").addClass("show-integral"); $("a.title").addClass("show-integral");

View File

@ -1,16 +1,15 @@
{% load i18n %}
<div class="modal hide" id="invite-user" tabindex="-1" role="dialog" <div class="modal hide" id="invite-user" tabindex="-1" role="dialog"
aria-labelledby="invite-user-label" aria-hidden="true"> aria-labelledby="invite-user-label" aria-hidden="true">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="invite-user-label">{% trans 'Invite coworkers to' %} {{product_name}}</h3> <h3 id="invite-user-label">{{ _('Invite coworkers to') }} {{product_name}}</h3>
</div> </div>
<form id="invite_user_form" class="form-horizontal" <form id="invite_user_form" class="form-horizontal"
action="/json/invite_users" method="POST">{% csrf_token %} action="/json/invite_users" method="POST">{{ csrf_input }}
<div class="modal-body"> <div class="modal-body">
<div class="control-group"> <div class="control-group">
<div id="invite-result"></div> <div id="invite-result"></div>
<label class="control-label" for="invitee_emails">{% trans 'Emails (one on each line or comma-separated)' %}</label> <label class="control-label" for="invitee_emails">{{ _('Emails (one on each line or comma-separated)') }}</label>
<div class="controls"> <div class="controls">
<textarea rows="2" id="invitee_emails" <textarea rows="2" id="invitee_emails"
name="invitee_emails" name="invitee_emails"
@ -19,13 +18,13 @@
</div> </div>
<div class="alert" id="invite_status"></div> <div class="alert" id="invite_status"></div>
<div class="control-group"> <div class="control-group">
<label class="control-label" for="streams_to_add">{% trans 'Streams they should join' %}</label> <label class="control-label" for="streams_to_add">{{ _('Streams they should join') }}</label>
<div class="controls" id="streams_to_add"></div> <div class="controls" id="streams_to_add"></div>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-default" data-dismiss="modal" aria-hidden="true">{% trans 'Cancel' %}</button> <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">{{ _('Cancel') }}</button>
<button id="submit-invitation" class="btn btn-primary" data-loading-text="Inviting..." type="submit">{% trans 'Invite' %}</button> <button id="submit-invitation" class="btn btn-primary" data-loading-text="Inviting..." type="submit">{{ _('Invite') }}</button>
</div> </div>
</form> </form>
</div> </div>

View File

@ -1,77 +1,76 @@
{% load i18n %}
<div class="modal hide" id="keyboard-shortcuts" tabindex="-1" role="dialog" <div class="modal hide" id="keyboard-shortcuts" tabindex="-1" role="dialog"
aria-labelledby="keyboard-shortcuts-label" aria-hidden="true"> aria-labelledby="keyboard-shortcuts-label" aria-hidden="true">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="keyboard-shortcuts-label">{% blocktrans %}Keyboard shortcuts{% endblocktrans %}</h3> <h3 id="keyboard-shortcuts-label">{% trans %}Keyboard shortcuts{% endtrans %}</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div> <div>
<table class="hotkeys_table table table-striped table-bordered table-condensed"> <table class="hotkeys_table table table-striped table-bordered table-condensed">
<thead> <thead>
<tr> <tr>
<th colspan="2">{% trans "Navigation" %}</th> <th colspan="2">{{ _("Navigation") }}</th>
</tr> </tr>
</thead> </thead>
<tr> <tr>
<td class="hotkey">/</td> <td class="hotkey">/</td>
<td class="definition">{% blocktrans %}Initiate a search{% endblocktrans %}</td> <td class="definition">{% trans %}Initiate a search{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">q</td> <td class="hotkey">q</td>
<td class="definition">{% blocktrans %}Search people{% endblocktrans %}</td> <td class="definition">{% trans %}Search people{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">Up or k</td> <td class="hotkey">Up or k</td>
<td class="definition">{% blocktrans %}Previous message{% endblocktrans %}</td> <td class="definition">{% trans %}Previous message{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">Down or j</td> <td class="hotkey">Down or j</td>
<td class="definition">{% blocktrans %}Next message{% endblocktrans %}</td> <td class="definition">{% trans %}Next message{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">PgUp, K</td> <td class="hotkey">PgUp, K</td>
<td class="definition">{% blocktrans %}Scroll up{% endblocktrans %}</td> <td class="definition">{% trans %}Scroll up{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">PgDn, J, Spacebar</td> <td class="hotkey">PgDn, J, Spacebar</td>
<td class="definition">{% blocktrans %}Scroll down{% endblocktrans %}</td> <td class="definition">{% trans %}Scroll down{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">End</td> <td class="hotkey">End</td>
<td class="definition">{% blocktrans %}Last message{% endblocktrans %}</td> <td class="definition">{% trans %}Last message{% endtrans %}</td>
</tr> </tr>
</table> </table>
<table class="hotkeys_table table table-striped table-bordered table-condensed"> <table class="hotkeys_table table table-striped table-bordered table-condensed">
<thead> <thead>
<tr> <tr>
<th colspan="2">{% blocktrans %}Composing messages{% endblocktrans %}</th> <th colspan="2">{% trans %}Composing messages{% endtrans %}</th>
</tr> </tr>
</thead> </thead>
<tr> <tr>
<td class="hotkey">Enter or r</td> <td class="hotkey">Enter or r</td>
<td class="definition">{% blocktrans %}Reply to message{% endblocktrans %}</td> <td class="definition">{% trans %}Reply to message{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">R</td> <td class="hotkey">R</td>
<td class="definition">{% blocktrans %}Reply to author{% endblocktrans %}</td> <td class="definition">{% trans %}Reply to author{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">c</td> <td class="hotkey">c</td>
<td class="definition">{% blocktrans %}New stream message{% endblocktrans %}</td> <td class="definition">{% trans %}New stream message{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">C</td> <td class="hotkey">C</td>
<td class="definition">{% blocktrans %}New private message{% endblocktrans %}</td> <td class="definition">{% trans %}New private message{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">Tab then Enter</td> <td class="hotkey">Tab then Enter</td>
<td class="definition">{% blocktrans %}Send message{% endblocktrans %}</td> <td class="definition">{% trans %}Send message{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">Esc</td> <td class="hotkey">Esc</td>
<td class="definition">{% blocktrans %}Cancel compose{% endblocktrans %}</td> <td class="definition">{% trans %}Cancel compose{% endtrans %}</td>
</tr> </tr>
</table> </table>
</div> </div>
@ -80,53 +79,53 @@
<table class="hotkeys_table table table-striped table-bordered table-condensed"> <table class="hotkeys_table table table-striped table-bordered table-condensed">
<thead> <thead>
<tr> <tr>
<th colspan="2">{% trans "Narrowing" %}</th> <th colspan="2">{{ _("Narrowing") }}</th>
</tr> </tr>
</thead> </thead>
<tr> <tr>
<td class="hotkey">s</td> <td class="hotkey">s</td>
<td class="definition">{% blocktrans %}Narrow by stream{% endblocktrans %}</td> <td class="definition">{% trans %}Narrow by stream{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">S</td> <td class="hotkey">S</td>
<td class="definition">{% blocktrans %}Narrow by topic{% endblocktrans %}</td> <td class="definition">{% trans %}Narrow by topic{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">v</td> <td class="hotkey">v</td>
<td class="definition">{% blocktrans %}Narrow to all private messages{% endblocktrans %}</td> <td class="definition">{% trans %}Narrow to all private messages{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">A or D</td> <td class="hotkey">A or D</td>
<td class="definition">{% blocktrans %}Cycle between stream narrows{% endblocktrans %}</td> <td class="definition">{% trans %}Cycle between stream narrows{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">Esc</td> <td class="hotkey">Esc</td>
<td class="definition">{% blocktrans %}Return to home view{% endblocktrans %}</td> <td class="definition">{% trans %}Return to home view{% endtrans %}</td>
</tr> </tr>
</table> </table>
<table class="hotkeys_table table table-striped table-bordered table-condensed"> <table class="hotkeys_table table table-striped table-bordered table-condensed">
<thead> <thead>
<tr> <tr>
<th colspan="2">{% trans "Menus" %}</th> <th colspan="2">{{ _("Menus") }}</th>
</tr> </tr>
</thead> </thead>
<tr> <tr>
<td class="hotkey">i</td> <td class="hotkey">i</td>
<td class="definition">{% blocktrans %}Open message actions menu{% endblocktrans %}</td> <td class="definition">{% trans %}Open message actions menu{% endtrans %}</td>
</tr> </tr>
<tr id="edit-message-hotkey-help"> <tr id="edit-message-hotkey-help">
<td class="hotkey">i then Enter</td> <td class="hotkey">i then Enter</td>
<td class="definition">{% blocktrans %}Edit a message you sent{% endblocktrans %}</td> <td class="definition">{% trans %}Edit a message you sent{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td class="hotkey">?</td> <td class="hotkey">?</td>
<td class="definition">{% blocktrans %}Show these keyboard shortcuts{% endblocktrans %}</td> <td class="definition">{% trans %}Show these keyboard shortcuts{% endtrans %}</td>
</tr> </tr>
</table> </table>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">{% trans "Close" %}</button> <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">{{ _("Close") }}</button>
</div> </div>
</div> </div>

View File

@ -1,23 +1,22 @@
{% load i18n %}
<div class="left-sidebar" id="left-sidebar"> <div class="left-sidebar" id="left-sidebar">
<div class="bottom_sidebar"> <div class="bottom_sidebar">
<ul id="global_filters" class="filters"> <ul id="global_filters" class="filters">
{# Special-case this link so we don't actually go to page top. #} {# Special-case this link so we don't actually go to page top. #}
<li data-name="home" <li data-name="home"
class="global-filter active-filter"><span class="filter-icon"><i class="icon-vector-home"></i></span><a href="#">{% trans 'Home' %} <span class="count"><span class="value"></span></span></a></li> class="global-filter active-filter"><span class="filter-icon"><i class="icon-vector-home"></i></span><a href="#">{{ _('Home') }} <span class="count"><span class="value"></span></span></a></li>
<li data-name="private" class="global-filter"><span class="filter-icon"><i class="icon-vector-user"></i></span><a href="#narrow/is/private">{% trans 'Private messages' %} <span class="count"><span class="value"></span></span></a></li> <li data-name="private" class="global-filter"><span class="filter-icon"><i class="icon-vector-user"></i></span><a href="#narrow/is/private">{{ _('Private messages') }} <span class="count"><span class="value"></span></span></a></li>
<li data-name="starred" class="global-filter"><span class="filter-icon"><i class="icon-vector-star"></i></span><a href="#narrow/is/starred">{% trans 'Starred messages' %}</a></li> <li data-name="starred" class="global-filter"><span class="filter-icon"><i class="icon-vector-star"></i></span><a href="#narrow/is/starred">{{ _('Starred messages') }}</a></li>
<li data-name="mentioned" class="global-filter"><span class="filter-icon"><i class="icon-vector-tag"></i></span><a href="#narrow/is/mentioned">{% trans '@-mentions' %}<span class="count"><span class="value"></span></span></a></li> <li data-name="mentioned" class="global-filter"><span class="filter-icon"><i class="icon-vector-tag"></i></span><a href="#narrow/is/mentioned">{{ _('@-mentions') }}<span class="count"><span class="value"></span></span></a></li>
</ul> </ul>
<div id="streams_list" class="zoom-out"> <div id="streams_list" class="zoom-out">
<div id="streams_header" class="zoom-in-hide"><h4 class="sidebar-title">{% trans 'STREAMS' %}</h4> <div id="streams_header" class="zoom-in-hide"><h4 class="sidebar-title">{{ _('STREAMS') }}</h4>
<a href=""><i id="streams_inline_cog" class='icon-vector-cog' data-toggle="tooltip" title="Subscribe, add, or configure streams"></i></a> <a href=""><i id="streams_inline_cog" class='icon-vector-cog' data-toggle="tooltip" title="Subscribe, add, or configure streams"></i></a>
</div> </div>
<div id="topics_header"> <div id="topics_header">
<div class="all-streams-padding"> <div class="all-streams-padding">
<ul class="filters"> <ul class="filters">
<li data-name="all-streams"> <li data-name="all-streams">
<i class="icon-vector-chevron-left"></i> <a href="" class="show-all-streams">{% trans 'All streams' %}</a> <i class="icon-vector-chevron-left"></i> <a href="" class="show-all-streams">{{ _('All streams') }}</a>
</li> </li>
</ul> </ul>
</div> </div>
@ -28,24 +27,24 @@
</div> </div>
<div id="share-the-love"> <div id="share-the-love">
<div id="share-the-love-expand-collapse"> <div id="share-the-love-expand-collapse">
<i class="toggle icon-vector-caret-right"></i><div id="sharethelove-header"><h4 class="share-the-love-title">{% trans 'SHARE THE LOVE' %}<span class="still-have-invites"> (<span class="invite-count">0</span>)</span></h4></div> <i class="toggle icon-vector-caret-right"></i><div id="sharethelove-header"><h4 class="share-the-love-title">{{ _('SHARE THE LOVE') }}<span class="still-have-invites"> (<span class="invite-count">0</span>)</span></h4></div>
</div> </div>
<div id="share-the-love-contents"> <div id="share-the-love-contents">
<div id="tell-a-friend-success" class="alert alert-success"> <div id="tell-a-friend-success" class="alert alert-success">
<strong>{% trans 'Thanks!' %}</strong> {% trans 'A hand-crafted, artisanal invite is on the way' %}. <strong>{{ _('Thanks!') }}</strong> {{ _('A hand-crafted, artisanal invite is on the way') }}.
</div> </div>
<div class="still-have-invites" id="encouraging-invite-message"> <div class="still-have-invites" id="encouraging-invite-message">
<p> <p>
{% trans "Know someone who would love Zulip for their company or group? Invite 'em!" %} {{ _("Know someone who would love Zulip for their company or group? Invite 'em!") }}
</p> </p>
</div> </div>
<div class="no-more-invites"> <div class="no-more-invites">
<p> <p>
{% blocktrans %}We'll have more invites for you soon, but {% trans %}We'll have more invites for you soon, but
for now, enjoy this <a target="_blank" for now, enjoy this <a target="_blank"
href="http://www.youtube.com/watch?v=PW71En5Pa5s#t=2m01s">song href="http://www.youtube.com/watch?v=PW71En5Pa5s#t=2m01s">song
that expresses how we feel when you're that expresses how we feel when you're
logged out</a>.{% endblocktrans %} logged out</a>.{% endtrans %}
</p> </p>
</div> </div>
<div class="still-have-invites"> <div class="still-have-invites">
@ -57,7 +56,7 @@
</div> </div>
<div class="invite-count-area"> <div class="invite-count-area">
<span id="invite-hearts"></span> <span id="invite-hearts"></span>
<small class="pull-right"><span class="invite-count">0</span> {% trans 'invite' %}<span class="invite-count-is-plural">s</span> {% trans 'remaining' %}</small> <small class="pull-right"><span class="invite-count">0</span> {{ _('invite') }}<span class="invite-count-is-plural">s</span> {{ _('remaining') }}</small>
</div> </div>
</div> </div>
</div> </div>

View File

@ -2,12 +2,9 @@
{# Login page. #} {# Login page. #}
{% load i18n %}
{% load minified_js %}
{% block customhead %} {% block customhead %}
{{ block.super }} {{ super() }}
{% minified_js 'signup' %} {{ minified_js('signup')|safe }}
{% endblock %} {% endblock %}
{% block os_announcement %} {% block os_announcement %}
@ -16,10 +13,10 @@
<img src="/static/images/logo/zballoon.png" class="os-illustration" alt="Zulip balloon" /> <img src="/static/images/logo/zballoon.png" class="os-illustration" alt="Zulip balloon" />
<div class="main-headline-text"> <div class="main-headline-text">
<span class="tagline os-tagline"> <span class="tagline os-tagline">
{% trans 'Zulip has been released as open source software!' %} {{ _('Zulip has been released as open source software!') }}
</span> </span>
<span class="footnote os-footnote"> <span class="footnote os-footnote">
{% trans 'Read the' %} <a href="https://blogs.dropbox.com/tech/2015/09/open-sourcing-zulip-a-dropbox-hack-week-project" target="_blank">{% trans 'announcement' %}</a> {% trans 'or go to' %} <a href="https://www.zulip.org" target="_blank">{% trans 'the Zulip open source project website' %}</a>. {{ _('Read the') }} <a href="https://blogs.dropbox.com/tech/2015/09/open-sourcing-zulip-a-dropbox-hack-week-project" target="_blank">{{ _('announcement') }}</a> {{ _('or go to') }} <a href="https://www.zulip.org" target="_blank">{{ _('the Zulip open source project website') }}</a>.
</span> </span>
</div> </div>
</div> </div>
@ -45,30 +42,30 @@ autofocus('#id_username');
<div class="app-main login-page-container"> <div class="app-main login-page-container">
{% if dev_auth_enabled %} {% if dev_auth_enabled %}
<h3 class="login-page-header">{% trans 'Zulip Dev Login' %}</h3> <h3 class="login-page-header">{{ _('Zulip Dev Login') }}</h3>
{% if not password_auth_enabled %} {% if not password_auth_enabled %}
<h4 class="login-page-subheader">{% trans 'Choose a user' %}:</h4> <h4 class="login-page-subheader">{{ _('Choose a user') }}:</h4>
{% endif %} {% endif %}
{% else %} {% else %}
<h3 class="login-page-header">{% trans 'You look familiar' %}.</h3> <h3 class="login-page-header">{{ _('You look familiar') }}.</h3>
{% endif %} {% endif %}
{% if only_sso %} {% if only_sso %}
{% comment %}SSO users don't have a password.{% endcomment %} {# SSO users don't have a password. #}
<div class="login-sso"> <div class="login-sso">
<a href="/accounts/login/sso" class="btn btn-large btn-primary">{% trans 'Sign in with SSO' %}</a> <a href="/accounts/login/sso" class="btn btn-large btn-primary">{{ _('Sign in with SSO') }}</a>
</div> </div>
{% else %} {% else %}
{% comment %}Non-SSO users.{% endcomment %} {# Non-SSO users. #}
{% if form.errors or desktop_sso_unknown_email %} {% if form.errors or desktop_sso_unknown_email %}
<div class="alert alert-error"> <div class="alert alert-error">
{% if desktop_sso_unknown_email %} {% if desktop_sso_unknown_email %}
{% trans 'Zulip is not currently available for your domain' %}. <br /> {{ _('Zulip is not currently available for your domain') }}. <br />
{% else %} {% else %}
{% for error in form.errors.values %} {% for error in form.errors.values() %}
<div>{{ error | striptags }}</div> <div>{{ error | striptags }}</div>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
@ -77,7 +74,7 @@ autofocus('#id_username');
{% if email %} {% if email %}
<div class="alert"> <div class="alert">
{% trans "You've already registered with this email address. Please log in below" %}. {{ _("You've already registered with this email address. Please log in below") }}.
</div> </div>
{% endif %} {% endif %}
@ -85,14 +82,14 @@ autofocus('#id_username');
<form name="login_form" id="login_form" method="post" class="login-form" <form name="login_form" id="login_form" method="post" class="login-form"
{% if desktop_sso_dispatch %} {% if desktop_sso_dispatch %}
{# desktop_sso_dispatch is only set when this template is invoked by zilencer.views #} {# desktop_sso_dispatch is only set when this template is invoked by zilencer.views #}
action="{% url 'zilencer.views.account_deployment_dispatch' %}" action="{{ url('zilencer.views.account_deployment_dispatch') }}"
{% else %} {% else %}
action="{% url 'django.contrib.auth.views.login' %}?next={{ next }}" action="{{ url('django.contrib.auth.views.login') }}?next={{ next }}"
{% endif %} {% endif %}
> >
{% csrf_token %} {{ csrf_input }}
<div class="control-group"> <div class="control-group">
<label for="id_username" class="control-label">{% trans 'Email' %}</label> <label for="id_username" class="control-label">{{ _('Email') }}</label>
<div class="controls"> <div class="controls">
<input id="id_username" type="email" name="username" class="email required" value="{{ email }}" maxlength="72" /> <input id="id_username" type="email" name="username" class="email required" value="{{ email }}" maxlength="72" />
</div> </div>
@ -100,7 +97,7 @@ autofocus('#id_username');
{% if not desktop_sso_dispatch %} {% if not desktop_sso_dispatch %}
<div class="control-group"> <div class="control-group">
<label for="id_password" class="control-label">{% trans 'Password' %}</label> <label for="id_password" class="control-label">{{ _('Password') }}</label>
<div class="controls"> <div class="controls">
<input id="id_password" name="password" class="required" type="password" /> <input id="id_password" name="password" class="required" type="password" />
</div> </div>
@ -111,7 +108,7 @@ autofocus('#id_username');
<input type="submit" class="btn btn-large btn-primary" value="Log in" /> <input type="submit" class="btn btn-large btn-primary" value="Log in" />
{% if not desktop_sso_dispatch %} {% if not desktop_sso_dispatch %}
<span class="login-forgot-password"> <span class="login-forgot-password">
<a href="{% url 'django.contrib.auth.views.password_reset' %}">{% trans 'Forgot password?' %}</a> <a href="{{ url('django.contrib.auth.views.password_reset') }}">{{ _('Forgot password?') }}</a>
</span> </span>
{% endif %} {% endif %}
</div> </div>
@ -120,18 +117,18 @@ autofocus('#id_username');
{% endif %} {% endif %}
{% if dev_auth_enabled %} {% if dev_auth_enabled %}
<form name="direct_login_form" id="direct_login_form" method="post" class="login-form" <form name="direct_login_form" id="direct_login_form" method="post" class="login-form"
action="{% url 'zerver.views.dev_direct_login' %}"> action="{{ url('zerver.views.dev_direct_login') }}">
{% csrf_token %} {{ csrf_input }}
<div class="control-group"> <div class="control-group">
{% if password_auth_enabled %} {% if password_auth_enabled %}
<label for="direct_email" class="direct-label">{% trans 'or Choose a user' %}:</label> <label for="direct_email" class="direct-label">{{ _('or Choose a user') }}:</label>
{% endif %} {% endif %}
<div class="controls"> <div class="controls">
<p>({% trans 'Administrators' %})</p> <p>({{ _('Administrators') }})</p>
{% for user_email in direct_admins %} {% for user_email in direct_admins %}
<p><input type="submit" name="direct_email" class="btn-direct btn-admin" value="{{ user_email }}" /></p> <p><input type="submit" name="direct_email" class="btn-direct btn-admin" value="{{ user_email }}" /></p>
{% endfor %} {% endfor %}
<p>({% trans 'Normal users' %})</p> <p>({{ _('Normal users') }})</p>
{% for user_email in direct_users %} {% for user_email in direct_users %}
<p><input type="submit" name="direct_email" class="btn-direct btn-user" value="{{ user_email }}" /></p> <p><input type="submit" name="direct_email" class="btn-direct btn-user" value="{{ user_email }}" /></p>
{% endfor %} {% endfor %}
@ -142,7 +139,7 @@ autofocus('#id_username');
{% if google_auth_enabled %} {% if google_auth_enabled %}
<div class="login-google"> <div class="login-google">
or <a href="{% url 'zerver.views.start_google_oauth2' %}" class="login-google-button zocial google">{% trans 'Sign in with Google' %}</a> or <a href="{{ url('zerver.views.start_google_oauth2') }}" class="login-google-button zocial google">{{ _('Sign in with Google') }}</a>
</div> </div>
{% endif %} {% endif %}

View File

@ -1,4 +1,4 @@
<div class="hidden"> <div class="hidden">
<form id="logout_form" action="/accounts/logout/" method="POST">{% csrf_token %} <form id="logout_form" action="/accounts/logout/" method="POST">{{ csrf_input }}
</form> </form>
</div> </div>

View File

@ -1,16 +1,15 @@
{% load i18n %}
<div class="modal hide" id="markdown-help" tabindex="-1" role="dialog" <div class="modal hide" id="markdown-help" tabindex="-1" role="dialog"
aria-labelledby="markdown-help-label" aria-hidden="true"> aria-labelledby="markdown-help-label" aria-hidden="true">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="markdown-help-label">{% blocktrans %}Message formatting{% endblocktrans %}</h3> <h3 id="markdown-help-label">{% trans %}Message formatting{% endtrans %}</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div id="markdown-instructions"> <div id="markdown-instructions">
<table class="table table-striped table-condensed table-rounded table-bordered" id="fmt_help_table"> <table class="table table-striped table-condensed table-rounded table-bordered" id="fmt_help_table">
<thead><tr> <thead><tr>
<th>{% blocktrans %}You type{% endblocktrans %}</th> <th>{% trans %}You type{% endtrans %}</th>
<th>{% blocktrans %}You get{% endblocktrans %}</th> <th>{% trans %}You get{% endtrans %}</th>
</tr></thead> </tr></thead>
<tbody> <tbody>
@ -71,7 +70,7 @@ def zulip():
</td> </td>
</tr> </tr>
<tr> <tr>
<td colspan="2">{% blocktrans %}You can also make a code block by indenting each line with 4 spaces.{% endblocktrans %}</td> <td colspan="2">{% trans %}You can also make a code block by indenting each line with 4 spaces.{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td>&gt; Quoted</td> <td>&gt; Quoted</td>
@ -85,17 +84,17 @@ Quoted block
<td><blockquote><p>Quoted block</p></blockquote></td> <td><blockquote><p>Quoted block</p></blockquote></td>
</tr> </tr>
<tr> <tr>
<td colspan="2">{% blocktrans %}You can also make <a target="_blank" <td colspan="2">{% trans %}You can also make <a target="_blank"
href="https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#wiki-tables">tables</a> href="https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#wiki-tables">tables</a>
with this <a target="_blank" with this <a target="_blank"
href="https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#wiki-tables">Markdown-ish href="https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#wiki-tables">Markdown-ish
table syntax</a>{% endblocktrans %}.</td> table syntax</a>{% endtrans %}.</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">{% trans "Close" %}</button> <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">{{ _("Close") }}</button>
</div> </div>
</div> </div>

View File

@ -1,6 +1,6 @@
{% comment %} {#
Mail sent to user when she was not logged in and received a PM or @-mention Mail sent to user when she was not logged in and received a PM or @-mention
{% endcomment %} #}
Hello {{ name }}, Hello {{ name }},

View File

@ -1,6 +1,6 @@
{% comment %} {#
Mail sent to user when she was not logged in and received a PM or @-mention Mail sent to user when she was not logged in and received a PM or @-mention
{% endcomment %} #}
Hello {{ name }}, Hello {{ name }},

View File

@ -1,4 +1,3 @@
{% load i18n %}
<div class="header"> <div class="header">
<div class="header-main rightside-userlist" id="top_navbar"> <div class="header-main rightside-userlist" id="top_navbar">
<div class="column-left"> <div class="column-left">
@ -17,7 +16,7 @@
<form id="searchbox_form" class="form-search navbar-search"> <form id="searchbox_form" class="form-search navbar-search">
<div id="search_arrows" class="input-append"> <div id="search_arrows" class="input-append">
<i class="icon-vector-search"></i> <i class="icon-vector-search"></i>
<input class="search-query input-block-level" id="search_query" type="text" placeholder="{% trans 'Search' %}" <input class="search-query input-block-level" id="search_query" type="text" placeholder="{{ _('Search') }}"
autocomplete="off" /> autocomplete="off" />
{# Start the button off disabled since there is no active search #} {# Start the button off disabled since there is no active search #}
<button class="btn search_button" type="button" id="search_exit" disabled="disabled"><i class="icon-vector-remove"></i></button> <button class="btn search_button" type="button" id="search_exit" disabled="disabled"><i class="icon-vector-remove"></i></button>
@ -39,70 +38,70 @@
<i class="icon-vector-cog"></i><i class="icon-vector-caret-down settings-dropdown-caret"></i> <i class="icon-vector-cog"></i><i class="icon-vector-caret-down settings-dropdown-caret"></i>
</a> </a>
<ul class="dropdown-menu" role="menu" aria-labelledby="settings-dropdown"> <ul class="dropdown-menu" role="menu" aria-labelledby="settings-dropdown">
{% comment %} {#
It is quite ingrained in our frontend code that your Home It is quite ingrained in our frontend code that your Home
view is a Bootstrap Nav tab, even though we don't show the tab view is a Bootstrap Nav tab, even though we don't show the tab
anymore anymore
{% endcomment %} #}
<li style="display:none;"><a href="#home" data-toggle="tab"></a></li> <li style="display:none;"><a href="#home" data-toggle="tab"></a></li>
<li title="Manage Streams"> <li title="Manage Streams">
<a href="#subscriptions" data-toggle="tab"> <a href="#subscriptions" data-toggle="tab">
<i class="icon-vector-exchange"></i> {% trans 'Manage Streams' %} <i class="icon-vector-exchange"></i> {{ _('Manage Streams') }}
</a> </a>
</li> </li>
<li title="Settings"> <li title="Settings">
<a href="#settings" data-toggle="tab"> <a href="#settings" data-toggle="tab">
<i class="icon-vector-wrench"></i> {% trans 'Settings' %} <i class="icon-vector-wrench"></i> {{ _('Settings') }}
</a> </a>
</li> </li>
<li title="Keyboard shortcuts"> <li title="Keyboard shortcuts">
<a href="#keyboard-shortcuts" role="button" data-toggle="modal"> <a href="#keyboard-shortcuts" role="button" data-toggle="modal">
<i class="icon-vector-question-sign"></i> {% trans 'Keyboard shortcuts' %} <i class="icon-vector-question-sign"></i> {{ _('Keyboard shortcuts') }}
</a> </a>
</li> </li>
<li title="Message formatting"> <li title="Message formatting">
<a href="#markdown-help" role="button" data-toggle="modal"> <a href="#markdown-help" role="button" data-toggle="modal">
<i class="icon-vector-pencil"></i> {% trans 'Message formatting' %} <i class="icon-vector-pencil"></i> {{ _('Message formatting') }}
</a> </a>
</li> </li>
<li title="Search help"> <li title="Search help">
<a href="#search-operators" role="button" data-toggle="modal"> <a href="#search-operators" role="button" data-toggle="modal">
<i class="icon-vector-search"></i> {% trans 'Search help' %} <i class="icon-vector-search"></i> {{ _('Search help') }}
</a> </a>
</li> </li>
<li class="divider"></li> <li class="divider"></li>
<li title="Desktop & mobile apps"> <li title="Desktop & mobile apps">
<a href="/apps" target="_blank" role="button"> <a href="/apps" target="_blank" role="button">
<i class="icon-vector-desktop"></i> {% trans 'Desktop & mobile apps' %} <i class="icon-vector-desktop"></i> {{ _('Desktop & mobile apps') }}
</a> </a>
</li> </li>
<li title="Integrations"> <li title="Integrations">
<a href="/integrations" target="_blank" role="button"> <a href="/integrations" target="_blank" role="button">
<i class="icon-vector-github"></i> {% trans 'Integrations' %} <i class="icon-vector-github"></i> {{ _('Integrations') }}
</a> </a>
</li> </li>
<li title="API documentation"> <li title="API documentation">
<a href="/api" target="_blank" role="button"> <a href="/api" target="_blank" role="button">
<i class="icon-vector-sitemap"></i> {% trans 'API documentation' %} <i class="icon-vector-sitemap"></i> {{ _('API documentation') }}
</a> </a>
</li> </li>
<li class="divider"></li> <li class="divider"></li>
<li title="Administration" class="admin-menu-item"> <li title="Administration" class="admin-menu-item">
<a href="#administration" role="button" data-toggle="tab"> <a href="#administration" role="button" data-toggle="tab">
<i class="icon-vector-bolt"></i> {% trans 'Administration' %} <i class="icon-vector-bolt"></i> {{ _('Administration') }}
</a> </a>
</li> </li>
{% if show_invites %} {% if show_invites %}
<li title="Invite coworkers to {{product_name}}"> <li title="Invite coworkers to {{product_name}}">
<a href="#invite-user" role="button" data-toggle="modal"> <a href="#invite-user" role="button" data-toggle="modal">
<i class="icon-vector-plus-sign"></i> {% trans 'Invite coworkers' %} <i class="icon-vector-plus-sign"></i> {{ _('Invite coworkers') }}
</a> </a>
</li> </li>
{% endif %} {% endif %}
{% if enable_feedback %} {% if enable_feedback %}
<li title="Feedback"> <li title="Feedback">
<a href="#feedback" class="feedback"> <a href="#feedback" class="feedback">
<i class="icon-vector-comment"></i> {% trans 'Feedback' %} <i class="icon-vector-comment"></i> {{ _('Feedback') }}
</a> </a>
</li> </li>
{% endif %} {% endif %}
@ -110,19 +109,19 @@
{% if show_webathena %} {% if show_webathena %}
<li title="Grant {{product_name}} the Kerberos tickets needed to run your Zephyr mirror via Webathena" id="webathena_login_menu"> <li title="Grant {{product_name}} the Kerberos tickets needed to run your Zephyr mirror via Webathena" id="webathena_login_menu">
<a href="#webathena" class="webathena_login"> <a href="#webathena" class="webathena_login">
<i class="icon-vector-bolt"></i>{% trans 'Link with Webathena' %} <i class="icon-vector-bolt"></i>{{ _('Link with Webathena') }}
</a> </a>
</li> </li>
{% endif %} {% endif %}
<li title="Log out"> <li title="Log out">
<a href="#logout" class="logout_button"> <a href="#logout" class="logout_button">
<i class="icon-vector-off"></i> {% trans 'Log out' %} <i class="icon-vector-off"></i> {{ _('Log out') }}
</a> </a>
</li> </li>
{% if show_debug %} {% if show_debug %}
<li title="Debug"> <li title="Debug">
<a href="#debug" data-toggle="tab"> <a href="#debug" data-toggle="tab">
<i class="icon-vector-barcode"></i> {% trans 'Debug' %} <i class="icon-vector-barcode"></i> {{ _('Debug') }}
</a> </a>
</li> </li>
{% endif %} {% endif %}

View File

@ -1,16 +1,13 @@
{% extends "zerver/base.html" %} {% extends "zerver/base.html" %}
{% load i18n %}
{% load compressed %}
{% comment %} {# A base template for stuff like login, register, etc.
A base template for stuff like login, register, etc.
Not inside the app itself, but covered by the same structure, Not inside the app itself, but covered by the same structure,
hence the name. hence the name.
{% endcomment %} #}
{% block customhead %} {% block customhead %}
{% compressed_css 'portico' %} {{ compressed_css('portico')|safe }}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
@ -28,13 +25,13 @@ hence the name.
<div class="column-right top-links"> <div class="column-right top-links">
{% if not only_sso %} {% if not only_sso %}
<a href="{{login_url}}">{% trans 'Log in' %}</a> <a href="{{login_url}}">{{ _('Log in') }}</a>
{% endif %} {% endif %}
{% if only_sso %} {% if only_sso %}
<a href="{% url 'login-sso' %}">{% trans 'Log In' %}</a> <a href="{{ url('login-sso') }}">{{ _('Log In') }}</a>
{% else %} {% else %}
<a href="{% url 'register' %}">{% trans 'Register' %}</a> <a href="{{ url('register') }}">{{ _('Register') }}</a>
{% endif %} {% endif %}
</div> </div>
</div> </div>
@ -55,19 +52,19 @@ hence the name.
<div class="footer"> <div class="footer">
<div class="footer-main"> <div class="footer-main">
<ul class="footer-navigation"> <ul class="footer-navigation">
<li><a href="/hello">{% trans 'About' %}</a></li> <li><a href="/hello">{{ _('About') }}</a></li>
{% if zulip_com %} {% if zulip_com %}
<li><span class="little-bullet">·</span></li> <li><span class="little-bullet">·</span></li>
<li><a href="/terms">{% trans 'Legal' %}</a></li> <li><a href="/terms">{{ _('Legal') }}</a></li>
{% endif %} {% endif %}
<li><span class="little-bullet">·</span></li> <li><span class="little-bullet">·</span></li>
<li><a href="{{login_url}}">{% trans 'Log in' %}</a></li> <li><a href="{{login_url}}">{{ _('Log in') }}</a></li>
{% if not only_sso %} {% if not only_sso %}
<li><span class="little-bullet">·</span></li> <li><span class="little-bullet">·</span></li>
<li> <li>
{% if zulip_com %} {% if zulip_com %}
{% else %} {% else %}
<a href="{% url 'register' %}">{% trans 'Register' %}</a> <a href="{{ url('register') }}">{{ _('Register') }}</a>
{% endif %} {% endif %}
</li> </li>
{% endif %} {% endif %}

View File

@ -1,10 +1,8 @@
{% extends "zerver/portico.html" %} {% extends "zerver/portico.html" %}
{% load minified_js %}
{# Portico page with signup code #} {# Portico page with signup code #}
{% block customhead %} {% block customhead %}
{{ block.super }} {{ super() }}
{% minified_js 'signup' %} {{ minified_js('signup')|safe }}
{% endblock %} {% endblock %}

View File

@ -1,14 +1,13 @@
{% extends "zerver/portico_signup.html" %} {% extends "zerver/portico_signup.html" %}
{% load i18n %} {#
{% comment %}
Gather other user information, after having confirmed Gather other user information, after having confirmed
their email address. their email address.
Form is validated both client-side using jquery-validate (see signup.js) and server-side. Form is validated both client-side using jquery-validate (see signup.js) and server-side.
{% endcomment %} #}
{% block customhead %} {% block customhead %}
{{ block.super }} {{ super() }}
<script type="text/javascript" src="/static/third/zxcvbn/zxcvbn.js"></script> <script type="text/javascript" src="/static/third/zxcvbn/zxcvbn.js"></script>
{% endblock %} {% endblock %}
@ -17,27 +16,27 @@ Form is validated both client-side using jquery-validate (see signup.js) and ser
<div class="pitch"> <div class="pitch">
<p style="margin-top:30px;">{% trans "You're almost there. We just need you to do one last thing" %}.</p> <p style="margin-top:30px;">{{ _("You're almost there. We just need you to do one last thing") }}.</p>
<h3>{% trans 'Tell us a bit about yourself' %}.</h3> <h3>{{ _('Tell us a bit about yourself') }}.</h3>
</div> </div>
<form method="post" class="form-horizontal" id="registration" action="{% url 'zerver.views.accounts_register' %}"> <form method="post" class="form-horizontal" id="registration" action="{{ url('zerver.views.accounts_register') }}">
{% csrf_token %} {{ csrf_input }}
<div class="control-group"> <div class="control-group">
<label for="id_email" class="control-label">{% trans 'Email' %}</label> <label for="id_email" class="control-label">{{ _('Email') }}</label>
<div class="controls fakecontrol"> <div class="controls fakecontrol">
<input type='hidden' name='key' value='{{ key }}' /> <input type='hidden' name='key' value='{{ key }}' />
<p>{{ email }}</p> <p>{{ email }}</p>
</div> </div>
</div> </div>
<div class="control-group"> <div class="control-group">
<label for="id_full_name" class="control-label">{% trans 'Full name' %}</label> <label for="id_full_name" class="control-label">{{ _('Full name') }}</label>
<div class="controls"> <div class="controls">
{% if lock_name %} {% if lock_name %}
<p class="fakecontrol">{{ full_name }}</p> <p class="fakecontrol">{{ full_name }}</p>
{% else %} {% else %}
<input id="id_full_name" class="required" type="text" name="full_name" <input id="id_full_name" class="required" type="text" name="full_name"
value="{% if full_name %}{{ full_name }}{% elif form.full_name.value %}{{ form.full_name.value }}{% endif %}" value="{% if full_name %}{{ full_name }}{% elif form.full_name.value() %}{{ form.full_name.value() }}{% endif %}"
maxlength="100" /> maxlength="100" />
{% if form.full_name.errors %} {% if form.full_name.errors %}
{% for error in form.full_name.errors %} {% for error in form.full_name.errors %}
@ -49,13 +48,13 @@ Form is validated both client-side using jquery-validate (see signup.js) and ser
</div> </div>
{% if password_auth_enabled %} {% if password_auth_enabled %}
<div class="control-group"> <div class="control-group">
<label for="id_password" class="control-label">{% trans 'Password' %}</label> <label for="id_password" class="control-label">{{ _('Password') }}</label>
<div class="controls"> <div class="controls">
<input id="id_password" class="required" type="password" name="password" <input id="id_password" class="required" type="password" name="password"
value="{% if form.password.value %}{{ form.password.value }}{% endif %}" value="{% if form.password.value() %}{{ form.password.value() }}{% endif %}"
maxlength="100" /> maxlength="100" />
{% if full_name %} {% if full_name %}
<span class="help-inline">{% trans 'This is used for mobile applications and other tools that require a password' %}.</span> <span class="help-inline">{{ _('This is used for mobile applications and other tools that require a password') }}.</span>
{% endif %} {% endif %}
{% if form.password.errors %} {% if form.password.errors %}
{% for error in form.password.errors %} {% for error in form.password.errors %}
@ -65,7 +64,7 @@ Form is validated both client-side using jquery-validate (see signup.js) and ser
</div> </div>
</div> </div>
<div class="control-group"> <div class="control-group">
<label class="control-label">{% trans 'Password strength' %}</label> <label class="control-label">{{ _('Password strength') }}</label>
<div class="controls"> <div class="controls">
<div class="progress" id="pw_strength"> <div class="progress" id="pw_strength">
<div class="bar bar-danger" style="width: 10%;"></div> <div class="bar bar-danger" style="width: 10%;"></div>
@ -79,17 +78,17 @@ Form is validated both client-side using jquery-validate (see signup.js) and ser
<div class="control-group"> <div class="control-group">
<div class="controls"> <div class="controls">
<label class="checkbox"> <label class="checkbox">
{% comment %} {#
This is somewhat subtle. This is somewhat subtle.
Checkboxes have a name and value, and when the checkbox is ticked, the form posts Checkboxes have a name and value, and when the checkbox is ticked, the form posts
with name=value. If the checkbox is unticked, the field just isn't present at all. with name=value. If the checkbox is unticked, the field just isn't present at all.
This is distinct from 'checked', which determines whether the checkbox appears This is distinct from 'checked', which determines whether the checkbox appears
at all. (So, it's not symmetric to the code above.) at all. (So, it's not symmetric to the code above.)
{% endcomment %} #}
<input id="id_terms" class="required" type="checkbox" name="terms" <input id="id_terms" class="required" type="checkbox" name="terms"
{% if form.terms.value %}checked="checked"{% endif %} /> {% if form.terms.value() %}checked="checked"{% endif %} />
{% trans 'I agree to the' %} <a href="/terms" target="_blank">{% trans 'Terms of Service' %}</a>. {{ _('I agree to the') }} <a href="/terms" target="_blank">{{ _('Terms of Service') }}</a>.
</label> </label>
{% if form.terms.errors %} {% if form.terms.errors %}
{% for error in form.terms.errors %} {% for error in form.terms.errors %}

View File

@ -1,18 +1,17 @@
{% extends "zerver/portico_signup.html" %} {% extends "zerver/portico_signup.html" %}
{% load i18n %}
{% block portico_content %} {% block portico_content %}
<div class="pitch"> <div class="pitch">
<h3>{% trans 'Reset your password' %}.</h3> <h3>{{ _('Reset your password') }}.</h3>
</div> </div>
<form method="post" class="form-horizontal" action="{% url 'django.contrib.auth.views.password_reset' %}"> <form method="post" class="form-horizontal" action="{{ url('django.contrib.auth.views.password_reset') }}">
{% csrf_token %} {{ csrf_input }}
<div class="control-group"> <div class="control-group">
<label for="id_email" class="control-label">{% trans 'Email' %}</label> <label for="id_email" class="control-label">{{ _('Email') }}</label>
<div class="controls"> <div class="controls">
<input id="id_email" class="required" type="text" name="email" <input id="id_email" class="required" type="text" name="email"
value="{% if form.email.value %}{{ form.email.value }}{% endif %}" value="{% if form.email.value() %}{{ form.email.value() }}{% endif %}"
maxlength="100" /> maxlength="100" />
{% if form.email.errors %} {% if form.email.errors %}
{% for error in form.email.errors %} {% for error in form.email.errors %}

View File

@ -1,7 +1,6 @@
{% extends "zerver/portico_signup.html" %} {% extends "zerver/portico_signup.html" %}
{% load i18n %}
{% block customhead %} {% block customhead %}
{{ block.super }} {{ super() }}
<script type="text/javascript" src="/static/third/zxcvbn/zxcvbn.js"></script> <script type="text/javascript" src="/static/third/zxcvbn/zxcvbn.js"></script>
{% endblock %} {% endblock %}
@ -9,17 +8,17 @@
<div class="pitch"> <div class="pitch">
<hr/> <hr/>
<h3>{% trans 'Reset your password' %}.</h3> <h3>{{ _('Reset your password') }}.</h3>
</div> </div>
{% if validlink %} {% if validlink %}
<form method="post" id="password_reset" class="form-horizontal"> <form method="post" id="password_reset" class="form-horizontal">
{% csrf_token %} {{ csrf_input }}
<div class="control-group"> <div class="control-group">
<label for="id_new_password1" class="control-label">{% trans 'Password' %}</label> <label for="id_new_password1" class="control-label">{{ _('Password') }}</label>
<div class="controls"> <div class="controls">
<input id="id_new_password1" class="required" type="password" name="new_password1" <input id="id_new_password1" class="required" type="password" name="new_password1"
value="{% if form.new_password1.value %}{{ form.new_password1.value }}{% endif %}" value="{% if form.new_password1.value() %}{{ form.new_password1.value() }}{% endif %}"
maxlength="100" /> maxlength="100" />
{% if form.new_password1.errors %} {% if form.new_password1.errors %}
{% for error in form.new_password1.errors %} {% for error in form.new_password1.errors %}
@ -29,7 +28,7 @@
</div> </div>
</div> </div>
<div class="control-group"> <div class="control-group">
<label class="control-label">{% trans 'Password strength' %}</label> <label class="control-label">{{ _('Password strength') }}</label>
<div class="controls"> <div class="controls">
<div class="progress" id="pw_strength"> <div class="progress" id="pw_strength">
<div class="bar bar-danger" style="width: 10%;"></div> <div class="bar bar-danger" style="width: 10%;"></div>
@ -37,10 +36,10 @@
</div> </div>
</div> </div>
<div class="control-group"> <div class="control-group">
<label for="id_new_password2" class="control-label">{% trans 'Confirm password' %}</label> <label for="id_new_password2" class="control-label">{{ _('Confirm password') }}</label>
<div class="controls"> <div class="controls">
<input id="id_new_password2" class="required" type="password" name="new_password2" <input id="id_new_password2" class="required" type="password" name="new_password2"
value="{% if form.new_password2.value %}{{ form.new_password2.value }}{% endif %}" value="{% if form.new_password2.value() %}{{ form.new_password2.value() }}{% endif %}"
maxlength="100" /> maxlength="100" />
{% if form.new_password2.errors %} {% if form.new_password2.errors %}
{% for error in form.new_password2.errors %} {% for error in form.new_password2.errors %}
@ -61,7 +60,7 @@
autofocus('#id_new_password1'); autofocus('#id_new_password1');
</script> </script>
{% else %} {% else %}
<p>{% trans 'Sorry, the link you provided is invalid or has already been used' %}.</p> <p>{{ _('Sorry, the link you provided is invalid or has already been used') }}.</p>
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@ -1,7 +1,6 @@
{% extends "zerver/portico_signup.html" %} {% extends "zerver/portico_signup.html" %}
{% load i18n %}
{% block portico_content %} {% block portico_content %}
<h1 style="margin-top: 20px">{% trans "We've reset your password!" %}</h1> <h1 style="margin-top: 20px">{{ _("We've reset your password!") }}</h1>
<p>{% trans 'Please' %} <a href="{% url 'django.contrib.auth.views.login' %}">{% trans 'log in' %}</a>.</p> <p>{{ _('Please') }} <a href="{{ url('django.contrib.auth.views.login') }}">{{ _('log in') }}</a>.</p>
{% endblock %} {% endblock %}

View File

@ -1,7 +1,6 @@
{% extends "zerver/portico_signup.html" %} {% extends "zerver/portico_signup.html" %}
{% load i18n %}
{% block portico_content %} {% block portico_content %}
<h1 style="margin-top: 20px">{% trans 'We just sent you a password reset!' %}</h1> <h1 style="margin-top: 20px">{{ _('We just sent you a password reset!') }}</h1>
<h1>{% trans 'Check your email to finish the process' %}.</h1> <h1>{{ _('Check your email to finish the process') }}.</h1>
<p>({% trans "Or don't, but then why did you fill out this form?" %})</p> <p>({{ _("Or don't, but then why did you fill out this form?") }})</p>
{% endblock %} {% endblock %}

View File

@ -1,47 +1,46 @@
{% load i18n %}
<div class="right-sidebar" id="right-sidebar"> <div class="right-sidebar" id="right-sidebar">
<div class="alert alert_sidebar alert-error home-error-bar" id="connection-error"> <div class="alert alert_sidebar alert-error home-error-bar" id="connection-error">
<strong>{% trans 'Unable to connect to' %} {{product_name}}.</strong> {% trans 'Updates may be delayed' %}. <strong>{{ _('Unable to connect to') }} {{product_name}}.</strong> {{ _('Updates may be delayed') }}.
<br /><br /> {% trans 'Retrying soon' %}... <br /><br /> <a class="restart_get_updates_button">{% trans 'Try now' %}</a>. <br /><br /> {{ _('Retrying soon') }}... <br /><br /> <a class="restart_get_updates_button">{{ _('Try now') }}</a>.
</div> </div>
<div class="alert alert_sidebar alert-error home-error-bar" id="get_old_messages_error"> <div class="alert alert_sidebar alert-error home-error-bar" id="get_old_messages_error">
<strong>{% trans 'Unable to connect to' %} {{product_name}}.</strong> {% trans 'Could not fetch messages' %}. <strong>{{ _('Unable to connect to') }} {{product_name}}.</strong> {{ _('Could not fetch messages') }}.
<br /><br /> {% trans 'Retrying soon' %}... <br /><br /> <br /><br /> {{ _('Retrying soon') }}... <br /><br />
</div> </div>
<div class="alert alert_sidebar alert-error home-error-bar" id="zephyr-mirror-error"> <div class="alert alert_sidebar alert-error home-error-bar" id="zephyr-mirror-error">
<strong>{% trans 'Your Zephyr mirror is not working' %}.</strong> <strong>{{ _('Your Zephyr mirror is not working') }}.</strong>
<span id="normal-zephyr-mirror-error-text">{% blocktrans %}We <span id="normal-zephyr-mirror-error-text">{% trans %}We
recommend that you <a class="webathena_login">give recommend that you <a class="webathena_login">give
{{product_name}} the ability to mirror the messages for you via {{product_name}} the ability to mirror the messages for you via
WebAthena</a>. If you'd prefer, you can instead WebAthena</a>. If you'd prefer, you can instead
<a href="/zephyr-mirror" target="_blank">run the Zephyr mirror script yourself</a> <a href="/zephyr-mirror" target="_blank">run the Zephyr mirror script yourself</a>
in a screen session{% endblocktrans %}.</span> in a screen session{% endtrans %}.</span>
<span id="desktop-zephyr-mirror-error-text" class="notdisplayed">{% blocktrans %}To fix <span id="desktop-zephyr-mirror-error-text" class="notdisplayed">{% trans %}To fix
this, you'll need this, you'll need
to use <a href="https://zephyr.zulip.com">the web interface</a>{% endblocktrans %}</span> to use <a href="https://zephyr.zulip.com">the web interface</a>{% endtrans %}</span>
</div> </div>
<div class="alert alert_sidebar alert-error home-error-bar" id="home-error"></div> <div class="alert alert_sidebar alert-error home-error-bar" id="home-error"></div>
<div class="alert alert_sidebar alert-error home-error-bar" id="reloading-application"></div> <div class="alert alert_sidebar alert-error home-error-bar" id="reloading-application"></div>
{% if enable_feedback %} {% if enable_feedback %}
<div id="feedback_section"> <div id="feedback_section">
<button type="button" class="btn btn-default btn-large" id="feedback_button"> <button type="button" class="btn btn-default btn-large" id="feedback_button">
<i class="icon-vector-comment"></i>&nbsp;&nbsp;{% trans 'Send feedback' %} <i class="icon-vector-comment"></i>&nbsp;&nbsp;{{ _('Send feedback') }}
</button> </button>
</div> </div>
{% endif %} {% endif %}
<div id="user-list"> <div id="user-list">
<div id="userlist-header"> <div id="userlist-header">
<h4 class='sidebar-title' id='userlist-title'>{% trans 'USERS' %}</h4> <h4 class='sidebar-title' id='userlist-title'>{{ _('USERS') }}</h4>
</div> </div>
<input class="user-list-filter" type="text" placeholder="Search people" /> <input class="user-list-filter" type="text" placeholder="Search people" />
<ul id="user_presences" class="filters scrolling_list"></ul> <ul id="user_presences" class="filters scrolling_list"></ul>
{% if show_invites %} {% if show_invites %}
<a id="invite-user-link" href="#invite-user" data-toggle="modal"><i class="icon-vector-plus-sign"></i>{% trans 'Invite coworkers' %}</a> <a id="invite-user-link" href="#invite-user" data-toggle="modal"><i class="icon-vector-plus-sign"></i>{{ _('Invite coworkers') }}</a>
{% endif %} {% endif %}
</div> </div>
<div id="group-pm-list"> <div id="group-pm-list">
<div id="group-pm-header"> <div id="group-pm-header">
<h4 class='sidebar-title' id='group-pm-title'>{% trans 'GROUP PMs' %}</h4> <h4 class='sidebar-title' id='group-pm-title'>{{ _('GROUP PMs') }}</h4>
</div> </div>
<ul id="group-pms" class="filters scrolling_list"> <ul id="group-pms" class="filters scrolling_list">
</ul> </ul>

View File

@ -1,82 +1,81 @@
{% load i18n %}
<div class="modal hide" id="search-operators" tabindex="-1" role="dialog" <div class="modal hide" id="search-operators" tabindex="-1" role="dialog"
aria-labelledby="search-operators-label" aria-hidden="true"> aria-labelledby="search-operators-label" aria-hidden="true">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="search-operators-label">{% trans 'Search help' %}</h3> <h3 id="search-operators-label">{{ _('Search help') }}</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<table class="table table-striped table-condensed table-rounded table-bordered" id="fmt_help_table"> <table class="table table-striped table-condensed table-rounded table-bordered" id="fmt_help_table">
<thead> <thead>
<tr> <tr>
<th>{% trans 'Operator' %}</th> <th>{{ _('Operator') }}</th>
<th>{% trans 'Effect' %}</th> <th>{{ _('Effect') }}</th>
</tr> </tr>
</thead> </thead>
<tr> <tr>
<td class="operator">stream:<span class="operator_value">stream</span></td> <td class="operator">stream:<span class="operator_value">stream</span></td>
<td class="definition">{% trans 'Narrow to messages on stream' %} <span class="operator_value">stream</span></td> <td class="definition">{{ _('Narrow to messages on stream') }} <span class="operator_value">stream</span></td>
</tr> </tr>
<tr> <tr>
<td class="operator">topic:<span class="operator_value">topic</span></td> <td class="operator">topic:<span class="operator_value">topic</span></td>
<td class="definition">{% trans 'Narrow to messages with topic' %} <span class="operator_value">topic</span></td> <td class="definition">{{ _('Narrow to messages with topic') }} <span class="operator_value">topic</span></td>
</tr> </tr>
<tr> <tr>
<td class="operator">pm-with:<span class="operator_value">email</span></td> <td class="operator">pm-with:<span class="operator_value">email</span></td>
<td class="definition">{% trans 'Narrow to private messages with' %} <span class="operator_value">email</span></td> <td class="definition">{{ _('Narrow to private messages with') }} <span class="operator_value">email</span></td>
</tr> </tr>
<tr> <tr>
<td class="operator">sender:<span class="operator_value">email</span></td> <td class="operator">sender:<span class="operator_value">email</span></td>
<td class="definition">{% trans 'Narrow to messages sent by' %} <span class="operator_value">email</span></td> <td class="definition">{{ _('Narrow to messages sent by') }} <span class="operator_value">email</span></td>
</tr> </tr>
<tr> <tr>
<td class="operator">sender:me</td> <td class="operator">sender:me</td>
<td class="definition">{% trans 'Narrow to messages sent by you' %}.</td> <td class="definition">{{ _('Narrow to messages sent by you') }}.</td>
</tr> </tr>
<tr> <tr>
<td class="operator">near:<span class="operator_value">id</span></td> <td class="operator">near:<span class="operator_value">id</span></td>
<td class="definition">{% trans 'Center the view around message ID' %} <span class="operator_value">id</span></td> <td class="definition">{{ _('Center the view around message ID') }} <span class="operator_value">id</span></td>
</tr> </tr>
<tr> <tr>
<td class="operator">id:<span class="operator_value">id</span></td> <td class="operator">id:<span class="operator_value">id</span></td>
<td class="definition">{% trans 'Narrow to just message ID' %} <span class="operator_value">id</span></td> <td class="definition">{{ _('Narrow to just message ID') }} <span class="operator_value">id</span></td>
</tr> </tr>
<tr> <tr>
<tr> <tr>
<td class="operator">is:alerted</td> <td class="operator">is:alerted</td>
<td class="definition">{% trans 'Narrow to messages with alert words' %}.</td> <td class="definition">{{ _('Narrow to messages with alert words') }}.</td>
</tr> </tr>
<td class="operator">is:mentioned</td> <td class="operator">is:mentioned</td>
<td class="definition">{% trans 'Narrow to messages that mention you' %}.</td> <td class="definition">{{ _('Narrow to messages that mention you') }}.</td>
</tr> </tr>
<tr> <tr>
<td class="operator">is:private</td> <td class="operator">is:private</td>
<td class="definition">{% trans 'Narrow to private messages' %}.</td> <td class="definition">{{ _('Narrow to private messages') }}.</td>
</tr> </tr>
<tr> <tr>
<td class="operator">is:starred</td> <td class="operator">is:starred</td>
<td class="definition">{% trans 'Narrow to starred messages' %}.</td> <td class="definition">{{ _('Narrow to starred messages') }}.</td>
</tr> </tr>
<tr> <tr>
<td class="operator"><span class="operator_value">keyword</span></td> <td class="operator"><span class="operator_value">keyword</span></td>
<td class="definition">{% trans 'Search for' %} <span class="operator_value">{% trans 'keyword' %}</span> {% trans 'in the topic or message content' %}</td> <td class="definition">{{ _('Search for') }} <span class="operator_value">{{ _('keyword') }}</span> {{ _('in the topic or message content') }}</td>
</tr> </tr>
<tr> <tr>
<td class="operator">-topic:<span class="operator_value">topic</span></td> <td class="operator">-topic:<span class="operator_value">topic</span></td>
<td class="definition">{% trans 'Exclude messages with topic' %} <span class="operator_value">topic</span></td> <td class="definition">{{ _('Exclude messages with topic') }} <span class="operator_value">topic</span></td>
</tr> </tr>
</table> </table>
<p>{% trans 'You can use any combination of these search operators in a single query' %}. {% trans 'For example' %}:</p> <p>{{ _('You can use any combination of these search operators in a single query') }}. {{ _('For example') }}:</p>
<p>&nbsp; <span class="operator">stream:<span class="operator_value">streamname</span> <p>&nbsp; <span class="operator">stream:<span class="operator_value">streamname</span>
sender:<span class="operator_value">user@example.com</span> sender:<span class="operator_value">user@example.com</span>
<span class="operator_value">keyword</span></span></p> <span class="operator_value">keyword</span></span></p>
<p>{% trans 'would search for messages sent by' %} <span class="operator_value">user@example.com</span> {% trans 'to stream' %} <p>{{ _('would search for messages sent by') }} <span class="operator_value">user@example.com</span> {{ _('to stream') }}
<span class="operator_value">streamname</span> <span class="operator_value">streamname</span>
{% trans 'containing the keyword' %} <span class="operator_value">keyword</span>.</p> {{ _('containing the keyword') }} <span class="operator_value">keyword</span>.</p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">{% trans 'Close' %}</button> <button class="btn btn-primary" data-dismiss="modal" aria-hidden="true">{{ _('Close') }}</button>
</div> </div>
</div> </div>

View File

@ -1,42 +1,41 @@
{% load i18n %}
<div class="modal hide" id="stream-creation" tabindex="-1" role="dialog" <div class="modal hide" id="stream-creation" tabindex="-1" role="dialog"
aria-labelledby="stream-creation-label" aria-hidden="true"> aria-labelledby="stream-creation-label" aria-hidden="true">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="stream-creation-label">{% blocktrans %}Create stream{% endblocktrans %} <span id="stream_name"></span></h3> <h3 id="stream-creation-label">{% trans %}Create stream{% endtrans %} <span id="stream_name"></span></h3>
</div> </div>
<form id="stream_creation_form" class="form-inline"> <form id="stream_creation_form" class="form-inline">
<div class="modal-body"> <div class="modal-body">
<div id="make-invite-only"> <div id="make-invite-only">
<b>{% blocktrans %}Stream accessibility{% endblocktrans %}</b><br /> <b>{% trans %}Stream accessibility{% endtrans %}</b><br />
<label class="radio"> <label class="radio">
<input type="radio" name="privacy" value="public" checked /> <input type="radio" name="privacy" value="public" checked />
<span class="icon-vector-globe"></span> <span class="icon-vector-globe"></span>
{% blocktrans %}Anyone can join{% endblocktrans %} {% trans %}Anyone can join{% endtrans %}
</label><br /> </label><br />
<label class="radio"> <label class="radio">
<input type="radio" name="privacy" value="invite-only" /> <input type="radio" name="privacy" value="invite-only" />
<span class="icon-vector-lock"></span> <span class="icon-vector-lock"></span>
{% blocktrans %}People must be invited{% endblocktrans %} {% trans %}People must be invited{% endtrans %}
</label> </label>
</div> </div>
<div id="announce-new-stream"> <div id="announce-new-stream">
<br /> <br />
<label class="checkbox"> <label class="checkbox">
<input type="checkbox" name="announce" value="announce" checked /> <input type="checkbox" name="announce" value="announce" checked />
{% blocktrans %}Announce stream{% endblocktrans %} {% trans %}Announce stream{% endtrans %}
</label> </label>
<span class="icon-vector-question-sign" id="announce-stream-docs"></span> <span class="icon-vector-question-sign" id="announce-stream-docs"></span>
</div> </div>
<br /> <br />
<div class="control-group"> <div class="control-group">
<label class="control-label" for="people_to_add"><b>{% blocktrans %}People to add{% endblocktrans %}</b></label><br /> <label class="control-label" for="people_to_add"><b>{% trans %}People to add{% endtrans %}</b></label><br />
<div class="controls" id="people_to_add"></div> <div class="controls" id="people_to_add"></div>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-default" data-dismiss="modal" aria-hidden="true">{% trans "Cancel" %}</button> <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">{{ _("Cancel") }}</button>
<button class="btn btn-primary" type="submit">{% trans "Create" %}</button> <button class="btn btn-primary" type="submit">{{ _("Create") }}</button>
</div> </div>
</form> </form>
</div> </div>

View File

@ -1,8 +1,7 @@
{% load i18n %}
{# Subscriptions management tab of the app. #} {# Subscriptions management tab of the app. #}
<div class="subscriptions"> <div class="subscriptions">
<h1><i class="icon-vector-exchange streams-icon"></i>{% trans "Streams" %}</h1> <h1><i class="icon-vector-exchange streams-icon"></i>{{ _("Streams") }}</h1>
<div class="alert" id="subscriptions-status"> <div class="alert" id="subscriptions-status">
<span id="response"></span> <span id="response"></span>
<span id="close-subscriptions-status"><i class="icon-vector-remove"></i></span> <span id="close-subscriptions-status"><i class="icon-vector-remove"></i></span>

View File

@ -1,6 +1,6 @@
{% comment %} {#
Mail sent to us when a user accepts the ToS Mail sent to us when a user accepts the ToS
{% endcomment %} #}
Hello, Hello,

View File

@ -1,16 +1,15 @@
{% load i18n %}
<div class="modal hide" id="tutorial-finale" tabindex="-1" role="dialog" <div class="modal hide" id="tutorial-finale" tabindex="-1" role="dialog"
aria-labelledby="tutorial-finale-label" aria-hidden="true"> aria-labelledby="tutorial-finale-label" aria-hidden="true">
<div class="modal-header"> <div class="modal-header">
<h3 id="tutorial-finale-label">{% blocktrans %}Welcome to {{ product_name }}{% endblocktrans %}</h3> <h3 id="tutorial-finale-label">{% trans %}Welcome to {{ product_name }}{% endtrans %}</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<p>{% blocktrans %}Streams, topics, and narrowing make {{ product_name }} conversations <p>{% trans %}Streams, topics, and narrowing make {{ product_name }} conversations
efficient and productive.{% endblocktrans %}</p> efficient and productive.{% endtrans %}</p>
<p>{% blocktrans %}That's all there is to it, so let's get started!{% endblocktrans %}</p> <p>{% trans %}That's all there is to it, so let's get started!{% endtrans %}</p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-primary" type="submit" id="tutorial-get-started">{% blocktrans %}Get started{% endblocktrans %}</button> <button class="btn btn-primary" type="submit" id="tutorial-get-started">{% trans %}Get started{% endtrans %}</button>
</div> </div>
</div> </div>

View File

@ -1,13 +1,12 @@
{% extends "zerver/portico.html" %} {% extends "zerver/portico.html" %}
{% load i18n %}
{% block portico_content %} {% block portico_content %}
<h1>{% blocktrans %}Unknown email unsubscribe request{% endblocktrans %}</h1> <h1>{% trans %}Unknown email unsubscribe request{% endtrans %}</h1>
<p>{% blocktrans %}Hi there! It looks like you tried to unsubscribe from something, but we don't <p>{% trans %}Hi there! It looks like you tried to unsubscribe from something, but we don't
recognize the URL.{% endblocktrans %}</p> recognize the URL.{% endtrans %}</p>
<p>{% blocktrans %}Please double-check that you have the full URL and try again, or <a href="mailto:{{ zulip_admin }}?Subject=Unsubscribe%20me%2C%20please!&Body=Hi%20there!%0A%0AI%20clicked%20this%20unsubscribe%20link%20in%20a%20Zulip%20e-mail%2C%20but%20it%20took%20me%20to%20an%20error%20page%3A%0A%0A_____________%0A%0APlease%20unsubscribe%20me.%0A%0AThanks%2C%0A_____________%0A">email us</a> and we'll get this squared away!{% endblocktrans %}</p> <p>{% trans %}Please double-check that you have the full URL and try again, or <a href="mailto:{{ zulip_admin }}?Subject=Unsubscribe%20me%2C%20please!&Body=Hi%20there!%0A%0AI%20clicked%20this%20unsubscribe%20link%20in%20a%20Zulip%20e-mail%2C%20but%20it%20took%20me%20to%20an%20error%20page%3A%0A%0A_____________%0A%0APlease%20unsubscribe%20me.%0A%0AThanks%2C%0A_____________%0A">email us</a> and we'll get this squared away!{% endtrans %}</p>
{% endblock %} {% endblock %}

View File

@ -1,12 +1,11 @@
{% extends "zerver/portico.html" %} {% extends "zerver/portico.html" %}
{% load i18n %}
{% block portico_content %} {% block portico_content %}
<h1>{% blocktrans %}Email settings updated{% endblocktrans %}</h1> <h1>{% trans %}Email settings updated{% endtrans %}</h1>
<p>{% blocktrans %}We've updated your email subscription settings, and you won't get {{ subscription_type }} emails anymore.{% endblocktrans %}</p> <p>{% trans %}We've updated your email subscription settings, and you won't get {{ subscription_type }} emails anymore.{% endtrans %}</p>
<p>{% blocktrans %}To undo this change or review your other subscription settings, please visit your <a href="https://{{ external_host }}/#settings">Zulip Settings page</a>{% endblocktrans %}.</p> <p>{% trans %}To undo this change or review your other subscription settings, please visit your <a href="https://{{ external_host }}/#settings">Zulip Settings page</a>{% endtrans %}.</p>
{% endblock %} {% endblock %}

View File

@ -1,7 +1,7 @@
{% comment %} {#
Mail sent to us when a company accepts the ToS for Zulip Enterprise Mail sent to us when a company accepts the ToS for Zulip Enterprise
edition. edition.
{% endcomment %} #}
Hello, Hello,

View File

@ -136,6 +136,8 @@ def is_django_block_tag(tag):
'ifequal', 'ifequal',
'verbatim', 'verbatim',
'blocktrans', 'blocktrans',
'trans',
'raw',
] ]
def get_handlebars_tag(text, i): def get_handlebars_tag(text, i):

View File

@ -2,10 +2,10 @@ from __future__ import absolute_import
from django import forms from django import forms
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.utils.safestring import mark_safe
from django.contrib.auth.forms import SetPasswordForm, AuthenticationForm, \ from django.contrib.auth.forms import SetPasswordForm, AuthenticationForm, \
PasswordResetForm PasswordResetForm
from django.conf import settings from django.conf import settings
from jinja2 import Markup as mark_safe
import logging import logging

View File

@ -3,7 +3,7 @@ from __future__ import absolute_import
from django.conf import settings from django.conf import settings
from django.template.defaultfilters import slugify from django.template.defaultfilters import slugify
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.safestring import mark_safe from jinja2 import Markup as mark_safe
import unicodedata import unicodedata
from zerver.lib.avatar import user_avatar_hash from zerver.lib.avatar import user_avatar_hash

View File

@ -0,0 +1,75 @@
"""
The contents of this file are taken from
[Django-admin](https://github.com/niwinz/django-jinja/blob/master/django_jinja/management/commands/makemessages.py)
Jinja2's i18n functionality is not exactly the same as Django's.
In particular, the tags names and their syntax are different:
1. The Django ``trans`` tag is replaced by a _() global.
2. The Django ``blocktrans`` tag is called ``trans``.
(1) isn't an issue, since the whole ``makemessages`` process is based on
converting the template tags to ``_()`` calls. However, (2) means that
those Jinja2 ``trans`` tags will not be picked up by Django's
``makemessages`` command.
There aren't any nice solutions here. While Jinja2's i18n extension does
come with extraction capabilities built in, the code behind ``makemessages``
unfortunately isn't extensible, so we can:
* Duplicate the command + code behind it.
* Offer a separate command for Jinja2 extraction.
* Try to get Django to offer hooks into makemessages().
* Monkey-patch.
We are currently doing that last thing. It turns out there we are lucky
for once: It's simply a matter of extending two regular expressions.
Credit for the approach goes to:
http://stackoverflow.com/questions/2090717/getting-translation-strings-for-jinja2-templates-integrated-with-django-1-x
"""
import re
from django.core.management.commands import makemessages
from django.utils.translation import trans_real
from django.template.base import BLOCK_TAG_START, BLOCK_TAG_END
strip_whitespace_right = re.compile(r"(%s-?\s*(trans|pluralize).*?-%s)\s+" % (BLOCK_TAG_START, BLOCK_TAG_END), re.U)
strip_whitespace_left = re.compile(r"\s+(%s-\s*(endtrans|pluralize).*?-?%s)" % (BLOCK_TAG_START, BLOCK_TAG_END), re.U)
def strip_whitespaces(src):
src = strip_whitespace_left.sub(r'\1', src)
src = strip_whitespace_right.sub(r'\1', src)
return src
class Command(makemessages.Command):
def handle(self, *args, **options):
old_endblock_re = trans_real.endblock_re
old_block_re = trans_real.block_re
old_constant_re = trans_real.constant_re
old_templatize = trans_real.templatize
# Extend the regular expressions that are used to detect
# translation blocks with an "OR jinja-syntax" clause.
trans_real.endblock_re = re.compile(
trans_real.endblock_re.pattern + '|' + r"""^-?\s*endtrans\s*-?$""")
trans_real.block_re = re.compile(
trans_real.block_re.pattern + '|' + r"""^-?\s*trans(?:\s+(?!'|")(?=.*?=.*?)|\s*-?$)""")
trans_real.plural_re = re.compile(
trans_real.plural_re.pattern + '|' + r"""^-?\s*pluralize(?:\s+.+|-?$)""")
trans_real.constant_re = re.compile(r"""_\(((?:".*?")|(?:'.*?')).*\)""")
def my_templatize(src, origin=None):
new_src = strip_whitespaces(src)
return old_templatize(new_src, origin)
trans_real.templatize = my_templatize
try:
super(Command, self).handle(*args, **options)
finally:
trans_real.endblock_re = old_endblock_re
trans_real.block_re = old_block_re
trans_real.templatize = old_templatize
trans_real.constant_re = old_constant_re

View File

@ -5,7 +5,7 @@ from django.conf import settings
from django.contrib.auth import authenticate, login, get_backends from django.contrib.auth import authenticate, login, get_backends
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, HttpResponseForbidden, HttpResponse from django.http import HttpResponseRedirect, HttpResponseForbidden, HttpResponse
from django.shortcuts import render_to_response, redirect from django.shortcuts import redirect
from django.template import RequestContext, loader from django.template import RequestContext, loader
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.cache import patch_cache_control from django.utils.cache import patch_cache_control
@ -67,6 +67,7 @@ import jwt
import hashlib import hashlib
import hmac import hmac
from zproject.jinja2 import render_to_response
from zerver.lib.rest import rest_dispatch as _rest_dispatch from zerver.lib.rest import rest_dispatch as _rest_dispatch
rest_dispatch = csrf_exempt((lambda request, *args, **kwargs: _rest_dispatch(request, globals(), *args, **kwargs))) rest_dispatch = csrf_exempt((lambda request, *args, **kwargs: _rest_dispatch(request, globals(), *args, **kwargs)))
@ -231,7 +232,7 @@ def accounts_register(request):
# we have to set it here. # we have to set it here.
'password_auth_enabled': password_auth_enabled(realm), 'password_auth_enabled': password_auth_enabled(realm),
}, },
context_instance=RequestContext(request)) request=request)
@zulip_login_required @zulip_login_required
def accounts_accept_terms(request): def accounts_accept_terms(request):
@ -256,7 +257,7 @@ def accounts_accept_terms(request):
form = ToSForm() form = ToSForm()
return render_to_response('zerver/accounts_accept_terms.html', return render_to_response('zerver/accounts_accept_terms.html',
{ 'form': form, 'company_name': domain, 'email': email }, { 'form': form, 'company_name': domain, 'email': email },
context_instance=RequestContext(request)) request=request)
from zerver.lib.ccache import make_ccache from zerver.lib.ccache import make_ccache
@ -316,7 +317,7 @@ def api_endpoint_docs(request):
'content': calls, 'content': calls,
'langs': langs, 'langs': langs,
}, },
context_instance=RequestContext(request)) request=request)
@authenticated_json_post_view @authenticated_json_post_view
@has_request_variables @has_request_variables
@ -384,7 +385,7 @@ def maybe_send_to_registration(request, email, full_name=''):
urllib.parse.quote_plus(full_name.encode('utf8'))))) urllib.parse.quote_plus(full_name.encode('utf8')))))
else: else:
return render_to_response('zerver/accounts_home.html', {'form': form}, return render_to_response('zerver/accounts_home.html', {'form': form},
context_instance=RequestContext(request)) request=request)
def login_or_register_remote_user(request, remote_username, user_profile, full_name=''): def login_or_register_remote_user(request, remote_username, user_profile, full_name=''):
if user_profile is None or user_profile.is_mirror_dummy: if user_profile is None or user_profile.is_mirror_dummy:
@ -601,7 +602,7 @@ def initial_invite_page(request):
params['invite_suffix'] = user.realm.domain params['invite_suffix'] = user.realm.domain
return render_to_response('zerver/initial_invite_page.html', params, return render_to_response('zerver/initial_invite_page.html', params,
context_instance=RequestContext(request)) request=request)
@require_post @require_post
def logout_then_login(request, **kwargs): def logout_then_login(request, **kwargs):
@ -665,7 +666,7 @@ def accounts_home(request):
form = create_homepage_form(request) form = create_homepage_form(request)
return render_to_response('zerver/accounts_home.html', return render_to_response('zerver/accounts_home.html',
{'form': form, 'current_url': request.get_full_path}, {'form': form, 'current_url': request.get_full_path},
context_instance=RequestContext(request)) request=request)
def approximate_unread_count(user_profile): def approximate_unread_count(user_profile):
not_in_home_view_recipients = [sub.recipient.id for sub in \ not_in_home_view_recipients = [sub.recipient.id for sub in \
@ -880,7 +881,7 @@ def home(request):
'embedded': narrow_stream is not None, 'embedded': narrow_stream is not None,
'product_name': product_name 'product_name': product_name
}, },
context_instance=RequestContext(request)) request=request)
patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True) patch_cache_control(response, no_cache=True, no_store=True, must_revalidate=True)
return response return response
@ -1280,4 +1281,4 @@ def email_unsubscribe(request, type, token):
return process_unsubscribe(token, display_name, unsubscribe_function) return process_unsubscribe(token, display_name, unsubscribe_function)
return render_to_response('zerver/unsubscribe_link_error.html', {}, return render_to_response('zerver/unsubscribe_link_error.html', {},
context_instance=RequestContext(request)) request=request)

View File

@ -0,0 +1,33 @@
from __future__ import absolute_import # Python 2 only
from django.contrib.staticfiles.storage import staticfiles_storage
from django.template.defaultfilters import slugify, pluralize
from django.core.urlresolvers import reverse
from django.template.loader import render_to_string
from django.utils import translation
from django.http import HttpResponse
from jinja2 import Environment
from .compressors import compressed_css, minified_js
def render_to_response(*args, **kwargs):
response = render_to_string(*args, **kwargs)
return HttpResponse(response)
def environment(**options):
env = Environment(**options)
env.globals.update({
'static': staticfiles_storage.url,
'url': reverse,
'compressed_css': compressed_css,
'minified_js': minified_js,
})
env.install_gettext_translations(translation)
env.filters['slugify'] = slugify
env.filters['pluralize'] = pluralize
return env

View File

@ -0,0 +1,66 @@
from __future__ import absolute_import
import sys
import jinja2
from django.utils import six
from django.template.backends import jinja2 as django_jinja2
from django.template import TemplateDoesNotExist, TemplateSyntaxError, Context
from django.utils.module_loading import import_string
from django.template.backends.utils import csrf_input_lazy, csrf_token_lazy
class Jinja2(django_jinja2.Jinja2):
"""Context processors aware Jinja2 backend.
The default Jinja2 backend in Django is not aware of context
processors so we just derive from the default Jinja2 backend
and add the functionality to pass the context processors to
the `Template` object.
"""
def __init__(self, params, *args, **kwargs):
# We need to remove `context_processors` from `OPTIONS` because
# `Environment` doesn't expect it
self.context_processors = params['OPTIONS'].pop('context_processors', [])
super(Jinja2, self).__init__(params, *args, **kwargs)
def get_template(self, template_name):
try:
return Template(self.env.get_template(template_name),
self.context_processors)
except jinja2.TemplateNotFound as exc:
six.reraise(TemplateDoesNotExist, TemplateDoesNotExist(exc.args),
sys.exc_info()[2])
except jinja2.TemplateSyntaxError as exc:
six.reraise(TemplateSyntaxError, TemplateSyntaxError(exc.args),
sys.exc_info()[2])
class Template(django_jinja2.Template):
"""Context processors aware Template.
This class upgrades the default `Template` to apply context
processors to the context before passing it to the `render`
function.
"""
def __init__(self, template, context_processors, *args, **kwargs):
self.context_processors = context_processors
super(Template, self).__init__(template, *args, **kwargs)
def render(self, context=None, request=None):
if context is None:
context = {}
if isinstance(context, Context):
context = context.flatten() # Jinja2 expects a dictionary
if request is not None:
context['request'] = request
context['csrf_input'] = csrf_input_lazy(request)
context['csrf_token'] = csrf_token_lazy(request)
for context_processor in self.context_processors:
cp = import_string(context_processor)
context.update(cp(request))
return self.template.render(context)

View File

@ -0,0 +1,22 @@
"""
`minified_js` is taken from `zerver.templatetags.minified_js.py`
"""
from __future__ import absolute_import # Python 2 only
from django.conf import settings
from django.template import TemplateSyntaxError
from pipeline.templatetags.compressed import CompressedCSSNode
from zerver.templatetags.minified_js import MinifiedJSNode
def compressed_css(package_name):
return CompressedCSSNode(package_name).render({package_name: package_name})
def minified_js(sourcefile):
if sourcefile not in settings.JS_SPECS:
raise TemplateSyntaxError(
"Invalid argument: no JS file %s".format(sourcefile))
return MinifiedJSNode(sourcefile).render({})

View File

@ -245,11 +245,29 @@ if PRODUCTION:
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', 'BACKEND': 'zproject.jinja2.backends.Jinja2',
'DIRS': [ 'DIRS': [
os.path.join(DEPLOY_ROOT, 'templates'), os.path.join(DEPLOY_ROOT, 'templates'),
], ],
'APP_DIRS': False, 'APP_DIRS': False,
'OPTIONS': {
'environment': 'zproject.jinja2.environment',
'extensions': [
'jinja2.ext.i18n',
'jinja2.ext.autoescape',
],
'context_processors': [
'zerver.context_processors.add_settings',
'zerver.context_processors.add_metrics',
],
},
},
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(DEPLOY_ROOT, 'django_templates'),
],
'APP_DIRS': False,
'OPTIONS': { 'OPTIONS': {
'debug': DEBUG, 'debug': DEBUG,
'loaders': LOADERS, 'loaders': LOADERS,