mirror of
https://github.com/spiral-project/ihatemoney.git
synced 2025-05-06 05:01:48 +02:00
Merge branch 'master' into improve_history_localization
This commit is contained in:
commit
b6820095d7
54 changed files with 4786 additions and 3628 deletions
|
@ -4,6 +4,9 @@ python:
|
||||||
- "3.6"
|
- "3.6"
|
||||||
- "3.7"
|
- "3.7"
|
||||||
- "3.8"
|
- "3.8"
|
||||||
|
- "3.9"
|
||||||
script: tox
|
script: tox
|
||||||
|
before_install:
|
||||||
|
- python -m pip install --upgrade pip virtualenv
|
||||||
install:
|
install:
|
||||||
- pip install tox-travis
|
- pip install tox-travis
|
||||||
|
|
|
@ -15,7 +15,9 @@ ENV NIGHTLY="" \
|
||||||
ACTIVATE_DEMO_PROJECT="True" \
|
ACTIVATE_DEMO_PROJECT="True" \
|
||||||
ADMIN_PASSWORD="" \
|
ADMIN_PASSWORD="" \
|
||||||
ALLOW_PUBLIC_PROJECT_CREATION="True" \
|
ALLOW_PUBLIC_PROJECT_CREATION="True" \
|
||||||
ACTIVATE_ADMIN_DASHBOARD="False"
|
ACTIVATE_ADMIN_DASHBOARD="False" \
|
||||||
|
BABEL_DEFAULT_TIMEZONE="UTC" \
|
||||||
|
GREENLET_TEST_CPP="no"
|
||||||
|
|
||||||
RUN apk update && apk add git gcc libc-dev libffi-dev openssl-dev wget &&\
|
RUN apk update && apk add git gcc libc-dev libffi-dev openssl-dev wget &&\
|
||||||
mkdir -p /etc/ihatemoney &&\
|
mkdir -p /etc/ihatemoney &&\
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -46,7 +46,7 @@ test: install-dev ## Run the tests
|
||||||
|
|
||||||
.PHONY: black
|
.PHONY: black
|
||||||
black: install-dev ## Run the tests
|
black: install-dev ## Run the tests
|
||||||
$(VENV)/bin/black --target-version=py34 .
|
$(VENV)/bin/black --target-version=py36 .
|
||||||
|
|
||||||
.PHONY: isort
|
.PHONY: isort
|
||||||
isort: install-dev ## Run the tests
|
isort: install-dev ## Run the tests
|
||||||
|
|
|
@ -9,6 +9,10 @@ I hate money
|
||||||
:target: https://hosted.weblate.org/engage/i-hate-money/?utm_source=widget
|
:target: https://hosted.weblate.org/engage/i-hate-money/?utm_source=widget
|
||||||
:alt: Translation status from Weblate
|
:alt: Translation status from Weblate
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/liberapay/receives/IHateMoney.svg?logo=liberapay
|
||||||
|
:target: https://liberapay.com/IHateMoney/donate
|
||||||
|
:alt: Donate
|
||||||
|
|
||||||
*I hate money* is a web application made to ease shared budget management.
|
*I hate money* is a web application made to ease shared budget management.
|
||||||
It keeps track of who bought what, when, and for whom; and helps to settle the
|
It keeps track of who bought what, when, and for whom; and helps to settle the
|
||||||
bills.
|
bills.
|
||||||
|
@ -25,7 +29,7 @@ encouraged to do so.
|
||||||
Requirements
|
Requirements
|
||||||
============
|
============
|
||||||
|
|
||||||
* **Python**: 3.6, 3.7, 3.8.
|
* **Python**: version 3.6 to 3.9.
|
||||||
* **Backends**: MySQL, PostgreSQL, SQLite, Memory.
|
* **Backends**: MySQL, PostgreSQL, SQLite, Memory.
|
||||||
|
|
||||||
Contributing
|
Contributing
|
||||||
|
@ -35,6 +39,8 @@ Do you wish to contribute to IHateMoney? Fantastic! There's a lot of very
|
||||||
useful help on the official `contributing
|
useful help on the official `contributing
|
||||||
<https://ihatemoney.readthedocs.io/en/latest/contributing.html>`_ page.
|
<https://ihatemoney.readthedocs.io/en/latest/contributing.html>`_ page.
|
||||||
|
|
||||||
|
You can also `donate some money <https://liberapay.com/IHateMoney/donate>`_. All funds will be used to maintain the `hosted version <https://ihatemoney.org>`_.
|
||||||
|
|
||||||
Translation status
|
Translation status
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ ACTIVATE_DEMO_PROJECT = $ACTIVATE_DEMO_PROJECT
|
||||||
ADMIN_PASSWORD = '$ADMIN_PASSWORD'
|
ADMIN_PASSWORD = '$ADMIN_PASSWORD'
|
||||||
ALLOW_PUBLIC_PROJECT_CREATION = $ALLOW_PUBLIC_PROJECT_CREATION
|
ALLOW_PUBLIC_PROJECT_CREATION = $ALLOW_PUBLIC_PROJECT_CREATION
|
||||||
ACTIVATE_ADMIN_DASHBOARD = $ACTIVATE_ADMIN_DASHBOARD
|
ACTIVATE_ADMIN_DASHBOARD = $ACTIVATE_ADMIN_DASHBOARD
|
||||||
|
BABEL_DEFAULT_TIMEZONE = "$BABEL_DEFAULT_TIMEZONE"
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
if [ "$NIGHTLY" == "True" -o "$NIGHTLY" == "true" ]; then
|
if [ "$NIGHTLY" == "True" -o "$NIGHTLY" == "true" ]; then
|
||||||
|
|
|
@ -31,6 +31,7 @@ connection string. This will look like::
|
||||||
|
|
||||||
SQLALCHEMY_DATABASE_URI = 'postgresql://myuser:mypass@localhost/dbname?client_encoding=utf8'
|
SQLALCHEMY_DATABASE_URI = 'postgresql://myuser:mypass@localhost/dbname?client_encoding=utf8'
|
||||||
|
|
||||||
|
.. _the SQLAlchemy documentation: http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls
|
||||||
|
|
||||||
`SECRET_KEY`
|
`SECRET_KEY`
|
||||||
------------
|
------------
|
||||||
|
@ -96,7 +97,26 @@ if set to ``"somestring"``, it will be served from a "folder"
|
||||||
|
|
||||||
- **Default value:** ``""`` (empty string)
|
- **Default value:** ``""`` (empty string)
|
||||||
|
|
||||||
.. _the SQLAlchemy documentation: http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls
|
`BABEL_DEFAULT_TIMEZONE`
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
The timezone that will be used to convert date and time when displaying them
|
||||||
|
to the user (all times are always stored in UTC internally).
|
||||||
|
If not set, it will default to the timezone configured on the Operating System
|
||||||
|
of the server running ihatemoney, which may or may not be what you want.
|
||||||
|
|
||||||
|
- **Default value:** *unset* (use the timezone of the server Operating System)
|
||||||
|
- **Production value:** Set to the timezone of your expected users, with a
|
||||||
|
format such as ``"Europe/Paris"``. See `this list of TZ database names`_
|
||||||
|
for a complete list.
|
||||||
|
|
||||||
|
Note: this setting is actually interpreted by Flask-Babel, see the
|
||||||
|
`Flask-Babel guide for formatting dates`_ for details.
|
||||||
|
|
||||||
|
.. _this list of TZ database name: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
|
||||||
|
|
||||||
|
.. _Flask-Babel guide for formatting dates: https://pythonhosted.org/Flask-Babel/#formatting-dates
|
||||||
|
|
||||||
|
|
||||||
Configuring emails sending
|
Configuring emails sending
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
|
@ -19,7 +19,7 @@ Requirements
|
||||||
|
|
||||||
«Ihatemoney» depends on:
|
«Ihatemoney» depends on:
|
||||||
|
|
||||||
* **Python**: either 3.6, 3.7 or 3.8 will work.
|
* **Python**: version 3.6 to 3.9 included will work.
|
||||||
* **A Backend**: to choose among MySQL, PostgreSQL, SQLite or Memory.
|
* **A Backend**: to choose among MySQL, PostgreSQL, SQLite or Memory.
|
||||||
* **Virtual environment** (recommended): `python3-venv` package under Debian/Ubuntu.
|
* **Virtual environment** (recommended): `python3-venv` package under Debian/Ubuntu.
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
Sphinx==3.3.0
|
Sphinx==3.5.3
|
||||||
docutils==0.16
|
docutils==0.17
|
||||||
|
|
|
@ -34,3 +34,7 @@ ALLOW_PUBLIC_PROJECT_CREATION = True
|
||||||
|
|
||||||
# If set to True, an administration dashboard is available.
|
# If set to True, an administration dashboard is available.
|
||||||
ACTIVATE_ADMIN_DASHBOARD = False
|
ACTIVATE_ADMIN_DASHBOARD = False
|
||||||
|
|
||||||
|
# You can change the timezone used to display time. By default it will be
|
||||||
|
#derived from the server OS.
|
||||||
|
#BABEL_DEFAULT_TIMEZONE = "Europe/Paris"
|
||||||
|
|
|
@ -14,7 +14,7 @@ class Singleton(type):
|
||||||
class CurrencyConverter(object, metaclass=Singleton):
|
class CurrencyConverter(object, metaclass=Singleton):
|
||||||
# Get exchange rates
|
# Get exchange rates
|
||||||
no_currency = "XXX"
|
no_currency = "XXX"
|
||||||
api_url = "https://api.exchangeratesapi.io/latest?base=USD"
|
api_url = "https://api.exchangerate.host/latest?base=USD"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -18,10 +18,12 @@ SUPPORTED_LANGUAGES = [
|
||||||
"nb_NO",
|
"nb_NO",
|
||||||
"nl",
|
"nl",
|
||||||
"pl",
|
"pl",
|
||||||
|
"pt",
|
||||||
"pt_BR",
|
"pt_BR",
|
||||||
"ru",
|
"ru",
|
||||||
"ta",
|
"ta",
|
||||||
"tr",
|
"tr",
|
||||||
"uk",
|
"uk",
|
||||||
"zh_Hans",
|
"zh_Hans",
|
||||||
|
"ja",
|
||||||
]
|
]
|
||||||
|
|
|
@ -80,7 +80,7 @@ def get_history(project, human_readable_names=True):
|
||||||
object_str = describe_version(version)
|
object_str = describe_version(version)
|
||||||
|
|
||||||
common_properties = {
|
common_properties = {
|
||||||
"time": version.transaction.issued_at.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
"time": version.transaction.issued_at,
|
||||||
"operation_type": version.operation_type,
|
"operation_type": version.operation_type,
|
||||||
"object_type": object_type,
|
"object_type": object_type,
|
||||||
"object_desc": object_str,
|
"object_desc": object_str,
|
||||||
|
|
|
@ -77,7 +77,7 @@ def run_migrations_online():
|
||||||
target_metadata=target_metadata,
|
target_metadata=target_metadata,
|
||||||
include_object=include_object,
|
include_object=include_object,
|
||||||
process_revision_directives=process_revision_directives,
|
process_revision_directives=process_revision_directives,
|
||||||
**current_app.extensions["migrate"].configure_args
|
**current_app.extensions["migrate"].configure_args,
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -96,7 +96,7 @@ class PatchedRelationShipBuilder(RelationshipBuilder):
|
||||||
association_col
|
association_col
|
||||||
== self.association_version_table.c[association_col.name]
|
== self.association_version_table.c[association_col.name]
|
||||||
for association_col in association_cols
|
for association_col in association_cols
|
||||||
]
|
],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.group_by(*association_cols)
|
.group_by(*association_cols)
|
||||||
|
|
|
@ -2,6 +2,7 @@ import os
|
||||||
import os.path
|
import os.path
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
from babel.dates import LOCALTZ
|
||||||
from flask import Flask, g, render_template, request, session
|
from flask import Flask, g, render_template, request, session
|
||||||
from flask_babel import Babel, format_currency
|
from flask_babel import Babel, format_currency
|
||||||
from flask_mail import Mail
|
from flask_mail import Mail
|
||||||
|
@ -152,8 +153,10 @@ def create_app(
|
||||||
app.jinja_env.filters["minimal_round"] = minimal_round
|
app.jinja_env.filters["minimal_round"] = minimal_round
|
||||||
app.jinja_env.filters["localize_list"] = localize_list
|
app.jinja_env.filters["localize_list"] = localize_list
|
||||||
|
|
||||||
# Translations
|
# Translations and time zone (used to display dates). The timezone is
|
||||||
babel = Babel(app)
|
# taken from the BABEL_DEFAULT_TIMEZONE settings, and falls back to
|
||||||
|
# the local timezone of the server OS by using LOCALTZ.
|
||||||
|
babel = Babel(app, default_timezone=str(LOCALTZ))
|
||||||
|
|
||||||
# Undocumented currencyformat filter from flask_babel is forwarding to Babel format_currency
|
# Undocumented currencyformat filter from flask_babel is forwarding to Babel format_currency
|
||||||
# We overwrite it to remove the currency sign ¤ when there is no currency
|
# We overwrite it to remove the currency sign ¤ when there is no currency
|
||||||
|
@ -169,7 +172,7 @@ def create_app(
|
||||||
number,
|
number,
|
||||||
currency if currency != CurrencyConverter.no_currency else "",
|
currency if currency != CurrencyConverter.no_currency else "",
|
||||||
*args,
|
*args,
|
||||||
**kwargs
|
**kwargs,
|
||||||
).strip()
|
).strip()
|
||||||
|
|
||||||
app.jinja_env.filters["currency"] = currency
|
app.jinja_env.filters["currency"] = currency
|
||||||
|
|
13
ihatemoney/static/css/download_mobile_app.css
Normal file
13
ihatemoney/static/css/download_mobile_app.css
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
.get-it-from {
|
||||||
|
width: 100px;
|
||||||
|
min-height: 110px;
|
||||||
|
border: 5px solid floralwhite;
|
||||||
|
background-color: white; margin: 10px;
|
||||||
|
}
|
||||||
|
.get-it-from:hover {
|
||||||
|
opacity: 80%;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
background: linear-gradient(150deg, #abe128 0%, #43ca61 100%);
|
||||||
|
font-family: 'Comfortaa', arial, serif;
|
||||||
|
}
|
129
ihatemoney/static/images/app-store.svg
Normal file
129
ihatemoney/static/images/app-store.svg
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="US_UK_Download_on_the" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
x="0px" y="0px" width="135px" height="40px" viewBox="0 0 135 40" enable-background="new 0 0 135 40" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="#A6A6A6" d="M130.197,40H4.729C2.122,40,0,37.872,0,35.267V4.726C0,2.12,2.122,0,4.729,0h125.468
|
||||||
|
C132.803,0,135,2.12,135,4.726v30.541C135,37.872,132.803,40,130.197,40L130.197,40z"/>
|
||||||
|
<path d="M134.032,35.268c0,2.116-1.714,3.83-3.834,3.83H4.729c-2.119,0-3.839-1.714-3.839-3.83V4.725
|
||||||
|
c0-2.115,1.72-3.835,3.839-3.835h125.468c2.121,0,3.834,1.72,3.834,3.835L134.032,35.268L134.032,35.268z"/>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#FFFFFF" d="M30.128,19.784c-0.029-3.223,2.639-4.791,2.761-4.864c-1.511-2.203-3.853-2.504-4.676-2.528
|
||||||
|
c-1.967-0.207-3.875,1.177-4.877,1.177c-1.022,0-2.565-1.157-4.228-1.123c-2.14,0.033-4.142,1.272-5.24,3.196
|
||||||
|
c-2.266,3.923-0.576,9.688,1.595,12.859c1.086,1.553,2.355,3.287,4.016,3.226c1.625-0.067,2.232-1.036,4.193-1.036
|
||||||
|
c1.943,0,2.513,1.036,4.207,0.997c1.744-0.028,2.842-1.56,3.89-3.127c1.255-1.78,1.759-3.533,1.779-3.623
|
||||||
|
C33.507,24.924,30.161,23.647,30.128,19.784z"/>
|
||||||
|
<path fill="#FFFFFF" d="M26.928,10.306c0.874-1.093,1.472-2.58,1.306-4.089c-1.265,0.056-2.847,0.875-3.758,1.944
|
||||||
|
c-0.806,0.942-1.526,2.486-1.34,3.938C24.557,12.205,26.016,11.382,26.928,10.306z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path fill="#FFFFFF" d="M53.645,31.504h-2.271l-1.244-3.909h-4.324l-1.185,3.909h-2.211l4.284-13.308h2.646L53.645,31.504z
|
||||||
|
M49.755,25.955L48.63,22.48c-0.119-0.355-0.342-1.191-0.671-2.507h-0.04c-0.131,0.566-0.342,1.402-0.632,2.507l-1.105,3.475
|
||||||
|
H49.755z"/>
|
||||||
|
<path fill="#FFFFFF" d="M64.662,26.588c0,1.632-0.441,2.922-1.323,3.869c-0.79,0.843-1.771,1.264-2.942,1.264
|
||||||
|
c-1.264,0-2.172-0.454-2.725-1.362h-0.04v5.055h-2.132V25.067c0-1.026-0.027-2.079-0.079-3.159h1.875l0.119,1.521h0.04
|
||||||
|
c0.711-1.146,1.79-1.718,3.238-1.718c1.132,0,2.077,0.447,2.833,1.342C64.284,23.949,64.662,25.127,64.662,26.588z M62.49,26.666
|
||||||
|
c0-0.934-0.21-1.704-0.632-2.31c-0.461-0.632-1.08-0.948-1.856-0.948c-0.526,0-1.004,0.176-1.431,0.523
|
||||||
|
c-0.428,0.35-0.708,0.807-0.839,1.373c-0.066,0.264-0.099,0.48-0.099,0.65v1.6c0,0.698,0.214,1.287,0.642,1.768
|
||||||
|
s0.984,0.721,1.668,0.721c0.803,0,1.428-0.31,1.875-0.928C62.266,28.496,62.49,27.68,62.49,26.666z"/>
|
||||||
|
<path fill="#FFFFFF" d="M75.699,26.588c0,1.632-0.441,2.922-1.324,3.869c-0.789,0.843-1.77,1.264-2.941,1.264
|
||||||
|
c-1.264,0-2.172-0.454-2.724-1.362H68.67v5.055h-2.132V25.067c0-1.026-0.027-2.079-0.079-3.159h1.875l0.119,1.521h0.04
|
||||||
|
c0.71-1.146,1.789-1.718,3.238-1.718c1.131,0,2.076,0.447,2.834,1.342C75.32,23.949,75.699,25.127,75.699,26.588z M73.527,26.666
|
||||||
|
c0-0.934-0.211-1.704-0.633-2.31c-0.461-0.632-1.078-0.948-1.855-0.948c-0.527,0-1.004,0.176-1.432,0.523
|
||||||
|
c-0.428,0.35-0.707,0.807-0.838,1.373c-0.065,0.264-0.099,0.48-0.099,0.65v1.6c0,0.698,0.214,1.287,0.64,1.768
|
||||||
|
c0.428,0.48,0.984,0.721,1.67,0.721c0.803,0,1.428-0.31,1.875-0.928C73.303,28.496,73.527,27.68,73.527,26.666z"/>
|
||||||
|
<path fill="#FFFFFF" d="M88.039,27.772c0,1.132-0.393,2.053-1.182,2.764c-0.867,0.777-2.074,1.165-3.625,1.165
|
||||||
|
c-1.432,0-2.58-0.276-3.449-0.829l0.494-1.777c0.936,0.566,1.963,0.85,3.082,0.85c0.803,0,1.428-0.182,1.877-0.544
|
||||||
|
c0.447-0.362,0.67-0.848,0.67-1.454c0-0.54-0.184-0.995-0.553-1.364c-0.367-0.369-0.98-0.712-1.836-1.029
|
||||||
|
c-2.33-0.869-3.494-2.142-3.494-3.816c0-1.094,0.408-1.991,1.225-2.689c0.814-0.699,1.9-1.048,3.258-1.048
|
||||||
|
c1.211,0,2.217,0.211,3.02,0.632l-0.533,1.738c-0.75-0.408-1.598-0.612-2.547-0.612c-0.75,0-1.336,0.185-1.756,0.553
|
||||||
|
c-0.355,0.329-0.533,0.73-0.533,1.205c0,0.526,0.203,0.961,0.611,1.303c0.355,0.316,1,0.658,1.936,1.027
|
||||||
|
c1.145,0.461,1.986,1,2.527,1.618C87.77,26.081,88.039,26.852,88.039,27.772z"/>
|
||||||
|
<path fill="#FFFFFF" d="M95.088,23.508h-2.35v4.659c0,1.185,0.414,1.777,1.244,1.777c0.381,0,0.697-0.033,0.947-0.099l0.059,1.619
|
||||||
|
c-0.42,0.157-0.973,0.236-1.658,0.236c-0.842,0-1.5-0.257-1.975-0.77c-0.473-0.514-0.711-1.376-0.711-2.587v-4.837h-1.4v-1.6h1.4
|
||||||
|
v-1.757l2.094-0.632v2.389h2.35V23.508z"/>
|
||||||
|
<path fill="#FFFFFF" d="M105.691,26.627c0,1.475-0.422,2.686-1.264,3.633c-0.883,0.975-2.055,1.461-3.516,1.461
|
||||||
|
c-1.408,0-2.529-0.467-3.365-1.401s-1.254-2.113-1.254-3.534c0-1.487,0.43-2.705,1.293-3.652c0.861-0.948,2.023-1.422,3.484-1.422
|
||||||
|
c1.408,0,2.541,0.467,3.396,1.402C105.283,24.021,105.691,25.192,105.691,26.627z M103.479,26.696
|
||||||
|
c0-0.885-0.189-1.644-0.572-2.277c-0.447-0.766-1.086-1.148-1.914-1.148c-0.857,0-1.508,0.383-1.955,1.148
|
||||||
|
c-0.383,0.634-0.572,1.405-0.572,2.317c0,0.885,0.189,1.644,0.572,2.276c0.461,0.766,1.105,1.148,1.936,1.148
|
||||||
|
c0.814,0,1.453-0.39,1.914-1.168C103.281,28.347,103.479,27.58,103.479,26.696z"/>
|
||||||
|
<path fill="#FFFFFF" d="M112.621,23.783c-0.211-0.039-0.436-0.059-0.672-0.059c-0.75,0-1.33,0.283-1.738,0.85
|
||||||
|
c-0.355,0.5-0.533,1.132-0.533,1.895v5.035h-2.131l0.02-6.574c0-1.106-0.027-2.113-0.08-3.021h1.857l0.078,1.836h0.059
|
||||||
|
c0.225-0.631,0.58-1.139,1.066-1.52c0.475-0.343,0.988-0.514,1.541-0.514c0.197,0,0.375,0.014,0.533,0.039V23.783z"/>
|
||||||
|
<path fill="#FFFFFF" d="M122.156,26.252c0,0.382-0.025,0.704-0.078,0.967h-6.396c0.025,0.948,0.334,1.673,0.928,2.173
|
||||||
|
c0.539,0.447,1.236,0.671,2.092,0.671c0.947,0,1.811-0.151,2.588-0.454l0.334,1.48c-0.908,0.396-1.98,0.593-3.217,0.593
|
||||||
|
c-1.488,0-2.656-0.438-3.506-1.313c-0.848-0.875-1.273-2.05-1.273-3.524c0-1.447,0.395-2.652,1.186-3.613
|
||||||
|
c0.828-1.026,1.947-1.539,3.355-1.539c1.383,0,2.43,0.513,3.141,1.539C121.873,24.047,122.156,25.055,122.156,26.252z
|
||||||
|
M120.123,25.699c0.014-0.632-0.125-1.178-0.414-1.639c-0.369-0.593-0.936-0.889-1.699-0.889c-0.697,0-1.264,0.289-1.697,0.869
|
||||||
|
c-0.355,0.461-0.566,1.014-0.631,1.658H120.123z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path fill="#FFFFFF" d="M49.05,10.009c0,1.177-0.353,2.063-1.058,2.658c-0.653,0.549-1.581,0.824-2.783,0.824
|
||||||
|
c-0.596,0-1.106-0.026-1.533-0.078V6.982c0.557-0.09,1.157-0.136,1.805-0.136c1.145,0,2.008,0.249,2.59,0.747
|
||||||
|
C48.723,8.156,49.05,8.961,49.05,10.009z M47.945,10.038c0-0.763-0.202-1.348-0.606-1.756c-0.404-0.407-0.994-0.611-1.771-0.611
|
||||||
|
c-0.33,0-0.611,0.022-0.844,0.068v4.889c0.129,0.02,0.365,0.029,0.708,0.029c0.802,0,1.421-0.223,1.857-0.669
|
||||||
|
S47.945,10.892,47.945,10.038z"/>
|
||||||
|
<path fill="#FFFFFF" d="M54.909,11.037c0,0.725-0.207,1.319-0.621,1.785c-0.434,0.479-1.009,0.718-1.727,0.718
|
||||||
|
c-0.692,0-1.243-0.229-1.654-0.689c-0.41-0.459-0.615-1.038-0.615-1.736c0-0.73,0.211-1.329,0.635-1.794s0.994-0.698,1.712-0.698
|
||||||
|
c0.692,0,1.248,0.229,1.669,0.688C54.708,9.757,54.909,10.333,54.909,11.037z M53.822,11.071c0-0.435-0.094-0.808-0.281-1.119
|
||||||
|
c-0.22-0.376-0.533-0.564-0.94-0.564c-0.421,0-0.741,0.188-0.961,0.564c-0.188,0.311-0.281,0.69-0.281,1.138
|
||||||
|
c0,0.435,0.094,0.808,0.281,1.119c0.227,0.376,0.543,0.564,0.951,0.564c0.4,0,0.714-0.191,0.94-0.574
|
||||||
|
C53.725,11.882,53.822,11.506,53.822,11.071z"/>
|
||||||
|
<path fill="#FFFFFF" d="M62.765,8.719l-1.475,4.714h-0.96l-0.611-2.047c-0.155-0.511-0.281-1.019-0.379-1.523h-0.019
|
||||||
|
c-0.091,0.518-0.217,1.025-0.379,1.523l-0.649,2.047h-0.971l-1.387-4.714h1.077l0.533,2.241c0.129,0.53,0.235,1.035,0.32,1.513
|
||||||
|
h0.019c0.078-0.394,0.207-0.896,0.389-1.503l0.669-2.25h0.854l0.641,2.202c0.155,0.537,0.281,1.054,0.378,1.552h0.029
|
||||||
|
c0.071-0.485,0.178-1.002,0.32-1.552l0.572-2.202H62.765z"/>
|
||||||
|
<path fill="#FFFFFF" d="M68.198,13.433H67.15v-2.7c0-0.832-0.316-1.248-0.95-1.248c-0.311,0-0.562,0.114-0.757,0.343
|
||||||
|
c-0.193,0.229-0.291,0.499-0.291,0.808v2.796h-1.048v-3.366c0-0.414-0.013-0.863-0.038-1.349h0.921l0.049,0.737h0.029
|
||||||
|
c0.122-0.229,0.304-0.418,0.543-0.569c0.284-0.176,0.602-0.265,0.95-0.265c0.44,0,0.806,0.142,1.097,0.427
|
||||||
|
c0.362,0.349,0.543,0.87,0.543,1.562V13.433z"/>
|
||||||
|
<path fill="#FFFFFF" d="M71.088,13.433h-1.047V6.556h1.047V13.433z"/>
|
||||||
|
<path fill="#FFFFFF" d="M77.258,11.037c0,0.725-0.207,1.319-0.621,1.785c-0.434,0.479-1.01,0.718-1.727,0.718
|
||||||
|
c-0.693,0-1.244-0.229-1.654-0.689c-0.41-0.459-0.615-1.038-0.615-1.736c0-0.73,0.211-1.329,0.635-1.794s0.994-0.698,1.711-0.698
|
||||||
|
c0.693,0,1.248,0.229,1.67,0.688C77.057,9.757,77.258,10.333,77.258,11.037z M76.17,11.071c0-0.435-0.094-0.808-0.281-1.119
|
||||||
|
c-0.219-0.376-0.533-0.564-0.939-0.564c-0.422,0-0.742,0.188-0.961,0.564c-0.188,0.311-0.281,0.69-0.281,1.138
|
||||||
|
c0,0.435,0.094,0.808,0.281,1.119c0.227,0.376,0.543,0.564,0.951,0.564c0.4,0,0.713-0.191,0.939-0.574
|
||||||
|
C76.074,11.882,76.17,11.506,76.17,11.071z"/>
|
||||||
|
<path fill="#FFFFFF" d="M82.33,13.433h-0.941l-0.078-0.543h-0.029c-0.322,0.433-0.781,0.65-1.377,0.65
|
||||||
|
c-0.445,0-0.805-0.143-1.076-0.427c-0.246-0.258-0.369-0.579-0.369-0.96c0-0.576,0.24-1.015,0.723-1.319
|
||||||
|
c0.482-0.304,1.16-0.453,2.033-0.446V10.3c0-0.621-0.326-0.931-0.979-0.931c-0.465,0-0.875,0.117-1.229,0.349l-0.213-0.688
|
||||||
|
c0.438-0.271,0.979-0.407,1.617-0.407c1.232,0,1.85,0.65,1.85,1.95v1.736C82.262,12.78,82.285,13.155,82.33,13.433z
|
||||||
|
M81.242,11.813v-0.727c-1.156-0.02-1.734,0.297-1.734,0.95c0,0.246,0.066,0.43,0.201,0.553c0.135,0.123,0.307,0.184,0.512,0.184
|
||||||
|
c0.23,0,0.445-0.073,0.641-0.218c0.197-0.146,0.318-0.331,0.363-0.558C81.236,11.946,81.242,11.884,81.242,11.813z"/>
|
||||||
|
<path fill="#FFFFFF" d="M88.285,13.433h-0.93l-0.049-0.757h-0.029c-0.297,0.576-0.803,0.864-1.514,0.864
|
||||||
|
c-0.568,0-1.041-0.223-1.416-0.669s-0.562-1.025-0.562-1.736c0-0.763,0.203-1.381,0.611-1.853c0.395-0.44,0.879-0.66,1.455-0.66
|
||||||
|
c0.633,0,1.076,0.213,1.328,0.64h0.02V6.556h1.049v5.607C88.248,12.622,88.26,13.045,88.285,13.433z M87.199,11.445v-0.786
|
||||||
|
c0-0.136-0.01-0.246-0.029-0.33c-0.059-0.252-0.186-0.464-0.379-0.635c-0.195-0.171-0.43-0.257-0.701-0.257
|
||||||
|
c-0.391,0-0.697,0.155-0.922,0.466c-0.223,0.311-0.336,0.708-0.336,1.193c0,0.466,0.107,0.844,0.322,1.135
|
||||||
|
c0.227,0.31,0.533,0.465,0.916,0.465c0.344,0,0.619-0.129,0.828-0.388C87.1,12.069,87.199,11.781,87.199,11.445z"/>
|
||||||
|
<path fill="#FFFFFF" d="M97.248,11.037c0,0.725-0.207,1.319-0.621,1.785c-0.434,0.479-1.008,0.718-1.727,0.718
|
||||||
|
c-0.691,0-1.242-0.229-1.654-0.689c-0.41-0.459-0.615-1.038-0.615-1.736c0-0.73,0.211-1.329,0.635-1.794s0.994-0.698,1.713-0.698
|
||||||
|
c0.691,0,1.248,0.229,1.668,0.688C97.047,9.757,97.248,10.333,97.248,11.037z M96.162,11.071c0-0.435-0.094-0.808-0.281-1.119
|
||||||
|
c-0.221-0.376-0.533-0.564-0.941-0.564c-0.42,0-0.74,0.188-0.961,0.564c-0.188,0.311-0.281,0.69-0.281,1.138
|
||||||
|
c0,0.435,0.094,0.808,0.281,1.119c0.227,0.376,0.543,0.564,0.951,0.564c0.4,0,0.715-0.191,0.941-0.574
|
||||||
|
C96.064,11.882,96.162,11.506,96.162,11.071z"/>
|
||||||
|
<path fill="#FFFFFF" d="M102.883,13.433h-1.047v-2.7c0-0.832-0.316-1.248-0.951-1.248c-0.311,0-0.562,0.114-0.756,0.343
|
||||||
|
s-0.291,0.499-0.291,0.808v2.796h-1.049v-3.366c0-0.414-0.012-0.863-0.037-1.349h0.92l0.049,0.737h0.029
|
||||||
|
c0.123-0.229,0.305-0.418,0.543-0.569c0.285-0.176,0.602-0.265,0.951-0.265c0.439,0,0.805,0.142,1.096,0.427
|
||||||
|
c0.363,0.349,0.543,0.87,0.543,1.562V13.433z"/>
|
||||||
|
<path fill="#FFFFFF" d="M109.936,9.504h-1.154v2.29c0,0.582,0.205,0.873,0.611,0.873c0.188,0,0.344-0.016,0.467-0.049
|
||||||
|
l0.027,0.795c-0.207,0.078-0.479,0.117-0.814,0.117c-0.414,0-0.736-0.126-0.969-0.378c-0.234-0.252-0.35-0.676-0.35-1.271V9.504
|
||||||
|
h-0.689V8.719h0.689V7.855l1.027-0.31v1.173h1.154V9.504z"/>
|
||||||
|
<path fill="#FFFFFF" d="M115.484,13.433h-1.049v-2.68c0-0.845-0.316-1.268-0.949-1.268c-0.486,0-0.818,0.245-1,0.735
|
||||||
|
c-0.031,0.103-0.049,0.229-0.049,0.377v2.835h-1.047V6.556h1.047v2.841h0.02c0.33-0.517,0.803-0.775,1.416-0.775
|
||||||
|
c0.434,0,0.793,0.142,1.078,0.427c0.355,0.355,0.533,0.883,0.533,1.581V13.433z"/>
|
||||||
|
<path fill="#FFFFFF" d="M121.207,10.853c0,0.188-0.014,0.346-0.039,0.475h-3.143c0.014,0.466,0.164,0.821,0.455,1.067
|
||||||
|
c0.266,0.22,0.609,0.33,1.029,0.33c0.465,0,0.889-0.074,1.271-0.223l0.164,0.728c-0.447,0.194-0.973,0.291-1.582,0.291
|
||||||
|
c-0.73,0-1.305-0.215-1.721-0.645c-0.418-0.43-0.625-1.007-0.625-1.731c0-0.711,0.193-1.303,0.582-1.775
|
||||||
|
c0.406-0.504,0.955-0.756,1.648-0.756c0.678,0,1.193,0.252,1.541,0.756C121.068,9.77,121.207,10.265,121.207,10.853z
|
||||||
|
M120.207,10.582c0.008-0.311-0.061-0.579-0.203-0.805c-0.182-0.291-0.459-0.437-0.834-0.437c-0.342,0-0.621,0.142-0.834,0.427
|
||||||
|
c-0.174,0.227-0.277,0.498-0.311,0.815H120.207z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 12 KiB |
95
ihatemoney/static/images/f-droid.svg
Normal file
95
ihatemoney/static/images/f-droid.svg
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="layer" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 652 652" style="enable-background:new 0 0 652 652;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#4D4D4D;}
|
||||||
|
.st1{fill:#8AB000;stroke:#769616;stroke-width:9.9598;stroke-linecap:round;}
|
||||||
|
.st2{fill:#FFFFFF;fill-opacity:0.298;}
|
||||||
|
.st3{fill:#263238;fill-opacity:0.2;}
|
||||||
|
.st4{fill:#8AB000;}
|
||||||
|
.st5{fill:#AEEA00;}
|
||||||
|
.st6{fill:#1976D2;}
|
||||||
|
.st7{fill:#FFFFFF;fill-opacity:0.2;}
|
||||||
|
.st8{fill:#0D47A1;}
|
||||||
|
.st9{fill:none;stroke:#0D47A1;stroke-width:7.5695;stroke-linecap:round;}
|
||||||
|
.st10{fill:#FFFFFF;}
|
||||||
|
.st11{fill:url(#SVGID_1_);}
|
||||||
|
</style>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M238.2,358.3l8.1-1.6v-54.9l-8.1-1.6v-9.3h60.9v21h-11.8l-0.7-9.1h-25v21.1h26.8v11.8h-26.8v21l8.2,1.6v9.2
|
||||||
|
h-31.7L238.2,358.3z M338.2,340.7h-29.6v-11.8h29.6L338.2,340.7z M381.9,290.9c9.4,0,17.1,3,23.1,9c6.1,6,9.1,13.6,9.1,23v12.7
|
||||||
|
c0,9.4-3,17.1-9.1,23c-6.1,5.9-13.8,8.9-23.1,8.9h-34.4v-9.2l8.1-1.6v-54.9l-8.1-1.6v-9.3h8.1H381.9z M371,302.8v52.9h10.1
|
||||||
|
c5.5,0,9.8-1.9,12.9-5.6c3.1-3.7,4.7-8.6,4.7-14.6v-12.8c0-5.9-1.6-10.7-4.7-14.5c-3.1-3.7-7.4-5.6-12.9-5.6H371z M423.3,358.3
|
||||||
|
l7.4-1.6v-35.3l-8.1-1.6v-9.3h22.4l0.7,8.3c1.3-2.9,3-5.2,5.2-6.9c2.1-1.6,4.5-2.5,7.3-2.5c0.8,0,1.6,0.1,2.5,0.2
|
||||||
|
c0.9,0.1,1.7,0.2,2.3,0.4l-1.6,14l-6.3-0.2c-2.2,0-4.1,0.4-5.6,1.3c-1.5,0.9-2.6,2.1-3.4,3.7v27.6l7.4,1.6v9.2h-30.1L423.3,358.3z
|
||||||
|
M466.5,338.5c0-8.5,2.4-15.4,7.1-20.8c4.8-5.4,11.3-8.1,19.7-8.1c8.4,0,15,2.7,19.7,8.1c4.8,5.4,7.2,12.4,7.2,20.9v1.1
|
||||||
|
c0,8.6-2.4,15.5-7.2,20.9c-4.7,5.4-11.3,8-19.6,8c-8.4,0-15.1-2.7-19.8-8c-4.7-5.4-7.1-12.4-7.1-20.9V338.5z M481.8,339.6
|
||||||
|
c0,5.2,0.9,9.4,2.7,12.5c1.8,3.1,4.8,4.7,8.8,4.7c4,0,6.9-1.6,8.7-4.7c1.9-3.2,2.8-7.3,2.8-12.5v-1.1c0-5-0.9-9.2-2.8-12.4
|
||||||
|
c-1.9-3.2-4.8-4.8-8.8-4.8c-4,0-6.9,1.6-8.7,4.8c-1.8,3.2-2.7,7.3-2.7,12.4V339.6z M526.3,358.3l7.4-1.6v-35.3l-8.2-1.6v-9.3h23.5
|
||||||
|
v46.1l7.4,1.6v9.2h-30.1V358.3z M549.1,297h-15.3v-11.5h15.3V297z M598.5,360.5c-1.8,2.6-3.9,4.6-6.4,6c-2.4,1.4-5.2,2-8.3,2
|
||||||
|
c-7,0-12.5-2.6-16.3-7.7c-3.9-5.1-5.8-11.9-5.8-20.3v-1.1c0-9,1.9-16.2,5.8-21.7c3.9-5.5,9.4-8.2,16.4-8.2c2.8,0,5.4,0.6,7.7,1.9
|
||||||
|
c2.3,1.2,4.3,3,6,5.3v-20.4l-8.2-1.6v-9.3h23.5v71.2l7.4,1.6v9.2h-20.7L598.5,360.5z M577,340.6c0,5,0.8,8.9,2.5,11.8
|
||||||
|
c1.7,2.8,4.4,4.3,8.2,4.3c2.2,0,4.2-0.5,5.8-1.4c1.6-0.9,3-2.2,4-3.9v-24.1c-1-1.8-2.4-3.2-4-4.2c-1.6-1-3.5-1.5-5.7-1.5
|
||||||
|
c-3.7,0-6.5,1.7-8.2,5c-1.7,3.3-2.6,7.7-2.6,13V340.6z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M195.9,236.9L179,258.8"/>
|
||||||
|
<path class="st2" d="M195.8,231.9c1.8,0,3,0.8,3.9,1.8c-8.1,9.6-9.4,11.1-20.5,24.8c-4.1,5.3-8.3,2.5-4.2-2.7l16.9-21.9
|
||||||
|
C192.9,232.6,194.3,232,195.8,231.9L195.8,231.9z"/>
|
||||||
|
<path class="st3" d="M199.8,233.8c0.5,0.6,2.2,3.2,0.1,6.2l-16.9,21.9c-4.1,5.3-4.6-2.4-4.6-2.4S193.2,241.5,199.8,233.8z"/>
|
||||||
|
<path class="st4" d="M196.9,232.9c1.7,0,3.8,0.6,3.3,3.2c-0.4,2-18.6,24.2-18.6,24.2c-4.1,5.3-9.9,2.7-5.9-2.6l16.9-21.8
|
||||||
|
C193.7,234.7,195.1,232.9,196.9,232.9z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M25.3,236.9l16.9,21.9"/>
|
||||||
|
<path class="st2" d="M25.4,231.9c-1.8,0-3,0.7-3.9,1.8c8.1,9.6,9.4,11.1,20.5,24.8c4.1,5.3,8.3,2.5,4.2-2.7l-16.9-21.9
|
||||||
|
C28.3,232.7,26.9,231.9,25.4,231.9z"/>
|
||||||
|
<path class="st3" d="M21.5,233.8c-1.5,1.8-1.5,4.4-0.1,6.2l16.9,21.9c4.1,5.3,4.6-2.4,4.6-2.4S28,241.5,21.5,233.8z"/>
|
||||||
|
<path class="st4" d="M24.3,232.9c-1.7,0-3.8,0.6-3.3,3.2c0.4,2,18.6,24.2,18.6,24.2c4.1,5.3,9.9,2.7,5.9-2.6l-16.9-21.8
|
||||||
|
C27.6,234.7,26.2,232.9,24.3,232.9z"/>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(40.672 -1004.938)">
|
||||||
|
<path class="st5" d="M6.2,1255.8h127.5c6.6,0,12,5.4,12,12v27.9c0,6.6-5.4,12-12,12H6.2c-6.6,0-12-5.4-12-12v-27.9
|
||||||
|
C-5.7,1261.1-0.4,1255.8,6.2,1255.8z"/>
|
||||||
|
<path class="st3" d="M6.2,1267.7h127.5c6.6,0,12,5.4,12,12v15.9c0,6.6-5.4,12-12,12H6.2c-6.6,0-12-5.4-12-12v-15.9
|
||||||
|
C-5.7,1273.1-0.4,1267.7,6.2,1267.7z"/>
|
||||||
|
<path class="st2" d="M6.2,1255.8h127.5c6.6,0,12,5.4,12,12v15.9c0,6.6-5.4,12-12,12H6.2c-6.6,0-12-5.4-12-12v-15.9
|
||||||
|
C-5.7,1261.1-0.4,1255.8,6.2,1255.8z"/>
|
||||||
|
<path class="st5" d="M6.2,1259.8h127.5c6.6,0,12,4.5,12,10.1v23.6c0,5.6-5.4,10.1-12,10.1H6.2c-6.6,0-12-4.5-12-10.1v-23.6
|
||||||
|
C-5.7,1264.3-0.4,1259.8,6.2,1259.8z"/>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(-1.328 -1004.938)">
|
||||||
|
<path class="st6" d="M48.2,1311.6h127.5c6.6,0,12,5.4,12,12v79.7c0,6.6-5.4,12-12,12H48.2c-6.6,0-12-5.4-12-12v-79.7
|
||||||
|
C36.3,1316.9,41.6,1311.6,48.2,1311.6z"/>
|
||||||
|
<path class="st3" d="M48.2,1363.4h127.5c6.6,0,12,5.4,12,12v27.9c0,6.6-5.4,12-12,12H48.2c-6.6,0-12-5.4-12-12v-27.9
|
||||||
|
C36.3,1368.7,41.6,1363.4,48.2,1363.4z"/>
|
||||||
|
<path class="st7" d="M48.2,1311.6h127.5c6.6,0,12,5.4,12,12v27.9c0,6.6-5.4,12-12,12H48.2c-6.6,0-12-5.4-12-12v-27.9
|
||||||
|
C36.3,1316.9,41.6,1311.6,48.2,1311.6z"/>
|
||||||
|
<path class="st6" d="M48.2,1315.5h127.5c6.6,0,12,4.9,12,11v73.6c0,6.1-5.4,11-12,11H48.2c-6.6,0-12-4.9-12-11v-73.6
|
||||||
|
C36.3,1320.5,41.6,1315.5,48.2,1315.5z"/>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(-1.328 8.425)">
|
||||||
|
<path class="st8" d="M112,325.1c-11.5,0-21.2,7.9-24,18.5h12.8c2.3-4.1,6.6-6.6,11.2-6.6c7.1,0,12.9,5.7,12.9,12.8
|
||||||
|
c0,0.1,0,0.1,0,0.2c0,7.1-5.7,12.9-12.8,12.9c-0.1,0-0.1,0-0.2,0c-5,0-9.5-2.9-11.7-7.4H87.7c2.6,11,12.5,19.3,24.2,19.3
|
||||||
|
c13.7,0,24.9-11.2,24.9-24.9C136.9,336.3,125.6,325.1,112,325.1z"/>
|
||||||
|
<circle class="st9" cx="112" cy="350" r="38"/>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(-1.328 -1004.438)">
|
||||||
|
<ellipse class="st3" cx="73.6" cy="1281.7" rx="13.4" ry="15.4"/>
|
||||||
|
<circle class="st10" cx="73.6" cy="1283.7" r="13.4"/>
|
||||||
|
</g>
|
||||||
|
<g transform="translate(18.172 -1004.438)">
|
||||||
|
<ellipse class="st3" cx="131.8" cy="1281.7" rx="13.4" ry="15.4"/>
|
||||||
|
<circle class="st10" cx="131.8" cy="1283.7" r="13.4"/>
|
||||||
|
</g>
|
||||||
|
<radialGradient id="SVGID_1_" cx="139.5457" cy="505.1199" r="22.671" gradientTransform="matrix(0 7.8673 8.4349 0 -4240.3135 -865.9722)" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop offset="0" style="stop-color:#FFFFFF;stop-opacity:9.800000e-002"/>
|
||||||
|
<stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
|
||||||
|
</radialGradient>
|
||||||
|
<path class="st11" d="M25.4,231.9c-2.7-0.1-5,2.1-5.1,4.8c0,1.2,0.4,2.3,1.1,3.2l14.4,18.6c-0.5,1.4-0.8,2.8-0.8,4.3v27.9
|
||||||
|
c0,6.6,5.3,12,12,12h127.5c6.6,0,12-5.3,12-12v-27.9c0-1.5-0.3-2.9-0.8-4.3l14.4-18.6c1.7-2.2,1.4-5.3-0.8-7c-1-0.8-2.2-1.1-3.4-1.1
|
||||||
|
c-1.5,0.1-2.8,0.8-3.7,2l-13.7,17.7c-1.3-0.5-2.6-0.7-3.9-0.7H46.9c-1.4,0-2.7,0.3-3.9,0.7l-13.7-17.7
|
||||||
|
C28.4,232.7,26.9,231.9,25.4,231.9L25.4,231.9z M46.9,306.6c-0.8,0-1.6,0.1-2.4,0.2c-5.5,1.1-9.5,5.9-9.5,11.6v79.8
|
||||||
|
c0,6.6,5.3,12,12,12h127.5c6.6,0,12-5.3,12-12v-79.8c0-5.6-4-10.5-9.5-11.6c-0.8-0.2-1.6-0.2-2.4-0.2L46.9,306.6L46.9,306.6z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.5 KiB |
BIN
ihatemoney/static/images/google-play.png
Normal file
BIN
ihatemoney/static/images/google-play.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 68 KiB |
26
ihatemoney/templates/download_mobile_app.html
Normal file
26
ihatemoney/templates/download_mobile_app.html
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{% extends "layout.html" %}
|
||||||
|
|
||||||
|
{% block css %}
|
||||||
|
<link rel=stylesheet type=text/css href="{{ url_for("static", filename='css/download_mobile_app.css') }}">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<main class="row py-5 justify-content-center text-center">
|
||||||
|
<div class=" col-10 text-center bg-dark text-light">
|
||||||
|
<h1 class="my-2">{{_("Download Mobile Application")}}</h1>
|
||||||
|
</div>
|
||||||
|
<h3 class="col-12 my-2 text-dark">{{_("Get it on")}}</h1>
|
||||||
|
<div class="col-12">
|
||||||
|
<a target="_blank" rel="noopener" href="https://play.google.com/store/apps/details?id=net.eneiluj.moneybuster&hl=en_US" class="text-decoration-none">
|
||||||
|
<img src="{{ url_for("static", filename='images/google-play.png') }}" class="get-it-from"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a target="_blank" rel="noopener" href="https://f-droid.org/en/packages/net.eneiluj.moneybuster/" class="text-decoration-none">
|
||||||
|
<img src="{{ url_for("static", filename='images/f-droid.svg') }}" class="get-it-from" />
|
||||||
|
</a>
|
||||||
|
<a target="__blank" rel="noopener" href="https://apps.apple.com/us/app/payforme/id1500428306" class="text-decoration-none">
|
||||||
|
<img src="{{ url_for("static", filename='images/app-store.svg') }}" class="get-it-from" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
{% endblock %}
|
|
@ -162,7 +162,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for event in history %}
|
{% for event in history %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><script>document.write(localizeTime("{{ event.time }}"));</script></td>
|
<td>{{ event.time|datetimeformat("medium") }}</td>
|
||||||
<td >
|
<td >
|
||||||
<div class="history_icon">
|
<div class="history_icon">
|
||||||
<i {% if event.operation_type == OperationType.INSERT %}
|
<i {% if event.operation_type == OperationType.INSERT %}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel=stylesheet type=text/css href="{{ url_for("static", filename='css/main.css') }}">
|
<link rel=stylesheet type=text/css href="{{ url_for("static", filename='css/main.css') }}">
|
||||||
|
{% block css %}{% endblock %}
|
||||||
<script src="{{ url_for("static", filename="js/jquery-3.1.1.min.js") }}"></script>
|
<script src="{{ url_for("static", filename="js/jquery-3.1.1.min.js") }}"></script>
|
||||||
<script src="{{ url_for("static", filename="js/ihatemoney.js") }}"></script>
|
<script src="{{ url_for("static", filename="js/ihatemoney.js") }}"></script>
|
||||||
<script src="{{ url_for("static", filename="js/tether.min.js") }}"></script>
|
<script src="{{ url_for("static", filename="js/tether.min.js") }}"></script>
|
||||||
|
@ -144,14 +145,14 @@
|
||||||
<a target="_blank" rel="noopener" data-toggle="tooltip" data-placement="top" title="{{ _('Code') }}" href="https://github.com/spiral-project/ihatemoney">
|
<a target="_blank" rel="noopener" data-toggle="tooltip" data-placement="top" title="{{ _('Code') }}" href="https://github.com/spiral-project/ihatemoney">
|
||||||
<i class="icon git">{{ static_include("images/git.svg") | safe }}</i>
|
<i class="icon git">{{ static_include("images/git.svg") | safe }}</i>
|
||||||
</a>
|
</a>
|
||||||
<a target="_blank" rel="noopener" data-toggle="tooltip" data-placement="top" title="{{ _('Mobile Application') }}" href="https://gitlab.com/eneiluj/moneybuster#moneybuster-for-android">
|
<a data-toggle="tooltip" data-placement="top" title="{{ _('Mobile Application') }}" href="{{url_for('main.mobile')}}">
|
||||||
<i class="icon mobile">{{ static_include("images/mobile-alt.svg") | safe }}</i>
|
<i class="icon mobile">{{ static_include("images/mobile-alt.svg") | safe }}</i>
|
||||||
</a>
|
</a>
|
||||||
<a target="_blank" rel="noopener" data-toggle="tooltip" data-placement="top" title="{{ _('Documentation') }}" href="https://ihatemoney.readthedocs.io/en/latest/">
|
<a target="_blank" rel="noopener" data-toggle="tooltip" data-placement="top" title="{{ _('Documentation') }}" href="https://ihatemoney.readthedocs.io/en/latest/">
|
||||||
<i class="icon book">{{ static_include("images/book.svg") | safe }}</i>
|
<i class="icon book">{{ static_include("images/book.svg") | safe }}</i>
|
||||||
</a>
|
</a>
|
||||||
{% if g.show_admin_dashboard_link %}
|
{% if g.show_admin_dashboard_link %}
|
||||||
<a target="_blank" rel="noopener" data-toggle="tooltip" data-placement="top" title="{{ _('Administation Dashboard') }}" href="{{ url_for("main.dashboard") }}">
|
<a target="_blank" rel="noopener" data-toggle="tooltip" data-placement="top" title="{{ _('Administation Dashboard') }}" href="{{ url_for('main.dashboard') }}">
|
||||||
<i class="icon admin">{{ static_include("images/cog.svg") | safe }}</i>
|
<i class="icon admin">{{ static_include("images/cog.svg") | safe }}</i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -110,7 +110,7 @@
|
||||||
<tr owers="{{bill.owers|join(',','id')}}" payer="{{bill.payer.id}}">
|
<tr owers="{{bill.owers|join(',','id')}}" payer="{{bill.payer.id}}">
|
||||||
<td>
|
<td>
|
||||||
<span data-toggle="tooltip" data-placement="top"
|
<span data-toggle="tooltip" data-placement="top"
|
||||||
title="{{ _('Added on %(date)s', date=bill.creation_date if bill.creation_date else bill.date) }}">
|
title="{{ _('Added on %(date)s', date=bill.creation_date|dateformat("long") if bill.creation_date else bill.date|dateformat("long")) }}">
|
||||||
{{ bill.date }}
|
{{ bill.date }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
|
748
ihatemoney/tests/api_test.py
Normal file
748
ihatemoney/tests/api_test.py
Normal file
|
@ -0,0 +1,748 @@
|
||||||
|
import base64
|
||||||
|
import datetime
|
||||||
|
import json
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from ihatemoney.tests.common.help_functions import em_surround
|
||||||
|
from ihatemoney.tests.common.ihatemoney_testcase import IhatemoneyTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class APITestCase(IhatemoneyTestCase):
|
||||||
|
|
||||||
|
"""Tests the API"""
|
||||||
|
|
||||||
|
def api_create(self, name, id=None, password=None, contact=None):
|
||||||
|
id = id or name
|
||||||
|
password = password or name
|
||||||
|
contact = contact or f"{name}@notmyidea.org"
|
||||||
|
|
||||||
|
return self.client.post(
|
||||||
|
"/api/projects",
|
||||||
|
data={
|
||||||
|
"name": name,
|
||||||
|
"id": id,
|
||||||
|
"password": password,
|
||||||
|
"contact_email": contact,
|
||||||
|
"default_currency": "USD",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
def api_add_member(self, project, name, weight=1):
|
||||||
|
self.client.post(
|
||||||
|
f"/api/projects/{project}/members",
|
||||||
|
data={"name": name, "weight": weight},
|
||||||
|
headers=self.get_auth(project),
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_auth(self, username, password=None):
|
||||||
|
password = password or username
|
||||||
|
base64string = (
|
||||||
|
base64.encodebytes(f"{username}:{password}".encode("utf-8"))
|
||||||
|
.decode("utf-8")
|
||||||
|
.replace("\n", "")
|
||||||
|
)
|
||||||
|
return {"Authorization": f"Basic {base64string}"}
|
||||||
|
|
||||||
|
def test_cors_requests(self):
|
||||||
|
# Create a project and test that CORS headers are present if requested.
|
||||||
|
resp = self.api_create("raclette")
|
||||||
|
self.assertStatus(201, resp)
|
||||||
|
|
||||||
|
# Try to do an OPTIONS requests and see if the headers are correct.
|
||||||
|
resp = self.client.options(
|
||||||
|
"/api/projects/raclette", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.headers["Access-Control-Allow-Origin"], "*")
|
||||||
|
|
||||||
|
def test_basic_auth(self):
|
||||||
|
# create a project
|
||||||
|
resp = self.api_create("raclette")
|
||||||
|
self.assertStatus(201, resp)
|
||||||
|
|
||||||
|
# try to do something on it being unauth should return a 401
|
||||||
|
resp = self.client.get("/api/projects/raclette")
|
||||||
|
self.assertStatus(401, resp)
|
||||||
|
|
||||||
|
# PUT / POST / DELETE / GET on the different resources
|
||||||
|
# should also return a 401
|
||||||
|
for verb in ("post",):
|
||||||
|
for resource in ("/raclette/members", "/raclette/bills"):
|
||||||
|
url = "/api/projects" + resource
|
||||||
|
self.assertStatus(401, getattr(self.client, verb)(url), verb + resource)
|
||||||
|
|
||||||
|
for verb in ("get", "delete", "put"):
|
||||||
|
for resource in ("/raclette", "/raclette/members/1", "/raclette/bills/1"):
|
||||||
|
url = "/api/projects" + resource
|
||||||
|
|
||||||
|
self.assertStatus(401, getattr(self.client, verb)(url), verb + resource)
|
||||||
|
|
||||||
|
def test_project(self):
|
||||||
|
# wrong email should return an error
|
||||||
|
resp = self.client.post(
|
||||||
|
"/api/projects",
|
||||||
|
data={
|
||||||
|
"name": "raclette",
|
||||||
|
"id": "raclette",
|
||||||
|
"password": "raclette",
|
||||||
|
"contact_email": "not-an-email",
|
||||||
|
"default_currency": "USD",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertTrue(400, resp.status_code)
|
||||||
|
self.assertEqual(
|
||||||
|
'{"contact_email": ["Invalid email address."]}\n', resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
|
||||||
|
# create it
|
||||||
|
resp = self.api_create("raclette")
|
||||||
|
self.assertTrue(201, resp.status_code)
|
||||||
|
|
||||||
|
# create it twice should return a 400
|
||||||
|
resp = self.api_create("raclette")
|
||||||
|
|
||||||
|
self.assertTrue(400, resp.status_code)
|
||||||
|
self.assertIn("id", json.loads(resp.data.decode("utf-8")))
|
||||||
|
|
||||||
|
# get information about it
|
||||||
|
resp = self.client.get(
|
||||||
|
"/api/projects/raclette", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertTrue(200, resp.status_code)
|
||||||
|
expected = {
|
||||||
|
"members": [],
|
||||||
|
"name": "raclette",
|
||||||
|
"contact_email": "raclette@notmyidea.org",
|
||||||
|
"default_currency": "USD",
|
||||||
|
"id": "raclette",
|
||||||
|
"logging_preference": 1,
|
||||||
|
}
|
||||||
|
decoded_resp = json.loads(resp.data.decode("utf-8"))
|
||||||
|
self.assertDictEqual(decoded_resp, expected)
|
||||||
|
|
||||||
|
# edit should work
|
||||||
|
resp = self.client.put(
|
||||||
|
"/api/projects/raclette",
|
||||||
|
data={
|
||||||
|
"contact_email": "yeah@notmyidea.org",
|
||||||
|
"default_currency": "USD",
|
||||||
|
"password": "raclette",
|
||||||
|
"name": "The raclette party",
|
||||||
|
"project_history": "y",
|
||||||
|
},
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
resp = self.client.get(
|
||||||
|
"/api/projects/raclette", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
expected = {
|
||||||
|
"name": "The raclette party",
|
||||||
|
"contact_email": "yeah@notmyidea.org",
|
||||||
|
"default_currency": "USD",
|
||||||
|
"members": [],
|
||||||
|
"id": "raclette",
|
||||||
|
"logging_preference": 1,
|
||||||
|
}
|
||||||
|
decoded_resp = json.loads(resp.data.decode("utf-8"))
|
||||||
|
self.assertDictEqual(decoded_resp, expected)
|
||||||
|
|
||||||
|
# password change is possible via API
|
||||||
|
resp = self.client.put(
|
||||||
|
"/api/projects/raclette",
|
||||||
|
data={
|
||||||
|
"contact_email": "yeah@notmyidea.org",
|
||||||
|
"default_currency": "USD",
|
||||||
|
"password": "tartiflette",
|
||||||
|
"name": "The raclette party",
|
||||||
|
},
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
resp = self.client.get(
|
||||||
|
"/api/projects/raclette", headers=self.get_auth("raclette", "tartiflette")
|
||||||
|
)
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
# delete should work
|
||||||
|
resp = self.client.delete(
|
||||||
|
"/api/projects/raclette", headers=self.get_auth("raclette", "tartiflette")
|
||||||
|
)
|
||||||
|
|
||||||
|
# get should return a 401 on an unknown resource
|
||||||
|
resp = self.client.get(
|
||||||
|
"/api/projects/raclette", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
self.assertEqual(401, resp.status_code)
|
||||||
|
|
||||||
|
def test_token_creation(self):
|
||||||
|
"""Test that token of project is generated"""
|
||||||
|
|
||||||
|
# Create project
|
||||||
|
resp = self.api_create("raclette")
|
||||||
|
self.assertTrue(201, resp.status_code)
|
||||||
|
|
||||||
|
# Get token
|
||||||
|
resp = self.client.get(
|
||||||
|
"/api/projects/raclette/token", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
decoded_resp = json.loads(resp.data.decode("utf-8"))
|
||||||
|
|
||||||
|
# Access with token
|
||||||
|
resp = self.client.get(
|
||||||
|
"/api/projects/raclette/token",
|
||||||
|
headers={"Authorization": f"Basic {decoded_resp['token']}"},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
|
||||||
|
def test_token_login(self):
|
||||||
|
resp = self.api_create("raclette")
|
||||||
|
# Get token
|
||||||
|
resp = self.client.get(
|
||||||
|
"/api/projects/raclette/token", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
decoded_resp = json.loads(resp.data.decode("utf-8"))
|
||||||
|
resp = self.client.get("/authenticate?token={}".format(decoded_resp["token"]))
|
||||||
|
# Test that we are redirected.
|
||||||
|
self.assertEqual(302, resp.status_code)
|
||||||
|
|
||||||
|
def test_member(self):
|
||||||
|
# create a project
|
||||||
|
self.api_create("raclette")
|
||||||
|
|
||||||
|
# get the list of members (should be empty)
|
||||||
|
req = self.client.get(
|
||||||
|
"/api/projects/raclette/members", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
self.assertEqual("[]\n", req.data.decode("utf-8"))
|
||||||
|
|
||||||
|
# add a member
|
||||||
|
req = self.client.post(
|
||||||
|
"/api/projects/raclette/members",
|
||||||
|
data={"name": "Zorglub"},
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# the id of the new member should be returned
|
||||||
|
self.assertStatus(201, req)
|
||||||
|
self.assertEqual("1\n", req.data.decode("utf-8"))
|
||||||
|
|
||||||
|
# the list of members should contain one member
|
||||||
|
req = self.client.get(
|
||||||
|
"/api/projects/raclette/members", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
self.assertEqual(len(json.loads(req.data.decode("utf-8"))), 1)
|
||||||
|
|
||||||
|
# Try to add another member with the same name.
|
||||||
|
req = self.client.post(
|
||||||
|
"/api/projects/raclette/members",
|
||||||
|
data={"name": "Zorglub"},
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
self.assertStatus(400, req)
|
||||||
|
|
||||||
|
# edit the member
|
||||||
|
req = self.client.put(
|
||||||
|
"/api/projects/raclette/members/1",
|
||||||
|
data={"name": "Fred", "weight": 2},
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
|
||||||
|
# get should return the new name
|
||||||
|
req = self.client.get(
|
||||||
|
"/api/projects/raclette/members/1", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
self.assertEqual("Fred", json.loads(req.data.decode("utf-8"))["name"])
|
||||||
|
self.assertEqual(2, json.loads(req.data.decode("utf-8"))["weight"])
|
||||||
|
|
||||||
|
# edit this member with same information
|
||||||
|
# (test PUT idemopotence)
|
||||||
|
req = self.client.put(
|
||||||
|
"/api/projects/raclette/members/1",
|
||||||
|
data={"name": "Fred"},
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
|
||||||
|
# de-activate the user
|
||||||
|
req = self.client.put(
|
||||||
|
"/api/projects/raclette/members/1",
|
||||||
|
data={"name": "Fred", "activated": False},
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
|
||||||
|
req = self.client.get(
|
||||||
|
"/api/projects/raclette/members/1", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
self.assertEqual(False, json.loads(req.data.decode("utf-8"))["activated"])
|
||||||
|
|
||||||
|
# re-activate the user
|
||||||
|
req = self.client.put(
|
||||||
|
"/api/projects/raclette/members/1",
|
||||||
|
data={"name": "Fred", "activated": True},
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
|
||||||
|
req = self.client.get(
|
||||||
|
"/api/projects/raclette/members/1", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
self.assertEqual(True, json.loads(req.data.decode("utf-8"))["activated"])
|
||||||
|
|
||||||
|
# delete a member
|
||||||
|
|
||||||
|
req = self.client.delete(
|
||||||
|
"/api/projects/raclette/members/1", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
|
||||||
|
# the list of members should be empty
|
||||||
|
req = self.client.get(
|
||||||
|
"/api/projects/raclette/members", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
self.assertEqual("[]\n", req.data.decode("utf-8"))
|
||||||
|
|
||||||
|
def test_bills(self):
|
||||||
|
# create a project
|
||||||
|
self.api_create("raclette")
|
||||||
|
|
||||||
|
# add members
|
||||||
|
self.api_add_member("raclette", "zorglub")
|
||||||
|
self.api_add_member("raclette", "fred")
|
||||||
|
self.api_add_member("raclette", "quentin")
|
||||||
|
|
||||||
|
# get the list of bills (should be empty)
|
||||||
|
req = self.client.get(
|
||||||
|
"/api/projects/raclette/bills", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
|
||||||
|
self.assertEqual("[]\n", req.data.decode("utf-8"))
|
||||||
|
|
||||||
|
# add a bill
|
||||||
|
req = self.client.post(
|
||||||
|
"/api/projects/raclette/bills",
|
||||||
|
data={
|
||||||
|
"date": "2011-08-10",
|
||||||
|
"what": "fromage",
|
||||||
|
"payer": "1",
|
||||||
|
"payed_for": ["1", "2"],
|
||||||
|
"amount": "25",
|
||||||
|
"external_link": "https://raclette.fr",
|
||||||
|
},
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# should return the id
|
||||||
|
self.assertStatus(201, req)
|
||||||
|
self.assertEqual(req.data.decode("utf-8"), "1\n")
|
||||||
|
|
||||||
|
# get this bill details
|
||||||
|
req = self.client.get(
|
||||||
|
"/api/projects/raclette/bills/1", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
|
||||||
|
# compare with the added info
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
expected = {
|
||||||
|
"what": "fromage",
|
||||||
|
"payer_id": 1,
|
||||||
|
"owers": [
|
||||||
|
{"activated": True, "id": 1, "name": "zorglub", "weight": 1},
|
||||||
|
{"activated": True, "id": 2, "name": "fred", "weight": 1},
|
||||||
|
],
|
||||||
|
"amount": 25.0,
|
||||||
|
"date": "2011-08-10",
|
||||||
|
"id": 1,
|
||||||
|
"converted_amount": 25.0,
|
||||||
|
"original_currency": "USD",
|
||||||
|
"external_link": "https://raclette.fr",
|
||||||
|
}
|
||||||
|
|
||||||
|
got = json.loads(req.data.decode("utf-8"))
|
||||||
|
self.assertEqual(
|
||||||
|
datetime.date.today(),
|
||||||
|
datetime.datetime.strptime(got["creation_date"], "%Y-%m-%d").date(),
|
||||||
|
)
|
||||||
|
del got["creation_date"]
|
||||||
|
self.assertDictEqual(expected, got)
|
||||||
|
|
||||||
|
# the list of bills should length 1
|
||||||
|
req = self.client.get(
|
||||||
|
"/api/projects/raclette/bills", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
self.assertEqual(1, len(json.loads(req.data.decode("utf-8"))))
|
||||||
|
|
||||||
|
# edit with errors should return an error
|
||||||
|
req = self.client.put(
|
||||||
|
"/api/projects/raclette/bills/1",
|
||||||
|
data={
|
||||||
|
"date": "201111111-08-10", # not a date
|
||||||
|
"what": "fromage",
|
||||||
|
"payer": "1",
|
||||||
|
"payed_for": ["1", "2"],
|
||||||
|
"amount": "25",
|
||||||
|
"external_link": "https://raclette.fr",
|
||||||
|
},
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertStatus(400, req)
|
||||||
|
self.assertEqual(
|
||||||
|
'{"date": ["This field is required."]}\n', req.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
|
||||||
|
# edit a bill
|
||||||
|
req = self.client.put(
|
||||||
|
"/api/projects/raclette/bills/1",
|
||||||
|
data={
|
||||||
|
"date": "2011-09-10",
|
||||||
|
"what": "beer",
|
||||||
|
"payer": "2",
|
||||||
|
"payed_for": ["1", "2"],
|
||||||
|
"amount": "25",
|
||||||
|
"external_link": "https://raclette.fr",
|
||||||
|
},
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# check its fields
|
||||||
|
req = self.client.get(
|
||||||
|
"/api/projects/raclette/bills/1", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
creation_date = datetime.datetime.strptime(
|
||||||
|
json.loads(req.data.decode("utf-8"))["creation_date"], "%Y-%m-%d"
|
||||||
|
).date()
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"what": "beer",
|
||||||
|
"payer_id": 2,
|
||||||
|
"owers": [
|
||||||
|
{"activated": True, "id": 1, "name": "zorglub", "weight": 1},
|
||||||
|
{"activated": True, "id": 2, "name": "fred", "weight": 1},
|
||||||
|
],
|
||||||
|
"amount": 25.0,
|
||||||
|
"date": "2011-09-10",
|
||||||
|
"external_link": "https://raclette.fr",
|
||||||
|
"converted_amount": 25.0,
|
||||||
|
"original_currency": "USD",
|
||||||
|
"id": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
got = json.loads(req.data.decode("utf-8"))
|
||||||
|
self.assertEqual(
|
||||||
|
creation_date,
|
||||||
|
datetime.datetime.strptime(got["creation_date"], "%Y-%m-%d").date(),
|
||||||
|
)
|
||||||
|
del got["creation_date"]
|
||||||
|
self.assertDictEqual(expected, got)
|
||||||
|
|
||||||
|
# delete a bill
|
||||||
|
req = self.client.delete(
|
||||||
|
"/api/projects/raclette/bills/1", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
|
||||||
|
# getting it should return a 404
|
||||||
|
req = self.client.get(
|
||||||
|
"/api/projects/raclette/bills/1", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
self.assertStatus(404, req)
|
||||||
|
|
||||||
|
def test_bills_with_calculation(self):
|
||||||
|
# create a project
|
||||||
|
self.api_create("raclette")
|
||||||
|
|
||||||
|
# add members
|
||||||
|
self.api_add_member("raclette", "zorglub")
|
||||||
|
self.api_add_member("raclette", "fred")
|
||||||
|
|
||||||
|
# valid amounts
|
||||||
|
input_expected = [
|
||||||
|
("((100 + 200.25) * 2 - 100) / 2", 250.25),
|
||||||
|
("3/2", 1.5),
|
||||||
|
("2 + 1 * 5 - 2 / 1", 5),
|
||||||
|
]
|
||||||
|
|
||||||
|
for i, pair in enumerate(input_expected):
|
||||||
|
input_amount, expected_amount = pair
|
||||||
|
id = i + 1
|
||||||
|
|
||||||
|
req = self.client.post(
|
||||||
|
"/api/projects/raclette/bills",
|
||||||
|
data={
|
||||||
|
"date": "2011-08-10",
|
||||||
|
"what": "fromage",
|
||||||
|
"payer": "1",
|
||||||
|
"payed_for": ["1", "2"],
|
||||||
|
"amount": input_amount,
|
||||||
|
},
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# should return the id
|
||||||
|
self.assertStatus(201, req)
|
||||||
|
self.assertEqual(req.data.decode("utf-8"), "{}\n".format(id))
|
||||||
|
|
||||||
|
# get this bill's details
|
||||||
|
req = self.client.get(
|
||||||
|
"/api/projects/raclette/bills/{}".format(id),
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# compare with the added info
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
expected = {
|
||||||
|
"what": "fromage",
|
||||||
|
"payer_id": 1,
|
||||||
|
"owers": [
|
||||||
|
{"activated": True, "id": 1, "name": "zorglub", "weight": 1},
|
||||||
|
{"activated": True, "id": 2, "name": "fred", "weight": 1},
|
||||||
|
],
|
||||||
|
"amount": expected_amount,
|
||||||
|
"date": "2011-08-10",
|
||||||
|
"id": id,
|
||||||
|
"external_link": "",
|
||||||
|
"original_currency": "USD",
|
||||||
|
"converted_amount": expected_amount,
|
||||||
|
}
|
||||||
|
|
||||||
|
got = json.loads(req.data.decode("utf-8"))
|
||||||
|
self.assertEqual(
|
||||||
|
datetime.date.today(),
|
||||||
|
datetime.datetime.strptime(got["creation_date"], "%Y-%m-%d").date(),
|
||||||
|
)
|
||||||
|
del got["creation_date"]
|
||||||
|
self.assertDictEqual(expected, got)
|
||||||
|
|
||||||
|
# should raise errors
|
||||||
|
erroneous_amounts = [
|
||||||
|
"lambda ", # letters
|
||||||
|
"(20 + 2", # invalid expression
|
||||||
|
"20/0", # invalid calc
|
||||||
|
"9999**99999999999999999", # exponents
|
||||||
|
"2" * 201, # greater than 200 chars,
|
||||||
|
]
|
||||||
|
|
||||||
|
for amount in erroneous_amounts:
|
||||||
|
req = self.client.post(
|
||||||
|
"/api/projects/raclette/bills",
|
||||||
|
data={
|
||||||
|
"date": "2011-08-10",
|
||||||
|
"what": "fromage",
|
||||||
|
"payer": "1",
|
||||||
|
"payed_for": ["1", "2"],
|
||||||
|
"amount": amount,
|
||||||
|
},
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
self.assertStatus(400, req)
|
||||||
|
|
||||||
|
def test_statistics(self):
|
||||||
|
# create a project
|
||||||
|
self.api_create("raclette")
|
||||||
|
|
||||||
|
# add members
|
||||||
|
self.api_add_member("raclette", "zorglub")
|
||||||
|
self.api_add_member("raclette", "fred")
|
||||||
|
|
||||||
|
# add a bill
|
||||||
|
req = self.client.post(
|
||||||
|
"/api/projects/raclette/bills",
|
||||||
|
data={
|
||||||
|
"date": "2011-08-10",
|
||||||
|
"what": "fromage",
|
||||||
|
"payer": "1",
|
||||||
|
"payed_for": ["1", "2"],
|
||||||
|
"amount": "25",
|
||||||
|
},
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# get the list of bills (should be empty)
|
||||||
|
req = self.client.get(
|
||||||
|
"/api/projects/raclette/statistics", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
self.assertEqual(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"balance": 12.5,
|
||||||
|
"member": {
|
||||||
|
"activated": True,
|
||||||
|
"id": 1,
|
||||||
|
"name": "zorglub",
|
||||||
|
"weight": 1.0,
|
||||||
|
},
|
||||||
|
"paid": 25.0,
|
||||||
|
"spent": 12.5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"balance": -12.5,
|
||||||
|
"member": {
|
||||||
|
"activated": True,
|
||||||
|
"id": 2,
|
||||||
|
"name": "fred",
|
||||||
|
"weight": 1.0,
|
||||||
|
},
|
||||||
|
"paid": 0,
|
||||||
|
"spent": 12.5,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
json.loads(req.data.decode("utf-8")),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_username_xss(self):
|
||||||
|
# create a project
|
||||||
|
# self.api_create("raclette")
|
||||||
|
self.post_project("raclette")
|
||||||
|
self.login("raclette")
|
||||||
|
|
||||||
|
# add members
|
||||||
|
self.api_add_member("raclette", "<script>")
|
||||||
|
|
||||||
|
result = self.client.get("/raclette/")
|
||||||
|
self.assertNotIn("<script>", result.data.decode("utf-8"))
|
||||||
|
|
||||||
|
def test_weighted_bills(self):
|
||||||
|
# create a project
|
||||||
|
self.api_create("raclette")
|
||||||
|
|
||||||
|
# add members
|
||||||
|
self.api_add_member("raclette", "zorglub")
|
||||||
|
self.api_add_member("raclette", "freddy familly", 4)
|
||||||
|
self.api_add_member("raclette", "quentin")
|
||||||
|
|
||||||
|
# add a bill
|
||||||
|
req = self.client.post(
|
||||||
|
"/api/projects/raclette/bills",
|
||||||
|
data={
|
||||||
|
"date": "2011-08-10",
|
||||||
|
"what": "fromage",
|
||||||
|
"payer": "1",
|
||||||
|
"payed_for": ["1", "2"],
|
||||||
|
"amount": "25",
|
||||||
|
},
|
||||||
|
headers=self.get_auth("raclette"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# get this bill details
|
||||||
|
req = self.client.get(
|
||||||
|
"/api/projects/raclette/bills/1", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
creation_date = datetime.datetime.strptime(
|
||||||
|
json.loads(req.data.decode("utf-8"))["creation_date"], "%Y-%m-%d"
|
||||||
|
).date()
|
||||||
|
|
||||||
|
# compare with the added info
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
expected = {
|
||||||
|
"what": "fromage",
|
||||||
|
"payer_id": 1,
|
||||||
|
"owers": [
|
||||||
|
{"activated": True, "id": 1, "name": "zorglub", "weight": 1},
|
||||||
|
{"activated": True, "id": 2, "name": "freddy familly", "weight": 4},
|
||||||
|
],
|
||||||
|
"amount": 25.0,
|
||||||
|
"date": "2011-08-10",
|
||||||
|
"id": 1,
|
||||||
|
"external_link": "",
|
||||||
|
"converted_amount": 25.0,
|
||||||
|
"original_currency": "USD",
|
||||||
|
}
|
||||||
|
got = json.loads(req.data.decode("utf-8"))
|
||||||
|
self.assertEqual(
|
||||||
|
creation_date,
|
||||||
|
datetime.datetime.strptime(got["creation_date"], "%Y-%m-%d").date(),
|
||||||
|
)
|
||||||
|
del got["creation_date"]
|
||||||
|
self.assertDictEqual(expected, got)
|
||||||
|
|
||||||
|
# getting it should return a 404
|
||||||
|
req = self.client.get(
|
||||||
|
"/api/projects/raclette", headers=self.get_auth("raclette")
|
||||||
|
)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"activated": True,
|
||||||
|
"id": 1,
|
||||||
|
"name": "zorglub",
|
||||||
|
"weight": 1.0,
|
||||||
|
"balance": 20.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"activated": True,
|
||||||
|
"id": 2,
|
||||||
|
"name": "freddy familly",
|
||||||
|
"weight": 4.0,
|
||||||
|
"balance": -20.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"activated": True,
|
||||||
|
"id": 3,
|
||||||
|
"name": "quentin",
|
||||||
|
"weight": 1.0,
|
||||||
|
"balance": 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"contact_email": "raclette@notmyidea.org",
|
||||||
|
"id": "raclette",
|
||||||
|
"name": "raclette",
|
||||||
|
"logging_preference": 1,
|
||||||
|
"default_currency": "USD",
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
decoded_req = json.loads(req.data.decode("utf-8"))
|
||||||
|
self.assertDictEqual(decoded_req, expected)
|
||||||
|
|
||||||
|
def test_log_created_from_api_call(self):
|
||||||
|
# create a project
|
||||||
|
self.api_create("raclette")
|
||||||
|
self.login("raclette")
|
||||||
|
|
||||||
|
# add members
|
||||||
|
self.api_add_member("raclette", "zorglub")
|
||||||
|
|
||||||
|
resp = self.client.get("/raclette/history", follow_redirects=True)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn(
|
||||||
|
f"Participant {em_surround('zorglub')} added", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
f"Project {em_surround('raclette')} added", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 2)
|
||||||
|
self.assertNotIn("127.0.0.1", resp.data.decode("utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
1451
ihatemoney/tests/budget_test.py
Normal file
1451
ihatemoney/tests/budget_test.py
Normal file
File diff suppressed because it is too large
Load diff
5
ihatemoney/tests/common/help_functions.py
Normal file
5
ihatemoney/tests/common/help_functions.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
def em_surround(string, regex_escape=False):
|
||||||
|
if regex_escape:
|
||||||
|
return r'<em class="font-italic">%s<\/em>' % string
|
||||||
|
else:
|
||||||
|
return '<em class="font-italic">%s</em>' % string
|
70
ihatemoney/tests/common/ihatemoney_testcase.py
Normal file
70
ihatemoney/tests/common/ihatemoney_testcase.py
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
from flask_testing import TestCase
|
||||||
|
from werkzeug.security import generate_password_hash
|
||||||
|
|
||||||
|
from ihatemoney import models
|
||||||
|
from ihatemoney.run import create_app, db
|
||||||
|
|
||||||
|
|
||||||
|
class BaseTestCase(TestCase):
|
||||||
|
|
||||||
|
SECRET_KEY = "TEST SESSION"
|
||||||
|
|
||||||
|
def create_app(self):
|
||||||
|
# Pass the test object as a configuration.
|
||||||
|
return create_app(self)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
db.create_all()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
# clean after testing
|
||||||
|
db.session.remove()
|
||||||
|
db.drop_all()
|
||||||
|
|
||||||
|
def login(self, project, password=None, test_client=None):
|
||||||
|
password = password or project
|
||||||
|
|
||||||
|
return self.client.post(
|
||||||
|
"/authenticate",
|
||||||
|
data=dict(id=project, password=password),
|
||||||
|
follow_redirects=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def post_project(self, name, follow_redirects=True):
|
||||||
|
"""Create a fake project"""
|
||||||
|
# create the project
|
||||||
|
return self.client.post(
|
||||||
|
"/create",
|
||||||
|
data={
|
||||||
|
"name": name,
|
||||||
|
"id": name,
|
||||||
|
"password": name,
|
||||||
|
"contact_email": f"{name}@notmyidea.org",
|
||||||
|
"default_currency": "USD",
|
||||||
|
},
|
||||||
|
follow_redirects=follow_redirects,
|
||||||
|
)
|
||||||
|
|
||||||
|
def create_project(self, name):
|
||||||
|
project = models.Project(
|
||||||
|
id=name,
|
||||||
|
name=str(name),
|
||||||
|
password=generate_password_hash(name),
|
||||||
|
contact_email=f"{name}@notmyidea.org",
|
||||||
|
default_currency="USD",
|
||||||
|
)
|
||||||
|
models.db.session.add(project)
|
||||||
|
models.db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
class IhatemoneyTestCase(BaseTestCase):
|
||||||
|
SQLALCHEMY_DATABASE_URI = "sqlite://"
|
||||||
|
TESTING = True
|
||||||
|
WTF_CSRF_ENABLED = False # Simplifies the tests.
|
||||||
|
|
||||||
|
def assertStatus(self, expected, resp, url=""):
|
||||||
|
return self.assertEqual(
|
||||||
|
expected,
|
||||||
|
resp.status_code,
|
||||||
|
f"{url} expected {expected}, got {resp.status_code}",
|
||||||
|
)
|
599
ihatemoney/tests/history_test.py
Normal file
599
ihatemoney/tests/history_test.py
Normal file
|
@ -0,0 +1,599 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from ihatemoney import history, models
|
||||||
|
from ihatemoney.tests.common.help_functions import em_surround
|
||||||
|
from ihatemoney.tests.common.ihatemoney_testcase import IhatemoneyTestCase
|
||||||
|
from ihatemoney.versioning import LoggingMode
|
||||||
|
|
||||||
|
|
||||||
|
class HistoryTestCase(IhatemoneyTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.post_project("demo")
|
||||||
|
self.login("demo")
|
||||||
|
|
||||||
|
def test_simple_create_logentry_no_ip(self):
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn(f"Project {em_surround('demo')} added", resp.data.decode("utf-8"))
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 1)
|
||||||
|
self.assertNotIn("127.0.0.1", resp.data.decode("utf-8"))
|
||||||
|
|
||||||
|
def change_privacy_to(self, logging_preference):
|
||||||
|
# Change only logging_preferences
|
||||||
|
new_data = {
|
||||||
|
"name": "demo",
|
||||||
|
"contact_email": "demo@notmyidea.org",
|
||||||
|
"password": "demo",
|
||||||
|
"default_currency": "USD",
|
||||||
|
}
|
||||||
|
|
||||||
|
if logging_preference != LoggingMode.DISABLED:
|
||||||
|
new_data["project_history"] = "y"
|
||||||
|
if logging_preference == LoggingMode.RECORD_IP:
|
||||||
|
new_data["ip_recording"] = "y"
|
||||||
|
|
||||||
|
# Disable History
|
||||||
|
resp = self.client.post("/demo/edit", data=new_data, follow_redirects=True)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertNotIn("danger", resp.data.decode("utf-8"))
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/edit")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
if logging_preference == LoggingMode.DISABLED:
|
||||||
|
self.assertIn('<input id="project_history"', resp.data.decode("utf-8"))
|
||||||
|
else:
|
||||||
|
self.assertIn(
|
||||||
|
'<input checked id="project_history"', resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
|
||||||
|
if logging_preference == LoggingMode.RECORD_IP:
|
||||||
|
self.assertIn('<input checked id="ip_recording"', resp.data.decode("utf-8"))
|
||||||
|
else:
|
||||||
|
self.assertIn('<input id="ip_recording"', resp.data.decode("utf-8"))
|
||||||
|
|
||||||
|
def assert_empty_history_logging_disabled(self):
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertIn(
|
||||||
|
"This project has history disabled. New actions won't appear below. ",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
self.assertIn("Nothing to list", resp.data.decode("utf-8"))
|
||||||
|
self.assertNotIn(
|
||||||
|
"The table below reflects actions recorded prior to disabling project history.",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
self.assertNotIn(
|
||||||
|
"Some entries below contain IP addresses,", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
self.assertNotIn("127.0.0.1", resp.data.decode("utf-8"))
|
||||||
|
self.assertNotIn("<td> -- </td>", resp.data.decode("utf-8"))
|
||||||
|
self.assertNotIn(
|
||||||
|
f"Project {em_surround('demo')} added", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_project_edit(self):
|
||||||
|
new_data = {
|
||||||
|
"name": "demo2",
|
||||||
|
"contact_email": "demo2@notmyidea.org",
|
||||||
|
"password": "123456",
|
||||||
|
"project_history": "y",
|
||||||
|
"default_currency": "USD",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.client.post("/demo/edit", data=new_data, follow_redirects=True)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn(f"Project {em_surround('demo')} added", resp.data.decode("utf-8"))
|
||||||
|
self.assertIn(
|
||||||
|
f"Project contact email changed to {em_surround('demo2@notmyidea.org')}",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
self.assertIn("Project private code changed", resp.data.decode("utf-8"))
|
||||||
|
self.assertIn(
|
||||||
|
f"Project renamed to {em_surround('demo2')}", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
self.assertLess(
|
||||||
|
resp.data.decode("utf-8").index("Project renamed "),
|
||||||
|
resp.data.decode("utf-8").index("Project contact email changed to "),
|
||||||
|
)
|
||||||
|
self.assertLess(
|
||||||
|
resp.data.decode("utf-8").index("Project renamed "),
|
||||||
|
resp.data.decode("utf-8").index("Project private code changed"),
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 4)
|
||||||
|
self.assertNotIn("127.0.0.1", resp.data.decode("utf-8"))
|
||||||
|
|
||||||
|
def test_project_privacy_edit(self):
|
||||||
|
resp = self.client.get("/demo/edit")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn(
|
||||||
|
'<input checked id="project_history" name="project_history" type="checkbox" value="y">',
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.change_privacy_to(LoggingMode.DISABLED)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn("Disabled Project History\n", resp.data.decode("utf-8"))
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 2)
|
||||||
|
self.assertNotIn("127.0.0.1", resp.data.decode("utf-8"))
|
||||||
|
|
||||||
|
self.change_privacy_to(LoggingMode.RECORD_IP)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn(
|
||||||
|
"Enabled Project History & IP Address Recording", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 2)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("127.0.0.1"), 1)
|
||||||
|
|
||||||
|
self.change_privacy_to(LoggingMode.ENABLED)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn("Disabled IP Address Recording\n", resp.data.decode("utf-8"))
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 2)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("127.0.0.1"), 2)
|
||||||
|
|
||||||
|
def test_project_privacy_edit2(self):
|
||||||
|
self.change_privacy_to(LoggingMode.RECORD_IP)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn("Enabled IP Address Recording\n", resp.data.decode("utf-8"))
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 1)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("127.0.0.1"), 1)
|
||||||
|
|
||||||
|
self.change_privacy_to(LoggingMode.DISABLED)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn(
|
||||||
|
"Disabled Project History & IP Address Recording", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 1)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("127.0.0.1"), 2)
|
||||||
|
|
||||||
|
self.change_privacy_to(LoggingMode.ENABLED)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn("Enabled Project History\n", resp.data.decode("utf-8"))
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 2)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("127.0.0.1"), 2)
|
||||||
|
|
||||||
|
def do_misc_database_operations(self, logging_mode):
|
||||||
|
new_data = {
|
||||||
|
"name": "demo2",
|
||||||
|
"contact_email": "demo2@notmyidea.org",
|
||||||
|
"password": "123456",
|
||||||
|
"default_currency": "USD",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Keep privacy settings where they were
|
||||||
|
if logging_mode != LoggingMode.DISABLED:
|
||||||
|
new_data["project_history"] = "y"
|
||||||
|
if logging_mode == LoggingMode.RECORD_IP:
|
||||||
|
new_data["ip_recording"] = "y"
|
||||||
|
|
||||||
|
resp = self.client.post("/demo/edit", data=new_data, follow_redirects=True)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
# adds a member to this project
|
||||||
|
resp = self.client.post(
|
||||||
|
"/demo/members/add", data={"name": "zorglub"}, follow_redirects=True
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
user_id = models.Person.query.one().id
|
||||||
|
|
||||||
|
# create a bill
|
||||||
|
resp = self.client.post(
|
||||||
|
"/demo/add",
|
||||||
|
data={
|
||||||
|
"date": "2011-08-10",
|
||||||
|
"what": "fromage à raclette",
|
||||||
|
"payer": user_id,
|
||||||
|
"payed_for": [user_id],
|
||||||
|
"amount": "25",
|
||||||
|
},
|
||||||
|
follow_redirects=True,
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
bill_id = models.Bill.query.one().id
|
||||||
|
|
||||||
|
# edit the bill
|
||||||
|
resp = self.client.post(
|
||||||
|
f"/demo/edit/{bill_id}",
|
||||||
|
data={
|
||||||
|
"date": "2011-08-10",
|
||||||
|
"what": "fromage à raclette",
|
||||||
|
"payer": user_id,
|
||||||
|
"payed_for": [user_id],
|
||||||
|
"amount": "10",
|
||||||
|
},
|
||||||
|
follow_redirects=True,
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
# delete the bill
|
||||||
|
resp = self.client.get(f"/demo/delete/{bill_id}", follow_redirects=True)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
# delete user using POST method
|
||||||
|
resp = self.client.post(
|
||||||
|
f"/demo/members/{user_id}/delete", follow_redirects=True
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
def test_disable_clear_no_new_records(self):
|
||||||
|
# Disable logging
|
||||||
|
self.change_privacy_to(LoggingMode.DISABLED)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn(
|
||||||
|
"This project has history disabled. New actions won't appear below. ",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
"The table below reflects actions recorded prior to disabling project history.",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
self.assertNotIn("Nothing to list", resp.data.decode("utf-8"))
|
||||||
|
self.assertNotIn(
|
||||||
|
"Some entries below contain IP addresses,", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Clear Existing Entries
|
||||||
|
resp = self.client.post("/demo/erase_history", follow_redirects=True)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assert_empty_history_logging_disabled()
|
||||||
|
|
||||||
|
# Do lots of database operations & check that there's still no history
|
||||||
|
self.do_misc_database_operations(LoggingMode.DISABLED)
|
||||||
|
|
||||||
|
self.assert_empty_history_logging_disabled()
|
||||||
|
|
||||||
|
def test_clear_ip_records(self):
|
||||||
|
# Enable IP Recording
|
||||||
|
self.change_privacy_to(LoggingMode.RECORD_IP)
|
||||||
|
|
||||||
|
# Do lots of database operations to generate IP address entries
|
||||||
|
self.do_misc_database_operations(LoggingMode.RECORD_IP)
|
||||||
|
|
||||||
|
# Disable IP Recording
|
||||||
|
self.change_privacy_to(LoggingMode.ENABLED)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertNotIn(
|
||||||
|
"This project has history disabled. New actions won't appear below. ",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
self.assertNotIn(
|
||||||
|
"The table below reflects actions recorded prior to disabling project history.",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
self.assertNotIn("Nothing to list", resp.data.decode("utf-8"))
|
||||||
|
self.assertIn(
|
||||||
|
"Some entries below contain IP addresses,", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("127.0.0.1"), 10)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 1)
|
||||||
|
|
||||||
|
# Generate more operations to confirm additional IP info isn't recorded
|
||||||
|
self.do_misc_database_operations(LoggingMode.ENABLED)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("127.0.0.1"), 10)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 6)
|
||||||
|
|
||||||
|
# Clear IP Data
|
||||||
|
resp = self.client.post("/demo/strip_ip_addresses", follow_redirects=True)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertNotIn(
|
||||||
|
"This project has history disabled. New actions won't appear below. ",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
self.assertNotIn(
|
||||||
|
"The table below reflects actions recorded prior to disabling project history.",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
self.assertNotIn("Nothing to list", resp.data.decode("utf-8"))
|
||||||
|
self.assertNotIn(
|
||||||
|
"Some entries below contain IP addresses,", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("127.0.0.1"), 0)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 16)
|
||||||
|
|
||||||
|
def test_logs_for_common_actions(self):
|
||||||
|
# adds a member to this project
|
||||||
|
resp = self.client.post(
|
||||||
|
"/demo/members/add", data={"name": "zorglub"}, follow_redirects=True
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn(
|
||||||
|
f"Participant {em_surround('zorglub')} added", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
|
||||||
|
# create a bill
|
||||||
|
resp = self.client.post(
|
||||||
|
"/demo/add",
|
||||||
|
data={
|
||||||
|
"date": "2011-08-10",
|
||||||
|
"what": "fromage à raclette",
|
||||||
|
"payer": 1,
|
||||||
|
"payed_for": [1],
|
||||||
|
"amount": "25",
|
||||||
|
},
|
||||||
|
follow_redirects=True,
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn(
|
||||||
|
f"Bill {em_surround('fromage à raclette')} added",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# edit the bill
|
||||||
|
resp = self.client.post(
|
||||||
|
"/demo/edit/1",
|
||||||
|
data={
|
||||||
|
"date": "2011-08-10",
|
||||||
|
"what": "new thing",
|
||||||
|
"payer": 1,
|
||||||
|
"payed_for": [1],
|
||||||
|
"amount": "10",
|
||||||
|
},
|
||||||
|
follow_redirects=True,
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn(
|
||||||
|
f"Bill {em_surround('fromage à raclette')} added",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
self.assertRegex(
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
r"Bill %s:\s* amount changed\s* from %s\s* to %s"
|
||||||
|
% (
|
||||||
|
em_surround("fromage à raclette", regex_escape=True),
|
||||||
|
em_surround("25.0", regex_escape=True),
|
||||||
|
em_surround("10.0", regex_escape=True),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
"Bill %s renamed to %s"
|
||||||
|
% (em_surround("fromage à raclette"), em_surround("new thing")),
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
self.assertLess(
|
||||||
|
resp.data.decode("utf-8").index(
|
||||||
|
f"Bill {em_surround('fromage à raclette')} renamed to"
|
||||||
|
),
|
||||||
|
resp.data.decode("utf-8").index("amount changed"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# delete the bill
|
||||||
|
resp = self.client.get("/demo/delete/1", follow_redirects=True)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn(
|
||||||
|
f"Bill {em_surround('new thing')} removed", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
|
||||||
|
# edit user
|
||||||
|
resp = self.client.post(
|
||||||
|
"/demo/members/1/edit",
|
||||||
|
data={"weight": 2, "name": "new name"},
|
||||||
|
follow_redirects=True,
|
||||||
|
)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertRegex(
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
r"Participant %s:\s* weight changed\s* from %s\s* to %s"
|
||||||
|
% (
|
||||||
|
em_surround("zorglub", regex_escape=True),
|
||||||
|
em_surround("1.0", regex_escape=True),
|
||||||
|
em_surround("2.0", regex_escape=True),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
"Participant %s renamed to %s"
|
||||||
|
% (em_surround("zorglub"), em_surround("new name")),
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
self.assertLess(
|
||||||
|
resp.data.decode("utf-8").index(
|
||||||
|
f"Participant {em_surround('zorglub')} renamed"
|
||||||
|
),
|
||||||
|
resp.data.decode("utf-8").index("weight changed"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# delete user using POST method
|
||||||
|
resp = self.client.post("/demo/members/1/delete", follow_redirects=True)
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertIn(
|
||||||
|
f"Participant {em_surround('new name')} removed", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_double_bill_double_person_edit_second(self):
|
||||||
|
|
||||||
|
# add two members
|
||||||
|
self.client.post("/demo/members/add", data={"name": "User 1"})
|
||||||
|
self.client.post("/demo/members/add", data={"name": "User 2"})
|
||||||
|
|
||||||
|
# add two bills
|
||||||
|
self.client.post(
|
||||||
|
"/demo/add",
|
||||||
|
data={
|
||||||
|
"date": "2020-04-13",
|
||||||
|
"what": "Bill 1",
|
||||||
|
"payer": 1,
|
||||||
|
"payed_for": [1, 2],
|
||||||
|
"amount": "25",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.client.post(
|
||||||
|
"/demo/add",
|
||||||
|
data={
|
||||||
|
"date": "2020-04-13",
|
||||||
|
"what": "Bill 2",
|
||||||
|
"payer": 1,
|
||||||
|
"payed_for": [1, 2],
|
||||||
|
"amount": "20",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Should be 5 history entries at this point
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 5)
|
||||||
|
self.assertNotIn("127.0.0.1", resp.data.decode("utf-8"))
|
||||||
|
|
||||||
|
# Edit ONLY the amount on the first bill
|
||||||
|
self.client.post(
|
||||||
|
"/demo/edit/1",
|
||||||
|
data={
|
||||||
|
"date": "2020-04-13",
|
||||||
|
"what": "Bill 1",
|
||||||
|
"payer": 1,
|
||||||
|
"payed_for": [1, 2],
|
||||||
|
"amount": "88",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertRegex(
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
r"Bill {}:\s* amount changed\s* from {}\s* to {}".format(
|
||||||
|
em_surround("Bill 1", regex_escape=True),
|
||||||
|
em_surround("25.0", regex_escape=True),
|
||||||
|
em_surround("88.0", regex_escape=True),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertNotRegex(
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
r"Removed\s* {}\s* and\s* {}\s* from\s* owers list".format(
|
||||||
|
em_surround("User 1", regex_escape=True),
|
||||||
|
em_surround("User 2", regex_escape=True),
|
||||||
|
),
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Should be 6 history entries at this point
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 6)
|
||||||
|
self.assertNotIn("127.0.0.1", resp.data.decode("utf-8"))
|
||||||
|
|
||||||
|
def test_bill_add_remove_add(self):
|
||||||
|
# add two members
|
||||||
|
self.client.post("/demo/members/add", data={"name": "User 1"})
|
||||||
|
self.client.post("/demo/members/add", data={"name": "User 2"})
|
||||||
|
|
||||||
|
# add 1 bill
|
||||||
|
self.client.post(
|
||||||
|
"/demo/add",
|
||||||
|
data={
|
||||||
|
"date": "2020-04-13",
|
||||||
|
"what": "Bill 1",
|
||||||
|
"payer": 1,
|
||||||
|
"payed_for": [1, 2],
|
||||||
|
"amount": "25",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# delete the bill
|
||||||
|
self.client.get("/demo/delete/1", follow_redirects=True)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 5)
|
||||||
|
self.assertNotIn("127.0.0.1", resp.data.decode("utf-8"))
|
||||||
|
self.assertIn(f"Bill {em_surround('Bill 1')} added", resp.data.decode("utf-8"))
|
||||||
|
self.assertIn(
|
||||||
|
f"Bill {em_surround('Bill 1')} removed", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add a new bill
|
||||||
|
self.client.post(
|
||||||
|
"/demo/add",
|
||||||
|
data={
|
||||||
|
"date": "2020-04-13",
|
||||||
|
"what": "Bill 2",
|
||||||
|
"payer": 1,
|
||||||
|
"payed_for": [1, 2],
|
||||||
|
"amount": "20",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = self.client.get("/demo/history")
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
self.assertEqual(resp.data.decode("utf-8").count("<td> -- </td>"), 6)
|
||||||
|
self.assertNotIn("127.0.0.1", resp.data.decode("utf-8"))
|
||||||
|
self.assertIn(f"Bill {em_surround('Bill 1')} added", resp.data.decode("utf-8"))
|
||||||
|
self.assertEqual(
|
||||||
|
resp.data.decode("utf-8").count(f"Bill {em_surround('Bill 1')} added"), 1
|
||||||
|
)
|
||||||
|
self.assertIn(f"Bill {em_surround('Bill 2')} added", resp.data.decode("utf-8"))
|
||||||
|
self.assertIn(
|
||||||
|
f"Bill {em_surround('Bill 1')} removed", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_double_bill_double_person_edit_second_no_web(self):
|
||||||
|
u1 = models.Person(project_id="demo", name="User 1")
|
||||||
|
u2 = models.Person(project_id="demo", name="User 1")
|
||||||
|
|
||||||
|
models.db.session.add(u1)
|
||||||
|
models.db.session.add(u2)
|
||||||
|
models.db.session.commit()
|
||||||
|
|
||||||
|
b1 = models.Bill(what="Bill 1", payer_id=u1.id, owers=[u2], amount=10)
|
||||||
|
b2 = models.Bill(what="Bill 2", payer_id=u2.id, owers=[u2], amount=11)
|
||||||
|
|
||||||
|
# This db commit exposes the "spurious owers edit" bug
|
||||||
|
models.db.session.add(b1)
|
||||||
|
models.db.session.commit()
|
||||||
|
|
||||||
|
models.db.session.add(b2)
|
||||||
|
models.db.session.commit()
|
||||||
|
|
||||||
|
history_list = history.get_history(models.Project.query.get("demo"))
|
||||||
|
self.assertEqual(len(history_list), 5)
|
||||||
|
|
||||||
|
# Change just the amount
|
||||||
|
b1.amount = 5
|
||||||
|
models.db.session.commit()
|
||||||
|
|
||||||
|
history_list = history.get_history(models.Project.query.get("demo"))
|
||||||
|
for entry in history_list:
|
||||||
|
if "prop_changed" in entry:
|
||||||
|
self.assertNotIn("owers", entry["prop_changed"])
|
||||||
|
self.assertEqual(len(history_list), 6)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
265
ihatemoney/tests/main_test.py
Normal file
265
ihatemoney/tests/main_test.py
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import smtplib
|
||||||
|
import socket
|
||||||
|
import unittest
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
from sqlalchemy import orm
|
||||||
|
|
||||||
|
from ihatemoney import models
|
||||||
|
from ihatemoney.currency_convertor import CurrencyConverter
|
||||||
|
from ihatemoney.manage import DeleteProject, GenerateConfig, GeneratePasswordHash
|
||||||
|
from ihatemoney.run import load_configuration
|
||||||
|
from ihatemoney.tests.common.ihatemoney_testcase import BaseTestCase, IhatemoneyTestCase
|
||||||
|
|
||||||
|
# Unset configuration file env var if previously set
|
||||||
|
os.environ.pop("IHATEMONEY_SETTINGS_FILE_PATH", None)
|
||||||
|
|
||||||
|
__HERE__ = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigurationTestCase(BaseTestCase):
|
||||||
|
def test_default_configuration(self):
|
||||||
|
"""Test that default settings are loaded when no other configuration file is specified"""
|
||||||
|
self.assertFalse(self.app.config["DEBUG"])
|
||||||
|
self.assertEqual(
|
||||||
|
self.app.config["SQLALCHEMY_DATABASE_URI"], "sqlite:////tmp/ihatemoney.db"
|
||||||
|
)
|
||||||
|
self.assertFalse(self.app.config["SQLALCHEMY_TRACK_MODIFICATIONS"])
|
||||||
|
self.assertEqual(
|
||||||
|
self.app.config["MAIL_DEFAULT_SENDER"],
|
||||||
|
("Budget manager", "budget@notmyidea.org"),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_env_var_configuration_file(self):
|
||||||
|
"""Test that settings are loaded from the specified configuration file"""
|
||||||
|
os.environ["IHATEMONEY_SETTINGS_FILE_PATH"] = os.path.join(
|
||||||
|
__HERE__, "ihatemoney_envvar.cfg"
|
||||||
|
)
|
||||||
|
load_configuration(self.app)
|
||||||
|
self.assertEqual(self.app.config["SECRET_KEY"], "lalatra")
|
||||||
|
|
||||||
|
# Test that the specified configuration file is loaded
|
||||||
|
# even if the default configuration file ihatemoney.cfg exists
|
||||||
|
os.environ["IHATEMONEY_SETTINGS_FILE_PATH"] = os.path.join(
|
||||||
|
__HERE__, "ihatemoney_envvar.cfg"
|
||||||
|
)
|
||||||
|
self.app.config.root_path = __HERE__
|
||||||
|
load_configuration(self.app)
|
||||||
|
self.assertEqual(self.app.config["SECRET_KEY"], "lalatra")
|
||||||
|
|
||||||
|
os.environ.pop("IHATEMONEY_SETTINGS_FILE_PATH", None)
|
||||||
|
|
||||||
|
def test_default_configuration_file(self):
|
||||||
|
"""Test that settings are loaded from the default configuration file"""
|
||||||
|
self.app.config.root_path = __HERE__
|
||||||
|
load_configuration(self.app)
|
||||||
|
self.assertEqual(self.app.config["SECRET_KEY"], "supersecret")
|
||||||
|
|
||||||
|
|
||||||
|
class ServerTestCase(IhatemoneyTestCase):
|
||||||
|
def test_homepage(self):
|
||||||
|
# See https://github.com/spiral-project/ihatemoney/pull/358
|
||||||
|
self.app.config["APPLICATION_ROOT"] = "/"
|
||||||
|
req = self.client.get("/")
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
|
||||||
|
def test_unprefixed(self):
|
||||||
|
self.app.config["APPLICATION_ROOT"] = "/"
|
||||||
|
req = self.client.get("/foo/")
|
||||||
|
self.assertStatus(303, req)
|
||||||
|
|
||||||
|
def test_prefixed(self):
|
||||||
|
self.app.config["APPLICATION_ROOT"] = "/foo"
|
||||||
|
req = self.client.get("/foo/")
|
||||||
|
self.assertStatus(200, req)
|
||||||
|
|
||||||
|
|
||||||
|
class CommandTestCase(BaseTestCase):
|
||||||
|
def test_generate_config(self):
|
||||||
|
"""Simply checks that all config file generation
|
||||||
|
- raise no exception
|
||||||
|
- produce something non-empty
|
||||||
|
"""
|
||||||
|
cmd = GenerateConfig()
|
||||||
|
for config_file in cmd.get_options()[0].kwargs["choices"]:
|
||||||
|
with patch("sys.stdout", new=io.StringIO()) as stdout:
|
||||||
|
cmd.run(config_file)
|
||||||
|
print(stdout.getvalue())
|
||||||
|
self.assertNotEqual(len(stdout.getvalue().strip()), 0)
|
||||||
|
|
||||||
|
def test_generate_password_hash(self):
|
||||||
|
cmd = GeneratePasswordHash()
|
||||||
|
with patch("sys.stdout", new=io.StringIO()) as stdout, patch(
|
||||||
|
"getpass.getpass", new=lambda prompt: "secret"
|
||||||
|
): # NOQA
|
||||||
|
cmd.run()
|
||||||
|
print(stdout.getvalue())
|
||||||
|
self.assertEqual(len(stdout.getvalue().strip()), 189)
|
||||||
|
|
||||||
|
def test_demo_project_deletion(self):
|
||||||
|
self.create_project("demo")
|
||||||
|
self.assertEquals(models.Project.query.get("demo").name, "demo")
|
||||||
|
|
||||||
|
cmd = DeleteProject()
|
||||||
|
cmd.run("demo")
|
||||||
|
|
||||||
|
self.assertEqual(len(models.Project.query.all()), 0)
|
||||||
|
|
||||||
|
|
||||||
|
class ModelsTestCase(IhatemoneyTestCase):
|
||||||
|
def test_bill_pay_each(self):
|
||||||
|
|
||||||
|
self.post_project("raclette")
|
||||||
|
|
||||||
|
# add members
|
||||||
|
self.client.post("/raclette/members/add", data={"name": "zorglub", "weight": 2})
|
||||||
|
self.client.post("/raclette/members/add", data={"name": "fred"})
|
||||||
|
self.client.post("/raclette/members/add", data={"name": "tata"})
|
||||||
|
# Add a member with a balance=0 :
|
||||||
|
self.client.post("/raclette/members/add", data={"name": "pépé"})
|
||||||
|
|
||||||
|
# create bills
|
||||||
|
self.client.post(
|
||||||
|
"/raclette/add",
|
||||||
|
data={
|
||||||
|
"date": "2011-08-10",
|
||||||
|
"what": "fromage à raclette",
|
||||||
|
"payer": 1,
|
||||||
|
"payed_for": [1, 2, 3],
|
||||||
|
"amount": "10.0",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.client.post(
|
||||||
|
"/raclette/add",
|
||||||
|
data={
|
||||||
|
"date": "2011-08-10",
|
||||||
|
"what": "red wine",
|
||||||
|
"payer": 2,
|
||||||
|
"payed_for": [1],
|
||||||
|
"amount": "20",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.client.post(
|
||||||
|
"/raclette/add",
|
||||||
|
data={
|
||||||
|
"date": "2011-08-10",
|
||||||
|
"what": "delicatessen",
|
||||||
|
"payer": 1,
|
||||||
|
"payed_for": [1, 2],
|
||||||
|
"amount": "10",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
project = models.Project.query.get_by_name(name="raclette")
|
||||||
|
zorglub = models.Person.query.get_by_name(name="zorglub", project=project)
|
||||||
|
zorglub_bills = models.Bill.query.options(
|
||||||
|
orm.subqueryload(models.Bill.owers)
|
||||||
|
).filter(models.Bill.owers.contains(zorglub))
|
||||||
|
for bill in zorglub_bills.all():
|
||||||
|
if bill.what == "red wine":
|
||||||
|
pay_each_expected = 20 / 2
|
||||||
|
self.assertEqual(bill.pay_each(), pay_each_expected)
|
||||||
|
if bill.what == "fromage à raclette":
|
||||||
|
pay_each_expected = 10 / 4
|
||||||
|
self.assertEqual(bill.pay_each(), pay_each_expected)
|
||||||
|
if bill.what == "delicatessen":
|
||||||
|
pay_each_expected = 10 / 3
|
||||||
|
self.assertEqual(bill.pay_each(), pay_each_expected)
|
||||||
|
|
||||||
|
|
||||||
|
class EmailFailureTestCase(IhatemoneyTestCase):
|
||||||
|
def test_creation_email_failure_smtp(self):
|
||||||
|
self.login("raclette")
|
||||||
|
with patch.object(
|
||||||
|
self.app.mail, "send", MagicMock(side_effect=smtplib.SMTPException)
|
||||||
|
):
|
||||||
|
resp = self.post_project("raclette")
|
||||||
|
# Check that an error message is displayed
|
||||||
|
self.assertIn(
|
||||||
|
"We tried to send you an reminder email, but there was an error",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
# Check that we were redirected to the home page anyway
|
||||||
|
self.assertIn(
|
||||||
|
'You probably want to <a href="/raclette/members/add"',
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_creation_email_failure_socket(self):
|
||||||
|
self.login("raclette")
|
||||||
|
with patch.object(self.app.mail, "send", MagicMock(side_effect=socket.error)):
|
||||||
|
resp = self.post_project("raclette")
|
||||||
|
# Check that an error message is displayed
|
||||||
|
self.assertIn(
|
||||||
|
"We tried to send you an reminder email, but there was an error",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
# Check that we were redirected to the home page anyway
|
||||||
|
self.assertIn(
|
||||||
|
'You probably want to <a href="/raclette/members/add"',
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_password_reset_email_failure(self):
|
||||||
|
self.create_project("raclette")
|
||||||
|
for exception in (smtplib.SMTPException, socket.error):
|
||||||
|
with patch.object(self.app.mail, "send", MagicMock(side_effect=exception)):
|
||||||
|
resp = self.client.post(
|
||||||
|
"/password-reminder", data={"id": "raclette"}, follow_redirects=True
|
||||||
|
)
|
||||||
|
# Check that an error message is displayed
|
||||||
|
self.assertIn(
|
||||||
|
"there was an error while sending you an email",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
# Check that we were not redirected to the success page
|
||||||
|
self.assertNotIn(
|
||||||
|
"A link to reset your password has been sent to you",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_invitation_email_failure(self):
|
||||||
|
self.login("raclette")
|
||||||
|
self.post_project("raclette")
|
||||||
|
for exception in (smtplib.SMTPException, socket.error):
|
||||||
|
with patch.object(self.app.mail, "send", MagicMock(side_effect=exception)):
|
||||||
|
resp = self.client.post(
|
||||||
|
"/raclette/invite",
|
||||||
|
data={"emails": "toto@notmyidea.org"},
|
||||||
|
follow_redirects=True,
|
||||||
|
)
|
||||||
|
# Check that an error message is displayed
|
||||||
|
self.assertIn(
|
||||||
|
"there was an error while trying to send the invitation emails",
|
||||||
|
resp.data.decode("utf-8"),
|
||||||
|
)
|
||||||
|
# Check that we are still on the same page (no redirection)
|
||||||
|
self.assertIn(
|
||||||
|
"Invite people to join this project", resp.data.decode("utf-8")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCurrencyConverter(unittest.TestCase):
|
||||||
|
converter = CurrencyConverter()
|
||||||
|
mock_data = {"USD": 1, "EUR": 0.8115}
|
||||||
|
converter.get_rates = MagicMock(return_value=mock_data)
|
||||||
|
|
||||||
|
def test_only_one_instance(self):
|
||||||
|
one = id(CurrencyConverter())
|
||||||
|
two = id(CurrencyConverter())
|
||||||
|
self.assertEqual(one, two)
|
||||||
|
|
||||||
|
def test_get_currencies(self):
|
||||||
|
self.assertCountEqual(self.converter.get_currencies(), ["USD", "EUR"])
|
||||||
|
|
||||||
|
def test_exchange_currency(self):
|
||||||
|
result = self.converter.exchange_currency(100, "USD", "EUR")
|
||||||
|
self.assertEqual(result, 81.15)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
@ -1,163 +1,167 @@
|
||||||
|
|
||||||
msgid ""
|
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: 2020-05-30 21:50+0200\n"
|
"POT-Creation-Date: 2020-05-30 21:50+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: 2021-01-08 14:32+0000\n"
|
||||||
"Last-Translator: Automatically generated\n"
|
"Last-Translator: Oliver Klimt <klimt.oliver@gmail.com>\n"
|
||||||
|
"Language-Team: Czech <https://hosted.weblate.org/projects/i-hate-money/"
|
||||||
|
"i-hate-money/cs/>\n"
|
||||||
"Language: cs\n"
|
"Language: cs\n"
|
||||||
"Language-Team: none\n"
|
|
||||||
"Plural-Forms: nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2)\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"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||||
|
"X-Generator: Weblate 4.4.1-dev\n"
|
||||||
"Generated-By: Babel 2.8.0\n"
|
"Generated-By: Babel 2.8.0\n"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Not a valid amount or expression. Only numbers and + - * / operators are "
|
"Not a valid amount or expression. Only numbers and + - * / operators are "
|
||||||
"accepted."
|
"accepted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Neplatná částka nebo výraz. Pouze čísla a operátory + - * / jsou přípustná"
|
||||||
|
|
||||||
msgid "Project name"
|
msgid "Project name"
|
||||||
msgstr ""
|
msgstr "Název projektu"
|
||||||
|
|
||||||
msgid "Private code"
|
msgid "Private code"
|
||||||
msgstr ""
|
msgstr "Přístupový kód"
|
||||||
|
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr ""
|
msgstr "Email"
|
||||||
|
|
||||||
msgid "Enable project history"
|
msgid "Enable project history"
|
||||||
msgstr ""
|
msgstr "Povolit historii projektu"
|
||||||
|
|
||||||
msgid "Use IP tracking for project history"
|
msgid "Use IP tracking for project history"
|
||||||
msgstr ""
|
msgstr "Záznam IP adres pro historii projektu"
|
||||||
|
|
||||||
msgid "Default Currency"
|
msgid "Default Currency"
|
||||||
msgstr ""
|
msgstr "Výchozí měna"
|
||||||
|
|
||||||
msgid "Import previously exported JSON file"
|
msgid "Import previously exported JSON file"
|
||||||
msgstr ""
|
msgstr "Import exportovaného JSON souboru"
|
||||||
|
|
||||||
msgid "Import"
|
msgid "Import"
|
||||||
msgstr ""
|
msgstr "Import"
|
||||||
|
|
||||||
msgid "Project identifier"
|
msgid "Project identifier"
|
||||||
msgstr ""
|
msgstr "Identifikátor projektu"
|
||||||
|
|
||||||
msgid "Create the project"
|
msgid "Create the project"
|
||||||
msgstr ""
|
msgstr "Vytvořit projekt"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"A project with this identifier (\"%(project)s\") already exists. Please "
|
"A project with this identifier (\"%(project)s\") already exists. Please "
|
||||||
"choose a new identifier"
|
"choose a new identifier"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Projekt s tímto identifikátorem (\"%(project)s\") již existuje, zvolte nový "
|
||||||
|
"identifikátor"
|
||||||
|
|
||||||
msgid "Get in"
|
msgid "Get in"
|
||||||
msgstr ""
|
msgstr "Vstoupit"
|
||||||
|
|
||||||
msgid "Admin password"
|
msgid "Admin password"
|
||||||
msgstr ""
|
msgstr "Administrátorské heslo"
|
||||||
|
|
||||||
msgid "Send me the code by email"
|
msgid "Send me the code by email"
|
||||||
msgstr ""
|
msgstr "Poslat kód na e-mail"
|
||||||
|
|
||||||
msgid "This project does not exists"
|
msgid "This project does not exists"
|
||||||
msgstr ""
|
msgstr "Tento projekt neexistuje"
|
||||||
|
|
||||||
msgid "Password mismatch"
|
msgid "Password mismatch"
|
||||||
msgstr ""
|
msgstr "Heslo nesouhlasí"
|
||||||
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr ""
|
msgstr "Heslo"
|
||||||
|
|
||||||
msgid "Password confirmation"
|
msgid "Password confirmation"
|
||||||
msgstr ""
|
msgstr "Potvrzení hesla"
|
||||||
|
|
||||||
msgid "Reset password"
|
msgid "Reset password"
|
||||||
msgstr ""
|
msgstr "Obnova hesla"
|
||||||
|
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr ""
|
msgstr "Datum"
|
||||||
|
|
||||||
msgid "What?"
|
msgid "What?"
|
||||||
msgstr ""
|
msgstr "Co?"
|
||||||
|
|
||||||
msgid "Payer"
|
msgid "Payer"
|
||||||
msgstr ""
|
msgstr "Platící"
|
||||||
|
|
||||||
msgid "Amount paid"
|
msgid "Amount paid"
|
||||||
msgstr ""
|
msgstr "Zaplacená částka"
|
||||||
|
|
||||||
msgid "Currency"
|
msgid "Currency"
|
||||||
msgstr ""
|
msgstr "Měna"
|
||||||
|
|
||||||
msgid "External link"
|
msgid "External link"
|
||||||
msgstr ""
|
msgstr "Externí odkaz"
|
||||||
|
|
||||||
msgid "A link to an external document, related to this bill"
|
msgid "A link to an external document, related to this bill"
|
||||||
msgstr ""
|
msgstr "Externí odkaz k této účtence"
|
||||||
|
|
||||||
msgid "For whom?"
|
msgid "For whom?"
|
||||||
msgstr ""
|
msgstr "Od koho?"
|
||||||
|
|
||||||
msgid "Submit"
|
msgid "Submit"
|
||||||
msgstr ""
|
msgstr "Odeslat"
|
||||||
|
|
||||||
msgid "Submit and add a new one"
|
msgid "Submit and add a new one"
|
||||||
msgstr ""
|
msgstr "Odeslat a přidat nový"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Project default: %(currency)s"
|
msgid "Project default: %(currency)s"
|
||||||
msgstr ""
|
msgstr "Výchozí měna projektu: %(currency)s"
|
||||||
|
|
||||||
msgid "Bills can't be null"
|
msgid "Bills can't be null"
|
||||||
msgstr ""
|
msgstr "Účtenka nemůže být nulová"
|
||||||
|
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr ""
|
msgstr "Jméno"
|
||||||
|
|
||||||
msgid "Weights should be positive"
|
msgid "Weights should be positive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Weight"
|
msgid "Weight"
|
||||||
msgstr ""
|
msgstr "Váha"
|
||||||
|
|
||||||
msgid "Add"
|
msgid "Add"
|
||||||
msgstr ""
|
msgstr "Přidat"
|
||||||
|
|
||||||
msgid "User name incorrect"
|
msgid "User name incorrect"
|
||||||
msgstr ""
|
msgstr "Nesprávné uživatelské jméno"
|
||||||
|
|
||||||
msgid "This project already have this member"
|
msgid "This project already have this member"
|
||||||
msgstr ""
|
msgstr "Projekt již obsahuje tohoto člena"
|
||||||
|
|
||||||
msgid "People to notify"
|
msgid "People to notify"
|
||||||
msgstr ""
|
msgstr "Osoby k informování"
|
||||||
|
|
||||||
msgid "Send invites"
|
msgid "Send invites"
|
||||||
msgstr ""
|
msgstr "Poslat pozvánky"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The email %(email)s is not valid"
|
msgid "The email %(email)s is not valid"
|
||||||
msgstr ""
|
msgstr "Toto (%(email)s) není validní e-mail"
|
||||||
|
|
||||||
msgid "Participant"
|
msgid "Participant"
|
||||||
msgstr ""
|
msgstr "Účastník"
|
||||||
|
|
||||||
msgid "Bill"
|
msgid "Bill"
|
||||||
msgstr ""
|
msgstr "Účet"
|
||||||
|
|
||||||
msgid "Project"
|
msgid "Project"
|
||||||
msgstr ""
|
msgstr "Projekt"
|
||||||
|
|
||||||
msgid "No Currency"
|
msgid "No Currency"
|
||||||
msgstr ""
|
msgstr "Žádná měna"
|
||||||
|
|
||||||
msgid "Too many failed login attempts, please retry later."
|
msgid "Too many failed login attempts, please retry later."
|
||||||
msgstr ""
|
msgstr "Příliš mnoho pokusů, zkuste to později."
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "This admin password is not the right one. Only %(num)d attempts left."
|
msgid "This admin password is not the right one. Only %(num)d attempts left."
|
||||||
|
@ -783,4 +787,3 @@ msgstr ""
|
||||||
#~ "is by the server, so don\\'t reuse"
|
#~ "is by the server, so don\\'t reuse"
|
||||||
#~ " a personal password!"
|
#~ " a personal password!"
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -1,17 +1,18 @@
|
||||||
|
|
||||||
msgid ""
|
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: 2020-05-30 21:50+0200\n"
|
"POT-Creation-Date: 2020-05-30 21:50+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: 2021-02-23 14:50+0000\n"
|
||||||
"Last-Translator: Automatically generated\n"
|
"Last-Translator: Michalis <michalisntovas@yahoo.gr>\n"
|
||||||
|
"Language-Team: Greek <https://hosted.weblate.org/projects/i-hate-money/"
|
||||||
|
"i-hate-money/el/>\n"
|
||||||
"Language: el\n"
|
"Language: el\n"
|
||||||
"Language-Team: none\n"
|
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1)\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"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
|
"X-Generator: Weblate 4.5\n"
|
||||||
"Generated-By: Babel 2.8.0\n"
|
"Generated-By: Babel 2.8.0\n"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
|
@ -62,37 +63,37 @@ msgid "Admin password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Send me the code by email"
|
msgid "Send me the code by email"
|
||||||
msgstr ""
|
msgstr "Στείλε μου τον κωδικό μέσω εμάιλ"
|
||||||
|
|
||||||
msgid "This project does not exists"
|
msgid "This project does not exists"
|
||||||
msgstr ""
|
msgstr "Το πρότζεκτ αυτό δεν υπάρχει"
|
||||||
|
|
||||||
msgid "Password mismatch"
|
msgid "Password mismatch"
|
||||||
msgstr ""
|
msgstr "Ο κωδικός δεν ταιριάζει"
|
||||||
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr ""
|
msgstr "Κωδικός"
|
||||||
|
|
||||||
msgid "Password confirmation"
|
msgid "Password confirmation"
|
||||||
msgstr ""
|
msgstr "Επιβεβαίωση κωδικού"
|
||||||
|
|
||||||
msgid "Reset password"
|
msgid "Reset password"
|
||||||
msgstr ""
|
msgstr "Επαναφορά κωδικού"
|
||||||
|
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr ""
|
msgstr "Ημερομηνία"
|
||||||
|
|
||||||
msgid "What?"
|
msgid "What?"
|
||||||
msgstr ""
|
msgstr "Τι?"
|
||||||
|
|
||||||
msgid "Payer"
|
msgid "Payer"
|
||||||
msgstr ""
|
msgstr "Πληρωτής"
|
||||||
|
|
||||||
msgid "Amount paid"
|
msgid "Amount paid"
|
||||||
msgstr ""
|
msgstr "Πληρωμένο ποσό"
|
||||||
|
|
||||||
msgid "Currency"
|
msgid "Currency"
|
||||||
msgstr ""
|
msgstr "Νόμισμα"
|
||||||
|
|
||||||
msgid "External link"
|
msgid "External link"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -101,13 +102,13 @@ msgid "A link to an external document, related to this bill"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "For whom?"
|
msgid "For whom?"
|
||||||
msgstr ""
|
msgstr "Για ποιόν?"
|
||||||
|
|
||||||
msgid "Submit"
|
msgid "Submit"
|
||||||
msgstr ""
|
msgstr "Υποβολή"
|
||||||
|
|
||||||
msgid "Submit and add a new one"
|
msgid "Submit and add a new one"
|
||||||
msgstr ""
|
msgstr "Υποβολή και προσθήκη νέου"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Project default: %(currency)s"
|
msgid "Project default: %(currency)s"
|
||||||
|
@ -117,51 +118,53 @@ msgid "Bills can't be null"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr ""
|
msgstr "Όνομα"
|
||||||
|
|
||||||
msgid "Weights should be positive"
|
msgid "Weights should be positive"
|
||||||
msgstr ""
|
msgstr "Τα βάρη πρέπει να είναι θετικά"
|
||||||
|
|
||||||
msgid "Weight"
|
msgid "Weight"
|
||||||
msgstr ""
|
msgstr "Βάρος"
|
||||||
|
|
||||||
msgid "Add"
|
msgid "Add"
|
||||||
msgstr ""
|
msgstr "Προσθήκη"
|
||||||
|
|
||||||
msgid "User name incorrect"
|
msgid "User name incorrect"
|
||||||
msgstr ""
|
msgstr "Λανθασμένο όνομα χρήστη"
|
||||||
|
|
||||||
msgid "This project already have this member"
|
msgid "This project already have this member"
|
||||||
msgstr ""
|
msgstr "Το πρότζεκτ έχει ήδη αυτό το μέλος"
|
||||||
|
|
||||||
msgid "People to notify"
|
msgid "People to notify"
|
||||||
msgstr ""
|
msgstr "Άτομα να ειδοποιήσεις"
|
||||||
|
|
||||||
msgid "Send invites"
|
msgid "Send invites"
|
||||||
msgstr ""
|
msgstr "Στείλε πρόσκληση"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The email %(email)s is not valid"
|
msgid "The email %(email)s is not valid"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Participant"
|
msgid "Participant"
|
||||||
msgstr ""
|
msgstr "Συμμέτοχος"
|
||||||
|
|
||||||
msgid "Bill"
|
msgid "Bill"
|
||||||
msgstr ""
|
msgstr "Λογαριασμός"
|
||||||
|
|
||||||
msgid "Project"
|
msgid "Project"
|
||||||
msgstr ""
|
msgstr "Πρότζεκτ"
|
||||||
|
|
||||||
msgid "No Currency"
|
msgid "No Currency"
|
||||||
msgstr ""
|
msgstr "Κανένα νόμισμα"
|
||||||
|
|
||||||
msgid "Too many failed login attempts, please retry later."
|
msgid "Too many failed login attempts, please retry later."
|
||||||
msgstr ""
|
msgstr "Πάρα πολλές αποτυχημένες προσπάθειες σύνδεσης, δοκιμάστε ξανά αργότερα."
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "This admin password is not the right one. Only %(num)d attempts left."
|
msgid "This admin password is not the right one. Only %(num)d attempts left."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Αυτός ο κωδικός διαχειριστή δεν είναι σωστός. Μένουν μόνο %(num)d "
|
||||||
|
"προσπάθειες."
|
||||||
|
|
||||||
msgid "You either provided a bad token or no project identifier."
|
msgid "You either provided a bad token or no project identifier."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -174,12 +177,14 @@ msgid "You have just created '%(project)s' to share your expenses"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "A reminder email has just been sent to you"
|
msgid "A reminder email has just been sent to you"
|
||||||
msgstr ""
|
msgstr "Ένα εμάιλ υπενθύμισης μόλις σας στάλθηκε"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"We tried to send you an reminder email, but there was an error. You can "
|
"We tried to send you an reminder email, but there was an error. You can "
|
||||||
"still use the project normally."
|
"still use the project normally."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Προσπαθήσαμε να σας στείλουμε ένα εμάιλ υπενθύμισης, αλλά υπήρξε ένα λάθος. "
|
||||||
|
"Μπορείτε ακόμα να χρησιμοποιήσετε το πρότζεκτ κανονικά."
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The project identifier is %(project)s"
|
msgid "The project identifier is %(project)s"
|
||||||
|
@ -198,10 +203,10 @@ msgid "Invalid token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Unknown project"
|
msgid "Unknown project"
|
||||||
msgstr ""
|
msgstr "Άγνωστο πρότζεκτ"
|
||||||
|
|
||||||
msgid "Password successfully reset."
|
msgid "Password successfully reset."
|
||||||
msgstr ""
|
msgstr "Επαναφορά του κωδικού επιτυχώς."
|
||||||
|
|
||||||
msgid "Project successfully uploaded"
|
msgid "Project successfully uploaded"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -210,14 +215,14 @@ msgid "Invalid JSON"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Project successfully deleted"
|
msgid "Project successfully deleted"
|
||||||
msgstr ""
|
msgstr "Το πρότζεκτ διαγράφηκε επιτυχώς"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "You have been invited to share your expenses for %(project)s"
|
msgid "You have been invited to share your expenses for %(project)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Your invitations have been sent"
|
msgid "Your invitations have been sent"
|
||||||
msgstr ""
|
msgstr "Οι προσκλήσεις έχουν σταλθεί"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Sorry, there was an error while trying to send the invitation emails. "
|
"Sorry, there was an error while trying to send the invitation emails. "
|
||||||
|
@ -248,7 +253,7 @@ msgid "User '%(name)s' has been edited"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "The bill has been added"
|
msgid "The bill has been added"
|
||||||
msgstr ""
|
msgstr "Ο λογαριασμός προστέθηκε"
|
||||||
|
|
||||||
msgid "The bill has been deleted"
|
msgid "The bill has been deleted"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -783,4 +788,3 @@ msgstr ""
|
||||||
#~ "is by the server, so don\\'t reuse"
|
#~ "is by the server, so don\\'t reuse"
|
||||||
#~ " a personal password!"
|
#~ " a personal password!"
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -3,49 +3,53 @@ 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: 2020-09-22 14:01+0200\n"
|
"POT-Creation-Date: 2020-09-22 14:01+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: 2020-11-11 16:28+0000\n"
|
||||||
"Last-Translator: Automatically generated\n"
|
"Last-Translator: Puyma <puyma@amyup.xyz>\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: Spanish <https://hosted.weblate.org/projects/i-hate-money/"
|
||||||
|
"i-hate-money/es/>\n"
|
||||||
"Language: es\n"
|
"Language: es\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"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"X-Generator: Translate Toolkit 3.0.0\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
|
"X-Generator: Weblate 4.4-dev\n"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Not a valid amount or expression. Only numbers and + - * / operators are "
|
"Not a valid amount or expression. Only numbers and + - * / operators are "
|
||||||
"accepted."
|
"accepted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Cantidad o expresión no válida. Solo se aceptan números y los operadores + - "
|
||||||
|
"* /."
|
||||||
|
|
||||||
msgid "Project name"
|
msgid "Project name"
|
||||||
msgstr ""
|
msgstr "Nombre del proyecto"
|
||||||
|
|
||||||
msgid "Private code"
|
msgid "Private code"
|
||||||
msgstr ""
|
msgstr "Código privado"
|
||||||
|
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr ""
|
msgstr "Correo electrónico"
|
||||||
|
|
||||||
msgid "Enable project history"
|
msgid "Enable project history"
|
||||||
msgstr ""
|
msgstr "Habilitar historial del proyecto"
|
||||||
|
|
||||||
msgid "Use IP tracking for project history"
|
msgid "Use IP tracking for project history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Default Currency"
|
msgid "Default Currency"
|
||||||
msgstr ""
|
msgstr "Moneda por defecto"
|
||||||
|
|
||||||
msgid "Import previously exported JSON file"
|
msgid "Import previously exported JSON file"
|
||||||
msgstr ""
|
msgstr "Importar .JSON previamente exportado"
|
||||||
|
|
||||||
msgid "Import"
|
msgid "Import"
|
||||||
msgstr ""
|
msgstr "Importar"
|
||||||
|
|
||||||
msgid "Project identifier"
|
msgid "Project identifier"
|
||||||
msgstr ""
|
msgstr "Identificador del proyecto"
|
||||||
|
|
||||||
msgid "Create the project"
|
msgid "Create the project"
|
||||||
msgstr ""
|
msgstr "Crear proyecto"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
|
@ -57,49 +61,49 @@ msgid "Get in"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Admin password"
|
msgid "Admin password"
|
||||||
msgstr ""
|
msgstr "Contraseña de administrador"
|
||||||
|
|
||||||
msgid "Send me the code by email"
|
msgid "Send me the code by email"
|
||||||
msgstr ""
|
msgstr "Envíame el código por correo electrónico"
|
||||||
|
|
||||||
msgid "This project does not exists"
|
msgid "This project does not exists"
|
||||||
msgstr ""
|
msgstr "Proyecto inexistente"
|
||||||
|
|
||||||
msgid "Password mismatch"
|
msgid "Password mismatch"
|
||||||
msgstr ""
|
msgstr "La contraseña no coincide"
|
||||||
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr ""
|
msgstr "Contraseña"
|
||||||
|
|
||||||
msgid "Password confirmation"
|
msgid "Password confirmation"
|
||||||
msgstr ""
|
msgstr "Confirmar contraseña"
|
||||||
|
|
||||||
msgid "Reset password"
|
msgid "Reset password"
|
||||||
msgstr ""
|
msgstr "Reestablecer contraseña"
|
||||||
|
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr ""
|
msgstr "Fecha"
|
||||||
|
|
||||||
msgid "What?"
|
msgid "What?"
|
||||||
msgstr ""
|
msgstr "¿Qué?"
|
||||||
|
|
||||||
msgid "Payer"
|
msgid "Payer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Amount paid"
|
msgid "Amount paid"
|
||||||
msgstr ""
|
msgstr "Cantidad pagada"
|
||||||
|
|
||||||
msgid "Currency"
|
msgid "Currency"
|
||||||
msgstr ""
|
msgstr "Divisa"
|
||||||
|
|
||||||
msgid "External link"
|
msgid "External link"
|
||||||
msgstr ""
|
msgstr "Enlace externo"
|
||||||
|
|
||||||
msgid "A link to an external document, related to this bill"
|
msgid "A link to an external document, related to this bill"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "For whom?"
|
msgid "For whom?"
|
||||||
msgstr ""
|
msgstr "¿Para quién?"
|
||||||
|
|
||||||
msgid "Submit"
|
msgid "Submit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -115,7 +119,7 @@ msgid "Bills can't be null"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr ""
|
msgstr "Nombre"
|
||||||
|
|
||||||
msgid "Weights should be positive"
|
msgid "Weights should be positive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -124,10 +128,10 @@ msgid "Weight"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Add"
|
msgid "Add"
|
||||||
msgstr ""
|
msgstr "Añadir"
|
||||||
|
|
||||||
msgid "User name incorrect"
|
msgid "User name incorrect"
|
||||||
msgstr ""
|
msgstr "Usuario incorrecto"
|
||||||
|
|
||||||
msgid "This project already have this member"
|
msgid "This project already have this member"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -136,20 +140,20 @@ msgid "People to notify"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Send invites"
|
msgid "Send invites"
|
||||||
msgstr ""
|
msgstr "Enviar invitaciones"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The email %(email)s is not valid"
|
msgid "The email %(email)s is not valid"
|
||||||
msgstr ""
|
msgstr "El correo %(email)s no es válido"
|
||||||
|
|
||||||
msgid "Participant"
|
msgid "Participant"
|
||||||
msgstr ""
|
msgstr "Participante"
|
||||||
|
|
||||||
msgid "Bill"
|
msgid "Bill"
|
||||||
msgstr ""
|
msgstr "Factura"
|
||||||
|
|
||||||
msgid "Project"
|
msgid "Project"
|
||||||
msgstr ""
|
msgstr "Proyecto"
|
||||||
|
|
||||||
msgid "No Currency"
|
msgid "No Currency"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -291,16 +295,16 @@ msgid "Oldest bill"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr ""
|
msgstr "Acciones"
|
||||||
|
|
||||||
msgid "edit"
|
msgid "edit"
|
||||||
msgstr ""
|
msgstr "editar"
|
||||||
|
|
||||||
msgid "delete"
|
msgid "delete"
|
||||||
msgstr ""
|
msgstr "eliminar"
|
||||||
|
|
||||||
msgid "show"
|
msgid "show"
|
||||||
msgstr ""
|
msgstr "mostrar"
|
||||||
|
|
||||||
msgid "The Dashboard is currently deactivated."
|
msgid "The Dashboard is currently deactivated."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -336,49 +340,49 @@ msgid "Can't remember the password?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr ""
|
msgstr "Cancelar"
|
||||||
|
|
||||||
msgid "Privacy Settings"
|
msgid "Privacy Settings"
|
||||||
msgstr ""
|
msgstr "Ajustes de privacidad"
|
||||||
|
|
||||||
msgid "Edit the project"
|
msgid "Edit the project"
|
||||||
msgstr ""
|
msgstr "Editar el proyecto"
|
||||||
|
|
||||||
msgid "Edit this bill"
|
msgid "Edit this bill"
|
||||||
msgstr ""
|
msgstr "Editar esta factura"
|
||||||
|
|
||||||
msgid "Add a bill"
|
msgid "Add a bill"
|
||||||
msgstr ""
|
msgstr "Añadir una factura"
|
||||||
|
|
||||||
msgid "Select all"
|
msgid "Select all"
|
||||||
msgstr ""
|
msgstr "Seleccionar todo"
|
||||||
|
|
||||||
msgid "Select none"
|
msgid "Select none"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Add participant"
|
msgid "Add participant"
|
||||||
msgstr ""
|
msgstr "Añadir participante"
|
||||||
|
|
||||||
msgid "Edit this member"
|
msgid "Edit this member"
|
||||||
msgstr ""
|
msgstr "Editar miembro"
|
||||||
|
|
||||||
msgid "john.doe@example.com, mary.moe@site.com"
|
msgid "john.doe@example.com, mary.moe@site.com"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Send the invitations"
|
msgid "Send the invitations"
|
||||||
msgstr ""
|
msgstr "Enviar invitaciones"
|
||||||
|
|
||||||
msgid "Download"
|
msgid "Download"
|
||||||
msgstr ""
|
msgstr "Descargar"
|
||||||
|
|
||||||
msgid "Disabled Project History"
|
msgid "Disabled Project History"
|
||||||
msgstr ""
|
msgstr "Historial del proyecto desactivado"
|
||||||
|
|
||||||
msgid "Disabled Project History & IP Address Recording"
|
msgid "Disabled Project History & IP Address Recording"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Enabled Project History"
|
msgid "Enabled Project History"
|
||||||
msgstr ""
|
msgstr "Historial del proyecto activado"
|
||||||
|
|
||||||
msgid "Disabled IP Address Recording"
|
msgid "Disabled IP Address Recording"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -396,10 +400,10 @@ msgid "changed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "from"
|
msgid "from"
|
||||||
msgstr ""
|
msgstr "de"
|
||||||
|
|
||||||
msgid "to"
|
msgid "to"
|
||||||
msgstr ""
|
msgstr "para"
|
||||||
|
|
||||||
msgid "Confirm Remove IP Adresses"
|
msgid "Confirm Remove IP Adresses"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -412,7 +416,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr ""
|
msgstr "Cerrar"
|
||||||
|
|
||||||
msgid "Confirm Delete"
|
msgid "Confirm Delete"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -426,10 +430,10 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Added"
|
msgid "Added"
|
||||||
msgstr ""
|
msgstr "Añadido"
|
||||||
|
|
||||||
msgid "Removed"
|
msgid "Removed"
|
||||||
msgstr ""
|
msgstr "Eliminado"
|
||||||
|
|
||||||
msgid "and"
|
msgid "and"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -477,10 +481,10 @@ msgid "Delete Stored IP Addresses"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Time"
|
msgid "Time"
|
||||||
msgstr ""
|
msgstr "Hora"
|
||||||
|
|
||||||
msgid "Event"
|
msgid "Event"
|
||||||
msgstr ""
|
msgstr "Evento"
|
||||||
|
|
||||||
msgid "IP address recording can be enabled on the settings page"
|
msgid "IP address recording can be enabled on the settings page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -492,7 +496,7 @@ msgid "From IP"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "added"
|
msgid "added"
|
||||||
msgstr ""
|
msgstr "añadido"
|
||||||
|
|
||||||
msgid "Project private code changed"
|
msgid "Project private code changed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -519,17 +523,17 @@ msgid "External link changed to"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Amount"
|
msgid "Amount"
|
||||||
msgstr ""
|
msgstr "Cantidad"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Amount in %(currency)s"
|
msgid "Amount in %(currency)s"
|
||||||
msgstr ""
|
msgstr "Cantidad en %(currency)s"
|
||||||
|
|
||||||
msgid "modified"
|
msgid "modified"
|
||||||
msgstr ""
|
msgstr "modificado"
|
||||||
|
|
||||||
msgid "removed"
|
msgid "removed"
|
||||||
msgstr ""
|
msgstr "eliminado"
|
||||||
|
|
||||||
msgid "changed in a unknown way"
|
msgid "changed in a unknown way"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -556,57 +560,59 @@ msgid "Simply sharing money with others?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "We can help!"
|
msgid "We can help!"
|
||||||
msgstr ""
|
msgstr "Podemos ayudar!"
|
||||||
|
|
||||||
msgid "Log in to an existing project"
|
msgid "Log in to an existing project"
|
||||||
msgstr ""
|
msgstr "Acceder a un proyecto existente"
|
||||||
|
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "can't remember your password?"
|
msgid "can't remember your password?"
|
||||||
msgstr ""
|
msgstr "¿no recuerdas tu contraseña?"
|
||||||
|
|
||||||
msgid "Create"
|
msgid "Create"
|
||||||
msgstr ""
|
msgstr "Crear"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Don\\'t reuse a personal password. Choose a private code and send it to "
|
"Don\\'t reuse a personal password. Choose a private code and send it to "
|
||||||
"your friends"
|
"your friends"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"No reutilizes una contraseña personal. Escoge un código privado i envíalo a "
|
||||||
|
"tus amigos"
|
||||||
|
|
||||||
msgid "Account manager"
|
msgid "Account manager"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Bills"
|
msgid "Bills"
|
||||||
msgstr ""
|
msgstr "Facturas"
|
||||||
|
|
||||||
msgid "Settle"
|
msgid "Settle"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Statistics"
|
msgid "Statistics"
|
||||||
msgstr ""
|
msgstr "Estadísticas"
|
||||||
|
|
||||||
msgid "History"
|
msgid "History"
|
||||||
msgstr ""
|
msgstr "Historia"
|
||||||
|
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr ""
|
msgstr "Ajustes"
|
||||||
|
|
||||||
msgid "Languages"
|
msgid "Languages"
|
||||||
msgstr ""
|
msgstr "Idiomas"
|
||||||
|
|
||||||
msgid "Projects"
|
msgid "Projects"
|
||||||
msgstr ""
|
msgstr "Proyectos"
|
||||||
|
|
||||||
msgid "Start a new project"
|
msgid "Start a new project"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Other projects :"
|
msgid "Other projects :"
|
||||||
msgstr ""
|
msgstr "Otros proyectos :"
|
||||||
|
|
||||||
msgid "switch to"
|
msgid "switch to"
|
||||||
msgstr ""
|
msgstr "cambiar a"
|
||||||
|
|
||||||
msgid "Dashboard"
|
msgid "Dashboard"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -615,16 +621,16 @@ msgid "Logout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Code"
|
msgid "Code"
|
||||||
msgstr ""
|
msgstr "Código"
|
||||||
|
|
||||||
msgid "Mobile Application"
|
msgid "Mobile Application"
|
||||||
msgstr ""
|
msgstr "Aplicación móvil"
|
||||||
|
|
||||||
msgid "Documentation"
|
msgid "Documentation"
|
||||||
msgstr ""
|
msgstr "Documentación"
|
||||||
|
|
||||||
msgid "Administation Dashboard"
|
msgid "Administation Dashboard"
|
||||||
msgstr ""
|
msgstr "Panel de administración"
|
||||||
|
|
||||||
msgid "\"I hate money\" is a free software"
|
msgid "\"I hate money\" is a free software"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -652,7 +658,7 @@ msgid "Older bills"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "When?"
|
msgid "When?"
|
||||||
msgstr ""
|
msgstr "¿Cuándo?"
|
||||||
|
|
||||||
msgid "Who paid?"
|
msgid "Who paid?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -675,19 +681,19 @@ msgid "Everyone but %(excluded)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "No bills"
|
msgid "No bills"
|
||||||
msgstr ""
|
msgstr "Sin facturas"
|
||||||
|
|
||||||
msgid "Nothing to list yet."
|
msgid "Nothing to list yet."
|
||||||
msgstr ""
|
msgstr "No hay nada que mostrar todavía."
|
||||||
|
|
||||||
msgid "You probably want to"
|
msgid "You probably want to"
|
||||||
msgstr ""
|
msgstr "Probablemente quieras"
|
||||||
|
|
||||||
msgid "add a bill"
|
msgid "add a bill"
|
||||||
msgstr ""
|
msgstr "añadir una factura"
|
||||||
|
|
||||||
msgid "add participants"
|
msgid "add participants"
|
||||||
msgstr ""
|
msgstr "añadir participantes"
|
||||||
|
|
||||||
msgid "Password reminder"
|
msgid "Password reminder"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -698,19 +704,19 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Return to home page"
|
msgid "Return to home page"
|
||||||
msgstr ""
|
msgstr "Volver a la página de inicio"
|
||||||
|
|
||||||
msgid "Your projects"
|
msgid "Your projects"
|
||||||
msgstr ""
|
msgstr "Tus proyectos"
|
||||||
|
|
||||||
msgid "Reset your password"
|
msgid "Reset your password"
|
||||||
msgstr ""
|
msgstr "Reestablecer tu contraseña"
|
||||||
|
|
||||||
msgid "Invite people to join this project"
|
msgid "Invite people to join this project"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Share Identifier & code"
|
msgid "Share Identifier & code"
|
||||||
msgstr ""
|
msgstr "Compartir identificador i código"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can share the project identifier and the private code by any "
|
"You can share the project identifier and the private code by any "
|
||||||
|
@ -718,10 +724,10 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Identifier:"
|
msgid "Identifier:"
|
||||||
msgstr ""
|
msgstr "Identificador:"
|
||||||
|
|
||||||
msgid "Share the Link"
|
msgid "Share the Link"
|
||||||
msgstr ""
|
msgstr "Compartir el enlace"
|
||||||
|
|
||||||
msgid "You can directly share the following link via your prefered medium"
|
msgid "You can directly share the following link via your prefered medium"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -740,28 +746,28 @@ msgid "Who pays?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "To whom?"
|
msgid "To whom?"
|
||||||
msgstr ""
|
msgstr "¿Para quién?"
|
||||||
|
|
||||||
msgid "Who?"
|
msgid "Who?"
|
||||||
msgstr ""
|
msgstr "¿Quién?"
|
||||||
|
|
||||||
msgid "Balance"
|
msgid "Balance"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "deactivate"
|
msgid "deactivate"
|
||||||
msgstr ""
|
msgstr "desactivar"
|
||||||
|
|
||||||
msgid "reactivate"
|
msgid "reactivate"
|
||||||
msgstr ""
|
msgstr "reactivar"
|
||||||
|
|
||||||
msgid "Paid"
|
msgid "Paid"
|
||||||
msgstr ""
|
msgstr "Pagado"
|
||||||
|
|
||||||
msgid "Spent"
|
msgid "Spent"
|
||||||
msgstr ""
|
msgstr "Gastado"
|
||||||
|
|
||||||
msgid "Expenses by Month"
|
msgid "Expenses by Month"
|
||||||
msgstr ""
|
msgstr "Gastos por mes"
|
||||||
|
|
||||||
msgid "Period"
|
msgid "Period"
|
||||||
msgstr ""
|
msgstr "Período"
|
||||||
|
|
Binary file not shown.
|
@ -3,8 +3,8 @@ 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: 2020-05-30 21:50+0200\n"
|
"POT-Creation-Date: 2020-05-30 21:50+0200\n"
|
||||||
"PO-Revision-Date: 2020-08-30 19:59+0000\n"
|
"PO-Revision-Date: 2020-11-11 16:28+0000\n"
|
||||||
"Last-Translator: Miguel Victoria Villaquiran <miguelvicvil@gmail.com>\n"
|
"Last-Translator: Puyma <puyma@amyup.xyz>\n"
|
||||||
"Language-Team: Spanish (Latin America) <https://hosted.weblate.org/projects/"
|
"Language-Team: Spanish (Latin America) <https://hosted.weblate.org/projects/"
|
||||||
"i-hate-money/i-hate-money/es_419/>\n"
|
"i-hate-money/i-hate-money/es_419/>\n"
|
||||||
"Language: es_419\n"
|
"Language: es_419\n"
|
||||||
|
@ -12,7 +12,7 @@ msgstr ""
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 4.2.1-dev\n"
|
"X-Generator: Weblate 4.4-dev\n"
|
||||||
"Generated-By: Babel 2.8.0\n"
|
"Generated-By: Babel 2.8.0\n"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
|
@ -38,7 +38,7 @@ msgid "Use IP tracking for project history"
|
||||||
msgstr "Registrar la IPs para el historial del proyecto"
|
msgstr "Registrar la IPs para el historial del proyecto"
|
||||||
|
|
||||||
msgid "Default Currency"
|
msgid "Default Currency"
|
||||||
msgstr "moneda predeterminada"
|
msgstr "Moneda por defecto"
|
||||||
|
|
||||||
msgid "Import previously exported JSON file"
|
msgid "Import previously exported JSON file"
|
||||||
msgstr "Importar archivo JSON previamente exportado"
|
msgstr "Importar archivo JSON previamente exportado"
|
||||||
|
@ -61,10 +61,10 @@ msgstr ""
|
||||||
"favor, elija un nuevo identificador"
|
"favor, elija un nuevo identificador"
|
||||||
|
|
||||||
msgid "Get in"
|
msgid "Get in"
|
||||||
msgstr "Entra"
|
msgstr "Entrar"
|
||||||
|
|
||||||
msgid "Admin password"
|
msgid "Admin password"
|
||||||
msgstr "Clave de Administrador"
|
msgstr "Contraseña de Administrador"
|
||||||
|
|
||||||
msgid "Send me the code by email"
|
msgid "Send me the code by email"
|
||||||
msgstr "Envíame el código por correo electrónico"
|
msgstr "Envíame el código por correo electrónico"
|
||||||
|
@ -103,7 +103,7 @@ msgid "External link"
|
||||||
msgstr "Enlace externo"
|
msgstr "Enlace externo"
|
||||||
|
|
||||||
msgid "A link to an external document, related to this bill"
|
msgid "A link to an external document, related to this bill"
|
||||||
msgstr "Un enlace a un documento externo relaccionado con esta factura"
|
msgstr "Un enlace a un documento externo relacionado con esta factura"
|
||||||
|
|
||||||
msgid "For whom?"
|
msgid "For whom?"
|
||||||
msgstr "¿Para quién?"
|
msgstr "¿Para quién?"
|
||||||
|
|
Binary file not shown.
|
@ -3,8 +3,8 @@ 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: 2020-05-30 21:50+0200\n"
|
"POT-Creation-Date: 2020-05-30 21:50+0200\n"
|
||||||
"PO-Revision-Date: 2020-09-26 09:40+0000\n"
|
"PO-Revision-Date: 2021-02-21 04:50+0000\n"
|
||||||
"Last-Translator: Fakhruddin Ahmad Darwis <fakhri.satu@gmail.com>\n"
|
"Last-Translator: Reza Almanda <rezaalmanda27@gmail.com>\n"
|
||||||
"Language-Team: Indonesian <https://hosted.weblate.org/projects/i-hate-money/"
|
"Language-Team: Indonesian <https://hosted.weblate.org/projects/i-hate-money/"
|
||||||
"i-hate-money/id/>\n"
|
"i-hate-money/id/>\n"
|
||||||
"Language: id\n"
|
"Language: id\n"
|
||||||
|
@ -12,14 +12,14 @@ msgstr ""
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
"X-Generator: Weblate 4.3-dev\n"
|
"X-Generator: Weblate 4.5\n"
|
||||||
"Generated-By: Babel 2.8.0\n"
|
"Generated-By: Babel 2.8.0\n"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Not a valid amount or expression. Only numbers and + - * / operators are "
|
"Not a valid amount or expression. Only numbers and + - * / operators are "
|
||||||
"accepted."
|
"accepted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Jumlah atau operator tidak valid. Hanya angka dan opertaor +-* yang "
|
"Bukan jumlah atau operator yang valid. Hanya angka dan operator + -* / yang "
|
||||||
"diterima."
|
"diterima."
|
||||||
|
|
||||||
msgid "Project name"
|
msgid "Project name"
|
||||||
|
@ -116,7 +116,7 @@ msgstr "Ajukan dan tambah yang baru"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Project default: %(currency)s"
|
msgid "Project default: %(currency)s"
|
||||||
msgstr ""
|
msgstr "Default proyek: %(currency)s"
|
||||||
|
|
||||||
msgid "Bills can't be null"
|
msgid "Bills can't be null"
|
||||||
msgstr "Tagihan tidak boleh kosong"
|
msgstr "Tagihan tidak boleh kosong"
|
||||||
|
@ -150,16 +150,16 @@ msgid "The email %(email)s is not valid"
|
||||||
msgstr "Surel %(email)s tidak valid"
|
msgstr "Surel %(email)s tidak valid"
|
||||||
|
|
||||||
msgid "Participant"
|
msgid "Participant"
|
||||||
msgstr ""
|
msgstr "Partisipan"
|
||||||
|
|
||||||
msgid "Bill"
|
msgid "Bill"
|
||||||
msgstr ""
|
msgstr "Tagihan"
|
||||||
|
|
||||||
msgid "Project"
|
msgid "Project"
|
||||||
msgstr "Proyek"
|
msgstr "Proyek"
|
||||||
|
|
||||||
msgid "No Currency"
|
msgid "No Currency"
|
||||||
msgstr ""
|
msgstr "Tidak ada mata uang"
|
||||||
|
|
||||||
msgid "Too many failed login attempts, please retry later."
|
msgid "Too many failed login attempts, please retry later."
|
||||||
msgstr "Terlalu banyak percobaan masuk, silakan coba lagi nanti."
|
msgstr "Terlalu banyak percobaan masuk, silakan coba lagi nanti."
|
||||||
|
@ -179,22 +179,26 @@ msgid "You have just created '%(project)s' to share your expenses"
|
||||||
msgstr "Anda baru saja membuat %(project)s untuk membagikan harga Anda"
|
msgstr "Anda baru saja membuat %(project)s untuk membagikan harga Anda"
|
||||||
|
|
||||||
msgid "A reminder email has just been sent to you"
|
msgid "A reminder email has just been sent to you"
|
||||||
msgstr ""
|
msgstr "Email pengingat baru saja dikirimkan kepada Anda"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"We tried to send you an reminder email, but there was an error. You can "
|
"We tried to send you an reminder email, but there was an error. You can "
|
||||||
"still use the project normally."
|
"still use the project normally."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Kami telah mengirimi Anda email pengingat, tetapi ada kesalahan. Anda masih "
|
||||||
|
"dapat menggunakan proyek secara normal."
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The project identifier is %(project)s"
|
msgid "The project identifier is %(project)s"
|
||||||
msgstr ""
|
msgstr "Pengidentifikasi proyek adalah %(project)s"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Sorry, there was an error while sending you an email with password reset "
|
"Sorry, there was an error while sending you an email with password reset "
|
||||||
"instructions. Please check the email configuration of the server or "
|
"instructions. Please check the email configuration of the server or "
|
||||||
"contact the administrator."
|
"contact the administrator."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Maaf, ada galat saat mengirim email berisi instruksi pengaturan ulang kata "
|
||||||
|
"sandi. Silakan periksa konfigurasi email peladen atau hubungi administrator."
|
||||||
|
|
||||||
msgid "No token provided"
|
msgid "No token provided"
|
||||||
msgstr "Belum ada token diberikan"
|
msgstr "Belum ada token diberikan"
|
||||||
|
@ -209,10 +213,10 @@ msgid "Password successfully reset."
|
||||||
msgstr "Kata sandi berhasil diatur ulang."
|
msgstr "Kata sandi berhasil diatur ulang."
|
||||||
|
|
||||||
msgid "Project successfully uploaded"
|
msgid "Project successfully uploaded"
|
||||||
msgstr ""
|
msgstr "Proyek berhasil diunggah"
|
||||||
|
|
||||||
msgid "Invalid JSON"
|
msgid "Invalid JSON"
|
||||||
msgstr ""
|
msgstr "JSON tidak valid"
|
||||||
|
|
||||||
msgid "Project successfully deleted"
|
msgid "Project successfully deleted"
|
||||||
msgstr "Proyek berhasil dihapus"
|
msgstr "Proyek berhasil dihapus"
|
||||||
|
@ -229,10 +233,12 @@ msgid ""
|
||||||
"Please check the email configuration of the server or contact the "
|
"Please check the email configuration of the server or contact the "
|
||||||
"administrator."
|
"administrator."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Maaf, ada galat saat mencoba mengirim email undangan. Silakan periksa "
|
||||||
|
"konfigurasi email peladen atau hubungi administrator."
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(member)s has been added"
|
msgid "%(member)s has been added"
|
||||||
msgstr ""
|
msgstr "%(member)s telah ditambahkan"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(name)s is part of this project again"
|
msgid "%(name)s is part of this project again"
|
||||||
|
@ -309,7 +315,7 @@ msgid "delete"
|
||||||
msgstr "hapus"
|
msgstr "hapus"
|
||||||
|
|
||||||
msgid "show"
|
msgid "show"
|
||||||
msgstr ""
|
msgstr "tampilkan"
|
||||||
|
|
||||||
msgid "The Dashboard is currently deactivated."
|
msgid "The Dashboard is currently deactivated."
|
||||||
msgstr "Dasbor sekarang ini sedang dinonaktifkan."
|
msgstr "Dasbor sekarang ini sedang dinonaktifkan."
|
||||||
|
@ -321,10 +327,10 @@ msgid "Edit project"
|
||||||
msgstr "Ubah proyek"
|
msgstr "Ubah proyek"
|
||||||
|
|
||||||
msgid "Import JSON"
|
msgid "Import JSON"
|
||||||
msgstr ""
|
msgstr "Impor JSON"
|
||||||
|
|
||||||
msgid "Choose file"
|
msgid "Choose file"
|
||||||
msgstr ""
|
msgstr "Pilih berkas"
|
||||||
|
|
||||||
msgid "Download project's data"
|
msgid "Download project's data"
|
||||||
msgstr "Unduh data proyek"
|
msgstr "Unduh data proyek"
|
||||||
|
@ -348,7 +354,7 @@ msgid "Cancel"
|
||||||
msgstr "Batalkan"
|
msgstr "Batalkan"
|
||||||
|
|
||||||
msgid "Privacy Settings"
|
msgid "Privacy Settings"
|
||||||
msgstr ""
|
msgstr "Pengaturan Privasi"
|
||||||
|
|
||||||
msgid "Edit the project"
|
msgid "Edit the project"
|
||||||
msgstr "Ubah proyek"
|
msgstr "Ubah proyek"
|
||||||
|
@ -381,16 +387,16 @@ msgid "Download"
|
||||||
msgstr "Unduh"
|
msgstr "Unduh"
|
||||||
|
|
||||||
msgid "Disabled Project History"
|
msgid "Disabled Project History"
|
||||||
msgstr ""
|
msgstr "Nonaktifkan riwayat proyek"
|
||||||
|
|
||||||
msgid "Disabled Project History & IP Address Recording"
|
msgid "Disabled Project History & IP Address Recording"
|
||||||
msgstr ""
|
msgstr "Nonaktifkan riwayat proyek & rekaman alamat IP"
|
||||||
|
|
||||||
msgid "Enabled Project History"
|
msgid "Enabled Project History"
|
||||||
msgstr ""
|
msgstr "Riwayat Proyek yang Diaktifkan"
|
||||||
|
|
||||||
msgid "Disabled IP Address Recording"
|
msgid "Disabled IP Address Recording"
|
||||||
msgstr ""
|
msgstr "Perekaman Alamat IP Dinonaktifkan"
|
||||||
|
|
||||||
msgid "Enabled Project History & IP Address Recording"
|
msgid "Enabled Project History & IP Address Recording"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -399,19 +405,19 @@ msgid "Enabled IP Address Recording"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "History Settings Changed"
|
msgid "History Settings Changed"
|
||||||
msgstr ""
|
msgstr "Setelan Riwayat Diubah"
|
||||||
|
|
||||||
msgid "changed"
|
msgid "changed"
|
||||||
msgstr ""
|
msgstr "diubah"
|
||||||
|
|
||||||
msgid "from"
|
msgid "from"
|
||||||
msgstr ""
|
msgstr "dari"
|
||||||
|
|
||||||
msgid "to"
|
msgid "to"
|
||||||
msgstr ""
|
msgstr "ke"
|
||||||
|
|
||||||
msgid "Confirm Remove IP Adresses"
|
msgid "Confirm Remove IP Adresses"
|
||||||
msgstr ""
|
msgstr "Konfirmasi Hapus Alamat IP"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure you want to delete all recorded IP addresses from this "
|
"Are you sure you want to delete all recorded IP addresses from this "
|
||||||
|
@ -419,32 +425,37 @@ msgid ""
|
||||||
" The rest of the project history will be unaffected. This "
|
" The rest of the project history will be unaffected. This "
|
||||||
"action cannot be undone."
|
"action cannot be undone."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Anda yakin ingin menghapus semua alamat IP yang direkam dari proyek ini?\n"
|
||||||
|
" Sisa riwayat proyek tidak akan terpengaruh. Tindakan ini "
|
||||||
|
"tidak bisa dibatalkan."
|
||||||
|
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr ""
|
msgstr "Tutup"
|
||||||
|
|
||||||
msgid "Confirm Delete"
|
msgid "Confirm Delete"
|
||||||
msgstr ""
|
msgstr "Konfirmasi Hapus"
|
||||||
|
|
||||||
msgid "Delete Confirmation"
|
msgid "Delete Confirmation"
|
||||||
msgstr ""
|
msgstr "Hapus Konfirmasi"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure you want to erase all history for this project? This action "
|
"Are you sure you want to erase all history for this project? This action "
|
||||||
"cannot be undone."
|
"cannot be undone."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Anda yakin ingin menghapus semua riwayat untuk proyek ini? Tindakan ini "
|
||||||
|
"tidak bisa dibatalkan."
|
||||||
|
|
||||||
msgid "Added"
|
msgid "Added"
|
||||||
msgstr ""
|
msgstr "Ditambahkan"
|
||||||
|
|
||||||
msgid "Removed"
|
msgid "Removed"
|
||||||
msgstr ""
|
msgstr "Dihapus"
|
||||||
|
|
||||||
msgid "and"
|
msgid "and"
|
||||||
msgstr ""
|
msgstr "dan"
|
||||||
|
|
||||||
msgid "owers list"
|
msgid "owers list"
|
||||||
msgstr ""
|
msgstr "daftar owers"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
|
@ -454,6 +465,12 @@ msgid ""
|
||||||
" <a href=\"%(url)s\">settings page</a>\n"
|
" <a href=\"%(url)s\">settings page</a>\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"\n"
|
||||||
|
" <i> Proyek ini memiliki riwayat yang dinonaktifkan. Tindakan "
|
||||||
|
"baru tidak akan muncul di bawah ini. Anda dapat mengaktifkan riwayat pada</i>"
|
||||||
|
"\n"
|
||||||
|
" <a href=\"%(url)s\">halaman pengaturan</a>\n"
|
||||||
|
" "
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
|
|
Binary file not shown.
|
@ -3,8 +3,8 @@ 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: 2020-05-30 21:50+0200\n"
|
"POT-Creation-Date: 2020-05-30 21:50+0200\n"
|
||||||
"PO-Revision-Date: 2020-10-26 19:27+0000\n"
|
"PO-Revision-Date: 2021-03-17 15:18+0000\n"
|
||||||
"Last-Translator: Sylphystia <yuidirnt@gmail.com>\n"
|
"Last-Translator: TomSolGit <Tommaso.solfa@gmail.com>\n"
|
||||||
"Language-Team: Italian <https://hosted.weblate.org/projects/i-hate-money/"
|
"Language-Team: Italian <https://hosted.weblate.org/projects/i-hate-money/"
|
||||||
"i-hate-money/it/>\n"
|
"i-hate-money/it/>\n"
|
||||||
"Language: it\n"
|
"Language: it\n"
|
||||||
|
@ -12,7 +12,7 @@ msgstr ""
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 4.3.2-dev\n"
|
"X-Generator: Weblate 4.5.2-dev\n"
|
||||||
"Generated-By: Babel 2.8.0\n"
|
"Generated-By: Babel 2.8.0\n"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
|
@ -40,7 +40,7 @@ msgid "Default Currency"
|
||||||
msgstr "Valuta predefinita"
|
msgstr "Valuta predefinita"
|
||||||
|
|
||||||
msgid "Import previously exported JSON file"
|
msgid "Import previously exported JSON file"
|
||||||
msgstr "Importare il file esportato JSON"
|
msgstr "Importare il file JSON esportato precedentemente"
|
||||||
|
|
||||||
msgid "Import"
|
msgid "Import"
|
||||||
msgstr "Importare"
|
msgstr "Importare"
|
||||||
|
@ -49,7 +49,7 @@ msgid "Project identifier"
|
||||||
msgstr "Identificatore del progetto"
|
msgstr "Identificatore del progetto"
|
||||||
|
|
||||||
msgid "Create the project"
|
msgid "Create the project"
|
||||||
msgstr "Creare il progetto"
|
msgstr "Crea il progetto"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
|
@ -57,13 +57,13 @@ msgid ""
|
||||||
"choose a new identifier"
|
"choose a new identifier"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Un progetto con questo identificatore (\"%(project)s\") esiste già. Per "
|
"Un progetto con questo identificatore (\"%(project)s\") esiste già. Per "
|
||||||
"favore scegliere un identificatore nuovo"
|
"favore scegli un identificatore nuovo"
|
||||||
|
|
||||||
msgid "Get in"
|
msgid "Get in"
|
||||||
msgstr "Entra"
|
msgstr "Entra"
|
||||||
|
|
||||||
msgid "Admin password"
|
msgid "Admin password"
|
||||||
msgstr "Password di amministrazione"
|
msgstr "Password dell'amministratore"
|
||||||
|
|
||||||
msgid "Send me the code by email"
|
msgid "Send me the code by email"
|
||||||
msgstr "Inviami il codice per email"
|
msgstr "Inviami il codice per email"
|
||||||
|
@ -102,7 +102,7 @@ msgid "External link"
|
||||||
msgstr "Link esterno"
|
msgstr "Link esterno"
|
||||||
|
|
||||||
msgid "A link to an external document, related to this bill"
|
msgid "A link to an external document, related to this bill"
|
||||||
msgstr "Un link a un documento esterno in relazione a questa spesa"
|
msgstr "Un link ad un documento esterno, relativo a questa spesa"
|
||||||
|
|
||||||
msgid "For whom?"
|
msgid "For whom?"
|
||||||
msgstr "Per chi?"
|
msgstr "Per chi?"
|
||||||
|
@ -111,7 +111,7 @@ msgid "Submit"
|
||||||
msgstr "Invia"
|
msgstr "Invia"
|
||||||
|
|
||||||
msgid "Submit and add a new one"
|
msgid "Submit and add a new one"
|
||||||
msgstr "Inviare e aggiungerne uno nuovo"
|
msgstr "Invia ed aggiungine uno nuovo"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Project default: %(currency)s"
|
msgid "Project default: %(currency)s"
|
||||||
|
@ -124,7 +124,7 @@ msgid "Name"
|
||||||
msgstr "Nome"
|
msgstr "Nome"
|
||||||
|
|
||||||
msgid "Weights should be positive"
|
msgid "Weights should be positive"
|
||||||
msgstr "Il peso deve essere positivo"
|
msgstr "I pesi dovrebbero essere positivi"
|
||||||
|
|
||||||
msgid "Weight"
|
msgid "Weight"
|
||||||
msgstr "Peso"
|
msgstr "Peso"
|
||||||
|
@ -139,10 +139,10 @@ msgid "This project already have this member"
|
||||||
msgstr "Membro già presente in questo progetto"
|
msgstr "Membro già presente in questo progetto"
|
||||||
|
|
||||||
msgid "People to notify"
|
msgid "People to notify"
|
||||||
msgstr "Persone da notificare"
|
msgstr "Persone da informare"
|
||||||
|
|
||||||
msgid "Send invites"
|
msgid "Send invites"
|
||||||
msgstr "Spedisci inviti"
|
msgstr "Invia inviti"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The email %(email)s is not valid"
|
msgid "The email %(email)s is not valid"
|
||||||
|
@ -166,8 +166,8 @@ msgstr "Troppi tentativi di accesso non riusciti. Riprova più tardi."
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "This admin password is not the right one. Only %(num)d attempts left."
|
msgid "This admin password is not the right one. Only %(num)d attempts left."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Questa password di amministrazione non è corretta. Solo %(num)d tentativi"
|
"Questa password di amministrazione non è quella corretta. Solo %(num)d "
|
||||||
" rimasti."
|
"tentativi rimasti."
|
||||||
|
|
||||||
msgid "You either provided a bad token or no project identifier."
|
msgid "You either provided a bad token or no project identifier."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
Binary file not shown.
|
@ -3,7 +3,7 @@ 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: 2020-10-22 06:40+0200\n"
|
"POT-Creation-Date: 2020-10-22 06:40+0200\n"
|
||||||
"PO-Revision-Date: 2020-11-04 17:27+0000\n"
|
"PO-Revision-Date: 2020-11-11 16:28+0000\n"
|
||||||
"Last-Translator: Jwen921 <yangjingwen0921@gmail.com>\n"
|
"Last-Translator: Jwen921 <yangjingwen0921@gmail.com>\n"
|
||||||
"Language-Team: Japanese <https://hosted.weblate.org/projects/i-hate-money/"
|
"Language-Team: Japanese <https://hosted.weblate.org/projects/i-hate-money/"
|
||||||
"i-hate-money/ja/>\n"
|
"i-hate-money/ja/>\n"
|
||||||
|
@ -12,7 +12,7 @@ msgstr ""
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
"X-Generator: Weblate 4.3.2-dev\n"
|
"X-Generator: Weblate 4.4-dev\n"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Not a valid amount or expression. Only numbers and + - * / operators are "
|
"Not a valid amount or expression. Only numbers and + - * / operators are "
|
||||||
|
@ -129,282 +129,283 @@ msgid "Add"
|
||||||
msgstr "追加"
|
msgstr "追加"
|
||||||
|
|
||||||
msgid "User name incorrect"
|
msgid "User name incorrect"
|
||||||
msgstr ""
|
msgstr "ユーザー名が正しくない"
|
||||||
|
|
||||||
msgid "This project already have this member"
|
msgid "This project already have this member"
|
||||||
msgstr ""
|
msgstr "プロジェクトはすでにこのメンバーを含めています"
|
||||||
|
|
||||||
msgid "People to notify"
|
msgid "People to notify"
|
||||||
msgstr ""
|
msgstr "知らせたい人"
|
||||||
|
|
||||||
msgid "Send invites"
|
msgid "Send invites"
|
||||||
msgstr ""
|
msgstr "招待状を出す"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The email %(email)s is not valid"
|
msgid "The email %(email)s is not valid"
|
||||||
msgstr ""
|
msgstr "メールアドレス%(email)sは無効"
|
||||||
|
|
||||||
msgid "Participant"
|
msgid "Participant"
|
||||||
msgstr ""
|
msgstr "参加者"
|
||||||
|
|
||||||
msgid "Bill"
|
msgid "Bill"
|
||||||
msgstr ""
|
msgstr "明細"
|
||||||
|
|
||||||
msgid "Project"
|
msgid "Project"
|
||||||
msgstr ""
|
msgstr "プロジェクト"
|
||||||
|
|
||||||
msgid "No Currency"
|
msgid "No Currency"
|
||||||
msgstr ""
|
msgstr "通貨なし"
|
||||||
|
|
||||||
msgid "Too many failed login attempts, please retry later."
|
msgid "Too many failed login attempts, please retry later."
|
||||||
msgstr ""
|
msgstr "何度もログインに失敗したので、時間をおいてから再度ログインして下さい。"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "This admin password is not the right one. Only %(num)d attempts left."
|
msgid "This admin password is not the right one. Only %(num)d attempts left."
|
||||||
msgstr ""
|
msgstr "この管理者パスワードは正しくないでウ。%(num)d試行しか残っていません。"
|
||||||
|
|
||||||
msgid "You either provided a bad token or no project identifier."
|
msgid "You either provided a bad token or no project identifier."
|
||||||
msgstr ""
|
msgstr "無効な入力かプロジェクト名なし。"
|
||||||
|
|
||||||
msgid "This private code is not the right one"
|
msgid "This private code is not the right one"
|
||||||
msgstr ""
|
msgstr "私用コードは正しくない"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "You have just created '%(project)s' to share your expenses"
|
msgid "You have just created '%(project)s' to share your expenses"
|
||||||
msgstr ""
|
msgstr "費用を共有するため、%(project)sが作られました"
|
||||||
|
|
||||||
msgid "A reminder email has just been sent to you"
|
msgid "A reminder email has just been sent to you"
|
||||||
msgstr ""
|
msgstr "催促メールがただいまあなたに送りました"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"We tried to send you an reminder email, but there was an error. You can "
|
"We tried to send you an reminder email, but there was an error. You can "
|
||||||
"still use the project normally."
|
"still use the project normally."
|
||||||
msgstr ""
|
msgstr "催促メールを送った時、エラーが発生しました。このプロジェクトはまだ使えます。"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The project identifier is %(project)s"
|
msgid "The project identifier is %(project)s"
|
||||||
msgstr ""
|
msgstr "プロジェクト名は%(project)s"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Sorry, there was an error while sending you an email with password reset "
|
"Sorry, there was an error while sending you an email with password reset "
|
||||||
"instructions. Please check the email configuration of the server or "
|
"instructions. Please check the email configuration of the server or "
|
||||||
"contact the administrator."
|
"contact the administrator."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"申し訳ございませんが、パスワード再設定の説明メールを送った時、エラーが発生しました。メールアドレスを一度確認してまたは管理者に連絡してください。"
|
||||||
|
|
||||||
msgid "No token provided"
|
msgid "No token provided"
|
||||||
msgstr ""
|
msgstr "印が入力されていない"
|
||||||
|
|
||||||
msgid "Invalid token"
|
msgid "Invalid token"
|
||||||
msgstr ""
|
msgstr "無効な印"
|
||||||
|
|
||||||
msgid "Unknown project"
|
msgid "Unknown project"
|
||||||
msgstr ""
|
msgstr "未知のプロジェクト"
|
||||||
|
|
||||||
msgid "Password successfully reset."
|
msgid "Password successfully reset."
|
||||||
msgstr ""
|
msgstr "パスワードを再設定できました。"
|
||||||
|
|
||||||
msgid "Project successfully uploaded"
|
msgid "Project successfully uploaded"
|
||||||
msgstr ""
|
msgstr "プロジェクトをアップロードできました"
|
||||||
|
|
||||||
msgid "Invalid JSON"
|
msgid "Invalid JSON"
|
||||||
msgstr ""
|
msgstr "無効なJSON"
|
||||||
|
|
||||||
msgid "Project successfully deleted"
|
msgid "Project successfully deleted"
|
||||||
msgstr ""
|
msgstr "プロジェクトを削除できました"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "You have been invited to share your expenses for %(project)s"
|
msgid "You have been invited to share your expenses for %(project)s"
|
||||||
msgstr ""
|
msgstr "%(project)sの費用を共有すると、あなたが誘われた"
|
||||||
|
|
||||||
msgid "Your invitations have been sent"
|
msgid "Your invitations have been sent"
|
||||||
msgstr ""
|
msgstr "あなたの招待状が送られました"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Sorry, there was an error while trying to send the invitation emails. "
|
"Sorry, there was an error while trying to send the invitation emails. "
|
||||||
"Please check the email configuration of the server or contact the "
|
"Please check the email configuration of the server or contact the "
|
||||||
"administrator."
|
"administrator."
|
||||||
msgstr ""
|
msgstr "申し訳ございませんが、招待メールを送ったとき、エラーが発生しました。メールアドレスを再度チェックするかまたは管理者に連絡ください。"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(member)s has been added"
|
msgid "%(member)s has been added"
|
||||||
msgstr ""
|
msgstr "%(member)sが追加されました"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(name)s is part of this project again"
|
msgid "%(name)s is part of this project again"
|
||||||
msgstr ""
|
msgstr "%(name)sはまたこのプロジェクトの一部になりました"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"User '%(name)s' has been deactivated. It will still appear in the users "
|
"User '%(name)s' has been deactivated. It will still appear in the users "
|
||||||
"list until its balance becomes zero."
|
"list until its balance becomes zero."
|
||||||
msgstr ""
|
msgstr "ユーザー%(name)sが無効にされました。このユーザーは残高がゼロになるまでリストに出ています。"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "User '%(name)s' has been removed"
|
msgid "User '%(name)s' has been removed"
|
||||||
msgstr ""
|
msgstr "ユーザー%(name)sが既に取り除かれました"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "User '%(name)s' has been edited"
|
msgid "User '%(name)s' has been edited"
|
||||||
msgstr ""
|
msgstr "ユーザー%(name)sが既に編集されました"
|
||||||
|
|
||||||
msgid "The bill has been added"
|
msgid "The bill has been added"
|
||||||
msgstr ""
|
msgstr "明細が追加されました"
|
||||||
|
|
||||||
msgid "The bill has been deleted"
|
msgid "The bill has been deleted"
|
||||||
msgstr ""
|
msgstr "明細が削除されました"
|
||||||
|
|
||||||
msgid "The bill has been modified"
|
msgid "The bill has been modified"
|
||||||
msgstr ""
|
msgstr "明細が変更されました"
|
||||||
|
|
||||||
msgid "Sorry, we were unable to find the page you've asked for."
|
msgid "Sorry, we were unable to find the page you've asked for."
|
||||||
msgstr ""
|
msgstr "申し訳ございませんが、求められるページが見つかりませんでした。"
|
||||||
|
|
||||||
msgid "The best thing to do is probably to get back to the main page."
|
msgid "The best thing to do is probably to get back to the main page."
|
||||||
msgstr ""
|
msgstr "メーンページに戻ったほうがいいかもしれません。"
|
||||||
|
|
||||||
msgid "Back to the list"
|
msgid "Back to the list"
|
||||||
msgstr ""
|
msgstr "リストに戻る"
|
||||||
|
|
||||||
msgid "Administration tasks are currently disabled."
|
msgid "Administration tasks are currently disabled."
|
||||||
msgstr ""
|
msgstr "現在管理者タスクが操作できません。"
|
||||||
|
|
||||||
msgid "The project you are trying to access do not exist, do you want to"
|
msgid "The project you are trying to access do not exist, do you want to"
|
||||||
msgstr ""
|
msgstr "アクセスしたいプロジェクトは存在していなくて、…したいですか"
|
||||||
|
|
||||||
msgid "create it"
|
msgid "create it"
|
||||||
msgstr ""
|
msgstr "作る"
|
||||||
|
|
||||||
msgid "?"
|
msgid "?"
|
||||||
msgstr ""
|
msgstr "?"
|
||||||
|
|
||||||
msgid "Create a new project"
|
msgid "Create a new project"
|
||||||
msgstr ""
|
msgstr "プロジェクトを新規作成する"
|
||||||
|
|
||||||
msgid "Number of members"
|
msgid "Number of members"
|
||||||
msgstr ""
|
msgstr "メンバー数"
|
||||||
|
|
||||||
msgid "Number of bills"
|
msgid "Number of bills"
|
||||||
msgstr ""
|
msgstr "明細書数"
|
||||||
|
|
||||||
msgid "Newest bill"
|
msgid "Newest bill"
|
||||||
msgstr ""
|
msgstr "最新の明細"
|
||||||
|
|
||||||
msgid "Oldest bill"
|
msgid "Oldest bill"
|
||||||
msgstr ""
|
msgstr "一番古い明細"
|
||||||
|
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr ""
|
msgstr "操作"
|
||||||
|
|
||||||
msgid "edit"
|
msgid "edit"
|
||||||
msgstr ""
|
msgstr "編集"
|
||||||
|
|
||||||
msgid "delete"
|
msgid "delete"
|
||||||
msgstr ""
|
msgstr "削除"
|
||||||
|
|
||||||
msgid "show"
|
msgid "show"
|
||||||
msgstr ""
|
msgstr "表示"
|
||||||
|
|
||||||
msgid "The Dashboard is currently deactivated."
|
msgid "The Dashboard is currently deactivated."
|
||||||
msgstr ""
|
msgstr "現在ダッシュボードは操作できません。"
|
||||||
|
|
||||||
msgid "you sure?"
|
msgid "you sure?"
|
||||||
msgstr ""
|
msgstr "確認?"
|
||||||
|
|
||||||
msgid "Edit project"
|
msgid "Edit project"
|
||||||
msgstr ""
|
msgstr "プロジェクトを編集する"
|
||||||
|
|
||||||
msgid "Import JSON"
|
msgid "Import JSON"
|
||||||
msgstr ""
|
msgstr "JSONを導入する"
|
||||||
|
|
||||||
msgid "Choose file"
|
msgid "Choose file"
|
||||||
msgstr ""
|
msgstr "ファイルを選択する"
|
||||||
|
|
||||||
msgid "Download project's data"
|
msgid "Download project's data"
|
||||||
msgstr ""
|
msgstr "プロジェクトのデータをダウンロードする"
|
||||||
|
|
||||||
msgid "Bill items"
|
msgid "Bill items"
|
||||||
msgstr ""
|
msgstr "明細項目"
|
||||||
|
|
||||||
msgid "Download the list of bills with owner, amount, reason,... "
|
msgid "Download the list of bills with owner, amount, reason,... "
|
||||||
msgstr ""
|
msgstr "所有者や金額、理由などの情報を含む明細リストをダウンロードする "
|
||||||
|
|
||||||
msgid "Settle plans"
|
msgid "Settle plans"
|
||||||
msgstr ""
|
msgstr "解決計画"
|
||||||
|
|
||||||
msgid "Download the list of transactions needed to settle the current bills."
|
msgid "Download the list of transactions needed to settle the current bills."
|
||||||
msgstr ""
|
msgstr "この明細に必要な取引リストをダウンロードします。"
|
||||||
|
|
||||||
msgid "Can't remember the password?"
|
msgid "Can't remember the password?"
|
||||||
msgstr ""
|
msgstr "パスワードを覚えていないです?"
|
||||||
|
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr ""
|
msgstr "キャンセル"
|
||||||
|
|
||||||
msgid "Privacy Settings"
|
msgid "Privacy Settings"
|
||||||
msgstr ""
|
msgstr "プライバシーの設定"
|
||||||
|
|
||||||
msgid "Edit the project"
|
msgid "Edit the project"
|
||||||
msgstr ""
|
msgstr "プロジェクトを編集する"
|
||||||
|
|
||||||
msgid "Edit this bill"
|
msgid "Edit this bill"
|
||||||
msgstr ""
|
msgstr "明細を編集する"
|
||||||
|
|
||||||
msgid "Add a bill"
|
msgid "Add a bill"
|
||||||
msgstr ""
|
msgstr "新しい明細書を追加する"
|
||||||
|
|
||||||
msgid "Select all"
|
msgid "Select all"
|
||||||
msgstr ""
|
msgstr "全て選択"
|
||||||
|
|
||||||
msgid "Select none"
|
msgid "Select none"
|
||||||
msgstr ""
|
msgstr "選択解除"
|
||||||
|
|
||||||
msgid "Add participant"
|
msgid "Add participant"
|
||||||
msgstr ""
|
msgstr "参加者を追加する"
|
||||||
|
|
||||||
msgid "Edit this member"
|
msgid "Edit this member"
|
||||||
msgstr ""
|
msgstr "このメンバーを編集する"
|
||||||
|
|
||||||
msgid "john.doe@example.com, mary.moe@site.com"
|
msgid "john.doe@example.com, mary.moe@site.com"
|
||||||
msgstr ""
|
msgstr "john.doe@example.com, mary.moe@site.com"
|
||||||
|
|
||||||
msgid "Send the invitations"
|
msgid "Send the invitations"
|
||||||
msgstr ""
|
msgstr "招待状を送る"
|
||||||
|
|
||||||
msgid "Download"
|
msgid "Download"
|
||||||
msgstr ""
|
msgstr "ダウンロードする"
|
||||||
|
|
||||||
msgid "Disabled Project History"
|
msgid "Disabled Project History"
|
||||||
msgstr ""
|
msgstr "操作できないプロジェクト歴史"
|
||||||
|
|
||||||
msgid "Disabled Project History & IP Address Recording"
|
msgid "Disabled Project History & IP Address Recording"
|
||||||
msgstr ""
|
msgstr "操作できないプロジェクトの歴史&IPアドレス記録"
|
||||||
|
|
||||||
msgid "Enabled Project History"
|
msgid "Enabled Project History"
|
||||||
msgstr ""
|
msgstr "操作可能なプロジェクト歴史"
|
||||||
|
|
||||||
msgid "Disabled IP Address Recording"
|
msgid "Disabled IP Address Recording"
|
||||||
msgstr ""
|
msgstr "操作できないIPアドレス記録"
|
||||||
|
|
||||||
msgid "Enabled Project History & IP Address Recording"
|
msgid "Enabled Project History & IP Address Recording"
|
||||||
msgstr ""
|
msgstr "操作可能なプロジェクト歴史&IPアドレス記録"
|
||||||
|
|
||||||
msgid "Enabled IP Address Recording"
|
msgid "Enabled IP Address Recording"
|
||||||
msgstr ""
|
msgstr "操作可能なIPアドレス記録"
|
||||||
|
|
||||||
msgid "History Settings Changed"
|
msgid "History Settings Changed"
|
||||||
msgstr ""
|
msgstr "歴史設定が変更された"
|
||||||
|
|
||||||
msgid "changed"
|
msgid "changed"
|
||||||
msgstr ""
|
msgstr "変更された"
|
||||||
|
|
||||||
msgid "from"
|
msgid "from"
|
||||||
msgstr ""
|
msgstr "から"
|
||||||
|
|
||||||
msgid "to"
|
msgid "to"
|
||||||
msgstr ""
|
msgstr "まで"
|
||||||
|
|
||||||
msgid "Confirm Remove IP Adresses"
|
msgid "Confirm Remove IP Adresses"
|
||||||
msgstr ""
|
msgstr "IPアドレスの取り除きを確認する"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure you want to delete all recorded IP addresses from this "
|
"Are you sure you want to delete all recorded IP addresses from this "
|
||||||
|
@ -412,32 +413,34 @@ msgid ""
|
||||||
" The rest of the project history will be unaffected. This "
|
" The rest of the project history will be unaffected. This "
|
||||||
"action cannot be undone."
|
"action cannot be undone."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"本当にこのプロジェクトから記録されたIPアドレスを全部削除したいですか。\n"
|
||||||
|
"残りのプロジェクト歴史が影響されていません。この操作は元に戻せません。"
|
||||||
|
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr ""
|
msgstr "閉じる"
|
||||||
|
|
||||||
msgid "Confirm Delete"
|
msgid "Confirm Delete"
|
||||||
msgstr ""
|
msgstr "削除を確認する"
|
||||||
|
|
||||||
msgid "Delete Confirmation"
|
msgid "Delete Confirmation"
|
||||||
msgstr ""
|
msgstr "確認を削除する"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure you want to erase all history for this project? This action "
|
"Are you sure you want to erase all history for this project? This action "
|
||||||
"cannot be undone."
|
"cannot be undone."
|
||||||
msgstr ""
|
msgstr "本当にこのプロジェクトの歴史をすべて消しますか。この操作は元に戻せません。"
|
||||||
|
|
||||||
msgid "Added"
|
msgid "Added"
|
||||||
msgstr ""
|
msgstr "追加された"
|
||||||
|
|
||||||
msgid "Removed"
|
msgid "Removed"
|
||||||
msgstr ""
|
msgstr "取り除かれた"
|
||||||
|
|
||||||
msgid "and"
|
msgid "and"
|
||||||
msgstr ""
|
msgstr "と"
|
||||||
|
|
||||||
msgid "owers list"
|
msgid "owers list"
|
||||||
msgstr ""
|
msgstr "全員リスト"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
|
@ -447,6 +450,10 @@ msgid ""
|
||||||
" <a href=\"%(url)s\">settings page</a>\n"
|
" <a href=\"%(url)s\">settings page</a>\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"\n"
|
||||||
|
" <i>このプロジェクトの歴史は操作できません。新しい操作は下に出ません。</i>で歴史を操作可能にすることができます。\n"
|
||||||
|
"<a href=\"%(url)s\">設定ページ</a>\n"
|
||||||
|
" "
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
|
@ -457,279 +464,284 @@ msgid ""
|
||||||
"them.</i></p>\n"
|
"them.</i></p>\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"\n"
|
||||||
|
" <i>下の表では操作不可になる前に、プロジェクトの歴史に対して記録された操作が反映されています。…できます。\n"
|
||||||
|
"<a href=\"#\" data-toggle=\"modal\" data-keyboard=\"false\" data-target"
|
||||||
|
"=\"#confirm-erase\">プロジェクトの歴史を取り除く</a> で取り除きます.</i></p>\n"
|
||||||
|
" "
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Some entries below contain IP addresses, even though this project has IP "
|
"Some entries below contain IP addresses, even though this project has IP "
|
||||||
"recording disabled. "
|
"recording disabled. "
|
||||||
msgstr ""
|
msgstr "このプロジェクトのIP記録が操作できない一方、下の入り口の一部がIPアドレスを含めています。 "
|
||||||
|
|
||||||
msgid "Delete stored IP addresses"
|
msgid "Delete stored IP addresses"
|
||||||
msgstr ""
|
msgstr "保存されたIPアドレスを削除する"
|
||||||
|
|
||||||
msgid "No history to erase"
|
msgid "No history to erase"
|
||||||
msgstr ""
|
msgstr "削除できる歴史はない"
|
||||||
|
|
||||||
msgid "Clear Project History"
|
msgid "Clear Project History"
|
||||||
msgstr ""
|
msgstr "プロジェクトの歴史を取り除く"
|
||||||
|
|
||||||
msgid "No IP Addresses to erase"
|
msgid "No IP Addresses to erase"
|
||||||
msgstr ""
|
msgstr "削除できるIPアドレスはない"
|
||||||
|
|
||||||
msgid "Delete Stored IP Addresses"
|
msgid "Delete Stored IP Addresses"
|
||||||
msgstr ""
|
msgstr "保存されたIPアドレスを削除する"
|
||||||
|
|
||||||
msgid "Time"
|
msgid "Time"
|
||||||
msgstr ""
|
msgstr "時間"
|
||||||
|
|
||||||
msgid "Event"
|
msgid "Event"
|
||||||
msgstr ""
|
msgstr "イベント"
|
||||||
|
|
||||||
msgid "IP address recording can be enabled on the settings page"
|
msgid "IP address recording can be enabled on the settings page"
|
||||||
msgstr ""
|
msgstr "設定ページでIPアドレス記録を編集可能にすることができる"
|
||||||
|
|
||||||
msgid "IP address recording can be disabled on the settings page"
|
msgid "IP address recording can be disabled on the settings page"
|
||||||
msgstr ""
|
msgstr "設定ページでIPアドレス記録を編集不可にすることができる"
|
||||||
|
|
||||||
msgid "From IP"
|
msgid "From IP"
|
||||||
msgstr ""
|
msgstr "IPから"
|
||||||
|
|
||||||
msgid "added"
|
msgid "added"
|
||||||
msgstr ""
|
msgstr "追加された"
|
||||||
|
|
||||||
msgid "Project private code changed"
|
msgid "Project private code changed"
|
||||||
msgstr ""
|
msgstr "プロジェクトの私用コードが変更された"
|
||||||
|
|
||||||
msgid "Project renamed to"
|
msgid "Project renamed to"
|
||||||
msgstr ""
|
msgstr "プロジェクト名が…に変更された"
|
||||||
|
|
||||||
msgid "Project contact email changed to"
|
msgid "Project contact email changed to"
|
||||||
msgstr ""
|
msgstr "プロジェクトの連絡メールが…に変更された"
|
||||||
|
|
||||||
msgid "Project settings modified"
|
msgid "Project settings modified"
|
||||||
msgstr ""
|
msgstr "プロジェクトの設定が修正された"
|
||||||
|
|
||||||
msgid "deactivated"
|
msgid "deactivated"
|
||||||
msgstr ""
|
msgstr "操作不可にされた"
|
||||||
|
|
||||||
msgid "reactivated"
|
msgid "reactivated"
|
||||||
msgstr ""
|
msgstr "再び変更可能にされた"
|
||||||
|
|
||||||
msgid "renamed to"
|
msgid "renamed to"
|
||||||
msgstr ""
|
msgstr "…という名前に変更された"
|
||||||
|
|
||||||
msgid "External link changed to"
|
msgid "External link changed to"
|
||||||
msgstr ""
|
msgstr "外部リンクが…に変更された"
|
||||||
|
|
||||||
msgid "Amount"
|
msgid "Amount"
|
||||||
msgstr ""
|
msgstr "金額"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Amount in %(currency)s"
|
msgid "Amount in %(currency)s"
|
||||||
msgstr ""
|
msgstr "%(currency)sでの金額"
|
||||||
|
|
||||||
msgid "modified"
|
msgid "modified"
|
||||||
msgstr ""
|
msgstr "修正された"
|
||||||
|
|
||||||
msgid "removed"
|
msgid "removed"
|
||||||
msgstr ""
|
msgstr "取り除かれた"
|
||||||
|
|
||||||
msgid "changed in a unknown way"
|
msgid "changed in a unknown way"
|
||||||
msgstr ""
|
msgstr "未知の方法で変更された"
|
||||||
|
|
||||||
msgid "Nothing to list"
|
msgid "Nothing to list"
|
||||||
msgstr ""
|
msgstr "表示できるものがない"
|
||||||
|
|
||||||
msgid "Someone probably cleared the project history."
|
msgid "Someone probably cleared the project history."
|
||||||
msgstr ""
|
msgstr "プロジェクトの歴史が誰かに取り除かれたかもしれません。"
|
||||||
|
|
||||||
msgid "Manage your shared <br />expenses, easily"
|
msgid "Manage your shared <br />expenses, easily"
|
||||||
msgstr ""
|
msgstr "あなたが共有した<br />費用を簡単に管理する"
|
||||||
|
|
||||||
msgid "Try out the demo"
|
msgid "Try out the demo"
|
||||||
msgstr ""
|
msgstr "デモを試す"
|
||||||
|
|
||||||
msgid "You're sharing a house?"
|
msgid "You're sharing a house?"
|
||||||
msgstr ""
|
msgstr "誰かと家を共有していますか?"
|
||||||
|
|
||||||
msgid "Going on holidays with friends?"
|
msgid "Going on holidays with friends?"
|
||||||
msgstr ""
|
msgstr "友達と旅行していますか?"
|
||||||
|
|
||||||
msgid "Simply sharing money with others?"
|
msgid "Simply sharing money with others?"
|
||||||
msgstr ""
|
msgstr "ただ他人とお金を割り当てていますか?"
|
||||||
|
|
||||||
msgid "We can help!"
|
msgid "We can help!"
|
||||||
msgstr ""
|
msgstr "助けてあげます!"
|
||||||
|
|
||||||
msgid "Log in to an existing project"
|
msgid "Log in to an existing project"
|
||||||
msgstr ""
|
msgstr "存在するプロジェクトにログインする"
|
||||||
|
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr ""
|
msgstr "ログイン"
|
||||||
|
|
||||||
msgid "can't remember your password?"
|
msgid "can't remember your password?"
|
||||||
msgstr ""
|
msgstr "パスワードを忘れた?"
|
||||||
|
|
||||||
msgid "Create"
|
msgid "Create"
|
||||||
msgstr ""
|
msgstr "作る"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Don\\'t reuse a personal password. Choose a private code and send it to "
|
"Don\\'t reuse a personal password. Choose a private code and send it to "
|
||||||
"your friends"
|
"your friends"
|
||||||
msgstr ""
|
msgstr "自分のパスワードを再利用しないでください。私用コードを選んで、友達に送る"
|
||||||
|
|
||||||
msgid "Account manager"
|
msgid "Account manager"
|
||||||
msgstr ""
|
msgstr "アカウント管理者"
|
||||||
|
|
||||||
msgid "Bills"
|
msgid "Bills"
|
||||||
msgstr ""
|
msgstr "明細書"
|
||||||
|
|
||||||
msgid "Settle"
|
msgid "Settle"
|
||||||
msgstr ""
|
msgstr "解決"
|
||||||
|
|
||||||
msgid "Statistics"
|
msgid "Statistics"
|
||||||
msgstr ""
|
msgstr "統計"
|
||||||
|
|
||||||
msgid "History"
|
msgid "History"
|
||||||
msgstr ""
|
msgstr "歴史"
|
||||||
|
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr ""
|
msgstr "設定"
|
||||||
|
|
||||||
msgid "Languages"
|
msgid "Languages"
|
||||||
msgstr ""
|
msgstr "言語"
|
||||||
|
|
||||||
msgid "Projects"
|
msgid "Projects"
|
||||||
msgstr ""
|
msgstr "プロジェクト"
|
||||||
|
|
||||||
msgid "Start a new project"
|
msgid "Start a new project"
|
||||||
msgstr ""
|
msgstr "新しいプロジェクトを始める"
|
||||||
|
|
||||||
msgid "Other projects :"
|
msgid "Other projects :"
|
||||||
msgstr ""
|
msgstr "他のプロジェクト:"
|
||||||
|
|
||||||
msgid "switch to"
|
msgid "switch to"
|
||||||
msgstr ""
|
msgstr "…に切り替える"
|
||||||
|
|
||||||
msgid "Dashboard"
|
msgid "Dashboard"
|
||||||
msgstr ""
|
msgstr "ダッシュボード"
|
||||||
|
|
||||||
msgid "Logout"
|
msgid "Logout"
|
||||||
msgstr ""
|
msgstr "ログアウト"
|
||||||
|
|
||||||
msgid "Code"
|
msgid "Code"
|
||||||
msgstr ""
|
msgstr "コード"
|
||||||
|
|
||||||
msgid "Mobile Application"
|
msgid "Mobile Application"
|
||||||
msgstr ""
|
msgstr "携帯アプリ"
|
||||||
|
|
||||||
msgid "Documentation"
|
msgid "Documentation"
|
||||||
msgstr ""
|
msgstr "書類"
|
||||||
|
|
||||||
msgid "Administation Dashboard"
|
msgid "Administation Dashboard"
|
||||||
msgstr ""
|
msgstr "管理ダッシュボード"
|
||||||
|
|
||||||
msgid "\"I hate money\" is a free software"
|
msgid "\"I hate money\" is a free software"
|
||||||
msgstr ""
|
msgstr "\"I hate money\"は無料のソフトウェアです"
|
||||||
|
|
||||||
msgid "you can contribute and improve it!"
|
msgid "you can contribute and improve it!"
|
||||||
msgstr ""
|
msgstr "あなたは貢献して、向上させることができます!"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(amount)s each"
|
msgid "%(amount)s each"
|
||||||
msgstr ""
|
msgstr "各自に%(amount)s"
|
||||||
|
|
||||||
msgid "Invite people"
|
msgid "Invite people"
|
||||||
msgstr ""
|
msgstr "人を誘う"
|
||||||
|
|
||||||
msgid "You should start by adding participants"
|
msgid "You should start by adding participants"
|
||||||
msgstr ""
|
msgstr "参加者を追加して始めましょう"
|
||||||
|
|
||||||
msgid "Add a new bill"
|
msgid "Add a new bill"
|
||||||
msgstr ""
|
msgstr "新しい明細を追加する"
|
||||||
|
|
||||||
msgid "Newer bills"
|
msgid "Newer bills"
|
||||||
msgstr ""
|
msgstr "もっと新しい明細"
|
||||||
|
|
||||||
msgid "Older bills"
|
msgid "Older bills"
|
||||||
msgstr ""
|
msgstr "もっと古い明細"
|
||||||
|
|
||||||
msgid "When?"
|
msgid "When?"
|
||||||
msgstr ""
|
msgstr "いつ?"
|
||||||
|
|
||||||
msgid "Who paid?"
|
msgid "Who paid?"
|
||||||
msgstr ""
|
msgstr "誰が支払った?"
|
||||||
|
|
||||||
msgid "For what?"
|
msgid "For what?"
|
||||||
msgstr ""
|
msgstr "何のため?"
|
||||||
|
|
||||||
msgid "How much?"
|
msgid "How much?"
|
||||||
msgstr ""
|
msgstr "いくら?"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Added on %(date)s"
|
msgid "Added on %(date)s"
|
||||||
msgstr ""
|
msgstr "%(date)sに追加された"
|
||||||
|
|
||||||
msgid "Everyone"
|
msgid "Everyone"
|
||||||
msgstr ""
|
msgstr "皆"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Everyone but %(excluded)s"
|
msgid "Everyone but %(excluded)s"
|
||||||
msgstr ""
|
msgstr "%(excluded)s以外にみんな"
|
||||||
|
|
||||||
msgid "No bills"
|
msgid "No bills"
|
||||||
msgstr ""
|
msgstr "明細なし"
|
||||||
|
|
||||||
msgid "Nothing to list yet."
|
msgid "Nothing to list yet."
|
||||||
msgstr ""
|
msgstr "表示できるものはありません。"
|
||||||
|
|
||||||
msgid "You probably want to"
|
msgid "You probably want to"
|
||||||
msgstr ""
|
msgstr "…したいかもしれない"
|
||||||
|
|
||||||
msgid "add a bill"
|
msgid "add a bill"
|
||||||
msgstr ""
|
msgstr "明細を追加する"
|
||||||
|
|
||||||
msgid "add participants"
|
msgid "add participants"
|
||||||
msgstr ""
|
msgstr "参加者を追加する"
|
||||||
|
|
||||||
msgid "Password reminder"
|
msgid "Password reminder"
|
||||||
msgstr ""
|
msgstr "パスワードを思いさせる"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"A link to reset your password has been sent to you, please check your "
|
"A link to reset your password has been sent to you, please check your "
|
||||||
"emails."
|
"emails."
|
||||||
msgstr ""
|
msgstr "パスワードを再設定するリンクを送りました。メールをチェックしてください。"
|
||||||
|
|
||||||
msgid "Return to home page"
|
msgid "Return to home page"
|
||||||
msgstr ""
|
msgstr "ホームページに戻る"
|
||||||
|
|
||||||
msgid "Your projects"
|
msgid "Your projects"
|
||||||
msgstr ""
|
msgstr "あなたのプロジェクト"
|
||||||
|
|
||||||
msgid "Reset your password"
|
msgid "Reset your password"
|
||||||
msgstr ""
|
msgstr "パスワードを再設定する"
|
||||||
|
|
||||||
msgid "Invite people to join this project"
|
msgid "Invite people to join this project"
|
||||||
msgstr ""
|
msgstr "他人をこのプロジェクトに招待する"
|
||||||
|
|
||||||
msgid "Share Identifier & code"
|
msgid "Share Identifier & code"
|
||||||
msgstr ""
|
msgstr "名前とコードを共有する"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"You can share the project identifier and the private code by any "
|
"You can share the project identifier and the private code by any "
|
||||||
"communication means."
|
"communication means."
|
||||||
msgstr ""
|
msgstr "プロジェクト名と私用コードは何の方法でも共有できます。"
|
||||||
|
|
||||||
msgid "Identifier:"
|
msgid "Identifier:"
|
||||||
msgstr ""
|
msgstr "名前:"
|
||||||
|
|
||||||
msgid "Share the Link"
|
msgid "Share the Link"
|
||||||
msgstr ""
|
msgstr "リンクを共有する"
|
||||||
|
|
||||||
msgid "You can directly share the following link via your prefered medium"
|
msgid "You can directly share the following link via your prefered medium"
|
||||||
msgstr ""
|
msgstr "好きの手段で以下のリンクを直接に共有できる"
|
||||||
|
|
||||||
msgid "Send via Emails"
|
msgid "Send via Emails"
|
||||||
msgstr ""
|
msgstr "メールで送る"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Specify a (comma separated) list of email adresses you want to notify "
|
"Specify a (comma separated) list of email adresses you want to notify "
|
||||||
|
@ -737,33 +749,35 @@ msgid ""
|
||||||
" creation of this budget management project and we will "
|
" creation of this budget management project and we will "
|
||||||
"send them an email for you."
|
"send them an email for you."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"…を知らせたいメールアドレスのリストを特定する(カンマ区切り)\n"
|
||||||
|
"彼らにこの予算管理プロジェクトの作成をメールでお知らせします。"
|
||||||
|
|
||||||
msgid "Who pays?"
|
msgid "Who pays?"
|
||||||
msgstr ""
|
msgstr "誰が支払った?"
|
||||||
|
|
||||||
msgid "To whom?"
|
msgid "To whom?"
|
||||||
msgstr ""
|
msgstr "誰まで?"
|
||||||
|
|
||||||
msgid "Who?"
|
msgid "Who?"
|
||||||
msgstr ""
|
msgstr "誰?"
|
||||||
|
|
||||||
msgid "Balance"
|
msgid "Balance"
|
||||||
msgstr ""
|
msgstr "残高"
|
||||||
|
|
||||||
msgid "deactivate"
|
msgid "deactivate"
|
||||||
msgstr ""
|
msgstr "操作不可にする"
|
||||||
|
|
||||||
msgid "reactivate"
|
msgid "reactivate"
|
||||||
msgstr ""
|
msgstr "再び調査可能にする"
|
||||||
|
|
||||||
msgid "Paid"
|
msgid "Paid"
|
||||||
msgstr ""
|
msgstr "支払われた"
|
||||||
|
|
||||||
msgid "Spent"
|
msgid "Spent"
|
||||||
msgstr ""
|
msgstr "使われた"
|
||||||
|
|
||||||
msgid "Expenses by Month"
|
msgid "Expenses by Month"
|
||||||
msgstr ""
|
msgstr "月別の費用"
|
||||||
|
|
||||||
msgid "Period"
|
msgid "Period"
|
||||||
msgstr ""
|
msgstr "期間"
|
||||||
|
|
Binary file not shown.
|
@ -3,7 +3,7 @@ msgstr ""
|
||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
"POT-Creation-Date: 2020-05-30 21:50+0200\n"
|
"POT-Creation-Date: 2020-05-30 21:50+0200\n"
|
||||||
"PO-Revision-Date: 2020-09-06 15:36+0000\n"
|
"PO-Revision-Date: 2021-02-17 02:50+0000\n"
|
||||||
"Last-Translator: Sander Kooijmans <weblate@gogognome.nl>\n"
|
"Last-Translator: Sander Kooijmans <weblate@gogognome.nl>\n"
|
||||||
"Language-Team: Dutch <https://hosted.weblate.org/projects/i-hate-money/"
|
"Language-Team: Dutch <https://hosted.weblate.org/projects/i-hate-money/"
|
||||||
"i-hate-money/nl/>\n"
|
"i-hate-money/nl/>\n"
|
||||||
|
@ -12,13 +12,15 @@ msgstr ""
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 4.3-dev\n"
|
"X-Generator: Weblate 4.5\n"
|
||||||
"Generated-By: Babel 2.8.0\n"
|
"Generated-By: Babel 2.8.0\n"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Not a valid amount or expression. Only numbers and + - * / operators are "
|
"Not a valid amount or expression. Only numbers and + - * / operators are "
|
||||||
"accepted."
|
"accepted."
|
||||||
msgstr "Geen geldig bedrag of expressie. Gebruik alleen getallen en + - * /"
|
msgstr ""
|
||||||
|
"Geen geldig bedrag of expressie. Gebruik alleen getallen en + - * / "
|
||||||
|
"operatoren."
|
||||||
|
|
||||||
msgid "Project name"
|
msgid "Project name"
|
||||||
msgstr "Projectnaam"
|
msgstr "Projectnaam"
|
||||||
|
@ -54,7 +56,7 @@ msgstr "Project aanmaken"
|
||||||
msgid ""
|
msgid ""
|
||||||
"A project with this identifier (\"%(project)s\") already exists. Please "
|
"A project with this identifier (\"%(project)s\") already exists. Please "
|
||||||
"choose a new identifier"
|
"choose a new identifier"
|
||||||
msgstr "Er is al een project genaamd (\"%(project)s\"). Kies een andere naam."
|
msgstr "Er is al een project genaamd (\"%(project)s\"). Kies een andere naam"
|
||||||
|
|
||||||
msgid "Get in"
|
msgid "Get in"
|
||||||
msgstr "Inloggen"
|
msgstr "Inloggen"
|
||||||
|
@ -112,7 +114,7 @@ msgstr "Versturen en nieuwe toevoegen"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Project default: %(currency)s"
|
msgid "Project default: %(currency)s"
|
||||||
msgstr ""
|
msgstr "Projectstandaard: %(currency)s"
|
||||||
|
|
||||||
msgid "Bills can't be null"
|
msgid "Bills can't be null"
|
||||||
msgstr "Rekeningen mogen niet null zijn"
|
msgstr "Rekeningen mogen niet null zijn"
|
||||||
|
@ -177,22 +179,27 @@ msgstr ""
|
||||||
"verdelen"
|
"verdelen"
|
||||||
|
|
||||||
msgid "A reminder email has just been sent to you"
|
msgid "A reminder email has just been sent to you"
|
||||||
msgstr ""
|
msgstr "Een herinneringsmail is zojuist naar u verzonden"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"We tried to send you an reminder email, but there was an error. You can "
|
"We tried to send you an reminder email, but there was an error. You can "
|
||||||
"still use the project normally."
|
"still use the project normally."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"We hebben geprobeerd een herinneringsmail te versturen, maar er is iets fout "
|
||||||
|
"gegaan. Je kunt het project nog steeds normaal gebruiken."
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The project identifier is %(project)s"
|
msgid "The project identifier is %(project)s"
|
||||||
msgstr ""
|
msgstr "Het project-id is %(project)s"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Sorry, there was an error while sending you an email with password reset "
|
"Sorry, there was an error while sending you an email with password reset "
|
||||||
"instructions. Please check the email configuration of the server or "
|
"instructions. Please check the email configuration of the server or "
|
||||||
"contact the administrator."
|
"contact the administrator."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Sorry, er is iets fout gegaan bij het verzenden van een e-mail met "
|
||||||
|
"instructies om je wachtwoord te herstellen. Controleer de e-mailinstellingen "
|
||||||
|
"van de server of neem contact op met de beheerder."
|
||||||
|
|
||||||
msgid "No token provided"
|
msgid "No token provided"
|
||||||
msgstr "Geen toegangssleutel opgegeven"
|
msgstr "Geen toegangssleutel opgegeven"
|
||||||
|
@ -207,7 +214,7 @@ msgid "Password successfully reset."
|
||||||
msgstr "Wachtwoord is hersteld."
|
msgstr "Wachtwoord is hersteld."
|
||||||
|
|
||||||
msgid "Project successfully uploaded"
|
msgid "Project successfully uploaded"
|
||||||
msgstr ""
|
msgstr "Project succesvol geüpload"
|
||||||
|
|
||||||
msgid "Invalid JSON"
|
msgid "Invalid JSON"
|
||||||
msgstr "Ongeldige JSON"
|
msgstr "Ongeldige JSON"
|
||||||
|
@ -227,6 +234,9 @@ msgid ""
|
||||||
"Please check the email configuration of the server or contact the "
|
"Please check the email configuration of the server or contact the "
|
||||||
"administrator."
|
"administrator."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Sorry, er is iets fout gegaan bij het verzenden van de uitnodigingsmails. "
|
||||||
|
"Controleer de e-mailinstellingen van de server of neem contact op met de "
|
||||||
|
"beheerder."
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(member)s has been added"
|
msgid "%(member)s has been added"
|
||||||
|
@ -342,13 +352,13 @@ msgstr ""
|
||||||
" te schikken."
|
" te schikken."
|
||||||
|
|
||||||
msgid "Can't remember the password?"
|
msgid "Can't remember the password?"
|
||||||
msgstr "Ben je je wachtwoord vergeten?"
|
msgstr "Wachtwoord vergeten?"
|
||||||
|
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Annuleren"
|
msgstr "Annuleren"
|
||||||
|
|
||||||
msgid "Privacy Settings"
|
msgid "Privacy Settings"
|
||||||
msgstr ""
|
msgstr "Privacy-instellingen"
|
||||||
|
|
||||||
msgid "Edit the project"
|
msgid "Edit the project"
|
||||||
msgstr "Project bewerken"
|
msgstr "Project bewerken"
|
||||||
|
@ -381,13 +391,13 @@ msgid "Download"
|
||||||
msgstr "Downloaden"
|
msgstr "Downloaden"
|
||||||
|
|
||||||
msgid "Disabled Project History"
|
msgid "Disabled Project History"
|
||||||
msgstr ""
|
msgstr "Uitgeschakelde Projectgeschiedenis"
|
||||||
|
|
||||||
msgid "Disabled Project History & IP Address Recording"
|
msgid "Disabled Project History & IP Address Recording"
|
||||||
msgstr ""
|
msgstr "Uitgeschakelde Projecthistorie & IP-Adres Vastlegging"
|
||||||
|
|
||||||
msgid "Enabled Project History"
|
msgid "Enabled Project History"
|
||||||
msgstr ""
|
msgstr "Ingeschakelde Projectgeschiedenis"
|
||||||
|
|
||||||
msgid "Disabled IP Address Recording"
|
msgid "Disabled IP Address Recording"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -399,7 +409,7 @@ msgid "Enabled IP Address Recording"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "History Settings Changed"
|
msgid "History Settings Changed"
|
||||||
msgstr ""
|
msgstr "Geschiedenisinstellingen Gewijzigd"
|
||||||
|
|
||||||
msgid "changed"
|
msgid "changed"
|
||||||
msgstr "gewijzigd"
|
msgstr "gewijzigd"
|
||||||
|
@ -419,20 +429,26 @@ msgid ""
|
||||||
" The rest of the project history will be unaffected. This "
|
" The rest of the project history will be unaffected. This "
|
||||||
"action cannot be undone."
|
"action cannot be undone."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Weet je zeker dat je alle vastgelegde IP-adressen wilt verwijderen van dit "
|
||||||
|
"project?\n"
|
||||||
|
"De rest van de projectgeschiedenis blijft onveranderd. Deze actie kan niet "
|
||||||
|
"ongedaan worden gemaakt."
|
||||||
|
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Sluiten"
|
msgstr "Sluiten"
|
||||||
|
|
||||||
msgid "Confirm Delete"
|
msgid "Confirm Delete"
|
||||||
msgstr ""
|
msgstr "Bevestig Verwijdering"
|
||||||
|
|
||||||
msgid "Delete Confirmation"
|
msgid "Delete Confirmation"
|
||||||
msgstr ""
|
msgstr "Bevestiging Verwijdering"
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure you want to erase all history for this project? This action "
|
"Are you sure you want to erase all history for this project? This action "
|
||||||
"cannot be undone."
|
"cannot be undone."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Weet je zeker dat je de gehele geschiedenis wilt verwijderen voor dit "
|
||||||
|
"project? Deze actie kan niet ongedaan worden gemaakt."
|
||||||
|
|
||||||
msgid "Added"
|
msgid "Added"
|
||||||
msgstr "Toegevoegd"
|
msgstr "Toegevoegd"
|
||||||
|
@ -454,6 +470,12 @@ msgid ""
|
||||||
" <a href=\"%(url)s\">settings page</a>\n"
|
" <a href=\"%(url)s\">settings page</a>\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"\n"
|
||||||
|
" <i>Dit project heeft de geschiedenis uitgeschakeld. Nieuwe "
|
||||||
|
"acties zullen niet hieronder verschijnen. Je kunt de geschiedenis aanzetten "
|
||||||
|
"op de </i>\n"
|
||||||
|
" <a href=\"%(url)s\">instellingen-pagina</a>\n"
|
||||||
|
" "
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
|
@ -474,19 +496,19 @@ msgid "Delete stored IP addresses"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "No history to erase"
|
msgid "No history to erase"
|
||||||
msgstr ""
|
msgstr "Geen geschiedenis om te wissen"
|
||||||
|
|
||||||
msgid "Clear Project History"
|
msgid "Clear Project History"
|
||||||
msgstr ""
|
msgstr "Verwijder Projectgeschiedenis"
|
||||||
|
|
||||||
msgid "No IP Addresses to erase"
|
msgid "No IP Addresses to erase"
|
||||||
msgstr ""
|
msgstr "Geen IP-adressen te verwijderen"
|
||||||
|
|
||||||
msgid "Delete Stored IP Addresses"
|
msgid "Delete Stored IP Addresses"
|
||||||
msgstr ""
|
msgstr "Verwijder opgeslagen IP-adressen"
|
||||||
|
|
||||||
msgid "Time"
|
msgid "Time"
|
||||||
msgstr ""
|
msgstr "Tijd"
|
||||||
|
|
||||||
msgid "Event"
|
msgid "Event"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -501,44 +523,44 @@ msgid "From IP"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "added"
|
msgid "added"
|
||||||
msgstr ""
|
msgstr "toegevoegd"
|
||||||
|
|
||||||
msgid "Project private code changed"
|
msgid "Project private code changed"
|
||||||
msgstr ""
|
msgstr "Privécode van project gewijzigd"
|
||||||
|
|
||||||
msgid "Project renamed to"
|
msgid "Project renamed to"
|
||||||
msgstr ""
|
msgstr "Project hernoemd tot"
|
||||||
|
|
||||||
msgid "Project contact email changed to"
|
msgid "Project contact email changed to"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Project settings modified"
|
msgid "Project settings modified"
|
||||||
msgstr ""
|
msgstr "Projectinstellingen gewijzigd"
|
||||||
|
|
||||||
msgid "deactivated"
|
msgid "deactivated"
|
||||||
msgstr ""
|
msgstr "gedeactiveerd"
|
||||||
|
|
||||||
msgid "reactivated"
|
msgid "reactivated"
|
||||||
msgstr ""
|
msgstr "gereactiveerd"
|
||||||
|
|
||||||
msgid "renamed to"
|
msgid "renamed to"
|
||||||
msgstr ""
|
msgstr "hernoemd naar"
|
||||||
|
|
||||||
msgid "External link changed to"
|
msgid "External link changed to"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Amount"
|
msgid "Amount"
|
||||||
msgstr ""
|
msgstr "Hoeveelheid"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Amount in %(currency)s"
|
msgid "Amount in %(currency)s"
|
||||||
msgstr ""
|
msgstr "Hoeveelheid in %(currency)s"
|
||||||
|
|
||||||
msgid "modified"
|
msgid "modified"
|
||||||
msgstr ""
|
msgstr "gewijzigd"
|
||||||
|
|
||||||
msgid "removed"
|
msgid "removed"
|
||||||
msgstr ""
|
msgstr "verwijderd"
|
||||||
|
|
||||||
msgid "changed in a unknown way"
|
msgid "changed in a unknown way"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -547,7 +569,7 @@ msgid "Nothing to list"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Someone probably cleared the project history."
|
msgid "Someone probably cleared the project history."
|
||||||
msgstr ""
|
msgstr "Iemand heeft waarschijnlijk de projectgeschiedenis verwijderd."
|
||||||
|
|
||||||
msgid "Manage your shared <br />expenses, easily"
|
msgid "Manage your shared <br />expenses, easily"
|
||||||
msgstr "Beheer eenvoudig je <br />gedeelde uitgaven"
|
msgstr "Beheer eenvoudig je <br />gedeelde uitgaven"
|
||||||
|
@ -574,7 +596,7 @@ msgid "Log in"
|
||||||
msgstr "Inloggen"
|
msgstr "Inloggen"
|
||||||
|
|
||||||
msgid "can't remember your password?"
|
msgid "can't remember your password?"
|
||||||
msgstr "ben je je wachtwoord vergeten?"
|
msgstr "wachtwoord vergeten?"
|
||||||
|
|
||||||
msgid "Create"
|
msgid "Create"
|
||||||
msgstr "Maken"
|
msgstr "Maken"
|
||||||
|
@ -583,6 +605,8 @@ msgid ""
|
||||||
"Don\\'t reuse a personal password. Choose a private code and send it to "
|
"Don\\'t reuse a personal password. Choose a private code and send it to "
|
||||||
"your friends"
|
"your friends"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Hergebruik geen persoonlijk wachtwoord. Kies een privécode en stuur het naar "
|
||||||
|
"je vrienden"
|
||||||
|
|
||||||
msgid "Account manager"
|
msgid "Account manager"
|
||||||
msgstr "Accountbeheer"
|
msgstr "Accountbeheer"
|
||||||
|
@ -597,7 +621,7 @@ msgid "Statistics"
|
||||||
msgstr "Statistieken"
|
msgstr "Statistieken"
|
||||||
|
|
||||||
msgid "History"
|
msgid "History"
|
||||||
msgstr ""
|
msgstr "Geschiedenis"
|
||||||
|
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "Instellingen"
|
msgstr "Instellingen"
|
||||||
|
@ -781,7 +805,7 @@ msgid "Expenses by Month"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Period"
|
msgid "Period"
|
||||||
msgstr ""
|
msgstr "Periode"
|
||||||
|
|
||||||
#~ msgid "%(msg_compl)sThe project identifier is %(project)s"
|
#~ msgid "%(msg_compl)sThe project identifier is %(project)s"
|
||||||
#~ msgstr "%(msg_compl)sDe project-id is %(project)s"
|
#~ msgstr "%(msg_compl)sDe project-id is %(project)s"
|
||||||
|
|
|
@ -676,16 +676,16 @@ msgstr "вы можете способствовать развитию и ул
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "%(amount)s each"
|
msgid "%(amount)s each"
|
||||||
msgstr "%(amount)s каждый"
|
msgstr "%(amount)s по каждому"
|
||||||
|
|
||||||
msgid "Invite people"
|
msgid "Invite people"
|
||||||
msgstr "Пригласить людей"
|
msgstr "Пригласите людей"
|
||||||
|
|
||||||
msgid "You should start by adding participants"
|
msgid "You should start by adding participants"
|
||||||
msgstr "Вам стоит начать с добавления пользователей"
|
msgstr "Вы должны начать с добавлением пользователей"
|
||||||
|
|
||||||
msgid "Add a new bill"
|
msgid "Add a new bill"
|
||||||
msgstr "Добавить новый счёт"
|
msgstr "Добавите новый счёт"
|
||||||
|
|
||||||
msgid "Newer bills"
|
msgid "Newer bills"
|
||||||
msgstr "Новые счета"
|
msgstr "Новые счета"
|
||||||
|
@ -749,7 +749,7 @@ msgid "Reset your password"
|
||||||
msgstr "Восстановить пароль"
|
msgstr "Восстановить пароль"
|
||||||
|
|
||||||
msgid "Invite people to join this project"
|
msgid "Invite people to join this project"
|
||||||
msgstr "Пригласить людей присоединиться к этому проекту"
|
msgstr "Пригласите людей присоединиться к этому проекту"
|
||||||
|
|
||||||
msgid "Share Identifier & code"
|
msgid "Share Identifier & code"
|
||||||
msgstr "Поделиться идентификатором и кодом"
|
msgstr "Поделиться идентификатором и кодом"
|
||||||
|
|
BIN
ihatemoney/translations/sr/LC_MESSAGES/messages.mo
Normal file
BIN
ihatemoney/translations/sr/LC_MESSAGES/messages.mo
Normal file
Binary file not shown.
770
ihatemoney/translations/sr/LC_MESSAGES/messages.po
Normal file
770
ihatemoney/translations/sr/LC_MESSAGES/messages.po
Normal file
|
@ -0,0 +1,770 @@
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2021-04-08 13:59+0200\n"
|
||||||
|
"PO-Revision-Date: 2021-04-09 13:26+0000\n"
|
||||||
|
"Last-Translator: Rastko Sarcevic <ralesarcevic@gmail.com>\n"
|
||||||
|
"Language-Team: Serbian <https://hosted.weblate.org/projects/i-hate-money/"
|
||||||
|
"i-hate-money/sr/>\n"
|
||||||
|
"Language: sr\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
|
||||||
|
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||||
|
"X-Generator: Weblate 4.6-dev\n"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Not a valid amount or expression. Only numbers and + - * / operators are "
|
||||||
|
"accepted."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Project name"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Private code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Email"
|
||||||
|
msgstr "Email"
|
||||||
|
|
||||||
|
msgid "Enable project history"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Use IP tracking for project history"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Default Currency"
|
||||||
|
msgstr "Podrazumevana Valuta"
|
||||||
|
|
||||||
|
msgid "Import previously exported JSON file"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Import"
|
||||||
|
msgstr "Uvezi"
|
||||||
|
|
||||||
|
msgid "Project identifier"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Create the project"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"A project with this identifier (\"%(project)s\") already exists. Please "
|
||||||
|
"choose a new identifier"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Get in"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Admin password"
|
||||||
|
msgstr "Administratorska lozinka"
|
||||||
|
|
||||||
|
msgid "Send me the code by email"
|
||||||
|
msgstr "Pošalji mi kod putem email-a"
|
||||||
|
|
||||||
|
msgid "This project does not exists"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Password mismatch"
|
||||||
|
msgstr "Lozinke se ne slažu"
|
||||||
|
|
||||||
|
msgid "Password"
|
||||||
|
msgstr "Lozinka"
|
||||||
|
|
||||||
|
msgid "Password confirmation"
|
||||||
|
msgstr "Potvrda lozinke"
|
||||||
|
|
||||||
|
msgid "Reset password"
|
||||||
|
msgstr "Resetuj lozinku"
|
||||||
|
|
||||||
|
msgid "Date"
|
||||||
|
msgstr "Datum"
|
||||||
|
|
||||||
|
msgid "What?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Payer"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Amount paid"
|
||||||
|
msgstr "Plaćeni iznos"
|
||||||
|
|
||||||
|
msgid "Currency"
|
||||||
|
msgstr "Valuta"
|
||||||
|
|
||||||
|
msgid "External link"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "A link to an external document, related to this bill"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "For whom?"
|
||||||
|
msgstr "Za koga?"
|
||||||
|
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr "Unesi"
|
||||||
|
|
||||||
|
msgid "Submit and add a new one"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "Project default: %(currency)s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Bills can't be null"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Name"
|
||||||
|
msgstr "Ime"
|
||||||
|
|
||||||
|
msgid "Weights should be positive"
|
||||||
|
msgstr "Težine moraju biti pozitivne"
|
||||||
|
|
||||||
|
msgid "Weight"
|
||||||
|
msgstr "Težina"
|
||||||
|
|
||||||
|
msgid "Add"
|
||||||
|
msgstr "Dodaj"
|
||||||
|
|
||||||
|
msgid "User name incorrect"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "This project already have this member"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "People to notify"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Send invites"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "The email %(email)s is not valid"
|
||||||
|
msgstr "Email %(email)s nije validan"
|
||||||
|
|
||||||
|
msgid "Participant"
|
||||||
|
msgstr "Učesnik"
|
||||||
|
|
||||||
|
msgid "Bill"
|
||||||
|
msgstr "Račun"
|
||||||
|
|
||||||
|
msgid "Project"
|
||||||
|
msgstr "Projekat"
|
||||||
|
|
||||||
|
msgid "No Currency"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Too many failed login attempts, please retry later."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "This admin password is not the right one. Only %(num)d attempts left."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "You either provided a bad token or no project identifier."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "This private code is not the right one"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "You have just created '%(project)s' to share your expenses"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "A reminder email has just been sent to you"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"We tried to send you an reminder email, but there was an error. You can "
|
||||||
|
"still use the project normally."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "The project identifier is %(project)s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Sorry, there was an error while sending you an email with password reset "
|
||||||
|
"instructions. Please check the email configuration of the server or "
|
||||||
|
"contact the administrator."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "No token provided"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Invalid token"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Unknown project"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Password successfully reset."
|
||||||
|
msgstr "Lozinka uspešno resetovana."
|
||||||
|
|
||||||
|
msgid "Project successfully uploaded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Invalid JSON"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Project successfully deleted"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "You have been invited to share your expenses for %(project)s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Your invitations have been sent"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Sorry, there was an error while trying to send the invitation emails. "
|
||||||
|
"Please check the email configuration of the server or contact the "
|
||||||
|
"administrator."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "%(member)s has been added"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "%(name)s is part of this project again"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"User '%(name)s' has been deactivated. It will still appear in the users "
|
||||||
|
"list until its balance becomes zero."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "User '%(name)s' has been removed"
|
||||||
|
msgstr "Korisnik %(name)s je uklonjen"
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "User '%(name)s' has been edited"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "The bill has been added"
|
||||||
|
msgstr "Račun je dodat"
|
||||||
|
|
||||||
|
msgid "The bill has been deleted"
|
||||||
|
msgstr "Račun je uklonjen"
|
||||||
|
|
||||||
|
msgid "The bill has been modified"
|
||||||
|
msgstr "Račun je izmenjen"
|
||||||
|
|
||||||
|
msgid "Sorry, we were unable to find the page you've asked for."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "The best thing to do is probably to get back to the main page."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Back to the list"
|
||||||
|
msgstr "Nazad na listu"
|
||||||
|
|
||||||
|
msgid "Administration tasks are currently disabled."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "The project you are trying to access do not exist, do you want to"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "create it"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "?"
|
||||||
|
msgstr "?"
|
||||||
|
|
||||||
|
msgid "Create a new project"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Number of members"
|
||||||
|
msgstr "Broj korisnika"
|
||||||
|
|
||||||
|
msgid "Number of bills"
|
||||||
|
msgstr "Broj računa"
|
||||||
|
|
||||||
|
msgid "Newest bill"
|
||||||
|
msgstr "Najnoviji račun"
|
||||||
|
|
||||||
|
msgid "Oldest bill"
|
||||||
|
msgstr "Najstariji račun"
|
||||||
|
|
||||||
|
msgid "Actions"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "edit"
|
||||||
|
msgstr "izmeni"
|
||||||
|
|
||||||
|
msgid "delete"
|
||||||
|
msgstr "ukloni"
|
||||||
|
|
||||||
|
msgid "show"
|
||||||
|
msgstr "prikaži"
|
||||||
|
|
||||||
|
msgid "The Dashboard is currently deactivated."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "you sure?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Edit project"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Import JSON"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Choose file"
|
||||||
|
msgstr "Izaberi fajl"
|
||||||
|
|
||||||
|
msgid "Download project's data"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Bill items"
|
||||||
|
msgstr "Stavke računa"
|
||||||
|
|
||||||
|
msgid "Download the list of bills with owner, amount, reason,... "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Settle plans"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Download the list of transactions needed to settle the current bills."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Can't remember the password?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr "Otkaži"
|
||||||
|
|
||||||
|
msgid "Privacy Settings"
|
||||||
|
msgstr "Podešavanja Privatnosti"
|
||||||
|
|
||||||
|
msgid "Edit the project"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Edit this bill"
|
||||||
|
msgstr "Izmeni ovaj račun"
|
||||||
|
|
||||||
|
msgid "Add a bill"
|
||||||
|
msgstr "Dodaj račun"
|
||||||
|
|
||||||
|
msgid "Select all"
|
||||||
|
msgstr "Izaberi sve"
|
||||||
|
|
||||||
|
msgid "Select none"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Add participant"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Edit this member"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "john.doe@example.com, mary.moe@site.com"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Send the invitations"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Download"
|
||||||
|
msgstr "Preuzmi"
|
||||||
|
|
||||||
|
msgid "Disabled Project History"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Disabled Project History & IP Address Recording"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Enabled Project History"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Disabled IP Address Recording"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Enabled Project History & IP Address Recording"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Enabled IP Address Recording"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "History Settings Changed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "changed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "from"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "to"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Confirm Remove IP Adresses"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Are you sure you want to delete all recorded IP addresses from this "
|
||||||
|
"project?\n"
|
||||||
|
" The rest of the project history will be unaffected. This "
|
||||||
|
"action cannot be undone."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Close"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Confirm Delete"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Delete Confirmation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Are you sure you want to erase all history for this project? This action "
|
||||||
|
"cannot be undone."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Added"
|
||||||
|
msgstr "Dodato"
|
||||||
|
|
||||||
|
msgid "Removed"
|
||||||
|
msgstr "Uklonjeno"
|
||||||
|
|
||||||
|
msgid "and"
|
||||||
|
msgstr "i"
|
||||||
|
|
||||||
|
msgid "owers list"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
" <i>This project has history disabled. New actions won't "
|
||||||
|
"appear below. You can enable history on the</i>\n"
|
||||||
|
" <a href=\"%(url)s\">settings page</a>\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
" <i>The table below reflects actions recorded prior to "
|
||||||
|
"disabling project history. You can\n"
|
||||||
|
" <a href=\"#\" data-toggle=\"modal\" data-keyboard=\"false\" "
|
||||||
|
"data-target=\"#confirm-erase\">clear project history</a> to remove "
|
||||||
|
"them.</i></p>\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Some entries below contain IP addresses, even though this project has IP "
|
||||||
|
"recording disabled. "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Delete stored IP addresses"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "No history to erase"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Clear Project History"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "No IP Addresses to erase"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Delete Stored IP Addresses"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Time"
|
||||||
|
msgstr "Vreme"
|
||||||
|
|
||||||
|
msgid "Event"
|
||||||
|
msgstr "Događaj"
|
||||||
|
|
||||||
|
msgid "IP address recording can be enabled on the settings page"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "IP address recording can be disabled on the settings page"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "From IP"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "added"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Project private code changed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Project renamed to"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Project contact email changed to"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Project settings modified"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "deactivated"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "reactivated"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "renamed to"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "External link changed to"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Amount"
|
||||||
|
msgstr "Iznos"
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "Amount in %(currency)s"
|
||||||
|
msgstr "Iznos u %(currency)s"
|
||||||
|
|
||||||
|
msgid "modified"
|
||||||
|
msgstr "izmenjeno"
|
||||||
|
|
||||||
|
msgid "removed"
|
||||||
|
msgstr "uklonjeno"
|
||||||
|
|
||||||
|
msgid "changed in a unknown way"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Nothing to list"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Someone probably cleared the project history."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Manage your shared <br />expenses, easily"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Try out the demo"
|
||||||
|
msgstr "Isprobaj demo verziju"
|
||||||
|
|
||||||
|
msgid "You're sharing a house?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Going on holidays with friends?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Simply sharing money with others?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "We can help!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Log in to an existing project"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Log in"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "can't remember your password?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Create"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Don\\'t reuse a personal password. Choose a private code and send it to "
|
||||||
|
"your friends"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Account manager"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Bills"
|
||||||
|
msgstr "Računi"
|
||||||
|
|
||||||
|
msgid "Settle"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Statistics"
|
||||||
|
msgstr "Statistika"
|
||||||
|
|
||||||
|
msgid "History"
|
||||||
|
msgstr "Istorija"
|
||||||
|
|
||||||
|
msgid "Settings"
|
||||||
|
msgstr "Podešavanja"
|
||||||
|
|
||||||
|
msgid "Languages"
|
||||||
|
msgstr "Jezici"
|
||||||
|
|
||||||
|
msgid "Projects"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Start a new project"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Other projects :"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "switch to"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Dashboard"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Logout"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Code"
|
||||||
|
msgstr "Kod"
|
||||||
|
|
||||||
|
msgid "Mobile Application"
|
||||||
|
msgstr "Mobilna Aplikacija"
|
||||||
|
|
||||||
|
msgid "Documentation"
|
||||||
|
msgstr "Dokumentacija"
|
||||||
|
|
||||||
|
msgid "Administation Dashboard"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "\"I hate money\" is a free software"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "you can contribute and improve it!"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "%(amount)s each"
|
||||||
|
msgstr "%(amount)s svako"
|
||||||
|
|
||||||
|
msgid "Invite people"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "You should start by adding participants"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Add a new bill"
|
||||||
|
msgstr "Dodaj novi račun"
|
||||||
|
|
||||||
|
msgid "Newer bills"
|
||||||
|
msgstr "Noviji računi"
|
||||||
|
|
||||||
|
msgid "Older bills"
|
||||||
|
msgstr "Stariji računi"
|
||||||
|
|
||||||
|
msgid "When?"
|
||||||
|
msgstr "Kada?"
|
||||||
|
|
||||||
|
msgid "Who paid?"
|
||||||
|
msgstr "Ko je platio?"
|
||||||
|
|
||||||
|
msgid "For what?"
|
||||||
|
msgstr "Za šta?"
|
||||||
|
|
||||||
|
msgid "How much?"
|
||||||
|
msgstr "Koliko?"
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "Added on %(date)s"
|
||||||
|
msgstr "Dodato %(date)s"
|
||||||
|
|
||||||
|
msgid "Everyone"
|
||||||
|
msgstr "Svi"
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "Everyone but %(excluded)s"
|
||||||
|
msgstr "Svi osim %(excluded)s"
|
||||||
|
|
||||||
|
msgid "No bills"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Nothing to list yet."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "You probably want to"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "add a bill"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "add participants"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Password reminder"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"A link to reset your password has been sent to you, please check your "
|
||||||
|
"emails."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Return to home page"
|
||||||
|
msgstr "Vrati se na početnu stranu"
|
||||||
|
|
||||||
|
msgid "Your projects"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Reset your password"
|
||||||
|
msgstr "Resetuj lozinku"
|
||||||
|
|
||||||
|
msgid "Invite people to join this project"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Share Identifier & code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"You can share the project identifier and the private code by any "
|
||||||
|
"communication means."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Identifier:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Share the Link"
|
||||||
|
msgstr "Podelite link"
|
||||||
|
|
||||||
|
msgid "You can directly share the following link via your prefered medium"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Send via Emails"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Specify a (comma separated) list of email adresses you want to notify "
|
||||||
|
"about the\n"
|
||||||
|
" creation of this budget management project and we will "
|
||||||
|
"send them an email for you."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Who pays?"
|
||||||
|
msgstr "Ko plaća?"
|
||||||
|
|
||||||
|
msgid "To whom?"
|
||||||
|
msgstr "Kome?"
|
||||||
|
|
||||||
|
msgid "Who?"
|
||||||
|
msgstr "Ko?"
|
||||||
|
|
||||||
|
msgid "Balance"
|
||||||
|
msgstr "Stanje"
|
||||||
|
|
||||||
|
msgid "deactivate"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "reactivate"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Paid"
|
||||||
|
msgstr "Plaćeno"
|
||||||
|
|
||||||
|
msgid "Spent"
|
||||||
|
msgstr "Potrošeno"
|
||||||
|
|
||||||
|
msgid "Expenses by Month"
|
||||||
|
msgstr "Mesečni troškovi"
|
||||||
|
|
||||||
|
msgid "Period"
|
||||||
|
msgstr "Period"
|
BIN
ihatemoney/translations/te/LC_MESSAGES/messages.mo
Normal file
BIN
ihatemoney/translations/te/LC_MESSAGES/messages.mo
Normal file
Binary file not shown.
|
@ -12,7 +12,7 @@ import socket
|
||||||
|
|
||||||
from babel import Locale
|
from babel import Locale
|
||||||
from babel.numbers import get_currency_name, get_currency_symbol
|
from babel.numbers import get_currency_name, get_currency_symbol
|
||||||
from flask import current_app, redirect, render_template, escape
|
from flask import current_app, escape, redirect, render_template
|
||||||
from flask_babel import get_locale, lazy_gettext as _
|
from flask_babel import get_locale, lazy_gettext as _
|
||||||
import jinja2
|
import jinja2
|
||||||
from werkzeug.routing import HTTPException, RoutingException
|
from werkzeug.routing import HTTPException, RoutingException
|
||||||
|
@ -363,6 +363,7 @@ def localize_list(list, surround_with_em=True):
|
||||||
output_str = start.format(start_object="{start_object}", next_object=output_str)
|
output_str = start.format(start_object="{start_object}", next_object=output_str)
|
||||||
return output_str.format(start_object=item_wrapper(list.pop()))
|
return output_str.format(start_object=item_wrapper(list.pop()))
|
||||||
|
|
||||||
|
|
||||||
def render_localized_currency(code, detailed=True):
|
def render_localized_currency(code, detailed=True):
|
||||||
if code == "XXX":
|
if code == "XXX":
|
||||||
return _("No Currency")
|
return _("No Currency")
|
||||||
|
@ -389,4 +390,3 @@ def render_localized_template(template_name_prefix, **context):
|
||||||
]
|
]
|
||||||
# render_template() supports a list of templates to try in order
|
# render_template() supports a list of templates to try in order
|
||||||
return render_template(templates, **context)
|
return render_template(templates, **context)
|
||||||
|
|
||||||
|
|
|
@ -270,6 +270,11 @@ def home():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@main.route("/mobile")
|
||||||
|
def mobile():
|
||||||
|
return render_template("download_mobile_app.html")
|
||||||
|
|
||||||
|
|
||||||
@main.route("/create", methods=["GET", "POST"])
|
@main.route("/create", methods=["GET", "POST"])
|
||||||
@requires_admin(bypass=("ALLOW_PUBLIC_PROJECT_CREATION", True))
|
@requires_admin(bypass=("ALLOW_PUBLIC_PROJECT_CREATION", True))
|
||||||
def create_project():
|
def create_project():
|
||||||
|
|
|
@ -14,6 +14,7 @@ classifiers =
|
||||||
Programming Language :: Python :: 3.6
|
Programming Language :: Python :: 3.6
|
||||||
Programming Language :: Python :: 3.7
|
Programming Language :: Python :: 3.7
|
||||||
Programming Language :: Python :: 3.8
|
Programming Language :: Python :: 3.8
|
||||||
|
Programming Language :: Python :: 3.9
|
||||||
Topic :: Internet :: WWW/HTTP
|
Topic :: Internet :: WWW/HTTP
|
||||||
Topic :: Internet :: WWW/HTTP :: WSGI :: Application
|
Topic :: Internet :: WWW/HTTP :: WSGI :: Application
|
||||||
|
|
||||||
|
@ -40,6 +41,7 @@ install_requires =
|
||||||
Jinja2~=2.11
|
Jinja2~=2.11
|
||||||
requests~=2.22
|
requests~=2.22
|
||||||
SQLAlchemy-Continuum~=1.3
|
SQLAlchemy-Continuum~=1.3
|
||||||
|
SQLAlchemy~=1.3.0 # New 1.4 changes API, see #728
|
||||||
|
|
||||||
[options.extras_require]
|
[options.extras_require]
|
||||||
dev =
|
dev =
|
||||||
|
|
7
tox.ini
7
tox.ini
|
@ -1,12 +1,12 @@
|
||||||
[tox]
|
[tox]
|
||||||
envlist = py38,py37,py36,docs,flake8,black
|
envlist = py39,py38,py37,py36,docs,flake8,black
|
||||||
skip_missing_interpreters = True
|
skip_missing_interpreters = True
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
|
|
||||||
commands =
|
commands =
|
||||||
python --version
|
python --version
|
||||||
py.test --pyargs ihatemoney.tests.tests
|
py.test --pyargs ihatemoney.tests
|
||||||
|
|
||||||
deps =
|
deps =
|
||||||
-e.[dev]
|
-e.[dev]
|
||||||
|
@ -22,7 +22,7 @@ changedir = {toxinidir}
|
||||||
|
|
||||||
[testenv:black]
|
[testenv:black]
|
||||||
commands =
|
commands =
|
||||||
black --check --target-version=py34 .
|
black --check --target-version=py36 .
|
||||||
isort -c -rc .
|
isort -c -rc .
|
||||||
changedir = {toxinidir}
|
changedir = {toxinidir}
|
||||||
|
|
||||||
|
@ -42,3 +42,4 @@ python =
|
||||||
3.6: py36
|
3.6: py36
|
||||||
3.7: py37
|
3.7: py37
|
||||||
3.8: py38, docs, black, flake8
|
3.8: py38, docs, black, flake8
|
||||||
|
3.9: py39
|
||||||
|
|
Loading…
Reference in a new issue