aboutsummaryrefslogtreecommitdiffstats
path: root/customising
diff options
context:
space:
mode:
Diffstat (limited to 'customising')
-rw-r--r--customising/config.md1137
-rw-r--r--customising/index.md44
-rw-r--r--customising/themes.md188
-rw-r--r--customising/translation.md179
4 files changed, 1548 insertions, 0 deletions
diff --git a/customising/config.md b/customising/config.md
new file mode 100644
index 000000000..dc9756181
--- /dev/null
+++ b/customising/config.md
@@ -0,0 +1,1137 @@
+---
+layout: page
+title: Configuration
+---
+
+# Configuring Alaveteli
+
+<p class="lead">
+ You can control much of how Alaveteli looks and behaves just by
+ changing the config settings.
+</p>
+
+## The general configuration file
+
+The alaveteli code ships with an example configuration file: `config/general.yml-example`.
+
+As part of the [installation process]({{ site.baseurl }}installing ), the
+example file gets copied to `config/general.yml`. You **must** edit this file to
+suit your needs.
+
+Note that the default settings for frontpage examples are designed to work with
+the dummy data shipped with Alaveteli. Once you have real data, you should
+certainly edit these.
+
+Note that there are [other configuration files](#other-config) too, for specific aspects of Alaveteli.
+
+
+## Config settings by topic
+
+The following are all the configuration settings that you can change in `config/general.yml`.
+When you edit this file, remember it must be in the <a href="http://yaml.org">YAML syntax</a>.
+It's not complicated but &mdash; especially if you're editing a list &mdash; be careful to get the
+indentation correct. If in doubt, look at the examples already in the file, and don't use tabs.
+
+
+### Appearance and overall behaviour of the site:
+
+<code><a href="#site_name">SITE_NAME</a></code>
+<br> <code><a href="#domain">DOMAIN</a></code>
+<br> <code><a href="#force_ssl">FORCE_SSL</a></code>
+<br> <code><a href="#force_registration_on_new_request">FORCE_REGISTRATION_ON_NEW_REQUEST</a></code>
+<br> <code><a href="#theme_urls">THEME_URLS</a></code>
+<br> <code><a href="#theme_branch">THEME_BRANCH</a></code>
+<br> <code><a href="#frontpage_publicbody_examples">FRONTPAGE_PUBLICBODY_EXAMPLES</a></code>
+<br> <code><a href="#public_body_statistics_page">PUBLIC_BODY_STATISTICS_PAGE</a></code>
+<br> <code><a href="#minimum_requests_for_statistics">MINIMUM_REQUESTS_FOR_STATISTICS</a></code>
+
+### Site status:
+
+<code><a href="#read_only">READ_ONLY</a></code>
+<br> <code><a href="#staging_site">STAGING_SITE</a></code>
+
+### Locale and internationalisation:
+
+<code><a href="#iso_country_code">ISO_COUNTRY_CODE</a></code>
+<br> <code><a href="#time_zone">TIME_ZONE</a></code>
+<br> <code><a href="#available_locales">AVAILABLE_LOCALES</a></code>
+<br> <code><a href="#default_locale">DEFAULT_LOCALE</a></code>
+<br> <code><a href="#use_default_browser_language">USE_DEFAULT_BROWSER_LANGUAGE</a></code>
+<br> <code><a href="#include_default_locale_in_urls">INCLUDE_DEFAULT_LOCALE_IN_URLS</a></code>
+
+### Definition of "late":
+
+<code><a href="#reply_late_after_days">REPLY_LATE_AFTER_DAYS</a></code>
+<br> <code><a href="#reply_very_late_after_days">REPLY_VERY_LATE_AFTER_DAYS</a></code>
+<br> <code><a href="#special_reply_very_late_after_days">SPECIAL_REPLY_VERY_LATE_AFTER_DAYS</a></code>
+<br> <code><a href="#working_or_calendar_days">WORKING_OR_CALENDAR_DAYS</a></code>
+
+### Admin access:
+
+<code><a href="#admin_username">ADMIN_USERNAME</a></code>
+<br> <code><a href="#admin_password">ADMIN_PASSWORD</a></code>
+<br> <code><a href="#admin_username">DISABLE_EMERGENCY_USER</a></code>
+<br> <code><a href="#skip_admin_auth">SKIP_ADMIN_AUTH</a></code>
+
+### Email management:
+
+<code><a href="#incoming_email_domain">INCOMING_EMAIL_DOMAIN</a></code>
+<br> <code><a href="#incoming_email_prefix">INCOMING_EMAIL_PREFIX</a></code>
+<br> <code><a href="#incoming_email_secret">INCOMING_EMAIL_SECRET</a></code>
+<br> <code><a href="#blackhole_prefix">BLACKHOLE_PREFIX</a></code>
+<br> <code><a href="#contact_email">CONTACT_EMAIL</a></code>
+<br> <code><a href="#contact_name">CONTACT_NAME</a></code>
+<br> <code><a href="#track_sender_email">TRACK_SENDER_EMAIL</a></code>
+<br> <code><a href="#track_sender_name">TRACK_SENDER_NAME</a></code>
+<br> <code><a href="#raw_emails_location">RAW_EMAILS_LOCATION</a></code>
+<br> <code><a href="#exception_notifications_from">EXCEPTION_NOTIFICATIONS_FROM</a></code>
+<br> <code><a href="#exception_notifications_to">EXCEPTION_NOTIFICATIONS_TO</a></code>
+<br> <code><a href="#forward_nonbounce_responses_to">FORWARD_NONBOUNCE_RESPONSES_TO</a></code>
+<br> <code><a href="#mta_log_path">MTA_LOG_PATH</a></code>
+<br> <code><a href="#mta_log_type">MTA_LOG_TYPE</a></code>
+
+### General admin (keys, paths, back-end services):
+
+<code><a href="#cookie_store_session_secret">COOKIE_STORE_SESSION_SECRET</a></code>
+<br> <code><a href="#recaptcha_public_key">RECAPTCHA_PUBLIC_KEY</a></code>
+<br> <code><a href="#recaptcha_private_key">RECAPTCHA_PRIVATE_KEY</a></code>
+<br> <code><a href="#gaze_url">GAZE_URL</a></code>
+<br> <code><a href="#ga_code">GA_CODE</a></code> (GA=Google Analytics)
+<br> <code><a href="#utility_search_path">UTILITY_SEARCH_PATH</a></code>
+<br> <code><a href="#shared_files_path">SHARED_FILES_PATH</a></code>
+<br> <code><a href="#shared_files">SHARED_FILES</a></code>
+<br> <code><a href="#shared_directories">SHARED_DIRECTORIES</a></code>
+
+### Behaviour settings and switches:
+
+<code><a href="#new_response_reminder_after_days">NEW_RESPONSE_REMINDER_AFTER_DAYS</a></code>
+<br> <code><a href="#max_requests_per_user_per_day">MAX_REQUESTS_PER_USER_PER_DAY</a></code>
+<br> <code><a href="#override_all_public_body_request_emails">OVERRIDE_ALL_PUBLIC_BODY_REQUEST_EMAILS</a></code>
+<br> <code><a href="#allow_batch_requests">ALLOW_BATCH_REQUESTS</a></code>
+<br> <code><a href="#public_body_list_fallback_to_default_locale">PUBLIC_BODY_LIST_FALLBACK_TO_DEFAULT_LOCALE</a></code>
+<br> <code><a href="#cache_fragments">CACHE_FRAGMENTS</a></code>
+
+### External public services:
+
+<code><a href="#blog_feed">BLOG_FEED</a></code>
+<br> <code><a href="#twitter_username">TWITTER_USERNAME</a></code>
+<br> <code><a href="#twitter_widget_id">TWITTER_WIDGET_ID</a></code>
+<br> <code><a href="#donation_url">DONATION_URL</a></code>
+
+### Development work or special cases:
+
+<code><a href="#debug_record_memory">DEBUG_RECORD_MEMORY</a></code>
+<br> <code><a href="#varnish_host">VARNISH_HOST</a></code>
+<br> <code><a href="#use_mailcatcher_in_development">USE_MAILCATCHER_IN_DEVELOPMENT</a></code>
+<br> <code><a href="#use_ghostscript_compression">USE_GHOSTSCRIPT_COMPRESSION</a></code>
+<br> <code><a href="#html_to_pdf_command">HTML_TO_PDF_COMMAND</a></code>
+
+
+---
+
+## All the general settings
+
+
+<dl class="glossary">
+
+ <dt>
+ <a name="site_name"><code>SITE_NAME</code></a>
+ </dt>
+ <dd>
+ <strong>SITE_NAME</strong> appears in various places throughout the site.
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ <code>SITE_NAME: 'Alaveteli'</code>
+ </li>
+ <li>
+ <code>SITE_NAME: 'WhatDoTheyKnow'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="domain"><code>DOMAIN</code></a>
+ </dt>
+ <dd>
+ Domain used in URLs generated by scripts (e.g. for going in some emails)
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ <code>DOMAIN: '127.0.0.1:3000'</code>
+ </li>
+ <li>
+ <code>DOMAIN: 'www.example.com'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="force_ssl"><code>FORCE_SSL</code></a>
+ </dt>
+ <dd>
+ If true forces everyone (in the production environment) to use encrypted connections
+ (via https) by redirecting unencrypted connections. This is <strong>highly
+ recommended</strong> so that logins can't be intercepted by naughty people.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>FORCE_SSL: true</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="iso_country_code"><code>ISO_COUNTRY_CODE</code></a>
+ </dt>
+ <dd>
+ The <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO country code</a>
+ of the country in which your Alaveteli site is deployed.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>ISO_COUNTRY_CODE: GB</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="time_zone"><code>TIME_ZONE</code></a>
+ </dt>
+ <dd>
+ This is the <a href="http://en.wikipedia.org/wiki/List_of_tz_database_time_zones">timezone</a>
+ that Alaveteli usese to display times and dates.
+ If not set, defaults to UTC.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>TIME_ZONE: Australia/Sydney</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="blog_feed"><code>BLOG_FEED</code></a>
+ </dt>
+ <dd>
+ These feeds are displayed accordingly on the Alaveteli "blog" page: <!-- TODO -->
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>BLOG_FEED: 'http://www.mysociety.org/category/projects/whatdotheyknow/feed/'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="twitter_username"><code>TWITTER_USERNAME</code></a>
+ <a name="twitter_widget_id"><code>TWITTER_WIDGET_ID</code></a>
+ </dt>
+ <dd>
+ If you want a twitter feed displayed on the "blog" page, provide the widget ID and username.
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ <code>TWITTER_USERNAME: WhatDoTheyKnow</code>
+ </li>
+ <li>
+ <code>TWITTER_WIDGET_ID: '833549204689320031'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="available_locales"><code>AVAILABLE_LOCALES</code></a> &
+ <a name="default_locale"><code>DEFAULT_LOCALE</code></a>
+ </dt>
+ <dd>
+ <strong>AVAILABLE_LOCALES</strong> lists all the locales you want your site to support.
+ If there is more than one, use spaces betwween the entries.
+ Nominate one of these locales as the default with <strong>DEFAULT_LOCALE</strong>.
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ <code>AVAILABLE_LOCALES: 'en es'</code>
+ </li>
+ <li>
+ <code>DEFAULT_LOCALE: 'en'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="use_default_browser_language"><code>USE_DEFAULT_BROWSER_LANGUAGE</code></a>
+ </dt>
+ <dd>
+ Should Alaveteli try to use the default language of the user's browser?
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>USE_DEFAULT_BROWSER_LANGUAGE: true</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="include_default_locale_in_urls"><code>INCLUDE_DEFAULT_LOCALE_IN_URLS</code></a>
+ </dt>
+ <dd>
+ Normally, Alaveteli will put the locale into its URLs, like this
+ <code>www.example.com/en/body/list/all</code>. If you don't want this
+ behaviour whenever the locale is the default one, set
+ <strong>INCLUDE_DEFAULT_LOCALE_IN_URLS</strong> to false.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>INCLUDE_DEFAULT_LOCALE_IN_URLS: true</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="reply_late_after_days"><code>REPLY_LATE_AFTER_DAYS</code></a><br>
+ <a name="reply_very_late_after_days"><code>REPLY_VERY_LATE_AFTER_DAYS</code></a><br>
+ <a name="special_reply_very_late_after_days"><code>SPECIAL_REPLY_VERY_LATE_AFTER_DAYS</code></a>
+ <a name="working_or_calendar_days"><code>WORKING_OR_CALENDAR_DAYS</code></a>
+ </dt>
+ <dd>
+ The <strong>REPLY...AFTER_DAYS</strong> settings define how many days must have
+ passed before an answer to a request is officially <em>late</em>.
+ The SPECIAL case is for some types of authority (for example: in the UK, schools) which are
+ granted a bit longer than everyone else to respond to questions.
+ The <strong>WORKING_OR_CALENDAR_DAYS</strong> setting can be either "working" (the default)
+ or "calendar", and determines which days are counted.
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ <code>REPLY_LATE_AFTER_DAYS: 20</code>
+ </li>
+ <li>
+ <code>REPLY_VERY_LATE_AFTER_DAYS: 40</code>
+ </li>
+ <li>
+ <code>SPECIAL_REPLY_VERY_LATE_AFTER_DAYS: 60</code>
+ </li>
+ <li>
+ <code>WORKING_OR_CALENDAR_DAYS: working</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="frontpage_publicbody_examples"><code>FRONTPAGE_PUBLICBODY_EXAMPLES</code></a>
+ </dt>
+ <dd>
+ Specify which public bodies you want to be listed as examples on the home page,
+ using their <code>short_names</code>.
+ If you want more than one, separate them with semicolons.
+ Comment this out if you want this to be auto-generated.
+ <p>
+ <strong>Warning</strong>: this is slow &mdash; don't use in production!
+ </p>
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ <code>FRONTPAGE_PUBLICBODY_EXAMPLES: 'tgq'</code>
+ </li>
+ <li>
+ <code>FRONTPAGE_PUBLICBODY_EXAMPLES: 'tgq;foo;bar'</code>
+ </li>
+ <li>
+ <code># FRONTPAGE_PUBLICBODY_EXAMPLES: </code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="theme_urls"><code>THEME_URLS</code></a>
+ </dt>
+ <dd>
+ URLs of <a href="{{ site.baseurl }}customising/themes">themes</a> to download and use
+ (when running the <code>rails-post-deploy</code> script). The earlier in the list means
+ the templates have a higher priority.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <pre>
+THEME_URLS:
+ - 'git://github.com/mysociety/alavetelitheme.git'
+</pre>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="theme_branch"><code>THEME_BRANCH</code></a>
+ </dt>
+ <dd>
+ When <code>rails-post-deploy</code> installs the <a href="{{ site.baseurl }}customising/themes">themes</a>,
+ it will try the theme branch first, but only if you've set <code>THEME_BRANCH</code>
+ to be true. If the branch doesn't exist it will fall back to using a tagged version
+ specific to your installed alaveteli version, and if that doesn't exist it will
+ back to <code>master</code>.
+ <p>
+ The default theme is the "Alaveteli" theme. This gets installed automatically when
+ <code>rails-post-deploy</code> runs.
+ </p>
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>THEME_BRANCH: false</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="force_registration_on_new_request"><code>FORCE_REGISTRATION_ON_NEW_REQUEST</code></a>
+ </dt>
+ <dd>
+ Does a user needs to sign in to start the New Request process?
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>FORCE_REGISTRATION_ON_NEW_REQUEST: false</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+
+ <dt>
+ <a name="incoming_email_domain"><code>INCOMING_EMAIL_DOMAIN</code></a>
+ </dt>
+ <dd>
+ Your email domain for incoming mail.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>INCOMING_EMAIL_DOMAIN: 'localhost'</code>
+ </li>
+ <li>
+ <code>INCOMING_EMAIL_DOMAIN: 'foifa.com'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="incoming_email_prefix"><code>INCOMING_EMAIL_PREFIX</code></a>
+ </dt>
+ <dd>
+ An optional prefix to help you distinguish FOI requests.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>INCOMING_EMAIL_PREFIX: ''</code>
+ </li>
+ <li>
+ <code>INCOMING_EMAIL_PREFIX: 'foi+'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+
+ <dt>
+ <a name="incoming_email_secret"><code>INCOMING_EMAIL_SECRET</code></a>
+ </dt>
+ <dd>
+ Used for hash in request email address.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>INCOMING_EMAIL_SECRET: '11ae 4e3b 70ff c001 3682 4a51 e86d ef5f'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="blackhole_prefix"><code>BLACKHOLE_PREFIX</code></a>
+ </dt>
+ <dd>
+ Used as envelope from at the incoming email domain for cases where you don't care about failure.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>BLACKHOLE_PREFIX: 'do-not-reply-to-this-address'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="admin_username"><code>ADMIN_USERNAME</code></a>
+ &amp;
+ <a name="admin_password"><code>ADMIN_PASSWORD</code></a>
+ <br>
+ <a name="admin_username"><code>DISABLE_EMERGENCY_USER</code></a>
+ </dt>
+ <dd>
+ The emergency user.
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ <code>ADMIN_USERNAME: 'adminxxxx'</code>
+ </li>
+ <li>
+ <code>ADMIN_PASSWORD: 'passwordx'</code>
+ </li>
+ <li>
+ <code>DISABLE_EMERGENCY_USER: false</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="skip_admin_auth"><code>SKIP_ADMIN_AUTH</code></a>
+ </dt>
+ <dd>
+ Set this to true, and the admin interface will be available to anonymous users.
+ Obviously, you should not set this to be true in production environments.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>SKIP_ADMIN_AUTH: false</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="contact_email"><code>CONTACT_EMAIL</code></a>
+ &amp;
+ <a name="contact_name"><code>CONTACT_NAME</code></a>
+ </dt>
+ <dd>
+ Email "from" details.
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ <code>CONTACT_EMAIL: 'team@example.com'</code>
+ </li>
+ <li>
+ <code>CONTACT_NAME: 'Alaveteli Webmaster'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="track_sender_email"><code>TRACK_SENDER_EMAIL</code></a> &amp;
+ <a name="track_sender_name"><code>TRACK_SENDER_NAME</code></a>
+ </dt>
+ <dd>
+ Email "from" details for track messages.
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ <code>TRACK_SENDER_EMAIL: 'alaveteli@example.com'</code>
+ </li>
+ <li>
+ <code>TRACK_SENDER_NAME: 'Alaveteli Webmaster'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="raw_emails_location"><code>RAW_EMAILS_LOCATION</code></a>
+ </dt>
+ <dd>
+ Where the raw incoming email data gets stored.
+ <strong>Make sure you back this up!</strong>
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>RAW_EMAILS_LOCATION: 'files/raw_emails'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="cookie_store_session_secret"><code>COOKIE_STORE_SESSION_SECRET</code></a>
+ </dt>
+ <dd>
+ Secret key for signing cookie_store sessions. Make it long and random.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>COOKIE_STORE_SESSION_SECRET: 'uIngVC238Jn9NsaQizMNf89pliYmDBFugPjHS2JJmzOp8'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="read_only"><code>READ_ONLY</code></a>
+ </dt>
+ <dd>
+ If present, <strong>READ_ONLY</strong> puts the site in read-only mode,
+ and uses the text as reason (whole paragraph). Please use a read-only database
+ user as well, as it only checks in a few obvious places.
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ Typically, you do <strong>not</strong> want to run your site in
+ read-only mode &mdash; so set <strong>READ_ONLY</strong> to be
+ an empty string.
+ <br>
+ <code>
+ READ_ONLY: ''
+ </code>
+ </li>
+ <li>
+ <code>
+ READ_ONLY: 'The site is not currently accepting requests while we move the server.'
+ </code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="staging_site"><code>STAGING_SITE</code></a>
+ </dt>
+ <dd>
+ Is this a staging or development site (1) or a live (production) site (0)?
+ This controls whether or not the <code>rails-post-deploy</code> script
+ will create the file <code>config/rails_env.rb</code> file to force
+ Rails into production environment.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>STAGING_SITE: 1</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="recaptcha_public_key"><code>RECAPTCHA_PUBLIC_KEY</code></a> &amp;
+ <a name="recaptcha_private_key"><code>RECAPTCHA_PRIVATE_KEY</code></a>
+ </dt>
+ <dd>
+ Recaptcha, for detecting humans. Get keys here:
+ <a href="http://recaptcha.net/whyrecaptcha.html">http://recaptcha.net/whyrecaptcha.html</a>
+
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ <code>RECAPTCHA_PUBLIC_KEY: '7HoPjGBBBBBBBBBkmj78HF9PjjaisQ893'</code>
+ </li>
+ <li>
+ <code>RECAPTCHA_PRIVATE_KEY: '7HjPjGBBBBBCBBBpuTy8a33sgnGG7A'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="new_response_reminder_after_days"><code>NEW_RESPONSE_REMINDER_AFTER_DAYS</code></a>
+ </dt>
+ <dd>
+ Number of days after which to send a 'new response reminder'.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>NEW_RESPONSE_REMINDER_AFTER_DAYS: [3, 10, 24]</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="debug_record_memory"><code>DEBUG_RECORD_MEMORY</code></a>
+ </dt>
+ <dd>
+ For debugging memory problems. If true, Alaveteli logs
+ the memory use increase of the Ruby process due to the
+ request (Linux only). Since Ruby never returns memory to the OS, if the
+ existing process previously served a larger request, this won't
+ show any consumption for the later request.
+
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>DEBUG_RECORD_MEMORY: false</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+
+ <dt>
+ <a name="use_ghostscript_compression"><code>USE_GHOSTSCRIPT_COMPRESSION</code></a>
+ </dt>
+ <dd>
+ Currently we default to using pdftk to compress PDFs. You can
+ optionally try Ghostscript, which should do a better job of
+ compression. Some versions of pdftk are buggy with respect to
+ compression, in which case Alaveteli doesn't recompress the PDFs at
+ all and logs a warning message "Unable to compress PDF" &mdash; which would
+ be another reason to try this setting.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>USE_GHOSTSCRIPT_COMPRESSION: true</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+
+ <dt>
+ <a name="gaze_url"><code>GAZE_URL</code></a>
+ </dt>
+ <dd>
+ Alateveli uses mySociety's gazeteer service to determine country from incoming
+ IP address (this lets us suggest an Alaveteli in their country, if one exists).
+ You shouldn't normally need to change this.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>GAZE_URL: http://gaze.mysociety.org</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="forward_nonbounce_responses_to"><code>FORWARD_NONBOUNCE_RESPONSES_TO</code></a>
+ </dt>
+ <dd>
+ The email address to which non-bounce responses should be forwarded
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>FORWARD_NONBOUNCE_RESPONSES_TO: user-support@example.com</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="html_to_pdf_command"><code>HTML_TO_PDF_COMMAND</code></a>
+ </dt>
+ <dd>
+ Path to a program that converts an HTML page in a file to PDF. It
+ should take two arguments: the URL, and a path to an output file.
+ A static binary of <a href="http://wkhtmltopdf.org">wkhtmltopdf</a> is recommended.
+ If the command is not present, a text-only version will be rendered
+ instead.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>HTML_TO_PDF_COMMAND: /usr/local/bin/wkhtmltopdf-amd64</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="exception_notifications_from"><code>EXCEPTION_NOTIFICATIONS_FROM</code></a> &amp;
+ <a name="exception_notifications_to"><code>EXCEPTION_NOTIFICATIONS_TO</code></a>
+ </dt>
+ <dd>
+ Email address(es) used for sending exception notifications.
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ <pre>
+EXCEPTION_NOTIFICATIONS_FROM: do-not-reply-to-this-address@example.com
+
+EXCEPTION_NOTIFICATIONS_TO:
+ - robin@example.com
+ - seb@example.com
+</pre>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="max_requests_per_user_per_day"><code>MAX_REQUESTS_PER_USER_PER_DAY</code></a>
+ </dt>
+ <dd>
+ This rate limiting can be turned off per-user via the admin interface.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>MAX_REQUESTS_PER_USER_PER_DAY: 6</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="varnish_host"><code>VARNISH_HOST</code></a>
+ </dt>
+ <dd>
+ If you're running behind Varnish, it might help to set this to
+ work out where to send purge requests.
+ Otherwise, don't set it.
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ <code>VARNISH_HOST: null</code>
+ </li>
+ <li>
+ <code>VARNISH_HOST: localhost</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="ga_code"><code>GA_CODE</code> (GA=Google Analytics)</a>
+ </dt>
+ <dd>
+ Adding a value here will enable Google Analytics on all non-admin pages for non-admin users.
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ <code>GA_CODE: ''</code>
+ </li>
+ <li>
+ <code>GA_CODE: 'AB-8222142-14'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+
+ <dt>
+ <a name="override_all_public_body_request_emails"><code>OVERRIDE_ALL_PUBLIC_BODY_REQUEST_EMAILS</code></a>
+ </dt>
+ <dd>
+ If you want to override <strong>all</strong> the public body request emails with
+ your own email address so that request emails that would normally go to the public body
+ go to you, use this setting.
+ This is useful for a staging server, so you can play with the whole process of sending requests
+ without inadvertently sending an email to a real authority.
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ <code>OVERRIDE_ALL_PUBLIC_BODY_REQUEST_EMAILS: test-email@foo.com</code>
+ </li>
+ <li>
+ If you don't want this behaviour, comment the setting out
+ <br>
+ <code># OVERRIDE_ALL_PUBLIC_BODY_REQUEST_EMAILS:</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="utility_search_path"><code>UTILITY_SEARCH_PATH</code></a>
+ </dt>
+ <dd>
+ Search path for external command-line utilities (such as pdftohtml, pdftk, unrtf).
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>UTILITY_SEARCH_PATH: ["/usr/bin", "/usr/local/bin"]</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+
+ <dt>
+ <a name="mta_log_path"><code>MTA_LOG_PATH</code></a>
+ </dt>
+ <dd>
+ Path to your exim or postfix log files that will get sucked up
+ by <code>script/load-mail-server-logs</code>.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>MTA_LOG_PATH: '/var/log/exim4/exim-mainlog-*'</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="mta_log_type"><code>MTA_LOG_TYPE</code></a>
+ </dt>
+ <dd>
+ Are you using "exim" or "postfix" for your Mail Transfer Agnt (MTA)?
+
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>MTA_LOG_TYPE: "exim"</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="donation_url"><code>DONATION_URL</code></a>
+ </dt>
+ <dd>
+ URL where people can donate to the organisation running the site. If set,
+ this will be included in the message people see when their request is
+ successful.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>DONATION_URL: "http://www.mysociety.org/donate/"</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="public_body_statistics_page"><code>PUBLIC_BODY_STATISTICS_PAGE</code></a> &amp;
+ <a name="minimum_requests_for_statistics"><code>MINIMUM_REQUESTS_FOR_STATISTICS</code></a>
+ </dt>
+ <dd>
+ If <strong>PUBLIC_BODY_STATISTICS_PAGE</strong> is set to true, Alaveteli will make a
+ page of statistics on the performance of public bodies (which you can see at
+ <code>/body_statistics</code>).
+ The page will only consider public bodies that have had at least the number of requests
+ set by <strong>MINIMUM_REQUESTS_FOR_STATISTICS</strong>.
+
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>PUBLIC_BODY_STATISTICS_PAGE: false</code>
+ </li>
+ <li>
+ <code>MINIMUM_REQUESTS_FOR_STATISTICS: 50</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="public_body_list_fallback_to_default_locale"><code>PUBLIC_BODY_LIST_FALLBACK_TO_DEFAULT_LOCALE</code></a>
+ </dt>
+ <dd>
+ If you would like the public body list page to include bodies that have no translation
+ in the current locale (but which do have a translation in the default locale), set this to true.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>PUBLIC_BODY_LIST_FALLBACK_TO_DEFAULT_LOCALE: false</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+
+ <dt>
+ <a name="use_mailcatcher_in_development"><code>USE_MAILCATCHER_IN_DEVELOPMENT</code></a>
+ </dt>
+ <dd>
+ <!-- TODO check mailcatcher URL -->
+ If true, while in development mode, try to send mail by SMTP to port
+ 1025 (the port the <a href="http://mailcatcher.me">mailcatcher</a> listens on by default):
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>USE_MAILCATCHER_IN_DEVELOPMENT: true</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="cache_fragments"><code>CACHE_FRAGMENTS</code></a>
+ </dt>
+ <dd>
+ Use memcached to cache HTML fragments for better performance.
+ This will only have an effect in environments where
+ <code>config.action_controller.perform_caching</code> is set to true
+
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>CACHE_FRAGMENTS: true</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+
+
+ <dt>
+ <a name="shared_files_path"><code>SHARED_FILES_PATH</code></a>
+ </dt>
+ <dd>
+ In some deployments of Alaveteli you may wish to install each newly
+ deployed version alongside the previous ones, in which case certain
+ files and resources should be shared between these installations.
+ For example, the <code>files</code> directory, the <code>cache</code> directory and the
+ generated graphs such as <code>public/foi-live-creation.png</code>. If you're
+ installing Alaveteli in such a setup then set <strong>SHARED_FILES_PATH</strong> to
+ the directory you're keeping these files under. Otherwise, leave it blank.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>SHARED_FILES_PATH: ''</code> <!-- TODO specific example -->
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+
+ <dt>
+ <a name="shared_files"><code>SHARED_FILES</code></a> &
+ <a name="shared_directories"><code>SHARED_DIRECTORIES</code></a>
+ </dt>
+ <dd>
+ If you have <strong>SHARED_FILES_PATH</strong> set, then these options list the files
+ and directories that are shared; i.e. those to which the deploy scripts
+ should create symlinks from the repository.
+ <div class="more-info">
+ <p>Examples:</p>
+ <ul>
+ <li>
+ <pre>
+SHARED_FILES:
+ - config/database.yml
+ - config/general.yml
+ - config/rails_env.rb
+ - config/newrelic.yml
+ - config/httpd.conf
+ - public/foi-live-creation.png
+ - public/foi-user-use.png
+ - config/aliases
+ </pre>
+ </li>
+ <li>
+ <pre>
+SHARED_DIRECTORIES:
+ - files/
+ - cache/
+ - lib/acts_as_xapian/xapiandbs/
+ - vendor/bundle
+ - public/assets
+ </pre>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+ <dt>
+ <a name="allow_batch_requests"><code>ALLOW_BATCH_REQUESTS</code></a>
+ </dt>
+ <dd>
+ Allow some users to make batch requests to multiple authorities. Once
+ this is set to true, you can enable batch requests for an individual
+ user via the user admin page.
+ <div class="more-info">
+ <p>Example:</p>
+ <ul>
+ <li>
+ <code>ALLOW_BATCH_REQUESTS: false</code>
+ </li>
+ </ul>
+ </div>
+ </dd>
+
+</dl>
+
+<a name="other-config"> </a>
+
+## Other configuration files
+
+Note that there are other configuration files for Alaveteli &mdash; you'll find them all
+in the `config` directory. These are presented in the git repository as `*-example` files
+which you can copy into place.
+
+<dl>
+ <dt>
+ <strong>database.yml</strong>
+ </dt>
+ <dd>
+ database settings (as per Rails)
+ </dd>
+ <dt>
+ <strong>deploy.yml</strong>
+ </dt>
+ <dd>
+ deployment specifications used by Capistrano
+ </dd>
+ <dt>
+ <strong>httpd.conf, nginx.conf</strong>
+ </dt>
+ <dd>
+ Apache and Nginx configuration suggestions
+ </dd>
+ <dt>
+ <strong>newrelic.yml</strong>
+ </dt>
+ <dd>
+ Analytics configuration
+ </dd>
+</dl> \ No newline at end of file
diff --git a/customising/index.md b/customising/index.md
new file mode 100644
index 000000000..db1f5321f
--- /dev/null
+++ b/customising/index.md
@@ -0,0 +1,44 @@
+---
+layout: page
+title: Customising
+---
+
+# Customising Alaveteli
+
+<p class="lead">
+ There are two ways to make your installation look and act the way you want.
+ Some behaviour can be controlled with <strong>configuration settings</strong>.
+ For more complex changes, you'll need to create a new <strong>theme</strong>.
+</p>
+
+
+## Configuration settings
+
+You can customise much of Alaveteli's behaviour just by editing the configuration
+file. This [complete list of Alaveteli's config settings]({{ site.baseurl }}customising/config)
+shows the sort of things you can control in this way.
+
+<!-- TODO key settings -->
+
+## Simple branding: colour and logo
+
+It's common to want to change the basic appearance of the site. Although you
+can simply edit the default templates and CSS to do this, we **strongly
+recommend** that you [create a theme]({{ site.baseurl }}customising/themes).
+
+Themes do not need to be especially complex, but they allow your changes to
+work alongside the core code, which you can then update (when new releases or
+updates become available).
+
+## Need Alaveteli in a different language?
+
+No problem! See the [information about translating Alaveteli]({{ site.baseurl }}customising/translation).
+
+## Complex changes
+
+If you are a developer (or you have a team of programmers available) you can
+add any customisation that you want. But it's important to do this without
+breaking the core code, so that you can accept new releases with updates.
+There's more detail in the [page about themes]({{ site.baseurl }}customising/themes).
+
+See also the [documentation for developers]({{ site.baseurl }}developers).
diff --git a/customising/themes.md b/customising/themes.md
new file mode 100644
index 000000000..f6e504eff
--- /dev/null
+++ b/customising/themes.md
@@ -0,0 +1,188 @@
+---
+layout: page
+title: Themes
+---
+
+# Alaveteli's themes
+
+<p class="lead">
+ Alaveteli uses <strong>themes</strong> to make the site look and run
+ differently from the default.
+ Simple changes like colour and logo are relatively easy, but themes can also
+ control more complex things like <em>how</em> the site behaves.
+</p>
+
+When you customise your Alaveteli site, there is a lot you can change just
+by editing the [config settings]({{ site.baseurl }}customising/config).
+But if you want to change the way the site looks, or add more specific
+behaviour, you'll need to make a **theme**.
+
+You don't need to be a programmer in order to make simple changes, but you will
+need to be confident enough to copy and change some files. If you're not sure
+about this, [ask for help](/community)!
+
+## What you might want to change
+
+The most common requirement is to brand the site: at a minimum,
+inserting your own logo and colour scheme. You may also want to tweak
+the different states that a request can go through. You'll also want
+to edit the categories that public bodies can appear in (i.e. the
+groupings on the left hand side of the
+"[View authorities](http://www.whatdotheyknow.com/body/list/all)" page
+on WhatDoTheyKnow.
+
+There may also be other things you want to customise -- drop a line on
+the developer's mailing list to discuss what you need. We're still working
+out the best way of doing these kinds of customisations!
+
+In any case, the important principle to bear in mind is that the less
+you override and customise the code, the easier your site will be to
+maintain in the long term. Any customisation is possible, but for
+each customisation beyond the simple cases documented here, ask
+yourself (or your client), "can we possibly live without this?" If the
+answer is "no", then consider starting a discussion about a pluggable
+way of achieving your goals, rather than overriding any of the core
+code.
+
+## General principles
+
+We try to encapsulate all site-specific functionality in one of these
+places:
+
+* Site [configuration]({{ site.baseurl }}customisation/config )
+ (e.g., the name of your site, the available
+ languages, and so on &mdash; all in `config/general.yml`)
+* Data (e.g. the public bodies to whom requests should be addressed)
+* A theme, installed in `lib/themes`.
+
+This document is about what you can do in a theme.
+
+By default, the sample theme ("alavetelitheme") has already been
+installed. See the setting
+[`THEME_URLS`]({{ site.baseurl }}customising/config/#theme_urls)
+in `general.yml` for an explanation.
+
+You can also install the sample theme by hand, by running:
+
+ bundle exec rails plugin install git://github.com/mysociety/alavetelitheme.git
+
+The sample theme contains examples for nearly everything you might
+want to customise. You should probably make a copy, rename it, and
+use that as the basis for your own theme.
+
+## Make sure your theme is as lightweight as possible
+
+The more you put in your theme, the harder it will be to upgrade to
+future versions of Alaveteli. Everything you place in your theme
+overrides things in the core theme, so if you make a new "main
+template", then new widgets that appear in the core theme won't appear
+on your website.
+
+Therefore, you should consider how you can brand your website without
+changing much in the core theme. The ideal would be if you are able
+to rebrand the site by only changing the CSS. You will also need to
+add custom help pages, as described below.
+
+## Branding the site
+
+The core templates that comprise the layout and user interface of an
+Alaveteli site live in `app/views/`. They use Rails' ERB syntax.
+For example, the template for the home page lives at
+`app/views/general/frontpage.html.erb`, and the template for the "about
+us" page is at `app/views/help/about.html.erb`.
+
+Obviously, you *could* edit those core files directly, but this would
+be a Bad Idea, because you would find it increasingly hard to do
+upgrades. Having said that, sometimes you may want to change the core
+templates in a way that would benefit everyone, in which case, discuss
+the changes on the mailing list, make them in a fork of Alaveteli, and
+then issue a pull request.
+
+Normally, however, you should override these pages **in your own
+theme**, by placing them at a corresponding location within your
+theme's `lib/` directory. These means that a file at
+`lib/themes/alavetelitheme/lib/help/about.rhml` will appear
+instead of the core "about us" file.
+
+Rails expects all its stylesheets to live at `<railshome>/public`,
+which presents a problem for plugins. Here's how we solve it: the
+stylesheet and associated resources for your theme live (by
+convention) in `alavetelitheme/public/`. This is symlinked from
+the main Rails app -- see `alavetelitheme/install.rb` to see how this
+happens.
+
+The partial at
+`alavetelitheme/lib/views/general/_before_head_end.html.erb` includes the
+custom CSS in your theme's stylesheet folder (by convention, in
+`alavetelitheme/public/stylesheets/`), with:
+
+ <%= stylesheet_link_tag "/alavetelitheme/stylesheets/custom" %>
+
+...which will, usually, need changing for your theme.
+
+## Adding your own categories for public bodies
+
+Categories are implemented in Alaveteli using tags. Specific tags can
+be designated to group authorities together as a category.
+
+There's a file in the sample theme,
+`alavetelitheme/lib/public_body_categories_en.rb`, which contains a
+nested structure that defines categories. It contains a comment
+describing its structure. You should make a copy of this file for each
+locale you support.
+
+## Customising the request states
+
+As mentioned above, if you can possibly live with the
+[default Alaveteli request statuses]({{ site.baseurl }}running/states),
+it would be good to do so. Note that you can set how many days counts
+as "overdue" in the main site config file &mdash;
+see [`REPLY_LATE_AFTER_DAYS`]({{ site.baseurl }}customising/config/#reply_late_after_days).
+
+If you can't live with the states as they are, there's a very basic
+way to add to them (which will get improved over time). There's not
+currently a way to remove any easily. There is an example of how to
+do this in the `alavetelitheme`.
+
+To do add states, create two modules in your theme,
+`InfoRequestCustomStates` and `RequestControllerCustomStates`. The
+former must have these methods:
+
+* `theme_calculate_status`: return a tag to identify the current state of the request
+* `theme_extra_states`: return a list of tags which identify the extra states you'd like to support
+* `theme_display_status`: return human-readable strings corresponding with these tags
+
+The latter must have one method:
+
+* `theme_describe_state`: Return a notice for the user suitable for
+ displaying after they've categorised a request; and redirect them to
+ a suitable next page
+
+When you've added your extra states, you also need to create the following files in your theme:
+
+* `lib/views/general/_custom_state_descriptions.html.erb`: Descriptions
+ of your new states, suitable for displaying to end users
+* `lib/views/general/_custom_state_transitions_complete.html.erb`:
+ Descriptions for any new states that you might characterise as
+ 'completion' states, for displaying on the categorisation form that
+ we ask requestors to fill out
+* `lib/views/general/_custom_state_transitions_pending.html.erb`: As
+ above, but for new states you might characterise as 'pending'
+ states.
+
+You can see examples of these customisations in
+[this commit](https://github.com/sebbacon/informatazyrtare-theme/commit/2b240491237bd72415990399904361ce9bfa431d)
+for the Kosovan version of Alaveteli, Informata Zyrtare (ignore the
+file `lib/views/general/_custom_state_transitions.html.erb`, which is
+unused).
+
+## Adding new pages in the navigation
+
+`alavetelitheme/lib/config/custom-routes.rb` allows you to extend the base routes in
+Alaveteli. The example in `alavetelitheme` adds an extra help page.
+You can also use this to override the behaviour of specific pages if
+necessary.
+
+## Adding or overriding models and controllers
+
+If you need to extend the behaviour of Alaveteli at the controller or model level, see `alavetelitheme/lib/controller_patches.rb` and `alavetelitheme/lib/model_patches.rb` for examples. \ No newline at end of file
diff --git a/customising/translation.md b/customising/translation.md
new file mode 100644
index 000000000..927067f89
--- /dev/null
+++ b/customising/translation.md
@@ -0,0 +1,179 @@
+---
+layout: page
+title: Translation
+---
+
+# Translating Alaveteli
+
+<p class="lead">
+ We've designed Alaveteli to be used in many different
+ jurisdictions all around the world. If it doesn't already
+ support the language you need, you can help by translating
+ it. This page explains how.
+</p>
+
+## Alaveteli's translations
+
+The software translations are implemented using GNU gettext, and the resource
+files are managed in Transifex.
+
+The Transifex project is at
+[https://www.transifex.net/projects/p/alaveteli](https://www.transifex.net/proje
+cts/p/alaveteli) -- you'll probably want an account there (ask on the mailing
+list). It has a fairly easy-to-use interface for contributing translations.
+
+There are three roles in the translation process, and each one is described
+below: **translator**, **developer**, and **release manager**. You probably only
+need to know about the one that applies to you.
+
+## Translation process: translator's view
+
+**If you're just working on translating Alavetli into a language you know, then
+this section is for you.**
+
+When a developer adds a new feature to the user interface in Alaveteli, they
+use some code to mark sentences or words ("strings") that they think will need
+to be translated.
+
+When the Alaveteli release manager is planning a release, they will upload a
+template containing all the strings to be translated (called a POT) to
+Transifex. This causes your own translations in Transifex to be updated with
+the latest strings.
+
+When you visit Transifex, it will prompt you to fill out values for all new
+strings, and all strings that have been modified. In the case where a string
+has only been slightly modified, such as with punctuation ("Hello" has become
+"Hello!"), Transifex will suggest a suitable translation for you (look for the
+"suggestions" tab under the source string).
+
+In order for this feature to work properly, the release manager has to download
+your translations, run a program that inserts the suggestions, and then upload
+them again. Therefore, when a release candidate is announced, make sure you
+have uploaded any outstanding translations, or you will lose them.
+
+When a release candidate has been annouced, there is a **translation freeze**:
+during this period, developers must not add any new strings to the software, so
+you can be confident that you're translating everything that will be in the
+final release.
+
+The release manager will also give you a **translation deadline**. After this
+date, you can continue to contribute new translations, but they won't make it
+into the release.
+
+### General notes on translation in Transifex
+
+Some strings will have comments attached to them from the Alaveteli
+application developers about the context in which the text appears in the
+application — these comments will appear under the 'Details' tab for the text
+in Transifex.
+
+Some strings will have **placeholders** in them to indicate that Alaveteli
+will insert some text of its own into them when they're displayed. They
+will be surrounded by double curly brackets, and look like this:
+
+<code>
+ some text with &#123;&#123;placeholder&#125;&#125; in it
+</code>
+
+For these strings, don't translate the placeholder. It needs to stay exactly
+the same for the text to be inserted properly:
+
+<code>
+ ein Text mit &#123;&#123;placeholder&#125;&#125; in ihm
+</code>
+
+Similarly, some strings may contain small bits of HTML — these will have
+code in angle brackets (it might really be indicating that the text is a link,
+or that it needs special formatting). For example:
+
+<code>
+ please &lt;a href=\"&#123;&#123;url&#125;&#125;\"&gt;send it to us&lt;/a&gt;
+</code>
+
+Again, don't edit the bits between the angle brackets — preserve them in your
+translation, and just edit the text around them. So the example might become:
+
+<code>
+ bitte &lt;a href=\"&#123;&#123;url&#125;&#125;\"&gt;schicken Sie es uns&lt;/a&gt;
+</code>
+
+Some strings are in the form of two pieces of text separated by a vertical
+bar (`|`) character, e.g. `IncomingMessage|Subject`. These represent attribute
+names, so `IncomingMessage|Subject` is the subject attribute of an incoming
+message on the site. Do not prioritise these types of text when translating --
+they do not appear on the site anywhere at the moment, and when they do, they
+will only be used in the admin interface. If you do translate them, only
+translate the text that comes *after* the `|`.
+
+## Translation process: developers' view
+
+**If you're writing new code for Alaveteli, then you're a developer, and you
+need to understand how to make any text you add easy for translators to work
+with.**
+
+Please read our [internationalisation
+guide](http://mysociety.github.io/internationalization.html) for our advice on
+using strings that will need translation. This applies across all mySociety
+projects, not just Alaveteli.
+
+The release manager will enforce a translation freeze just before a new release
+is cut. During such time, you must not introduce new strings to the code if
+your work is due for inclusion in this release. This is necessary to allow
+translators time to complete and check their translations against all the known
+strings.
+
+## Translation process: release manager's view
+
+**If you're responsible for coordinating translators and developers so that all
+the work comes together in a new release, you're the release manager.**
+
+This is the most complicated of the three roles -- the chances are this doesn't
+apply to you, so only read it if you want to understand how the process works.
+
+As the release manager, before you cut a new release branch, you must do the
+following:
+
+### Before the release candidate date:
+
+* Pick a date for the release branch to be cut ("release candidate date").
+* Make an announcement to the translators (using the "announcements"
+ feature in Transifex) that they should ensure they have any pending
+ translations saved in Transifex before the release candidate date.
+* Make an announcement to the developers that all new strings should
+ be committed before the release candidate date.
+
+### On the release candidate date:
+
+* Download all the current translations with `tx pull -a -f` and commit (important: there's no revision history in Transifex!).
+* You should also commit these translations to a hotfix for the
+ previous version, so they are preserved against the last known
+ good msgids.
+* Regenerate the POT file and individual PO files for each language,
+ using `bundle exec rake gettext:store_model_attributes`, followed by
+ `bundle exec rake gettext:find`
+ * Be careful not to include msgids from themes in `lib/themes`;
+ you might want to move them out of the way before running
+ the above commands.
+ * This updates the PO template, but also merges it with the
+ individual PO files, marking strings that have only changed
+ slightly as "fuzzy".
+* Re-upload the POT and PO files to Transifex from the
+ current release branch with `tx push -s -t`
+ * The point of uploading the PO files is that Transifex
+ converts the "fuzzy" suggestions from Transifex into
+ "suggestions" under each source string.
+ * Note that Transifex *does not* preserve fuzzy strings in the
+ PO files it makes available for download, on the grounds
+ that Transifex supports multiple suggestions, whereas
+ gettext only allows one fuzzy suggestion per msgid.
+* Remove the fuzzy strings from the local PO files (because they
+ make Rails very noisy), and then commit the result. You can do
+ this by re-pulling from Transifex.
+
+### On the release date:
+
+* Download and commit all the current translations to the current release branch.
+
+
+
+