docs: Add comma to all uses of "e.g." in contributor docs.

This commit is contained in:
Lauryn Menard 2024-07-04 12:33:43 +02:00 committed by Tim Abbott
parent 2bb037f2a0
commit 62d452f983
72 changed files with 255 additions and 255 deletions

View File

@ -213,13 +213,13 @@ down the line!
- Open up the parts of the UI that were changed, and make sure they look as - Open up the parts of the UI that were changed, and make sure they look as
you were expecting. you were expecting.
- Is the new UI consistent with similar UI elements? Think about fonts, colors, - Is the new UI consistent with similar UI elements? Think about fonts, colors,
sizes, etc. If a new or modified element has multiple states (e.g. "on" and sizes, etc. If a new or modified element has multiple states (e.g., "on" and
"off"), consider all of them. "off"), consider all of them.
- Is the new UI aligned correctly with the elements around it, both vertically and - Is the new UI aligned correctly with the elements around it, both vertically and
horizontally? horizontally?
- If the PR adds or modifies a clickable element, does it have a hover behavior - If the PR adds or modifies a clickable element, does it have a hover behavior
that's consistent with similar UI elements? that's consistent with similar UI elements?
- If the PR adds or modifies an element (e.g. a button or checkbox) that is - If the PR adds or modifies an element (e.g., a button or checkbox) that is
sometimes disabled, is the disabled version of the UI consistent with similar sometimes disabled, is the disabled version of the UI consistent with similar
UI elements? UI elements?
- Did the PR accidentally affect any other parts of the UI? E.g., if the PR - Did the PR accidentally affect any other parts of the UI? E.g., if the PR

View File

@ -171,7 +171,7 @@ This is a **complete sentence** that briefly summarizes your changes. There are
a few rules to keep in mind: a few rules to keep in mind:
- Start the sentence with an - Start the sentence with an
[imperative](https://en.wikipedia.org/wiki/Imperative_mood) verb, e.g. [imperative](https://en.wikipedia.org/wiki/Imperative_mood) verb, e.g.,
"fix", "add", "change", "rename", etc. "fix", "add", "change", "rename", etc.
- Use proper capitalization and punctuation. - Use proper capitalization and punctuation.
- Avoid abbreviations and acronyms. - Avoid abbreviations and acronyms.

View File

@ -60,7 +60,7 @@ better decisions as a group, and learn and have fun along the way.
where they are coming from. where they are coming from.
- If you think someone is factually mistaken, consider how they might have reached - If you think someone is factually mistaken, consider how they might have reached
their conclusion, and aim to get to a shared understanding. E.g.: their conclusion, and aim to get to a shared understanding. E.g.,:
- “I wasn't able to replicate this -- is it possible you are on an old Zulip - “I wasn't able to replicate this -- is it possible you are on an old Zulip
server?”, rather than “This bug report is wrong.” server?”, rather than “This bug report is wrong.”
@ -86,7 +86,7 @@ question in the development community, or suggesting a new feature. It's
especially important to thank and encourage folks who are stretching themselves especially important to thank and encourage folks who are stretching themselves
to try something new. to try something new.
- Remember to say “thanks” when responding to a question or suggestion. E.g.: - Remember to say “thanks” when responding to a question or suggestion. E.g.,:
- “Thanks for the report! ... ” when someone reports a bug. - “Thanks for the report! ... ” when someone reports a bug.
- “Thanks for reviewing my PR! ... ” - “Thanks for reviewing my PR! ... ”
@ -101,7 +101,7 @@ to try something new.
- You can use a variety of channels to express your appreciation. A comment - You can use a variety of channels to express your appreciation. A comment
directly in a Zulip thread or on a pull request is often best, but in some directly in a Zulip thread or on a pull request is often best, but in some
cases you may also want to send a friendly direct message. E.g.: cases you may also want to send a friendly direct message. E.g.,:
- “I've noticed that you've been answering lots of questions in #**development - “I've noticed that you've been answering lots of questions in #**development
help** lately. Thanks so much for doing that!” help** lately. Thanks so much for doing that!”

View File

@ -171,7 +171,7 @@ actual flows for LDAP configuration.
- To disable fakeldap, set `FAKE_LDAP_MODE` back to `None`. - To disable fakeldap, set `FAKE_LDAP_MODE` back to `None`.
- In all fakeldap configurations, users' fake LDAP passwords are equal - In all fakeldap configurations, users' fake LDAP passwords are equal
to their usernames (e.g. for `ldapuser1@zulip.com`, the password is to their usernames (e.g., for `ldapuser1@zulip.com`, the password is
`ldapuser1`). `ldapuser1`).
- `FAKE_LDAP_NUM_USERS` in `zproject/dev_settings.py` can be used to - `FAKE_LDAP_NUM_USERS` in `zproject/dev_settings.py` can be used to

View File

@ -151,7 +151,7 @@ guide][rtd-git-guide]. In brief, the steps are as follows.
On your **local computer**: On your **local computer**:
1. Open _Terminal_ (macOS/Linux) or _Git for BASH_. 1. Open _Terminal_ (macOS/Linux) or _Git for BASH_.
2. Change directory to where you cloned Zulip (e.g. `cd zulip`). 2. Change directory to where you cloned Zulip (e.g., `cd zulip`).
3. Use `git add` and `git commit` to stage and commit your changes (if you 3. Use `git add` and `git commit` to stage and commit your changes (if you
haven't already). haven't already).
4. Push your commits to GitHub with `git push origin branchname`. 4. Push your commits to GitHub with `git push origin branchname`.
@ -282,7 +282,7 @@ Next, read the following to learn more about developing for Zulip:
## Using an nginx reverse proxy ## Using an nginx reverse proxy
For some applications (e.g. developing an OAuth2 integration for For some applications (e.g., developing an OAuth2 integration for
Facebook), you may need your Zulip development to have a valid SSL Facebook), you may need your Zulip development to have a valid SSL
certificate. While `run-dev` doesn't support that, you can do this certificate. While `run-dev` doesn't support that, you can do this
with an `nginx` reverse proxy sitting in front of `run-dev`. with an `nginx` reverse proxy sitting in front of `run-dev`.

View File

@ -132,7 +132,7 @@ installation method described here. We require version 0.67.6+ of WSL 2.
$ sudo apt install rabbitmq-server memcached redis-server postgresql $ sudo apt install rabbitmq-server memcached redis-server postgresql
``` ```
1. Open `/etc/rabbitmq/rabbitmq-env.conf` using e.g.: 1. Open `/etc/rabbitmq/rabbitmq-env.conf` using e.g.,:
```console ```console
$ sudo nano /etc/rabbitmq/rabbitmq-env.conf $ sudo nano /etc/rabbitmq/rabbitmq-env.conf
@ -955,7 +955,7 @@ The `vagrant up` command basically does the following:
To debug such errors, you can log in to the Vagrant guest machine by To debug such errors, you can log in to the Vagrant guest machine by
running `vagrant ssh`, which should present you with a standard shell running `vagrant ssh`, which should present you with a standard shell
prompt. You can debug interactively by using e.g. prompt. You can debug interactively by using e.g.,
`cd zulip && ./tools/provision`, and then running the individual `cd zulip && ./tools/provision`, and then running the individual
subcommands that failed. Once you've resolved the problem, you can subcommands that failed. Once you've resolved the problem, you can
rerun `tools/provision` to proceed; the provisioning system is rerun `tools/provision` to proceed; the provisioning system is
@ -1094,7 +1094,7 @@ NO_PROXY localhost,127.0.0.1,.example.com,.zulipdev.com
``` ```
For proxies that require authentication, the config will be a bit more For proxies that require authentication, the config will be a bit more
complex, e.g.: complex, e.g.,:
```text ```text
HTTP_PROXY http://userName:userPassword@192.168.1.1:8080 HTTP_PROXY http://userName:userPassword@192.168.1.1:8080
@ -1119,7 +1119,7 @@ then do a `vagrant reload`.
### Using a different port for Vagrant ### Using a different port for Vagrant
You can also change the port on the host machine that Vagrant uses by You can also change the port on the host machine that Vagrant uses by
adding to your `~/.zulip-vagrant-config` file. E.g. if you set: adding to your `~/.zulip-vagrant-config` file. E.g., if you set:
```text ```text
HOST_PORT 9971 HOST_PORT 9971

View File

@ -1,12 +1,12 @@
If you ever want to recreate your development environment again from If you ever want to recreate your development environment again from
scratch (e.g. to test a change you've made to the provisioning scratch (e.g., to test a change you've made to the provisioning
process, or because you think something is broken), you can do so process, or because you think something is broken), you can do so
using `vagrant destroy` and then `vagrant up`. This will usually be using `vagrant destroy` and then `vagrant up`. This will usually be
much faster than the original `vagrant up` since the base image is much faster than the original `vagrant up` since the base image is
already cached on your machine (it takes about 5 minutes to run with a already cached on your machine (it takes about 5 minutes to run with a
fast Internet connection). fast Internet connection).
Any additional programs (e.g. Zsh, emacs, etc.) or configuration that Any additional programs (e.g., Zsh, emacs, etc.) or configuration that
you may have installed in the development environment will be lost you may have installed in the development environment will be lost
when you recreate it. To address this, you can create a script called when you recreate it. To address this, you can create a script called
`tools/custom_provision` in your Zulip Git checkout; and place any `tools/custom_provision` in your Zulip Git checkout; and place any

View File

@ -62,7 +62,7 @@ branch, or a significant time has passed since you last used it.
### Test an install ### Test an install
The `test-install` tooling takes a distribution release name The `test-install` tooling takes a distribution release name
(e.g. "jammy"), the path to an unpacked release directory (e.g., "jammy"), the path to an unpacked release directory
or tarball, and then any of the normal options you want to pass down or tarball, and then any of the normal options you want to pass down
into the installer. into the installer.

View File

@ -13,7 +13,7 @@ the development environment][authentication-dev-server].
## Common ## Common
- Zulip's `main` branch moves quickly, and you should rebase - Zulip's `main` branch moves quickly, and you should rebase
constantly with e.g. constantly with e.g.,
`git fetch upstream; git rebase upstream/main` to avoid developing `git fetch upstream; git rebase upstream/main` to avoid developing
on an old version of the Zulip codebase (leading to unnecessary on an old version of the Zulip codebase (leading to unnecessary
merge conflicts). merge conflicts).

View File

@ -354,7 +354,7 @@ it? There's several major benefits to this system:
pre-substituted for the user. pre-substituted for the user.
- We're able to share implementation language and visual styling with - We're able to share implementation language and visual styling with
our Help Center, which is especially useful for the extensive our Help Center, which is especially useful for the extensive
non-REST API documentation pages (e.g. our bot framework). non-REST API documentation pages (e.g., our bot framework).
Using the standard OpenAPI format gives us flexibility, though; if we Using the standard OpenAPI format gives us flexibility, though; if we
later choose to migrate to third-party tools, we don't need to redo later choose to migrate to third-party tools, we don't need to redo
@ -393,7 +393,7 @@ documentation for the REST API endpoint for uploading a file,
There are no parameters for this endpoint, and only one return value There are no parameters for this endpoint, and only one return value
specific to this endpoint, `uri`, which is the URL of the uploaded file. specific to this endpoint, `uri`, which is the URL of the uploaded file.
If we comment out that return value and example from the existing API If we comment out that return value and example from the existing API
documentation in `zerver/openapi/zulip.yaml`, e.g.: documentation in `zerver/openapi/zulip.yaml`, e.g.,:
```yaml ```yaml
/user_uploads: /user_uploads:

View File

@ -19,7 +19,7 @@ and a handful of longer guides. The feature articles serve a few different purpo
organization settings. organization settings.
Zulip help center documentation is available under `/help/` on any Zulip server; Zulip help center documentation is available under `/help/` on any Zulip server;
(e.g. <https://zulip.com/help/> or `http://localhost:9991/help/` in (e.g., <https://zulip.com/help/> or `http://localhost:9991/help/` in
the Zulip development environment). The help center documentation is not hosted the Zulip development environment). The help center documentation is not hosted
on ReadTheDocs, since Zulip supports running a server completely disconnected on ReadTheDocs, since Zulip supports running a server completely disconnected
from the Internet, and we'd like the documentation to be available in that from the Internet, and we'd like the documentation to be available in that
@ -55,7 +55,7 @@ There are over 100 feature articles and longer guides in the
the current documentation as a resource and guide as you begin. the current documentation as a resource and guide as you begin.
- Use the list on [Zulip help center home](https://zulip.com/help/) - Use the list on [Zulip help center home](https://zulip.com/help/)
to find the section of the docs (e.g. Preferences, Sending to find the section of the docs (e.g., Preferences, Sending
messages, Reading messages, etc.) that relates to the new feature messages, Reading messages, etc.) that relates to the new feature
you're documenting. you're documenting.
@ -144,7 +144,7 @@ updating existing documentation:
An anti-pattern is trying to make up for bad UX by adding help center An anti-pattern is trying to make up for bad UX by adding help center
documentation. It's worth remembering that for most articles, almost 100% of documentation. It's worth remembering that for most articles, almost 100% of
the users of the feature will never read the article. Instructions for the users of the feature will never read the article. Instructions for
filling out forms, interacting with UI widgets (e.g. typeaheads), interacting filling out forms, interacting with UI widgets (e.g., typeaheads), interacting
with modals, etc. should never go in the help center documentation. with modals, etc. should never go in the help center documentation.
In such cases, you may be able to fix the problem by adding text in-app, In such cases, you may be able to fix the problem by adding text in-app,
where the user will see it as they are interacting with the feature. where the user will see it as they are interacting with the feature.
@ -208,7 +208,7 @@ as guidance when documenting Zulip's features.
### User interface ### User interface
When you refer to the features in the Zulip UI, you should **bold** the When you refer to the features in the Zulip UI, you should **bold** the
feature's name followed by the feature itself (e.g. **Settings** page, feature's name followed by the feature itself (e.g., **Settings** page,
**Change password** button, **Email** field). No quotation marks should be **Change password** button, **Email** field). No quotation marks should be
used. Use **bold** for channel names, and quotation marks for topic names. used. Use **bold** for channel names, and quotation marks for topic names.
@ -242,7 +242,7 @@ an arrow key (↑, ↓, ←, →) will also need the `"arrow-key"` CSS class inc
in the `<kbd>` start tag (e.g., ` <kbd class="arrow-key">↑</kbd>`). in the `<kbd>` start tag (e.g., ` <kbd class="arrow-key">↑</kbd>`).
Use the labels one sees on the actual keyboard rather than the letter they Use the labels one sees on the actual keyboard rather than the letter they
produce when pressed (e.g. `R` and `Shift` + `R` rather than `r` and `R`). produce when pressed (e.g., `R` and `Shift` + `R` rather than `r` and `R`).
For symbols, such as `?` or `@`, that are produced through key combinations that For symbols, such as `?` or `@`, that are produced through key combinations that
change depending on the user's keyboard layout, you should use the symbol as it change depending on the user's keyboard layout, you should use the symbol as it
appears on a keyboard instead of any specific combination of keys. appears on a keyboard instead of any specific combination of keys.
@ -290,7 +290,7 @@ your documentation to help improve its readability:
### Images ### Images
Images and screenshots should be included in help center documentation Images and screenshots should be included in help center documentation
only if they will help guide the user in how to do something (e.g. if only if they will help guide the user in how to do something (e.g., if
the image will make it much clearer which element on the page the user the image will make it much clearer which element on the page the user
should interact with). For instance, an image of an element should should interact with). For instance, an image of an element should
not be included if the element the user needs to interact with is the not be included if the element the user needs to interact with is the
@ -435,7 +435,7 @@ languages in API docs, etc. To create a tab switcher, write:
{end_tabs} {end_tabs}
``` ```
The tab identifiers (e.g. `desktop-web` above) and their mappings to The tab identifiers (e.g., `desktop-web` above) and their mappings to
the tabs' labels are declared in the tabs' labels are declared in
[zerver/lib/markdown/tabbed_sections.py][tabbed-sections-code]. [zerver/lib/markdown/tabbed_sections.py][tabbed-sections-code].

View File

@ -46,7 +46,7 @@ for every pull request, accessible from a "Details" link in the
to submit a screenshot with any pull request modifying documentation to submit a screenshot with any pull request modifying documentation
to help make reviews efficient. to help make reviews efficient.
If you want to build the developer documentation locally (e.g. to test If you want to build the developer documentation locally (e.g., to test
your changes), the dependencies are automatically installed as part of your changes), the dependencies are automatically installed as part of
Zulip development environment provisioning, and you can build the Zulip development environment provisioning, and you can build the
documentation using: documentation using:
@ -58,7 +58,7 @@ documentation using:
and then opening `http://127.0.0.1:9991/docs/index.html` in your and then opening `http://127.0.0.1:9991/docs/index.html` in your
browser. The raw files are available at browser. The raw files are available at
`file:///path/to/zulip/docs/_build/html/index.html` in your browser `file:///path/to/zulip/docs/_build/html/index.html` in your browser
(so you can also use e.g. `firefox docs/_build/html/index.html` from (so you can also use e.g., `firefox docs/_build/html/index.html` from
the root of your Zulip checkout). the root of your Zulip checkout).
If you are adding a new page to the table of contents, you will want If you are adding a new page to the table of contents, you will want

View File

@ -19,7 +19,7 @@ In the Zulip project, we encourage submitting [draft pull
requests][github-help-draft-pr] early and often. This allows you to requests][github-help-draft-pr] early and often. This allows you to
share your code to make it easier to get feedback and help with your share your code to make it easier to get feedback and help with your
changes, even if you don't think your pull request is ready to be changes, even if you don't think your pull request is ready to be
merged (e.g. it might not work or pass tests). This sets expectations merged (e.g., it might not work or pass tests). This sets expectations
correctly for any feedback from other developers, and prevents your correctly for any feedback from other developers, and prevents your
work from being merged before you're confident in it. work from being merged before you're confident in it.

View File

