mirror of
https://github.com/zulip/zulip.git
synced 2025-10-24 00:23:49 +00:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd9847ffcb | ||
|
|
2bca1d4ef0 | ||
|
|
871fdddf86 | ||
|
|
bf4e01eb02 | ||
|
|
92ea9a0729 | ||
|
|
a36cb9b247 | ||
|
|
da71f67f85 | ||
|
|
5518abe1d6 | ||
|
|
b34848447e | ||
|
|
3d5c994a32 | ||
|
|
cfa2c6bf37 | ||
|
|
3d243a457f | ||
|
|
e414036eb3 | ||
|
|
9ec154bbe8 | ||
|
|
da479c3613 | ||
|
|
23d8f6e6b0 | ||
|
|
d929ad0122 | ||
|
|
429d0f9728 | ||
|
|
c905915055 | ||
|
|
b238d0e75e | ||
|
|
a4ebdac521 | ||
|
|
bdd6e1fabe | ||
|
|
d120ee25b4 | ||
|
|
14938fbf4c | ||
|
|
8babe17f8f | ||
|
|
724e1d3002 | ||
|
|
a474a08195 | ||
|
|
a48bbef766 | ||
|
|
71c5632e07 | ||
|
|
498b6e4670 | ||
|
|
925ddc28f4 | ||
|
|
3651b8d254 | ||
|
|
90d3cbceed |
@@ -54,7 +54,7 @@ author = 'The Zulip Team'
|
|||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '1.9'
|
version = '1.9'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '1.9.0'
|
release = '1.9.1'
|
||||||
|
|
||||||
# This allows us to insert a warning that appears only on an unreleased
|
# This allows us to insert a warning that appears only on an unreleased
|
||||||
# version, e.g. to say that something is likely to have changed.
|
# version, e.g. to say that something is likely to have changed.
|
||||||
|
|||||||
@@ -7,6 +7,19 @@ All notable changes to the Zulip server are documented in this file.
|
|||||||
This section lists notable unreleased changes; it is generally updated
|
This section lists notable unreleased changes; it is generally updated
|
||||||
in bursts.
|
in bursts.
|
||||||
|
|
||||||
|
### 1.9.1 -- 2018-11-30
|
||||||
|
|
||||||
|
This release is primarily intended to improve the experience for new
|
||||||
|
Zulip installations; it has minimal changes for existing servers.
|
||||||
|
|
||||||
|
- Added support for getting multi-domain certificates with setup-certbot.
|
||||||
|
- Improved various installer error messages and sections of the
|
||||||
|
installation documentation to help avoid for common mistakes.
|
||||||
|
- The Google auth integration now always offers an account chooser.
|
||||||
|
- Fixed buggy handling of avatars in Slack import.
|
||||||
|
- Fixed nginx configuration for mobile API authentication to access uploads.
|
||||||
|
- Updated translation data, including significant new Italian strings.
|
||||||
|
|
||||||
### 1.9.0 -- 2018-11-07
|
### 1.9.0 -- 2018-11-07
|
||||||
|
|
||||||
**Highlights:**
|
**Highlights:**
|
||||||
|
|||||||
@@ -74,20 +74,117 @@ those providers, Zulip's full-text search will be unavailable.
|
|||||||
## Putting the Zulip application behind a reverse proxy
|
## Putting the Zulip application behind a reverse proxy
|
||||||
|
|
||||||
Zulip is designed to support being run behind a reverse proxy server.
|
Zulip is designed to support being run behind a reverse proxy server.
|
||||||
There are few things you need to be careful about when configuring a
|
This section contains notes on the configuration required with
|
||||||
reverse proxy:
|
variable reverse proxy implementations.
|
||||||
|
|
||||||
|
### Installer options
|
||||||
|
|
||||||
|
If your Zulip server will not be on the public Internet, we recommend,
|
||||||
|
installing with the `--self-signed-cert` option (rather than the
|
||||||
|
`--certbot` option), since CertBot requires the server to be on the
|
||||||
|
public Internet.
|
||||||
|
|
||||||
|
#### Configuring Zulip to allow HTTP
|
||||||
|
|
||||||
|
Depending on your environment, you may want the reverse proxy to talk
|
||||||
|
to the Zulip server over HTTP; this can be secure when the Zulip
|
||||||
|
server is not directly exposed to the public Internet.
|
||||||
|
|
||||||
|
After installing the Zulip server as
|
||||||
|
[described above](#installer-options), you can configure Zulip to talk
|
||||||
|
HTTP as follows:
|
||||||
|
|
||||||
|
1. Add the following block to `/etc/zulip/zulip.conf`:
|
||||||
|
|
||||||
|
```
|
||||||
|
[application_server]
|
||||||
|
http_only = true
|
||||||
|
```
|
||||||
|
|
||||||
|
1. As root, run
|
||||||
|
`/home/zulip/deployments/current/scripts/zulip-puppet-apply`. This
|
||||||
|
will convert Zulip's main `nginx` configuration file to allow HTTP
|
||||||
|
instead of HTTPS.
|
||||||
|
|
||||||
|
1. Finally, restart the Zulip server, using
|
||||||
|
`/home/zulip/deployments/current/scripts/restart-server`.
|
||||||
|
|
||||||
|
### nginx configuration
|
||||||
|
|
||||||
|
You can look at our
|
||||||
|
[nginx reverse proxy configuration][nginx-loadbalancer] to see an
|
||||||
|
example of how to do this properly (the various include files are
|
||||||
|
available via the `zulip::nginx` puppet module). Or modify this example:
|
||||||
|
|
||||||
|
```
|
||||||
|
map $http_upgrade $connection_upgrade {
|
||||||
|
default upgrade;
|
||||||
|
'' close;
|
||||||
|
}
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name zulip.example.net;
|
||||||
|
|
||||||
|
ssl on;
|
||||||
|
ssl_certificate /path/to/fullchain-cert.pem;
|
||||||
|
ssl_certificate_key /path/to/private-key.pem;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_read_timeout 20m;
|
||||||
|
proxy_pass https://zulip-upstream-host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Don't forget to update `server_name`, `ssl_certificate`,
|
||||||
|
`ssl_certificate_key` and `proxy_pass` with propper values.
|
||||||
|
|
||||||
|
[nginx-proxy-config]: https://github.com/zulip/zulip/blob/master/puppet/zulip/files/nginx/zulip-include-common/proxy
|
||||||
|
[nginx-proxy-longpolling-config]: https://github.com/zulip/zulip/blob/master/puppet/zulip/files/nginx/zulip-include-common/proxy_longpolling
|
||||||
|
[voyager.pp]: https://github.com/zulip/zulip/blob/master/puppet/zulip/manifests/voyager.pp
|
||||||
|
[zulipchat-puppet]: https://github.com/zulip/zulip/tree/master/puppet/zulip_ops/manifests
|
||||||
|
[nginx-loadbalancer]: https://github.com/zulip/zulip/blob/master/puppet/zulip_ops/files/nginx/sites-available/loadbalancer
|
||||||
|
|
||||||
|
### HAProxy configuration
|
||||||
|
|
||||||
|
If you want to use HAProxy with Zulip, this `backend` config is a good
|
||||||
|
place to start.
|
||||||
|
|
||||||
|
```
|
||||||
|
backend zulip
|
||||||
|
mode http
|
||||||
|
balance leastconn
|
||||||
|
http-request set-header X-Client-IP %[src]
|
||||||
|
reqadd X-Forwarded-Proto:\ https
|
||||||
|
server zulip 10.10.10.10:80 check
|
||||||
|
```
|
||||||
|
|
||||||
|
Since this configuration uses the `http` mode, you will also need to
|
||||||
|
[configure Zulip to allow HTTP](#configuring-zulip-to-allow-http) as
|
||||||
|
described above.
|
||||||
|
|
||||||
|
### Other proxies
|
||||||
|
|
||||||
|
If you're using another reverse proxy implementation, there are few
|
||||||
|
things you need to be careful about when configuring it:
|
||||||
|
|
||||||
1. Configure your reverse proxy (or proxies) to correctly maintain the
|
1. Configure your reverse proxy (or proxies) to correctly maintain the
|
||||||
`X-Forwarded-For` HTTP header, which is supposed to contain the series
|
`X-Forwarded-For` HTTP header, which is supposed to contain the series
|
||||||
of IP addresses the request was forwarded through. This
|
of IP addresses the request was forwarded through. You can verify
|
||||||
[nginx code snippet][nginx-proxy-config] will do the right thing, and
|
your work by looking at `/var/log/zulip/server.log` and checking it
|
||||||
you can verify your work by looking at `/var/log/zulip/server.log` and
|
has the actual IP addresses of clients, not the IP address of the
|
||||||
checking it has the actual IP addresses of clients, not the IP address
|
proxy server.
|
||||||
of the proxy server.
|
|
||||||
|
|
||||||
2. Ensure your proxy doesn't interfere with Zulip's use of long-polling
|
2. Ensure your proxy doesn't interfere with Zulip's use of
|
||||||
for real-time push from the server to your users' browsers. This
|
long-polling for real-time push from the server to your users'
|
||||||
[nginx code snippet][nginx-proxy-longpolling-config] will do the right thing.
|
browsers. This [nginx code snippet][nginx-proxy-longpolling-config]
|
||||||
|
does this.
|
||||||
|
|
||||||
The key configuration options are, for the `/json/events` and
|
The key configuration options are, for the `/json/events` and
|
||||||
`/api/1/events` endpoints:
|
`/api/1/events` endpoints:
|
||||||
@@ -97,22 +194,11 @@ The key configuration options are, for the `/json/events` and
|
|||||||
* `proxy_buffering off`. If you don't do this, your `nginx` proxy may
|
* `proxy_buffering off`. If you don't do this, your `nginx` proxy may
|
||||||
return occasional 502 errors to clients using Zulip's events API.
|
return occasional 502 errors to clients using Zulip's events API.
|
||||||
|
|
||||||
3. The other tricky failure mode with `nginx` reverse proxies is that
|
3. The other tricky failure mode we've seen with `nginx` reverse
|
||||||
they can load-balance between the IPv4 and IPv6 addresses for a given
|
proxies is that they can load-balance between the IPv4 and IPv6
|
||||||
hostname. This can result in mysterious errors that can be quite
|
addresses for a given hostname. This can result in mysterious errors
|
||||||
difficult to debug. Be sure to declare your `upstreams` in a way that
|
that can be quite difficult to debug. Be sure to declare your
|
||||||
won't do load-balancing unexpectedly (e.g. pointing to a DNS name that
|
`upstreams` equivalent in a way that won't do load-balancing
|
||||||
you haven't configured with multiple IPs for your Zulip machine;
|
unexpectedly (e.g. pointing to a DNS name that you haven't configured
|
||||||
sometimes this happens with IPv6 configuration).
|
with multiple IPs for your Zulip machine; sometimes this happens with
|
||||||
|
IPv6 configuration).
|
||||||
You can look at our
|
|
||||||
[nginx reverse proxy configuration][nginx-loadbalancer] to see an
|
|
||||||
example of how to do this properly (the various include files are
|
|
||||||
available via the `zulip::nginx` puppet module).
|
|
||||||
|
|
||||||
[nginx-proxy-config]: https://github.com/zulip/zulip/blob/master/puppet/zulip/files/nginx/zulip-include-common/proxy
|
|
||||||
[nginx-proxy-longpolling-config]: https://github.com/zulip/zulip/blob/master/puppet/zulip/files/nginx/zulip-include-common/proxy_longpolling
|
|
||||||
[voyager.pp]: https://github.com/zulip/zulip/blob/master/puppet/zulip/manifests/voyager.pp
|
|
||||||
[zulipchat-puppet]: https://github.com/zulip/zulip/tree/master/puppet/zulip_ops/manifests
|
|
||||||
[nginx-loadbalancer]: https://github.com/zulip/zulip/blob/master/puppet/zulip_ops/files/nginx/sites-available/loadbalancer
|
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,30 @@ follows:
|
|||||||
providers
|
providers
|
||||||
* The password like `email_password = abcd1234` in `/etc/zulip/zulip-secrets.conf`.
|
* The password like `email_password = abcd1234` in `/etc/zulip/zulip-secrets.conf`.
|
||||||
|
|
||||||
|
### Using system email
|
||||||
|
|
||||||
|
If you'd like to send outgoing email using the local operating
|
||||||
|
system's email delivery configuration (e.g. you have `postfix`
|
||||||
|
configuration on the system that forwards email sent locally into your
|
||||||
|
corporate email system), you will likely need to use something like
|
||||||
|
these setting values:
|
||||||
|
|
||||||
|
```
|
||||||
|
EMAIL_HOST = 'localhost'
|
||||||
|
EMAIL_PORT = 25
|
||||||
|
EMAIL_USE_TLS = False
|
||||||
|
EMAIL_HOST_USER = ""
|
||||||
|
```
|
||||||
|
|
||||||
|
We should emphasize that because modern spam filtering is very
|
||||||
|
aggressive, you should make sure your downstream email system is
|
||||||
|
configured to properly sign outgoing email sent by your Zulip server
|
||||||
|
(or check your spam folder) when using this configuration. See
|
||||||
|
[documentation on using Django with a local postfix server][postfix-email]
|
||||||
|
for additional advice.
|
||||||
|
|
||||||
|
[postfix-email]: https://stackoverflow.com/questions/26333009/how-do-you-configure-django-to-send-mail-through-postfix
|
||||||
|
|
||||||
### Using Gmail for outgoing email
|
### Using Gmail for outgoing email
|
||||||
|
|
||||||
We don't recommend using an inbox product like Gmail for outgoing
|
We don't recommend using an inbox product like Gmail for outgoing
|
||||||
|
|||||||
@@ -55,6 +55,16 @@ archive of all the organization's uploaded files.
|
|||||||
|
|
||||||
## Import into a new Zulip server
|
## Import into a new Zulip server
|
||||||
|
|
||||||
|
The Zulip server you're importing into needs to be running the same
|
||||||
|
version of Zulip as the server you exported from, so that the same
|
||||||
|
formats are consistent. For exports from zulipchat.com, usually this
|
||||||
|
means you need to upgrade your Zulip server to the latest `master`
|
||||||
|
branch, using [upgrade-zulip-from-git][upgrade-zulip-from-git].
|
||||||
|
|
||||||
|
First [install a new Zulip server](../production/install.html),
|
||||||
|
skipping "Step 3: Create a Zulip organization, and log in" (you'll
|
||||||
|
create your Zulip organization via the data import tool instead).
|
||||||
|
|
||||||
Log in to a shell on your Zulip server as the `zulip` user. Run the
|
Log in to a shell on your Zulip server as the `zulip` user. Run the
|
||||||
following commands, replacing the filename with the path to your data
|
following commands, replacing the filename with the path to your data
|
||||||
export tarball:
|
export tarball:
|
||||||
|
|||||||
@@ -25,9 +25,15 @@ follows:
|
|||||||
If you installed your Zulip server with a version older than 1.6,
|
If you installed your Zulip server with a version older than 1.6,
|
||||||
you'll need to add the line (it won't be there to uncomment).
|
you'll need to add the line (it won't be there to uncomment).
|
||||||
|
|
||||||
1. If you're running Zulip 1.8.1 or newer, you can run `manage.py
|
1. If you're running Zulip 1.8.1 or newer, you can run the
|
||||||
register_server` from `/home/zulip/deployments/current`. This
|
registration command:
|
||||||
command will print the registration data it would send to the
|
```
|
||||||
|
# As root:
|
||||||
|
su zulip -c '/home/zulip/deployments/current/manage.py register_server'
|
||||||
|
# Or as the zulip user, you can skip the `su zulip -c`:
|
||||||
|
/home/zulip/deployments/current/manage.py register_server
|
||||||
|
```
|
||||||
|
This command will print the registration data it would send to the
|
||||||
mobile push notifications service, ask you to accept the terms of
|
mobile push notifications service, ask you to accept the terms of
|
||||||
service, and if you accept, register your server. Otherwise, see
|
service, and if you accept, register your server. Otherwise, see
|
||||||
the [legacy signup instructions](#legacy-signup).
|
the [legacy signup instructions](#legacy-signup).
|
||||||
|
|||||||
@@ -50,6 +50,21 @@ For servers hosting a large number of organizations, like
|
|||||||
`ROOT_DOMAIN_LANDING_PAGE = True` in `/etc/zulip/settings.py` so that
|
`ROOT_DOMAIN_LANDING_PAGE = True` in `/etc/zulip/settings.py` so that
|
||||||
the homepage for the server is a copy of the Zulip homepage.
|
the homepage for the server is a copy of the Zulip homepage.
|
||||||
|
|
||||||
|
### SSL Certificates
|
||||||
|
|
||||||
|
You'll need to install an SSL certificate valid for all the
|
||||||
|
(sub)domains you're using your Zulip server with. You can get an SSL
|
||||||
|
certificate covering several domains for free by using
|
||||||
|
[our Certbot wrapper tool](../production/ssl-certificates.html#after-zulip-is-already-installed),
|
||||||
|
though if you're going to host a large number of organizations, you
|
||||||
|
may want to get a wildcard certificate. You can also get a wildcard
|
||||||
|
certificate for
|
||||||
|
[free using Certbot](https://community.letsencrypt.org/t/getting-wildcard-certificates-with-certbot/56285),
|
||||||
|
but because of the stricter security checks for acquiring a wildcard
|
||||||
|
cert, it isn't possible for a generic script like `setup-certbot` to
|
||||||
|
create it for you; you'll have to do some manual steps with your DNS
|
||||||
|
provider.
|
||||||
|
|
||||||
### Other hostnames
|
### Other hostnames
|
||||||
|
|
||||||
If you'd like to use hostnames that are not subdomains of each other,
|
If you'd like to use hostnames that are not subdomains of each other,
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ strength allowed is controlled by two settings in
|
|||||||
figure out whether a stream with that name exists, but cannot see any
|
figure out whether a stream with that name exists, but cannot see any
|
||||||
other details about the stream.
|
other details about the stream.
|
||||||
|
|
||||||
* See [Stream permissions](/help/stream-permissions) for more details.
|
* See [Stream permissions](https://zulipchat.com/help/stream-permissions) for more details.
|
||||||
|
|
||||||
* Zulip supports editing the content and topics of messages that have
|
* Zulip supports editing the content and topics of messages that have
|
||||||
already been sent. As a general philosophy, our policies provide
|
already been sent. As a general philosophy, our policies provide
|
||||||
@@ -129,7 +129,7 @@ strength allowed is controlled by two settings in
|
|||||||
any time by that administrator.
|
any time by that administrator.
|
||||||
|
|
||||||
* See
|
* See
|
||||||
[Configuring message editing and deletion](/help/configure-message-editing-and-deletion)
|
[Configuring message editing and deletion](https://zulipchat.com/help/configure-message-editing-and-deletion)
|
||||||
for more details.
|
for more details.
|
||||||
|
|
||||||
## Users and Bots
|
## Users and Bots
|
||||||
@@ -146,7 +146,7 @@ strength allowed is controlled by two settings in
|
|||||||
exceptions:
|
exceptions:
|
||||||
|
|
||||||
* Administrators may get access to private messages via some types of
|
* Administrators may get access to private messages via some types of
|
||||||
[data export](/help/export-your-organization).
|
[data export](https://zulipchat.com/help/export-your-organization).
|
||||||
|
|
||||||
* 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 stream, then an administrator can indirectly get access to
|
to a private stream, then an administrator can indirectly get access to
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ administrator can do. To change any of the following settings, edit
|
|||||||
the `/etc/zulip/settings.py` file on your Zulip server, and then
|
the `/etc/zulip/settings.py` file on your Zulip server, and then
|
||||||
restart the server with the following command:
|
restart the server with the following command:
|
||||||
```
|
```
|
||||||
su zulip -c /home/zulip/deployments/current/scripts/restart-server
|
su zulip -c '/home/zulip/deployments/current/scripts/restart-server'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Specific settings
|
## Specific settings
|
||||||
|
|||||||
@@ -72,6 +72,9 @@ The `--hostname` and `--email` options are required when using
|
|||||||
Zulip server machine to be reachable by that name from the public
|
Zulip server machine to be reachable by that name from the public
|
||||||
Internet.
|
Internet.
|
||||||
|
|
||||||
|
If you need to configure a multiple domain certificate, you can generate
|
||||||
|
one as described in the section below after installing Zulip.
|
||||||
|
|
||||||
[doc-install-script]: ../production/install.html#step-2-install-zulip
|
[doc-install-script]: ../production/install.html#step-2-install-zulip
|
||||||
|
|
||||||
### After Zulip is already installed
|
### After Zulip is already installed
|
||||||
@@ -80,11 +83,12 @@ To enable the Certbot automation on an already-installed Zulip
|
|||||||
server, run the following commands:
|
server, run the following commands:
|
||||||
```
|
```
|
||||||
sudo -s # If not already root
|
sudo -s # If not already root
|
||||||
/home/zulip/deployments/current/scripts/setup/setup-certbot --hostname=HOSTNAME --email=EMAIL
|
/home/zulip/deployments/current/scripts/setup/setup-certbot --email=EMAIL HOSTNAME [HOSTNAME2...]
|
||||||
```
|
```
|
||||||
where HOSTNAME is the domain name users see in their browser when
|
where HOSTNAME is the domain name users see in their browser when
|
||||||
using the server (e.g., `zulip.example.com`), and EMAIL is a contact
|
using the server (e.g., `zulip.example.com`), and EMAIL is a contact
|
||||||
address for the server admins.
|
address for the server admins. Additional hostnames can also be
|
||||||
|
specified to issue a certificate for multiple domains.
|
||||||
|
|
||||||
### How it works
|
### How it works
|
||||||
|
|
||||||
|
|||||||
@@ -35,25 +35,35 @@ 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. In some AWS regions, you need to explicitly
|
||||||
|
[configure boto](http://boto.cloudhackers.com/en/latest/boto_config_tut.html)
|
||||||
|
to use AWS's SIGv4 signature format (because AWS has stopped
|
||||||
|
supporting the older v3 format in those regions). You can do this
|
||||||
|
by adding an `/etc/boto.cfg` containing the following:
|
||||||
|
```
|
||||||
|
[s3]
|
||||||
|
use-sigv4 = True
|
||||||
|
```
|
||||||
|
|
||||||
1. You will need to configure `nginx` to direct requests for uploaded
|
1. You will need to configure `nginx` to direct requests for uploaded
|
||||||
files to the Zulip server (which will then serve a redirect to the
|
files to the Zulip server (which will then serve a redirect to the
|
||||||
appropriate place in S3), rather than serving them directly.
|
appropriate place in S3), rather than serving them directly.
|
||||||
|
|
||||||
With Zulip 1.9.0 and newer, you can do this automatically with the
|
With Zulip 1.9.0 and newer, you can do this automatically with the
|
||||||
following commands run as root:
|
following commands run as root:
|
||||||
|
|
||||||
```
|
```
|
||||||
crudini --set /etc/zulip/zulip.conf application_server no_serve_uploads true
|
crudini --set /etc/zulip/zulip.conf application_server no_serve_uploads true
|
||||||
/home/zulip/deployments/current/scripts/zulip-puppet-apply
|
/home/zulip/deployments/current/scripts/zulip-puppet-apply
|
||||||
```
|
```
|
||||||
|
|
||||||
(The first line will update your `/etc/zulip/zulip.conf`).
|
(The first line will update your `/etc/zulip/zulip.conf`).
|
||||||
|
|
||||||
With older Zulip, you need to edit
|
With older Zulip, you need to edit
|
||||||
`/etc/nginx/sites-available/zulip-enterprise` to comment out the
|
`/etc/nginx/sites-available/zulip-enterprise` to comment out the
|
||||||
`nginx` configuration block for `/user_avatars` and the `include
|
`nginx` configuration block for `/user_avatars` and the `include
|
||||||
/etc/nginx/zulip-include/uploads.route` line and then reload the
|
/etc/nginx/zulip-include/uploads.route` line and then reload the
|
||||||
`nginx` service (`service nginx reload`).
|
`nginx` service (`service nginx reload`).
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ messages until the migration finishes.
|
|||||||
|
|
||||||
Once the migrations are complete, restart Zulip:
|
Once the migrations are complete, restart Zulip:
|
||||||
|
|
||||||
su zulip -c /home/zulip/deployments/current/scripts/restart-server
|
su zulip -c '/home/zulip/deployments/current/scripts/restart-server'
|
||||||
|
|
||||||
Now, you can use full-text search across all languages.
|
Now, you can use full-text search across all languages.
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ Then, set `USING_PGROONGA = False` in `/etc/zulip/settings.py`:
|
|||||||
|
|
||||||
And, restart Zulip:
|
And, restart Zulip:
|
||||||
|
|
||||||
su zulip -c /home/zulip/deployments/current/scripts/restart-server
|
su zulip -c '/home/zulip/deployments/current/scripts/restart-server'
|
||||||
|
|
||||||
Now, full-text search feature based on PGroonga is disabled. If you'd
|
Now, full-text search feature based on PGroonga is disabled. If you'd
|
||||||
like, you can also remove the `pgroonga = enabled` line in
|
like, you can also remove the `pgroonga = enabled` line in
|
||||||
|
|||||||
10
manage.py
10
manage.py
@@ -1,16 +1,20 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
from __future__ import (print_function)
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
if sys.version_info <= (3, 0):
|
||||||
|
print("Error: Zulip is a Python 3 project, and cannot be run with Python 2.")
|
||||||
|
print("Use e.g. `/path/to/manage.py` not `python /path/to/manage.py`.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
sys.path.append(BASE_DIR)
|
sys.path.append(BASE_DIR)
|
||||||
import scripts.lib.setup_path_on_import
|
import scripts.lib.setup_path_on_import
|
||||||
|
from scripts.lib.zulip_tools import script_should_not_be_root
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if 'posix' in os.name and os.geteuid() == 0:
|
script_should_not_be_root()
|
||||||
print("manage.py should not be run as root. Use `su zulip` to drop root.")
|
|
||||||
sys.exit(1)
|
|
||||||
if (os.access('/etc/zulip/zulip.conf', os.R_OK) and not
|
if (os.access('/etc/zulip/zulip.conf', os.R_OK) and not
|
||||||
os.access('/etc/zulip/zulip-secrets.conf', os.R_OK)):
|
os.access('/etc/zulip/zulip-secrets.conf', os.R_OK)):
|
||||||
# The best way to detect running manage.py as another user in
|
# The best way to detect running manage.py as another user in
|
||||||
|
|||||||
@@ -60,14 +60,28 @@ location / {
|
|||||||
uwsgi_pass django;
|
uwsgi_pass django;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Certain Django routes not under /api are shared between mobile and
|
||||||
|
# web and thus need API headers added. We don't collapse this with the
|
||||||
|
# above block for /events, because regular expressions take priority over
|
||||||
|
# paths in nginx's order-of-operations, and we don't want to override the
|
||||||
|
# tornado stuff.
|
||||||
|
location ~ ^/(user_uploads|avatar|thumbnail)/ {
|
||||||
|
add_header Access-Control-Allow-Origin *;
|
||||||
|
add_header Access-Control-Allow-Headers Authorization;
|
||||||
|
add_header Access-Control-Allow-Methods 'GET, POST, DELETE, PUT, PATCH, HEAD';
|
||||||
|
|
||||||
|
include uwsgi_params;
|
||||||
|
uwsgi_pass django;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Send all API routes not covered above to Django via uWSGI
|
||||||
location /api/ {
|
location /api/ {
|
||||||
add_header Access-Control-Allow-Origin *;
|
add_header Access-Control-Allow-Origin *;
|
||||||
add_header Access-Control-Allow-Headers Authorization;
|
add_header Access-Control-Allow-Headers Authorization;
|
||||||
add_header Access-Control-Allow-Methods 'GET, POST, DELETE, PUT, PATCH, HEAD';
|
add_header Access-Control-Allow-Methods 'GET, POST, DELETE, PUT, PATCH, HEAD';
|
||||||
|
|
||||||
include uwsgi_params;
|
include uwsgi_params;
|
||||||
uwsgi_pass django;
|
uwsgi_pass django;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
include /etc/nginx/zulip-include/app.d/*.conf;
|
include /etc/nginx/zulip-include/app.d/*.conf;
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ PUPPET_CLASSES="${PUPPET_CLASSES:-zulip::voyager}"
|
|||||||
VIRTUALENV_NEEDED="${VIRTUALENV_NEEDED:-yes}"
|
VIRTUALENV_NEEDED="${VIRTUALENV_NEEDED:-yes}"
|
||||||
|
|
||||||
if [ -n "$SELF_SIGNED_CERT" ] && [ -n "$USE_CERTBOT" ]; then
|
if [ -n "$SELF_SIGNED_CERT" ] && [ -n "$USE_CERTBOT" ]; then
|
||||||
|
set +x
|
||||||
echo "error: --self-signed-cert and --certbot are incompatible" >&2
|
echo "error: --self-signed-cert and --certbot are incompatible" >&2
|
||||||
echo >&2
|
echo >&2
|
||||||
usage
|
usage
|
||||||
@@ -80,14 +81,16 @@ export LANGUAGE="en_US.UTF-8"
|
|||||||
|
|
||||||
# Check for a supported OS release.
|
# Check for a supported OS release.
|
||||||
apt-get install -y lsb-release sudo
|
apt-get install -y lsb-release sudo
|
||||||
os_release="$(lsb_release -sc)"
|
os_info="$(lsb_release --short --id --release --codename)"
|
||||||
case "$os_release" in
|
{ read -r os_id; read -r os_release; read -r os_codename; } <<< "$os_info"
|
||||||
|
|
||||||
|
case "$os_codename" in
|
||||||
trusty|xenial|stretch|bionic) ;;
|
trusty|xenial|stretch|bionic) ;;
|
||||||
*)
|
*)
|
||||||
set +x
|
set +x
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
|
||||||
Unsupported OS release: $os_release
|
Unsupported OS release: $os_codename
|
||||||
|
|
||||||
Zulip in production is supported only on:
|
Zulip in production is supported only on:
|
||||||
- Debian 9 "stretch"
|
- Debian 9 "stretch"
|
||||||
@@ -101,12 +104,30 @@ EOF
|
|||||||
exit 1
|
exit 1
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
if [ "$os_id" = Ubuntu ] && ! apt-cache policy |
|
||||||
|
grep -q "^ release v=$os_release,o=Ubuntu,a=$os_codename,n=$os_codename,l=Ubuntu,c=universe"; then
|
||||||
|
set +x
|
||||||
|
cat <<'EOF'
|
||||||
|
|
||||||
|
You must enable the Ubuntu Universe repository before installing
|
||||||
|
Zulip. You can do this with: `add-apt-repository universe`.
|
||||||
|
|
||||||
|
For more information, see:
|
||||||
|
https://zulip.readthedocs.io/en/latest/production/requirements.html
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Check for at least ~1.9GB of RAM before starting installation;
|
# Check for at least ~1.9GB of RAM before starting installation;
|
||||||
# otherwise users will find out about insufficient RAM via weird
|
# otherwise users will find out about insufficient RAM via weird
|
||||||
# errors like a segfault running `pip install`.
|
# errors like a segfault running `pip install`.
|
||||||
mem_kb=$(head -n1 /proc/meminfo | awk '{print $2}')
|
mem_kb=$(head -n1 /proc/meminfo | awk '{print $2}')
|
||||||
if [ "$mem_kb" -lt 1900000 ]; then
|
if [ "$mem_kb" -lt 1900000 ]; then
|
||||||
echo "Insufficient RAM. Zulip requires at least 2GB of RAM."
|
set +x
|
||||||
|
echo -e '\033[0;31m' >&2
|
||||||
|
echo "Insufficient RAM. Zulip requires at least 2GB of RAM." >&2
|
||||||
|
echo >&2
|
||||||
|
echo -e '\033[0m' >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -141,15 +162,22 @@ EOF
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
apt-get -y dist-upgrade "${APT_OPTIONS[@]}"
|
apt-get -y dist-upgrade "${APT_OPTIONS[@]}"
|
||||||
apt-get install -y \
|
if ! apt-get install -y \
|
||||||
puppet git curl wget \
|
puppet git curl wget \
|
||||||
python python3 python-six python3-six crudini \
|
python python3 python-six python3-six crudini \
|
||||||
"${ADDITIONAL_PACKAGES[@]}"
|
"${ADDITIONAL_PACKAGES[@]}"; then
|
||||||
|
set +x
|
||||||
|
echo -e '\033[0;31m' >&2
|
||||||
|
echo "Installing packages failed; is network working and (on Ubuntu) the universe repository enabled?" >&2
|
||||||
|
echo >&2
|
||||||
|
echo -e '\033[0m' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -n "$USE_CERTBOT" ]; then
|
if [ -n "$USE_CERTBOT" ]; then
|
||||||
"$ZULIP_PATH"/scripts/setup/setup-certbot \
|
"$ZULIP_PATH"/scripts/setup/setup-certbot \
|
||||||
--no-zulip-conf --method=standalone \
|
--no-zulip-conf --method=standalone \
|
||||||
--hostname "$EXTERNAL_HOST" --email "$ZULIP_ADMINISTRATOR"
|
"$EXTERNAL_HOST" --email "$ZULIP_ADMINISTRATOR"
|
||||||
elif [ -n "$SELF_SIGNED_CERT" ]; then
|
elif [ -n "$SELF_SIGNED_CERT" ]; then
|
||||||
"$ZULIP_PATH"/scripts/setup/generate-self-signed-cert \
|
"$ZULIP_PATH"/scripts/setup/generate-self-signed-cert \
|
||||||
--exists-ok "${EXTERNAL_HOST:-$(hostname)}"
|
--exists-ok "${EXTERNAL_HOST:-$(hostname)}"
|
||||||
@@ -303,7 +331,7 @@ if [ "$has_appserver" = 0 ]; then
|
|||||||
# If we're installing from a git checkout, we need to run
|
# If we're installing from a git checkout, we need to run
|
||||||
# `tools/update-prod-static` in order to build the static
|
# `tools/update-prod-static` in order to build the static
|
||||||
# assets.
|
# assets.
|
||||||
su zulip -c "/home/zulip/deployments/current/tools/update-prod-static --authors-not-required"
|
su zulip -c '/home/zulip/deployments/current/tools/update-prod-static --authors-not-required'
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -319,7 +347,7 @@ if [ -n "$NO_INIT_DB" ]; then
|
|||||||
|
|
||||||
Stopping because --no-init-db was passed. To complete the installation, run:
|
Stopping because --no-init-db was passed. To complete the installation, run:
|
||||||
|
|
||||||
su zulip -c /home/zulip/deployments/current/scripts/setup/initialize-database
|
su zulip -c '/home/zulip/deployments/current/scripts/setup/initialize-database'
|
||||||
EOF
|
EOF
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ SOURCES_FILE=/etc/apt/sources.list.d/zulip.list
|
|||||||
STAMP_FILE=/etc/apt/sources.list.d/zulip.list.apt-update-in-progress
|
STAMP_FILE=/etc/apt/sources.list.d/zulip.list.apt-update-in-progress
|
||||||
zulip_source_hash=$(sha1sum "$SOURCES_FILE")
|
zulip_source_hash=$(sha1sum "$SOURCES_FILE")
|
||||||
|
|
||||||
apt-get install -y lsb-release apt-transport-https
|
apt-get install -y lsb-release apt-transport-https gnupg
|
||||||
|
|
||||||
SCRIPTS_PATH="$(dirname "$(dirname "$0")")"
|
SCRIPTS_PATH="$(dirname "$(dirname "$0")")"
|
||||||
|
|
||||||
|
|||||||
@@ -11,16 +11,14 @@ os.environ["PYTHONUNBUFFERED"] = "y"
|
|||||||
|
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
from scripts.lib.zulip_tools import DEPLOYMENTS_DIR, FAIL, WARNING, ENDC, \
|
from scripts.lib.zulip_tools import DEPLOYMENTS_DIR, FAIL, WARNING, ENDC, \
|
||||||
su_to_zulip, get_deployment_lock, release_deployment_lock
|
su_to_zulip, get_deployment_lock, release_deployment_lock, script_should_be_root
|
||||||
|
|
||||||
|
script_should_be_root(strip_lib_from_paths=True)
|
||||||
|
|
||||||
logging.Formatter.converter = time.gmtime
|
logging.Formatter.converter = time.gmtime
|
||||||
logging.basicConfig(format="%(asctime)s upgrade-zulip: %(message)s",
|
logging.basicConfig(format="%(asctime)s upgrade-zulip: %(message)s",
|
||||||
level=logging.INFO)
|
level=logging.INFO)
|
||||||
|
|
||||||
if os.getuid() != 0:
|
|
||||||
logging.error("Must be run as root.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if len(sys.argv) != 2:
|
if len(sys.argv) != 2:
|
||||||
print(FAIL + "Usage: %s <tarball>" % (sys.argv[0],) + ENDC)
|
print(FAIL + "Usage: %s <tarball>" % (sys.argv[0],) + ENDC)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|||||||
@@ -24,16 +24,14 @@ os.environ["PYTHONUNBUFFERED"] = "y"
|
|||||||
|
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
from scripts.lib.zulip_tools import DEPLOYMENTS_DIR, FAIL, WARNING, ENDC, make_deploy_path, \
|
from scripts.lib.zulip_tools import DEPLOYMENTS_DIR, FAIL, WARNING, ENDC, make_deploy_path, \
|
||||||
get_deployment_lock, release_deployment_lock, su_to_zulip
|
get_deployment_lock, release_deployment_lock, su_to_zulip, script_should_be_root
|
||||||
|
|
||||||
|
script_should_be_root(strip_lib_from_paths=True)
|
||||||
|
|
||||||
logging.Formatter.converter = time.gmtime
|
logging.Formatter.converter = time.gmtime
|
||||||
logging.basicConfig(format="%(asctime)s upgrade-zulip-from-git: %(message)s",
|
logging.basicConfig(format="%(asctime)s upgrade-zulip-from-git: %(message)s",
|
||||||
level=logging.INFO)
|
level=logging.INFO)
|
||||||
|
|
||||||
if os.getuid() != 0:
|
|
||||||
logging.error("Must be run as root.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("refname", help="Git reference, e.g. a branch, tag, or commit ID.")
|
parser.add_argument("refname", help="Git reference, e.g. a branch, tag, or commit ID.")
|
||||||
parser.add_argument("--remote-url", dest="remote_url",
|
parser.add_argument("--remote-url", dest="remote_url",
|
||||||
|
|||||||
@@ -20,16 +20,14 @@ os.environ["LANG"] = "en_US.UTF-8"
|
|||||||
os.environ["LANGUAGE"] = "en_US.UTF-8"
|
os.environ["LANGUAGE"] = "en_US.UTF-8"
|
||||||
|
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
from scripts.lib.zulip_tools import DEPLOYMENTS_DIR, FAIL, WARNING, ENDC, su_to_zulip
|
from scripts.lib.zulip_tools import DEPLOYMENTS_DIR, FAIL, WARNING, ENDC, su_to_zulip, script_should_be_root
|
||||||
|
|
||||||
|
script_should_be_root()
|
||||||
|
|
||||||
logging.Formatter.converter = time.gmtime
|
logging.Formatter.converter = time.gmtime
|
||||||
logging.basicConfig(format="%(asctime)s upgrade-zulip-stage-2: %(message)s",
|
logging.basicConfig(format="%(asctime)s upgrade-zulip-stage-2: %(message)s",
|
||||||
level=logging.INFO)
|
level=logging.INFO)
|
||||||
|
|
||||||
if os.getuid() != 0:
|
|
||||||
logging.error("Must be run as root.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# make sure we have appropriate file permissions
|
# make sure we have appropriate file permissions
|
||||||
os.umask(0o22)
|
os.umask(0o22)
|
||||||
|
|
||||||
|
|||||||
@@ -359,3 +359,30 @@ def file_or_package_hash_updated(paths, hash_name, is_force, package_versions=[]
|
|||||||
hash_file.write(new_hash)
|
hash_file.write(new_hash)
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def is_root() -> bool:
|
||||||
|
if 'posix' in os.name and os.geteuid() == 0:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def script_should_not_be_root() -> None:
|
||||||
|
script_name = os.path.abspath(sys.argv[0])
|
||||||
|
if is_root():
|
||||||
|
msg = ("{shortname} should not be run as root. Use `su zulip` to switch to the 'zulip'\n"
|
||||||
|
"user before rerunning this, or use \n su zulip -c '{name} ...'\n"
|
||||||
|
"to switch users and run this as a single command.").format(
|
||||||
|
name=script_name,
|
||||||
|
shortname=os.path.basename(script_name))
|
||||||
|
print(msg)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def script_should_be_root(strip_lib_from_paths: bool=False) -> None:
|
||||||
|
script_name = os.path.abspath(sys.argv[0])
|
||||||
|
# Since these Python scripts are run inside a thin shell wrapper,
|
||||||
|
# we need to replace the paths in order to ensure we instruct
|
||||||
|
# users to (re)run the right command.
|
||||||
|
if strip_lib_from_paths:
|
||||||
|
script_name = script_name.replace("scripts/lib/upgrade", "scripts/upgrade")
|
||||||
|
if not is_root():
|
||||||
|
print("{} must be run as root.".format(script_name))
|
||||||
|
sys.exit(1)
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ set -e
|
|||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat <<EOF >&2
|
cat <<EOF >&2
|
||||||
Usage: $0 --hostname=zulip.example.com --email=admin@example.com [--method={webroot|standalone}] [--no-zulip-conf]
|
Usage: $0 --email=admin@example.com [--method={webroot|standalone}] \
|
||||||
|
[--no-zulip-conf] hostname.example.com [another.example.com]
|
||||||
EOF
|
EOF
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
@@ -15,15 +16,10 @@ if [ "$EUID" -ne 0 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
method=webroot
|
method=webroot
|
||||||
args="$(getopt -o '' --long help,hostname:,email:,method:,deploy-hook:,no-zulip-conf,agree-tos -n "$0" -- "$@")"
|
args="$(getopt -o '' --long help,email:,method:,deploy-hook:,no-zulip-conf,agree-tos -n "$0" -- "$@")"
|
||||||
eval "set -- $args"
|
eval "set -- $args"
|
||||||
while true; do
|
while true; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--hostname)
|
|
||||||
DOMAIN="$2"
|
|
||||||
shift
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--email)
|
--email)
|
||||||
EMAIL="$2"
|
EMAIL="$2"
|
||||||
shift
|
shift
|
||||||
@@ -52,11 +48,19 @@ while true; do
|
|||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--)
|
--)
|
||||||
|
shift
|
||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Parse the remaining arguments as Subject Alternative Names to pass to certbot
|
||||||
|
HOSTNAMES=()
|
||||||
|
for arg; do
|
||||||
|
HOSTNAMES+=(-d "$arg")
|
||||||
|
done
|
||||||
|
DOMAIN=$1
|
||||||
|
|
||||||
if [ -n "$show_help" ]; then
|
if [ -n "$show_help" ]; then
|
||||||
usage
|
usage
|
||||||
fi
|
fi
|
||||||
@@ -94,7 +98,7 @@ chmod a+x "$CERTBOT_PATH"
|
|||||||
# Passing --force-interactive suppresses a warning, but also brings up
|
# Passing --force-interactive suppresses a warning, but also brings up
|
||||||
# an annoying prompt we stifle with --no-eff-email.
|
# an annoying prompt we stifle with --no-eff-email.
|
||||||
"$CERTBOT_PATH" certonly "${method_args[@]}" \
|
"$CERTBOT_PATH" certonly "${method_args[@]}" \
|
||||||
-d "$DOMAIN" -m "$EMAIL" \
|
"${HOSTNAMES[@]}" -m "$EMAIL" \
|
||||||
$agree_tos --force-renewal \
|
$agree_tos --force-renewal \
|
||||||
"${deploy_hook[@]}" \
|
"${deploy_hook[@]}" \
|
||||||
--force-interactive --no-eff-email
|
--force-interactive --no-eff-email
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ import sys
|
|||||||
import subprocess
|
import subprocess
|
||||||
import configparser
|
import configparser
|
||||||
import re
|
import re
|
||||||
from lib.zulip_tools import parse_lsb_release
|
from lib.zulip_tools import parse_lsb_release, script_should_be_root
|
||||||
|
|
||||||
|
script_should_be_root()
|
||||||
|
|
||||||
force = False
|
force = False
|
||||||
extra_args = sys.argv[1:]
|
extra_args = sys.argv[1:]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2018-11-07 15:19+0000\n"
|
"POT-Creation-Date: 2018-11-28 20:32+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -1393,9 +1393,10 @@ msgstr ""
|
|||||||
|
|
||||||
#: templates/zerver/emails/compiled/confirm_new_email.html:29
|
#: templates/zerver/emails/compiled/confirm_new_email.html:29
|
||||||
#: templates/zerver/emails/compiled/confirm_registration.html:27
|
#: templates/zerver/emails/compiled/confirm_registration.html:27
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:56
|
#: templates/zerver/emails/compiled/followup_day1.html:55
|
||||||
#: templates/zerver/emails/compiled/invitation.html:26
|
#: templates/zerver/emails/compiled/invitation.html:26
|
||||||
#: templates/zerver/emails/compiled/invitation_reminder.html:22
|
#: templates/zerver/emails/compiled/invitation_reminder.html:22
|
||||||
|
#: templates/zerver/emails/compiled/realm_reactivation.html:36
|
||||||
#: templates/zerver/emails/confirm_new_email.source.html:28
|
#: templates/zerver/emails/confirm_new_email.source.html:28
|
||||||
#: templates/zerver/emails/confirm_new_email.txt:15
|
#: templates/zerver/emails/confirm_new_email.txt:15
|
||||||
#: templates/zerver/emails/confirm_registration.source.html:26
|
#: templates/zerver/emails/confirm_registration.source.html:26
|
||||||
@@ -1411,8 +1412,9 @@ msgstr ""
|
|||||||
|
|
||||||
#: templates/zerver/emails/compiled/confirm_new_email.html:30
|
#: templates/zerver/emails/compiled/confirm_new_email.html:30
|
||||||
#: templates/zerver/emails/compiled/confirm_registration.html:28
|
#: templates/zerver/emails/compiled/confirm_registration.html:28
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:57
|
#: templates/zerver/emails/compiled/followup_day1.html:56
|
||||||
#: templates/zerver/emails/compiled/notify_change_in_email.html:15
|
#: templates/zerver/emails/compiled/notify_change_in_email.html:15
|
||||||
|
#: templates/zerver/emails/compiled/realm_reactivation.html:37
|
||||||
#: templates/zerver/emails/confirm_new_email.source.html:29
|
#: templates/zerver/emails/confirm_new_email.source.html:29
|
||||||
#: templates/zerver/emails/confirm_new_email.txt:16
|
#: templates/zerver/emails/confirm_new_email.txt:16
|
||||||
#: templates/zerver/emails/confirm_registration.source.html:27
|
#: templates/zerver/emails/confirm_registration.source.html:27
|
||||||
@@ -1452,6 +1454,7 @@ msgid "Complete registration"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/confirm_registration.html:20
|
#: templates/zerver/emails/compiled/confirm_registration.html:20
|
||||||
|
#: templates/zerver/emails/compiled/realm_reactivation.html:29
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
@@ -1500,88 +1503,80 @@ msgid "Thanks for using Zulip!"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:9
|
#: templates/zerver/emails/compiled/followup_day1.html:9
|
||||||
#: templates/zerver/emails/compiled/invitation.html:9
|
msgid "Welcome to Zulip!"
|
||||||
#: templates/zerver/emails/followup_day1.source.html:8
|
|
||||||
#: templates/zerver/emails/followup_day1.txt:1
|
|
||||||
#: templates/zerver/emails/invitation.source.html:8
|
|
||||||
#: templates/zerver/emails/invitation.txt:1
|
|
||||||
msgid "Hi there,"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:11
|
#: templates/zerver/emails/compiled/followup_day1.html:13
|
||||||
#: templates/zerver/emails/followup_day1.source.html:10
|
|
||||||
#: templates/zerver/emails/followup_day1.txt:3
|
|
||||||
msgid "Welcome to Zulip! A few tips to get you started:"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:14
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Zulip works best when it's always open, so we suggest downloading\n"
|
" You've created the new Zulip organization <b>%(realm_name)s</b>.\n"
|
||||||
" our <a href=\"https://zulipchat.com/apps\" style=\"color:hsl(164, 42%%, "
|
" "
|
||||||
"47%%); text-decoration:underline\">desktop and mobile apps</a>.\n"
|
|
||||||
" "
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:19
|
#: templates/zerver/emails/compiled/followup_day1.html:17
|
||||||
#: templates/zerver/emails/followup_day1.source.html:18
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" To access your account from the apps, enter this Organization URL:\n"
|
" You've joined the Zulip organization <b>%(realm_name)s</b>.\n"
|
||||||
" "
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/followup_day1.html:24
|
||||||
|
msgid "Your account details:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/followup_day1.html:26
|
||||||
|
msgid "Organization URL:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:29
|
#: templates/zerver/emails/compiled/followup_day1.html:29
|
||||||
#, python-format
|
msgid "Use your LDAP account to login"
|
||||||
msgid ""
|
|
||||||
"\n"
|
|
||||||
" Become a Zulip pro with a few\n"
|
|
||||||
" <a href=\"%(keyboard_shortcuts_link)s\" style=\"color:hsl(164, 42%%, "
|
|
||||||
"47%%); text-decoration:underline\">keyboard shortcuts</a>:\n"
|
|
||||||
" "
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:34
|
#: templates/zerver/emails/compiled/followup_day1.html:32
|
||||||
#: templates/zerver/emails/followup_day1.source.html:33
|
msgid "Email:"
|
||||||
#: templates/zerver/emails/followup_day1.txt:17
|
|
||||||
msgid "Next unread thread"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:35
|
#: templates/zerver/emails/compiled/followup_day1.html:35
|
||||||
#: templates/zerver/emails/followup_day1.source.html:34
|
|
||||||
#: templates/zerver/emails/followup_day1.txt:18
|
|
||||||
msgid "Reply to message under the blue box"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:36
|
|
||||||
#: templates/zerver/emails/followup_day1.source.html:35
|
|
||||||
#: templates/zerver/emails/followup_day1.txt:19
|
|
||||||
msgid "Start a new topic"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:40
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Give our <a href=\"%(getting_started_link)s\" style=\"color:hsl(164, "
|
" (you'll need these to sign in to the <a href=\"https://zulipchat.com/apps"
|
||||||
"42%%, 47%%); text-decoration:underline\">guide for new\n"
|
"\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">mobile "
|
||||||
" %(user_role_group)s</a> a spin.\n"
|
"and desktop</a> apps)\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/followup_day1.html:42
|
||||||
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
" Check out our <a href=\"%(getting_started_link)s\" style=\"color:"
|
||||||
|
"hsl(164, 42%%, 47%%); text-decoration:underline\">guide for admins</a>, "
|
||||||
|
"become a Zulip pro with a\n"
|
||||||
|
" few <a href=\"%(keyboard_shortcuts_link)s\" style=\"color:hsl(164, "
|
||||||
|
"42%%, 47%%); text-decoration:underline\">keyboard shortcuts</a>, or <a href="
|
||||||
|
"\"%(realm_uri)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:"
|
||||||
|
"underline\">dive right in</a>!\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:47
|
#: templates/zerver/emails/compiled/followup_day1.html:47
|
||||||
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Zulip combines the real-time ease of chat with the threaded "
|
" <a href=\"%(getting_started_link)s\" style=\"color:hsl(164, 42%%, "
|
||||||
"organization\n"
|
"47%%); text-decoration:underline\">Learn more</a> about Zulip, become a pro "
|
||||||
" of email. Zulip is about productivity—making communication fun and\n"
|
"with a few\n"
|
||||||
" easy, while avoiding the distracting and disorganized conversations of\n"
|
" <a href=\"%(keyboard_shortcuts_link)s\" style=\"color:hsl(164, 42%%, "
|
||||||
" chatrooms. We hope you love using Zulip as much as we do.\n"
|
"47%%); text-decoration:underline\">keyboard shortcuts</a>, or <a href="
|
||||||
" "
|
"\"%(realm_uri)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:"
|
||||||
|
"underline\">dive right in</a>!\n"
|
||||||
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:61
|
#: templates/zerver/emails/compiled/followup_day1.html:60
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
@@ -1595,6 +1590,14 @@ msgid ""
|
|||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/invitation.html:9
|
||||||
|
#: templates/zerver/emails/followup_day1.source.html:8
|
||||||
|
#: templates/zerver/emails/followup_day1.txt:1
|
||||||
|
#: templates/zerver/emails/invitation.source.html:8
|
||||||
|
#: templates/zerver/emails/invitation.txt:1
|
||||||
|
msgid "Hi there,"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/invitation.html:12
|
#: templates/zerver/emails/compiled/invitation.html:12
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -1675,6 +1678,38 @@ msgstr ""
|
|||||||
msgid "Best,"
|
msgid "Best,"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/realm_reactivation.html:10
|
||||||
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
" Dear former administrators of %(realm_name)s,\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/realm_reactivation.html:15
|
||||||
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
" One of your administrators requested reactivation of the\n"
|
||||||
|
" previously deactivated Zulip organization hosted at %(realm_uri)s. If "
|
||||||
|
"you'd\n"
|
||||||
|
" like to do confirm that request and reactivate the organization, please "
|
||||||
|
"click here:\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/realm_reactivation.html:21
|
||||||
|
msgid "Reactivate organization"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/realm_reactivation.html:23
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
" If the request was in error, you can take no action and this link\n"
|
||||||
|
" will expire in 24 hours.\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/confirm_new_email.source.html:21
|
#: templates/zerver/emails/confirm_new_email.source.html:21
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -1719,6 +1754,11 @@ msgid ""
|
|||||||
"questions."
|
"questions."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/followup_day1.source.html:10
|
||||||
|
#: templates/zerver/emails/followup_day1.txt:3
|
||||||
|
msgid "Welcome to Zulip! A few tips to get you started:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/followup_day1.source.html:13
|
#: templates/zerver/emails/followup_day1.source.html:13
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
@@ -1727,6 +1767,13 @@ msgid ""
|
|||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/followup_day1.source.html:18
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
" To access your account from the apps, enter this Organization URL:\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/followup_day1.source.html:28
|
#: templates/zerver/emails/followup_day1.source.html:28
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -1736,6 +1783,21 @@ msgid ""
|
|||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/followup_day1.source.html:33
|
||||||
|
#: templates/zerver/emails/followup_day1.txt:17
|
||||||
|
msgid "Next unread thread"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/followup_day1.source.html:34
|
||||||
|
#: templates/zerver/emails/followup_day1.txt:18
|
||||||
|
msgid "Reply to message under the blue box"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/followup_day1.source.html:35
|
||||||
|
#: templates/zerver/emails/followup_day1.txt:19
|
||||||
|
msgid "Start a new topic"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/followup_day1.source.html:39
|
#: templates/zerver/emails/followup_day1.source.html:39
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -3324,43 +3386,43 @@ msgstr ""
|
|||||||
msgid "Wrong subdomain"
|
msgid "Wrong subdomain"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:716 zerver/views/auth.py:747
|
#: zerver/views/auth.py:717 zerver/views/auth.py:748
|
||||||
msgid "Dev environment not enabled."
|
msgid "Dev environment not enabled."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:732 zerver/views/auth.py:780
|
#: zerver/views/auth.py:733 zerver/views/auth.py:781
|
||||||
msgid "This organization has been deactivated."
|
msgid "This organization has been deactivated."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:735 zerver/views/auth.py:777
|
#: zerver/views/auth.py:736 zerver/views/auth.py:778
|
||||||
msgid "Your account has been disabled."
|
msgid "Your account has been disabled."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:738
|
#: zerver/views/auth.py:739
|
||||||
msgid "This user is not registered."
|
msgid "This user is not registered."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:783
|
#: zerver/views/auth.py:784
|
||||||
msgid "Password auth is disabled in your team."
|
msgid "Password auth is disabled in your team."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:789
|
#: zerver/views/auth.py:790
|
||||||
msgid "This user is not registered; do so from a browser."
|
msgid "This user is not registered; do so from a browser."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:791 zerver/views/auth.py:875
|
#: zerver/views/auth.py:792 zerver/views/auth.py:876
|
||||||
msgid "Your username or password is incorrect."
|
msgid "Your username or password is incorrect."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:816
|
#: zerver/views/auth.py:817
|
||||||
msgid "Invalid subdomain"
|
msgid "Invalid subdomain"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:822
|
#: zerver/views/auth.py:823
|
||||||
msgid "Subdomain required"
|
msgid "Subdomain required"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:883
|
#: zerver/views/auth.py:884
|
||||||
msgid "GOOGLE_CLIENT_ID is not configured"
|
msgid "GOOGLE_CLIENT_ID is not configured"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,11 +2,11 @@
|
|||||||
"\"__file_name__\" was too large; the maximum file size is 25MiB.": "\"__file_name__\" 이 너무 큽니다.; 최대 파일크기는 25MiB입니다.",
|
"\"__file_name__\" was too large; the maximum file size is 25MiB.": "\"__file_name__\" 이 너무 큽니다.; 최대 파일크기는 25MiB입니다.",
|
||||||
"(This user has been deactivated)": "(이 사용자는 비활성화되었습니다.)",
|
"(This user has been deactivated)": "(이 사용자는 비활성화되었습니다.)",
|
||||||
"(no topic)": "(주제없음)",
|
"(no topic)": "(주제없음)",
|
||||||
"1 day": "",
|
"1 day": "1 일",
|
||||||
"1 hour": "",
|
"1 hour": "1 시간",
|
||||||
"1 week": "",
|
"1 week": "1 주",
|
||||||
"10 minutes": "",
|
"10 minutes": "10 분",
|
||||||
"2 minutes": "",
|
"2 minutes": "2 분",
|
||||||
"24-hour time (17:00 instead of 5:00 PM)": "24 시간 표시 (5:00 PM 대신 17:00)",
|
"24-hour time (17:00 instead of 5:00 PM)": "24 시간 표시 (5:00 PM 대신 17:00)",
|
||||||
"<b>Private, protected history:</b> must be invited by a member; new members can only see messages sent after they join; hidden from non-administrator users": "",
|
"<b>Private, protected history:</b> must be invited by a member; new members can only see messages sent after they join; hidden from non-administrator users": "",
|
||||||
"<b>Private, shared history:</b> must be invited by a member; new members can view complete message history; hidden from non-administrator users": "",
|
"<b>Private, shared history:</b> must be invited by a member; new members can view complete message history; hidden from non-administrator users": "",
|
||||||
@@ -39,13 +39,13 @@
|
|||||||
"Add member...": "회원 추가 ...",
|
"Add member...": "회원 추가 ...",
|
||||||
"Add members of your organization to mentionable user groups.": "관심있는 사용자 그룹에 단체 구성원을 추가하십시오.",
|
"Add members of your organization to mentionable user groups.": "관심있는 사용자 그룹에 단체 구성원을 추가하십시오.",
|
||||||
"Add new default stream": "새 기본 스트림 추가",
|
"Add new default stream": "새 기본 스트림 추가",
|
||||||
"Add option": "",
|
"Add option": "옵션 추가",
|
||||||
"Add profile field": "",
|
"Add profile field": "",
|
||||||
"Add question": "",
|
"Add question": "질문 추가",
|
||||||
"Add stream": "스트림 추가",
|
"Add stream": "스트림 추가",
|
||||||
"Add task": "",
|
"Add task": "업무 추가",
|
||||||
"Added successfully!": "성공적으로 추가됨!",
|
"Added successfully!": "성공적으로 추가됨!",
|
||||||
"Administrator": "",
|
"Administrator": "관리자",
|
||||||
"Administrators can always delete any message.": "관리자는 언제든지 모든 메시지를 삭제할 수 있습니다.",
|
"Administrators can always delete any message.": "관리자는 언제든지 모든 메시지를 삭제할 수 있습니다.",
|
||||||
"Admins only": "관리자 만",
|
"Admins only": "관리자 만",
|
||||||
"Alert word": "경고문",
|
"Alert word": "경고문",
|
||||||
@@ -149,7 +149,7 @@
|
|||||||
"Default language": "기본 언어",
|
"Default language": "기본 언어",
|
||||||
"Default streams": "기본 스트림",
|
"Default streams": "기본 스트림",
|
||||||
"Default user settings": "",
|
"Default user settings": "",
|
||||||
"Delete": "",
|
"Delete": "삭제",
|
||||||
"Delete alert word": "경고문 삭제",
|
"Delete alert word": "경고문 삭제",
|
||||||
"Delete avatar": "아바타 삭제",
|
"Delete avatar": "아바타 삭제",
|
||||||
"Delete bot": "봇 삭제",
|
"Delete bot": "봇 삭제",
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
"total": 140
|
"total": 140
|
||||||
},
|
},
|
||||||
"it": {
|
"it": {
|
||||||
"not_translated": 129,
|
"not_translated": 0,
|
||||||
"total": 140
|
"total": 140
|
||||||
},
|
},
|
||||||
"ja": {
|
"ja": {
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
"total": 140
|
"total": 140
|
||||||
},
|
},
|
||||||
"ko": {
|
"ko": {
|
||||||
"not_translated": 10,
|
"not_translated": 9,
|
||||||
"total": 140
|
"total": 140
|
||||||
},
|
},
|
||||||
"ml": {
|
"ml": {
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
"total": 140
|
"total": 140
|
||||||
},
|
},
|
||||||
"zh_Hans": {
|
"zh_Hans": {
|
||||||
"not_translated": 8,
|
"not_translated": 0,
|
||||||
"total": 140
|
"total": 140
|
||||||
},
|
},
|
||||||
"zh_Hant": {
|
"zh_Hant": {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ msgstr ""
|
|||||||
"Project-Id-Version: Zulip\n"
|
"Project-Id-Version: Zulip\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2018-11-03 00:32+0000\n"
|
"POT-Creation-Date: 2018-11-03 00:32+0000\n"
|
||||||
"PO-Revision-Date: 2018-11-05 14:34+0000\n"
|
"PO-Revision-Date: 2018-11-07 18:54+0000\n"
|
||||||
"Last-Translator: André Lopes Pereira <andrelopespereira@gmail.com>\n"
|
"Last-Translator: André Lopes Pereira <andrelopespereira@gmail.com>\n"
|
||||||
"Language-Team: Portuguese (http://www.transifex.com/zulip/zulip/language/pt/)\n"
|
"Language-Team: Portuguese (http://www.transifex.com/zulip/zulip/language/pt/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
@@ -842,7 +842,7 @@ msgstr "Documentação detalhada de atalhos de teclado"
|
|||||||
#: templates/zerver/app/left_sidebar.html:5
|
#: templates/zerver/app/left_sidebar.html:5
|
||||||
#: templates/zerver/app/left_sidebar.html:10
|
#: templates/zerver/app/left_sidebar.html:10
|
||||||
msgid "All messages"
|
msgid "All messages"
|
||||||
msgstr "Todas mensagens"
|
msgstr "Todas as mensagens"
|
||||||
|
|
||||||
#: templates/zerver/app/left_sidebar.html:33
|
#: templates/zerver/app/left_sidebar.html:33
|
||||||
msgid "Starred messages"
|
msgid "Starred messages"
|
||||||
|
|||||||
@@ -276,7 +276,7 @@
|
|||||||
"Mark all messages in <b>__stream.name__</b> as read": "Marcar todas as mensagens em <b>__stream.name__</b> como lidas",
|
"Mark all messages in <b>__stream.name__</b> as read": "Marcar todas as mensagens em <b>__stream.name__</b> como lidas",
|
||||||
"Mark all messages in <b>__topic_name__</b> as read": "Marcar todas as mensagens em <b>__topic_name__</b> como lidas",
|
"Mark all messages in <b>__topic_name__</b> as read": "Marcar todas as mensagens em <b>__topic_name__</b> como lidas",
|
||||||
"Marketing team": "Time de marketing",
|
"Marketing team": "Time de marketing",
|
||||||
"Marking all messages as read\u2026": "Marcando todas as mensagens como lidas...",
|
"Marking all messages as read\u2026": "Marcando todas as mensagens como lidas\\\\u2026",
|
||||||
"Member": "Membro",
|
"Member": "Membro",
|
||||||
"Members and admins": "Membros e administradores",
|
"Members and admins": "Membros e administradores",
|
||||||
"Members and admins, but only admins can add generic bots": "Membros e administradores, mas apenas administradores podem adicionar bots genéricos",
|
"Members and admins, but only admins can add generic bots": "Membros e administradores, mas apenas administradores podem adicionar bots genéricos",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
# Sergey Korablin <s.korablin@gmail.com>, 2018
|
# Sergey Korablin <s.korablin@gmail.com>, 2018
|
||||||
# Sergey Korablin <s.korablin@gmail.com>, 2018
|
# Sergey Korablin <s.korablin@gmail.com>, 2018
|
||||||
# Никита Радченко <aygolan@gmail.com>, 2016
|
# Никита Радченко <aygolan@gmail.com>, 2016
|
||||||
# Султонбек Ахмедов <cooltonbek@gmail.com>, 2018
|
# Султонбек Ахмедов <davlaterra@ya.ru>, 2018
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Zulip\n"
|
"Project-Id-Version: Zulip\n"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Zulip\n"
|
"Project-Id-Version: Zulip\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2018-11-07 15:19+0000\n"
|
"POT-Creation-Date: 2018-11-28 20:32+0000\n"
|
||||||
"PO-Revision-Date: 2018-04-11 21:06+0000\n"
|
"PO-Revision-Date: 2018-04-11 21:06+0000\n"
|
||||||
"Last-Translator: Tim Abbott <tabbott@kandralabs.com>\n"
|
"Last-Translator: Tim Abbott <tabbott@kandralabs.com>\n"
|
||||||
"Language-Team: Tamil (http://www.transifex.com/zulip/zulip/language/ta/)\n"
|
"Language-Team: Tamil (http://www.transifex.com/zulip/zulip/language/ta/)\n"
|
||||||
@@ -1407,9 +1407,10 @@ msgstr ""
|
|||||||
|
|
||||||
#: templates/zerver/emails/compiled/confirm_new_email.html:29
|
#: templates/zerver/emails/compiled/confirm_new_email.html:29
|
||||||
#: templates/zerver/emails/compiled/confirm_registration.html:27
|
#: templates/zerver/emails/compiled/confirm_registration.html:27
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:56
|
#: templates/zerver/emails/compiled/followup_day1.html:55
|
||||||
#: templates/zerver/emails/compiled/invitation.html:26
|
#: templates/zerver/emails/compiled/invitation.html:26
|
||||||
#: templates/zerver/emails/compiled/invitation_reminder.html:22
|
#: templates/zerver/emails/compiled/invitation_reminder.html:22
|
||||||
|
#: templates/zerver/emails/compiled/realm_reactivation.html:36
|
||||||
#: templates/zerver/emails/confirm_new_email.source.html:28
|
#: templates/zerver/emails/confirm_new_email.source.html:28
|
||||||
#: templates/zerver/emails/confirm_new_email.txt:15
|
#: templates/zerver/emails/confirm_new_email.txt:15
|
||||||
#: templates/zerver/emails/confirm_registration.source.html:26
|
#: templates/zerver/emails/confirm_registration.source.html:26
|
||||||
@@ -1425,8 +1426,9 @@ msgstr ""
|
|||||||
|
|
||||||
#: templates/zerver/emails/compiled/confirm_new_email.html:30
|
#: templates/zerver/emails/compiled/confirm_new_email.html:30
|
||||||
#: templates/zerver/emails/compiled/confirm_registration.html:28
|
#: templates/zerver/emails/compiled/confirm_registration.html:28
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:57
|
#: templates/zerver/emails/compiled/followup_day1.html:56
|
||||||
#: templates/zerver/emails/compiled/notify_change_in_email.html:15
|
#: templates/zerver/emails/compiled/notify_change_in_email.html:15
|
||||||
|
#: templates/zerver/emails/compiled/realm_reactivation.html:37
|
||||||
#: templates/zerver/emails/confirm_new_email.source.html:29
|
#: templates/zerver/emails/confirm_new_email.source.html:29
|
||||||
#: templates/zerver/emails/confirm_new_email.txt:16
|
#: templates/zerver/emails/confirm_new_email.txt:16
|
||||||
#: templates/zerver/emails/confirm_registration.source.html:27
|
#: templates/zerver/emails/confirm_registration.source.html:27
|
||||||
@@ -1468,6 +1470,7 @@ msgid "Complete registration"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/confirm_registration.html:20
|
#: templates/zerver/emails/compiled/confirm_registration.html:20
|
||||||
|
#: templates/zerver/emails/compiled/realm_reactivation.html:29
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
@@ -1516,88 +1519,82 @@ msgid "Thanks for using Zulip!"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:9
|
#: templates/zerver/emails/compiled/followup_day1.html:9
|
||||||
#: templates/zerver/emails/compiled/invitation.html:9
|
msgid "Welcome to Zulip!"
|
||||||
#: templates/zerver/emails/followup_day1.source.html:8
|
|
||||||
#: templates/zerver/emails/followup_day1.txt:1
|
|
||||||
#: templates/zerver/emails/invitation.source.html:8
|
|
||||||
#: templates/zerver/emails/invitation.txt:1
|
|
||||||
msgid "Hi there,"
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:11
|
#: templates/zerver/emails/compiled/followup_day1.html:13
|
||||||
#: templates/zerver/emails/followup_day1.source.html:10
|
|
||||||
#: templates/zerver/emails/followup_day1.txt:3
|
|
||||||
msgid "Welcome to Zulip! A few tips to get you started:"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:14
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Zulip works best when it's always open, so we suggest downloading\n"
|
" You've created the new Zulip organization <b>%(realm_name)s</b>.\n"
|
||||||
" our <a href=\"https://zulipchat.com/apps\" style=\"color:hsl(164, 42%%, "
|
" "
|
||||||
"47%%); text-decoration:underline\">desktop and mobile apps</a>.\n"
|
|
||||||
" "
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:19
|
#: templates/zerver/emails/compiled/followup_day1.html:17
|
||||||
#: templates/zerver/emails/followup_day1.source.html:18
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" To access your account from the apps, enter this Organization URL:\n"
|
" You've joined the Zulip organization <b>%(realm_name)s</b>.\n"
|
||||||
" "
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/followup_day1.html:24
|
||||||
|
msgid "Your account details:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/followup_day1.html:26
|
||||||
|
msgid "Organization URL:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:29
|
#: templates/zerver/emails/compiled/followup_day1.html:29
|
||||||
#, python-format
|
msgid "Use your LDAP account to login"
|
||||||
msgid ""
|
|
||||||
"\n"
|
|
||||||
" Become a Zulip pro with a few\n"
|
|
||||||
" <a href=\"%(keyboard_shortcuts_link)s\" style=\"color:hsl(164, 42%%, "
|
|
||||||
"47%%); text-decoration:underline\">keyboard shortcuts</a>:\n"
|
|
||||||
" "
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:34
|
#: templates/zerver/emails/compiled/followup_day1.html:32
|
||||||
#: templates/zerver/emails/followup_day1.source.html:33
|
#, fuzzy
|
||||||
#: templates/zerver/emails/followup_day1.txt:17
|
#| msgid "Email"
|
||||||
msgid "Next unread thread"
|
msgid "Email:"
|
||||||
msgstr ""
|
msgstr "மின்னஞ்சல்"
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:35
|
#: templates/zerver/emails/compiled/followup_day1.html:35
|
||||||
#: templates/zerver/emails/followup_day1.source.html:34
|
|
||||||
#: templates/zerver/emails/followup_day1.txt:18
|
|
||||||
msgid "Reply to message under the blue box"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:36
|
|
||||||
#: templates/zerver/emails/followup_day1.source.html:35
|
|
||||||
#: templates/zerver/emails/followup_day1.txt:19
|
|
||||||
msgid "Start a new topic"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:40
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Give our <a href=\"%(getting_started_link)s\" style=\"color:hsl(164, "
|
" (you'll need these to sign in to the <a href=\"https://zulipchat.com/apps"
|
||||||
"42%%, 47%%); text-decoration:underline\">guide for new\n"
|
"\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">mobile "
|
||||||
" %(user_role_group)s</a> a spin.\n"
|
"and desktop</a> apps)\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/followup_day1.html:42
|
||||||
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
" Check out our <a href=\"%(getting_started_link)s\" style=\"color:"
|
||||||
|
"hsl(164, 42%%, 47%%); text-decoration:underline\">guide for admins</a>, "
|
||||||
|
"become a Zulip pro with a\n"
|
||||||
|
" few <a href=\"%(keyboard_shortcuts_link)s\" style=\"color:hsl(164, "
|
||||||
|
"42%%, 47%%); text-decoration:underline\">keyboard shortcuts</a>, or <a href="
|
||||||
|
"\"%(realm_uri)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:"
|
||||||
|
"underline\">dive right in</a>!\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:47
|
#: templates/zerver/emails/compiled/followup_day1.html:47
|
||||||
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Zulip combines the real-time ease of chat with the threaded "
|
" <a href=\"%(getting_started_link)s\" style=\"color:hsl(164, 42%%, "
|
||||||
"organization\n"
|
"47%%); text-decoration:underline\">Learn more</a> about Zulip, become a pro "
|
||||||
" of email. Zulip is about productivity—making communication fun and\n"
|
"with a few\n"
|
||||||
" easy, while avoiding the distracting and disorganized conversations of\n"
|
" <a href=\"%(keyboard_shortcuts_link)s\" style=\"color:hsl(164, 42%%, "
|
||||||
" chatrooms. We hope you love using Zulip as much as we do.\n"
|
"47%%); text-decoration:underline\">keyboard shortcuts</a>, or <a href="
|
||||||
" "
|
"\"%(realm_uri)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:"
|
||||||
|
"underline\">dive right in</a>!\n"
|
||||||
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:61
|
#: templates/zerver/emails/compiled/followup_day1.html:60
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
@@ -1611,6 +1608,14 @@ msgid ""
|
|||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/invitation.html:9
|
||||||
|
#: templates/zerver/emails/followup_day1.source.html:8
|
||||||
|
#: templates/zerver/emails/followup_day1.txt:1
|
||||||
|
#: templates/zerver/emails/invitation.source.html:8
|
||||||
|
#: templates/zerver/emails/invitation.txt:1
|
||||||
|
msgid "Hi there,"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/invitation.html:12
|
#: templates/zerver/emails/compiled/invitation.html:12
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -1691,6 +1696,38 @@ msgstr ""
|
|||||||
msgid "Best,"
|
msgid "Best,"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/realm_reactivation.html:10
|
||||||
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
" Dear former administrators of %(realm_name)s,\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/realm_reactivation.html:15
|
||||||
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
" One of your administrators requested reactivation of the\n"
|
||||||
|
" previously deactivated Zulip organization hosted at %(realm_uri)s. If "
|
||||||
|
"you'd\n"
|
||||||
|
" like to do confirm that request and reactivate the organization, please "
|
||||||
|
"click here:\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/realm_reactivation.html:21
|
||||||
|
msgid "Reactivate organization"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/compiled/realm_reactivation.html:23
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
" If the request was in error, you can take no action and this link\n"
|
||||||
|
" will expire in 24 hours.\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/confirm_new_email.source.html:21
|
#: templates/zerver/emails/confirm_new_email.source.html:21
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -1735,6 +1772,11 @@ msgid ""
|
|||||||
"questions."
|
"questions."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/followup_day1.source.html:10
|
||||||
|
#: templates/zerver/emails/followup_day1.txt:3
|
||||||
|
msgid "Welcome to Zulip! A few tips to get you started:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/followup_day1.source.html:13
|
#: templates/zerver/emails/followup_day1.source.html:13
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
@@ -1743,6 +1785,13 @@ msgid ""
|
|||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/followup_day1.source.html:18
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
" To access your account from the apps, enter this Organization URL:\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/followup_day1.source.html:28
|
#: templates/zerver/emails/followup_day1.source.html:28
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -1752,6 +1801,21 @@ msgid ""
|
|||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/followup_day1.source.html:33
|
||||||
|
#: templates/zerver/emails/followup_day1.txt:17
|
||||||
|
msgid "Next unread thread"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/followup_day1.source.html:34
|
||||||
|
#: templates/zerver/emails/followup_day1.txt:18
|
||||||
|
msgid "Reply to message under the blue box"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/zerver/emails/followup_day1.source.html:35
|
||||||
|
#: templates/zerver/emails/followup_day1.txt:19
|
||||||
|
msgid "Start a new topic"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: templates/zerver/emails/followup_day1.source.html:39
|
#: templates/zerver/emails/followup_day1.source.html:39
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -3342,43 +3406,43 @@ msgstr ""
|
|||||||
msgid "Wrong subdomain"
|
msgid "Wrong subdomain"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:716 zerver/views/auth.py:747
|
#: zerver/views/auth.py:717 zerver/views/auth.py:748
|
||||||
msgid "Dev environment not enabled."
|
msgid "Dev environment not enabled."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:732 zerver/views/auth.py:780
|
#: zerver/views/auth.py:733 zerver/views/auth.py:781
|
||||||
msgid "This organization has been deactivated."
|
msgid "This organization has been deactivated."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:735 zerver/views/auth.py:777
|
#: zerver/views/auth.py:736 zerver/views/auth.py:778
|
||||||
msgid "Your account has been disabled."
|
msgid "Your account has been disabled."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:738
|
#: zerver/views/auth.py:739
|
||||||
msgid "This user is not registered."
|
msgid "This user is not registered."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:783
|
#: zerver/views/auth.py:784
|
||||||
msgid "Password auth is disabled in your team."
|
msgid "Password auth is disabled in your team."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:789
|
#: zerver/views/auth.py:790
|
||||||
msgid "This user is not registered; do so from a browser."
|
msgid "This user is not registered; do so from a browser."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:791 zerver/views/auth.py:875
|
#: zerver/views/auth.py:792 zerver/views/auth.py:876
|
||||||
msgid "Your username or password is incorrect."
|
msgid "Your username or password is incorrect."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:816
|
#: zerver/views/auth.py:817
|
||||||
msgid "Invalid subdomain"
|
msgid "Invalid subdomain"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:822
|
#: zerver/views/auth.py:823
|
||||||
msgid "Subdomain required"
|
msgid "Subdomain required"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: zerver/views/auth.py:883
|
#: zerver/views/auth.py:884
|
||||||
msgid "GOOGLE_CLIENT_ID is not configured"
|
msgid "GOOGLE_CLIENT_ID is not configured"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ msgstr ""
|
|||||||
"Project-Id-Version: Zulip\n"
|
"Project-Id-Version: Zulip\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2018-11-03 00:32+0000\n"
|
"POT-Creation-Date: 2018-11-03 00:32+0000\n"
|
||||||
"PO-Revision-Date: 2018-11-03 00:04+0000\n"
|
"PO-Revision-Date: 2018-11-08 07:30+0000\n"
|
||||||
"Last-Translator: Tim Abbott <tabbott@kandralabs.com>\n"
|
"Last-Translator: longjiang li <cqlilon@live.com>\n"
|
||||||
"Language-Team: Chinese Simplified (http://www.transifex.com/zulip/zulip/language/zh-Hans/)\n"
|
"Language-Team: Chinese Simplified (http://www.transifex.com/zulip/zulip/language/zh-Hans/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
@@ -318,7 +318,7 @@ msgstr "保存为草稿"
|
|||||||
|
|
||||||
#: templates/zerver/app/compose.html:20
|
#: templates/zerver/app/compose.html:20
|
||||||
msgid "New message"
|
msgid "New message"
|
||||||
msgstr ""
|
msgstr "新消息"
|
||||||
|
|
||||||
#: templates/zerver/app/compose.html:27 templates/zerver/app/compose.html:28
|
#: templates/zerver/app/compose.html:27 templates/zerver/app/compose.html:28
|
||||||
msgid "New topic"
|
msgid "New topic"
|
||||||
@@ -1380,7 +1380,7 @@ msgid ""
|
|||||||
" If you did not request this change, please contact us immediately at\n"
|
" If you did not request this change, please contact us immediately at\n"
|
||||||
" <a href=\"mailto:%(support_email)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">%(support_email)s</a>.\n"
|
" <a href=\"mailto:%(support_email)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">%(support_email)s</a>.\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr "\n如果您没有发送修改请求,请立即联系我们<a href=\"mailto:%(support_email)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">%(support_email)s</a>"
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/confirm_new_email.html:29
|
#: templates/zerver/emails/compiled/confirm_new_email.html:29
|
||||||
#: templates/zerver/emails/compiled/confirm_registration.html:27
|
#: templates/zerver/emails/compiled/confirm_registration.html:27
|
||||||
@@ -1450,7 +1450,7 @@ msgid ""
|
|||||||
" <a href=\"mailto:%(support_email)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">%(support_email)s</a>,\n"
|
" <a href=\"mailto:%(support_email)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">%(support_email)s</a>,\n"
|
||||||
" if you have any questions.\n"
|
" if you have any questions.\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr "\n如果您有任何问题,都可以告诉我们<a href=\"mailto:%(support_email)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">%(support_email)s</a>"
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/find_team.html:9
|
#: templates/zerver/emails/compiled/find_team.html:9
|
||||||
#: templates/zerver/emails/find_team.source.html:8
|
#: templates/zerver/emails/find_team.source.html:8
|
||||||
@@ -1511,7 +1511,7 @@ msgid ""
|
|||||||
" Zulip works best when it's always open, so we suggest downloading\n"
|
" Zulip works best when it's always open, so we suggest downloading\n"
|
||||||
" our <a href=\"https://zulipchat.com/apps\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">desktop and mobile apps</a>.\n"
|
" our <a href=\"https://zulipchat.com/apps\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">desktop and mobile apps</a>.\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr "\n为了使用Zulip时获得更好的体验,建议下载使用<a href=\"https://zulipchat.com/apps\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">桌面端和移动端App</a>"
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:19
|
#: templates/zerver/emails/compiled/followup_day1.html:19
|
||||||
#: templates/zerver/emails/followup_day1.source.html:18
|
#: templates/zerver/emails/followup_day1.source.html:18
|
||||||
@@ -1528,7 +1528,7 @@ msgid ""
|
|||||||
" Become a Zulip pro with a few\n"
|
" Become a Zulip pro with a few\n"
|
||||||
" <a href=\"%(keyboard_shortcuts_link)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">keyboard shortcuts</a>:\n"
|
" <a href=\"%(keyboard_shortcuts_link)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">keyboard shortcuts</a>:\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr "\n为了更方便的使用Zulip,了解一下<a href=\"%(keyboard_shortcuts_link)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">快捷键</a>:"
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:34
|
#: templates/zerver/emails/compiled/followup_day1.html:34
|
||||||
#: templates/zerver/emails/followup_day1.source.html:33
|
#: templates/zerver/emails/followup_day1.source.html:33
|
||||||
@@ -1555,7 +1555,7 @@ msgid ""
|
|||||||
" Give our <a href=\"%(getting_started_link)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">guide for new\n"
|
" Give our <a href=\"%(getting_started_link)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">guide for new\n"
|
||||||
" %(user_role_group)s</a> a spin.\n"
|
" %(user_role_group)s</a> a spin.\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr "\n快速浏览<a href=\"%(getting_started_link)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">%(user_role_group)s新手教程</a>"
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/followup_day1.html:47
|
#: templates/zerver/emails/compiled/followup_day1.html:47
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -1576,7 +1576,7 @@ msgid ""
|
|||||||
" chat with us live on the\n"
|
" chat with us live on the\n"
|
||||||
" <a href=\"https://chat.zulip.org\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">Zulip community server</a>!\n"
|
" <a href=\"https://chat.zulip.org\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">Zulip community server</a>!\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr "\n例如:关注我们的<a href=\"https://twitter.com/zulip\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">Twitter</a>,给我们的<a href=\"https://github.com/zulip/zulip\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">GitHub</a>加星,或者在<a href=\"https://chat.zulip.org\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">Zulip community server</a>和我们在线交流"
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/invitation.html:12
|
#: templates/zerver/emails/compiled/invitation.html:12
|
||||||
#, python-format
|
#, python-format
|
||||||
@@ -1601,7 +1601,7 @@ msgid ""
|
|||||||
"Feel free to give us a shout at <a href=\"mailto:%(support_email)s\" "
|
"Feel free to give us a shout at <a href=\"mailto:%(support_email)s\" "
|
||||||
"style=\"color:hsl(164, 42%%, 47%%); text-"
|
"style=\"color:hsl(164, 42%%, 47%%); text-"
|
||||||
"decoration:underline\">%(support_email)s</a>, if you have any questions."
|
"decoration:underline\">%(support_email)s</a>, if you have any questions."
|
||||||
msgstr ""
|
msgstr "如果您有任何问题,都可以告诉我们<a href=\"mailto:%(support_email)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">%(support_email)s</a>"
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/invitation.html:27
|
#: templates/zerver/emails/compiled/invitation.html:27
|
||||||
#: templates/zerver/emails/compiled/invitation_reminder.html:23
|
#: templates/zerver/emails/compiled/invitation_reminder.html:23
|
||||||
@@ -1625,7 +1625,7 @@ msgid ""
|
|||||||
"href=\"mailto:%(referrer_email)s\" style=\"color:hsl(164, 42%%, 47%%); text-"
|
"href=\"mailto:%(referrer_email)s\" style=\"color:hsl(164, 42%%, 47%%); text-"
|
||||||
"decoration:underline\">%(referrer_email)s</a>) wants you to join them on "
|
"decoration:underline\">%(referrer_email)s</a>) wants you to join them on "
|
||||||
"Zulip, a workplace chat tool that actually makes you more productive."
|
"Zulip, a workplace chat tool that actually makes you more productive."
|
||||||
msgstr ""
|
msgstr "友情提示:%(referrer_name)s(<a href=\"mailto:%(referrer_email)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">%(referrer_email)s</a>)邀请你加入他们的Zulip,一个能大大提高工作效率的交流工具"
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/invitation_reminder.html:19
|
#: templates/zerver/emails/compiled/invitation_reminder.html:19
|
||||||
#, python-format
|
#, python-format
|
||||||
@@ -1633,7 +1633,7 @@ msgid ""
|
|||||||
"We're here for you at <a href=\"mailto:%(support_email)s\" "
|
"We're here for you at <a href=\"mailto:%(support_email)s\" "
|
||||||
"style=\"color:hsl(164, 42%%, 47%%); text-"
|
"style=\"color:hsl(164, 42%%, 47%%); text-"
|
||||||
"decoration:underline\">%(support_email)s</a> if you have any questions."
|
"decoration:underline\">%(support_email)s</a> if you have any questions."
|
||||||
msgstr ""
|
msgstr "如果您有任何问题请联系我们<a href=\"mailto:%(support_email)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">%(support_email)s</a>"
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/notify_change_in_email.html:9
|
#: templates/zerver/emails/compiled/notify_change_in_email.html:9
|
||||||
#: templates/zerver/emails/notify_change_in_email.source.html:8
|
#: templates/zerver/emails/notify_change_in_email.source.html:8
|
||||||
@@ -1651,7 +1651,7 @@ msgid ""
|
|||||||
"change, please contact us immediately at <a "
|
"change, please contact us immediately at <a "
|
||||||
"href=\"mailto:%(support_email)s\" style=\"color:hsl(164, 42%%, 47%%); text-"
|
"href=\"mailto:%(support_email)s\" style=\"color:hsl(164, 42%%, 47%%); text-"
|
||||||
"decoration:underline\">%(support_email)s</a>."
|
"decoration:underline\">%(support_email)s</a>."
|
||||||
msgstr ""
|
msgstr "您Zulip账户关联的电子邮件变更为<a href=\"%(new_email)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">%(new_email)s</a>。如果不是您请求的变更请立即联系我们<a href=\"mailto:%(support_email)s\" style=\"color:hsl(164, 42%%, 47%%); text-decoration:underline\">%(support_email)s</a>"
|
||||||
|
|
||||||
#: templates/zerver/emails/compiled/notify_change_in_email.html:14
|
#: templates/zerver/emails/compiled/notify_change_in_email.html:14
|
||||||
#: templates/zerver/emails/notify_change_in_email.source.html:13
|
#: templates/zerver/emails/notify_change_in_email.source.html:13
|
||||||
@@ -2371,7 +2371,7 @@ msgstr "必须是组织管理员"
|
|||||||
|
|
||||||
#: zerver/decorator.py:142
|
#: zerver/decorator.py:142
|
||||||
msgid "Must be a billing administrator or an organization administrator"
|
msgid "Must be a billing administrator or an organization administrator"
|
||||||
msgstr ""
|
msgstr "必须是账单管理员或者组织管理员"
|
||||||
|
|
||||||
#: zerver/decorator.py:224
|
#: zerver/decorator.py:224
|
||||||
msgid "Invalid subdomain for push notifications bouncer"
|
msgid "Invalid subdomain for push notifications bouncer"
|
||||||
@@ -3011,7 +3011,7 @@ msgstr "名称中有无效字符!"
|
|||||||
|
|
||||||
#: zerver/lib/users.py:39
|
#: zerver/lib/users.py:39
|
||||||
msgid "Name is already in use!"
|
msgid "Name is already in use!"
|
||||||
msgstr ""
|
msgstr "用户名已被占用"
|
||||||
|
|
||||||
#: zerver/lib/users.py:44 zerver/views/users.py:283 zerver/views/users.py:455
|
#: zerver/lib/users.py:44 zerver/views/users.py:283 zerver/views/users.py:455
|
||||||
msgid "Bad name or username"
|
msgid "Bad name or username"
|
||||||
@@ -3736,7 +3736,7 @@ msgstr "无法停用唯一的社群管理员"
|
|||||||
|
|
||||||
#: zerver/views/users.py:97
|
#: zerver/views/users.py:97
|
||||||
msgid "Guests cannot be organization administrators"
|
msgid "Guests cannot be organization administrators"
|
||||||
msgstr ""
|
msgstr "访客不能是组织管理员"
|
||||||
|
|
||||||
#: zerver/views/users.py:101
|
#: zerver/views/users.py:101
|
||||||
msgid "Cannot remove the only organization administrator"
|
msgid "Cannot remove the only organization administrator"
|
||||||
|
|||||||
@@ -292,14 +292,14 @@
|
|||||||
"Mobile notifications": "移动端通知",
|
"Mobile notifications": "移动端通知",
|
||||||
"Mobile notifications always (even when online)": "移动端通知(在线)",
|
"Mobile notifications always (even when online)": "移动端通知(在线)",
|
||||||
"Mobile notifications when offline": "离线时移动端通知",
|
"Mobile notifications when offline": "离线时移动端通知",
|
||||||
"Mobile push notifications are not configured on this server.": "",
|
"Mobile push notifications are not configured on this server.": "服务器未配置移动端推送通知",
|
||||||
"More than 2 weeks ago": "超过2周",
|
"More than 2 weeks ago": "超过2周",
|
||||||
"Mute stream": "静音频道",
|
"Mute stream": "静音频道",
|
||||||
"Mute the stream <b>__stream.name__</b>": "频道"<b>__stream.name__</b>"开启免打扰",
|
"Mute the stream <b>__stream.name__</b>": "频道"<b>__stream.name__</b>"开启免打扰",
|
||||||
"Mute the topic <b>__subject__</b>": "话题"<b>__subject__</b>"开启免打扰",
|
"Mute the topic <b>__subject__</b>": "话题"<b>__subject__</b>"开启免打扰",
|
||||||
"Mute the topic <b>__topic_name__</b>": "话题"<b>__topic_name__</b>"开启免打扰",
|
"Mute the topic <b>__topic_name__</b>": "话题"<b>__topic_name__</b>"开启免打扰",
|
||||||
"Mute topic": "静音主题",
|
"Mute topic": "静音主题",
|
||||||
"Muted streams don't show up in \\\"All messages\\\" or generate notifications unless you are mentioned.": "",
|
"Muted streams don't show up in \\\"All messages\\\" or generate notifications unless you are mentioned.": "开启免打扰频道不会出现在\\\"所有信息 \"\\中,也不会产生通知,除非您被@提醒。",
|
||||||
"Muted topics": "已静音主题",
|
"Muted topics": "已静音主题",
|
||||||
"N": "N",
|
"N": "N",
|
||||||
"Name": "名称",
|
"Name": "名称",
|
||||||
@@ -316,14 +316,14 @@
|
|||||||
"New conversation": "新对话",
|
"New conversation": "新对话",
|
||||||
"New email": "新电子邮件",
|
"New email": "新电子邮件",
|
||||||
"New full name": "新全名",
|
"New full name": "新全名",
|
||||||
"New members can only see messages sent after they join.": "",
|
"New members can only see messages sent after they join.": "新成员只能看到加入后发送的消息。",
|
||||||
"New members can view complete message history.": "",
|
"New members can view complete message history.": "新成员可以查看完整的消息历史。",
|
||||||
"New password": "新密码",
|
"New password": "新密码",
|
||||||
"New password is too weak": "",
|
"New password is too weak": "新密码太弱",
|
||||||
"New private message": "写私信",
|
"New private message": "写私信",
|
||||||
"New stream message": "写消息",
|
"New stream message": "写消息",
|
||||||
"New stream notifications:": "",
|
"New stream notifications:": "新频道通知:",
|
||||||
"New task": "",
|
"New task": "新任务",
|
||||||
"New topic": "新话题",
|
"New topic": "新话题",
|
||||||
"New user notifications:": "新用户通知",
|
"New user notifications:": "新用户通知",
|
||||||
"Next week": "下周",
|
"Next week": "下周",
|
||||||
@@ -334,7 +334,7 @@
|
|||||||
"No default streams match you current filter.": "没有默认频道可以匹配你当前的过滤器。",
|
"No default streams match you current filter.": "没有默认频道可以匹配你当前的过滤器。",
|
||||||
"No description.": "没有描述信息。",
|
"No description.": "没有描述信息。",
|
||||||
"No drafts.": "没有草稿",
|
"No drafts.": "没有草稿",
|
||||||
"No invites match your current filter.": "",
|
"No invites match your current filter.": "没有邀请匹配当前过滤器。",
|
||||||
"No more topics.": "没有更多话题。",
|
"No more topics.": "没有更多话题。",
|
||||||
"No restrictions": "无限制",
|
"No restrictions": "无限制",
|
||||||
"No users match your current filter.": "没有匹配到用户在你的筛选器中。",
|
"No users match your current filter.": "没有匹配到用户在你的筛选器中。",
|
||||||
@@ -346,25 +346,25 @@
|
|||||||
"Notifications stream changed!": "频道通知已更改!",
|
"Notifications stream changed!": "频道通知已更改!",
|
||||||
"Notifications stream disabled!": "频道通知已禁用!",
|
"Notifications stream disabled!": "频道通知已禁用!",
|
||||||
"Old password": "旧密码",
|
"Old password": "旧密码",
|
||||||
"On __last_active__": "",
|
"On __last_active__": "在__last_active__",
|
||||||
"On __last_active_date__": "",
|
"On __last_active_date__": "在__last_active_date__",
|
||||||
"Only organization administrators can add bots to this organization": "只有组织管理员可以将机器人添加到该组织",
|
"Only organization administrators can add bots to this organization": "只有组织管理员可以将机器人添加到该组织",
|
||||||
"Only organization administrators can add custom emoji in this organization.": "只有社群管理员才能自定义表情在这个社群中。",
|
"Only organization administrators can add custom emoji in this organization.": "只有社群管理员才能自定义表情在这个社群中。",
|
||||||
"Only organization administrators can add generic bots": "只有组织管理员可以添加通用机器人",
|
"Only organization administrators can add generic bots": "只有组织管理员可以添加通用机器人",
|
||||||
"Only organization administrators can edit these settings.": "只有社群管理员才能编辑这些设置。",
|
"Only organization administrators can edit these settings.": "只有社群管理员才能编辑这些设置。",
|
||||||
"Only organization administrators can post.": "",
|
"Only organization administrators can post.": "只有组织管理员才能发布。",
|
||||||
"Only organization admins are allowed to post to this stream.": "",
|
"Only organization admins are allowed to post to this stream.": "只有组织管理员可以发布到这个频道。",
|
||||||
"Optional": "可选设置",
|
"Optional": "可选设置",
|
||||||
"Organization": "社群",
|
"Organization": "社群",
|
||||||
"Organization administrators can change this in the organization settings.": "",
|
"Organization administrators can change this in the organization settings.": "组织管理员可以在组织设置中更改此设置。",
|
||||||
"Organization avatar": "社群头像",
|
"Organization avatar": "社群头像",
|
||||||
"Organization description": "",
|
"Organization description": "组织描述",
|
||||||
"Organization name": "社群名称",
|
"Organization name": "社群名称",
|
||||||
"Organization permissions": "社群许可",
|
"Organization permissions": "社群许可",
|
||||||
"Organization profile": "社群资料",
|
"Organization profile": "社群资料",
|
||||||
"Organization settings": "社区设置",
|
"Organization settings": "社区设置",
|
||||||
"Other notification settings": "",
|
"Other notification settings": "其他通知设置",
|
||||||
"Other permissions": "",
|
"Other permissions": "其他权限",
|
||||||
"Outgoing webhook message format": "送出的webhook消息格式",
|
"Outgoing webhook message format": "送出的webhook消息格式",
|
||||||
"Owner": "所有者",
|
"Owner": "所有者",
|
||||||
"Password": "密码",
|
"Password": "密码",
|
||||||
@@ -376,96 +376,96 @@
|
|||||||
"Pin stream to top of left sidebar": "钉住频道在左侧栏的顶部",
|
"Pin stream to top of left sidebar": "钉住频道在左侧栏的顶部",
|
||||||
"Please just upload one file.": "请上传一个文件",
|
"Please just upload one file.": "请上传一个文件",
|
||||||
"Please re-enter your password to confirm your identity.": "请重新输入密码以确认你的身份。",
|
"Please re-enter your password to confirm your identity.": "请重新输入密码以确认你的身份。",
|
||||||
"Please specify a date or time": "",
|
"Please specify a date or time": "请注明日期或时间",
|
||||||
"Please specify a stream": "请指定频道",
|
"Please specify a stream": "请指定频道",
|
||||||
"Please specify a topic": "请指定话题",
|
"Please specify a topic": "请指定话题",
|
||||||
"Please specify at least one valid recipient": "",
|
"Please specify at least one valid recipient": "请至少指定一个可用的收信人",
|
||||||
"Prevent users from changing their email address": "阻止用户更改邮件地址",
|
"Prevent users from changing their email address": "阻止用户更改邮件地址",
|
||||||
"Prevent users from changing their name": "防止用户更改名称",
|
"Prevent users from changing their name": "防止用户更改名称",
|
||||||
"Preview profile": "",
|
"Preview profile": "预览资料",
|
||||||
"Private messages and @-mentions": "私信和@提醒",
|
"Private messages and @-mentions": "私信和@提醒",
|
||||||
"Profile": "",
|
"Profile": "资料",
|
||||||
"Profile field settings": "",
|
"Profile field settings": "资料字段设置",
|
||||||
"Question": "",
|
"Question": "问题",
|
||||||
"Quote and reply": "引用并回复",
|
"Quote and reply": "引用并回复",
|
||||||
"Reactivate": "启用",
|
"Reactivate": "启用",
|
||||||
"Reactivate bot": "重启机器人",
|
"Reactivate bot": "重启机器人",
|
||||||
"Regular expression": "正则表达式",
|
"Regular expression": "正则表达式",
|
||||||
"Remind me about this": "",
|
"Remind me about this": "提醒我",
|
||||||
"Reminder not set!": "",
|
"Reminder not set!": "提醒没有设置!",
|
||||||
"Reminder set!": "",
|
"Reminder set!": "提醒已设置!",
|
||||||
"Remove": "移除",
|
"Remove": "移除",
|
||||||
"Remove from default": "取消默认频道",
|
"Remove from default": "取消默认频道",
|
||||||
"Reply (r)": "",
|
"Reply (r)": "回复(r)",
|
||||||
"Reply mentioning user": "回复提到用户",
|
"Reply mentioning user": "回复提到用户",
|
||||||
"Require topics in stream messages": "频道消息中所需的主题",
|
"Require topics in stream messages": "频道消息中所需的主题",
|
||||||
"Resend": "",
|
"Resend": "重新发送",
|
||||||
"Resend invitation to <span class=\"email\"></span>": "",
|
"Resend invitation to <span class=\"email\"></span>": "重新发送邀请到<span class=\"email\"></span>",
|
||||||
"Resend now": "",
|
"Resend now": "立即重新发送",
|
||||||
"Resending encountered an error. Please reload and try again.": "",
|
"Resending encountered an error. Please reload and try again.": "重发是发生错误。请刷新后再试",
|
||||||
"Restore draft": "恢复草稿",
|
"Restore draft": "恢复草稿",
|
||||||
"Restrict email domains of new users?": "",
|
"Restrict email domains of new users?": "限制新用户的电子邮件域?",
|
||||||
"Restrict posting to organization administrators": "",
|
"Restrict posting to organization administrators": "限制发布到组织管理员",
|
||||||
"Restrict to a list of domains": "",
|
"Restrict to a list of domains": "限制到一个域列表",
|
||||||
"Retry": "重试",
|
"Retry": "重试",
|
||||||
"Revoke": "",
|
"Revoke": "撤销",
|
||||||
"Revoke invitation to <span class=\"email\"></span>": "",
|
"Revoke invitation to <span class=\"email\"></span>": "撤销发送给<span class=\"email\"></span>的邀请",
|
||||||
"Revoke now": "",
|
"Revoke now": "立即撤销",
|
||||||
"Role": "",
|
"Role": "角色",
|
||||||
"Save": "保存",
|
"Save": "保存",
|
||||||
"Save changes": "保存修改",
|
"Save changes": "保存修改",
|
||||||
"Save failed": "",
|
"Save failed": "保存失败",
|
||||||
"Saved": "",
|
"Saved": "已保存",
|
||||||
"Saved. Please <a class='reload_link'>reload</a> for the change to take effect.": "",
|
"Saved. Please <a class='reload_link'>reload</a> for the change to take effect.": "已保存。请<a class='reload_link'>刷新</a>使更改生效",
|
||||||
"Saving": "",
|
"Saving": "保存中",
|
||||||
"Search": "搜索",
|
"Search": "搜索",
|
||||||
"Search operators": "搜索管理者",
|
"Search operators": "搜索管理者",
|
||||||
"Search results": "搜索结果",
|
"Search results": "搜索结果",
|
||||||
"Search subscribers": "搜索订阅者",
|
"Search subscribers": "搜索订阅者",
|
||||||
"Search uploads...": "搜索已上传的文件",
|
"Search uploads...": "搜索已上传的文件",
|
||||||
"See the rest of this message": "查看其余内容",
|
"See the rest of this message": "查看其余内容",
|
||||||
"Select date and time": "",
|
"Select date and time": "选择日期和时间",
|
||||||
"Select default language": "选择默认语言",
|
"Select default language": "选择默认语言",
|
||||||
"Send digest emails when I'm away": "",
|
"Send digest emails when I'm away": "当我离线时发送摘要邮件",
|
||||||
"Send email notifications for new logins to my account": "",
|
"Send email notifications for new logins to my account": "我的帐户进行新的登录时发送电子邮件通知",
|
||||||
"Send emails introducing Zulip to new users": "",
|
"Send emails introducing Zulip to new users": "向新用户发送介绍Zulip的电子邮件",
|
||||||
"Send private message": "发送私有消息",
|
"Send private message": "发送私有消息",
|
||||||
"Sent!": "",
|
"Sent!": "已发送!",
|
||||||
"Settings": "设置",
|
"Settings": "设置",
|
||||||
"Setup": "",
|
"Setup": "设置",
|
||||||
"Setup two factor authentication": "",
|
"Setup two factor authentication": "设置双重认证",
|
||||||
"Show counts for starred messages": "",
|
"Show counts for starred messages": "显示星标消息的数量",
|
||||||
"Show previews of linked websites": "显示链接网站的预览",
|
"Show previews of linked websites": "显示链接网站的预览",
|
||||||
"Show previews of uploaded and linked images": "显示上传文件链接的图像预览",
|
"Show previews of uploaded and linked images": "显示上传文件链接的图像预览",
|
||||||
"Show/change your API key": "显示/修改您的 API Key",
|
"Show/change your API key": "显示/修改您的 API Key",
|
||||||
"Signup notifications stream changed!": "",
|
"Signup notifications stream changed!": "频道注册通知已变更",
|
||||||
"Signup notifications stream disabled!": "",
|
"Signup notifications stream disabled!": "频道注册通知已禁用",
|
||||||
"Size": "大小",
|
"Size": "大小",
|
||||||
"Slack compatible": "高度兼容",
|
"Slack compatible": "高度兼容",
|
||||||
"Slack's outgoing webhooks": "",
|
"Slack's outgoing webhooks": "Slack发送的webhook",
|
||||||
"Sorry, the file was too large.": "对不起,文件太大了。",
|
"Sorry, the file was too large.": "对不起,文件太大了。",
|
||||||
"Star": "星标",
|
"Star": "星标",
|
||||||
"Stream": "频道",
|
"Stream": "频道",
|
||||||
"Stream color": "频道颜色",
|
"Stream color": "频道颜色",
|
||||||
"Stream created recently": "",
|
"Stream created recently": "最近创建的频道",
|
||||||
"Stream creation": "频道创建",
|
"Stream creation": "频道创建",
|
||||||
"Stream description": "频道描述",
|
"Stream description": "频道描述",
|
||||||
"Stream description (optional)": "频道描述(可选)",
|
"Stream description (optional)": "频道描述(可选)",
|
||||||
"Stream membership": "频道用户",
|
"Stream membership": "频道用户",
|
||||||
"Stream messages": "频道消息",
|
"Stream messages": "频道消息",
|
||||||
"Stream name": "频道名称",
|
"Stream name": "频道名称",
|
||||||
"Stream permissions": "",
|
"Stream permissions": "频道权限",
|
||||||
"Stream settings": "频道设置",
|
"Stream settings": "频道设置",
|
||||||
"Stream successfully created!": "",
|
"Stream successfully created!": "频道创建成功",
|
||||||
"Streams": "频道",
|
"Streams": "频道",
|
||||||
"Submit": "",
|
"Submit": "提交",
|
||||||
"Subscribe": "订阅",
|
"Subscribe": "订阅",
|
||||||
"Subscribed": "已订阅",
|
"Subscribed": "已订阅",
|
||||||
"Subscribed successfully!": "",
|
"Subscribed successfully!": "订阅成功",
|
||||||
"Subscriber count": "",
|
"Subscriber count": "订阅者数量",
|
||||||
"Subscribers": "订阅者",
|
"Subscribers": "订阅者",
|
||||||
"Task already exists": "",
|
"Task already exists": "任务已经存在",
|
||||||
"Text": "",
|
"Text": "文本",
|
||||||
"The email body will become the Zulip message": "电子邮件正文将成为Zulip消息",
|
"The email body will become the Zulip message": "电子邮件正文将成为Zulip消息",
|
||||||
"The email subject will become the Zulip topic": "电子邮件正文将成为Zulip话题",
|
"The email subject will become the Zulip topic": "电子邮件正文将成为Zulip话题",
|
||||||
"The email will be forwarded to this stream": "邮件将会转发到这个频道中",
|
"The email will be forwarded to this stream": "邮件将会转发到这个频道中",
|
||||||
@@ -474,27 +474,27 @@
|
|||||||
"The stream description has been updated!": "频道描述信息已更新",
|
"The stream description has been updated!": "频道描述信息已更新",
|
||||||
"The stream has been renamed!": "频道重命名成功!",
|
"The stream has been renamed!": "频道重命名成功!",
|
||||||
"The stream to which new stream notifications go to.": "新流通知发送到的频道。",
|
"The stream to which new stream notifications go to.": "新流通知发送到的频道。",
|
||||||
"The stream which new user signup notifications go to.": "",
|
"The stream which new user signup notifications go to.": "新用户注册通知频道",
|
||||||
"Their password will be cleared from our systems, and any bots they maintain will be disabled.": "这些用户的密码会被从系统中清除,他们的机器人用户也会被关闭。",
|
"Their password will be cleared from our systems, and any bots they maintain will be disabled.": "这些用户的密码会被从系统中清除,他们的机器人用户也会被关闭。",
|
||||||
"There are no messages to reply to.": "",
|
"There are no messages to reply to.": "没有消息可回复",
|
||||||
"These settings are explained in detail in the <a target=\"_blank\" href=\"/help/stream-permissions\">help center</a>.": "",
|
"These settings are explained in detail in the <a target=\"_blank\" href=\"/help/stream-permissions\">help center</a>.": "这些设置在<a target=\"_blank\" href=\"/help/stream-permissions\">帮助中心</a>中有详细说明。",
|
||||||
"This action is permanent and cannot be undone. All users will permanently lose access to their Zulip accounts.": "",
|
"This action is permanent and cannot be undone. All users will permanently lose access to their Zulip accounts.": "这项操作是永久且不可撤销的。所有用户将永久失去对Zulip账户的访问权限。",
|
||||||
"This is a <span class=\"fa fa-globe\" aria-hidden=\"true\"></span> <b>public stream</b>. Anybody in your organization can join.": "",
|
"This is a <span class=\"fa fa-globe\" aria-hidden=\"true\"></span> <b>public stream</b>. Anybody in your organization can join.": "这是一个<span class=\"fa fa-globe\" aria-hidden=\"true\"></span><b>公共频道</b>。所有组织成员都可以加入",
|
||||||
"This is a <span class=\"fa fa-lock\" aria-hidden=\"true\"></span> <b>private stream</b>. Only people who have been invited can access its content, but any member of the stream can invite others.": "",
|
"This is a <span class=\"fa fa-lock\" aria-hidden=\"true\"></span> <b>private stream</b>. Only people who have been invited can access its content, but any member of the stream can invite others.": "这是一个<span class=\"fa fa-lock\" aria-hidden=\"true\"></span><b>私有频道</b>。仅有邀请的用户可以对该频道进行访问,该频道的用户也可以邀请其它用户。",
|
||||||
"This is a private stream": "这是一个私有频道",
|
"This is a private stream": "这是一个私有频道",
|
||||||
"This organization is configured to restrict editing of message content to __minutes_to_edit__ minutes after it is sent.": "这个社群组织已限制讯息发送间隔,请与 __minutes_to_edit__ 分钟后再发。",
|
"This organization is configured to restrict editing of message content to __minutes_to_edit__ minutes after it is sent.": "这个社群组织已限制讯息发送间隔,请与 __minutes_to_edit__ 分钟后再发。",
|
||||||
"This stream is reserved for <strong>announcements</strong>. <br /> Are you sure you want to message all <strong>__count__</strong> people in this stream?": "",
|
"This stream is reserved for <strong>announcements</strong>. <br /> Are you sure you want to message all <strong>__count__</strong> people in this stream?": "此频道用于<strong>公告</strong>。<br />您确定向频道中所有<strong>__count__</strong>人发送消息吗?",
|
||||||
"Time settings": "时间设置",
|
"Time settings": "时间设置",
|
||||||
"Time zone": "时区",
|
"Time zone": "时区",
|
||||||
"Time's up!": "时间到了!",
|
"Time's up!": "时间到了!",
|
||||||
"Today": "今日",
|
"Today": "今日",
|
||||||
"Toggle subscription": "触发订阅",
|
"Toggle subscription": "触发订阅",
|
||||||
"Tomorrow": "",
|
"Tomorrow": "明天",
|
||||||
"Topic": "话题",
|
"Topic": "话题",
|
||||||
"Topic editing only": "只能主题编辑",
|
"Topic editing only": "只能主题编辑",
|
||||||
"Try again": "再试一次",
|
"Try again": "再试一次",
|
||||||
"Two factor authentication": "",
|
"Two factor authentication": "双重认证",
|
||||||
"Type": "",
|
"Type": "类型",
|
||||||
"URL format string": "URL格式",
|
"URL format string": "URL格式",
|
||||||
"Un-collapse": "展开",
|
"Un-collapse": "展开",
|
||||||
"Unable to upload that many files at once.": "无法一次上传这么多的文件。",
|
"Unable to upload that many files at once.": "无法一次上传这么多的文件。",
|
||||||
@@ -507,35 +507,35 @@
|
|||||||
"Unpin stream <b>__stream.name__</b> from top": "取消频道\"<b>__stream.name__</b>\"置顶",
|
"Unpin stream <b>__stream.name__</b> from top": "取消频道\"<b>__stream.name__</b>\"置顶",
|
||||||
"Unstar": "取消星标",
|
"Unstar": "取消星标",
|
||||||
"Unsubscribe": "退订",
|
"Unsubscribe": "退订",
|
||||||
"Unsubscribed successfully!": "",
|
"Unsubscribed successfully!": "退订成功",
|
||||||
"Up to N minutes after posting": "",
|
"Up to N minutes after posting": "发布后N分钟",
|
||||||
"Up to __time_limit__ after posting": "",
|
"Up to __time_limit__ after posting": "发布后__time_limit__",
|
||||||
"Update successful: Subdomains allowed for __domain__": "更新成功:允许新的域名于__domain__",
|
"Update successful: Subdomains allowed for __domain__": "更新成功:允许新的域名于__domain__",
|
||||||
"Update successful: Subdomains no longer allowed for __domain__": "更新成功:不在允许这个域名 __domain__",
|
"Update successful: Subdomains no longer allowed for __domain__": "更新成功:不在允许这个域名 __domain__",
|
||||||
"Updated settings!": "",
|
"Updated settings!": "更新设置",
|
||||||
"Updated successfully!": "更新成功!",
|
"Updated successfully!": "更新成功!",
|
||||||
"Upload avatar": "上传头像",
|
"Upload avatar": "上传头像",
|
||||||
"Upload icon": "上传图标",
|
"Upload icon": "上传图标",
|
||||||
"Upload image or GIF": "",
|
"Upload image or GIF": "上传图片",
|
||||||
"Upload new avatar": "上传一个新头像",
|
"Upload new avatar": "上传一个新头像",
|
||||||
"Upload new icon": "上传新图标",
|
"Upload new icon": "上传新图标",
|
||||||
"Uploaded files": "已上传文件",
|
"Uploaded files": "已上传文件",
|
||||||
"Uploading icon.": "图标上传中",
|
"Uploading icon.": "图标上传中",
|
||||||
"Uploading\u2026": "上传",
|
"Uploading\u2026": "上传",
|
||||||
"User already subscribed.": "",
|
"User already subscribed.": "用户已经订阅",
|
||||||
"User avatar": "用户头像",
|
"User avatar": "用户头像",
|
||||||
"User group added!": "",
|
"User group added!": "用户组已添加",
|
||||||
"User groups": "用户组",
|
"User groups": "用户组",
|
||||||
"User identity": "用户标识",
|
"User identity": "用户标识",
|
||||||
"User is already not subscribed.": "",
|
"User is already not subscribed.": "用户没有订阅",
|
||||||
"User list on left sidebar in narrow windows": "窗口右侧变懒的用户列表",
|
"User list on left sidebar in narrow windows": "窗口右侧变懒的用户列表",
|
||||||
"User role": "",
|
"User role": "用户角色",
|
||||||
"User settings": "用户设置",
|
"User settings": "用户设置",
|
||||||
"User(s) invited successfully.": "",
|
"User(s) invited successfully.": "用户邀请成功",
|
||||||
"Username": "用户名",
|
"Username": "用户名",
|
||||||
"Username (a-z, 0-9, and dashes only)": "",
|
"Username (a-z, 0-9, and dashes only)": "用户名(字母、数字和下划线)",
|
||||||
"Users can edit the topic of any message": "",
|
"Users can edit the topic of any message": "用户可以编辑消息的主题",
|
||||||
"Video chat provider": "",
|
"Video chat provider": "视频聊天提供者",
|
||||||
"View edit history": "显示编辑历史 ",
|
"View edit history": "显示编辑历史 ",
|
||||||
"View file": "显示文件",
|
"View file": "显示文件",
|
||||||
"View messages sent": "显示已发送消息",
|
"View messages sent": "显示已发送消息",
|
||||||
@@ -543,58 +543,58 @@
|
|||||||
"View source": "显示源",
|
"View source": "显示源",
|
||||||
"View source / Edit topic": "查看源 / 编辑主题",
|
"View source / Edit topic": "查看源 / 编辑主题",
|
||||||
"View stream": "显示频道",
|
"View stream": "显示频道",
|
||||||
"View user profile": "",
|
"View user profile": "查看用户资料",
|
||||||
"View your profile": "",
|
"View your profile": "查看我的资料",
|
||||||
"Visual desktop notifications": "",
|
"Visual desktop notifications": "可视桌面通知",
|
||||||
"Warning: <strong>__stream_name__</strong> is a private stream.": "",
|
"Warning: <strong>__stream_name__</strong> is a private stream.": "警告:<strong>__stream_name__</strong>是私有频道",
|
||||||
"Who can add bots": "",
|
"Who can add bots": "谁能添加机器人",
|
||||||
"Who can add custom emoji": "",
|
"Who can add custom emoji": "谁能添加自定义表情",
|
||||||
"Who can create streams": "",
|
"Who can create streams": "谁能创建频道",
|
||||||
"Working\u2026": "进行中",
|
"Working\u2026": "进行中",
|
||||||
"Yes": "是",
|
"Yes": "是",
|
||||||
"Yes, delete this stream": "是的,删除该频道",
|
"Yes, delete this stream": "是的,删除该频道",
|
||||||
"Yes, send": "是的,发送",
|
"Yes, send": "是的,发送",
|
||||||
"Yes, subscribe __count__ users!": "确定,订阅 __count__ 用户!",
|
"Yes, subscribe __count__ users!": "确定,订阅 __count__ 用户!",
|
||||||
"Yes. Members and admins can send invitations.": "",
|
"Yes. Members and admins can send invitations.": "是的,普通成员和管理员可以发送邀请",
|
||||||
"Yes. Only admins can send invitations.": "",
|
"Yes. Only admins can send invitations.": "是的,只有管理员可以发送邀请",
|
||||||
"Yesterday": "昨天",
|
"Yesterday": "昨天",
|
||||||
"You and __display_reply_to__": "您和__display_reply_to__",
|
"You and __display_reply_to__": "您和__display_reply_to__",
|
||||||
"You and __recipients__": "你和 __recipients__",
|
"You and __recipients__": "你和 __recipients__",
|
||||||
"You are not currently subscribed to this stream.": "您目前未订阅此频道。",
|
"You are not currently subscribed to this stream.": "您目前未订阅此频道。",
|
||||||
"You are not subscribed to stream __stream__": "你没有订阅__stream__频道",
|
"You are not subscribed to stream __stream__": "你没有订阅__stream__频道",
|
||||||
"You can send emails to Zulip! Just copy and use this address as an email recipient, and:": "您可以发送电子邮件给Zulip! 只需复制并使用此地址作为电子邮件收件人,并且:",
|
"You can send emails to Zulip! Just copy and use this address as an email recipient, and:": "您可以发送电子邮件给Zulip! 只需复制并使用此地址作为电子邮件收件人,并且:",
|
||||||
"You cannot create a stream with no subscribers!": "",
|
"You cannot create a stream with no subscribers!": "创建频道时必须有订阅者",
|
||||||
"You have no active bots.": "你没有可用的机器人。",
|
"You have no active bots.": "你没有可用的机器人。",
|
||||||
"You have no inactive bots.": "你没有不可用的机器人。",
|
"You have no inactive bots.": "你没有不可用的机器人。",
|
||||||
"You have not muted any topics yet.": "你还没有任何静音的话题",
|
"You have not muted any topics yet.": "你还没有任何静音的话题",
|
||||||
"You have not uploaded any files.": "目前没有上传任何文件。",
|
"You have not uploaded any files.": "目前没有上传任何文件。",
|
||||||
"You have nothing to send!": "消息不能为空!",
|
"You have nothing to send!": "消息不能为空!",
|
||||||
"You must be an organization administrator to create a stream without subscribing.": "",
|
"You must be an organization administrator to create a stream without subscribing.": "您必须是组织管理员才能在不订阅的情况下创建频道",
|
||||||
"You need to be running Zephyr mirroring in order to send messages!": "您需要运行Zephyr镜像服务以便发送消息!",
|
"You need to be running Zephyr mirroring in order to send messages!": "您需要运行Zephyr镜像服务以便发送消息!",
|
||||||
"You subscribed to stream __stream__": "你订阅了 __stream__ 频道",
|
"You subscribed to stream __stream__": "你订阅了 __stream__ 频道",
|
||||||
"You unsubscribed from stream __stream__": "你取消订阅了 __stream__ 频道",
|
"You unsubscribed from stream __stream__": "你取消订阅了 __stream__ 频道",
|
||||||
"You're not subscribed to this stream. You will not be notified if other users reply to your message.": "",
|
"You're not subscribed to this stream. You will not be notified if other users reply to your message.": "您没有订阅这个频道。如果其他用户回复您的邮件,您将不会收到通知。",
|
||||||
"Your API key:": "您的 API Key:",
|
"Your API key:": "您的 API Key:",
|
||||||
"Your account": "你的账户",
|
"Your account": "你的账户",
|
||||||
"Your bots": "你的机器人",
|
"Your bots": "你的机器人",
|
||||||
"Your reminder note is empty!": "",
|
"Your reminder note is empty!": "您没有提醒事项",
|
||||||
"[Condense this message]": "[收起消息]",
|
"[Condense this message]": "[收起消息]",
|
||||||
"[Configure]": "",
|
"[Configure]": "[配置]",
|
||||||
"[Disable]": "[禁用]",
|
"[Disable]": "[禁用]",
|
||||||
"[More...]": "[更多...]",
|
"[More...]": "[更多...]",
|
||||||
"__hours__ hours ago": "",
|
"__hours__ hours ago": "__hours__小时以前",
|
||||||
"__minutes__ min to edit": "__minutes__分钟内完成编辑",
|
"__minutes__ min to edit": "__minutes__分钟内完成编辑",
|
||||||
"__minutes__ minutes ago": "",
|
"__minutes__ minutes ago": "__minutes__分钟以前",
|
||||||
"__seconds__ sec to edit": "__seconds__秒内完成编辑",
|
"__seconds__ sec to edit": "__seconds__秒内完成编辑",
|
||||||
"__starred_status__ this message": "__starred_status__这个消息",
|
"__starred_status__ this message": "__starred_status__这个消息",
|
||||||
"__wildcard_mention_token__ (Notify stream)": "",
|
"__wildcard_mention_token__ (Notify stream)": "__wildcard_mention_token__ (通知频道)",
|
||||||
"and": "来",
|
"and": "来",
|
||||||
"cookie": "cookie",
|
"cookie": "cookie",
|
||||||
"in 1 hour": "1小时内",
|
"in 1 hour": "1小时内",
|
||||||
"in 20 minutes": "20分钟内",
|
"in 20 minutes": "20分钟内",
|
||||||
"in 3 hours": "3小时内",
|
"in 3 hours": "3小时内",
|
||||||
"leafy green vegetable": "",
|
"leafy green vegetable": "绿叶蔬菜",
|
||||||
"marketing": "",
|
"marketing": "销售",
|
||||||
"more conversations": "更多会话",
|
"more conversations": "更多会话",
|
||||||
"more topics": "更多话题"
|
"more topics": "更多话题"
|
||||||
}
|
}
|
||||||
@@ -33,9 +33,10 @@ organization first.
|
|||||||
|
|
||||||
### Import into a self-hosted Zulip server
|
### Import into a self-hosted Zulip server
|
||||||
|
|
||||||
Because the import tool is very new, you will need to
|
First
|
||||||
upgrade your Zulip server to the latest `master` branch,
|
[install a new Zulip server](https://zulip.readthedocs.io/en/stable/production/install.html),
|
||||||
using [upgrade-zulip-from-git][upgrade-zulip-from-git].
|
skipping "Step 3: Create a Zulip organization, and log in" (you'll
|
||||||
|
create your Zulip organization via the data import tool instead).
|
||||||
|
|
||||||
Log in to a shell on your Zulip server as the `zulip` user. To import with
|
Log in to a shell on your Zulip server as the `zulip` user. To import with
|
||||||
the most common configuration, run the following commands, replacing
|
the most common configuration, run the following commands, replacing
|
||||||
|
|||||||
@@ -65,6 +65,11 @@ organization first.
|
|||||||
|
|
||||||
### Import into a self-hosted Zulip server
|
### Import into a self-hosted Zulip server
|
||||||
|
|
||||||
|
First
|
||||||
|
[install a new Zulip server](https://zulip.readthedocs.io/en/stable/production/install.html),
|
||||||
|
skipping "Step 3: Create a Zulip organization, and log in" (you'll
|
||||||
|
create your Zulip organization via the data import tool instead).
|
||||||
|
|
||||||
Because the import tool is very new, you will need to
|
Because the import tool is very new, you will need to
|
||||||
upgrade your Zulip server to the latest `master` branch,
|
upgrade your Zulip server to the latest `master` branch,
|
||||||
using [upgrade-zulip-from-git][upgrade-zulip-from-git].
|
using [upgrade-zulip-from-git][upgrade-zulip-from-git].
|
||||||
|
|||||||
@@ -35,9 +35,10 @@ organization first.
|
|||||||
|
|
||||||
### Import into a self-hosted Zulip server
|
### Import into a self-hosted Zulip server
|
||||||
|
|
||||||
Because the import tool is very new, you will need to
|
First
|
||||||
upgrade your Zulip server to the latest `master` branch,
|
[install a new Zulip server](https://zulip.readthedocs.io/en/stable/production/install.html),
|
||||||
using [upgrade-zulip-from-git][upgrade-zulip-from-git].
|
skipping "Step 3: Create a Zulip organization, and log in" (you'll
|
||||||
|
create your Zulip organization via the data import tool instead).
|
||||||
|
|
||||||
Log in to a shell on your Zulip server as the `zulip` user. To import with
|
Log in to a shell on your Zulip server as the `zulip` user. To import with
|
||||||
the most common configuration, run the following commands, replacing
|
the most common configuration, run the following commands, replacing
|
||||||
|
|||||||
@@ -770,6 +770,10 @@ def build_custom_checkers(by_lang):
|
|||||||
'include_only': set(['docs/']),
|
'include_only': set(['docs/']),
|
||||||
'description': "Use relative links (../foo/bar.html) to other documents in docs/",
|
'description': "Use relative links (../foo/bar.html) to other documents in docs/",
|
||||||
},
|
},
|
||||||
|
{'pattern': "su zulip -c [^']",
|
||||||
|
'include_only': set(['docs/']),
|
||||||
|
'description': "Always quote arguments using `su zulip -c '` to avoid confusion about how su works.",
|
||||||
|
},
|
||||||
{'pattern': r'\][(][^#h]',
|
{'pattern': r'\][(][^#h]',
|
||||||
'include_only': set(['README.md', 'CONTRIBUTING.md']),
|
'include_only': set(['README.md', 'CONTRIBUTING.md']),
|
||||||
'description': "Use absolute links from docs served by GitHub",
|
'description': "Use absolute links from docs served by GitHub",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
ZULIP_VERSION = "1.9.0"
|
ZULIP_VERSION = "1.9.1"
|
||||||
|
|
||||||
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
# Bump the minor PROVISION_VERSION to indicate that folks should provision
|
||||||
# only when going from an old version of the code to a newer version. Bump
|
# only when going from an old version of the code to a newer version. Bump
|
||||||
|
|||||||
@@ -388,11 +388,11 @@ def process_avatars(avatar_list: List[ZerverFieldsT], avatar_dir: str, realm_id:
|
|||||||
downloaded. For simpler conversions see write_avatar_png.
|
downloaded. For simpler conversions see write_avatar_png.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_avatar(avatar_upload_list: List[str]) -> int:
|
def get_avatar(avatar_upload_item: List[str]) -> int:
|
||||||
avatar_url = avatar_upload_list[0]
|
avatar_url = avatar_upload_item[0]
|
||||||
|
|
||||||
image_path = os.path.join(avatar_dir, avatar_original_list[1])
|
image_path = os.path.join(avatar_dir, avatar_upload_item[1])
|
||||||
original_image_path = os.path.join(avatar_dir, avatar_original_list[2])
|
original_image_path = os.path.join(avatar_dir, avatar_upload_item[2])
|
||||||
|
|
||||||
response = requests.get(avatar_url + size_url_suffix, stream=True)
|
response = requests.get(avatar_url + size_url_suffix, stream=True)
|
||||||
with open(image_path, 'wb') as image_file:
|
with open(image_path, 'wb') as image_file:
|
||||||
|
|||||||
@@ -599,7 +599,8 @@ def import_uploads_s3(bucket_name: str, import_dir: Path, processing_avatars: bo
|
|||||||
user_profile = get_user_profile_by_id(user_profile_id)
|
user_profile = get_user_profile_by_id(user_profile_id)
|
||||||
key.set_metadata("user_profile_id", str(user_profile.id))
|
key.set_metadata("user_profile_id", str(user_profile.id))
|
||||||
|
|
||||||
key.set_metadata("orig_last_modified", record['last_modified'])
|
if 'last_modified' in record:
|
||||||
|
key.set_metadata("orig_last_modified", record['last_modified'])
|
||||||
key.set_metadata("realm_id", str(record['realm_id']))
|
key.set_metadata("realm_id", str(record['realm_id']))
|
||||||
|
|
||||||
# Zulip exports will always have a content-type, but third-party exports might not.
|
# Zulip exports will always have a content-type, but third-party exports might not.
|
||||||
|
|||||||
@@ -114,8 +114,8 @@ def send_apple_push_notification(user_id: int, devices: List[DeviceToken],
|
|||||||
|
|
||||||
client = get_apns_client() # type: APNsClient
|
client = get_apns_client() # type: APNsClient
|
||||||
if client is None:
|
if client is None:
|
||||||
logging.warning("APNs: Dropping a notification because nothing configured. "
|
logging.debug("APNs: Dropping a notification because nothing configured. "
|
||||||
"Set PUSH_NOTIFICATION_BOUNCER_URL (or APNS_CERT_FILE).")
|
"Set PUSH_NOTIFICATION_BOUNCER_URL (or APNS_CERT_FILE).")
|
||||||
return
|
return
|
||||||
|
|
||||||
if remote:
|
if remote:
|
||||||
@@ -186,8 +186,8 @@ def send_android_push_notification_to_user(user_profile: UserProfile, data: Dict
|
|||||||
def send_android_push_notification(devices: List[DeviceToken], data: Dict[str, Any],
|
def send_android_push_notification(devices: List[DeviceToken], data: Dict[str, Any],
|
||||||
remote: bool=False) -> None:
|
remote: bool=False) -> None:
|
||||||
if not gcm:
|
if not gcm:
|
||||||
logging.warning("Skipping sending a GCM push notification since "
|
logging.debug("Skipping sending a GCM push notification since "
|
||||||
"PUSH_NOTIFICATION_BOUNCER_URL and ANDROID_GCM_API_KEY are both unset")
|
"PUSH_NOTIFICATION_BOUNCER_URL and ANDROID_GCM_API_KEY are both unset")
|
||||||
return
|
return
|
||||||
reg_ids = [device.token for device in devices]
|
reg_ids = [device.token for device in devices]
|
||||||
|
|
||||||
@@ -429,6 +429,12 @@ def push_notifications_enabled() -> bool:
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def initialize_push_notifications() -> None:
|
||||||
|
if not push_notifications_enabled():
|
||||||
|
logging.warning("Mobile push notifications are not configured.\n "
|
||||||
|
"See https://zulip.readthedocs.io/en/latest/"
|
||||||
|
"production/mobile-push-notifications.html")
|
||||||
|
|
||||||
def get_gcm_alert(message: Message) -> str:
|
def get_gcm_alert(message: Message) -> str:
|
||||||
"""
|
"""
|
||||||
Determine what alert string to display based on the missed messages.
|
Determine what alert string to display based on the missed messages.
|
||||||
@@ -637,7 +643,7 @@ def handle_push_notification(user_profile_id: int, missed_message: Dict[str, Any
|
|||||||
user_profile = get_user_profile_by_id(user_profile_id)
|
user_profile = get_user_profile_by_id(user_profile_id)
|
||||||
(message, user_message) = access_message(user_profile, missed_message['message_id'])
|
(message, user_message) = access_message(user_profile, missed_message['message_id'])
|
||||||
if user_message is not None:
|
if user_message is not None:
|
||||||
# If ther user has read the message already, don't push-notify.
|
# If the user has read the message already, don't push-notify.
|
||||||
#
|
#
|
||||||
# TODO: It feels like this is already handled when things are
|
# TODO: It feels like this is already handled when things are
|
||||||
# put in the queue; maybe we should centralize this logic with
|
# put in the queue; maybe we should centralize this logic with
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ class S3UploadBackend(ZulipUploadBackend):
|
|||||||
bucket_name = settings.S3_AVATAR_BUCKET
|
bucket_name = settings.S3_AVATAR_BUCKET
|
||||||
conn = S3Connection(settings.S3_KEY, settings.S3_SECRET_KEY)
|
conn = S3Connection(settings.S3_KEY, settings.S3_SECRET_KEY)
|
||||||
bucket = get_bucket(conn, bucket_name)
|
bucket = get_bucket(conn, bucket_name)
|
||||||
key = bucket.get_key(file_path)
|
key = bucket.get_key(file_path + ".original")
|
||||||
image_data = key.get_contents_as_string()
|
image_data = key.get_contents_as_string()
|
||||||
|
|
||||||
resized_medium = resize_avatar(image_data, MEDIUM_AVATAR_SIZE) # type: ignore # image_data is `bytes`, boto subs are wrong
|
resized_medium = resize_avatar(image_data, MEDIUM_AVATAR_SIZE) # type: ignore # image_data is `bytes`, boto subs are wrong
|
||||||
|
|||||||
@@ -3,26 +3,20 @@ import sys
|
|||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import CommandError
|
||||||
|
|
||||||
from zerver.models import Realm, get_realm
|
from zerver.lib.management import ZulipBaseCommand
|
||||||
|
from zerver.models import get_realm
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(ZulipBaseCommand):
|
||||||
help = """Show the admins in a realm."""
|
help = """Show the admins in a realm."""
|
||||||
|
|
||||||
def add_arguments(self, parser: ArgumentParser) -> None:
|
def add_arguments(self, parser: ArgumentParser) -> None:
|
||||||
parser.add_argument('realm', metavar='<realm>', type=str,
|
self.add_realm_args(parser, required=True)
|
||||||
help="realm to show admins for")
|
|
||||||
|
|
||||||
def handle(self, *args: Any, **options: str) -> None:
|
|
||||||
realm_name = options['realm']
|
|
||||||
|
|
||||||
try:
|
|
||||||
realm = get_realm(realm_name)
|
|
||||||
except Realm.DoesNotExist:
|
|
||||||
print('There is no realm called %s.' % (realm_name,))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
def handle(self, *args: Any, **options: Any) -> None:
|
||||||
|
realm = self.get_realm(options)
|
||||||
|
assert realm is not None # True because of required=True above
|
||||||
users = realm.get_admin_users()
|
users = realm.get_admin_users()
|
||||||
|
|
||||||
if users:
|
if users:
|
||||||
@@ -32,4 +26,5 @@ class Command(BaseCommand):
|
|||||||
else:
|
else:
|
||||||
print('There are no admins for this realm!')
|
print('There are no admins for this realm!')
|
||||||
|
|
||||||
print('\nYou can use the "knight" management command to knight admins.')
|
print('\nYou can use the "knight" management command to make more users admins.')
|
||||||
|
print('\nOr with the --revoke argument, remove admin status from users.')
|
||||||
|
|||||||
@@ -668,10 +668,15 @@ class TestAPNs(PushNotificationTest):
|
|||||||
mock.patch('zerver.lib.push_notifications.logging') as mock_logging:
|
mock.patch('zerver.lib.push_notifications.logging') as mock_logging:
|
||||||
mock_get.return_value = None
|
mock_get.return_value = None
|
||||||
self.send()
|
self.send()
|
||||||
mock_logging.warning.assert_called_once_with(
|
mock_logging.debug.assert_called_once_with(
|
||||||
"APNs: Dropping a notification because nothing configured. "
|
"APNs: Dropping a notification because nothing configured. "
|
||||||
"Set PUSH_NOTIFICATION_BOUNCER_URL (or APNS_CERT_FILE).")
|
"Set PUSH_NOTIFICATION_BOUNCER_URL (or APNS_CERT_FILE).")
|
||||||
mock_logging.info.assert_not_called()
|
mock_logging.warning.assert_not_called()
|
||||||
|
from zerver.lib.push_notifications import initialize_push_notifications
|
||||||
|
initialize_push_notifications()
|
||||||
|
mock_logging.warning.assert_called_once_with(
|
||||||
|
"Mobile push notifications are not configured.\n "
|
||||||
|
"See https://zulip.readthedocs.io/en/latest/production/mobile-push-notifications.html")
|
||||||
|
|
||||||
def test_success(self) -> None:
|
def test_success(self) -> None:
|
||||||
with self.mock_apns() as mock_apns, \
|
with self.mock_apns() as mock_apns, \
|
||||||
@@ -1154,11 +1159,11 @@ class GCMTest(PushNotificationTest):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
class GCMNotSetTest(GCMTest):
|
class GCMNotSetTest(GCMTest):
|
||||||
@mock.patch('logging.warning')
|
@mock.patch('logging.debug')
|
||||||
def test_gcm_is_none(self, mock_warning: mock.MagicMock) -> None:
|
def test_gcm_is_none(self, mock_debug: mock.MagicMock) -> None:
|
||||||
apn.gcm = None
|
apn.gcm = None
|
||||||
apn.send_android_push_notification_to_user(self.user_profile, {})
|
apn.send_android_push_notification_to_user(self.user_profile, {})
|
||||||
mock_warning.assert_called_with(
|
mock_debug.assert_called_with(
|
||||||
"Skipping sending a GCM push notification since PUSH_NOTIFICATION_BOUNCER_URL "
|
"Skipping sending a GCM push notification since PUSH_NOTIFICATION_BOUNCER_URL "
|
||||||
"and ANDROID_GCM_API_KEY are both unset")
|
"and ANDROID_GCM_API_KEY are both unset")
|
||||||
|
|
||||||
|
|||||||
@@ -348,6 +348,7 @@ def send_oauth_request_to_google(request: HttpRequest) -> HttpResponse:
|
|||||||
'redirect_uri': reverse_on_root('zerver.views.auth.finish_google_oauth2'),
|
'redirect_uri': reverse_on_root('zerver.views.auth.finish_google_oauth2'),
|
||||||
'scope': 'profile email',
|
'scope': 'profile email',
|
||||||
'state': csrf_state,
|
'state': csrf_state,
|
||||||
|
'prompt': 'select_account',
|
||||||
}
|
}
|
||||||
return redirect(google_uri + urllib.parse.urlencode(params))
|
return redirect(google_uri + urllib.parse.urlencode(params))
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ from zerver.lib.feedback import handle_feedback
|
|||||||
from zerver.lib.queue import SimpleQueueClient, queue_json_publish, retry_event
|
from zerver.lib.queue import SimpleQueueClient, queue_json_publish, retry_event
|
||||||
from zerver.lib.timestamp import timestamp_to_datetime
|
from zerver.lib.timestamp import timestamp_to_datetime
|
||||||
from zerver.lib.notifications import handle_missedmessage_emails
|
from zerver.lib.notifications import handle_missedmessage_emails
|
||||||
from zerver.lib.push_notifications import handle_push_notification, handle_remove_push_notification
|
from zerver.lib.push_notifications import handle_push_notification, handle_remove_push_notification, \
|
||||||
|
initialize_push_notifications
|
||||||
from zerver.lib.actions import do_send_confirmation_email, \
|
from zerver.lib.actions import do_send_confirmation_email, \
|
||||||
do_update_user_activity, do_update_user_activity_interval, do_update_user_presence, \
|
do_update_user_activity, do_update_user_activity_interval, do_update_user_presence, \
|
||||||
internal_send_message, check_send_message, extract_recipients, \
|
internal_send_message, check_send_message, extract_recipients, \
|
||||||
@@ -352,6 +353,13 @@ class MissedMessageSendingWorker(EmailSendingWorker): # nocoverage
|
|||||||
|
|
||||||
@assign_queue('missedmessage_mobile_notifications')
|
@assign_queue('missedmessage_mobile_notifications')
|
||||||
class PushNotificationsWorker(QueueProcessingWorker): # nocoverage
|
class PushNotificationsWorker(QueueProcessingWorker): # nocoverage
|
||||||
|
def start(self) -> None:
|
||||||
|
# initialize_push_notifications doesn't strictly do anything
|
||||||
|
# beyond printing some logging warnings if push notifications
|
||||||
|
# are not available in the current configuration.
|
||||||
|
initialize_push_notifications()
|
||||||
|
super().start()
|
||||||
|
|
||||||
def consume(self, data: Mapping[str, Any]) -> None:
|
def consume(self, data: Mapping[str, Any]) -> None:
|
||||||
if data.get("type", "add") == "remove":
|
if data.get("type", "add") == "remove":
|
||||||
handle_remove_push_notification(data['user_profile_id'], data['message_id'])
|
handle_remove_push_notification(data['user_profile_id'], data['message_id'])
|
||||||
|
|||||||
@@ -71,8 +71,13 @@ ZULIP_ADMINISTRATOR = 'zulip-admin@example.com'
|
|||||||
# The noreply address to be used as the sender for certain generated
|
# The noreply address to be used as the sender for certain generated
|
||||||
# emails. Messages sent to this address could contain sensitive user
|
# emails. Messages sent to this address could contain sensitive user
|
||||||
# data and should not be delivered anywhere. The default is
|
# data and should not be delivered anywhere. The default is
|
||||||
# e.g. noreply@zulip.example.com (if EXTERNAL_HOST is
|
# e.g. noreply-{random_token}@zulip.example.com (if EXTERNAL_HOST is
|
||||||
# zulip.example.com).
|
# zulip.example.com). There are potential security issues if you set
|
||||||
|
# ADD_TOKENS_TO_NOREPLY_ADDRESS=False to remove the token; see
|
||||||
|
# https://zulip.readthedocs.io/en/latest/production/email.html for details.
|
||||||
|
#ADD_TOKENS_TO_NOREPLY_ADDRESS = True
|
||||||
|
#TOKENIZED_NOREPLY_EMAIL_ADDRESS = "noreply-{token}@example.com"
|
||||||
|
# Used for noreply emails only if ADD_TOKENS_TO_NOREPLY_ADDRESS=False
|
||||||
#NOREPLY_EMAIL_ADDRESS = 'noreply@example.com'
|
#NOREPLY_EMAIL_ADDRESS = 'noreply@example.com'
|
||||||
|
|
||||||
# Many countries and bulk mailers require certain types of email to display
|
# Many countries and bulk mailers require certain types of email to display
|
||||||
|
|||||||
Reference in New Issue
Block a user