@ -410,7 +410,7 @@ To git@github.com:christi3k/zulip.git
! [rejected] 1754-docs-add-git-workflow -> 1754-docs-add-git-workflow (non-fast-forward) ! [rejected] 1754-docs-add-git-workflow -> 1754-docs-add-git-workflow (non-fast-forward)
error: failed to push some refs to 'git@github.com:christi3k/zulip.git' error: failed to push some refs to 'git@github.com:christi3k/zulip.git'
hint: Updates were rejected because the tip of your current branch is behind hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g. hint: its remote counterpart. Integrate the remote changes (e.g.,
hint: 'git pull ...') before pushing again. hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
``` ```

View File

@ -120,7 +120,7 @@ HEAD is now at 5a1e982 tools: Update clean-branches to clean review branches.
`tools/push-to-pull-request` is primarily useful for maintainers who `tools/push-to-pull-request` is primarily useful for maintainers who
are merging other users' commits into a Zulip repository. After doing are merging other users' commits into a Zulip repository. After doing
`reset-to-pull-request` or `fetch-pull-request` and making some `reset-to-pull-request` or `fetch-pull-request` and making some
changes, you can push a branch back to a pull request with e.g. changes, you can push a branch back to a pull request with e.g.,
`tools/push-to-pull-request 1234`. This is useful for a few things: `tools/push-to-pull-request 1234`. This is useful for a few things:
- Getting CI to run and enabling you to use the GitHub "Merge" buttons - Getting CI to run and enabling you to use the GitHub "Merge" buttons

View File

@ -1,6 +1,6 @@
# How to have an amazing experience # How to have an amazing experience
If you are joining Zulip as part of an outreach program (e.g. If you are joining Zulip as part of an outreach program (e.g.,
[GSoC](https://summerofcode.withgoogle.com/) or [GSoC](https://summerofcode.withgoogle.com/) or
[Outreachy](https://www.outreachy.org/)), welcome! Please make sure you read [Outreachy](https://www.outreachy.org/)), welcome! Please make sure you read
this page carefully early on, and we encourage you to come back to it over the this page carefully early on, and we encourage you to come back to it over the
@ -125,7 +125,7 @@ You can find many examples in the
working on, not just issue/PR numbers. working on, not just issue/PR numbers.
- For projects where you are waiting on feedback, what **type of feedback** is - For projects where you are waiting on feedback, what **type of feedback** is
needed (e.g. product review, next round of code review after initial needed (e.g., product review, next round of code review after initial
feedback has been addressed, answer to some question, etc.). Use [silent feedback has been addressed, answer to some question, etc.). Use [silent
mentions](https://zulip.com/help/mention-a-user-or-group#silently-mention-a-user) mentions](https://zulip.com/help/mention-a-user-or-group#silently-mention-a-user)
to indicate whose feedback is required, if you think you know who it should to indicate whose feedback is required, if you think you know who it should
@ -183,7 +183,7 @@ time, start by quickly sharing your initial thoughts or feedback on the general
direction, and let the PR author know when you expect to provide a more detailed direction, and let the PR author know when you expect to provide a more detailed
review. review.
Make sure the GitHub comments on the PR are always clear on the status -- e.g. Make sure the GitHub comments on the PR are always clear on the status -- e.g.,
buddy code review has been requested, feedback is being discussed, code buddy buddy code review has been requested, feedback is being discussed, code buddy
has approved the PR, etc. This will help project maintainers know when it's time has approved the PR, etc. This will help project maintainers know when it's time
to move on to the next step of the review process. to move on to the next step of the review process.

View File

@ -90,7 +90,7 @@ requests to those services, but the Django-based database libraries we
use in most of our codebase don't support that, and in any case, use in most of our codebase don't support that, and in any case,
our architecture doesn't require Tornado to do that). our architecture doesn't require Tornado to do that).
The parts that are activated relatively rarely (e.g. when people type or The parts that are activated relatively rarely (e.g., when people type or
click on something) are processed by the Django application server. click on something) are processed by the Django application server.
There is detailed documentation on the There is detailed documentation on the
@ -209,7 +209,7 @@ RabbitMQ is a queueing system. Its config files live in
`zulip/puppet/zulip/files/rabbitmq`. Initial configuration happens in `zulip/puppet/zulip/files/rabbitmq`. Initial configuration happens in
`zulip/scripts/setup/configure-rabbitmq`. `zulip/scripts/setup/configure-rabbitmq`.
We use RabbitMQ for queuing expensive work (e.g. sending emails We use RabbitMQ for queuing expensive work (e.g., sending emails
triggered by a message, push notifications, some analytics, etc.) that triggered by a message, push notifications, some analytics, etc.) that
require reliable delivery but which we don't want to do on the main require reliable delivery but which we don't want to do on the main
thread. It's also used for communication between the application server thread. It's also used for communication between the application server
@ -256,7 +256,7 @@ administrator, e.g., in case of outages.
This component is intended to install Nagios plugins intended to be run This component is intended to install Nagios plugins intended to be run
on a Nagios server; most of the Zulip Nagios plugins are intended to be on a Nagios server; most of the Zulip Nagios plugins are intended to be
run on the Zulip servers themselves, and are included with the relevant run on the Zulip servers themselves, and are included with the relevant
component of the Zulip server (e.g. component of the Zulip server (e.g.,
`puppet/zulip/manifests/postgresql_backups.pp` installs a few under `puppet/zulip/manifests/postgresql_backups.pp` installs a few under
`/usr/lib/nagios/plugins/zulip_backups`). `/usr/lib/nagios/plugins/zulip_backups`).

View File

@ -198,7 +198,7 @@ _Released 2024-03-19_
- Fixed the “Topics are required for this organization” pop-up incorrectly - Fixed the “Topics are required for this organization” pop-up incorrectly
closing on some keypresses. closing on some keypresses.
- Fixed the analytics cron job leaking its lock if unexpectedly interrupted - Fixed the analytics cron job leaking its lock if unexpectedly interrupted
(e.g. by a reboot). (e.g., by a reboot).
- Fixed sorting by expiration date in the “Invites” settings panel. - Fixed sorting by expiration date in the “Invites” settings panel.
- Fixed the gear menu staying open after clicking on “plan management”. - Fixed the gear menu staying open after clicking on “plan management”.
- Fixed a small visual issue with bot icons in the left sidebar DM section. - Fixed a small visual issue with bot icons in the left sidebar DM section.
@ -1697,7 +1697,7 @@ _Released 2021-07-22_
- Fixed a performance/scalability issue for installations using the S3 - Fixed a performance/scalability issue for installations using the S3
file uploads backend. file uploads backend.
- Fixed a bug where users could turn other users messages they could - Fixed a bug where users could turn other users messages they could
read into widgets (e.g. polls). read into widgets (e.g., polls).
- Fixed a bug where emoji and avatar image requests were sent through - Fixed a bug where emoji and avatar image requests were sent through
Camo; doing so does not add any security benefit, and broke custom Camo; doing so does not add any security benefit, and broke custom
emoji that had been imported from Slack in Zulip 1.8.1 or earlier. emoji that had been imported from Slack in Zulip 1.8.1 or earlier.
@ -1813,7 +1813,7 @@ _Released 2021-05-13_
`zulip::foo` to `zulip::profile::foo`. Configuration referencing `zulip::foo` to `zulip::profile::foo`. Configuration referencing
these `/etc/zulip/zulip.conf` will be automatically updated during these `/etc/zulip/zulip.conf` will be automatically updated during
the upgrade process, but if you have a complex deployment or you the upgrade process, but if you have a complex deployment or you
maintain `zulip.conf` is another system (E.g. with the [manual maintain `zulip.conf` is another system (e.g., with the [manual
configuration][docker-zulip-manual] option for configuration][docker-zulip-manual] option for
[docker-zulip][docker-zulip]), you'll want to manually update the [docker-zulip][docker-zulip]), you'll want to manually update the
`puppet_classes` variable. `puppet_classes` variable.
@ -1895,7 +1895,7 @@ _Released 2021-05-13_
unsubscribe links. unsubscribe links.
- Password forms now have a "Show password" widget. - Password forms now have a "Show password" widget.
- Fixed performance issues when creating hundreds of new users in - Fixed performance issues when creating hundreds of new users in
quick succession (E.g. at the start of a conference or event). quick succession (e.g., at the start of a conference or event).
- Fixed performance issues in organizations with thousands of online users. - Fixed performance issues in organizations with thousands of online users.
- Fixed numerous rare exceptions when running Zulip at scale. - Fixed numerous rare exceptions when running Zulip at scale.
- Fixed several subtle installer bugs. - Fixed several subtle installer bugs.
@ -3439,7 +3439,7 @@ _Released 2017-10-25_
- Switched from npm to yarn for downloading JS packages. - Switched from npm to yarn for downloading JS packages.
- Switched the function of the 'q' and 'w' search hotkeys. - Switched the function of the 'q' and 'w' search hotkeys.
- Simplified the settings for configuring senders for our emails. - Simplified the settings for configuring senders for our emails.
- Emoji can now be typed with spaces, e.g. entering "robot face" in - Emoji can now be typed with spaces, e.g., entering "robot face" in
the typeahead as well as "robot_face". the typeahead as well as "robot_face".
- Improved title and alt text for Unicode emoji. - Improved title and alt text for Unicode emoji.
- Added development tools to make iterating on emails and error pages easy. - Added development tools to make iterating on emails and error pages easy.
@ -3657,7 +3657,7 @@ _Released 2017-02-06_
notifications. notifications.
- Added buttons to download .zuliprc files. - Added buttons to download .zuliprc files.
- Added italics and strikethrough support in Markdown implementation. - Added italics and strikethrough support in Markdown implementation.
- Added errors for common installations mistakes (e.g. too little RAM). - Added errors for common installations mistakes (e.g., too little RAM).
- Added a new /authors page showing the contributors to the current - Added a new /authors page showing the contributors to the current
Zulip version. Zulip version.
- Added illustrations to the 404 and 500 pages. - Added illustrations to the 404 and 500 pages.
@ -3678,7 +3678,7 @@ _Released 2017-02-06_
- Fixed Zulip Tornado service not working with http_proxy set in environment. - Fixed Zulip Tornado service not working with http_proxy set in environment.
- Fixed text overflow in stream subscriptions. - Fixed text overflow in stream subscriptions.
- Fixed CSS issues with message topic editing. - Fixed CSS issues with message topic editing.
- Fixed several transactionality bugs (e.g. in Huddle creation). - Fixed several transactionality bugs (e.g., in Huddle creation).
- Fixed missed-message email configuration error handling. - Fixed missed-message email configuration error handling.
- Fixed annoying @-mentions in Jira integration. - Fixed annoying @-mentions in Jira integration.
- Fixed various mismatches between frontend and backend Markdown - Fixed various mismatches between frontend and backend Markdown
@ -3892,7 +3892,7 @@ _Released 2016-05-02_
- Added options for configuring PostgreSQL, RabbitMQ, Redis, and memcached - Added options for configuring PostgreSQL, RabbitMQ, Redis, and memcached
in settings.py. in settings.py.
- Added documentation on using Hubot to integrate with useful services - Added documentation on using Hubot to integrate with useful services
not yet integrated with Zulip directly (e.g. Google Hangouts). not yet integrated with Zulip directly (e.g., Google Hangouts).
- Added new management command to test sending email from Zulip. - Added new management command to test sending email from Zulip.
- Added Codeship, Pingdom, Taiga, TeamCity, and Yo integrations. - Added Codeship, Pingdom, Taiga, TeamCity, and Yo integrations.
- Added Nagios plugins to the main distribution. - Added Nagios plugins to the main distribution.

View File

@ -92,7 +92,7 @@ Django context (i.e. with database access).
- `zerver/management/commands/` - `zerver/management/commands/`
[Management commands](../subsystems/management-commands.md) one might run at a [Management commands](../subsystems/management-commands.md) one might run at a
production deployment site (e.g. scripts to change a value or production deployment site (e.g., scripts to change a value or
deactivate a user properly). deactivate a user properly).
- `zilencer/management/commands/` includes some dev-specific - `zilencer/management/commands/` includes some dev-specific
@ -115,7 +115,7 @@ Django context (i.e. with database access).
- `tools/` Scripts used only in a Zulip development environment. - `tools/` Scripts used only in a Zulip development environment.
These are not included in production release tarballs for Zulip, so These are not included in production release tarballs for Zulip, so
that we can include scripts here one wouldn't want someone to run in that we can include scripts here one wouldn't want someone to run in
production accidentally (e.g. things that delete the Zulip database production accidentally (e.g., things that delete the Zulip database
without prompting). without prompting).
- `tools/setup/` Subdirectory of `tools/` for things only used during - `tools/setup/` Subdirectory of `tools/` for things only used during

View File

@ -32,7 +32,7 @@ server repository][zulip-server].
Organizations self-hosting Zulip primarily use stable releases. Organizations self-hosting Zulip primarily use stable releases.
- The numbering scheme is simple: the first digit indicates the major - The numbering scheme is simple: the first digit indicates the major
release series (which we'll refer to as "7.x"). (Before Zulip 3.0, release series (which we'll refer to as "7.x"). (Before Zulip 3.0,
Zulip versions had another digit, e.g. 1.9.2 was a bug fix release Zulip versions had another digit, e.g., 1.9.2 was a bug fix release
in the Zulip 1.9.x major release series). in the Zulip 1.9.x major release series).
- [New major releases][blog-major-releases], like Zulip 7.0, are - [New major releases][blog-major-releases], like Zulip 7.0, are
published every 3-6 months, and contain hundreds of features, bug published every 3-6 months, and contain hundreds of features, bug
@ -121,7 +121,7 @@ bug fix release, transparently documenting the issue(s) using the
industry-standard [CVE advisory process](https://cve.mitre.org/). industry-standard [CVE advisory process](https://cve.mitre.org/).
When new security releases are published, we simultaneously publish When new security releases are published, we simultaneously publish
the fixes to the `main` and stable release branches (E.g. `4.x`), so the fixes to the `main` and stable release branches (e.g., `4.x`), so
that anyone using those branches can immediately upgrade as well. that anyone using those branches can immediately upgrade as well.
See also our [security model][security-model] documentation. See also our [security model][security-model] documentation.
@ -143,7 +143,7 @@ The nag will appear only to organization administrators starting a
month before the deadline; after that, it will appear for all users on month before the deadline; after that, it will appear for all users on
the server. the server.
You can adjust the deadline for your installation by setting e.g. You can adjust the deadline for your installation by setting e.g.,
`SERVER_UPGRADE_NAG_DEADLINE_DAYS = 30 * 21` in `SERVER_UPGRADE_NAG_DEADLINE_DAYS = 30 * 21` in
`/etc/zulip/settings.py` and then [restarting the server](../production/settings.md). `/etc/zulip/settings.py` and then [restarting the server](../production/settings.md).

View File

@ -367,7 +367,7 @@ Other fields you may want to sync from LDAP include:
group last, if you'd like a user who is in both groups to be a realm group last, if you'd like a user who is in both groups to be a realm
owner rather than a guest). owner rather than a guest).
- String fields like `default_language` (e.g. `en`) or `timezone`, if - String fields like `default_language` (e.g., `en`) or `timezone`, if
you have that data in the right format in your LDAP database. you have that data in the right format in your LDAP database.
You can look at the [full list of fields][models-py] in the Zulip user You can look at the [full list of fields][models-py] in the Zulip user
@ -544,7 +544,7 @@ it as follows:
metadata and enter them on the right-hand side of this metadata and enter them on the right-hand side of this
Python dictionary: Python dictionary:
1. Set the outer `idp_name` key to be an identifier for your IdP, 1. Set the outer `idp_name` key to be an identifier for your IdP,
e.g. `testshib` or `okta`. This field appears in URLs for e.g., `testshib` or `okta`. This field appears in URLs for
parts of your Zulip server's SAML authentication flow. parts of your Zulip server's SAML authentication flow.
2. The IdP should provide the `url` and `entity_id` values. 2. The IdP should provide the `url` and `entity_id` values.
3. Save the `x509cert` value to a file; you'll use it in the 3. Save the `x509cert` value to a file; you'll use it in the
@ -1165,7 +1165,7 @@ If you need to use this feature in combination with those backends,
you should make your logic be applied when processing the you should make your logic be applied when processing the
`ZulipDummyBackend` - which is the final layer of the authentication `ZulipDummyBackend` - which is the final layer of the authentication
checks for whether authentication should succeed. If you want to checks for whether authentication should succeed. If you want to
reject authentication requests e.g. based on IP address of the reject authentication requests e.g., based on IP address of the
request, this is where it should happen. request, this is where it should happen.
::: :::

View File

@ -206,7 +206,7 @@ the following after unpacking a Zulip production release tarball:
``` ```
To run the database on a separate server, including a cloud provider's managed To run the database on a separate server, including a cloud provider's managed
PostgreSQL instance (e.g. AWS RDS), or with a warm-standby replica for PostgreSQL instance (e.g., AWS RDS), or with a warm-standby replica for
reliability, see our [dedicated PostgreSQL documentation][postgresql]. reliability, see our [dedicated PostgreSQL documentation][postgresql].
[standalone.pp]: https://github.com/zulip/zulip/blob/main/puppet/zulip/manifests/profile/standalone.pp [standalone.pp]: https://github.com/zulip/zulip/blob/main/puppet/zulip/manifests/profile/standalone.pp

View File

@ -80,7 +80,7 @@ with [`EMAIL_USE_SSL = True`](https://docs.djangoproject.com/en/5.0/ref/settings
### Using system email ### Using system email
If you'd like to send outgoing email using the local operating If you'd like to send outgoing email using the local operating
system's email delivery configuration (e.g. you have `postfix` system's email delivery configuration (e.g., you have `postfix`
configuration on the system that forwards email sent locally into your configuration on the system that forwards email sent locally into your
corporate email system), you will likely need to use something like corporate email system), you will likely need to use something like
these setting values: these setting values:
@ -118,7 +118,7 @@ how to make it work:
["less secure"](https://support.google.com/accounts/answer/6010255); ["less secure"](https://support.google.com/accounts/answer/6010255);
Gmail doesn't allow servers to send outgoing email by default. Gmail doesn't allow servers to send outgoing email by default.
- Note also that the rate limits for Gmail are also quite low - Note also that the rate limits for Gmail are also quite low
(e.g. 100 / day), so it's easy to get rate-limited if your server (e.g., 100 / day), so it's easy to get rate-limited if your server
has significant traffic. For more active servers, we recommend has significant traffic. For more active servers, we recommend
moving to a free account on a transactional email service. moving to a free account on a transactional email service.

View File

@ -123,7 +123,7 @@ When that finishes, your Zulip server should be fully operational again.
It's common, when testing backup restoration, to restore backups with a It's common, when testing backup restoration, to restore backups with a
different user-facing hostname than the original server to avoid different user-facing hostname than the original server to avoid
disrupting service (e.g. `zuliptest.example.com` rather than disrupting service (e.g., `zuliptest.example.com` rather than
`zulip.example.com`). `zulip.example.com`).
If you do so, just like any other time you change the hostname, you'll If you do so, just like any other time you change the hostname, you'll
@ -136,7 +136,7 @@ errors when trying to access it via `zuliptest.example.com`.
#### Changing database settings #### Changing database settings
If you wish to restore onto a very differently configured host (e.g. with If you wish to restore onto a very differently configured host (e.g., with
`REMOTE_POSTGRES_HOST` set to a different value), you can edit `REMOTE_POSTGRES_HOST` set to a different value), you can edit
`/etc/zulip/settings.py` to configure the host to suit the new host's needs, `/etc/zulip/settings.py` to configure the host to suit the new host's needs,
then restore with `--keep-settings`: then restore with `--keep-settings`:
@ -197,7 +197,7 @@ emails to send). You can check whether these queues are empty using
#### Backup details #### Backup details
This section is primarily for users managing backups themselves This section is primarily for users managing backups themselves
(E.g. if they're using a remote PostgreSQL database with an existing (e.g., if they're using a remote PostgreSQL database with an existing
backup strategy), and also serves as documentation for what is backup strategy), and also serves as documentation for what is
included in the backups generated by Zulip's standard tools. The included in the backups generated by Zulip's standard tools. The
data includes: data includes:
@ -213,7 +213,7 @@ data includes:
will be stored in that directory and you'll want to back it up. will be stored in that directory and you'll want to back it up.
- Your Zulip configuration including secrets from `/etc/zulip/`. - Your Zulip configuration including secrets from `/etc/zulip/`.
E.g. if you lose the value of `secret_key`, all users will need to E.g., if you lose the value of `secret_key`, all users will need to
log in again when you set up a replacement server since you won't be log in again when you set up a replacement server since you won't be
able to verify their cookies. If you lose `avatar_salt`, any able to verify their cookies. If you lose `avatar_salt`, any
user-uploaded avatars will need to be re-uploaded (since avatar user-uploaded avatars will need to be re-uploaded (since avatar
@ -408,7 +408,7 @@ importing.
The commands above create an imported organization on the root domain The commands above create an imported organization on the root domain
(`EXTERNAL_HOST`) of the Zulip installation. You can also import into a (`EXTERNAL_HOST`) of the Zulip installation. You can also import into a
custom subdomain, e.g. if you already have an existing organization on the custom subdomain, e.g., if you already have an existing organization on the
root domain. Replace the last two lines above with the following, after replacing root domain. Replace the last two lines above with the following, after replacing
`<subdomain>` with the desired subdomain. `<subdomain>` with the desired subdomain.
@ -433,7 +433,7 @@ recommend starting with sending one to yourself for testing:
./manage.py send_password_reset_email -u username@example.com ./manage.py send_password_reset_email -u username@example.com
``` ```
and then once you're ready, you can email them to everyone using e.g. and then once you're ready, you can email them to everyone using e.g.,
```bash ```bash
./manage.py send_password_reset_email -r '' --all-users ./manage.py send_password_reset_email -r '' --all-users
@ -467,7 +467,7 @@ If you're hosting multiple organizations and would like to remove
uploads from a single organization, you'll need to access `realm.id` uploads from a single organization, you'll need to access `realm.id`
in the management shell before deleting the organization from the in the management shell before deleting the organization from the
database (this will be `2` for the first organization created on a database (this will be `2` for the first organization created on a
Zulip server, shown in the example below), e.g.: Zulip server, shown in the example below), e.g.,:
```bash ```bash
rm -rf /home/zulip/uploads/*/2/ rm -rf /home/zulip/uploads/*/2/

View File

@ -54,14 +54,14 @@ unlikely to ever need to interact with that realm.)
Unless you are Unless you are
[hosting multiple organizations on your Zulip server](multiple-organizations.md), [hosting multiple organizations on your Zulip server](multiple-organizations.md),
your single Zulip organization on the root domain will have the empty your single Zulip organization on the root domain will have the empty
string (`''`) as its `string_id`. So you can run e.g.: string (`''`) as its `string_id`. So you can run e.g.,:
```console ```console
zulip@zulip:~$ /home/zulip/deployments/current/manage.py show_admins -r '' zulip@zulip:~$ /home/zulip/deployments/current/manage.py show_admins -r ''
``` ```
Otherwise, the `string_id` will correspond to the organization's Otherwise, the `string_id` will correspond to the organization's
subdomain. E.g. on `it.zulip.example.com`, use subdomain. E.g., on `it.zulip.example.com`, use
`/home/zulip/deployments/current/manage.py show_admins -r it`. `/home/zulip/deployments/current/manage.py show_admins -r it`.
## manage.py shell ## manage.py shell

View File

@ -8,7 +8,7 @@ If you do modify Zulip and then report an issue you see in your
modified version of Zulip, please be responsible about communicating modified version of Zulip, please be responsible about communicating
that fact: that fact:
- Ideally, you'd reproduce the issue in an unmodified version (e.g. in - Ideally, you'd reproduce the issue in an unmodified version (e.g., in
[the Zulip development community](https://zulip.com/development-community/) or on [the Zulip development community](https://zulip.com/development-community/) or on
[zulip.com](https://zulip.com)). [zulip.com](https://zulip.com)).
- Where that is difficult or you think it's very unlikely your changes - Where that is difficult or you think it's very unlikely your changes
@ -159,7 +159,7 @@ responsive in debugging any problems caused by a patch we asked
you to apply. you to apply.
Also, consider asking whether a small fix that is important to you can Also, consider asking whether a small fix that is important to you can
be added to the current stable release branch (E.g. `2.1.x`). In be added to the current stable release branch (e.g., `2.1.x`). In
addition to scheduling that change for Zulip's next bug fix release, addition to scheduling that change for Zulip's next bug fix release,
we support changes in stable release branches as though they were we support changes in stable release branches as though they were
released. released.
@ -190,8 +190,8 @@ upgrade to Zulip `main` using [upgrade-zulip-from-git][]. Before
upgrading to `main`, make sure you understand: upgrading to `main`, make sure you understand:
- In Zulip's version numbering scheme, `main` will always be "newer" - In Zulip's version numbering scheme, `main` will always be "newer"
than the latest maintenance release (E.g. `3.1` or `2.1.6`) and than the latest maintenance release (e.g., `3.1` or `2.1.6`) and
"older" than the next major release (E.g. `3.0` or `4.0`). "older" than the next major release (e.g., `3.0` or `4.0`).
- The `main` branch is under very active development; dozens of new - The `main` branch is under very active development; dozens of new
changes are integrated into it on most days. The `main` branch changes are integrated into it on most days. The `main` branch
can have thousands of changes not present in the latest release (all can have thousands of changes not present in the latest release (all

View File

@ -14,7 +14,7 @@ reading.
Zulip's approach for supporting multiple organizations on a single Zulip's approach for supporting multiple organizations on a single
Zulip server is for each organization to be hosted on its own Zulip server is for each organization to be hosted on its own
subdomain. E.g. you'd have `org1.zulip.example.com` and subdomain. E.g., you'd have `org1.zulip.example.com` and
`org2.zulip.example.com`. `org2.zulip.example.com`.
Web security standards mean that one subdomain per organization is Web security standards mean that one subdomain per organization is
@ -81,12 +81,12 @@ into the database.
### The root domain ### The root domain
Most Zulip servers host a single Zulip organization on the root domain Most Zulip servers host a single Zulip organization on the root domain
(e.g. `zulip.example.com`). The way this is implemented internally (e.g., `zulip.example.com`). The way this is implemented internally
involves the organization having the empty string (`''`) as its involves the organization having the empty string (`''`) as its
"subdomain". "subdomain".
You can mix having an organization on the root domain and some others You can mix having an organization on the root domain and some others
on subdomains (e.g. `subdivision.zulip.example.com`), but this only on subdomains (e.g., `subdivision.zulip.example.com`), but this only
works well if there are no users in common between the two works well if there are no users in common between the two
organizations, because the auth cookies for the root domain are organizations, because the auth cookies for the root domain are
visible to the subdomain (so it's not possible for a single visible to the subdomain (so it's not possible for a single
@ -111,7 +111,7 @@ provider with a whitelist of callback URLs to your Zulip server (or
even a single URL). For those vendors that support a whitelist, you even a single URL). For those vendors that support a whitelist, you
can provide the callback URLs for each of your Zulip organizations. can provide the callback URLs for each of your Zulip organizations.
The cleaner solution is to register a special subdomain, e.g. The cleaner solution is to register a special subdomain, e.g.,
`auth.zulip.example.com` with the third-party provider, and then set `auth.zulip.example.com` with the third-party provider, and then set
`SOCIAL_AUTH_SUBDOMAIN = 'auth'` in `/etc/zulip/settings.py`, so that `SOCIAL_AUTH_SUBDOMAIN = 'auth'` in `/etc/zulip/settings.py`, so that
Zulip knows to use that subdomain for these authentication callbacks. Zulip knows to use that subdomain for these authentication callbacks.

View File

@ -19,13 +19,13 @@ primary application server. There are two possible flavors of this -- using a
managed PostgreSQL instance from a cloud provider, or separating the PostgreSQL managed PostgreSQL instance from a cloud provider, or separating the PostgreSQL
server onto a separate (but still Zulip-managed) server for scaling purposes. server onto a separate (but still Zulip-managed) server for scaling purposes.
### Cloud-provider-managed PostgreSQL (e.g. Amazon RDS) ### Cloud-provider-managed PostgreSQL (e.g., Amazon RDS)
You can use a database-as-a-service like Amazon RDS for the Zulip database. The You can use a database-as-a-service like Amazon RDS for the Zulip database. The
experience is slightly degraded, in that most providers don't include useful experience is slightly degraded, in that most providers don't include useful
dictionary files in their installations, and don't provide a way to provide them dictionary files in their installations, and don't provide a way to provide them
yourself, resulting in a degraded [full-text search][fts] experience around yourself, resulting in a degraded [full-text search][fts] experience around
issues dictionary files are relevant (e.g. stemming). issues dictionary files are relevant (e.g., stemming).
[fts]: ../subsystems/full-text-search.md [fts]: ../subsystems/full-text-search.md

View File

@ -99,7 +99,7 @@ on hardware requirements for larger organizations.
features](https://zulip.com/help/allow-image-link-previews). features](https://zulip.com/help/allow-image-link-previews).
- Outgoing SMTP access (usually port 587) to your [SMTP - Outgoing SMTP access (usually port 587) to your [SMTP
server](email.md) so that Zulip can send emails. server](email.md) so that Zulip can send emails.
- A domain name (e.g. `zulip.example.com`) that your users will use to - A domain name (e.g., `zulip.example.com`) that your users will use to
access the Zulip server. In order to generate valid SSL access the Zulip server. In order to generate valid SSL
certificates [with Certbot][doc-certbot], and to enable other certificates [with Certbot][doc-certbot], and to enable other
services such as Google authentication, public DNS name is simpler, services such as Google authentication, public DNS name is simpler,
@ -143,7 +143,7 @@ certificate documentation](ssl-certificates.md).
#### Outgoing email #### Outgoing email
- Outgoing email (SMTP) credentials that Zulip can use to send - Outgoing email (SMTP) credentials that Zulip can use to send
outgoing emails to users (e.g. email address confirmation emails outgoing emails to users (e.g., email address confirmation emails
during the signup process, message notification emails, password during the signup process, message notification emails, password
reset, etc.). If you don't have an existing outgoing SMTP solution, reset, etc.). If you don't have an existing outgoing SMTP solution,
read about read about
@ -158,7 +158,7 @@ This section details some basic guidelines for running a Zulip server
for larger organizations (especially >1000 users or 500+ daily active for larger organizations (especially >1000 users or 500+ daily active
users). Zulip's resource needs depend mainly on 3 parameters: users). Zulip's resource needs depend mainly on 3 parameters:
- daily active users (e.g. number of employees if everyone's an - daily active users (e.g., number of employees if everyone's an
employee) employee)
- total user accounts (can be much larger) - total user accounts (can be much larger)
- message volume. - message volume.

View File

@ -87,7 +87,7 @@ that your Zulip server sits at `https://10.10.10.10:443`; see
1. Configure the root `nginx.conf` file. We recommend using 1. Configure the root `nginx.conf` file. We recommend using
`/etc/nginx/nginx.conf` from your Zulip server for our recommended `/etc/nginx/nginx.conf` from your Zulip server for our recommended
settings. E.g. if you don't set `client_max_body_size`, it won't be settings. E.g., if you don't set `client_max_body_size`, it won't be
possible to upload large files to your Zulip server. possible to upload large files to your Zulip server.
1. Configure the `nginx` site-specific configuration (in 1. Configure the `nginx` site-specific configuration (in
@ -149,7 +149,7 @@ Apache requires you use the hostname, not the IP address; see
1. Create an Apache2 virtual host configuration file, similar to the 1. Create an Apache2 virtual host configuration file, similar to the
following. Place it the appropriate path for your Apache2 following. Place it the appropriate path for your Apache2
installation and enable it (E.g. if you use Debian or Ubuntu, then installation and enable it (e.g., if you use Debian or Ubuntu, then
place it in `/etc/apache2/sites-available/zulip.example.com.conf` place it in `/etc/apache2/sites-available/zulip.example.com.conf`
and then run and then run
`a2ensite zulip.example.com && systemctl reload apache2`): `a2ensite zulip.example.com && systemctl reload apache2`):
@ -268,7 +268,7 @@ things you need to be careful about when configuring it:
addresses for a given hostname. This can result in mysterious errors addresses for a given hostname. This can result in mysterious errors
that can be quite difficult to debug. Be sure to declare your that can be quite difficult to debug. Be sure to declare your
`upstreams` equivalent in a way that won't do load-balancing `upstreams` equivalent in a way that won't do load-balancing
unexpectedly (e.g. pointing to a DNS name that you haven't configured unexpectedly (e.g., pointing to a DNS name that you haven't configured
with multiple IPs for your Zulip machine; sometimes this happens with with multiple IPs for your Zulip machine; sometimes this happens with
IPv6 configuration). IPv6 configuration).

View File

@ -124,7 +124,7 @@ strength allowed is controlled by two settings in
already been sent. As a general philosophy, our policies provide already been sent. As a general philosophy, our policies provide
hard limits on the ways in which message content can be changed or hard limits on the ways in which message content can be changed or
undone. In contrast, our policies around message topics favor undone. In contrast, our policies around message topics favor
usefulness (e.g. for conversational organization) over faithfulness usefulness (e.g., for conversational organization) over faithfulness
to the original. In all configurations: to the original. In all configurations:
- Message content can only ever be modified by the original author. - Message content can only ever be modified by the original author.
@ -158,7 +158,7 @@ strength allowed is controlled by two settings in
- Administrators can change the ownership of a bot. If a bot is subscribed - Administrators can change the ownership of a bot. If a bot is subscribed
to a private channel, then an administrator can indirectly get access to to a private channel, then an administrator can indirectly get access to
channel messages by taking control of the bot, though the access will be channel messages by taking control of the bot, though the access will be
limited to what the bot can do. (E.g. incoming webhook bots cannot read limited to what the bot can do. (e.g., incoming webhook bots cannot read
messages.) messages.)
- Every Zulip user has an API key, available on the settings page. - Every Zulip user has an API key, available on the settings page.
@ -187,7 +187,7 @@ strength allowed is controlled by two settings in
- Incoming webhook bots can only send messages into Zulip. - Incoming webhook bots can only send messages into Zulip.
- Outgoing webhook bots and Generic bots can essentially do anything a - Outgoing webhook bots and Generic bots can essentially do anything a
non-administrator user can, with a few exceptions (e.g. a bot cannot non-administrator user can, with a few exceptions (e.g., a bot cannot
log in to the web application, register for mobile push log in to the web application, register for mobile push
notifications, or create other bots). notifications, or create other bots).
- Bots with the `can_forge_sender` permission can send messages that appear to have been sent by - Bots with the `can_forge_sender` permission can send messages that appear to have been sent by
@ -203,7 +203,7 @@ strength allowed is controlled by two settings in
- Zulip supports user-uploaded files. Ideally they should be hosted - Zulip supports user-uploaded files. Ideally they should be hosted
from a separate domain from the main Zulip server to protect against from a separate domain from the main Zulip server to protect against
various same-domain attacks (e.g. zulip-user-content.example.com). various same-domain attacks (e.g., zulip-user-content.example.com).
We support two ways of hosting them: the basic `LOCAL_UPLOADS_DIR` We support two ways of hosting them: the basic `LOCAL_UPLOADS_DIR`
file storage backend, where they are stored in a directory on the file storage backend, where they are stored in a directory on the
@ -221,7 +221,7 @@ strength allowed is controlled by two settings in
instead of the URL, so this is arguably pretty good protection.) instead of the URL, so this is arguably pretty good protection.)
However, to help protect against accidental sharing of URLs to However, to help protect against accidental sharing of URLs to
restricted files (e.g. by forwarding a missed-message email or leaks restricted files (e.g., by forwarding a missed-message email or leaks
involving the Referer header), every access to an uploaded file has involving the Referer header), every access to an uploaded file has
access control verified (confirming that the browser is logged into access control verified (confirming that the browser is logged into
a Zulip account that has received the uploaded file in question). a Zulip account that has received the uploaded file in question).

View File

@ -142,7 +142,7 @@ processes to use][supervisor-minfds]; defaults to 40000. If your Zulip deploymen
is very large (hundreds of thousands of concurrent users), your Django processes is very large (hundreds of thousands of concurrent users), your Django processes
hit this limit and refuse connections to clients. Raising it above this default hit this limit and refuse connections to clients. Raising it above this default
may require changing system-level limits, particularly if you are using a may require changing system-level limits, particularly if you are using a
virtualized environment (e.g. Docker, or Proxmox LXC). virtualized environment (e.g., Docker, or Proxmox LXC).
[supervisor-minfds]: http://supervisord.org/configuration.html?highlight=minfds#supervisord-section-values [supervisor-minfds]: http://supervisord.org/configuration.html?highlight=minfds#supervisord-section-values

View File

@ -87,11 +87,11 @@ that version of Zulip.
Branches with names like `2.1.x` are stable release branches, Branches with names like `2.1.x` are stable release branches,
containing the changes planned for the next minor release containing the changes planned for the next minor release
(E.g. 2.1.5); we support these stable release branches as though they (e.g., 2.1.5); we support these stable release branches as though they
were a published release. were a published release.
The `main` branch contains changes planned for the next major The `main` branch contains changes planned for the next major
release (E.g. 3.0); see our documentation on [running release (e.g., 3.0); see our documentation on [running
`main`](modify.md#upgrading-to-main) before upgrading to it. `main`](modify.md#upgrading-to-main) before upgrading to it.
By default, this uses the main upstream Zulip server repository, but By default, this uses the main upstream Zulip server repository, but
@ -168,7 +168,7 @@ guide](troubleshooting.md).
The upgrade scripts are idempotent, so there's no harm in trying again The upgrade scripts are idempotent, so there's no harm in trying again
after resolving an issue. The most common causes of errors are: after resolving an issue. The most common causes of errors are:
- Networking issues (e.g. your Zulip server doesn't have reliable - Networking issues (e.g., your Zulip server doesn't have reliable
Internet access or needs a proxy set up). Fix the networking issue Internet access or needs a proxy set up). Fix the networking issue
and try again. and try again.
- Especially when using `upgrade-zulip-from-git`, systems with the - Especially when using `upgrade-zulip-from-git`, systems with the
@ -197,7 +197,7 @@ in any reports.
### Rolling back to a prior version ### Rolling back to a prior version
This rollback process is intended for minor releases (e.g. `2.0.3` to This rollback process is intended for minor releases (e.g., `2.0.3` to
`2.0.6`); a more complicated process is required to roll back database `2.0.6`); a more complicated process is required to roll back database
migrations before downgrading to an older major release. migrations before downgrading to an older major release.
@ -229,8 +229,8 @@ code, the upgrade will abort.
The hook is run with the following environment variables set: The hook is run with the following environment variables set:
- `ZULIP_OLD_VERSION`: The version being upgraded from, which may either be a - `ZULIP_OLD_VERSION`: The version being upgraded from, which may either be a
release name (e.g. `7.0` or `7.0-beta3`) or the output from `git describe` release name (e.g., `7.0` or `7.0-beta3`) or the output from `git describe`
(e.g. `7.0-beta3-2-gdc158b18f2`). (e.g., `7.0-beta3-2-gdc158b18f2`).
- `ZULIP_NEW_VERSION`: The version being upgraded to, in the same format as - `ZULIP_NEW_VERSION`: The version being upgraded to, in the same format as
`ZULIP_OLD_VERSION`. `ZULIP_OLD_VERSION`.
@ -258,7 +258,7 @@ hooks included with Zulip.
:::{warning} :::{warning}
If you have modified service configuration files installed by If you have modified service configuration files installed by
Zulip (e.g. the nginx configuration), the Zulip upgrade process will Zulip (e.g., the nginx configuration), the Zulip upgrade process will
overwrite your configuration when it does the `puppet apply`. overwrite your configuration when it does the `puppet apply`.
::: :::
@ -292,7 +292,7 @@ and the latter for `server` contexts.
## Upgrading the operating system ## Upgrading the operating system
When you upgrade the operating system on which Zulip is installed When you upgrade the operating system on which Zulip is installed
(E.g. Ubuntu 20.04 Focal to Ubuntu 22.04 Jammy), you need to take (e.g., Ubuntu 20.04 Focal to Ubuntu 22.04 Jammy), you need to take
some additional steps to update your Zulip installation, documented some additional steps to update your Zulip installation, documented
below. below.
@ -314,7 +314,7 @@ instructions for other supported platforms.
``` ```
3. Switch to the root user and upgrade the operating system using the 3. Switch to the root user and upgrade the operating system using the
OS's standard tooling. E.g. for Ubuntu, this means running OS's standard tooling. E.g., for Ubuntu, this means running
`do-release-upgrade` and following the prompts until it completes `do-release-upgrade` and following the prompts until it completes
successfully: successfully:
@ -367,7 +367,7 @@ instructions for other supported platforms.
``` ```
3. Switch to the root user and upgrade the operating system using the 3. Switch to the root user and upgrade the operating system using the
OS's standard tooling. E.g. for Ubuntu, this means running OS's standard tooling. E.g., for Ubuntu, this means running
`do-release-upgrade` and following the prompts until it completes `do-release-upgrade` and following the prompts until it completes
successfully: successfully:

View File

@ -33,17 +33,17 @@ backend. To enable this backend, you need to do the following:
1. Set the `S3_AUTH_UPLOADS_BUCKET` and `S3_AVATAR_BUCKET` settings in 1. Set the `S3_AUTH_UPLOADS_BUCKET` and `S3_AVATAR_BUCKET` settings in
`/etc/zulip/settings.py` to be the names of the S3 buckets you `/etc/zulip/settings.py` to be the names of the S3 buckets you
created (e.g. `"exampleinc-zulip-uploads"`). created (e.g., `"exampleinc-zulip-uploads"`).
1. Comment out the `LOCAL_UPLOADS_DIR` setting in 1. Comment out the `LOCAL_UPLOADS_DIR` setting in
`/etc/zulip/settings.py` (add a `#` at the start of the line). `/etc/zulip/settings.py` (add a `#` at the start of the line).
1. If you are using a non-AWS block storage provider, 1. If you are using a non-AWS block storage provider,
you need to set the `S3_ENDPOINT_URL` setting to your you need to set the `S3_ENDPOINT_URL` setting to your
endpoint url (e.g. `"https://s3.eu-central-1.amazonaws.com"`). endpoint url (e.g., `"https://s3.eu-central-1.amazonaws.com"`).
For certain AWS regions, you may need to set the `S3_REGION` For certain AWS regions, you may need to set the `S3_REGION`
setting to your default AWS region's code (e.g. `"eu-central-1"`). setting to your default AWS region's code (e.g., `"eu-central-1"`).
1. Finally, restart the Zulip server so that your settings changes 1. Finally, restart the Zulip server so that your settings changes
take effect take effect

View File

@ -7,7 +7,7 @@ designed around the following goals:
- Minimal impact on scalability and service complexity. - Minimal impact on scalability and service complexity.
- Well-tested so that we can count on the results being correct. - Well-tested so that we can count on the results being correct.
- Efficient to query so that we can display data in-app (e.g. on the channels - Efficient to query so that we can display data in-app (e.g., on the channels
page) with minimum impact on the overall performance of those pages. page) with minimum impact on the overall performance of those pages.
- Storage size smaller than the size of the main Message/UserMessage - Storage size smaller than the size of the main Message/UserMessage
database tables, so that we can store the data in the main PostgreSQL database tables, so that we can store the data in the main PostgreSQL
@ -45,7 +45,7 @@ set of database tables. Each of these tables has the following fields:
an hour (or UTC day) boundary for stats collected at hourly (or daily) an hour (or UTC day) boundary for stats collected at hourly (or daily)
frequency. The time interval is determined by the `CountStat`. frequency. The time interval is determined by the `CountStat`.
- various "id" fields: Foreign keys into `Realm`, `UserProfile`, `Stream`, or - various "id" fields: Foreign keys into `Realm`, `UserProfile`, `Stream`, or
nothing. E.g. the `RealmCount` table has a foreign key into `Realm`. nothing. E.g., the `RealmCount` table has a foreign key into `Realm`.
- value: The integer counts. For `"active_users_audit:is_bot:hour"` in the - value: The integer counts. For `"active_users_audit:is_bot:hour"` in the
`RealmCount` table, this is the number of active humans or bots (depending `RealmCount` table, this is the number of active humans or bots (depending
on subgroup) in a particular realm at a particular `end_time`. For on subgroup) in a particular realm at a particular `end_time`. For
@ -114,7 +114,7 @@ efficient:
for this, which is why we use raw database queries (which we usually avoid for this, which is why we use raw database queries (which we usually avoid
in Zulip) rather than the ORM. in Zulip) rather than the ORM.
- Aggregating where possible to avoid unnecessary queries against the - Aggregating where possible to avoid unnecessary queries against the
`Message` and `UserMessage` tables. E.g. rather than querying the `Message` `Message` and `UserMessage` tables. E.g., rather than querying the `Message`
table both to generate sent message counts for each realm and again for table both to generate sent message counts for each realm and again for
each user, we just query for each user, and then add up the numbers for each user, we just query for each user, and then add up the numbers for
the users to get the totals for the realm. the users to get the totals for the realm.
@ -147,10 +147,10 @@ analytics tests, to make sure it stays that way as we refactor.
The system discussed above is designed primarily around the technical The system discussed above is designed primarily around the technical
problem of showing useful analytics about things where the raw data is problem of showing useful analytics about things where the raw data is
already stored in the database (e.g. `Message`, `UserMessage`). This is great already stored in the database (e.g., `Message`, `UserMessage`). This is great
because we can always backfill that data to the beginning of time, but of because we can always backfill that data to the beginning of time, but of
course sometimes one wants to do analytics on things that aren't worth course sometimes one wants to do analytics on things that aren't worth
storing every data point for (e.g. activity data, request performance storing every data point for (e.g., activity data, request performance
statistics, etc.). There is currently a reference implementation of a statistics, etc.). There is currently a reference implementation of a
`LoggingCountStat` that shows how to handle such a situation. `LoggingCountStat` that shows how to handle such a situation.
@ -203,7 +203,7 @@ Tips and tricks:
better in Chrome than in Firefox, though this hasn't been extensively better in Chrome than in Firefox, though this hasn't been extensively
verified. verified.
- Unless a graph has a ton of data, it is typically better to just redraw it - Unless a graph has a ton of data, it is typically better to just redraw it
when something changes (e.g. in the various aggregation click handlers) when something changes (e.g., in the various aggregation click handlers)
rather than to use retrace or relayout or do other complicated rather than to use retrace or relayout or do other complicated
things. Performance on the `/stats` page is nice but not critical, and we've things. Performance on the `/stats` page is nice but not critical, and we've
run into a lot of small bugs when trying to use Plotly's retrace/relayout. run into a lot of small bugs when trying to use Plotly's retrace/relayout.
@ -211,7 +211,7 @@ Tips and tricks:
isn't documented well. isn't documented well.
- `'paper'` as a Plotly option refers to the bounding box of the graph (or - `'paper'` as a Plotly option refers to the bounding box of the graph (or
something related to that). something related to that).
- You can't right click and inspect the elements of a Plotly graph (e.g. the - You can't right click and inspect the elements of a Plotly graph (e.g., the
bars in a bar graph) in your browser, since there is an interaction layer bars in a bar graph) in your browser, since there is an interaction layer
on top of it. But if you hunt around the document tree you should be able on top of it. But if you hunt around the document tree you should be able
to find it. to find it.

View File

@ -47,7 +47,7 @@ work.
As a side note, the policy of using these accessor functions wherever As a side note, the policy of using these accessor functions wherever
possible is a good idea, regardless of caching, because the functions possible is a good idea, regardless of caching, because the functions
also generally take care of details you might not think about also generally take care of details you might not think about
(e.g. case-insensitive matching of channel names or email addresses). (e.g., case-insensitive matching of channel names or email addresses).
It's amazing how slightly tricky logic that's duplicated in several It's amazing how slightly tricky logic that's duplicated in several
places invariably ends up buggy in some of those places, and in places invariably ends up buggy in some of those places, and in
aggregate we call these accessor functions hundreds of times in aggregate we call these accessor functions hundreds of times in
@ -158,7 +158,7 @@ those keys from the cache (if present).
Maintaining these flush functions requires some care (every time we Maintaining these flush functions requires some care (every time we
add a new cache, we need to look through them), but overall it's a add a new cache, we need to look through them), but overall it's a
pretty simple algorithm: If the changed data appears in any form in a pretty simple algorithm: If the changed data appears in any form in a
given cache key, that cache key needs to be cleared. E.g. the given cache key, that cache key needs to be cleared. E.g., the
`active_user_ids_cache_key` cache for a realm needs to be flushed `active_user_ids_cache_key` cache for a realm needs to be flushed
whenever a new user is created in that realm, or user is whenever a new user is created in that realm, or user is
deactivated/reactivated, even though it's just a list of IDs and thus deactivated/reactivated, even though it's just a list of IDs and thus
@ -231,7 +231,7 @@ them in loops (the same applies for database queries!). Instead, one
should use a bulk query. We have a fancy function, should use a bulk query. We have a fancy function,
`generate_bulk_cached_fetch`, which is super magical and handles this `generate_bulk_cached_fetch`, which is super magical and handles this
for us, with support for a bunch of fancy features like marshalling for us, with support for a bunch of fancy features like marshalling
data before/after going into the cache (e.g. to compress `message` data before/after going into the cache (e.g., to compress `message`
objects to minimize data transfer between Django and memcached). objects to minimize data transfer between Django and memcached).
## In-process caching in Django ## In-process caching in Django

View File

@ -3,7 +3,7 @@
`zerver.models.Client` is Zulip's analogue of the HTTP User-Agent `zerver.models.Client` is Zulip's analogue of the HTTP User-Agent
header (and is populated from User-Agent). It exists for use in header (and is populated from User-Agent). It exists for use in
analytics and other places to provide human-readable summary data analytics and other places to provide human-readable summary data
about "which Zulip client" was used for an operation (e.g. was it the about "which Zulip client" was used for an operation (e.g., was it the
Android app, the desktop app, or a bot?). Android app, the desktop app, or a bot?).
In general, it shouldn't be used for anything controlling the behavior In general, it shouldn't be used for anything controlling the behavior

View File

@ -136,7 +136,7 @@ highlighting. The system is largely managed by the code in
versions in a `requirements.txt` file to declare what we're using. versions in a `requirements.txt` file to declare what we're using.
Since we have a few different installation targets, we maintain Since we have a few different installation targets, we maintain
several `requirements.txt` format files in the `requirements/` several `requirements.txt` format files in the `requirements/`
directory (e.g. `dev.in` for development, `prod.in` for directory (e.g., `dev.in` for development, `prod.in` for
production, `docs.in` for ReadTheDocs, `common.in` for the vast production, `docs.in` for ReadTheDocs, `common.in` for the vast
majority of packages common to prod and development, etc.). We use majority of packages common to prod and development, etc.). We use
`pip install --no-deps` to ensure we only install the packages we `pip install --no-deps` to ensure we only install the packages we

View File

@ -3,7 +3,7 @@
This page has developer documentation on the Zulip email system. If you're This page has developer documentation on the Zulip email system. If you're
trying to configure your server to send email, you might be looking for our trying to configure your server to send email, you might be looking for our
guide to [sending outgoing email](../production/email.md). If you're trying to guide to [sending outgoing email](../production/email.md). If you're trying to
configure an email integration to receive incoming email (e.g. so that users configure an email integration to receive incoming email (e.g., so that users
can reply to message notification emails via email), you might be interested in can reply to message notification emails via email), you might be interested in
our instructions for our instructions for
[setting up an email integration](https://zulip.com/integrations/doc/email). [setting up an email integration](https://zulip.com/integrations/doc/email).
@ -33,7 +33,7 @@ with only a few things you need to know to get started.
One slightly complicated decision you may have to make when adding an email One slightly complicated decision you may have to make when adding an email
is figuring out how to schedule it. There are 3 ways to schedule email. is figuring out how to schedule it. There are 3 ways to schedule email.
- Send it immediately, in the current Django process, e.g. by calling - Send it immediately, in the current Django process, e.g., by calling
`send_email` directly. An example of this is the `confirm_registration` `send_email` directly. An example of this is the `confirm_registration`
email. email.
- Add it to a queue. An example is the `invitation` email. - Add it to a queue. An example is the `invitation` email.
@ -56,7 +56,7 @@ custom backend, `EmailLogBackEnd`. It does the following:
- Logs any sent emails to `var/log/email_content.log`. This log is - Logs any sent emails to `var/log/email_content.log`. This log is
displayed by the `/emails` endpoint displayed by the `/emails` endpoint
(e.g. http://zulip.zulipdev.com:9991/emails). (e.g., http://zulip.zulipdev.com:9991/emails).
- Print a friendly message on console advertising `/emails` to make - Print a friendly message on console advertising `/emails` to make
this nice and discoverable. this nice and discoverable.
@ -157,7 +157,7 @@ are multiple copies or they contain CSS colors, you did it wrong.
A final note for translating emails is that strings that are sent to A final note for translating emails is that strings that are sent to
user accounts (where we know the user's language) are higher-priority user accounts (where we know the user's language) are higher-priority
to translate than things sent to an email address (where we don't). to translate than things sent to an email address (where we don't).
E.g. for password reset emails, it makes sense for the code path for E.g., for password reset emails, it makes sense for the code path for
people with an actual account can be tagged for translation, while the people with an actual account can be tagged for translation, while the
code path for the "you don't have an account email" might not be, code path for the "you don't have an account email" might not be,
since we might not know what language to use in the second case. since we might not know what language to use in the second case.

View File

@ -64,15 +64,15 @@ to be consumed by the delivery system.
Usually, this list of users is one of 3 things: Usually, this list of users is one of 3 things:
- A single user (e.g. for user-level settings changes). - A single user (e.g., for user-level settings changes).
- Everyone in the realm (e.g. for organization-level settings changes, - Everyone in the realm (e.g., for organization-level settings changes,
like new realm emoji). like new realm emoji).
- Everyone who would receive a given message (for messages, emoji - Everyone who would receive a given message (for messages, emoji
reactions, message editing, etc.); i.e. the subscribers to a channel reactions, message editing, etc.); i.e. the subscribers to a channel
or the people on a direct message thread. or the people on a direct message thread.
It is the responsibility of the caller of `send_event` to choose the It is the responsibility of the caller of `send_event` to choose the
list of user IDs correctly. There can be security problems if e.g. an list of user IDs correctly. There can be security problems if e.g., an
event containing direct message content is sent to the entire event containing direct message content is sent to the entire
organization. However, if an event isn't sent to enough clients, organization. However, if an event isn't sent to enough clients,
there will likely be user-visible real-time sync bugs. there will likely be user-visible real-time sync bugs.
@ -175,7 +175,7 @@ anyway).
When a client starts up, it usually wants to get 2 things from the When a client starts up, it usually wants to get 2 things from the
server: server:
- The "current state" of various pieces of data, e.g. the current - The "current state" of various pieces of data, e.g., the current
settings, set of users in the organization (for typeahead), channel, settings, set of users in the organization (for typeahead), channel,
messages, etc. (aka the "initial state"). messages, etc. (aka the "initial state").
- A subscription to receive updates to those data when they are - A subscription to receive updates to those data when they are
@ -212,7 +212,7 @@ request; the logic is in `zerver/views/events_register.py` and
that had been added to the Tornado event queue since it that had been added to the Tornado event queue since it
was created. was created.
- Finally, Django "applies" the events (see the `apply_events` - Finally, Django "applies" the events (see the `apply_events`
function) to the initial state that it fetched. E.g. for a name function) to the initial state that it fetched. E.g., for a name
change event, it finds the user data in the `realm_user` data change event, it finds the user data in the `realm_user` data
structure, and updates it to have the new name. structure, and updates it to have the new name.
@ -266,7 +266,7 @@ action and then fetching a fresh copy of the state.
In particular, `verify_action` does the following: In particular, `verify_action` does the following:
- Call `fetch_initial_state_data` to get the current state. - Call `fetch_initial_state_data` to get the current state.
- Call the action function (e.g. `do_add_default_stream`). - Call the action function (e.g., `do_add_default_stream`).
- Capture the events generated by the action function. - Capture the events generated by the action function.
- Check the events generated are documented in the [OpenAPI - Check the events generated are documented in the [OpenAPI
schema](../documentation/api.md) defined in schema](../documentation/api.md) defined in
@ -421,7 +421,7 @@ to make sure we handle backwards-compatibility properly.
`GET /events` API documentation. It's also a good idea to and open `GET /events` API documentation. It's also a good idea to and open
issues with the mobile and terminal projects to notify them. issues with the mobile and terminal projects to notify them.
- If we're making changes that could confuse existing client app logic - If we're making changes that could confuse existing client app logic
that parses events (E.g. changing the type/meaning of an existing that parses events (e.g., changing the type/meaning of an existing
field, or removing a field), we need to be very careful, since Zulip field, or removing a field), we need to be very careful, since Zulip
supports old clients connecting to a modern server. See our supports old clients connecting to a modern server. See our
[release lifecycle](../overview/release-lifecycle.md) documentation [release lifecycle](../overview/release-lifecycle.md) documentation
@ -441,14 +441,14 @@ to make sure we handle backwards-compatibility properly.
format, or Tornado may crash when upgrading past the relevant format, or Tornado may crash when upgrading past the relevant
commit. We attempt to contain that sort of logic in the `from_dict` commit. We attempt to contain that sort of logic in the `from_dict`
function (which is used for changing event queue formats) and function (which is used for changing event queue formats) and
`client_capabilities` conditionals (E.g. in `client_capabilities` conditionals (e.g., in
`process_deletion_event`). Compatibility code not related to a `process_deletion_event`). Compatibility code not related to a
`client_capabilities` entry should be marked with a `client_capabilities` entry should be marked with a
`# TODO/compatibility: ...` comment noting when it can be safely deleted; `# TODO/compatibility: ...` comment noting when it can be safely deleted;
we grep for these comments entries during major releases. we grep for these comments entries during major releases.
- Schema changes are a sensitive operation, and like with database - Schema changes are a sensitive operation, and like with database
schema changes, it's critical to do thoughtful manual testing. schema changes, it's critical to do thoughtful manual testing.
E.g. run the mobile app against your test server and verify it E.g., run the mobile app against your test server and verify it
handles the new event properly, or arrange for your new Tornado code handles the new event properly, or arrange for your new Tornado code
to actually process a pre-upgrade event and verify via the browser to actually process a pre-upgrade event and verify via the browser
console what came out. console what came out.

View File

@ -30,9 +30,9 @@ different flows:
- The user uses the "back" button in their browser (basically - The user uses the "back" button in their browser (basically
equivalent to the previous one, as a _link_ out of the browser history equivalent to the previous one, as a _link_ out of the browser history
will be visited). will be visited).
- The user clicking some in-app click handler (e.g. "Channel settings" - The user clicking some in-app click handler (e.g., "Channel settings"
for an individual channel), that potentially does for an individual channel), that potentially does
several UI-manipulating things including e.g. loading the channels several UI-manipulating things including e.g., loading the channels
overlay, and needs to update the hash without re-triggering the open overlay, and needs to update the hash without re-triggering the open
animation (etc.). animation (etc.).
- Within an overlay like the channels overlay, the user clicks to - Within an overlay like the channels overlay, the user clicks to
@ -45,7 +45,7 @@ different flows:
- A server-initiated browser reload (done after a new version is - A server-initiated browser reload (done after a new version is
deployed, or when a user comes back after being idle for a while, deployed, or when a user comes back after being idle for a while,
see [notes below][self-server-reloads]), where we try to preserve see [notes below][self-server-reloads]), where we try to preserve
extra state (e.g. content of compose box, scroll position within a extra state (e.g., content of compose box, scroll position within a
narrow) using the `/#reload` hash prefix. narrow) using the `/#reload` hash prefix.
When making changes to the hashchange system, it is **essential** to When making changes to the hashchange system, it is **essential** to
@ -65,7 +65,7 @@ The main external API lives in `web/src/browser_history.js`:
Internally you have these functions: Internally you have these functions:
- `hashchange.hashchanged` is the function used to handle the hash, - `hashchange.hashchanged` is the function used to handle the hash,
whether it's changed by the browser (e.g. by clicking on a link to whether it's changed by the browser (e.g., by clicking on a link to
a hash or using the back button) or triggered internally. a hash or using the back button) or triggered internally.
- `hashchange.do_hashchange_normal` handles most cases, like loading the main - `hashchange.do_hashchange_normal` handles most cases, like loading the main
page (but maybe with a specific URL if you are narrowed to a page (but maybe with a specific URL if you are narrowed to a

View File

@ -83,8 +83,8 @@ with its corresponding CSS selector as `.my-multiword-class`.
When changing any part of the Zulip CSS, it's important to check that When changing any part of the Zulip CSS, it's important to check that
the new CSS looks good at a wide range of screen widths, from very the new CSS looks good at a wide range of screen widths, from very
wide screen (e.g. 1920px) all the way down to narrow phone screens wide screen (e.g., 1920px) all the way down to narrow phone screens
(e.g. 480px). (e.g., 480px).
For complex changes, it's definitely worth testing in a few different For complex changes, it's definitely worth testing in a few different
browsers to make sure things look the same. browsers to make sure things look the same.
@ -228,9 +228,9 @@ needs to be accessible from one of the entry points defined either in
`web/src/bundles/common.ts` which itself is imported to the `web/src/bundles/common.ts` which itself is imported to the
`app` and `common` bundles. `app` and `common` bundles.
- If it's just used on a single standalone page which is only used in - If it's just used on a single standalone page which is only used in
a development environment (e.g. `/devlogin`) create a new entry a development environment (e.g., `/devlogin`) create a new entry
point in `web/webpack.dev-assets.json` or it's used in both point in `web/webpack.dev-assets.json` or it's used in both
production and development (e.g. `/stats`) create a new entry point production and development (e.g., `/stats`) create a new entry point
in `web/webpack.assets.json`. Use the `bundle` macro (defined in in `web/webpack.assets.json`. Use the `bundle` macro (defined in
`templates/zerver/base.html`) in the relevant Jinja2 template to `templates/zerver/base.html`) in the relevant Jinja2 template to
inject the compiled JS and CSS. inject the compiled JS and CSS.
@ -246,10 +246,10 @@ A few useful notes are:
`/home/zulip/prod-static`. When a new version is deployed, before the `/home/zulip/prod-static`. When a new version is deployed, before the
server is restarted, files are copied into that directory. server is restarted, files are copied into that directory.
- We use the VFL (versioned file layout) strategy, where each file in - We use the VFL (versioned file layout) strategy, where each file in
the codebase (e.g. `favicon.ico`) gets a new name the codebase (e.g., `favicon.ico`) gets a new name
(e.g. `favicon.c55d45ae8c58.ico`) that contains a hash in it. Each (e.g., `favicon.c55d45ae8c58.ico`) that contains a hash in it. Each
deployment, has a manifest file deployment, has a manifest file
(e.g. `/home/zulip/deployments/current/staticfiles.json`) that maps (e.g., `/home/zulip/deployments/current/staticfiles.json`) that maps
codebase filenames to serving filenames for that deployment. The codebase filenames to serving filenames for that deployment. The
benefit of this VFL approach is that all the static files for past benefit of this VFL approach is that all the static files for past
deployments can coexist, which in turn eliminates most classes of deployments can coexist, which in turn eliminates most classes of
@ -257,7 +257,7 @@ A few useful notes are:
deployment can't find their static assets. It also is necessary for deployment can't find their static assets. It also is necessary for
any incremental rollout strategy where different clients get any incremental rollout strategy where different clients get
different versions of the site. different versions of the site.
- Some paths for files (e.g. emoji) are stored in the - Some paths for files (e.g., emoji) are stored in the
`rendered_content` of past messages, and thus cannot be removed `rendered_content` of past messages, and thus cannot be removed
without breaking the rendering of old messages (or doing a without breaking the rendering of old messages (or doing a
mass-rerender of old messages). mass-rerender of old messages).

View File

@ -111,7 +111,7 @@ The format of this output is:
- HTTP method - HTTP method
- HTTP status code - HTTP status code
- Time to process - Time to process
- (Optional perf data details, e.g. database time/queries, memcached - (Optional perf data details, e.g., database time/queries, memcached
time/queries, Django process startup time, Markdown processing time, time/queries, Django process startup time, Markdown processing time,
etc.) etc.)
- Endpoint/URL from zproject/urls.py - Endpoint/URL from zproject/urls.py
@ -200,7 +200,7 @@ Blueslip supports several error levels:
than returning execution to the caller. than returning execution to the caller.
- `blueslip.error`: For logging of events that are definitely caused by a bug - `blueslip.error`: For logging of events that are definitely caused by a bug
and thus sufficiently important to be reported, but where we can handle the and thus sufficiently important to be reported, but where we can handle the
error without creating major user-facing problems (e.g. an exception when error without creating major user-facing problems (e.g., an exception when
handling a presence update). handling a presence update).
- `blueslip.warn`: For logging of events that are a problem but not important - `blueslip.warn`: For logging of events that are a problem but not important
enough to log an error to Sentry in production. They are, however, highlighted enough to log an error to Sentry in production. They are, however, highlighted
@ -208,7 +208,7 @@ Blueslip supports several error levels:
production. production.
- `blueslip.log` (and `blueslip.info`): Logged to the JS console in development - `blueslip.log` (and `blueslip.info`): Logged to the JS console in development
and also in the Sentry breadcrumb log in production. Useful for data that and also in the Sentry breadcrumb log in production. Useful for data that
might help discern what state the browser was in during an error (e.g. whether might help discern what state the browser was in during an error (e.g., whether
the user was in a narrow). the user was in a narrow).
- `blueslip.debug`: Similar to `blueslip.log`, but are not printed to - `blueslip.debug`: Similar to `blueslip.log`, but are not printed to
the JS console in development. the JS console in development.

View File

@ -13,22 +13,22 @@ While Zulip takes advantage of built-in Django management commands for
things like managing Django migrations, we also have dozens that we've things like managing Django migrations, we also have dozens that we've
written for a range of purposes: written for a range of purposes:
- Cron jobs to do regular updates, e.g. `update_analytics_counts.py`, - Cron jobs to do regular updates, e.g., `update_analytics_counts.py`,
`sync_ldap_user_data`, etc. `sync_ldap_user_data`, etc.
- Useful parts of provisioning or upgrading a Zulip development - Useful parts of provisioning or upgrading a Zulip development
environment or server, e.g. `makemessages`, `compilemessages`, environment or server, e.g., `makemessages`, `compilemessages`,
`populate_db`, `fill_memcached_caches`, etc. `populate_db`, `fill_memcached_caches`, etc.
- The actual scripts run by supervisord to run the persistent - The actual scripts run by supervisord to run the persistent
processes in a Zulip server, e.g. `runtornado` and `process_queue`. processes in a Zulip server, e.g., `runtornado` and `process_queue`.
- For a sysadmin to verify a Zulip server's configuration during - For a sysadmin to verify a Zulip server's configuration during
installation, e.g. `checkconfig`, `send_test_email`. installation, e.g., `checkconfig`, `send_test_email`.
- As the interface for doing those rare operations that don't have a - As the interface for doing those rare operations that don't have a
UI yet, e.g. `deactivate_realm`, `reactivate_realm`, UI yet, e.g., `deactivate_realm`, `reactivate_realm`,
`change_user_email` (for the case where the user doesn't control the `change_user_email` (for the case where the user doesn't control the
old email address). old email address).
- For a sysadmin to easily interact with and script common possible - For a sysadmin to easily interact with and script common possible
changes they might want to make to the database on a Zulip server. changes they might want to make to the database on a Zulip server.
E.g. `send_password_reset_email`, `export`, `purge_queue`. E.g., `send_password_reset_email`, `export`, `purge_queue`.
## Writing management commands ## Writing management commands

View File

@ -147,10 +147,10 @@ object and other arguments passed into `do_convert` (`sent_by_bot`,
`translate_emoticons`, `mention_data`, etc.). Because `translate_emoticons`, `mention_data`, etc.). Because
Python-Markdown doesn't support directly passing arguments into the Python-Markdown doesn't support directly passing arguments into the
Markdown processor, our logic attaches these data to the Markdown Markdown processor, our logic attaches these data to the Markdown
processor object via e.g. `_md_engine.zulip_db_data`, and then processor object via e.g., `_md_engine.zulip_db_data`, and then
individual Markdown rules can access the data from there. individual Markdown rules can access the data from there.
For non-message contexts (e.g. an organization's profile (aka the For non-message contexts (e.g., an organization's profile (aka the
thing on the right-hand side of the login page), channel descriptions, thing on the right-hand side of the login page), channel descriptions,
or rendering custom profile fields), one needs to just pass in a or rendering custom profile fields), one needs to just pass in a
`message_realm` (see, for example, `zulip_default_context` for the `message_realm` (see, for example, `zulip_default_context` for the
@ -166,7 +166,7 @@ Markdown, not newer Markdown variants like CommonMark.
Markdown is great for group chat for the same reason it's been Markdown is great for group chat for the same reason it's been
successful in products ranging from blogs to wikis to bug trackers: successful in products ranging from blogs to wikis to bug trackers:
it's close enough to how people try to express themselves when writing it's close enough to how people try to express themselves when writing
plain text (e.g. emails) that it helps more than getting in the way. plain text (e.g., emails) that it helps more than getting in the way.
The main issue for using Markdown in instant messaging is that the The main issue for using Markdown in instant messaging is that the
Markdown standard syntax used in a lot of wikis/blogs has nontrivial Markdown standard syntax used in a lot of wikis/blogs has nontrivial
@ -212,7 +212,7 @@ accurate.
- Allow only `*` syntax for italics, not `_`. This resolves an issue where - Allow only `*` syntax for italics, not `_`. This resolves an issue where
people were using `_` and hitting it by mistake too often. Asterisks people were using `_` and hitting it by mistake too often. Asterisks
surrounded by spaces won't trigger italics, either (e.g. with stock Markdown surrounded by spaces won't trigger italics, either (e.g., with stock Markdown
`You should use char * instead of void * there` would produce undesired `You should use char * instead of void * there` would produce undesired
results). results).

View File

@ -28,7 +28,7 @@ as follows:
- `do_send_messages` is the synchronous message-sending code path, - `do_send_messages` is the synchronous message-sending code path,
and passing the following data in its `send_event` call: and passing the following data in its `send_event` call:
- Data about the message's content (E.g. mentions, wildcard - Data about the message's content (e.g., mentions, wildcard
mentions, and alert words) and encodes it into the `UserMessage` mentions, and alert words) and encodes it into the `UserMessage`
table's `flags` structure, which is in turn passed into table's `flags` structure, which is in turn passed into
`send_event` for each user receiving the message. `send_event` for each user receiving the message.
@ -72,7 +72,7 @@ as follows:
`receiver_is_off_zulip` returns `True`, which checks whether the user has any `receiver_is_off_zulip` returns `True`, which checks whether the user has any
current events system clients registered to receive `message` current events system clients registered to receive `message`
events. This check is done immediately (handling soft disconnects, events. This check is done immediately (handling soft disconnects,
where E.g. the user closes their last Zulip tab and we get the where e.g., the user closes their last Zulip tab and we get the
`DELETE /events/{queue_id}` request). `DELETE /events/{queue_id}` request).
- The `receiver_is_off_zulip` check is effectively repeated when - The `receiver_is_off_zulip` check is effectively repeated when
event queues are garbage-collected (in `missedmessage_hook`) by event queues are garbage-collected (in `missedmessage_hook`) by
@ -89,7 +89,7 @@ as follows:
notifications in cases like a mention added during message notifications in cases like a mention added during message
editing. editing.
- The notification sending logic for message edits - The notification sending logic for message edits
inside Tornado has extensive automated test suites; e.g. inside Tornado has extensive automated test suites; e.g.,
`test_message_edit_notifications.py` covers all the cases around `test_message_edit_notifications.py` covers all the cases around
editing a message to add/remove a mention. editing a message to add/remove a mention.
- We may in the future want to add some sort of system for letting - We may in the future want to add some sort of system for letting

View File

@ -4,7 +4,7 @@ When you're using Zulip and you reload, or narrow to a channel, how
does Zulip decide where to place you? does Zulip decide where to place you?
Conceptually, Zulip takes you to the place where you left off Conceptually, Zulip takes you to the place where you left off
(e.g. the first unread message), not the most recent messages, to (e.g., the first unread message), not the most recent messages, to
facilitate reviewing all the discussions that happened while you were facilitate reviewing all the discussions that happened while you were
away from your computer. The scroll position is then set to keep that away from your computer. The scroll position is then set to keep that
message in view and away from both the top and bottom of the visible message in view and away from both the top and bottom of the visible
@ -53,7 +53,7 @@ channels.)
### Unnarrow: previous sequence ### Unnarrow: previous sequence
When you unnarrow using e.g. the `a` key, you will automatically be When you unnarrow using e.g., the `a` key, you will automatically be
taken to the same message that was selected in the Combined feed view before taken to the same message that was selected in the Combined feed view before
you narrowed, unless in the narrow you read new messages, in which you narrowed, unless in the narrow you read new messages, in which
case you will be jumped forward to the first unread and non-muted case you will be jumped forward to the first unread and non-muted

View File

@ -13,7 +13,7 @@ scalability problems for a team chat tool like Zulip.
There's a lot of performance-related details in the backend and There's a lot of performance-related details in the backend and
network protocol design that we won't get into here. The focus of network protocol design that we won't get into here. The focus of
this is what one needs to know to correctly implement a Zulip client's this is what one needs to know to correctly implement a Zulip client's
presence implementation (e.g. web app, mobile app, terminal client, or presence implementation (e.g., web app, mobile app, terminal client, or
other tool that's intended to represent whether a user is online and other tool that's intended to represent whether a user is online and
using Zulip). using Zulip).
@ -36,7 +36,7 @@ about that data structure:
- It's really important that the timestamp is the last time we heard - It's really important that the timestamp is the last time we heard
from the client. A client can only interpret the status to display from the client. A client can only interpret the status to display
about another user by doing a simple computation using the (status, about another user by doing a simple computation using the (status,
timestamp) pair. E.g. a user who last used Zulip 1 week ago will timestamp) pair. E.g., a user who last used Zulip 1 week ago will
have a timestamp of 1 week ago and a status of "active". Why? have a timestamp of 1 week ago and a status of "active". Why?
Because this correctly handles the race conditions. For example, if Because this correctly handles the race conditions. For example, if
the threshold for displaying a user as "offline" was 5 minutes the threshold for displaying a user as "offline" was 5 minutes
@ -50,7 +50,7 @@ about that data structure:
- The `status_from_timestamp` function in `web/src/presence.js` is - The `status_from_timestamp` function in `web/src/presence.js` is
useful sample code; the `OFFLINE_THRESHOLD_SECS` check is critical useful sample code; the `OFFLINE_THRESHOLD_SECS` check is critical
to correct output. to correct output.
- We provide the data for e.g. whether the user was online on their - We provide the data for e.g., whether the user was online on their
desktop or the mobile app, but for a basic client, you will likely desktop or the mobile app, but for a basic client, you will likely
only want to parse the "aggregated" key, which shows the summary only want to parse the "aggregated" key, which shows the summary
answer for "is this user online". answer for "is this user online".

View File

@ -5,11 +5,11 @@ used for a variety of purposes:
- Asynchronously doing expensive operations like sending email - Asynchronously doing expensive operations like sending email
notifications which can take seconds per email and thus would notifications which can take seconds per email and thus would
otherwise time out when 100s are triggered at once (E.g. inviting a otherwise time out when 100s are triggered at once (e.g., inviting a
lot of new users to a realm). lot of new users to a realm).
- Asynchronously doing non-time-critical somewhat expensive operations - Asynchronously doing non-time-critical somewhat expensive operations
like updating analytics tables (e.g. UserActivityInternal) which like updating analytics tables (e.g., UserActivityInternal) which
don't have any immediate runtime effect. don't have any immediate runtime effect.
- Communicating events to push to clients (browsers, etc.) from the - Communicating events to push to clients (browsers, etc.) from the
@ -40,7 +40,7 @@ To add a new queue processor:
processor. This suffices to test your queue worker in the Zulip development processor. This suffices to test your queue worker in the Zulip development
environment (`tools/run-dev` will automatically restart the queue processors environment (`tools/run-dev` will automatically restart the queue processors
and start running your new queue processor code). You can also run a single and start running your new queue processor code). You can also run a single
queue processor manually using e.g. `./manage.py process_queue --queue=user_activity`. queue processor manually using e.g., `./manage.py process_queue --queue=user_activity`.
- So that supervisord will know to run the queue processor in - So that supervisord will know to run the queue processor in
production, you will need to add to the `queues` variable in production, you will need to add to the `queues` variable in

View File

@ -92,5 +92,5 @@ lookup should still work even if you disable proxy for
127.0.0.1 testsubdomain.zulipdev.com 127.0.0.1 testsubdomain.zulipdev.com
``` ```
These records are also useful if you want to e.g. run the Puppeteer tests These records are also useful if you want to e.g., run the Puppeteer tests
when you are not connected to the Internet. when you are not connected to the Internet.

View File

@ -5,12 +5,12 @@ preparing a new release.
### A week before the release ### A week before the release
- _Major releases only (e.g. 4.0):_ - _Major releases only (e.g., 4.0):_
- Upgrade all Python dependencies in - Upgrade all Python dependencies in
`requirements` to latest upstream versions so they can burn in (use `requirements` to latest upstream versions so they can burn in (use
`pip list --outdated`). `pip list --outdated`).
- Upgrade all puppet dependencies in `puppet/deps.yaml` - Upgrade all puppet dependencies in `puppet/deps.yaml`
- Upgrade all puppet-installed dependencies (e.g. Smokescreen, go, - Upgrade all puppet-installed dependencies (e.g., Smokescreen, go,
etc) in `puppet/zulip/manifests/common.pp` etc) in `puppet/zulip/manifests/common.pp`
- [Upload strings to - [Upload strings to
Transifex](../translating/internationalization.md#translation-process) Transifex](../translating/internationalization.md#translation-process)
@ -49,7 +49,7 @@ preparing a new release.
- If the draft post should remain secret until release, avoid using - If the draft post should remain secret until release, avoid using
a guessable Git branch name for the pull request (the deployment a guessable Git branch name for the pull request (the deployment
preview URL is based on the branch name). preview URL is based on the branch name).
- _Major releases only (e.g. 4.0):_ Schedule team members to provide - _Major releases only (e.g., 4.0):_ Schedule team members to provide
extra responsive #production help support following the release. extra responsive #production help support following the release.
### Executing the release ### Executing the release
@ -94,12 +94,12 @@ preparing a new release.
once it is built, and how to test it. Verify it, then publish it to once it is built, and how to test it. Verify it, then publish it to
DigitalOcean marketplace. DigitalOcean marketplace.
- _Major releases only:_ - _Major releases only:_
- Create a release branch (e.g. `4.x`). - Create a release branch (e.g., `4.x`).
- On the release branch, update `ZULIP_VERSION` in `version.py` to - On the release branch, update `ZULIP_VERSION` in `version.py` to
the present release with a `+git` suffix, e.g. `4.0+git`. the present release with a `+git` suffix, e.g., `4.0+git`.
- On `main`, update `ZULIP_VERSION` to the future major release with - On `main`, update `ZULIP_VERSION` to the future major release with
a `-dev+git` suffix, e.g. `5.0-dev+git`. Make a Git tag for this a `-dev+git` suffix, e.g., `5.0-dev+git`. Make a Git tag for this
update commit with a `-dev` suffix, e.g. `5.0-dev`. Push the tag update commit with a `-dev` suffix, e.g., `5.0-dev`. Push the tag
to both zulip.git and zulip-internal.git to get a correct version to both zulip.git and zulip-internal.git to get a correct version
number for future Cloud deployments. number for future Cloud deployments.
- Add the new release to `.github/ISSUE_TEMPLATE/2_bug_report.md`. - Add the new release to `.github/ISSUE_TEMPLATE/2_bug_report.md`.
@ -113,16 +113,16 @@ preparing a new release.
- Add a new line to the `production_upgrade` matrix in - Add a new line to the `production_upgrade` matrix in
`.github/workflows/production-suite.yml`. `.github/workflows/production-suite.yml`.
- Update /history page in `templates/corporate/history.md`. - Update /history page in `templates/corporate/history.md`.
- _Minor releases only (e.g. 3.2):_ - _Minor releases only (e.g., 3.2):_
- On the release branch, update `ZULIP_VERSION` to the present - On the release branch, update `ZULIP_VERSION` to the present
release with a `+git` suffix, e.g. `3.2+git`. release with a `+git` suffix, e.g., `3.2+git`.
- On main, update `LATEST_RELEASE_VERSION` with the released - On main, update `LATEST_RELEASE_VERSION` with the released
version, as well as the changelog changes from the release branch. version, as well as the changelog changes from the release branch.
- _Prereleases only (e.g. 7.0-beta3):_ - _Prereleases only (e.g., 7.0-beta3):_
- Atop the prerelease commit (e.g. `7.0-beta3`), make a commit - Atop the prerelease commit (e.g., `7.0-beta3`), make a commit
updating `ZULIP_VERSION` to the prerelease version with a `+git` updating `ZULIP_VERSION` to the prerelease version with a `+git`
suffix, e.g. `7.0-beta3+git`. Push this to `main`. (If `main` has suffix, e.g., `7.0-beta3+git`. Push this to `main`. (If `main` has
already diverged from the prerelease, a merge commit will be already diverged from the prerelease, a merge commit will be
needed here.) needed here.)
- Delete the prerelease branch (e.g. `7.0-beta3-branch`); it's now - Delete the prerelease branch (e.g., `7.0-beta3-branch`); it's now
an ancestor of `main` and thus unnecessary. an ancestor of `main` and thus unnecessary.

View File

@ -49,7 +49,7 @@ migrations.
migration that exists on the release branch. This should be migration that exists on the release branch. This should be
followed, on `main`, by a migration which merges the two resulting followed, on `main`, by a migration which merges the two resulting
tips; you can make such a merge with `manage.py makemigrations --merge`. tips; you can make such a merge with `manage.py makemigrations --merge`.
- **Large tables**: For our very largest tables (e.g. Message and - **Large tables**: For our very largest tables (e.g., Message and
UserMessage), we often need to take precautions when adding columns UserMessage), we often need to take precautions when adding columns
to the table, performing data backfills, or building indexes. We to the table, performing data backfills, or building indexes. We
have a `zerver/lib/migrate.py` library to help with adding columns have a `zerver/lib/migrate.py` library to help with adding columns
@ -63,7 +63,7 @@ migrations.
- **Atomicity**. By default, each Django migration is run atomically - **Atomicity**. By default, each Django migration is run atomically
inside a transaction. This can be problematic if one wants to do inside a transaction. This can be problematic if one wants to do
something in a migration that touches a lot of data and would best something in a migration that touches a lot of data and would best
be done in batches of e.g. 1000 objects (e.g. a `Message` or be done in batches of e.g., 1000 objects (e.g., a `Message` or
`UserMessage` table change). There is a [useful Django `UserMessage` table change). There is a [useful Django
feature][migrations-non-atomic] that makes it possible to add feature][migrations-non-atomic] that makes it possible to add
`atomic=False` at the top of a `Migration` class and thus not have `atomic=False` at the top of a `Migration` class and thus not have
@ -130,7 +130,7 @@ migrations.
to do lots of small batches, potentially with a brief sleep in to do lots of small batches, potentially with a brief sleep in
between, so that we don't block other operations from finishing. between, so that we don't block other operations from finishing.
- **Rerunnability/idempotency**. Good migrations are ones where if - **Rerunnability/idempotency**. Good migrations are ones where if
operational concerns (e.g. it taking down the Zulip server for operational concerns (e.g., it taking down the Zulip server for
users) interfere with it finishing, it's easy to restart the users) interfere with it finishing, it's easy to restart the
migration without doing a bunch of hand investigation. Ideally, migration without doing a bunch of hand investigation. Ideally,
the migration can even continue where it left off, without needing the migration can even continue where it left off, without needing
@ -144,7 +144,7 @@ migrations.
2. Second, do a migration to copy values from the old column to 2. Second, do a migration to copy values from the old column to
the new column, to ensure that the two data stores agree. the new column, to ensure that the two data stores agree.
3. Third, a commit that stops writing to the old field. 3. Third, a commit that stops writing to the old field.
4. Any cleanup work, e.g. if the old field were a column, we'd do 4. Any cleanup work, e.g., if the old field were a column, we'd do
a migration to remove it entirely here. a migration to remove it entirely here.
This multi-step process is how most migrations on large database This multi-step process is how most migrations on large database

View File

@ -22,7 +22,7 @@ There are 3 related structures:
IDs go in what order. IDs go in what order.
- A `message_list` is built on top of `message_list_data` and - A `message_list` is built on top of `message_list_data` and
additionally contains the data for a visible-to-the-user message list additionally contains the data for a visible-to-the-user message list
(E.g. where trailing bookends should appear, a selected message, (e.g., where trailing bookends should appear, a selected message,
etc.). etc.).
- A `message_list_view` is built on top of `message_list` and - A `message_list_view` is built on top of `message_list` and
additionally contains rendering details like a window of up to 400 additionally contains rendering details like a window of up to 400
@ -37,7 +37,7 @@ and narrowing).
The compose box does a lot of fancy things that are out of scope for The compose box does a lot of fancy things that are out of scope for
this article. But it also does a decent amount of client-side this article. But it also does a decent amount of client-side
validation before sending a message off to the server, especially validation before sending a message off to the server, especially
around mentions (E.g. checking the channel name is a valid channel, around mentions (e.g., checking the channel name is a valid channel,
displaying a warning about the number of recipients before a user can displaying a warning about the number of recipients before a user can
use `@**all**` or mention a user who is not subscribed to the current use `@**all**` or mention a user who is not subscribed to the current
channel, etc.). channel, etc.).
@ -62,12 +62,12 @@ This section details the ways in which it is different:
[queue](queuing.md) to actually send the message. [queue](queuing.md) to actually send the message.
See `maybe_enqueue_notifications` and `zerver/lib/notification_data.py` for See `maybe_enqueue_notifications` and `zerver/lib/notification_data.py` for
this part of the logic. this part of the logic.
- Splicing user-dependent data (E.g. `flags` such as when the user - Splicing user-dependent data (e.g., `flags` such as when the user
was `mentioned`) into the events. was `mentioned`) into the events.
- Handling the [local echo details](#local-echo). - Handling the [local echo details](#local-echo).
- Handling certain client configuration options that affect - Handling certain client configuration options that affect
messages. E.g. determining whether to send the messages. E.g., determining whether to send the
plaintext/Markdown raw content or the rendered HTML (e.g. the plaintext/Markdown raw content or the rendered HTML (e.g., the
`apply_markdown` and `client_gravatar` features in our `apply_markdown` and `client_gravatar` features in our
[events API docs](https://zulip.com/api/register-queue)). [events API docs](https://zulip.com/api/register-queue)).
- Following our standard naming convention, input validation is done - Following our standard naming convention, input validation is done
@ -94,7 +94,7 @@ This section details the ways in which it is different:
step adds a lot of complexity, because the events system cannot step adds a lot of complexity, because the events system cannot
make queries to the database directly. make queries to the database directly.
- Trigger any other deferred work caused by the current message, - Trigger any other deferred work caused by the current message,
e.g. [outgoing webhooks](https://zulip.com/api/outgoing-webhooks) e.g., [outgoing webhooks](https://zulip.com/api/outgoing-webhooks)
or embedded bots. or embedded bots.
- Every query is designed to be a bulk query; we carefully - Every query is designed to be a bulk query; we carefully
unit-test this system for how many database and memcached queries unit-test this system for how many database and memcached queries
@ -146,7 +146,7 @@ messages.
is passed two special parameters that clients not implementing local is passed two special parameters that clients not implementing local
echo don't use: `queue_id` and `local_id`. The `queue_id` is the ID echo don't use: `queue_id` and `local_id`. The `queue_id` is the ID
of the client's event queue; here, it is used just as a unique of the client's event queue; here, it is used just as a unique
identifier for the specific client (e.g. a browser tab) that sent identifier for the specific client (e.g., a browser tab) that sent
the message. And the `local_id` is, by the construction above, a the message. And the `local_id` is, by the construction above, a
unique value within that namespace identifying the message. unique value within that namespace identifying the message.
- The `do_send_messages` backend code path includes the `queue_id` and - The `do_send_messages` backend code path includes the `queue_id` and

View File

@ -29,7 +29,7 @@ Zulip uses the [Django settings
system](https://docs.djangoproject.com/en/5.0/topics/settings/), which system](https://docs.djangoproject.com/en/5.0/topics/settings/), which
means that the settings files are Python programs that set a lot of means that the settings files are Python programs that set a lot of
variables with all-capital names like `EMAIL_GATEWAY_PATTERN`. You can variables with all-capital names like `EMAIL_GATEWAY_PATTERN`. You can
access these anywhere in the Zulip Django code using e.g.: access these anywhere in the Zulip Django code using e.g.,:
```python ```python
from django.conf import settings from django.conf import settings
@ -37,7 +37,7 @@ print(settings.EMAIL_GATEWAY_PATTERN)
``` ```
Additionally, if you need to access a Django setting in a shell Additionally, if you need to access a Django setting in a shell
script (or just on the command line for debugging), you can use e.g.: script (or just on the command line for debugging), you can use e.g.,:
```console ```console
$ ./scripts/get-django-setting EMAIL_GATEWAY_PATTERN $ ./scripts/get-django-setting EMAIL_GATEWAY_PATTERN
@ -55,7 +55,7 @@ In a production environment, we have:
administrator-facing settings file for Zulip. It contains all the administrator-facing settings file for Zulip. It contains all the
server-specific settings, such as how to send outgoing email, the server-specific settings, such as how to send outgoing email, the
hostname of the PostgreSQL database, etc., but does not contain any hostname of the PostgreSQL database, etc., but does not contain any
secrets (e.g. passwords, secret API keys, cryptographic keys, etc.). secrets (e.g., passwords, secret API keys, cryptographic keys, etc.).
The way we generally do settings that can be controlled with shell The way we generally do settings that can be controlled with shell
access to a Zulip server is to put a default in access to a Zulip server is to put a default in
`zproject/default_settings.py`, and then override it here. As this `zproject/default_settings.py`, and then override it here. As this
@ -91,7 +91,7 @@ In a production environment, we have:
- `zproject/computed_settings.py` contains all the settings that are - `zproject/computed_settings.py` contains all the settings that are
constant for all Zulip installations or computed as a function of constant for all Zulip installations or computed as a function of
`zproject/configured_settings.py` (e.g. configuration for logging, `zproject/configured_settings.py` (e.g., configuration for logging,
static assets, middleware, etc.). static assets, middleware, etc.).
In a development environment, we have `zproject/settings.py`, and In a development environment, we have `zproject/settings.py`, and
@ -106,7 +106,7 @@ additionally:
features like [authentication features like [authentication
options](../development/authentication.md) that require secrets to options](../development/authentication.md) that require secrets to
work. It is also used to set certain settings that in production work. It is also used to set certain settings that in production
belong in `/etc/zulip/settings.py`, e.g. `SOCIAL_AUTH_GITHUB_KEY`. belong in `/etc/zulip/settings.py`, e.g., `SOCIAL_AUTH_GITHUB_KEY`.
You can see a full list with `git grep development_only=True`, or You can see a full list with `git grep development_only=True`, or
add additional settings of this form if needed. add additional settings of this form if needed.
@ -152,11 +152,11 @@ want those settings.
### Testing non-default settings ### Testing non-default settings
You can write tests for settings using e.g. You can write tests for settings using e.g.,
`with self.settings(TERMS_OF_SERVICE=None)`. However, this only works `with self.settings(TERMS_OF_SERVICE=None)`. However, this only works
for settings which are checked at runtime, not settings which are only for settings which are checked at runtime, not settings which are only
accessed in initialization of Django (or Zulip) internals accessed in initialization of Django (or Zulip) internals
(e.g. `DATABASES`). See the [Django docs on overriding settings in (e.g., `DATABASES`). See the [Django docs on overriding settings in
tests][django-test-settings] for more details. tests][django-test-settings] for more details.
[django-test-settings]: https://docs.djangoproject.com/en/5.0/topics/testing/tools/#overriding-settings [django-test-settings]: https://docs.djangoproject.com/en/5.0/topics/testing/tools/#overriding-settings

View File

@ -172,7 +172,7 @@ is the extent of our checking.
Finally, we're checking line length in Python code (and hope to extend Finally, we're checking line length in Python code (and hope to extend
this to other parts of the codebase soon). You can use this to other parts of the codebase soon). You can use
`#ignorelinelength` for special cases where a very long line makes `#ignorelinelength` for special cases where a very long line makes
sense (e.g. a link in a comment to an extremely long URL). sense (e.g., a link in a comment to an extremely long URL).
#### Python code #### Python code

View File

@ -160,7 +160,7 @@ So, to summarize our approach to integration vs. unit testing:
HTTP response and the internal state of the server following the request HTTP response and the internal state of the server following the request
are both correct. are both correct.
- Following the end-to-end principle in system design, where possible - Following the end-to-end principle in system design, where possible
we write tests that execute a complete flow (e.g. registering a new we write tests that execute a complete flow (e.g., registering a new
Zulip account) rather than testing the implementations of individual Zulip account) rather than testing the implementations of individual
functions. functions.
- We invest in the performance of Zulip in part to give users a great - We invest in the performance of Zulip in part to give users a great
@ -214,7 +214,7 @@ test conditions.
The benefit of this strategy is that you guarantee that the test setup The benefit of this strategy is that you guarantee that the test setup
only differs as intended: Done well, it helps avoid the otherwise only differs as intended: Done well, it helps avoid the otherwise
extremely common failure mode where a `test_foo_failure` test passes extremely common failure mode where a `test_foo_failure` test passes
for the wrong reason. (E.g. the action fails not because of the for the wrong reason. (e.g., the action fails not because of the
permission check, but because a required HTTP parameter was only added permission check, but because a required HTTP parameter was only added
to an adjacent `test_foo_success`). to an adjacent `test_foo_success`).

View File

@ -121,7 +121,7 @@ Here are some example action methods that tests may use for data setup:
### Testing code that accesses the filesystem ### Testing code that accesses the filesystem
Some tests need to access the filesystem (e.g. `test_upload.py` tests Some tests need to access the filesystem (e.g., `test_upload.py` tests
for `LocalUploadBackend` and the data import tests). Doing for `LocalUploadBackend` and the data import tests). Doing
this correctly requires care to avoid problems like: this correctly requires care to avoid problems like:
@ -142,7 +142,7 @@ To avoid these problems, you can do the following:
avoid conflicts with other tests run later by the same test process. avoid conflicts with other tests run later by the same test process.
Our common testing infrastructure handles some of this for you, Our common testing infrastructure handles some of this for you,
e.g. it replaces `settings.LOCAL_UPLOADS_DIR` for each test process e.g., it replaces `settings.LOCAL_UPLOADS_DIR` for each test process
with a unique path under `/var/<uuid>/test-backend`. And with a unique path under `/var/<uuid>/test-backend`. And
`UploadSerializeMixin` manages some of the cleanup work for `UploadSerializeMixin` manages some of the cleanup work for
`test_upload.py`. `test_upload.py`.
@ -252,7 +252,7 @@ foo.qux = 42
``` ```
is _not_ going to throw any errors. Our mock silently accepts all these calls and records them. is _not_ going to throw any errors. Our mock silently accepts all these calls and records them.
`Mock` also implements methods for us to access and assert its records, e.g. `Mock` also implements methods for us to access and assert its records, e.g.,
```python ```python
foo.bar.assert_called_with('quux') foo.bar.assert_called_with('quux')

View File

@ -274,7 +274,7 @@ These instructions assume you're using the Vagrant development environment.
1. In the `Configure Node.js Remote Interpreter`, window select `Vagrant` 1. In the `Configure Node.js Remote Interpreter`, window select `Vagrant`
1. Wait for WebStorm to connect to Vagrant. This will be displayed 1. Wait for WebStorm to connect to Vagrant. This will be displayed
by the `Vagrant Host URL` section updating to contain the Vagrant by the `Vagrant Host URL` section updating to contain the Vagrant
SSH URL, e.g. `ssh://vagrant@127.0.0.1:2222`. SSH URL, e.g., `ssh://vagrant@127.0.0.1:2222`.
1. **Set the `Node.js interpreter path` to `/usr/local/bin/node`** 1. **Set the `Node.js interpreter path` to `/usr/local/bin/node`**
1. Hit `OK` 2 times to get back to the `Run/Debug Configurations` window. 1. Hit `OK` 2 times to get back to the `Run/Debug Configurations` window.
1. Under `Working Directory` select the root `zulip` directory. 1. Under `Working Directory` select the root `zulip` directory.
@ -288,7 +288,7 @@ Congratulations! You've now set up the integration.
To use Webstorm to debug a given node test file, do the following: To use Webstorm to debug a given node test file, do the following:
1. Under `Application parameters` choose the node test file that you 1. Under `Application parameters` choose the node test file that you
are trying to test (e.g. `web/tests/message_store.test.js`). are trying to test (e.g., `web/tests/message_store.test.js`).
1. Under `Path Mappings`, set `Project Root` to `/srv/zulip` 1. Under `Path Mappings`, set `Project Root` to `/srv/zulip`
(i.e. where the `zulip` Git repository is mounted in the Vagrant guest). (i.e. where the `zulip` Git repository is mounted in the Vagrant guest).
1. Use the WebStorm debugger; see [this overview][webstorm-debugging] 1. Use the WebStorm debugger; see [this overview][webstorm-debugging]

View File

@ -3,8 +3,8 @@
While our [node test suite](testing-with-node.md) is the While our [node test suite](testing-with-node.md) is the
preferred way to test most frontend code because they are easy to preferred way to test most frontend code because they are easy to
write and maintain, some code is best tested in a real browser, either write and maintain, some code is best tested in a real browser, either
because of navigation (E.g. login) or because we want to verify the because of navigation (e.g., login) or because we want to verify the
interaction between Zulip logic and browser behavior (E.g. copy/paste, interaction between Zulip logic and browser behavior (e.g., copy/paste,
keyboard shortcuts, etc.). keyboard shortcuts, etc.).
## Running tests ## Running tests
@ -74,7 +74,7 @@ integration](continuous-integration.md):
affects any of the selectors used in the tests? If so, the test may affects any of the selectors used in the tests? If so, the test may
just need to be updated for your changes. just need to be updated for your changes.
- Does the test fail deterministically when you run it locally using - Does the test fail deterministically when you run it locally using
E.g. `./tools/test-js-with-puppeteer compose.ts`? If so, you can e.g., `./tools/test-js-with-puppeteer compose.ts`? If so, you can
iteratively debug to see the failure. iteratively debug to see the failure.
- Does the test fail nondeterministically? If so, the problem is - Does the test fail nondeterministically? If so, the problem is
likely that a `waitForSelector` statement is either missing or not likely that a `waitForSelector` statement is either missing or not
@ -141,7 +141,7 @@ notes above:
`main`. `main`.
- With black-box browser tests like these, it's very important to write your code - With black-box browser tests like these, it's very important to write your code
to wait for browser's UI to update before taking any action that to wait for browser's UI to update before taking any action that
assumes the last step was processed by the browser (E.g. after you assumes the last step was processed by the browser (e.g., after you
click on a user's avatar, you need an explicit wait for the profile click on a user's avatar, you need an explicit wait for the profile
popover to appear before you can try to click on a menu item in that popover to appear before you can try to click on a menu item in that
popover). This means that before essentially every action in your popover). This means that before essentially every action in your

View File

@ -40,7 +40,7 @@ typically involve running subsets of the tests with commands like these:
``` ```
The commands above will all run in just a few seconds. Many more The commands above will all run in just a few seconds. Many more
useful options are discussed in each tool's documentation (e.g. useful options are discussed in each tool's documentation (e.g.,
`./tools/test-backend --help`). `./tools/test-backend --help`).
## Major test suites ## Major test suites
@ -117,7 +117,7 @@ reasons:
As a result, Zulip's major test suites should never access the As a result, Zulip's major test suites should never access the
Internet directly. Since code in Zulip does need to access the Internet directly. Since code in Zulip does need to access the
Internet (e.g. to access various third-party APIs), this means that Internet (e.g., to access various third-party APIs), this means that
the Zulip tests use mocking to basically hardcode (for the purposes of the Zulip tests use mocking to basically hardcode (for the purposes of
the test) what responses should be used for any outgoing Internet the test) what responses should be used for any outgoing Internet
requests that Zulip would make in the code path being tested. requests that Zulip would make in the code path being tested.

View File

@ -71,7 +71,7 @@ Our plan is to order which modules we migrate carefully, starting with
those that: those that:
- Appear frequently as reverse dependencies of other modules - Appear frequently as reverse dependencies of other modules
(e.g. `people.js`). These are most valuable to do first because (e.g., `people.js`). These are most valuable to do first because
then we have types on the data being interacted with by other then we have types on the data being interacted with by other
modules when we migrate those. modules when we migrate those.
- Don't have large open pull requests (to avoid merge conflicts); one - Don't have large open pull requests (to avoid merge conflicts); one
@ -82,11 +82,11 @@ those that:
When migrating a module, we want to be especially thoughtful about When migrating a module, we want to be especially thoughtful about
putting together a commit structure that makes mistakes unlikely and putting together a commit structure that makes mistakes unlikely and
the changes easy to verify. E.g.: the changes easy to verify. E.g.,:
- First a commit that just converts the language to TypeScript adding - First a commit that just converts the language to TypeScript adding
types. The result may potentially have some violations of the types. The result may potentially have some violations of the
long-term style we want (e.g. not using `const`). Depending on how long-term style we want (e.g., not using `const`). Depending on how
we're handling linting, we set some override eslint rules at the top we're handling linting, we set some override eslint rules at the top
of the module at this stage so CI still passes. of the module at this stage so CI still passes.
- Then a commit just migrating use of `var` to `const/let` without - Then a commit just migrating use of `var` to `const/let` without

View File

@ -30,7 +30,7 @@ Message 可直译为“消息”、“信息”等,两者皆可,这里统一
- Stream - **频道** - Stream - **频道**
There were several other optional translations, e.g. "群组(Group)", " There were several other optional translations, e.g., "群组(Group)", "
主题(Subject)", and "栏目(Column)". The "频道(Channel)" is in use now, 主题(Subject)", and "栏目(Column)". The "频道(Channel)" is in use now,
which is inspired by the chat "Channel" in the game Ingress. Since which is inspired by the chat "Channel" in the game Ingress. Since
"Stream" can be "Created/Deleted" or "Subscribed/Unsubscribed", "Stream" can be "Created/Deleted" or "Subscribed/Unsubscribed",
@ -96,7 +96,7 @@ The perfect tense subscribed/unsubscribed is translated as "已订阅/已
scope of ...". The two words share the common meanings. scope of ...". The two words share the common meanings.
2. "筛选" is a common computer phrase and has been well 2. "筛选" is a common computer phrase and has been well
accepted by public, e.g. the "Filter(筛选)" feature in Microsoft accepted by public, e.g., the "Filter(筛选)" feature in Microsoft
Excel. Excel.
In addition, in the searching context "Narrow to ..." is not In addition, in the searching context "Narrow to ..." is not

View File

@ -57,9 +57,9 @@ the reader and remember to capitalize _Du_.
**Prefer imperative over constructions with auxiliary verbs.** **Prefer imperative over constructions with auxiliary verbs.**
For instructions, try to use the imperative (e.g. _"Gehe auf die Seite"_ - For instructions, try to use the imperative (e.g., _"Gehe auf die Seite"_ -
_"Go to the page"_) instead of constructions with auxiliary verbs _"Go to the page"_) instead of constructions with auxiliary verbs
(e.g. _"Du musst auf die Seite ... gehen"_ - _"You have to go the page ..."_). (e.g., _"Du musst auf die Seite ... gehen"_ - _"You have to go the page ..."_).
This keeps the phrases short, less stiff and avoids unnecessary addressing This keeps the phrases short, less stiff and avoids unnecessary addressing
of the reader. of the reader.
@ -69,14 +69,14 @@ of the reader.
To be consistent with other online platforms, use continuous labels for buttons, To be consistent with other online platforms, use continuous labels for buttons,
item titles, etc. with verbs in infinitive form, item titles, etc. with verbs in infinitive form,
e.g. _Manage streams_ - _Kanäle verwalten_ instead of _Verwalte Kanäle_. e.g., _Manage streams_ - _Kanäle verwalten_ instead of _Verwalte Kanäle_.
### Concatenation of words ### Concatenation of words
**Try to avoid it.** **Try to avoid it.**
German is famous for its concatenations of nouns German is famous for its concatenations of nouns
(e.g. _Heizölrückstoßdämpfung_, which means _fuel oil recoil attenuation_). (e.g., _Heizölrückstoßdämpfung_, which means _fuel oil recoil attenuation_).
For the sake of correct rendering and simplicity, you should try to avoid such For the sake of correct rendering and simplicity, you should try to avoid such
concatenations whenever possible, since they can break the layout of the Zulip concatenations whenever possible, since they can break the layout of the Zulip
frontend. Try to stick to a maximum length of 20 characters and follow your frontend. Try to stick to a maximum length of 20 characters and follow your
@ -99,7 +99,7 @@ so you should not be afraid of using them if they provide an advantage over
the German equivalent. Take the following two examples as a reference: the German equivalent. Take the following two examples as a reference:
- Translating _Bot_: Use _Bot_, as a completely accurate German - Translating _Bot_: Use _Bot_, as a completely accurate German
equivalent **doesn't** exist (e.g. _Roboter_) and the term _Bot_ is not equivalent **doesn't** exist (e.g., _Roboter_) and the term _Bot_ is not
unknown to German speakers. unknown to German speakers.
### Special characters ### Special characters
@ -133,7 +133,7 @@ Make sure to not walk into such a trap.
- Balance common verbs and nouns with specific IT-related translations - Balance common verbs and nouns with specific IT-related translations
of English terms - this can be tricky, try to check how other resources of English terms - this can be tricky, try to check how other resources
were translated (e.g. Gmail, Microsoft websites, Facebook) to decide were translated (e.g., Gmail, Microsoft websites, Facebook) to decide
what wouldn't sound awkward / rude in German. what wouldn't sound awkward / rude in German.
- For additional translation information, feel free to check out - For additional translation information, feel free to check out
@ -152,7 +152,7 @@ _"Nachricht" (Facebook, WhatsApp, Transifex)_
- Direct Message (DM), Direct Messages (DMs) - **Direktnachricht (DM), Direktnachrichten (DMs)** - Direct Message (DM), Direct Messages (DMs) - **Direktnachricht (DM), Direktnachrichten (DMs)**
While we try to avoid concatenating words whenever possible, "Direktnachricht" is used While we try to avoid concatenating words whenever possible, "Direktnachricht" is used
by many other platforms (e.g. X/Twitter, Slack, Discord). by many other platforms (e.g., X/Twitter, Slack, Discord).
Use _DM_ with its plural form _DMs_ rather than DN/DNs in line with other services. Use _DM_ with its plural form _DMs_ rather than DN/DNs in line with other services.
_"Direktnachricht" (X/Twitter, Slack)_ _"Direktnachricht" (X/Twitter, Slack)_
@ -272,7 +272,7 @@ _"Deabonnieren" (YouTube, Transifex)_
Transifex has two different translations for "Narrow to" - Transifex has two different translations for "Narrow to" -
"Schränke auf ... ein." and "Begrenze auf ... ." Both sound a bit strange to a "Schränke auf ... ein." and "Begrenze auf ... ." Both sound a bit strange to a
German speaker, since they would expect grammatically correct sentences when German speaker, since they would expect grammatically correct sentences when
using the imperative (e.g. "Schränke diesen Stream ein auf ... .") Since this using the imperative (e.g., "Schränke diesen Stream ein auf ... .") Since this
would be too long for many labels, the infinitive "begrenzen auf" is preferable. would be too long for many labels, the infinitive "begrenzen auf" is preferable.
"einschränken auf" sounds equally good, but Transifex shows more use cases for "einschränken auf" sounds equally good, but Transifex shows more use cases for
"begrenzen auf". "begrenzen auf".
@ -282,7 +282,7 @@ _"Schränke auf ... ein." (Transifex) "Begrenze auf ... ." (Transifex)_
- Filter - **Filtern** - Filter - **Filtern**
A direct translation is fine here. Watch out to to use the infinitive instead A direct translation is fine here. Watch out to to use the infinitive instead
of the imperative, e.g. "Nachrichten filtern" instead of "Filtere Nachrichten". of the imperative, e.g., "Nachrichten filtern" instead of "Filtere Nachrichten".
_"Filtern" (Thunderbird, LinkedIn)_ _"Filtern" (Thunderbird, LinkedIn)_

View File

@ -3,7 +3,7 @@
- Use _आप_ as the second-person pronoun. Don't use तुम or तू. - Use _आप_ as the second-person pronoun. Don't use तुम or तू.
(See [chat thread](https://chat.zulip.org/#narrow/channel/58-translation/topic/Hindi.20Translation/near/1762384).) (See [chat thread](https://chat.zulip.org/#narrow/channel/58-translation/topic/Hindi.20Translation/near/1762384).)
- Imperative, active, and continuous verbs, e.g. _manage streams_ - - Imperative, active, and continuous verbs, e.g., _manage streams_ -
_चैनल प्रबंधित करें_, not _चैनल प्रबंधन_. _चैनल प्रबंधित करें_, not _चैनल प्रबंधन_.
- Warm and friendly phrasing whenever appropriate. - Warm and friendly phrasing whenever appropriate.
@ -12,7 +12,7 @@
- Balance common verbs and nouns with specific IT-related translations - Balance common verbs and nouns with specific IT-related translations
of English terms - this can be tricky, try to check how other of English terms - this can be tricky, try to check how other
resources were translated (e.g. Gmail, Microsoft websites, Facebook) resources were translated (e.g., Gmail, Microsoft websites, Facebook)
to decide what wouldn't sound awkward / rude in Hindi. to decide what wouldn't sound awkward / rude in Hindi.
Some terms are very tricky to translate, so be sure to communicate Some terms are very tricky to translate, so be sure to communicate

View File

@ -13,7 +13,7 @@ principles are important in how we think about internationalization:
tagged for translation in both [HTML templates](#html-templates) and tagged for translation in both [HTML templates](#html-templates) and
code, and our linters attempt to enforce this. There are some code, and our linters attempt to enforce this. There are some
exceptions: we don't tag strings in Zulip's landing pages exceptions: we don't tag strings in Zulip's landing pages
(e.g. /features/) and other documentation (e.g. /help/) for (e.g., /features/) and other documentation (e.g., /help/) for
translation at this time (though we do aim for those pages to be translation at this time (though we do aim for those pages to be
usable with tools like Google Translate). usable with tools like Google Translate).
- Translating all the strings in Zulip for a language and maintaining - Translating all the strings in Zulip for a language and maintaining
@ -41,12 +41,12 @@ their style guidelines.
There are a few critical details about human language that are important There are a few critical details about human language that are important
to understand when implementing an internationalized application: to understand when implementing an internationalized application:
- **Punctuation** varies between languages (e.g. Japanese doesn't use - **Punctuation** varies between languages (e.g., Japanese doesn't use
`.`s at the end of sentences). This means that you should always `.`s at the end of sentences). This means that you should always
include end-of-sentence symbols like `.` and `?` inside the include end-of-sentence symbols like `.` and `?` inside the
to-be-translated strings, so that translators can correctly to-be-translated strings, so that translators can correctly
translate the content. translate the content.
- **Word order** varies between languages (e.g. some languages put - **Word order** varies between languages (e.g., some languages put
subjects before verbs, others the other way around). This means subjects before verbs, others the other way around). This means
that **concatenating translatable strings** produces broken results that **concatenating translatable strings** produces broken results
(more details with examples are below). (more details with examples are below).
@ -63,7 +63,7 @@ to understand when implementing an internationalized application:
find your string. find your string.
There's a lot of other interesting differences that are important for There's a lot of other interesting differences that are important for
i18n (e.g. Zulip has a "full name" field rather than "first name" and i18n (e.g., Zulip has a "full name" field rather than "first name" and
"last name" because different cultures order the surnames and given "last name" because different cultures order the surnames and given
names differently), but the above issues are likely to be relevant to names differently), but the above issues are likely to be relevant to
most people working on Zulip. most people working on Zulip.
@ -172,7 +172,7 @@ from django.utils.translation import gettext as _
Zulip expects all the error messages to be translatable as well. To Zulip expects all the error messages to be translatable as well. To
ensure this, the error message passed to `JsonableError` ensure this, the error message passed to `JsonableError`
should always be a literal string enclosed by `_()` should always be a literal string enclosed by `_()`
function, e.g.: function, e.g.,:
```python ```python
JsonableError(_('English text')) JsonableError(_('English text'))
@ -180,7 +180,7 @@ JsonableError(_('English text'))
If you're declaring a user-facing string at top level or in a class, you need to If you're declaring a user-facing string at top level or in a class, you need to
use `gettext_lazy` instead, to ensure that the translation happens at use `gettext_lazy` instead, to ensure that the translation happens at
request-processing time when Django knows what language to use, e.g.: request-processing time when Django knows what language to use, e.g.,:
```python ```python
from zproject.backends import check_password_strength, email_belongs_to_ldap from zproject.backends import check_password_strength, email_belongs_to_ldap

View File

@ -2,22 +2,22 @@
Use semi-formal Polish for translation, some specifics: Use semi-formal Polish for translation, some specifics:
- Informal "you" (_ty_) instead of more formal approaches (e.g. plural - Informal "you" (_ty_) instead of more formal approaches (e.g., plural
"you" (_wy_), using any formal titles like _Państwo_, _Pan/Pani_). "you" (_wy_), using any formal titles like _Państwo_, _Pan/Pani_).
- Gender-neutral forms of verbs, e.g. _unsubscribed_ - _odsubskrybowano_, - Gender-neutral forms of verbs, e.g., _unsubscribed_ - _odsubskrybowano_,
not \*odsubskrybowałeś". not \*odsubskrybowałeś".
- Imperative, active and continuous verbs, e.g. _manage streams_ - - Imperative, active and continuous verbs, e.g., _manage streams_ -
_zarządzaj kanałami_, not _zarządź kanałami_. _zarządzaj kanałami_, not _zarządź kanałami_.
- Not using reflexive _się_, e.g. _log out_ would be simply _wyloguj_, - Not using reflexive _się_, e.g., _log out_ would be simply _wyloguj_,
not _wyloguj się_. not _wyloguj się_.
- Warm and friendly phrasing whenever appropriate. - Warm and friendly phrasing whenever appropriate.
- No slang or regional phrases that could be unclear or too informal, - No slang or regional phrases that could be unclear or too informal,
e.g. _zajawka_. e.g., _zajawka_.
- Consistent usage of Zulip-specific terms and common verbs for - Consistent usage of Zulip-specific terms and common verbs for
actions, even if it means repeating - this is one of the key aspects actions, even if it means repeating - this is one of the key aspects
@ -30,7 +30,7 @@ Use semi-formal Polish for translation, some specifics:
- Balance common verbs and nouns with specific IT-related translations - Balance common verbs and nouns with specific IT-related translations
of English terms - this can be tricky, try to check how other of English terms - this can be tricky, try to check how other
resources were translated (e.g. Gmail, Microsoft websites, Facebook) resources were translated (e.g., Gmail, Microsoft websites, Facebook)
to decide what wouldn't sound awkward in Polish. to decide what wouldn't sound awkward in Polish.
Some terms are very tricky to translate, so be sure to communicate Some terms are very tricky to translate, so be sure to communicate
@ -69,7 +69,7 @@ and _dostosowanie do potrzeb klienta_ is too long
example: example:
You can personalize Zulip in many ways, e.g. by pinning certain streams. You can personalize Zulip in many ways, e.g., by pinning certain streams.
> Możesz spersonalizować Zulipa na wiele sposobów, np. przypinając niektóre kanały. > Możesz spersonalizować Zulipa na wiele sposobów, np. przypinając niektóre kanały.

View File

@ -3,14 +3,14 @@
Use informal Spanish for translation: Use informal Spanish for translation:
- Informal "you" (_tú_) instead of formal form _usted_. Many top software - Informal "you" (_tú_) instead of formal form _usted_. Many top software
companies (e.g. Google) use the informal one, because it's much more common in companies (e.g., Google) use the informal one, because it's much more common in
the daily language and avoids making translations look like they were written the daily language and avoids making translations look like they were written
by machines. by machines.
- Imperative, active, and continuous verbs, e.g. _manage streams_ - - Imperative, active, and continuous verbs, e.g., _manage streams_ -
_gestionar canales_, not _gestión de canales_. _gestionar canales_, not _gestión de canales_.
- Not using reflexive _se_ e.g. _log out_ should be _salir_, not _salirse_, - Not using reflexive _se_ e.g., _log out_ should be _salir_, not _salirse_,
whenever the infinitive form is possible without making the translation whenever the infinitive form is possible without making the translation
awkward. awkward.
@ -20,7 +20,7 @@ Use informal Spanish for translation:
- Balance common verbs and nouns with specific IT-related translations - Balance common verbs and nouns with specific IT-related translations
of English terms - this can be tricky, try to check how other of English terms - this can be tricky, try to check how other
resources were translated (e.g. Gmail, Microsoft websites, Facebook) resources were translated (e.g., Gmail, Microsoft websites, Facebook)
to decide what wouldn't sound awkward / rude in Spanish. to decide what wouldn't sound awkward / rude in Spanish.
- Latest RAE rule ("solo" should - Latest RAE rule ("solo" should

View File

@ -32,7 +32,7 @@ Zulip:
:::{note} :::{note}
Unless you plan to contribute country-specific translations, do not Unless you plan to contribute country-specific translations, do not
select a country-specific language in the **Languages** menu when you sign select a country-specific language in the **Languages** menu when you sign
up. E.g. use **English (United Kingdom)** if you plan to translate Zulip up. E.g., use **English (United Kingdom)** if you plan to translate Zulip
into UK English, but select **Russian** rather than **Russian (Russia)** for into UK English, but select **Russian** rather than **Russian (Russia)** for
general Russian translations. general Russian translations.
::: :::
@ -132,13 +132,13 @@ There are a few ways to see your translations in the Zulip UI:
- If your system has languages configured in your OS/browser, Zulip's - If your system has languages configured in your OS/browser, Zulip's
portico (logged-out) pages will automatically use your configured portico (logged-out) pages will automatically use your configured
language. Note that we only tag for translation strings in pages language. Note that we only tag for translation strings in pages
that individual users need to use (e.g. `/login/`, `/register/`, that individual users need to use (e.g., `/login/`, `/register/`,
etc.), not marketing pages like `/features/`. etc.), not marketing pages like `/features/`.
- In case you need to understand how the above interact, Zulip figures - In case you need to understand how the above interact, Zulip figures
out the language the user requests in a browser using the following out the language the user requests in a browser using the following
prioritization (mostly copied from the Django docs): prioritization (mostly copied from the Django docs):
1. It looks for the language code as a URL prefix (e.g. `/de/login/`). 1. It looks for the language code as a URL prefix (e.g., `/de/login/`).
1. It looks for the cookie named 'django_language'. You can set a 1. It looks for the cookie named 'django_language'. You can set a
different name through the `LANGUAGE_COOKIE_NAME` setting. different name through the `LANGUAGE_COOKIE_NAME` setting.
1. It looks for the `Accept-Language` HTTP header in the HTTP request 1. It looks for the `Accept-Language` HTTP header in the HTTP request
@ -180,7 +180,7 @@ translation:
### Translation style guides ### Translation style guides
We maintain translation style guides for Zulip, giving guidance on how We maintain translation style guides for Zulip, giving guidance on how
Zulip should be translated into specific languages (e.g. what word to Zulip should be translated into specific languages (e.g., what word to
translate words like "channel" to), with reasoning, so that future translate words like "channel" to), with reasoning, so that future
translators can understand and preserve those decisions: translators can understand and preserve those decisions:
@ -223,6 +223,6 @@ The Zulip test suite enforces these capitalization guidelines in the
web app codebase [in our test web app codebase [in our test
suite](../testing/testing.md#other-test-suites) suite](../testing/testing.md#other-test-suites)
(`./tools/check-capitalization`; `tools/lib/capitalization.py` has (`./tools/check-capitalization`; `tools/lib/capitalization.py` has
some exclude lists, e.g. `IGNORED_PHRASES`). some exclude lists, e.g., `IGNORED_PHRASES`).
[translation-channel]: https://chat.zulip.org/#narrow/channel/58-translation [translation-channel]: https://chat.zulip.org/#narrow/channel/58-translation

View File

@ -3,10 +3,10 @@
Use semi-formal Urdu for translation: Use semi-formal Urdu for translation:
- Formal "you" (_آپ_) instead of informal form _تم_. Many top software - Formal "you" (_آپ_) instead of informal form _تم_. Many top software
companies (e.g. Google, Facebook, Microsoft) use the formal one, because it's typically companies (e.g., Google, Facebook, Microsoft) use the formal one, because it's typically
considered rude to use the informal one without an established acquaintance with someone. considered rude to use the informal one without an established acquaintance with someone.
- Imperative, active, and continuous verbs, e.g. _manage streams_ - - Imperative, active, and continuous verbs, e.g., _manage streams_ -
_سٹریمس کی رہنمائ کریں_, not _سٹریمس کی رہنمائ_. _سٹریمس کی رہنمائ کریں_, not _سٹریمس کی رہنمائ_.
- Warm and friendly phrasing whenever appropriate. - Warm and friendly phrasing whenever appropriate.
@ -15,7 +15,7 @@ Use semi-formal Urdu for translation:
- Balance common verbs and nouns with specific IT-related translations - Balance common verbs and nouns with specific IT-related translations
of English terms - this can be tricky, try to check how other of English terms - this can be tricky, try to check how other
resources were translated (e.g. Gmail, Microsoft websites, Facebook) resources were translated (e.g., Gmail, Microsoft websites, Facebook)
to decide what wouldn't sound awkward/rude in Urdu. to decide what wouldn't sound awkward/rude in Urdu.
Some terms are very tricky to translate, so be sure to communicate Some terms are very tricky to translate, so be sure to communicate

View File

@ -117,7 +117,7 @@ includes both views that serve HTML (new pages on Zulip) as well as new
API endpoints that serve JSON-formatted data. API endpoints that serve JSON-formatted data.
**Testing:** At the very least, add a test of your event data flowing **Testing:** At the very least, add a test of your event data flowing
through the system in `test_events.py` and an API test (e.g. for a through the system in `test_events.py` and an API test (e.g., for a
Realm setting, in `test_realm.py`). Realm setting, in `test_realm.py`).
### Frontend changes ### Frontend changes
@ -506,7 +506,7 @@ framework is `do_set_realm_property_test`, and in `test_realm.py`, it is
`do_test_realm_update_api`. `do_test_realm_update_api`.
One still needs to add a test for whether the setting actually One still needs to add a test for whether the setting actually
controls the feature it is supposed to control, however (e.g. for this controls the feature it is supposed to control, however (e.g., for this
example feature, whether sending a message without a topic fails with example feature, whether sending a message without a topic fails with
the setting enabled). the setting enabled).

View File

@ -19,7 +19,7 @@ Linux/macOS environments (Unix shells). You can also use a tool, for example
When searching Google, or Zulip's docs, you'll find commands that begin When searching Google, or Zulip's docs, you'll find commands that begin
with a dollar sign `$` or a dollar sign preceded by some text with a dollar sign `$` or a dollar sign preceded by some text
(e.g. `(venv)john@laptop:~$`). (e.g., `(venv)john@laptop:~$`).
This is called the **prompt**, and it's only an indicator that the shell is This is called the **prompt**, and it's only an indicator that the shell is
awaiting new orders. The prompt can contain useful information, let's look awaiting new orders. The prompt can contain useful information, let's look
@ -168,7 +168,7 @@ the shell provides two different separators:
Sometimes you end up with a very long command, that is hard to read and may Sometimes you end up with a very long command, that is hard to read and may
be unclear. This is a problem, especially if you want to share that command, be unclear. This is a problem, especially if you want to share that command,
e.g. in a documentation file. e.g., in a documentation file.
In those cases, you can use a backslash at the end of each line, to inform the In those cases, you can use a backslash at the end of each line, to inform the
shell "wait, there's more on the next line". shell "wait, there's more on the next line".
@ -328,7 +328,7 @@ There are many more commands in the shell, besides the ones explained in this
file. file.
[Here](https://www.git-tower.com/blog/command-line-cheat-sheet/) you can find [Here](https://www.git-tower.com/blog/command-line-cheat-sheet/) you can find
a simple yet useful cheatsheet, created by Tower, that could help you a simple yet useful cheatsheet, created by Tower, that could help you
understand and remember what other common commands do (e.g. `ls`). understand and remember what other common commands do (e.g., `ls`).
## Git ## Git

View File

@ -193,7 +193,7 @@ REQ also helps us with request variable validation. For example:
not automatically marshall the input from JSON). not automatically marshall the input from JSON).
- Since there is no need to JSON-encode strings, usually simply - Since there is no need to JSON-encode strings, usually simply
`my_string=REQ()` is correct. One can pass e.g. `my_string=REQ()` is correct. One can pass e.g.,
`str_validator=check_string_in(...)` where one wants to run a `str_validator=check_string_in(...)` where one wants to run a
validator on the value of a string. validator on the value of a string.
@ -252,7 +252,7 @@ code (i.e. all 400 type errors are thrown there), and the actions code
is responsible for atomically executing the change (this is usually is responsible for atomically executing the change (this is usually
signalled by having the actions function have a name starting with signalled by having the actions function have a name starting with
`do_`. So in most cases, errors in an actions function will be the `do_`. So in most cases, errors in an actions function will be the
result of an operational problem (e.g. lost connection to the result of an operational problem (e.g., lost connection to the
database) and lead to a 500 error. If an actions function is database) and lead to a 500 error. If an actions function is
responsible for validation as well, it should have a name starting responsible for validation as well, it should have a name starting
with `check_`. with `check_`.