From 23b7e397f2f9e62b961096daa03b0b04546b4b03 Mon Sep 17 00:00:00 2001 From: eMerzh Date: Sun, 5 Apr 2020 23:39:50 +0200 Subject: [PATCH 01/47] fix(Home): correct responsive width of cards (#549) --- ihatemoney/static/css/main.css | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ihatemoney/static/css/main.css b/ihatemoney/static/css/main.css index a646b175..32c267ea 100644 --- a/ihatemoney/static/css/main.css +++ b/ihatemoney/static/css/main.css @@ -150,6 +150,11 @@ body { margin-bottom: 20px; margin-left: 25px; } +@media (max-width: 400px) { + .home .card { + min-width: unset; + } +} /* Other */ #bills { @@ -320,13 +325,15 @@ footer .footer-left { background: url("../images/see.png") no-repeat right; } -#bill_table, #monthly_stats { +#bill_table, +#monthly_stats { margin-top: 30px; margin-bottom: 30px; } @media (min-width: 768px) { - .split_bills, #table_overflow.statistics { + .split_bills, + #table_overflow.statistics { /* The table is shifted to left, so add the spacer width on the right to match */ width: calc(100% + 15px); } From 4b79efe18a9952268d65b98813e3929a8179ed2c Mon Sep 17 00:00:00 2001 From: Charles Rose <33735833+rosechar@users.noreply.github.com> Date: Tue, 7 Apr 2020 11:09:33 -0400 Subject: [PATCH 02/47] updated web.py to make session permanent (#547) * moved making session permanent to after authentication in web.py Co-authored-by: Charlie Rose --- ihatemoney/web.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ihatemoney/web.py b/ihatemoney/web.py index 1b80ab62..a3b10726 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -235,6 +235,8 @@ def authenticate(project_id=None): # add the project on the top of the list session["projects"].insert(0, (project_id, project.name)) session[project_id] = True + # Set session to permanent to make language choice persist + session.permanent = True session.update() setattr(g, "project", project) return redirect(url_for(".list_bills")) From 03251c090e64082acfe301e844610f64c8f8fdef Mon Sep 17 00:00:00 2001 From: eMerzh Date: Wed, 8 Apr 2020 14:00:24 +0200 Subject: [PATCH 03/47] merge settings and import to avoid clutter (#550) --- ihatemoney/forms.py | 5 ++- ihatemoney/static/css/main.css | 12 ++++++- ihatemoney/templates/edit_project.html | 43 ++++++++++++++++++++------ ihatemoney/templates/layout.html | 1 - ihatemoney/templates/upload_json.html | 10 ------ ihatemoney/web.py | 42 ++++++++++++------------- 6 files changed, 70 insertions(+), 43 deletions(-) delete mode 100644 ihatemoney/templates/upload_json.html diff --git a/ihatemoney/forms.py b/ihatemoney/forms.py index 88afd296..62c21444 100644 --- a/ihatemoney/forms.py +++ b/ihatemoney/forms.py @@ -114,8 +114,11 @@ class EditProjectForm(FlaskForm): class UploadForm(FlaskForm): file = FileField( - "JSON", validators=[FileRequired(), FileAllowed(["json", "JSON"], "JSON only!")] + "JSON", + validators=[FileRequired(), FileAllowed(["json", "JSON"], "JSON only!")], + description=_("Import previously exported JSON file"), ) + submit = SubmitField(_("Import")) class ProjectForm(EditProjectForm): diff --git a/ihatemoney/static/css/main.css b/ihatemoney/static/css/main.css index 32c267ea..fe8eec20 100644 --- a/ihatemoney/static/css/main.css +++ b/ihatemoney/static/css/main.css @@ -185,7 +185,7 @@ footer { padding: 45px 50px; } -@media (min-width: 768px) { +@media (min-width: 1024px) { footer { padding-left: calc(25% + 50px); } @@ -523,3 +523,13 @@ footer .icon svg { text-align: right; width: 200px; } + +/* edit settings */ + +.edit-project form { + margin-top: 1em; + margin-bottom: 3em; +} +.edit-project .custom-file { + margin-bottom: 2em; +} diff --git a/ihatemoney/templates/edit_project.html b/ihatemoney/templates/edit_project.html index dcbbbc86..b7861c51 100644 --- a/ihatemoney/templates/edit_project.html +++ b/ihatemoney/templates/edit_project.html @@ -5,18 +5,43 @@ { $(this).html("{{_("you sure?")}}"); }); + + $('.custom-file-input').on('change', function(event) { + var filename = [].slice.call(this.files).map(function (file) { return file.name}).join(',') + var $labelElement = $(this).parents('.custom-file').find('.custom-file-label') + $labelElement.text(filename) + }) {% endblock %} {% block content %} -

{{ _("Edit project") }}

-

-

- {{ forms.edit_project(edit_form) }} -
-

+
-

{{ _("Download project's data") }}

-

+

{{ _("Edit project") }}

+
+ {{ forms.edit_project(edit_form) }} +
+ + +

{{ _("Import JSON") }}

+
+ {{ import_form.hidden_tag() }} + +
+
+ {{ import_form.file(class="custom-file-input") }} + + {{ import_form.file.description }} + +
+ +
+ +
+ {{ import_form.submit(class="btn btn-primary") }} +
+
+ +

{{ _("Download project's data") }}

@@ -51,5 +76,5 @@

{{ _('Download the list of transactions needed to settle the current bills.') }}

-

+
{% endblock %} diff --git a/ihatemoney/templates/layout.html b/ihatemoney/templates/layout.html index dc3d32f6..8609779c 100644 --- a/ihatemoney/templates/layout.html +++ b/ihatemoney/templates/layout.html @@ -46,7 +46,6 @@ - {% endblock %} {% endif %} diff --git a/ihatemoney/templates/upload_json.html b/ihatemoney/templates/upload_json.html deleted file mode 100644 index 64aca0fe..00000000 --- a/ihatemoney/templates/upload_json.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "layout.html" %} - -{% block content %} -

{{ _("Import JSON") }}

-

-

- {{ forms.upload_json(form) }} -
-

-{% endblock %} diff --git a/ihatemoney/web.py b/ihatemoney/web.py index a3b10726..8e0bca6c 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -384,36 +384,36 @@ def reset_password(): @main.route("//edit", methods=["GET", "POST"]) def edit_project(): edit_form = EditProjectForm() - if request.method == "POST": - if edit_form.validate(): - project = edit_form.update(g.project) - db.session.add(project) - db.session.commit() + import_form = UploadForm() + # Import form + if import_form.validate_on_submit(): + try: + import_project(import_form.file.data.stream, g.project) + flash(_("Project successfully uploaded")) - return redirect(url_for(".list_bills")) + return redirect(url_for("main.list_bills")) + except ValueError: + flash(_("Invalid JSON"), category="error") + + # Edit form + if edit_form.validate_on_submit(): + project = edit_form.update(g.project) + db.session.add(project) + db.session.commit() + + return redirect(url_for("main.list_bills")) else: edit_form.name.data = g.project.name edit_form.contact_email.data = g.project.contact_email return render_template( - "edit_project.html", edit_form=edit_form, current_view="edit_project" + "edit_project.html", + edit_form=edit_form, + import_form=import_form, + current_view="edit_project", ) -@main.route("//upload_json", methods=["GET", "POST"]) -def upload_json(): - form = UploadForm() - if form.validate_on_submit(): - try: - import_project(form.file.data.stream, g.project) - flash(_("Project successfully uploaded")) - except ValueError: - flash(_("Invalid JSON"), category="error") - return redirect(url_for("main.list_bills")) - - return render_template("upload_json.html", form=form) - - def import_project(file, project): json_file = json.load(file) From da89c353905bb04c337ca489c4b5751facba1cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Allan=20Nordh=C3=B8y?= Date: Sun, 12 Apr 2020 07:58:00 +0000 Subject: [PATCH 04/47] Spelling in documentation fixed, Weblate link (#551) --- docs/contributing.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index a810d121..f35a3c8f 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -1,14 +1,14 @@ Contributing ############ -Setup a dev environment +Set up a dev environment ======================= -You must develop on top of the git master branch:: +You must develop on top of the Git master branch:: git clone https://github.com/spiral-project/ihatemoney.git -Then you need to build your dev environments. Choose your way… +Then you need to build your dev environment. Choose your way… The quick way ------------- @@ -43,7 +43,7 @@ It's as simple as that! Updating -------- -In case you want to update to newer versions (from git), you can just run the "update" command:: +In case you want to update to newer versions (from Git), you can just run the "update" command:: make update @@ -57,7 +57,7 @@ database revision file:: make create-database-revision If your changes are simple enough, the generated script will be populated with -the necessary migrations steps. You can edit the generated script. eg: to add +the necessary migrations steps. You can edit the generated script. e.g: To add data migrations. For complex migrations, it is recommended to start from an empty revision file @@ -101,7 +101,7 @@ To do so:: make test We are using the `black `_ formatter -for all the python files in this project. Be sure to run it locally on your +for all the Python files in this project. Be sure to run it locally on your files. To do so, just run:: black ihatemoney @@ -112,16 +112,16 @@ hook, for instance). As a designer / Front-end developer ----------------------------------- -Feel free to provide us mockups or to involve yourself into the discussions -hapenning on the github issue tracker. All ideas are welcome. Of course, if you +Feel free to provide mockups, or to involve yourself in the discussions +hapenning on the GitHub issue tracker. All ideas are welcome. Of course, if you know how to implement them, feel free to fork and make a pull request. As a translator --------------- If you're able to translate Ihatemoney in your own language, -head over to `the website we use for translations `_ -and start translating! +head over to `the website we use for translations `_ +and start translating. All the heavy lifting will be done automatically, and your strings will eventually be integrated. @@ -134,7 +134,7 @@ End-user You are using the application and found a bug? You have some ideas about how to improve the project? Please tell us `by filling a new issue `_. -Or, if you prefer, you can send me an email to `alexis@notmyidea.org` and I +Or, if you prefer, you can send me an e-mail to `alexis@notmyidea.org` and I will update the issue tracker with your feedback. Thanks again! @@ -150,7 +150,7 @@ Install doc dependencies (within the virtualenv, if any):: pip install -r docs/requirements.txt -And to produce html doc in `docs/_output` folder:: +And to produce a HTML doc in the `docs/_output` folder:: cd docs/ make html From 91ef80ebb712b06b6c48336beeb7f60219b0f062 Mon Sep 17 00:00:00 2001 From: Glandos Date: Sun, 12 Apr 2020 10:45:35 +0200 Subject: [PATCH 05/47] Fix spelling (#552) --- docs/contributing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index f35a3c8f..b053f8b6 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -113,7 +113,7 @@ As a designer / Front-end developer ----------------------------------- Feel free to provide mockups, or to involve yourself in the discussions -hapenning on the GitHub issue tracker. All ideas are welcome. Of course, if you +happening on the GitHub issue tracker. All ideas are welcome. Of course, if you know how to implement them, feel free to fork and make a pull request. As a translator From 026a0722357d74b143ed2d974ad2d871a56041b3 Mon Sep 17 00:00:00 2001 From: Andrew Dickinson Date: Mon, 20 Apr 2020 09:30:27 -0400 Subject: [PATCH 06/47] Add Project History Page (#553) Co-Authored-By: Glandos All project activity can be tracked, using SQLAlchemy-continuum. IP addresses can optionally be recorded. --- ihatemoney/forms.py | 35 +- ihatemoney/history.py | 139 ++++ .../versions/2dcb0c0048dc_autologger.py | 214 ++++++ .../cb038f79982e_sqlite_autoincrement.py | 50 ++ ihatemoney/models.py | 74 +- ihatemoney/patch_sqlalchemy_continuum.py | 138 ++++ ihatemoney/static/css/main.css | 44 +- ihatemoney/static/images/add.png | Bin 0 -> 264 bytes ihatemoney/static/images/x.svg | 8 + ihatemoney/static/js/ihatemoney.js | 4 + ihatemoney/templates/forms.html | 18 + ihatemoney/templates/history.html | 250 +++++++ ihatemoney/templates/layout.html | 1 + ihatemoney/tests/tests.py | 648 +++++++++++++++++- ihatemoney/utils.py | 25 +- ihatemoney/versioning.py | 94 +++ ihatemoney/web.py | 49 +- requirements.txt | 1 + setup.cfg | 1 + 19 files changed, 1783 insertions(+), 10 deletions(-) create mode 100644 ihatemoney/history.py create mode 100644 ihatemoney/migrations/versions/2dcb0c0048dc_autologger.py create mode 100644 ihatemoney/migrations/versions/cb038f79982e_sqlite_autoincrement.py create mode 100644 ihatemoney/patch_sqlalchemy_continuum.py create mode 100644 ihatemoney/static/images/add.png create mode 100644 ihatemoney/static/images/x.svg create mode 100644 ihatemoney/templates/history.html create mode 100644 ihatemoney/versioning.py diff --git a/ihatemoney/forms.py b/ihatemoney/forms.py index 62c21444..495eefa1 100644 --- a/ihatemoney/forms.py +++ b/ihatemoney/forms.py @@ -1,7 +1,7 @@ from flask_wtf.form import FlaskForm from wtforms.fields.core import SelectField, SelectMultipleField from wtforms.fields.html5 import DateField, DecimalField, URLField -from wtforms.fields.simple import PasswordField, SubmitField, StringField +from wtforms.fields.simple import PasswordField, SubmitField, StringField, BooleanField from wtforms.validators import ( Email, DataRequired, @@ -14,7 +14,7 @@ from flask_wtf.file import FileField, FileAllowed, FileRequired from flask_babel import lazy_gettext as _ from flask import request -from werkzeug.security import generate_password_hash +from werkzeug.security import generate_password_hash, check_password_hash from datetime import datetime from re import match @@ -22,7 +22,7 @@ from jinja2 import Markup import email_validator -from ihatemoney.models import Project, Person +from ihatemoney.models import Project, Person, LoggingMode from ihatemoney.utils import slugify, eval_arithmetic_expression @@ -89,6 +89,19 @@ class EditProjectForm(FlaskForm): name = StringField(_("Project name"), validators=[DataRequired()]) password = StringField(_("Private code"), validators=[DataRequired()]) contact_email = StringField(_("Email"), validators=[DataRequired(), Email()]) + project_history = BooleanField(_("Enable project history")) + ip_recording = BooleanField(_("Use IP tracking for project history")) + + @property + def logging_preference(self): + """Get the LoggingMode object corresponding to current form data.""" + if not self.project_history.data: + return LoggingMode.DISABLED + else: + if self.ip_recording.data: + return LoggingMode.RECORD_IP + else: + return LoggingMode.ENABLED def save(self): """Create a new project with the information given by this form. @@ -100,14 +113,20 @@ class EditProjectForm(FlaskForm): id=self.id.data, password=generate_password_hash(self.password.data), contact_email=self.contact_email.data, + logging_preference=self.logging_preference, ) return project def update(self, project): """Update the project with the information from the form""" project.name = self.name.data - project.password = generate_password_hash(self.password.data) + + # Only update password if changed to prevent spurious log entries + if not check_password_hash(project.password, self.password.data): + project.password = generate_password_hash(self.password.data) + project.contact_email = self.contact_email.data + project.logging_preference = self.logging_preference return project @@ -126,6 +145,14 @@ class ProjectForm(EditProjectForm): password = PasswordField(_("Private code"), validators=[DataRequired()]) submit = SubmitField(_("Create the project")) + def save(self): + # WTForms Boolean Fields don't insert the default value when the + # request doesn't include any value the way that other fields do, + # so we'll manually do it here + self.project_history.data = LoggingMode.default() != LoggingMode.DISABLED + self.ip_recording.data = LoggingMode.default() == LoggingMode.RECORD_IP + return super().save() + def validate_id(form, field): form.id.data = slugify(field.data) if (form.id.data == "dashboard") or Project.query.get(form.id.data): diff --git a/ihatemoney/history.py b/ihatemoney/history.py new file mode 100644 index 00000000..cda141e4 --- /dev/null +++ b/ihatemoney/history.py @@ -0,0 +1,139 @@ +from flask_babel import gettext as _ +from sqlalchemy_continuum import ( + Operation, + parent_class, +) + +from ihatemoney.models import ( + PersonVersion, + ProjectVersion, + BillVersion, + Person, +) + + +def get_history_queries(project): + """Generate queries for each type of version object for a given project.""" + person_changes = PersonVersion.query.filter_by(project_id=project.id) + + project_changes = ProjectVersion.query.filter_by(id=project.id) + + bill_changes = ( + BillVersion.query.with_entities(BillVersion.id.label("bill_version_id")) + .join(Person, BillVersion.payer_id == Person.id) + .filter(Person.project_id == project.id) + ) + sub_query = bill_changes.subquery() + bill_changes = BillVersion.query.filter(BillVersion.id.in_(sub_query)) + + return person_changes, project_changes, bill_changes + + +def history_sort_key(history_item_dict): + """ + Return the key necessary to sort history entries. First order sort is time + of modification, but for simultaneous modifications we make the re-name + modification occur last so that the simultaneous entries make sense using + the old name. + """ + second_order = 0 + if "prop_changed" in history_item_dict: + changed_property = history_item_dict["prop_changed"] + if changed_property == "name" or changed_property == "what": + second_order = 1 + + return history_item_dict["time"], second_order + + +def describe_version(version_obj): + """Use the base model str() function to describe a version object""" + return parent_class(type(version_obj)).__str__(version_obj) + + +def describe_owers_change(version, human_readable_names): + """Compute the set difference to get added/removed owers lists.""" + before_owers = {version.id: version for version in version.previous.owers} + after_owers = {version.id: version for version in version.owers} + + added_ids = set(after_owers).difference(set(before_owers)) + removed_ids = set(before_owers).difference(set(after_owers)) + + if not human_readable_names: + return added_ids, removed_ids + + added = [describe_version(after_owers[ower_id]) for ower_id in added_ids] + removed = [describe_version(before_owers[ower_id]) for ower_id in removed_ids] + + return added, removed + + +def get_history(project, human_readable_names=True): + """ + Fetch history for all models associated with a given project. + :param human_readable_names Whether to replace id numbers with readable names + :return A sorted list of dicts with history information + """ + person_query, project_query, bill_query = get_history_queries(project) + history = [] + for version_list in [person_query.all(), project_query.all(), bill_query.all()]: + for version in version_list: + object_type = { + "Person": _("Person"), + "Bill": _("Bill"), + "Project": _("Project"), + }[parent_class(type(version)).__name__] + + # Use the old name if applicable + if version.previous: + object_str = describe_version(version.previous) + else: + object_str = describe_version(version) + + common_properties = { + "time": version.transaction.issued_at.strftime("%Y-%m-%dT%H:%M:%SZ"), + "operation_type": version.operation_type, + "object_type": object_type, + "object_desc": object_str, + "ip": version.transaction.remote_addr, + } + + if version.operation_type == Operation.UPDATE: + # Only iterate the changeset if the previous version + # Was logged + if version.previous: + changeset = version.changeset + if isinstance(version, BillVersion): + if version.owers != version.previous.owers: + added, removed = describe_owers_change( + version, human_readable_names + ) + + if added: + changeset["owers_added"] = (None, added) + if removed: + changeset["owers_removed"] = (None, removed) + + for (prop, (val_before, val_after),) in changeset.items(): + if human_readable_names: + if prop == "payer_id": + prop = "payer" + if val_after is not None: + val_after = describe_version(version.payer) + if version.previous and val_before is not None: + val_before = describe_version( + version.previous.payer + ) + else: + val_after = None + + next_event = common_properties.copy() + next_event["prop_changed"] = prop + next_event["val_before"] = val_before + next_event["val_after"] = val_after + history.append(next_event) + else: + history.append(common_properties) + else: + history.append(common_properties) + + return sorted(history, key=history_sort_key, reverse=True) diff --git a/ihatemoney/migrations/versions/2dcb0c0048dc_autologger.py b/ihatemoney/migrations/versions/2dcb0c0048dc_autologger.py new file mode 100644 index 00000000..08008355 --- /dev/null +++ b/ihatemoney/migrations/versions/2dcb0c0048dc_autologger.py @@ -0,0 +1,214 @@ +"""autologger + +Revision ID: 2dcb0c0048dc +Revises: 6c6fb2b7f229 +Create Date: 2020-04-10 18:12:41.285590 + +""" + +# revision identifiers, used by Alembic. +revision = "2dcb0c0048dc" +down_revision = "6c6fb2b7f229" + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "bill_version", + sa.Column("id", sa.Integer(), autoincrement=False, nullable=False), + sa.Column("payer_id", sa.Integer(), autoincrement=False, nullable=True), + sa.Column("amount", sa.Float(), autoincrement=False, nullable=True), + sa.Column("date", sa.Date(), autoincrement=False, nullable=True), + sa.Column("creation_date", sa.Date(), autoincrement=False, nullable=True), + sa.Column("what", sa.UnicodeText(), autoincrement=False, nullable=True), + sa.Column( + "external_link", sa.UnicodeText(), autoincrement=False, nullable=True + ), + sa.Column("archive", sa.Integer(), autoincrement=False, nullable=True), + sa.Column( + "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False + ), + sa.Column("end_transaction_id", sa.BigInteger(), nullable=True), + sa.Column("operation_type", sa.SmallInteger(), nullable=False), + sa.PrimaryKeyConstraint("id", "transaction_id"), + ) + op.create_index( + op.f("ix_bill_version_end_transaction_id"), + "bill_version", + ["end_transaction_id"], + unique=False, + ) + op.create_index( + op.f("ix_bill_version_operation_type"), + "bill_version", + ["operation_type"], + unique=False, + ) + op.create_index( + op.f("ix_bill_version_transaction_id"), + "bill_version", + ["transaction_id"], + unique=False, + ) + op.create_table( + "billowers_version", + sa.Column("bill_id", sa.Integer(), autoincrement=False, nullable=False), + sa.Column("person_id", sa.Integer(), autoincrement=False, nullable=False), + sa.Column( + "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False + ), + sa.Column("end_transaction_id", sa.BigInteger(), nullable=True), + sa.Column("operation_type", sa.SmallInteger(), nullable=False), + sa.PrimaryKeyConstraint("bill_id", "person_id", "transaction_id"), + ) + op.create_index( + op.f("ix_billowers_version_end_transaction_id"), + "billowers_version", + ["end_transaction_id"], + unique=False, + ) + op.create_index( + op.f("ix_billowers_version_operation_type"), + "billowers_version", + ["operation_type"], + unique=False, + ) + op.create_index( + op.f("ix_billowers_version_transaction_id"), + "billowers_version", + ["transaction_id"], + unique=False, + ) + op.create_table( + "person_version", + sa.Column("id", sa.Integer(), autoincrement=False, nullable=False), + sa.Column( + "project_id", sa.String(length=64), autoincrement=False, nullable=True + ), + sa.Column("name", sa.UnicodeText(), autoincrement=False, nullable=True), + sa.Column("weight", sa.Float(), autoincrement=False, nullable=True), + sa.Column("activated", sa.Boolean(), autoincrement=False, nullable=True), + sa.Column( + "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False + ), + sa.Column("end_transaction_id", sa.BigInteger(), nullable=True), + sa.Column("operation_type", sa.SmallInteger(), nullable=False), + sa.PrimaryKeyConstraint("id", "transaction_id"), + ) + op.create_index( + op.f("ix_person_version_end_transaction_id"), + "person_version", + ["end_transaction_id"], + unique=False, + ) + op.create_index( + op.f("ix_person_version_operation_type"), + "person_version", + ["operation_type"], + unique=False, + ) + op.create_index( + op.f("ix_person_version_transaction_id"), + "person_version", + ["transaction_id"], + unique=False, + ) + op.create_table( + "project_version", + sa.Column("id", sa.String(length=64), autoincrement=False, nullable=False), + sa.Column("name", sa.UnicodeText(), autoincrement=False, nullable=True), + sa.Column( + "password", sa.String(length=128), autoincrement=False, nullable=True + ), + sa.Column( + "contact_email", sa.String(length=128), autoincrement=False, nullable=True + ), + sa.Column( + "logging_preference", + sa.Enum("DISABLED", "ENABLED", "RECORD_IP", name="loggingmode"), + server_default="ENABLED", + autoincrement=False, + nullable=True, + ), + sa.Column( + "transaction_id", sa.BigInteger(), autoincrement=False, nullable=False + ), + sa.Column("end_transaction_id", sa.BigInteger(), nullable=True), + sa.Column("operation_type", sa.SmallInteger(), nullable=False), + sa.PrimaryKeyConstraint("id", "transaction_id"), + ) + op.create_index( + op.f("ix_project_version_end_transaction_id"), + "project_version", + ["end_transaction_id"], + unique=False, + ) + op.create_index( + op.f("ix_project_version_operation_type"), + "project_version", + ["operation_type"], + unique=False, + ) + op.create_index( + op.f("ix_project_version_transaction_id"), + "project_version", + ["transaction_id"], + unique=False, + ) + op.create_table( + "transaction", + sa.Column("issued_at", sa.DateTime(), nullable=True), + sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False), + sa.Column("remote_addr", sa.String(length=50), nullable=True), + sa.PrimaryKeyConstraint("id"), + ) + op.add_column( + "project", + sa.Column( + "logging_preference", + sa.Enum("DISABLED", "ENABLED", "RECORD_IP", name="loggingmode"), + server_default="ENABLED", + nullable=False, + ), + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("project", "logging_preference") + op.drop_table("transaction") + op.drop_index( + op.f("ix_project_version_transaction_id"), table_name="project_version" + ) + op.drop_index( + op.f("ix_project_version_operation_type"), table_name="project_version" + ) + op.drop_index( + op.f("ix_project_version_end_transaction_id"), table_name="project_version" + ) + op.drop_table("project_version") + op.drop_index(op.f("ix_person_version_transaction_id"), table_name="person_version") + op.drop_index(op.f("ix_person_version_operation_type"), table_name="person_version") + op.drop_index( + op.f("ix_person_version_end_transaction_id"), table_name="person_version" + ) + op.drop_table("person_version") + op.drop_index( + op.f("ix_billowers_version_transaction_id"), table_name="billowers_version" + ) + op.drop_index( + op.f("ix_billowers_version_operation_type"), table_name="billowers_version" + ) + op.drop_index( + op.f("ix_billowers_version_end_transaction_id"), table_name="billowers_version" + ) + op.drop_table("billowers_version") + op.drop_index(op.f("ix_bill_version_transaction_id"), table_name="bill_version") + op.drop_index(op.f("ix_bill_version_operation_type"), table_name="bill_version") + op.drop_index(op.f("ix_bill_version_end_transaction_id"), table_name="bill_version") + op.drop_table("bill_version") + # ### end Alembic commands ### diff --git a/ihatemoney/migrations/versions/cb038f79982e_sqlite_autoincrement.py b/ihatemoney/migrations/versions/cb038f79982e_sqlite_autoincrement.py new file mode 100644 index 00000000..ae5ab326 --- /dev/null +++ b/ihatemoney/migrations/versions/cb038f79982e_sqlite_autoincrement.py @@ -0,0 +1,50 @@ +"""sqlite_autoincrement + +Revision ID: cb038f79982e +Revises: 2dcb0c0048dc +Create Date: 2020-04-13 17:40:02.426957 + +""" + +# revision identifiers, used by Alembic. +revision = "cb038f79982e" +down_revision = "2dcb0c0048dc" + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + alter_table_batches = [ + op.batch_alter_table( + "person", recreate="always", table_kwargs={"sqlite_autoincrement": True} + ), + op.batch_alter_table( + "bill", recreate="always", table_kwargs={"sqlite_autoincrement": True} + ), + op.batch_alter_table( + "billowers", recreate="always", table_kwargs={"sqlite_autoincrement": True} + ), + ] + + for batch_op in alter_table_batches: + with batch_op: + pass + + +def downgrade(): + alter_table_batches = [ + op.batch_alter_table( + "person", recreate="always", table_kwargs={"sqlite_autoincrement": False} + ), + op.batch_alter_table( + "bill", recreate="always", table_kwargs={"sqlite_autoincrement": False} + ), + op.batch_alter_table( + "billowers", recreate="always", table_kwargs={"sqlite_autoincrement": False} + ), + ] + + for batch_op in alter_table_batches: + with batch_op: + pass diff --git a/ihatemoney/models.py b/ihatemoney/models.py index 4d32fd97..d765c93d 100644 --- a/ihatemoney/models.py +++ b/ihatemoney/models.py @@ -1,6 +1,8 @@ from collections import defaultdict from datetime import datetime + +import sqlalchemy from flask_sqlalchemy import SQLAlchemy, BaseQuery from flask import g, current_app @@ -13,6 +15,40 @@ from itsdangerous import ( BadSignature, SignatureExpired, ) +from sqlalchemy_continuum import make_versioned +from sqlalchemy_continuum.plugins import FlaskPlugin +from sqlalchemy_continuum import version_class + +from ihatemoney.patch_sqlalchemy_continuum import PatchedBuilder +from ihatemoney.versioning import ( + LoggingMode, + ConditionalVersioningManager, + version_privacy_predicate, + get_ip_if_allowed, +) + + +make_versioned( + user_cls=None, + manager=ConditionalVersioningManager( + # Conditionally Disable the versioning based on each + # project's privacy preferences + tracking_predicate=version_privacy_predicate, + # Patch in a fix to a SQLAchemy-Continuum Bug. + # See patch_sqlalchemy_continuum.py + builder=PatchedBuilder(), + ), + plugins=[ + FlaskPlugin( + # Redirect to our own function, which respects user preferences + # on IP address collection + remote_addr_factory=get_ip_if_allowed, + # Suppress the plugin's attempt to grab a user id, + # which imports the flask_login module (causing an error) + current_user_id_factory=lambda: None, + ) + ], +) db = SQLAlchemy() @@ -22,11 +58,20 @@ class Project(db.Model): def get_by_name(self, name): return Project.query.filter(Project.name == name).one() + # Direct SQLAlchemy-Continuum to track changes to this model + __versioned__ = {} + id = db.Column(db.String(64), primary_key=True) name = db.Column(db.UnicodeText) password = db.Column(db.String(128)) contact_email = db.Column(db.String(128)) + logging_preference = db.Column( + db.Enum(LoggingMode), + default=LoggingMode.default(), + nullable=False, + server_default=LoggingMode.default().name, + ) members = db.relationship("Person", backref="project") query_class = ProjectQuery @@ -37,6 +82,7 @@ class Project(db.Model): "id": self.id, "name": self.name, "contact_email": self.contact_email, + "logging_preference": self.logging_preference.value, "members": [], } @@ -277,6 +323,9 @@ class Project(db.Model): return None return data["project_id"] + def __str__(self): + return self.name + def __repr__(self): return "" % self.name @@ -301,6 +350,11 @@ class Person(db.Model): query_class = PersonQuery + # Direct SQLAlchemy-Continuum to track changes to this model + __versioned__ = {} + + __table_args__ = {"sqlite_autoincrement": True} + id = db.Column(db.Integer, primary_key=True) project_id = db.Column(db.String(64), db.ForeignKey("project.id")) bills = db.relationship("Bill", backref="payer") @@ -337,8 +391,9 @@ class Person(db.Model): # We need to manually define a join table for m2m relations billowers = db.Table( "billowers", - db.Column("bill_id", db.Integer, db.ForeignKey("bill.id")), - db.Column("person_id", db.Integer, db.ForeignKey("person.id")), + db.Column("bill_id", db.Integer, db.ForeignKey("bill.id"), primary_key=True), + db.Column("person_id", db.Integer, db.ForeignKey("person.id"), primary_key=True), + sqlite_autoincrement=True, ) @@ -365,6 +420,11 @@ class Bill(db.Model): query_class = BillQuery + # Direct SQLAlchemy-Continuum to track changes to this model + __versioned__ = {} + + __table_args__ = {"sqlite_autoincrement": True} + id = db.Column(db.Integer, primary_key=True) payer_id = db.Column(db.Integer, db.ForeignKey("person.id")) @@ -403,6 +463,9 @@ class Bill(db.Model): else: return 0 + def __str__(self): + return "%s for %s" % (self.amount, self.what) + def __repr__(self): return "" % ( self.amount, @@ -426,3 +489,10 @@ class Archive(db.Model): def __repr__(self): return "" + + +sqlalchemy.orm.configure_mappers() + +PersonVersion = version_class(Person) +ProjectVersion = version_class(Project) +BillVersion = version_class(Bill) diff --git a/ihatemoney/patch_sqlalchemy_continuum.py b/ihatemoney/patch_sqlalchemy_continuum.py new file mode 100644 index 00000000..e0680c6a --- /dev/null +++ b/ihatemoney/patch_sqlalchemy_continuum.py @@ -0,0 +1,138 @@ +""" +A temporary work-around to patch SQLAlchemy-continuum per: +https://github.com/kvesteri/sqlalchemy-continuum/pull/242 + +Source code reproduced under their license: + + Copyright (c) 2012, Konsta Vesterinen + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * The names of the contributors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" + +import sqlalchemy as sa +from sqlalchemy_continuum import Operation +from sqlalchemy_continuum.builder import Builder +from sqlalchemy_continuum.expression_reflector import VersionExpressionReflector +from sqlalchemy_continuum.relationship_builder import RelationshipBuilder +from sqlalchemy_continuum.utils import option, adapt_columns + + +class PatchedRelationShipBuilder(RelationshipBuilder): + def association_subquery(self, obj): + """ + Returns an EXISTS clause that checks if an association exists for given + SQLAlchemy declarative object. This query is used by + many_to_many_criteria method. + + Example query: + + .. code-block:: sql + + EXISTS ( + SELECT 1 + FROM article_tag_version + WHERE article_id = 3 + AND tag_id = tags_version.id + AND operation_type != 2 + AND EXISTS ( + SELECT 1 + FROM article_tag_version as article_tag_version2 + WHERE article_tag_version2.tag_id = article_tag_version.tag_id + AND article_tag_version2.tx_id <=5 + AND article_tag_version2.article_id = 3 + GROUP BY article_tag_version2.tag_id + HAVING + MAX(article_tag_version2.tx_id) = + article_tag_version.tx_id + ) + ) + + :param obj: SQLAlchemy declarative object + """ + + tx_column = option(obj, "transaction_column_name") + join_column = self.property.primaryjoin.right.name + object_join_column = self.property.primaryjoin.left.name + reflector = VersionExpressionReflector(obj, self.property) + + association_table_alias = self.association_version_table.alias() + association_cols = [ + association_table_alias.c[association_col.name] + for _, association_col in self.remote_to_association_column_pairs + ] + + association_exists = sa.exists( + sa.select([1]) + .where( + sa.and_( + association_table_alias.c[tx_column] <= getattr(obj, tx_column), + association_table_alias.c[join_column] + == getattr(obj, object_join_column), + *[ + association_col + == self.association_version_table.c[association_col.name] + for association_col in association_cols + ] + ) + ) + .group_by(*association_cols) + .having( + sa.func.max(association_table_alias.c[tx_column]) + == self.association_version_table.c[tx_column] + ) + .correlate(self.association_version_table) + ) + return sa.exists( + sa.select([1]) + .where( + sa.and_( + reflector(self.property.primaryjoin), + association_exists, + self.association_version_table.c.operation_type != Operation.DELETE, + adapt_columns(self.property.secondaryjoin), + ) + ) + .correlate(self.local_cls, self.remote_cls) + ) + + +class PatchedBuilder(Builder): + def build_relationships(self, version_classes): + """ + Builds relationships for all version classes. + + :param version_classes: list of generated version classes + """ + for cls in version_classes: + if not self.manager.option(cls, "versioning"): + continue + + for prop in sa.inspect(cls).iterate_properties: + if prop.key == "versions": + continue + builder = PatchedRelationShipBuilder(self.manager, cls, prop) + builder() diff --git a/ihatemoney/static/css/main.css b/ihatemoney/static/css/main.css index fe8eec20..7d91c38d 100644 --- a/ihatemoney/static/css/main.css +++ b/ihatemoney/static/css/main.css @@ -326,7 +326,8 @@ footer .footer-left { } #bill_table, -#monthly_stats { +#monthly_stats, +#history_table { margin-top: 30px; margin-bottom: 30px; } @@ -363,6 +364,36 @@ footer .footer-left { background: url("../images/see.png") no-repeat right; } +.history_icon > .delete, +.history_icon > .add, +.history_icon > .edit { + font-size: 0px; + display: block; + width: 16px; + height: 16px; + margin: 2px; + margin-right: 10px; + margin-top: 3px; + float: left; +} + +.history_icon > .delete { + background: url("../images/delete.png") no-repeat right; +} + +.history_icon > .edit { + background: url("../images/edit.png") no-repeat right; +} + +.history_icon > .add { + background: url("../images/add.png") no-repeat right; +} + +.history_text { + display: table-cell; +} + + .balance .balance-value { text-align: right; } @@ -518,12 +549,23 @@ footer .icon svg { fill: white; } +.icon.icon-red { + fill: #dc3545; +} +.btn:hover .icon.icon-red { + fill: white !important; +} + /* align the first column */ #monthly_stats tr *:first-child { text-align: right; width: 200px; } +#history_warnings { + margin-top: 30px; +} + /* edit settings */ .edit-project form { diff --git a/ihatemoney/static/images/add.png b/ihatemoney/static/images/add.png new file mode 100644 index 0000000000000000000000000000000000000000..262891bf14eb8c2967317ad8694398745903f51c GIT binary patch literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zKpodXn9)gNb_Gz7y~NYkmHi0|w~&#r=$j2LK%uFgE{-73qGpx{W<)cpFi!#q6HF \ No newline at end of file diff --git a/ihatemoney/static/js/ihatemoney.js b/ihatemoney/static/js/ihatemoney.js index c240dc1a..9ffc8771 100644 --- a/ihatemoney/static/js/ihatemoney.js +++ b/ihatemoney/static/js/ihatemoney.js @@ -5,3 +5,7 @@ function selectCheckboxes(value){ els[i].checked = value; } } + +function localizeTime(utcTimestamp) { + return new Date(utcTimestamp).toLocaleString() +} diff --git a/ihatemoney/templates/forms.html b/ihatemoney/templates/forms.html index bec70184..33a283f2 100644 --- a/ihatemoney/templates/forms.html +++ b/ihatemoney/templates/forms.html @@ -20,6 +20,16 @@ {% endmacro %} +{% macro checkbox(field) %} +
+ {{ field(id=field.name) }} + + {% if field.description %} + {{ field.description }} + {% endif %} +
+{% endmacro %} + {% macro submit(field, cancel=False, home=False) -%}
@@ -78,6 +88,14 @@ {{ input(form.name) }} {{ input(form.password) }} {{ input(form.contact_email) }} +
+ +
+ {{ checkbox(form.project_history) }} + {{ checkbox(form.ip_recording) }} +
+
+
{{ _("delete") }} diff --git a/ihatemoney/templates/history.html b/ihatemoney/templates/history.html new file mode 100644 index 00000000..875040e4 --- /dev/null +++ b/ihatemoney/templates/history.html @@ -0,0 +1,250 @@ +{% extends "sidebar_table_layout.html" %} + +{% macro change_to_logging_preference(event) %} +{% if event.val_after == LoggingMode.DISABLED %} + {% if event.val_before == LoggingMode.ENABLED %} + {{ _("Disabled Project History") }} + {% else %} + {{ _("Disabled Project History & IP Address Recording") }} + {% endif %} +{% elif event.val_after == LoggingMode.ENABLED %} + {% if event.val_before == LoggingMode.DISABLED %} + {{ _("Enabled Project History") }} + {% elif event.val_before == LoggingMode.RECORD_IP %} + {{ _("Disabled IP Address Recording") }} + {% else %} + {{ _("Enabled Project History") }} + {% endif %} +{% elif event.val_after == LoggingMode.RECORD_IP %} + {% if event.val_before == LoggingMode.DISABLED %} + {{ _("Enabled Project History & IP Address Recording") }} + {% elif event.val_before == LoggingMode.ENABLED %} + {{ _("Enabled IP Address Recording") }} + {% else %} + {{ _("Enabled Project History & IP Address Recording") }} + {% endif %} +{% else %} + {# Should be unreachable #} + {{ _("History Settings Changed") }} +{% endif %} +{% endmacro %} + +{% macro describe_object(event) %}{{ event.object_type }} {{ event.object_desc }}{% endmacro %} + +{% macro simple_property_change(event, localized_property_name, from=True) %} + {{ describe_object(event) }}: + {{ localized_property_name }} {{ _("changed") }} + {% if from %}{{ _("from") }} {{ event.val_before }}{% endif %} + {{ _("to") }} {{ event.val_after }} +{% endmacro %} + +{% macro clear_history_modals() %} + + + + +{% endmacro %} + +{% macro owers_changed(event, add) %} + {{ describe_object(event) }}: {% if add %}{{ _("Added") }}{% else %}{{ _("Removed") }}{% endif %} + {% if event.val_after|length > 1 %} + {% for name in event.val_after %} + {{ name }}{% if event.val_after|length > 2 and loop.index != event.val_after|length %},{% endif %} + {% if loop.index == event.val_after|length - 1 %} {{ _("and") }} {% endif %} + {% endfor %} + {% else %} + {{ event.val_after[0] }} + {% endif %} + {% if add %}{{ _("to") }}{% else %}{{ _("from") }}{% endif %} + {{ _("owers list") }} +{% endmacro %} + +{% block sidebar %} +
+ + + + + + + + {% set balance = g.project.balance %} + {% for member in g.project.members | sort(attribute='name') if member.activated or balance[member.id]|round(2) != 0 %} + + + + + {% endfor %} +
{{ _("Who?") }}{{ _("Balance") }}
{{ member.name }} + {% if balance[member.id]|round(2) > 0 %}+{% endif %}{{ "%.2f" | format(balance[member.id]) }} +
+
+{% endblock %} + + + +{% block content %} + {% if current_log_pref == LoggingMode.DISABLED or (current_log_pref != LoggingMode.RECORD_IP and any_ip_addresses) %} +
+ {% if current_log_pref == LoggingMode.DISABLED %} +

+ {{ _("This project has history disabled. New actions won't appear below. You can enable history on the") }} + {{ _("settings page") }} +

+ {% if history %} +

{{ _("The table below reflects actions recorded prior to disabling project history. You can ") }} + {{ _("clear project history") }} {{ _("to remove them.") }}

+ {% endif %} + {% endif %} + {% if current_log_pref != LoggingMode.RECORD_IP and any_ip_addresses %} +

{{ _("Some entries below contain IP addresses, even though this project has IP recording disabled. ") }} + {{ _("Delete stored IP addresses") }}

+ {% endif %} +
+ {% endif %} + {{ clear_history_modals() }} + + + {{ static_include("images/x.svg") | safe }} + {{ _("Clear Project History") }} + + + + + {{ static_include("images/x.svg") | safe }} + {{ _("Delete Stored IP Addresses") }} + + + +
+ {% if history %} + + + + + + + + {% for event in history %} + + + + + + {% endfor %} + +
{{ _("Time") }}{{ _("Event") }} + + {{ _("From IP") }}
+
+ +
+
+ {% if event.operation_type == OperationType.INSERT %} + {{ event.object_type }} {{ event.object_desc }} {{ _("added") }} + {% elif event.operation_type == OperationType.UPDATE %} + {% if event.object_type == _("Project") %} + {% if event.prop_changed == "password" %} + {{ _("Project private code changed") }} + {% elif event.prop_changed == "logging_preference" %} + {{ change_to_logging_preference(event) }} + {% elif event.prop_changed == "name" %} + {{ _("Project renamed to") }} {{ event.val_after }} + {% elif event.prop_changed == "contact_email" %} + {{ _("Project contact email changed to") }} {{ event.val_after }} + {% else %} + {{ _("Project settings modified") }} + {% endif %} + {% elif event.prop_changed == "activated" %} + {{ event.object_type }} {{ event.object_desc }} + {% if event.val_after == False %}{{ _("deactivated") }}{% else %}{{ _("reactivated") }}{% endif %} + {% elif event.prop_changed == "name" or event.prop_changed == "what" %} + {{ describe_object(event) }} {{ _("renamed") }} {{ _("to") }} {{ event.val_after }} + {% elif event.prop_changed == "weight" %} + {{ simple_property_change(event, _("Weight")) }} + {% elif event.prop_changed == "external_link" %} + {{ describe_object(event) }}: {{ _("External link changed to") }} + {{ event.val_after }} + {% elif event.prop_changed == "owers_added" %} + {{ owers_changed(event, True)}} + {% elif event.prop_changed == "owers_removed" %} + {{ owers_changed(event, False)}} + {% elif event.prop_changed == "payer" %} + {{ simple_property_change(event, _("Payer"))}} + {% elif event.prop_changed == "amount" %} + {{ simple_property_change(event, _("Amount")) }} + {% elif event.prop_changed == "date" %} + {{ simple_property_change(event, _("Date")) }} + {% else %} + {{ describe_object(event) }} {{ _("modified") }} + {% endif %} + {% elif event.operation_type == OperationType.DELETE %} + {{ event.object_type }} {{ event.object_desc }} {{ _("removed") }} + {% else %} + {# Should be unreachable #} + {{ describe_object(event) }} {{ _("changed in a unknown way") }} + {% endif %} +
+
{% if event.ip %}{{ event.ip }}{% else %} -- {% endif %}
+ {% else %} +
+
+
+ {{ static_include("images/hand-holding-heart.svg") | safe }} +

{{ _('Nothing to list')}}

+

+ {{ _("Someone probably") }}
+ {{ _("cleared the project history.") }} +

+
+
+ {% endif %} + +{% endblock %} diff --git a/ihatemoney/templates/layout.html b/ihatemoney/templates/layout.html index 8609779c..eaf13a6e 100644 --- a/ihatemoney/templates/layout.html +++ b/ihatemoney/templates/layout.html @@ -45,6 +45,7 @@ + {% endblock %} {% endif %} diff --git a/ihatemoney/tests/tests.py b/ihatemoney/tests/tests.py index c4b1585c..5dff64d9 100644 --- a/ihatemoney/tests/tests.py +++ b/ihatemoney/tests/tests.py @@ -17,7 +17,8 @@ from flask_testing import TestCase from ihatemoney.run import create_app, db, load_configuration from ihatemoney.manage import GenerateConfig, GeneratePasswordHash, DeleteProject -from ihatemoney import models +from ihatemoney import models, history +from ihatemoney.versioning import LoggingMode from ihatemoney import utils from sqlalchemy import orm @@ -843,6 +844,7 @@ class BudgetTestCase(IhatemoneyTestCase): "name": "Super raclette party!", "contact_email": "alexis@notmyidea.org", "password": "didoudida", + "logging_preference": LoggingMode.ENABLED.value, } resp = self.client.post("/raclette/edit", data=new_data, follow_redirects=True) @@ -1517,6 +1519,7 @@ class APITestCase(IhatemoneyTestCase): "name": "raclette", "contact_email": "raclette@notmyidea.org", "id": "raclette", + "logging_preference": 1, } decoded_resp = json.loads(resp.data.decode("utf-8")) self.assertDictEqual(decoded_resp, expected) @@ -1528,6 +1531,7 @@ class APITestCase(IhatemoneyTestCase): "contact_email": "yeah@notmyidea.org", "password": "raclette", "name": "The raclette party", + "project_history": "y", }, headers=self.get_auth("raclette"), ) @@ -1544,6 +1548,7 @@ class APITestCase(IhatemoneyTestCase): "contact_email": "yeah@notmyidea.org", "members": [], "id": "raclette", + "logging_preference": 1, } decoded_resp = json.loads(resp.data.decode("utf-8")) self.assertDictEqual(decoded_resp, expected) @@ -2104,12 +2109,32 @@ class APITestCase(IhatemoneyTestCase): "contact_email": "raclette@notmyidea.org", "id": "raclette", "name": "raclette", + "logging_preference": 1, } 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", "alexis") + + resp = self.client.get("/raclette/history", follow_redirects=True) + self.assertEqual(resp.status_code, 200) + self.assertIn( + "Person %s added" % em_surround("alexis"), resp.data.decode("utf-8") + ) + self.assertIn( + "Project %s added" % em_surround("raclette"), resp.data.decode("utf-8"), + ) + self.assertEqual(resp.data.decode("utf-8").count(" -- "), 2) + self.assertNotIn("127.0.0.1", resp.data.decode("utf-8")) + class ServerTestCase(IhatemoneyTestCase): def test_homepage(self): @@ -2224,5 +2249,626 @@ class ModelsTestCase(IhatemoneyTestCase): self.assertEqual(bill.pay_each(), pay_each_expected) +def em_surround(string, regex_escape=False): + if regex_escape: + return r'%s<\/em>' % string + else: + return '%s' % string + + +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( + "Project %s added" % em_surround("demo"), resp.data.decode("utf-8"), + ) + self.assertEqual(resp.data.decode("utf-8").count(" -- "), 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", + } + + 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(' -- ", resp.data.decode("utf-8")) + self.assertNotIn( + "Project %s added" % em_surround("demo"), resp.data.decode("utf-8") + ) + + def test_project_edit(self): + new_data = { + "name": "demo2", + "contact_email": "demo2@notmyidea.org", + "password": "123456", + "project_history": "y", + } + + 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( + "Project %s added" % em_surround("demo"), resp.data.decode("utf-8") + ) + self.assertIn( + "Project contact email changed to %s" % em_surround("demo2@notmyidea.org"), + resp.data.decode("utf-8"), + ) + self.assertIn( + "Project private code changed", resp.data.decode("utf-8"), + ) + self.assertIn( + "Project renamed to %s" % 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(" -- "), 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( + '', + 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(" -- "), 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(" -- "), 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(" -- "), 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(" -- "), 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(" -- "), 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(" -- "), 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", + } + + # 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": "alexis"}, 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( + "/demo/edit/%i" % 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("/demo/delete/%i" % bill_id, follow_redirects=True) + self.assertEqual(resp.status_code, 200) + + # delete user using POST method + resp = self.client.post( + "/demo/members/%i/delete" % user_id, 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(" -- "), 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(" -- "), 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(" -- "), 16) + + def test_logs_for_common_actions(self): + # adds a member to this project + resp = self.client.post( + "/demo/members/add", data={"name": "alexis"}, follow_redirects=True + ) + self.assertEqual(resp.status_code, 200) + + resp = self.client.get("/demo/history") + self.assertEqual(resp.status_code, 200) + self.assertIn( + "Person %s added" % em_surround("alexis"), 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( + "Bill %s added" % em_surround("25.0 for fromage à raclette"), + 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( + "Bill %s added" % em_surround("25.0 for fromage à raclette"), + 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("25.0 for 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("25.0 for fromage à raclette"), em_surround("new thing"),), + resp.data.decode("utf-8"), + ) + self.assertLess( + resp.data.decode("utf-8").index( + "Bill %s renamed to" % em_surround("25.0 for fromage à raclette") + ), + 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( + "Bill %s removed" % em_surround("10.0 for new thing"), + 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"Person %s:\s* Weight changed\s* from %s\s* to %s" + % ( + em_surround("alexis", regex_escape=True), + em_surround("1.0", regex_escape=True), + em_surround("2.0", regex_escape=True), + ), + ) + self.assertIn( + "Person %s renamed to %s" + % (em_surround("alexis"), em_surround("new name"),), + resp.data.decode("utf-8"), + ) + self.assertLess( + resp.data.decode("utf-8").index( + "Person %s renamed" % em_surround("alexis") + ), + 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( + "Person %s removed" % em_surround("new name"), 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(" -- "), 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:\s* Amount changed\s* from %s\s* to %s" + % ( + em_surround("25.0 for 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\s* and\s* %s\s* from\s* owers list" + % ( + 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(" -- "), 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(" -- "), 5) + self.assertNotIn("127.0.0.1", resp.data.decode("utf-8")) + self.assertIn( + "Bill %s added" % em_surround("25.0 for Bill 1"), resp.data.decode("utf-8") + ) + self.assertIn( + "Bill %s removed" % em_surround("25.0 for Bill 1"), + 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(" -- "), 6) + self.assertNotIn("127.0.0.1", resp.data.decode("utf-8")) + self.assertIn( + "Bill %s added" % em_surround("25.0 for Bill 1"), resp.data.decode("utf-8") + ) + self.assertEqual( + resp.data.decode("utf-8").count( + "Bill %s added" % em_surround("25.0 for Bill 1") + ), + 1, + ) + self.assertIn( + "Bill %s added" % em_surround("20.0 for Bill 2"), resp.data.decode("utf-8") + ) + self.assertIn( + "Bill %s removed" % em_surround("25.0 for Bill 1"), + 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() diff --git a/ihatemoney/utils.py b/ihatemoney/utils.py index 126b9dee..0641d1c4 100644 --- a/ihatemoney/utils.py +++ b/ihatemoney/utils.py @@ -2,6 +2,7 @@ import re import os import ast import operator +from enum import Enum from io import BytesIO, StringIO @@ -12,7 +13,6 @@ from babel import Locale from werkzeug.routing import HTTPException, RoutingException from datetime import datetime, timedelta - import csv @@ -257,3 +257,26 @@ def same_bill(bill1, bill2): if bill1[a] != bill2[a]: return False return True + + +class FormEnum(Enum): + """Extend builtin Enum class to be seamlessly compatible with WTForms""" + + @classmethod + def choices(cls): + return [(choice, choice.name) for choice in cls] + + @classmethod + def coerce(cls, item): + """Coerce a str or int representation into an Enum object""" + if isinstance(item, cls): + return item + + # If item is not already a Enum object then it must be + # a string or int corresponding to an ID (e.g. '0' or 1) + # Either int() or cls() will correctly throw a TypeError if this + # is not the case + return cls(int(item)) + + def __str__(self): + return str(self.value) diff --git a/ihatemoney/versioning.py b/ihatemoney/versioning.py new file mode 100644 index 00000000..50ad6ec8 --- /dev/null +++ b/ihatemoney/versioning.py @@ -0,0 +1,94 @@ +from flask import g +from sqlalchemy.orm.attributes import get_history +from sqlalchemy_continuum import VersioningManager +from sqlalchemy_continuum.plugins.flask import fetch_remote_addr + +from ihatemoney.utils import FormEnum + + +class LoggingMode(FormEnum): + """Represents a project's history preferences.""" + + DISABLED = 0 + ENABLED = 1 + RECORD_IP = 2 + + @classmethod + def default(cls): + return cls.ENABLED + + +class ConditionalVersioningManager(VersioningManager): + """Conditionally enable version tracking based on the given predicate.""" + + def __init__(self, tracking_predicate, *args, **kwargs): + """Create version entry iff tracking_predicate() returns True.""" + super().__init__(*args, **kwargs) + self.tracking_predicate = tracking_predicate + + def before_flush(self, session, flush_context, instances): + if self.tracking_predicate(): + return super().before_flush(session, flush_context, instances) + else: + # At least one call to unit_of_work() needs to be made against the + # session object to prevent a KeyError later. This doesn't create + # a version or transaction entry + self.unit_of_work(session) + + def after_flush(self, session, flush_context): + if self.tracking_predicate(): + return super().after_flush(session, flush_context) + else: + # At least one call to unit_of_work() needs to be made against the + # session object to prevent a KeyError later. This doesn't create + # a version or transaction entry + self.unit_of_work(session) + + +def version_privacy_predicate(): + """Evaluate if the project of the current session has enabled logging.""" + logging_enabled = False + try: + if g.project.logging_preference != LoggingMode.DISABLED: + logging_enabled = True + + # If logging WAS enabled prior to this transaction, + # we log this one last transaction + old_logging_mode = get_history(g.project, "logging_preference")[2] + if old_logging_mode and old_logging_mode[0] != LoggingMode.DISABLED: + logging_enabled = True + except AttributeError: + # g.project doesn't exist, it's being created or this action is outside + # the scope of a project. Use the default logging mode to decide + if LoggingMode.default() != LoggingMode.DISABLED: + logging_enabled = True + return logging_enabled + + +def get_ip_if_allowed(): + """ + Get the remote address (IP address) of the current Flask context, if the + project's privacy settings allow it. Behind the scenes, this calls back to + the FlaskPlugin from SQLAlchemy-Continuum in order to maintain forward + compatibility + """ + ip_logging_allowed = False + try: + if g.project.logging_preference == LoggingMode.RECORD_IP: + ip_logging_allowed = True + + # If ip recording WAS enabled prior to this transaction, + # we record the IP for this one last transaction + old_logging_mode = get_history(g.project, "logging_preference")[2] + if old_logging_mode and old_logging_mode[0] == LoggingMode.RECORD_IP: + ip_logging_allowed = True + except AttributeError: + # g.project doesn't exist, it's being created or this action is outside + # the scope of a project. Use the default logging mode to decide + if LoggingMode.default() == LoggingMode.RECORD_IP: + ip_logging_allowed = True + + if ip_logging_allowed: + return fetch_remote_addr() + else: + return None diff --git a/ihatemoney/web.py b/ihatemoney/web.py index 8e0bca6c..744d1bfa 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -31,6 +31,7 @@ from flask import ( from flask_babel import get_locale, gettext as _ from flask_mail import Message from sqlalchemy import orm +from sqlalchemy_continuum import Operation from werkzeug.exceptions import NotFound from werkzeug.security import check_password_hash, generate_password_hash @@ -46,7 +47,8 @@ from ihatemoney.forms import ( get_billform_for, UploadForm, ) -from ihatemoney.models import db, Project, Person, Bill +from ihatemoney.history import get_history_queries, get_history +from ihatemoney.models import db, Project, Person, Bill, LoggingMode from ihatemoney.utils import ( Redirect303, list_of_dicts2json, @@ -404,6 +406,12 @@ def edit_project(): return redirect(url_for("main.list_bills")) else: edit_form.name.data = g.project.name + + if g.project.logging_preference != LoggingMode.DISABLED: + edit_form.project_history.data = True + if g.project.logging_preference == LoggingMode.RECORD_IP: + edit_form.ip_recording.data = True + edit_form.contact_email.data = g.project.contact_email return render_template( @@ -742,6 +750,45 @@ def settle_bill(): return render_template("settle_bills.html", bills=bills, current_view="settle_bill") +@main.route("//history") +def history(): + """Query for the version entries associated with this project.""" + history = get_history(g.project, human_readable_names=True) + + any_ip_addresses = any(event["ip"] for event in history) + + return render_template( + "history.html", + current_view="history", + history=history, + any_ip_addresses=any_ip_addresses, + LoggingMode=LoggingMode, + OperationType=Operation, + current_log_pref=g.project.logging_preference, + ) + + +@main.route("//erase_history", methods=["POST"]) +def erase_history(): + """Erase all history entries associated with this project.""" + for query in get_history_queries(g.project): + query.delete(synchronize_session="fetch") + + db.session.commit() + return redirect(url_for(".history")) + + +@main.route("//strip_ip_addresses", methods=["POST"]) +def strip_ip_addresses(): + """Strip ip addresses from history entries associated with this project.""" + for query in get_history_queries(g.project): + for version_object in query.all(): + version_object.transaction.remote_addr = None + + db.session.commit() + return redirect(url_for(".history")) + + @main.route("//statistics") def statistics(): """Compute what each member has paid and spent and display it""" diff --git a/requirements.txt b/requirements.txt index 27280428..d6893e84 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,5 +23,6 @@ MarkupSafe==1.1.1 python-dateutil==2.8.0 pytz==2019.2 SQLAlchemy==1.3.8 +SQLAlchemy-Continuum==1.3.9 Werkzeug==0.16.0 WTForms==2.2.1 diff --git a/setup.cfg b/setup.cfg index b62a3f57..8d334e80 100644 --- a/setup.cfg +++ b/setup.cfg @@ -25,6 +25,7 @@ install_requires = flask flask-wtf flask-sqlalchemy<3.0 + SQLAlchemy-Continuum flask-mail Flask-Migrate Flask-script From 5d3266873eb4892dc2e5b9da499532d1ad013197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Tue, 21 Apr 2020 10:30:13 +0200 Subject: [PATCH 07/47] Update known working set. (#558) * Update known working set. * Pin dependencies in setup.cfg. * Cleanup Makefile. * Try the python_version trick. --- .travis.yml | 1 + CHANGELOG.rst | 2 +- MANIFEST.in | 2 +- Makefile | 19 ++++++------------- dev-requirements.txt | 6 ------ docs/contributing.rst | 6 ++---- requirements.txt | 28 ---------------------------- setup.cfg | 42 ++++++++++++++++++++++-------------------- tox.ini | 12 ++++-------- 9 files changed, 37 insertions(+), 81 deletions(-) delete mode 100644 dev-requirements.txt delete mode 100644 requirements.txt diff --git a/.travis.yml b/.travis.yml index c18d65f8..b3753ea0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ python: - "3.5" - "3.6" - "3.7" + - "3.8" script: tox install: - pip install tox-travis diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 76831ccb..e4ecb923 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,7 +9,7 @@ This document describes changes between each past release. - Add support for espanol latino america (es_419) - Use the external debts lib to solve settlements (#476) - Remove balance column in statistics view (#323) - +- Remove requirements files in favor of setup.cfg pinning (#558) 4.1.3 (2019-09-18) ================== diff --git a/MANIFEST.in b/MANIFEST.in index 74ea23b1..d47086be 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ include *.rst recursive-include ihatemoney *.rst *.py *.yaml *.po *.mo *.html *.css *.js *.eot *.svg *.woff *.txt *.png *.ini *.cfg *.j2 -include LICENSE CONTRIBUTORS CHANGELOG.rst requirements.txt +include LICENSE CONTRIBUTORS CHANGELOG.rst diff --git a/Makefile b/Makefile index 42b0e263..ae9e46c1 100644 --- a/Makefile +++ b/Makefile @@ -11,10 +11,10 @@ ZOPFLIPNG := zopflipng .PHONY: all all: install ## Alias for install .PHONY: install -install: virtualenv $(INSTALL_STAMP) ## Install dependencies -$(INSTALL_STAMP): +install: setup.cfg $(INSTALL_STAMP) ## Install dependencies +$(INSTALL_STAMP): virtualenv $(VENV)/bin/pip install -U pip - $(VENV)/bin/pip install -r requirements.txt + $(VENV)/bin/pip install -e . touch $(INSTALL_STAMP) .PHONY: virtualenv @@ -23,9 +23,9 @@ $(PYTHON): $(VIRTUALENV) $(VENV) .PHONY: install-dev -install-dev: $(INSTALL_STAMP) $(DEV_STAMP) ## Install development dependencies -$(DEV_STAMP): $(PYTHON) dev-requirements.txt - $(VENV)/bin/pip install -Ur dev-requirements.txt +install-dev: setup.cfg $(INSTALL_STAMP) $(DEV_STAMP) ## Install development dependencies +$(DEV_STAMP): $(PYTHON) + $(VENV)/bin/pip install -Ue .[dev] touch $(DEV_STAMP) .PHONY: remove-install-stamp @@ -76,13 +76,6 @@ create-empty-database-revision: ## Create an empty database revision @read -p "Please enter a message describing this revision: " rev_message; \ $(PYTHON) -m ihatemoney.manage db revision -d ihatemoney/migrations -m "$${rev_message}" -.PHONY: build-requirements -build-requirements: ## Save currently installed packages to requirements.txt - $(VIRTUALENV) $(TEMPDIR) - $(TEMPDIR)/bin/pip install -U pip - $(TEMPDIR)/bin/pip install -Ue "." - $(TEMPDIR)/bin/pip freeze | grep -v -- '-e' > requirements.txt - .PHONY: clean clean: ## Destroy the virtual environment rm -rf .venv diff --git a/dev-requirements.txt b/dev-requirements.txt deleted file mode 100644 index 9163cf81..00000000 --- a/dev-requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -zest.releaser -tox -pytest -flake8 -Flask-Testing -black ; python_version >= '3.6' diff --git a/docs/contributing.rst b/docs/contributing.rst index b053f8b6..5cff063b 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -2,7 +2,7 @@ Contributing ############ Set up a dev environment -======================= +======================== You must develop on top of the Git master branch:: @@ -23,10 +23,8 @@ install dependencies, and run the test server. The hard way ------------ -Alternatively, you can also use the `requirements.txt` file to install the -dependencies yourself. That would be:: +Alternatively, you can use pip to install dependencies yourself. That would be:: - pip install -r requirements.txt pip install -e . And then run the application:: diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index d6893e84..00000000 --- a/requirements.txt +++ /dev/null @@ -1,28 +0,0 @@ -alembic==1.2.0 -aniso8601==8.0.0 -Babel==2.7.0 -blinker==1.4 -Click==7.0 -debts==0.4 -dnspython==1.16.0 -email-validator==1.0.4 -Flask==1.1.1 -Flask-Babel==0.12.2 -Flask-Cors==3.0.8 -Flask-Mail==0.9.1 -Flask-Migrate==2.5.2 -Flask-RESTful==0.3.7 -Flask-Script==2.0.6 -Flask-SQLAlchemy==2.4.1 -Flask-WTF==0.14.2 -idna==2.8 -itsdangerous==1.1.0 -Jinja2==2.10.1 -Mako==1.1.0 -MarkupSafe==1.1.1 -python-dateutil==2.8.0 -pytz==2019.2 -SQLAlchemy==1.3.8 -SQLAlchemy-Continuum==1.3.9 -Werkzeug==0.16.0 -WTForms==2.2.1 diff --git a/setup.cfg b/setup.cfg index 8d334e80..571f538b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -14,6 +14,7 @@ classifiers = Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 Topic :: Internet :: WWW/HTTP Topic :: Internet :: WWW/HTTP :: WSGI :: Application @@ -22,29 +23,30 @@ packages = find: include_package_data = True zip_safe = False install_requires = - flask - flask-wtf - flask-sqlalchemy<3.0 - SQLAlchemy-Continuum - flask-mail - Flask-Migrate - Flask-script - flask-babel - flask-restful - jinja2 - blinker - flask-cors - itsdangerous - email_validator - debts + blinker==1.4 + debts==0.5 + email_validator==1.0.5 + Flask-Babel==1.0.0 + Flask-Cors==3.0.8 + Flask-Mail==0.9.1 + Flask-Migrate==2.5.3 + Flask-RESTful==0.3.8 + Flask-Script==2.0.6 + Flask-SQLAlchemy==2.4.1 + Flask-WTF==0.14.3 + Flask==1.1.2 + itsdangerous==1.1.0 + Jinja2==2.11.2 + SQLAlchemy-Continuum==1.3.9 [options.extras_require] dev = - zest.releaser - tox - pytest - flake8 - Flask-Testing + black==19.10b0 ; python_version >= '3.6' + flake8==3.7.9 + Flask-Testing==0.8.0 + pytest==5.4.1 + tox==3.14.6 + zest.releaser==6.20.1 [options.entry_points] console_scripts = diff --git a/tox.ini b/tox.ini index 5e6d5e42..b5ff7055 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py37,py36,py35,docs,flake8,black +envlist = py38,py37,py36,py35,docs,flake8,black skip_missing_interpreters = True [testenv] @@ -9,8 +9,7 @@ commands = py.test --pyargs ihatemoney.tests.tests deps = - -rdev-requirements.txt - -rrequirements.txt + -e.[dev] # To be sure we are importing ihatemoney pkg from pip-installed version changedir = /tmp @@ -23,14 +22,10 @@ changedir = {toxinidir} [testenv:black] commands = black --check --target-version=py34 . -deps = - -rdev-requirements.txt changedir = {toxinidir} [testenv:flake8] commands = flake8 ihatemoney -deps = - -rdev-requirements.txt changedir = {toxinidir} [flake8] @@ -43,5 +38,6 @@ extend-ignore = [travis] python = 3.5: py35 - 3.6: py36, docs, black, flake8 + 3.6: py36 3.7: py37 + 3.8: py38, docs, black, flake8 From 5efb158938efadd663154458389549d5e2767d01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Tue, 21 Apr 2020 10:34:04 +0200 Subject: [PATCH 08/47] Update docs requirements sphinx and docutils. --- docs/requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 75b31607..3cfd193c 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,2 +1,2 @@ -Sphinx==1.5.5 -docutils==0.13.1 +Sphinx==3.0.2 +docutils==0.16 From f0b40578adeca5e9fc75787c00787c20f1072144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Tue, 21 Apr 2020 11:15:35 +0200 Subject: [PATCH 09/47] Fix makefile --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index ae9e46c1..d21a1cf9 100644 --- a/Makefile +++ b/Makefile @@ -11,8 +11,8 @@ ZOPFLIPNG := zopflipng .PHONY: all all: install ## Alias for install .PHONY: install -install: setup.cfg $(INSTALL_STAMP) ## Install dependencies -$(INSTALL_STAMP): virtualenv +install: virtualenv setup.cfg $(INSTALL_STAMP) ## Install dependencies +$(INSTALL_STAMP): $(VENV)/bin/pip install -U pip $(VENV)/bin/pip install -e . touch $(INSTALL_STAMP) @@ -23,7 +23,7 @@ $(PYTHON): $(VIRTUALENV) $(VENV) .PHONY: install-dev -install-dev: setup.cfg $(INSTALL_STAMP) $(DEV_STAMP) ## Install development dependencies +install-dev: virtualenv setup.cfg $(INSTALL_STAMP) $(DEV_STAMP) ## Install development dependencies $(DEV_STAMP): $(PYTHON) $(VENV)/bin/pip install -Ue .[dev] touch $(DEV_STAMP) From 299c64a48cb6278eebe1d7cc54d878953ecc5fa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Tue, 21 Apr 2020 13:59:41 +0200 Subject: [PATCH 10/47] Add isort support. (#561) --- .isort.cfg | 13 ++++++++++ Makefile | 12 ++++++++-- docs/conf.py | 3 ++- ihatemoney/api/common.py | 11 +++++---- ihatemoney/api/v1/resources.py | 14 +++++------ ihatemoney/forms.py | 30 +++++++++++------------- ihatemoney/history.py | 12 ++-------- ihatemoney/manage.py | 6 ++--- ihatemoney/models.py | 24 ++++++++----------- ihatemoney/patch_sqlalchemy_continuum.py | 2 +- ihatemoney/run.py | 7 +++--- ihatemoney/tests/tests.py | 29 ++++++++++------------- ihatemoney/utils.py | 26 ++++++++++---------- ihatemoney/web.py | 26 ++++++++++---------- setup.cfg | 1 + tox.ini | 4 +++- 16 files changed, 113 insertions(+), 107 deletions(-) create mode 100644 .isort.cfg diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 00000000..ba73fb7a --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,13 @@ +[settings] +# Needed for black compatibility +multi_line_output=3 +include_trailing_comma=True +force_grid_wrap=0 +line_length=88 +combine_as_imports=True + +# If set, imports will be sorted within their section independent to the import_type. +force_sort_within_sections=True + +# skip +skip_glob=.local,**/migrations/**,**/node_modules/**,**/node-forge/** diff --git a/Makefile b/Makefile index d21a1cf9..a6817094 100644 --- a/Makefile +++ b/Makefile @@ -41,11 +41,19 @@ serve: install ## Run the ihatemoney server $(PYTHON) -m ihatemoney.manage runserver .PHONY: test -test: $(DEV_STAMP) ## Run the tests +test: install-dev ## Run the tests $(VENV)/bin/tox +.PHONY: black +black: install-dev ## Run the tests + $(VENV)/bin/black --target-version=py34 . + +.PHONY: isort +isort: install-dev ## Run the tests + $(VENV)/bin/isort -rc . + .PHONY: release -release: $(DEV_STAMP) ## Release a new version (see https://ihatemoney.readthedocs.io/en/latest/contributing.html#how-to-release) +release: install-dev ## Release a new version (see https://ihatemoney.readthedocs.io/en/latest/contributing.html#how-to-release) $(VENV)/bin/fullrelease .PHONY: compress-assets diff --git a/docs/conf.py b/docs/conf.py index 82c0e03d..4789396e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,5 +1,6 @@ # coding: utf8 -import sys, os +import os +import sys templates_path = ["_templates"] source_suffix = ".rst" diff --git a/ihatemoney/api/common.py b/ihatemoney/api/common.py index 728d2a8e..51ce96e8 100644 --- a/ihatemoney/api/common.py +++ b/ihatemoney/api/common.py @@ -1,12 +1,13 @@ # coding: utf8 -from flask import request, current_app +from functools import wraps + +from flask import current_app, request from flask_restful import Resource, abort +from werkzeug.security import check_password_hash from wtforms.fields.core import BooleanField -from ihatemoney.models import db, Project, Person, Bill -from ihatemoney.forms import ProjectForm, EditProjectForm, MemberForm, get_billform_for -from werkzeug.security import check_password_hash -from functools import wraps +from ihatemoney.forms import EditProjectForm, MemberForm, ProjectForm, get_billform_for +from ihatemoney.models import Bill, Person, Project, db def need_auth(f): diff --git a/ihatemoney/api/v1/resources.py b/ihatemoney/api/v1/resources.py index 821ba2bd..87950f65 100644 --- a/ihatemoney/api/v1/resources.py +++ b/ihatemoney/api/v1/resources.py @@ -1,17 +1,17 @@ # coding: utf8 from flask import Blueprint -from flask_restful import Api from flask_cors import CORS +from flask_restful import Api from ihatemoney.api.common import ( - ProjectsHandler, - ProjectHandler, - TokenHandler, - MemberHandler, - ProjectStatsHandler, - MembersHandler, BillHandler, BillsHandler, + MemberHandler, + MembersHandler, + ProjectHandler, + ProjectsHandler, + ProjectStatsHandler, + TokenHandler, ) api = Blueprint("api", __name__, url_prefix="/api") diff --git a/ihatemoney/forms.py b/ihatemoney/forms.py index 495eefa1..989b3022 100644 --- a/ihatemoney/forms.py +++ b/ihatemoney/forms.py @@ -1,29 +1,27 @@ +from datetime import datetime +from re import match + +import email_validator +from flask import request +from flask_babel import lazy_gettext as _ +from flask_wtf.file import FileAllowed, FileField, FileRequired from flask_wtf.form import FlaskForm +from jinja2 import Markup +from werkzeug.security import check_password_hash, generate_password_hash from wtforms.fields.core import SelectField, SelectMultipleField from wtforms.fields.html5 import DateField, DecimalField, URLField -from wtforms.fields.simple import PasswordField, SubmitField, StringField, BooleanField +from wtforms.fields.simple import BooleanField, PasswordField, StringField, SubmitField from wtforms.validators import ( - Email, DataRequired, - ValidationError, + Email, EqualTo, NumberRange, Optional, + ValidationError, ) -from flask_wtf.file import FileField, FileAllowed, FileRequired -from flask_babel import lazy_gettext as _ -from flask import request -from werkzeug.security import generate_password_hash, check_password_hash - -from datetime import datetime -from re import match -from jinja2 import Markup - -import email_validator - -from ihatemoney.models import Project, Person, LoggingMode -from ihatemoney.utils import slugify, eval_arithmetic_expression +from ihatemoney.models import LoggingMode, Person, Project +from ihatemoney.utils import eval_arithmetic_expression, slugify def strip_filter(string): diff --git a/ihatemoney/history.py b/ihatemoney/history.py index cda141e4..40aa7619 100644 --- a/ihatemoney/history.py +++ b/ihatemoney/history.py @@ -1,15 +1,7 @@ from flask_babel import gettext as _ -from sqlalchemy_continuum import ( - Operation, - parent_class, -) +from sqlalchemy_continuum import Operation, parent_class -from ihatemoney.models import ( - PersonVersion, - ProjectVersion, - BillVersion, - Person, -) +from ihatemoney.models import BillVersion, Person, PersonVersion, ProjectVersion def get_history_queries(project): diff --git a/ihatemoney/manage.py b/ihatemoney/manage.py index 6343ee7c..a192844c 100755 --- a/ihatemoney/manage.py +++ b/ihatemoney/manage.py @@ -1,16 +1,16 @@ #!/usr/bin/env python +import getpass import os import random import sys -import getpass -from flask_script import Manager, Command, Option from flask_migrate import Migrate, MigrateCommand +from flask_script import Command, Manager, Option from werkzeug.security import generate_password_hash +from ihatemoney.models import Project, db from ihatemoney.run import create_app -from ihatemoney.models import db, Project from ihatemoney.utils import create_jinja_env diff --git a/ihatemoney/models.py b/ihatemoney/models.py index d765c93d..eae442ac 100644 --- a/ihatemoney/models.py +++ b/ihatemoney/models.py @@ -1,33 +1,29 @@ from collections import defaultdict - from datetime import datetime -import sqlalchemy -from flask_sqlalchemy import SQLAlchemy, BaseQuery -from flask import g, current_app - from debts import settle -from sqlalchemy import orm -from sqlalchemy.sql import func +from flask import current_app, g +from flask_sqlalchemy import BaseQuery, SQLAlchemy from itsdangerous import ( - TimedJSONWebSignatureSerializer, - URLSafeSerializer, BadSignature, SignatureExpired, + TimedJSONWebSignatureSerializer, + URLSafeSerializer, ) -from sqlalchemy_continuum import make_versioned +import sqlalchemy +from sqlalchemy import orm +from sqlalchemy.sql import func +from sqlalchemy_continuum import make_versioned, version_class from sqlalchemy_continuum.plugins import FlaskPlugin -from sqlalchemy_continuum import version_class from ihatemoney.patch_sqlalchemy_continuum import PatchedBuilder from ihatemoney.versioning import ( - LoggingMode, ConditionalVersioningManager, - version_privacy_predicate, + LoggingMode, get_ip_if_allowed, + version_privacy_predicate, ) - make_versioned( user_cls=None, manager=ConditionalVersioningManager( diff --git a/ihatemoney/patch_sqlalchemy_continuum.py b/ihatemoney/patch_sqlalchemy_continuum.py index e0680c6a..dbbd9083 100644 --- a/ihatemoney/patch_sqlalchemy_continuum.py +++ b/ihatemoney/patch_sqlalchemy_continuum.py @@ -38,7 +38,7 @@ from sqlalchemy_continuum import Operation from sqlalchemy_continuum.builder import Builder from sqlalchemy_continuum.expression_reflector import VersionExpressionReflector from sqlalchemy_continuum.relationship_builder import RelationshipBuilder -from sqlalchemy_continuum.utils import option, adapt_columns +from sqlalchemy_continuum.utils import adapt_columns, option class PatchedRelationShipBuilder(RelationshipBuilder): diff --git a/ihatemoney/run.py b/ihatemoney/run.py index 161761c0..c4b53234 100644 --- a/ihatemoney/run.py +++ b/ihatemoney/run.py @@ -2,12 +2,13 @@ import os import os.path import warnings -from flask import Flask, g, request, session, render_template +from flask import Flask, g, render_template, request, session from flask_babel import Babel from flask_mail import Mail -from flask_migrate import Migrate, upgrade, stamp +from flask_migrate import Migrate, stamp, upgrade from werkzeug.middleware.proxy_fix import ProxyFix +from ihatemoney import default_settings from ihatemoney.api.v1 import api as apiv1 from ihatemoney.models import db from ihatemoney.utils import ( @@ -19,8 +20,6 @@ from ihatemoney.utils import ( ) from ihatemoney.web import main as web_interface -from ihatemoney import default_settings - def setup_database(app): """Prepare the database. Create tables, run migrations etc.""" diff --git a/ihatemoney/tests/tests.py b/ihatemoney/tests/tests.py index 5dff64d9..b27fafcc 100644 --- a/ihatemoney/tests/tests.py +++ b/ihatemoney/tests/tests.py @@ -1,26 +1,23 @@ # coding: utf8 +import base64 +from collections import defaultdict +import datetime +import io +import json +import os +from time import sleep import unittest from unittest.mock import patch -import datetime -import os -import io -import json -import base64 - -from collections import defaultdict -from time import sleep - -from werkzeug.security import generate_password_hash, check_password_hash from flask import session from flask_testing import TestCase - -from ihatemoney.run import create_app, db, load_configuration -from ihatemoney.manage import GenerateConfig, GeneratePasswordHash, DeleteProject -from ihatemoney import models, history -from ihatemoney.versioning import LoggingMode -from ihatemoney import utils from sqlalchemy import orm +from werkzeug.security import check_password_hash, generate_password_hash + +from ihatemoney import history, models, utils +from ihatemoney.manage import DeleteProject, GenerateConfig, GeneratePasswordHash +from ihatemoney.run import create_app, db, load_configuration +from ihatemoney.versioning import LoggingMode # Unset configuration file env var if previously set os.environ.pop("IHATEMONEY_SETTINGS_FILE_PATH", None) diff --git a/ihatemoney/utils.py b/ihatemoney/utils.py index 0641d1c4..d8c887bb 100644 --- a/ihatemoney/utils.py +++ b/ihatemoney/utils.py @@ -1,19 +1,17 @@ -import re -import os import ast -import operator -from enum import Enum - -from io import BytesIO, StringIO - -import jinja2 -from json import dumps, JSONEncoder -from flask import redirect, current_app -from babel import Locale -from werkzeug.routing import HTTPException, RoutingException -from datetime import datetime, timedelta - import csv +from datetime import datetime, timedelta +from enum import Enum +from io import BytesIO, StringIO +from json import JSONEncoder, dumps +import operator +import os +import re + +from babel import Locale +from flask import current_app, redirect +import jinja2 +from werkzeug.routing import HTTPException, RoutingException def slugify(value): diff --git a/ihatemoney/web.py b/ihatemoney/web.py index 744d1bfa..a12eae19 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -8,25 +8,27 @@ Basically, this blueprint takes care of the authentication and provides some shortcuts to make your life better when coding (see `pull_project` and `add_project_id` for a quick overview) """ +from datetime import datetime +from functools import wraps import json import os -from functools import wraps from smtplib import SMTPRecipientsRefused from dateutil.parser import parse +from dateutil.relativedelta import relativedelta from flask import ( - abort, Blueprint, + abort, current_app, flash, g, redirect, render_template, request, - session, - url_for, send_file, send_from_directory, + session, + url_for, ) from flask_babel import get_locale, gettext as _ from flask_mail import Message @@ -42,23 +44,21 @@ from ihatemoney.forms import ( InviteForm, MemberForm, PasswordReminder, - ResetPasswordForm, ProjectForm, - get_billform_for, + ResetPasswordForm, UploadForm, + get_billform_for, ) -from ihatemoney.history import get_history_queries, get_history -from ihatemoney.models import db, Project, Person, Bill, LoggingMode +from ihatemoney.history import get_history, get_history_queries +from ihatemoney.models import Bill, LoggingMode, Person, Project, db from ihatemoney.utils import ( - Redirect303, - list_of_dicts2json, - list_of_dicts2csv, LoginThrottler, + Redirect303, get_members, + list_of_dicts2csv, + list_of_dicts2json, same_bill, ) -from datetime import datetime -from dateutil.relativedelta import relativedelta main = Blueprint("main", __name__) diff --git a/setup.cfg b/setup.cfg index 571f538b..be62af27 100644 --- a/setup.cfg +++ b/setup.cfg @@ -44,6 +44,7 @@ dev = black==19.10b0 ; python_version >= '3.6' flake8==3.7.9 Flask-Testing==0.8.0 + isort==4.3.21 pytest==5.4.1 tox==3.14.6 zest.releaser==6.20.1 diff --git a/tox.ini b/tox.ini index b5ff7055..7632ed83 100644 --- a/tox.ini +++ b/tox.ini @@ -21,7 +21,9 @@ deps = changedir = {toxinidir} [testenv:black] -commands = black --check --target-version=py34 . +commands = + black --check --target-version=py34 . + isort -c -rc . changedir = {toxinidir} [testenv:flake8] From 32ccbd09aaec592f17d54792d6bd383f927275ae Mon Sep 17 00:00:00 2001 From: Glandos Date: Tue, 21 Apr 2020 14:17:23 +0200 Subject: [PATCH 11/47] Update CONTRIBUTORS --- CONTRIBUTORS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 3b243fea..340471df 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -7,20 +7,27 @@ Adrien CLERC Alexandre Avenel Alexis Métaireau Allan Nordhøy +am97 +Andrew Dickinson Arnaud Bos Baptiste Jonglez Benjamin Bouvier Berteh +bmatticus Brice Maron Byron Ullauri Carey Metcalfe Daniel Schreiber +DavidRThrashJr donkers +Edwin Smulders Elizabeth Sherrock +eMerzh Feth AREZKI Frédéric Sureau Glandos Heimen Stoffels +James Leong Jocelyn Delalande Lucas Verney Luc Didry @@ -37,3 +44,4 @@ Richard Coates THANOS SIOURDAKIS Toover Xavier Mehrenberger +zorun From 11aef3f3d1dfc8732f4765c8e54a1fcc5b8128c7 Mon Sep 17 00:00:00 2001 From: Glandos Date: Tue, 21 Apr 2020 14:41:27 +0200 Subject: [PATCH 12/47] update i18n (#562) --- ihatemoney/messages.pot | 242 ++++++++++++++- .../translations/cs/LC_MESSAGES/messages.po | 253 ++++++++++++++- .../translations/de/LC_MESSAGES/messages.po | 292 ++++++++++++++++-- .../translations/el/LC_MESSAGES/messages.po | 244 ++++++++++++++- .../es_419/LC_MESSAGES/messages.po | 246 ++++++++++++++- .../translations/fr/LC_MESSAGES/messages.po | 262 ++++++++++++++-- .../translations/id/LC_MESSAGES/messages.po | 284 +++++++++++++++-- .../nb_NO/LC_MESSAGES/messages.po | 259 ++++++++++++++-- .../translations/nl/LC_MESSAGES/messages.po | 257 ++++++++++++++- .../translations/tr/LC_MESSAGES/messages.po | 244 ++++++++++++++- .../translations/uk/LC_MESSAGES/messages.po | 258 +++++++++++++++- .../zh_HANS-CN/LC_MESSAGES/messages.po | 256 ++++++++++++++- 12 files changed, 2887 insertions(+), 210 deletions(-) diff --git a/ihatemoney/messages.pot b/ihatemoney/messages.pot index d6401a56..18782fed 100644 --- a/ihatemoney/messages.pot +++ b/ihatemoney/messages.pot @@ -12,6 +12,18 @@ msgstr "" msgid "Email" msgstr "" +msgid "Enable project history" +msgstr "" + +msgid "Use IP tracking for project history" +msgstr "" + +msgid "Import previously exported JSON file" +msgstr "" + +msgid "Import" +msgstr "" + msgid "Project identifier" msgstr "" @@ -106,6 +118,15 @@ msgstr "" msgid "The email %(email)s is not valid" msgstr "" +msgid "Person" +msgstr "" + +msgid "Bill" +msgstr "" + +msgid "Project" +msgstr "" + msgid "Too many failed login attempts, please retry later." msgstr "" @@ -139,6 +160,12 @@ msgstr "" msgid "Password successfully reset." msgstr "" +msgid "Project successfully uploaded" +msgstr "" + +msgid "Invalid JSON" +msgstr "" + msgid "Project successfully deleted" msgstr "" @@ -204,9 +231,6 @@ msgstr "" msgid "Create a new project" msgstr "" -msgid "Project" -msgstr "" - msgid "Number of members" msgstr "" @@ -228,6 +252,9 @@ msgstr "" msgid "delete" msgstr "" +msgid "see" +msgstr "" + msgid "The Dashboard is currently deactivated." msgstr "" @@ -237,6 +264,12 @@ msgstr "" msgid "Edit project" msgstr "" +msgid "Import JSON" +msgstr "" + +msgid "Choose file" +msgstr "" + msgid "Download project's data" msgstr "" @@ -258,6 +291,9 @@ msgstr "" msgid "Cancel" msgstr "" +msgid "Privacy Settings" +msgstr "" + msgid "Edit the project" msgstr "" @@ -288,6 +324,186 @@ msgstr "" msgid "Download" msgstr "" +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 "" + +msgid "Removed" +msgstr "" + +msgid "and" +msgstr "" + +msgid "owers list" +msgstr "" + +msgid "Who?" +msgstr "" + +msgid "Balance" +msgstr "" + +msgid "" +"This project has history disabled. New actions won't appear below. You " +"can enable history on the" +msgstr "" + +msgid "settings page" +msgstr "" + +msgid "" +"The table below reflects actions recorded prior to disabling project " +"history. You can " +msgstr "" + +msgid "clear project history" +msgstr "" + +msgid "to remove them." +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 "" + +msgid "Event" +msgstr "" + +msgid "IP address recording can be" +msgstr "" + +msgid "enabled" +msgstr "" + +msgid "disabled" +msgstr "" + +msgid "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" +msgstr "" + +msgid "External link changed to" +msgstr "" + +msgid "Amount" +msgstr "" + +msgid "modified" +msgstr "" + +msgid "removed" +msgstr "" + +msgid "changed in a unknown way" +msgstr "" + +msgid "Nothing to list" +msgstr "" + +msgid "Someone probably" +msgstr "" + +msgid "cleared the project history." +msgstr "" + msgid "Manage your shared
expenses, easily" msgstr "" @@ -335,6 +551,9 @@ msgstr "" msgid "Statistics" msgstr "" +msgid "History" +msgstr "" + msgid "Settings" msgstr "" @@ -392,6 +611,12 @@ msgstr "" msgid "Add a new bill" msgstr "" +msgid "Newer bills" +msgstr "" + +msgid "Older bills" +msgstr "" + msgid "When?" msgstr "" @@ -418,9 +643,6 @@ msgstr "" msgid "each" msgstr "" -msgid "see" -msgstr "" - msgid "No bills" msgstr "" @@ -489,15 +711,15 @@ msgstr "" msgid "To whom?" msgstr "" -msgid "Who?" -msgstr "" - msgid "Paid" msgstr "" msgid "Spent" msgstr "" -msgid "Balance" +msgid "Expenses by Month" +msgstr "" + +msgid "Period" msgstr "" diff --git a/ihatemoney/translations/cs/LC_MESSAGES/messages.po b/ihatemoney/translations/cs/LC_MESSAGES/messages.po index adc914fb..b5ebf740 100644 --- a/ihatemoney/translations/cs/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/cs/LC_MESSAGES/messages.po @@ -1,16 +1,18 @@ + msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-24 18:27+0200\n" +"POT-Creation-Date: 2020-04-21 14:18+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Automatically generated\n" -"Language-Team: none\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" -"Content-Type: text/plain; charset=UTF-8\n" +"Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Translate Toolkit 2.4.0\n" +"Generated-By: Babel 2.7.0\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " @@ -26,6 +28,18 @@ msgstr "" msgid "Email" msgstr "" +msgid "Enable project history" +msgstr "" + +msgid "Use IP tracking for project history" +msgstr "" + +msgid "Import previously exported JSON file" +msgstr "" + +msgid "Import" +msgstr "" + msgid "Project identifier" msgstr "" @@ -120,6 +134,15 @@ msgstr "" msgid "The email %(email)s is not valid" msgstr "" +msgid "Person" +msgstr "" + +msgid "Bill" +msgstr "" + +msgid "Project" +msgstr "" + msgid "Too many failed login attempts, please retry later." msgstr "" @@ -153,6 +176,12 @@ msgstr "" msgid "Password successfully reset." msgstr "" +msgid "Project successfully uploaded" +msgstr "" + +msgid "Invalid JSON" +msgstr "" + msgid "Project successfully deleted" msgstr "" @@ -218,9 +247,6 @@ msgstr "" msgid "Create a new project" msgstr "" -msgid "Project" -msgstr "" - msgid "Number of members" msgstr "" @@ -242,6 +268,9 @@ msgstr "" msgid "delete" msgstr "" +msgid "see" +msgstr "" + msgid "The Dashboard is currently deactivated." msgstr "" @@ -251,6 +280,12 @@ msgstr "" msgid "Edit project" msgstr "" +msgid "Import JSON" +msgstr "" + +msgid "Choose file" +msgstr "" + msgid "Download project's data" msgstr "" @@ -272,6 +307,9 @@ msgstr "" msgid "Cancel" msgstr "" +msgid "Privacy Settings" +msgstr "" + msgid "Edit the project" msgstr "" @@ -302,6 +340,186 @@ msgstr "" msgid "Download" msgstr "" +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 "" + +msgid "Removed" +msgstr "" + +msgid "and" +msgstr "" + +msgid "owers list" +msgstr "" + +msgid "Who?" +msgstr "" + +msgid "Balance" +msgstr "" + +msgid "" +"This project has history disabled. New actions won't appear below. You " +"can enable history on the" +msgstr "" + +msgid "settings page" +msgstr "" + +msgid "" +"The table below reflects actions recorded prior to disabling project " +"history. You can " +msgstr "" + +msgid "clear project history" +msgstr "" + +msgid "to remove them." +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 "" + +msgid "Event" +msgstr "" + +msgid "IP address recording can be" +msgstr "" + +msgid "enabled" +msgstr "" + +msgid "disabled" +msgstr "" + +msgid "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" +msgstr "" + +msgid "External link changed to" +msgstr "" + +msgid "Amount" +msgstr "" + +msgid "modified" +msgstr "" + +msgid "removed" +msgstr "" + +msgid "changed in a unknown way" +msgstr "" + +msgid "Nothing to list" +msgstr "" + +msgid "Someone probably" +msgstr "" + +msgid "cleared the project history." +msgstr "" + msgid "Manage your shared
expenses, easily" msgstr "" @@ -349,6 +567,9 @@ msgstr "" msgid "Statistics" msgstr "" +msgid "History" +msgstr "" + msgid "Settings" msgstr "" @@ -406,6 +627,12 @@ msgstr "" msgid "Add a new bill" msgstr "" +msgid "Newer bills" +msgstr "" + +msgid "Older bills" +msgstr "" + msgid "When?" msgstr "" @@ -432,9 +659,6 @@ msgstr "" msgid "each" msgstr "" -msgid "see" -msgstr "" - msgid "No bills" msgstr "" @@ -503,14 +727,15 @@ msgstr "" msgid "To whom?" msgstr "" -msgid "Who?" -msgstr "" - msgid "Paid" msgstr "" msgid "Spent" msgstr "" -msgid "Balance" +msgid "Expenses by Month" msgstr "" + +msgid "Period" +msgstr "" + diff --git a/ihatemoney/translations/de/LC_MESSAGES/messages.po b/ihatemoney/translations/de/LC_MESSAGES/messages.po index d96ba17a..2a93670a 100644 --- a/ihatemoney/translations/de/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/de/LC_MESSAGES/messages.po @@ -1,25 +1,26 @@ + msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-12 09:58+0200\n" +"POT-Creation-Date: 2020-04-21 14:18+0200\n" "PO-Revision-Date: 2020-02-12 10:50+0000\n" "Last-Translator: flolilo \n" -"Language-Team: German \n" "Language: de\n" +"Language-Team: German \n" +"Plural-Forms: nplurals=2; plural=n != 1\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" -"Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 3.11-dev\n" +"Generated-By: Babel 2.7.0\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " "accepted." msgstr "" -"Kein gültiger Betrag oder Ausdruck. Es werden nur Zahlen und die Operatoren +" -" - * / akzeptiert." +"Kein gültiger Betrag oder Ausdruck. Es werden nur Zahlen und die " +"Operatoren + - * / akzeptiert." msgid "Project name" msgstr "Projektname" @@ -30,6 +31,18 @@ msgstr "Privater Code" msgid "Email" msgstr "E-Mail" +msgid "Enable project history" +msgstr "" + +msgid "Use IP tracking for project history" +msgstr "" + +msgid "Import previously exported JSON file" +msgstr "" + +msgid "Import" +msgstr "" + msgid "Project identifier" msgstr "Projektkennung" @@ -41,8 +54,8 @@ msgid "" "A project with this identifier (\"%(project)s\") already exists. Please " "choose a new identifier" msgstr "" -"Ein Projekt mit der Kennung (\"%(project)s\") existiert bereits. Bitte wähle " -"eine andere Kennung" +"Ein Projekt mit der Kennung (\"%(project)s\") existiert bereits. Bitte " +"wähle eine andere Kennung" msgid "Get in" msgstr "Eintreten" @@ -80,6 +93,12 @@ msgstr "Von" msgid "Amount paid" msgstr "Betrag" +msgid "External link" +msgstr "" + +msgid "A link to an external document, related to this bill" +msgstr "" + msgid "For whom?" msgstr "Für wen?" @@ -120,6 +139,15 @@ msgstr "Einladung senden" msgid "The email %(email)s is not valid" msgstr "Die E-Mail-Adresse(n) %(email)s ist/sind nicht gültig" +msgid "Person" +msgstr "" + +msgid "Bill" +msgstr "" + +msgid "Project" +msgstr "Projekt" + msgid "Too many failed login attempts, please retry later." msgstr "Zu viele fehlgeschlagene Anmeldeversuche, bitte versuche es später." @@ -130,8 +158,7 @@ msgstr "" "verbleibend." msgid "You either provided a bad token or no project identifier." -msgstr "" -"Du hast entweder einen ungültigen Token oder keine Projekt-ID angegeben." +msgstr "Du hast entweder einen ungültigen Token oder keine Projekt-ID angegeben." msgid "This private code is not the right one" msgstr "Der private Code ist nicht korrekt" @@ -158,6 +185,12 @@ msgstr "Unbekanntes Projekt" msgid "Password successfully reset." msgstr "Passwort erfolgreich zurückgesetzt." +msgid "Project successfully uploaded" +msgstr "" + +msgid "Invalid JSON" +msgstr "" + msgid "Project successfully deleted" msgstr "Projekt erfolgreich gelöscht" @@ -225,9 +258,6 @@ msgstr "?" msgid "Create a new project" msgstr "Neues Projekt erstellen" -msgid "Project" -msgstr "Projekt" - msgid "Number of members" msgstr "Anzahl der Teilnehmer" @@ -249,6 +279,9 @@ msgstr "Bearbeiten" msgid "delete" msgstr "Löschen" +msgid "see" +msgstr "" + msgid "The Dashboard is currently deactivated." msgstr "Das Dashboard ist aktuell deaktiviert." @@ -258,6 +291,12 @@ msgstr "Bist du sicher?" msgid "Edit project" msgstr "Projekt bearbeiten" +msgid "Import JSON" +msgstr "" + +msgid "Choose file" +msgstr "" + msgid "Download project's data" msgstr "Projektdaten herunterladen" @@ -279,6 +318,9 @@ msgstr "Passwort vergessen?" msgid "Cancel" msgstr "Abbrechen" +msgid "Privacy Settings" +msgstr "" + msgid "Edit the project" msgstr "Projekt bearbeiten" @@ -309,6 +351,186 @@ msgstr "Einladung versenden" msgid "Download" msgstr "Herunterladen" +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 "" + +msgid "Removed" +msgstr "" + +msgid "and" +msgstr "" + +msgid "owers list" +msgstr "" + +msgid "Who?" +msgstr "Wer?" + +msgid "Balance" +msgstr "Bilanz" + +msgid "" +"This project has history disabled. New actions won't appear below. You " +"can enable history on the" +msgstr "" + +msgid "settings page" +msgstr "" + +msgid "" +"The table below reflects actions recorded prior to disabling project " +"history. You can " +msgstr "" + +msgid "clear project history" +msgstr "" + +msgid "to remove them." +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 "" + +msgid "Event" +msgstr "" + +msgid "IP address recording can be" +msgstr "" + +msgid "enabled" +msgstr "" + +msgid "disabled" +msgstr "" + +msgid "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" +msgstr "" + +msgid "External link changed to" +msgstr "" + +msgid "Amount" +msgstr "" + +msgid "modified" +msgstr "" + +msgid "removed" +msgstr "" + +msgid "changed in a unknown way" +msgstr "" + +msgid "Nothing to list" +msgstr "" + +msgid "Someone probably" +msgstr "" + +msgid "cleared the project history." +msgstr "" + msgid "Manage your shared
expenses, easily" msgstr "Verwalten deine geteilten
Ausgaben ganz einfach" @@ -343,8 +565,9 @@ msgid "" "This access code will be sent to your friends. It is stored as-is by the " "server, so don\\'t reuse a personal password!" msgstr "" -"Dieser Zugangscode wird an deine Freunde gesendet. Es wird als Klartext auf " -"dem Server gespeichert. Bitte verwenden daher kein persönliches Passwort!" +"Dieser Zugangscode wird an deine Freunde gesendet. Es wird als Klartext " +"auf dem Server gespeichert. Bitte verwenden daher kein persönliches " +"Passwort!" msgid "Account manager" msgstr "Konten" @@ -358,6 +581,9 @@ msgstr "Bilanz" msgid "Statistics" msgstr "Statistik" +msgid "History" +msgstr "" + msgid "Settings" msgstr "Einstellungen" @@ -415,6 +641,12 @@ msgstr "Du kannst anfangen, Teilnehmer hinzuzufügen" msgid "Add a new bill" msgstr "Neue Ausgabe" +msgid "Newer bills" +msgstr "" + +msgid "Older bills" +msgstr "" + msgid "When?" msgstr "Wann?" @@ -485,8 +717,8 @@ msgid "" "You can share the project identifier and the private code by any " "communication means." msgstr "" -"Du kannst die Projekt-ID und den privaten Code auf jedem Kommunikationsweg " -"weitergeben." +"Du kannst die Projekt-ID und den privaten Code auf jedem " +"Kommunikationsweg weitergeben." msgid "Identifier:" msgstr "ID:" @@ -495,8 +727,7 @@ msgid "Share the Link" msgstr "Link teilen" msgid "You can directly share the following link via your prefered medium" -msgstr "" -"Du kannst den folgenden Link direkt über dein bevorzugtes Medium teilen" +msgstr "Du kannst den folgenden Link direkt über dein bevorzugtes Medium teilen" msgid "Send via Emails" msgstr "Per E-Mail versenden" @@ -507,10 +738,10 @@ msgid "" " creation of this budget management project and we will " "send them an email for you." msgstr "" -"Gib eine (durch Kommas getrennte) Liste von E-Mail-Adressen an, die du über " -"die\n" -"\t\t\tErstellung dieses Projekts informieren möchtest, und wir senden ihnen " -"eine E-Mail." +"Gib eine (durch Kommas getrennte) Liste von E-Mail-Adressen an, die du " +"über die\n" +"\t\t\tErstellung dieses Projekts informieren möchtest, und wir senden " +"ihnen eine E-Mail." msgid "Who pays?" msgstr "Wer zahlt?" @@ -518,14 +749,15 @@ msgstr "Wer zahlt?" msgid "To whom?" msgstr "An wen?" -msgid "Who?" -msgstr "Wer?" - msgid "Paid" msgstr "Bezahlt" msgid "Spent" msgstr "Ausgegeben" -msgid "Balance" -msgstr "Bilanz" +msgid "Expenses by Month" +msgstr "" + +msgid "Period" +msgstr "" + diff --git a/ihatemoney/translations/el/LC_MESSAGES/messages.po b/ihatemoney/translations/el/LC_MESSAGES/messages.po index 14132161..74da58c7 100644 --- a/ihatemoney/translations/el/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/el/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-01 21:48+0200\n" +"POT-Creation-Date: 2020-04-21 14:18+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Automatically generated\n" "Language: el\n" @@ -28,6 +28,18 @@ msgstr "" msgid "Email" msgstr "" +msgid "Enable project history" +msgstr "" + +msgid "Use IP tracking for project history" +msgstr "" + +msgid "Import previously exported JSON file" +msgstr "" + +msgid "Import" +msgstr "" + msgid "Project identifier" msgstr "" @@ -122,6 +134,15 @@ msgstr "" msgid "The email %(email)s is not valid" msgstr "" +msgid "Person" +msgstr "" + +msgid "Bill" +msgstr "" + +msgid "Project" +msgstr "" + msgid "Too many failed login attempts, please retry later." msgstr "" @@ -155,6 +176,12 @@ msgstr "" msgid "Password successfully reset." msgstr "" +msgid "Project successfully uploaded" +msgstr "" + +msgid "Invalid JSON" +msgstr "" + msgid "Project successfully deleted" msgstr "" @@ -220,9 +247,6 @@ msgstr "" msgid "Create a new project" msgstr "" -msgid "Project" -msgstr "" - msgid "Number of members" msgstr "" @@ -244,6 +268,9 @@ msgstr "" msgid "delete" msgstr "" +msgid "see" +msgstr "" + msgid "The Dashboard is currently deactivated." msgstr "" @@ -253,6 +280,12 @@ msgstr "" msgid "Edit project" msgstr "" +msgid "Import JSON" +msgstr "" + +msgid "Choose file" +msgstr "" + msgid "Download project's data" msgstr "" @@ -274,6 +307,9 @@ msgstr "" msgid "Cancel" msgstr "" +msgid "Privacy Settings" +msgstr "" + msgid "Edit the project" msgstr "" @@ -304,6 +340,186 @@ msgstr "" msgid "Download" msgstr "" +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 "" + +msgid "Removed" +msgstr "" + +msgid "and" +msgstr "" + +msgid "owers list" +msgstr "" + +msgid "Who?" +msgstr "" + +msgid "Balance" +msgstr "" + +msgid "" +"This project has history disabled. New actions won't appear below. You " +"can enable history on the" +msgstr "" + +msgid "settings page" +msgstr "" + +msgid "" +"The table below reflects actions recorded prior to disabling project " +"history. You can " +msgstr "" + +msgid "clear project history" +msgstr "" + +msgid "to remove them." +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 "" + +msgid "Event" +msgstr "" + +msgid "IP address recording can be" +msgstr "" + +msgid "enabled" +msgstr "" + +msgid "disabled" +msgstr "" + +msgid "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" +msgstr "" + +msgid "External link changed to" +msgstr "" + +msgid "Amount" +msgstr "" + +msgid "modified" +msgstr "" + +msgid "removed" +msgstr "" + +msgid "changed in a unknown way" +msgstr "" + +msgid "Nothing to list" +msgstr "" + +msgid "Someone probably" +msgstr "" + +msgid "cleared the project history." +msgstr "" + msgid "Manage your shared
expenses, easily" msgstr "" @@ -351,6 +567,9 @@ msgstr "" msgid "Statistics" msgstr "" +msgid "History" +msgstr "" + msgid "Settings" msgstr "" @@ -408,6 +627,12 @@ msgstr "" msgid "Add a new bill" msgstr "" +msgid "Newer bills" +msgstr "" + +msgid "Older bills" +msgstr "" + msgid "When?" msgstr "" @@ -434,9 +659,6 @@ msgstr "" msgid "each" msgstr "" -msgid "see" -msgstr "" - msgid "No bills" msgstr "" @@ -505,16 +727,16 @@ msgstr "" msgid "To whom?" msgstr "" -msgid "Who?" -msgstr "" - msgid "Paid" msgstr "" msgid "Spent" msgstr "" -msgid "Balance" +msgid "Expenses by Month" +msgstr "" + +msgid "Period" msgstr "" #~ msgid "" diff --git a/ihatemoney/translations/es_419/LC_MESSAGES/messages.po b/ihatemoney/translations/es_419/LC_MESSAGES/messages.po index 1ce97596..adf12ba7 100644 --- a/ihatemoney/translations/es_419/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/es_419/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-20 11:52+0200\n" +"POT-Creation-Date: 2020-04-21 14:18+0200\n" "PO-Revision-Date: 2019-09-25 22:28+0000\n" "Last-Translator: Diego Caraballo \n" "Language: es_419\n" @@ -31,6 +31,18 @@ msgstr "Código privado" msgid "Email" msgstr "Correo Electrónico" +msgid "Enable project history" +msgstr "" + +msgid "Use IP tracking for project history" +msgstr "" + +msgid "Import previously exported JSON file" +msgstr "" + +msgid "Import" +msgstr "" + msgid "Project identifier" msgstr "Identificador de proyecto" @@ -127,6 +139,15 @@ msgstr "Enviar invitaciones" msgid "The email %(email)s is not valid" msgstr "El correo electrónico %(email)s no es válido" +msgid "Person" +msgstr "" + +msgid "Bill" +msgstr "" + +msgid "Project" +msgstr "Proyecto" + msgid "Too many failed login attempts, please retry later." msgstr "" "Demasiados intentos fallidos de inicio de sesión, vuelva a intentarlo más" @@ -164,6 +185,12 @@ msgstr "Proyecto desconocido" msgid "Password successfully reset." msgstr "Contraseña restablecida con éxito." +msgid "Project successfully uploaded" +msgstr "" + +msgid "Invalid JSON" +msgstr "" + msgid "Project successfully deleted" msgstr "Proyecto eliminado correctamente" @@ -231,9 +258,6 @@ msgstr "?" msgid "Create a new project" msgstr "Crear un nuevo proyecto" -msgid "Project" -msgstr "Proyecto" - msgid "Number of members" msgstr "Número de miembros" @@ -255,6 +279,9 @@ msgstr "Editar" msgid "delete" msgstr "Eliminar" +msgid "see" +msgstr "ver" + msgid "The Dashboard is currently deactivated." msgstr "El panel está desactivado actualmente." @@ -264,6 +291,12 @@ msgstr "¿Estás seguro?" msgid "Edit project" msgstr "Editar proyecto" +msgid "Import JSON" +msgstr "" + +msgid "Choose file" +msgstr "" + msgid "Download project's data" msgstr "Descargar datos del proyecto" @@ -287,6 +320,9 @@ msgstr "¿No recuerdas la contraseña?" msgid "Cancel" msgstr "Cancelar" +msgid "Privacy Settings" +msgstr "" + msgid "Edit the project" msgstr "Editar el proyecto" @@ -317,6 +353,186 @@ msgstr "Enviar las invitaciones" msgid "Download" msgstr "Descargar" +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 "" + +msgid "Removed" +msgstr "" + +msgid "and" +msgstr "" + +msgid "owers list" +msgstr "" + +msgid "Who?" +msgstr "¿Quién?" + +msgid "Balance" +msgstr "Balance" + +msgid "" +"This project has history disabled. New actions won't appear below. You " +"can enable history on the" +msgstr "" + +msgid "settings page" +msgstr "" + +msgid "" +"The table below reflects actions recorded prior to disabling project " +"history. You can " +msgstr "" + +msgid "clear project history" +msgstr "" + +msgid "to remove them." +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 "" + +msgid "Event" +msgstr "" + +msgid "IP address recording can be" +msgstr "" + +msgid "enabled" +msgstr "" + +msgid "disabled" +msgstr "" + +msgid "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" +msgstr "" + +msgid "External link changed to" +msgstr "" + +msgid "Amount" +msgstr "" + +msgid "modified" +msgstr "" + +msgid "removed" +msgstr "" + +msgid "changed in a unknown way" +msgstr "" + +msgid "Nothing to list" +msgstr "" + +msgid "Someone probably" +msgstr "" + +msgid "cleared the project history." +msgstr "" + msgid "Manage your shared
expenses, easily" msgstr "Gestione sus gastos compartidos
fácilmente" @@ -366,6 +582,9 @@ msgstr "Resolver" msgid "Statistics" msgstr "Estadísticas" +msgid "History" +msgstr "" + msgid "Settings" msgstr "Configuración" @@ -423,6 +642,12 @@ msgstr "Deberías comenzar agregando participantes" msgid "Add a new bill" msgstr "Añadir una nueva factura" +msgid "Newer bills" +msgstr "" + +msgid "Older bills" +msgstr "" + msgid "When?" msgstr "¿Cuando?" @@ -449,9 +674,6 @@ msgstr "Todo el mundo menos %(excluded)s" msgid "each" msgstr "Cada" -msgid "see" -msgstr "ver" - msgid "No bills" msgstr "Sin facturas" @@ -530,15 +752,15 @@ msgstr "¿Quién paga?" msgid "To whom?" msgstr "¿A quién?" -msgid "Who?" -msgstr "¿Quién?" - msgid "Paid" msgstr "Pagado" msgid "Spent" msgstr "Gastado" -msgid "Balance" -msgstr "Balance" +msgid "Expenses by Month" +msgstr "" + +msgid "Period" +msgstr "" diff --git a/ihatemoney/translations/fr/LC_MESSAGES/messages.po b/ihatemoney/translations/fr/LC_MESSAGES/messages.po index f4c1f36c..48864aa9 100644 --- a/ihatemoney/translations/fr/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/fr/LC_MESSAGES/messages.po @@ -7,17 +7,16 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2019-10-01 21:48+0200\n" +"POT-Creation-Date: 2020-04-21 14:18+0200\n" "PO-Revision-Date: 2019-10-07 22:56+0000\n" "Last-Translator: Alexis Metaireau \n" -"Language-Team: French \n" "Language: fr\n" +"Language-Team: French \n" +"Plural-Forms: nplurals=2; plural=n > 1\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 3.9-dev\n" "Generated-By: Babel 2.7.0\n" msgid "" @@ -36,6 +35,18 @@ msgstr "Code d’accès" msgid "Email" msgstr "Email" +msgid "Enable project history" +msgstr "" + +msgid "Use IP tracking for project history" +msgstr "" + +msgid "Import previously exported JSON file" +msgstr "" + +msgid "Import" +msgstr "Importer" + msgid "Project identifier" msgstr "Identifiant du projet" @@ -132,6 +143,15 @@ msgstr "Envoyer les invitations" msgid "The email %(email)s is not valid" msgstr "L’email %(email)s est invalide" +msgid "Person" +msgstr "" + +msgid "Bill" +msgstr "" + +msgid "Project" +msgstr "Projets" + msgid "Too many failed login attempts, please retry later." msgstr "Trop d'échecs d’authentification successifs, veuillez réessayer plus tard." @@ -167,6 +187,12 @@ msgstr "Project inconnu" msgid "Password successfully reset." msgstr "Le mot de passe a été changé avec succès." +msgid "Project successfully uploaded" +msgstr "Le projet a été correctement importé" + +msgid "Invalid JSON" +msgstr "Le fichier JSON est invalide" + msgid "Project successfully deleted" msgstr "Projet supprimé" @@ -234,9 +260,6 @@ msgstr " ?" msgid "Create a new project" msgstr "Créer un nouveau projet" -msgid "Project" -msgstr "Projets" - msgid "Number of members" msgstr "Nombre de membres" @@ -258,6 +281,9 @@ msgstr "éditer" msgid "delete" msgstr "supprimer" +msgid "see" +msgstr "voir" + msgid "The Dashboard is currently deactivated." msgstr "Le tableau de bord est actuellement désactivée." @@ -267,6 +293,12 @@ msgstr "c’est sûr ?" msgid "Edit project" msgstr "Éditer le projet" +msgid "Import JSON" +msgstr "" + +msgid "Choose file" +msgstr "" + msgid "Download project's data" msgstr "Télécharger les données du projet" @@ -288,6 +320,9 @@ msgstr "Vous ne vous souvenez plus du code d’accès ?" msgid "Cancel" msgstr "Annuler" +msgid "Privacy Settings" +msgstr "" + msgid "Edit the project" msgstr "Éditer le projet" @@ -318,6 +353,186 @@ msgstr "Envoyer les invitations" msgid "Download" msgstr "Télécharger" +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 "" + +msgid "Removed" +msgstr "" + +msgid "and" +msgstr "" + +msgid "owers list" +msgstr "" + +msgid "Who?" +msgstr "Qui ?" + +msgid "Balance" +msgstr "Solde" + +msgid "" +"This project has history disabled. New actions won't appear below. You " +"can enable history on the" +msgstr "" + +msgid "settings page" +msgstr "" + +msgid "" +"The table below reflects actions recorded prior to disabling project " +"history. You can " +msgstr "" + +msgid "clear project history" +msgstr "" + +msgid "to remove them." +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 "" + +msgid "Event" +msgstr "" + +msgid "IP address recording can be" +msgstr "" + +msgid "enabled" +msgstr "" + +msgid "disabled" +msgstr "" + +msgid "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" +msgstr "" + +msgid "External link changed to" +msgstr "" + +msgid "Amount" +msgstr "" + +msgid "modified" +msgstr "" + +msgid "removed" +msgstr "" + +msgid "changed in a unknown way" +msgstr "" + +msgid "Nothing to list" +msgstr "" + +msgid "Someone probably" +msgstr "" + +msgid "cleared the project history." +msgstr "" + msgid "Manage your shared
expenses, easily" msgstr "Gérez vos dépenses
partagées, facilement" @@ -367,6 +582,9 @@ msgstr "Remboursements" msgid "Statistics" msgstr "Statistiques" +msgid "History" +msgstr "" + msgid "Settings" msgstr "Options" @@ -424,6 +642,12 @@ msgstr "Vous devriez commencer par ajouter des participants" msgid "Add a new bill" msgstr "Nouvelle facture" +msgid "Newer bills" +msgstr "" + +msgid "Older bills" +msgstr "" + msgid "When?" msgstr "Quand ?" @@ -450,9 +674,6 @@ msgstr "Tout le monde sauf %(excluded)s" msgid "each" msgstr "chacun" -msgid "see" -msgstr "voir" - msgid "No bills" msgstr "Pas encore de factures" @@ -527,27 +748,17 @@ msgstr "Qui doit payer ?" msgid "To whom?" msgstr "Pour qui ?" -msgid "Who?" -msgstr "Qui ?" - msgid "Paid" msgstr "A payé" msgid "Spent" msgstr "A dépensé" -msgid "Balance" -msgstr "Solde" - -msgid "Import" -msgstr "Importer" - -msgid "Project successfully uploaded" -msgstr "Le projet a été correctement importé" - -msgid "Invalid JSON" -msgstr "Le fichier JSON est invalide" +msgid "Expenses by Month" +msgstr "" +msgid "Period" +msgstr "" #~ msgid "" #~ "The project identifier is used to " @@ -695,3 +906,4 @@ msgstr "Le fichier JSON est invalide" #~ msgid "A link to reset your password has been sent to your email." #~ msgstr "Un lien pour changer votre mot de passe vous a été envoyé par mail." + diff --git a/ihatemoney/translations/id/LC_MESSAGES/messages.po b/ihatemoney/translations/id/LC_MESSAGES/messages.po index 1a7f7edf..a28ce9e6 100644 --- a/ihatemoney/translations/id/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/id/LC_MESSAGES/messages.po @@ -1,24 +1,26 @@ + msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-11-15 09:12+0200\n" +"POT-Creation-Date: 2020-04-21 14:18+0200\n" "PO-Revision-Date: 2019-11-16 10:04+0000\n" "Last-Translator: Muhammad Fauzi \n" -"Language-Team: Indonesian \n" "Language: id\n" +"Language-Team: Indonesian \n" +"Plural-Forms: nplurals=1; plural=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" -"Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 3.10-dev\n" +"Generated-By: Babel 2.7.0\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " "accepted." msgstr "" -"Jumlah atau operator tidak valid. Hanya angka dan opertaor +-* yang diterima." +"Jumlah atau operator tidak valid. Hanya angka dan opertaor +-* yang " +"diterima." msgid "Project name" msgstr "Nama proyek" @@ -29,6 +31,18 @@ msgstr "Kode pribadi" msgid "Email" msgstr "Surel" +msgid "Enable project history" +msgstr "" + +msgid "Use IP tracking for project history" +msgstr "" + +msgid "Import previously exported JSON file" +msgstr "" + +msgid "Import" +msgstr "" + msgid "Project identifier" msgstr "Pengidentifikasi proyek" @@ -40,8 +54,8 @@ msgid "" "A project with this identifier (\"%(project)s\") already exists. Please " "choose a new identifier" msgstr "" -"Sebuah proyek dengan ID ini (\"%(project)s\") sudah ada. Silakan pilih ID " -"baru" +"Sebuah proyek dengan ID ini (\"%(project)s\") sudah ada. Silakan pilih ID" +" baru" msgid "Get in" msgstr "Masuk" @@ -125,6 +139,15 @@ msgstr "Kirim undangan" msgid "The email %(email)s is not valid" msgstr "Surel %(email)s tidak valid" +msgid "Person" +msgstr "" + +msgid "Bill" +msgstr "" + +msgid "Project" +msgstr "Proyek" + msgid "Too many failed login attempts, please retry later." msgstr "Terlalu banyak percobaan masuk, silakan coba lagi nanti." @@ -158,6 +181,12 @@ msgstr "Proyek tidak diketahui" msgid "Password successfully reset." msgstr "Kata sandi berhasil diatur ulang." +msgid "Project successfully uploaded" +msgstr "" + +msgid "Invalid JSON" +msgstr "" + msgid "Project successfully deleted" msgstr "Proyek berhasil dihapus" @@ -225,9 +254,6 @@ msgstr "?" msgid "Create a new project" msgstr "Buat proyek baru" -msgid "Project" -msgstr "Proyek" - msgid "Number of members" msgstr "Jumlah anggota" @@ -249,6 +275,9 @@ msgstr "ubah" msgid "delete" msgstr "hapus" +msgid "see" +msgstr "lihat" + msgid "The Dashboard is currently deactivated." msgstr "Dasbor sekarang ini sedang dinonaktifkan." @@ -258,6 +287,12 @@ msgstr "Anda yakin?" msgid "Edit project" msgstr "Ubah proyek" +msgid "Import JSON" +msgstr "" + +msgid "Choose file" +msgstr "" + msgid "Download project's data" msgstr "Unduh data proyek" @@ -279,6 +314,9 @@ msgstr "Tidak bisa mengingat kata sandi?" msgid "Cancel" msgstr "Batalkan" +msgid "Privacy Settings" +msgstr "" + msgid "Edit the project" msgstr "Ubah proyek" @@ -309,6 +347,186 @@ msgstr "Kirim undangan" msgid "Download" msgstr "Unduh" +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 "" + +msgid "Removed" +msgstr "" + +msgid "and" +msgstr "" + +msgid "owers list" +msgstr "" + +msgid "Who?" +msgstr "Siapa?" + +msgid "Balance" +msgstr "Saldo" + +msgid "" +"This project has history disabled. New actions won't appear below. You " +"can enable history on the" +msgstr "" + +msgid "settings page" +msgstr "" + +msgid "" +"The table below reflects actions recorded prior to disabling project " +"history. You can " +msgstr "" + +msgid "clear project history" +msgstr "" + +msgid "to remove them." +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 "" + +msgid "Event" +msgstr "" + +msgid "IP address recording can be" +msgstr "" + +msgid "enabled" +msgstr "" + +msgid "disabled" +msgstr "" + +msgid "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" +msgstr "" + +msgid "External link changed to" +msgstr "" + +msgid "Amount" +msgstr "" + +msgid "modified" +msgstr "" + +msgid "removed" +msgstr "" + +msgid "changed in a unknown way" +msgstr "" + +msgid "Nothing to list" +msgstr "" + +msgid "Someone probably" +msgstr "" + +msgid "cleared the project history." +msgstr "" + msgid "Manage your shared
expenses, easily" msgstr "Atur pembagian harga
Anda, dengan mudah" @@ -343,8 +561,8 @@ msgid "" "This access code will be sent to your friends. It is stored as-is by the " "server, so don\\'t reuse a personal password!" msgstr "" -"Kode akses ini akan dikirimkan ke teman Anda. Kode ini disimpan dalam bentuk " -"teks biasa dalam server, jadi jangan gunakan password Anda!" +"Kode akses ini akan dikirimkan ke teman Anda. Kode ini disimpan dalam " +"bentuk teks biasa dalam server, jadi jangan gunakan password Anda!" msgid "Account manager" msgstr "Pengatur akun" @@ -358,6 +576,9 @@ msgstr "Atur" msgid "Statistics" msgstr "Statistik" +msgid "History" +msgstr "" + msgid "Settings" msgstr "Pengaturan" @@ -415,6 +636,12 @@ msgstr "Anda harus mulai dengan menambahkan partisipan" msgid "Add a new bill" msgstr "Tambah tagihan baru" +msgid "Newer bills" +msgstr "" + +msgid "Older bills" +msgstr "" + msgid "When?" msgstr "Kapan?" @@ -441,9 +668,6 @@ msgstr "Semua orang kecuali %(excluded)s" msgid "each" msgstr "setiap" -msgid "see" -msgstr "lihat" - msgid "No bills" msgstr "Tidak ada tagihan" @@ -466,8 +690,8 @@ msgid "" "A link to reset your password has been sent to you, please check your " "emails." msgstr "" -"Tautan atur ulang kata sandi telah dikirim kepada Anda, silakan cek email " -"Anda." +"Tautan atur ulang kata sandi telah dikirim kepada Anda, silakan cek email" +" Anda." msgid "Return to home page" msgstr "Kembali ke halaman depan" @@ -499,7 +723,8 @@ msgstr "Bagikan tautan" msgid "You can directly share the following link via your prefered medium" msgstr "" -"Anda bisa membagikan tautan secara langsung melalui media yang Anda inginkan" +"Anda bisa membagikan tautan secara langsung melalui media yang Anda " +"inginkan" msgid "Send via Emails" msgstr "Kirim melalui surel" @@ -510,10 +735,10 @@ msgid "" " creation of this budget management project and we will " "send them an email for you." msgstr "" -"Spesifikkan daftar alamat surel (dipisah dengan koma) yang akan Anda kirim " -"pemberitahuan tentang\n" -" pembuatan dari manajemen anggaran proyek ini dan kami akan " -"memngirim mereka sebuah surel." +"Spesifikkan daftar alamat surel (dipisah dengan koma) yang akan Anda " +"kirim pemberitahuan tentang\n" +" pembuatan dari manajemen anggaran proyek ini dan kami " +"akan memngirim mereka sebuah surel." msgid "Who pays?" msgstr "Siapa membayar?" @@ -521,14 +746,15 @@ msgstr "Siapa membayar?" msgid "To whom?" msgstr "Kepada siapa?" -msgid "Who?" -msgstr "Siapa?" - msgid "Paid" msgstr "Dibayar" msgid "Spent" msgstr "Dihabiskan" -msgid "Balance" -msgstr "Saldo" +msgid "Expenses by Month" +msgstr "" + +msgid "Period" +msgstr "" + diff --git a/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po b/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po index 1a95c5e6..4ea69e97 100644 --- a/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po @@ -1,18 +1,18 @@ + msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-09-30 23:53+0200\n" +"POT-Creation-Date: 2020-04-21 14:18+0200\n" "PO-Revision-Date: 2019-11-12 09:04+0000\n" "Last-Translator: Allan Nordhøy \n" -"Language-Team: Norwegian Bokmål \n" "Language: nb_NO\n" +"Language-Team: Norwegian Bokmål \n" +"Plural-Forms: nplurals=2; plural=n != 1\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 3.10-dev\n" "Generated-By: Babel 2.7.0\n" msgid "" @@ -31,6 +31,18 @@ msgstr "Privat kode" msgid "Email" msgstr "E-post" +msgid "Enable project history" +msgstr "" + +msgid "Use IP tracking for project history" +msgstr "" + +msgid "Import previously exported JSON file" +msgstr "" + +msgid "Import" +msgstr "" + msgid "Project identifier" msgstr "Prosjektidentifikator" @@ -129,6 +141,15 @@ msgstr "Send invitasjoner" msgid "The email %(email)s is not valid" msgstr "E-posten \"%(email)s\" er ikke gyldig" +msgid "Person" +msgstr "" + +msgid "Bill" +msgstr "" + +msgid "Project" +msgstr "Prosjekt" + msgid "Too many failed login attempts, please retry later." msgstr "For mange mislykkede innloggingsforsøk, prøv igjen senere." @@ -165,6 +186,12 @@ msgstr "Ukjent prosjekt" msgid "Password successfully reset." msgstr "Passord tilbakestilt." +msgid "Project successfully uploaded" +msgstr "" + +msgid "Invalid JSON" +msgstr "" + #, fuzzy msgid "Project successfully deleted" msgstr "Prosjekt slettet" @@ -237,9 +264,6 @@ msgstr "?" msgid "Create a new project" msgstr "Opprett et nytt prosjekt" -msgid "Project" -msgstr "Prosjekt" - msgid "Number of members" msgstr "Antall medlemmer" @@ -261,6 +285,10 @@ msgstr "rediger" msgid "delete" msgstr "slett" +#, fuzzy +msgid "see" +msgstr "se" + msgid "The Dashboard is currently deactivated." msgstr "Oversikten er for tiden avskrudd." @@ -270,6 +298,12 @@ msgstr "er du sikker?" msgid "Edit project" msgstr "Rediger prosjekt" +msgid "Import JSON" +msgstr "" + +msgid "Choose file" +msgstr "" + msgid "Download project's data" msgstr "Last ned prosjektets data" @@ -294,6 +328,9 @@ msgstr "Husker du ikke passordet?" msgid "Cancel" msgstr "Avbryt" +msgid "Privacy Settings" +msgstr "" + msgid "Edit the project" msgstr "Rediger prosjektet" @@ -325,6 +362,187 @@ msgstr "Send ut invitasjonene" msgid "Download" msgstr "Last nd" +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 "" + +msgid "Removed" +msgstr "" + +msgid "and" +msgstr "" + +msgid "owers list" +msgstr "" + +msgid "Who?" +msgstr "Hvem?" + +#, fuzzy +msgid "Balance" +msgstr "Kontobalanse" + +msgid "" +"This project has history disabled. New actions won't appear below. You " +"can enable history on the" +msgstr "" + +msgid "settings page" +msgstr "" + +msgid "" +"The table below reflects actions recorded prior to disabling project " +"history. You can " +msgstr "" + +msgid "clear project history" +msgstr "" + +msgid "to remove them." +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 "" + +msgid "Event" +msgstr "" + +msgid "IP address recording can be" +msgstr "" + +msgid "enabled" +msgstr "" + +msgid "disabled" +msgstr "" + +msgid "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" +msgstr "" + +msgid "External link changed to" +msgstr "" + +msgid "Amount" +msgstr "" + +msgid "modified" +msgstr "" + +msgid "removed" +msgstr "" + +msgid "changed in a unknown way" +msgstr "" + +msgid "Nothing to list" +msgstr "" + +msgid "Someone probably" +msgstr "" + +msgid "cleared the project history." +msgstr "" + msgid "Manage your shared
expenses, easily" msgstr "Håndter delte
utgifter, enkelt" @@ -376,6 +594,9 @@ msgstr "Gjør opp" msgid "Statistics" msgstr "Statistikk" +msgid "History" +msgstr "" + msgid "Settings" msgstr "Innstillinger" @@ -436,6 +657,12 @@ msgstr "Du kan starte ved å legge til deltagere" msgid "Add a new bill" msgstr "Legg til en ny regning" +msgid "Newer bills" +msgstr "" + +msgid "Older bills" +msgstr "" + msgid "When?" msgstr "Når?" @@ -462,10 +689,6 @@ msgstr "Alle, unntagen %(excluded)s" msgid "each" msgstr "hver" -#, fuzzy -msgid "see" -msgstr "se" - msgid "No bills" msgstr "Ingen regninger" @@ -546,18 +769,17 @@ msgstr "Hvem betaler?" msgid "To whom?" msgstr "Til hvem?" -msgid "Who?" -msgstr "Hvem?" - msgid "Paid" msgstr "Betalt" msgid "Spent" msgstr "Forbrukt" -#, fuzzy -msgid "Balance" -msgstr "Kontobalanse" +msgid "Expenses by Month" +msgstr "" + +msgid "Period" +msgstr "" #~ msgid "" #~ "The project identifier is used to " @@ -672,3 +894,4 @@ msgstr "Kontobalanse" #~ "En lenke for å tilbakestille passordet" #~ " har blitt sent til deg per " #~ "e-post." + diff --git a/ihatemoney/translations/nl/LC_MESSAGES/messages.po b/ihatemoney/translations/nl/LC_MESSAGES/messages.po index d93204e8..02142022 100644 --- a/ihatemoney/translations/nl/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/nl/LC_MESSAGES/messages.po @@ -1,18 +1,18 @@ + msgid "" msgstr "" -"Project-Id-Version: \n" +"Project-Id-Version: \n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2019-09-30 23:53+0200\n" +"POT-Creation-Date: 2020-04-21 14:18+0200\n" "PO-Revision-Date: 2019-10-07 22:56+0000\n" "Last-Translator: Heimen Stoffels \n" -"Language-Team: Dutch \n" "Language: nl\n" +"Language-Team: Dutch \n" +"Plural-Forms: nplurals=2; plural=n != 1\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 3.9-dev\n" "Generated-By: Babel 2.7.0\n" msgid "" @@ -29,6 +29,18 @@ msgstr "Privécode" msgid "Email" msgstr "E-mailadres" +msgid "Enable project history" +msgstr "" + +msgid "Use IP tracking for project history" +msgstr "" + +msgid "Import previously exported JSON file" +msgstr "" + +msgid "Import" +msgstr "" + msgid "Project identifier" msgstr "Project-id" @@ -123,6 +135,15 @@ msgstr "Uitnodigingen versturen" msgid "The email %(email)s is not valid" msgstr "Het e-mailadres '%(email)s' is onjuist" +msgid "Person" +msgstr "" + +msgid "Bill" +msgstr "" + +msgid "Project" +msgstr "Project" + msgid "Too many failed login attempts, please retry later." msgstr "Te vaak onjuist ingelogd. Probeer het later opnieuw." @@ -158,6 +179,12 @@ msgstr "Onbekend project" msgid "Password successfully reset." msgstr "Wachtwoord is hersteld." +msgid "Project successfully uploaded" +msgstr "" + +msgid "Invalid JSON" +msgstr "" + msgid "Project successfully deleted" msgstr "Project is verwijderd" @@ -225,9 +252,6 @@ msgstr "?" msgid "Create a new project" msgstr "Nieuw project aanmaken" -msgid "Project" -msgstr "Project" - msgid "Number of members" msgstr "Aantal deelnemers" @@ -249,6 +273,9 @@ msgstr "bewerken" msgid "delete" msgstr "verwijderen" +msgid "see" +msgstr "bekijk" + msgid "The Dashboard is currently deactivated." msgstr "De overzichtspagina is momenteel uitgeschakeld." @@ -258,6 +285,12 @@ msgstr "weet je het zeker?" msgid "Edit project" msgstr "Project aanpassen" +msgid "Import JSON" +msgstr "" + +msgid "Choose file" +msgstr "" + msgid "Download project's data" msgstr "Projectgegevens downloaden" @@ -281,6 +314,9 @@ msgstr "Ben je je wachtwoord vergeten?" msgid "Cancel" msgstr "Annuleren" +msgid "Privacy Settings" +msgstr "" + msgid "Edit the project" msgstr "Project bewerken" @@ -311,6 +347,186 @@ msgstr "Uitnodigingen versturen" msgid "Download" msgstr "Downloaden" +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 "" + +msgid "Removed" +msgstr "" + +msgid "and" +msgstr "" + +msgid "owers list" +msgstr "" + +msgid "Who?" +msgstr "Wie?" + +msgid "Balance" +msgstr "Saldo" + +msgid "" +"This project has history disabled. New actions won't appear below. You " +"can enable history on the" +msgstr "" + +msgid "settings page" +msgstr "" + +msgid "" +"The table below reflects actions recorded prior to disabling project " +"history. You can " +msgstr "" + +msgid "clear project history" +msgstr "" + +msgid "to remove them." +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 "" + +msgid "Event" +msgstr "" + +msgid "IP address recording can be" +msgstr "" + +msgid "enabled" +msgstr "" + +msgid "disabled" +msgstr "" + +msgid "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" +msgstr "" + +msgid "External link changed to" +msgstr "" + +msgid "Amount" +msgstr "" + +msgid "modified" +msgstr "" + +msgid "removed" +msgstr "" + +msgid "changed in a unknown way" +msgstr "" + +msgid "Nothing to list" +msgstr "" + +msgid "Someone probably" +msgstr "" + +msgid "cleared the project history." +msgstr "" + msgid "Manage your shared
expenses, easily" msgstr "Beheer eenvoudig je
gedeelde uitgaven" @@ -360,6 +576,9 @@ msgstr "Schikken" msgid "Statistics" msgstr "Statistieken" +msgid "History" +msgstr "" + msgid "Settings" msgstr "Instellingen" @@ -417,6 +636,12 @@ msgstr "Begin met het toevoegen van deelnemers" msgid "Add a new bill" msgstr "Nieuwe rekening toevoegen" +msgid "Newer bills" +msgstr "" + +msgid "Older bills" +msgstr "" + msgid "When?" msgstr "Wanneer?" @@ -443,9 +668,6 @@ msgstr "Iedereen, behalve %(excluded)s" msgid "each" msgstr "per persoon" -msgid "see" -msgstr "bekijk" - msgid "No bills" msgstr "Geen rekeningen" @@ -522,17 +744,17 @@ msgstr "Wie betaalt?" msgid "To whom?" msgstr "Aan wie?" -msgid "Who?" -msgstr "Wie?" - msgid "Paid" msgstr "Betaald" msgid "Spent" msgstr "Uitgegeven" -msgid "Balance" -msgstr "Saldo" +msgid "Expenses by Month" +msgstr "" + +msgid "Period" +msgstr "" #~ msgid "" #~ "The project identifier is used to " @@ -647,3 +869,4 @@ msgstr "Saldo" #~ "Er is een link met " #~ "wachtwoordherstelinstructies naar je e-mailadres " #~ "verstuurd." + diff --git a/ihatemoney/translations/tr/LC_MESSAGES/messages.po b/ihatemoney/translations/tr/LC_MESSAGES/messages.po index c072285c..defa954d 100644 --- a/ihatemoney/translations/tr/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/tr/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-01 21:48+0200\n" +"POT-Creation-Date: 2020-04-21 14:18+0200\n" "PO-Revision-Date: 2019-08-07 13:24+0000\n" "Last-Translator: Mesut Akcan \n" "Language: tr\n" @@ -31,6 +31,18 @@ msgstr "Özel kod" msgid "Email" msgstr "E-posta" +msgid "Enable project history" +msgstr "" + +msgid "Use IP tracking for project history" +msgstr "" + +msgid "Import previously exported JSON file" +msgstr "" + +msgid "Import" +msgstr "" + msgid "Project identifier" msgstr "Proje tanımlayıcısı" @@ -127,6 +139,15 @@ msgstr "" msgid "The email %(email)s is not valid" msgstr "" +msgid "Person" +msgstr "" + +msgid "Bill" +msgstr "" + +msgid "Project" +msgstr "" + msgid "Too many failed login attempts, please retry later." msgstr "" @@ -160,6 +181,12 @@ msgstr "" msgid "Password successfully reset." msgstr "" +msgid "Project successfully uploaded" +msgstr "" + +msgid "Invalid JSON" +msgstr "" + msgid "Project successfully deleted" msgstr "" @@ -225,9 +252,6 @@ msgstr "" msgid "Create a new project" msgstr "" -msgid "Project" -msgstr "" - msgid "Number of members" msgstr "" @@ -249,6 +273,9 @@ msgstr "" msgid "delete" msgstr "" +msgid "see" +msgstr "" + msgid "The Dashboard is currently deactivated." msgstr "" @@ -258,6 +285,12 @@ msgstr "" msgid "Edit project" msgstr "" +msgid "Import JSON" +msgstr "" + +msgid "Choose file" +msgstr "" + msgid "Download project's data" msgstr "" @@ -279,6 +312,9 @@ msgstr "" msgid "Cancel" msgstr "" +msgid "Privacy Settings" +msgstr "" + msgid "Edit the project" msgstr "" @@ -309,6 +345,186 @@ msgstr "" msgid "Download" msgstr "" +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 "" + +msgid "Removed" +msgstr "" + +msgid "and" +msgstr "" + +msgid "owers list" +msgstr "" + +msgid "Who?" +msgstr "" + +msgid "Balance" +msgstr "" + +msgid "" +"This project has history disabled. New actions won't appear below. You " +"can enable history on the" +msgstr "" + +msgid "settings page" +msgstr "" + +msgid "" +"The table below reflects actions recorded prior to disabling project " +"history. You can " +msgstr "" + +msgid "clear project history" +msgstr "" + +msgid "to remove them." +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 "" + +msgid "Event" +msgstr "" + +msgid "IP address recording can be" +msgstr "" + +msgid "enabled" +msgstr "" + +msgid "disabled" +msgstr "" + +msgid "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" +msgstr "" + +msgid "External link changed to" +msgstr "" + +msgid "Amount" +msgstr "" + +msgid "modified" +msgstr "" + +msgid "removed" +msgstr "" + +msgid "changed in a unknown way" +msgstr "" + +msgid "Nothing to list" +msgstr "" + +msgid "Someone probably" +msgstr "" + +msgid "cleared the project history." +msgstr "" + msgid "Manage your shared
expenses, easily" msgstr "" @@ -356,6 +572,9 @@ msgstr "" msgid "Statistics" msgstr "" +msgid "History" +msgstr "" + msgid "Settings" msgstr "" @@ -413,6 +632,12 @@ msgstr "" msgid "Add a new bill" msgstr "" +msgid "Newer bills" +msgstr "" + +msgid "Older bills" +msgstr "" + msgid "When?" msgstr "" @@ -439,9 +664,6 @@ msgstr "" msgid "each" msgstr "" -msgid "see" -msgstr "" - msgid "No bills" msgstr "" @@ -510,16 +732,16 @@ msgstr "" msgid "To whom?" msgstr "" -msgid "Who?" -msgstr "" - msgid "Paid" msgstr "" msgid "Spent" msgstr "" -msgid "Balance" +msgid "Expenses by Month" +msgstr "" + +msgid "Period" msgstr "" #~ msgid "What do you want to download ?" diff --git a/ihatemoney/translations/uk/LC_MESSAGES/messages.po b/ihatemoney/translations/uk/LC_MESSAGES/messages.po index 27894755..6b7c3a24 100644 --- a/ihatemoney/translations/uk/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/uk/LC_MESSAGES/messages.po @@ -1,19 +1,20 @@ + msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-12-05 15:35+0200\n" +"POT-Creation-Date: 2020-04-21 14:18+0200\n" "PO-Revision-Date: 2019-12-08 16:26+0000\n" "Last-Translator: Tymofij Lytvynenko \n" -"Language-Team: Ukrainian \n" "Language: uk\n" +"Language-Team: Ukrainian \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" "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" -"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 3.10-dev\n" +"Generated-By: Babel 2.7.0\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " @@ -29,6 +30,18 @@ msgstr "Приватний код" msgid "Email" msgstr "Е-пошта" +msgid "Enable project history" +msgstr "" + +msgid "Use IP tracking for project history" +msgstr "" + +msgid "Import previously exported JSON file" +msgstr "" + +msgid "Import" +msgstr "" + msgid "Project identifier" msgstr "Ідентифікатор проєкту" @@ -123,6 +136,15 @@ msgstr "" msgid "The email %(email)s is not valid" msgstr "" +msgid "Person" +msgstr "" + +msgid "Bill" +msgstr "" + +msgid "Project" +msgstr "" + msgid "Too many failed login attempts, please retry later." msgstr "" @@ -156,6 +178,12 @@ msgstr "" msgid "Password successfully reset." msgstr "" +msgid "Project successfully uploaded" +msgstr "" + +msgid "Invalid JSON" +msgstr "" + msgid "Project successfully deleted" msgstr "" @@ -221,9 +249,6 @@ msgstr "" msgid "Create a new project" msgstr "" -msgid "Project" -msgstr "" - msgid "Number of members" msgstr "" @@ -245,6 +270,9 @@ msgstr "" msgid "delete" msgstr "" +msgid "see" +msgstr "" + msgid "The Dashboard is currently deactivated." msgstr "" @@ -254,6 +282,12 @@ msgstr "" msgid "Edit project" msgstr "" +msgid "Import JSON" +msgstr "" + +msgid "Choose file" +msgstr "" + msgid "Download project's data" msgstr "" @@ -275,6 +309,9 @@ msgstr "" msgid "Cancel" msgstr "" +msgid "Privacy Settings" +msgstr "" + msgid "Edit the project" msgstr "" @@ -305,6 +342,186 @@ msgstr "" msgid "Download" msgstr "" +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 "" + +msgid "Removed" +msgstr "" + +msgid "and" +msgstr "" + +msgid "owers list" +msgstr "" + +msgid "Who?" +msgstr "" + +msgid "Balance" +msgstr "" + +msgid "" +"This project has history disabled. New actions won't appear below. You " +"can enable history on the" +msgstr "" + +msgid "settings page" +msgstr "" + +msgid "" +"The table below reflects actions recorded prior to disabling project " +"history. You can " +msgstr "" + +msgid "clear project history" +msgstr "" + +msgid "to remove them." +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 "" + +msgid "Event" +msgstr "" + +msgid "IP address recording can be" +msgstr "" + +msgid "enabled" +msgstr "" + +msgid "disabled" +msgstr "" + +msgid "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" +msgstr "" + +msgid "External link changed to" +msgstr "" + +msgid "Amount" +msgstr "" + +msgid "modified" +msgstr "" + +msgid "removed" +msgstr "" + +msgid "changed in a unknown way" +msgstr "" + +msgid "Nothing to list" +msgstr "" + +msgid "Someone probably" +msgstr "" + +msgid "cleared the project history." +msgstr "" + msgid "Manage your shared
expenses, easily" msgstr "" @@ -352,6 +569,9 @@ msgstr "" msgid "Statistics" msgstr "" +msgid "History" +msgstr "" + msgid "Settings" msgstr "" @@ -409,6 +629,12 @@ msgstr "" msgid "Add a new bill" msgstr "" +msgid "Newer bills" +msgstr "" + +msgid "Older bills" +msgstr "" + msgid "When?" msgstr "" @@ -435,9 +661,6 @@ msgstr "" msgid "each" msgstr "" -msgid "see" -msgstr "" - msgid "No bills" msgstr "" @@ -506,14 +729,15 @@ msgstr "" msgid "To whom?" msgstr "" -msgid "Who?" -msgstr "" - msgid "Paid" msgstr "" msgid "Spent" msgstr "" -msgid "Balance" +msgid "Expenses by Month" msgstr "" + +msgid "Period" +msgstr "" + diff --git a/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po b/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po index 64251ec9..906c9f6c 100644 --- a/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po @@ -1,18 +1,19 @@ + msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-10-01 21:48+0200\n" +"POT-Creation-Date: 2020-04-21 14:18+0200\n" "PO-Revision-Date: 2020-02-09 12:01+0000\n" "Last-Translator: Muge Niu \n" -"Language-Team: Chinese (Simplified) \n" -"Language: zh_HANS-CN\n" +"Language: zh_HANS_CN\n" +"Language-Team: Chinese (Simplified) " +"" +"\n" +"Plural-Forms: nplurals=1; plural=0\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 3.11-dev\n" "Generated-By: Babel 2.7.0\n" msgid "" @@ -29,6 +30,18 @@ msgstr "共享密钥" msgid "Email" msgstr "邮箱" +msgid "Enable project history" +msgstr "" + +msgid "Use IP tracking for project history" +msgstr "" + +msgid "Import previously exported JSON file" +msgstr "" + +msgid "Import" +msgstr "" + msgid "Project identifier" msgstr "账目名称" @@ -123,6 +136,15 @@ msgstr "" msgid "The email %(email)s is not valid" msgstr "" +msgid "Person" +msgstr "" + +msgid "Bill" +msgstr "" + +msgid "Project" +msgstr "" + msgid "Too many failed login attempts, please retry later." msgstr "" @@ -156,6 +178,12 @@ msgstr "" msgid "Password successfully reset." msgstr "" +msgid "Project successfully uploaded" +msgstr "" + +msgid "Invalid JSON" +msgstr "" + msgid "Project successfully deleted" msgstr "" @@ -221,9 +249,6 @@ msgstr "?" msgid "Create a new project" msgstr "" -msgid "Project" -msgstr "" - msgid "Number of members" msgstr "" @@ -245,6 +270,9 @@ msgstr "" msgid "delete" msgstr "" +msgid "see" +msgstr "" + msgid "The Dashboard is currently deactivated." msgstr "" @@ -254,6 +282,12 @@ msgstr "" msgid "Edit project" msgstr "" +msgid "Import JSON" +msgstr "" + +msgid "Choose file" +msgstr "" + msgid "Download project's data" msgstr "" @@ -275,6 +309,9 @@ msgstr "" msgid "Cancel" msgstr "取消" +msgid "Privacy Settings" +msgstr "" + msgid "Edit the project" msgstr "" @@ -305,6 +342,186 @@ msgstr "" msgid "Download" msgstr "下载" +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 "" + +msgid "Removed" +msgstr "" + +msgid "and" +msgstr "" + +msgid "owers list" +msgstr "" + +msgid "Who?" +msgstr "谁?" + +msgid "Balance" +msgstr "" + +msgid "" +"This project has history disabled. New actions won't appear below. You " +"can enable history on the" +msgstr "" + +msgid "settings page" +msgstr "" + +msgid "" +"The table below reflects actions recorded prior to disabling project " +"history. You can " +msgstr "" + +msgid "clear project history" +msgstr "" + +msgid "to remove them." +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 "" + +msgid "Event" +msgstr "" + +msgid "IP address recording can be" +msgstr "" + +msgid "enabled" +msgstr "" + +msgid "disabled" +msgstr "" + +msgid "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" +msgstr "" + +msgid "External link changed to" +msgstr "" + +msgid "Amount" +msgstr "" + +msgid "modified" +msgstr "" + +msgid "removed" +msgstr "" + +msgid "changed in a unknown way" +msgstr "" + +msgid "Nothing to list" +msgstr "" + +msgid "Someone probably" +msgstr "" + +msgid "cleared the project history." +msgstr "" + msgid "Manage your shared
expenses, easily" msgstr "" @@ -352,6 +569,9 @@ msgstr "" msgid "Statistics" msgstr "" +msgid "History" +msgstr "" + msgid "Settings" msgstr "" @@ -409,6 +629,12 @@ msgstr "" msgid "Add a new bill" msgstr "" +msgid "Newer bills" +msgstr "" + +msgid "Older bills" +msgstr "" + msgid "When?" msgstr "什么时候?" @@ -435,9 +661,6 @@ msgstr "" msgid "each" msgstr "" -msgid "see" -msgstr "" - msgid "No bills" msgstr "" @@ -506,16 +729,16 @@ msgstr "" msgid "To whom?" msgstr "" -msgid "Who?" -msgstr "谁?" - msgid "Paid" msgstr "" msgid "Spent" msgstr "" -msgid "Balance" +msgid "Expenses by Month" +msgstr "" + +msgid "Period" msgstr "" #~ msgid "" @@ -610,3 +833,4 @@ msgstr "" #~ msgid "A link to reset your password has been sent to your email." #~ msgstr "" + From 8e6643302ffa2605f905b9a41888527dffc21564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Wed, 22 Apr 2020 09:42:50 +0200 Subject: [PATCH 13/47] Add a word about isort in the contributing docs. (#564) --- docs/contributing.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 5cff063b..c88d0c35 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -98,13 +98,14 @@ To do so:: make test -We are using the `black `_ formatter -for all the Python files in this project. Be sure to run it locally on your -files. To do so, just run:: +We are using `black `_ and +`isort `_ formatters for all the Python +files in this project. Be sure to run it locally on your files. +To do so, just run:: - black ihatemoney + make black isort -You can also integrate it with your dev environment (as a *format-on-save* +You can also integrate them with your dev environment (as a *format-on-save* hook, for instance). As a designer / Front-end developer From 3592a8e2f7d2901f77c590031212e242c5f9de4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Thu, 23 Apr 2020 10:10:37 +0200 Subject: [PATCH 14/47] Update translations. --- .../translations/de/LC_MESSAGES/messages.mo | Bin 11412 -> 11121 bytes .../translations/el/LC_MESSAGES/messages.mo | Bin 418 -> 418 bytes .../es_419/LC_MESSAGES/messages.mo | Bin 11626 -> 11626 bytes .../translations/fr/LC_MESSAGES/messages.mo | Bin 11042 -> 11776 bytes .../nb_NO/LC_MESSAGES/messages.mo | Bin 8612 -> 8891 bytes .../translations/nl/LC_MESSAGES/messages.mo | Bin 10845 -> 11153 bytes .../translations/tr/LC_MESSAGES/messages.mo | Bin 1724 -> 1724 bytes .../zh_HANS-CN/LC_MESSAGES/messages.mo | Bin 887 -> 2158 bytes 8 files changed, 0 insertions(+), 0 deletions(-) diff --git a/ihatemoney/translations/de/LC_MESSAGES/messages.mo b/ihatemoney/translations/de/LC_MESSAGES/messages.mo index f50651701c3cc322f64765516ccb4c49ec3b9528..5887acc14c8f10c9b0d2cc60c2f865d033a144f2 100644 GIT binary patch delta 3599 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 C!?Aw= diff --git a/ihatemoney/translations/el/LC_MESSAGES/messages.mo b/ihatemoney/translations/el/LC_MESSAGES/messages.mo index 842349518bd4ca38aee8384f47422e938d12d641..c316b44adfac9c845a8f08068ef2bb2a66ec256d 100644 GIT binary patch delta 31 mcmZ3)yoh;1EuWEru7QcJk)eX2iIt(n#%>`-Rtr4?E(QRBQU?V9 delta 31 mcmZ3)yoh;1EuW#Ku7Rblk%@w#nU$&8#%>`-R&zZAE(QRC(FYg+ diff --git a/ihatemoney/translations/es_419/LC_MESSAGES/messages.mo b/ihatemoney/translations/es_419/LC_MESSAGES/messages.mo index 7f1de2ccf2c7a77a837bb4042af6c251037dccbf..ced1f3ad34e7ab0b16f82d9d69d12bcc8b3c91f2 100644 GIT binary patch delta 34 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 diff --git a/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.mo b/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.mo index dd628180ad55e1f41064e1aea8cdb92b86c7fab7..1542f52144109dd8e2d32881ae96ba1c96d9aa1b 100644 GIT binary patch delta 2508 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 bMUUs4O^EFj-Id#tP-i#!*EB^_@@oDDD)V;K delta 2666 zcmY+^eN5F=9LMqRO+dWZMGOQ)h_x<#cea2r8|FihN5~ALJf2XFHCDT2P@%RJg;W*C2EVr2p*I+f)Vgnw;NOVP* zO~xpkgz?BNOGJ;E&(dk=!9t9}ir@{a!&v&8Fbj7eAA6IpX?PMf@c?SVK@7zqyaR_( z3H^>?7(LZYxh0_bUW{gaOQSKJ3nfTWwhHxN9o~+O7>-*|0d-(8cH`Z64*8gehZR@? zl9^>W{UxZts!;Q3#NWy04MmG|)?MFU#(D68?&_9Ek=x0r zCay*u)_PPz?Z{Aj9yQ-fsLH)MjrwcA5iV$N-$pI;8S2yz;bNS?w{S7(DU)AO0gR#o z2qk(=I1S@47Sk{Xm*HB}{QFUX9mARUiI0Yt#$_zUP-gAG3e@2`jq`94X{2H%sxmdG zOqwwtw;?gw>!?iM#VvRqb+#6>KVDpmOljLuiTk=~DDoauM7^jCPdT1N9kz3hgQ&g# z4$JT-ti`!A%!;rROYj8hEg3~(uq@J7MM_bX*vuD!`K*fu2iJO0r96hp$hK934u z#JN9)3iu`}kWlI^-KYg3QS%g{#+9MonkuK?f*-l40DATQ-$mNA?NQWg(}_9QhdgIr zVm*G1%P}t@81Ob!AkU!|+Kud@?L+PHVN|KlB1N#TP>EedVz--^&H6Tj4b`D5M-5nm z+JcR!$~2=gdK$HtyKpuhLM{9ussf**&csF3fA12!-Y72+S3VCMIz^!?L;p!mmNZG*?H9XQPftr(}G)& zh&l_Y7=q=f`Bz|!-v8A!l<6ktfezG!ov8Qz0G8pOxCECG?JC_zm3RPI(|$x9uE`m} zvl5RwD@CX+twe3rBdCDdacVUUKMfs@1CB=>`!SsBA7DOSKn3c`3})y-*0f}&e{ZJW z?S3tA**$h!Alx(R_WvEX)0112ol}&Zx6qqgP`s$X|6+V%1pVA1Z(e?JUSXg=eyPh< z=)XSm<-ivSf4LScZ)9Qe-{Eb63bnICzBf8 d?u|{io@r`Z@BcPqBrG_5b(SN|0n3xzJOu(Jl-3QYb{{X*tXO_Zbc0P0Nz31F> zzUR*Vy?)g&!LB_f@}nn zU@bTb3jaTRJ_bb|OCWBtanLnTD)Ug-4S*Gwf~DWSVR(vgG znY4VpW@LuvLZZ#_kr4%ElI(Mi@1cNTxwHq71+uHbX9~lpNWE0kVg88XA`s(x}U-MjA^c zin7Uv+@zgxuGf)$yp!t5XuOUb zp>-h-J;F>25-PNkN^~m?P@Z6>Y;!ScqR42JC7@#!X(`oJdZAHnbf~5-+X(n%n(C^B zp=cZYx(wUXnQzRQwckWg;Fa!u8QE#tgDuS@6%9qI2fu7;wn2RTej40%7%r*%*`-u zO2!y%R+Dt6jyFS1hN?sF)_f2XqEtn>z6&l!EGfsZ^~w0Lef7<4#~PZS3`*@x*2Al2$;KAQzK#Xx#OzA$CKa zfn8-STGEs?2}e}7!qi9zA=NCe6QXo5Q))DDGE^fLrZo}OF5AltaeNut(iNt=^ zAWILvA=&wUcWN^K(@m#u*qu1%ocS>~{-rZHQaF9PaPgtre}iBycO_l^I5qLqf5GF_ z)e2|s2WM)`nYg|5;H&)fTp@MNy>KTxpUTdE=Z?%cgMGPMGbES3o*O*tOrOnN>n84{ z>1<}K&@)u{_9}6QXPl|g?0jGT^kQ~?p>SoEI0GZ@Y%g(ouQ-_nZ(nz;KbJX6+|e8E zgvjQpv!rf_+%lum!8v^C(Zz#Q>2_mI1u&Zj5+vBIUx`RQrDrtAW?Idd<& z@I6)*zAmZei{O>w8(yeFPhV~^O$w>;{Lek8C!3jd28If$Zh}pm^tcb_{;WHfan4_J z25x%N`u%`zp7_M=9m;0zIs=gQhBKdb&fi&j&`q+LRQ7&vvBSkTcXZZCT^4qJrd!~D D6D;3d delta 442 zcmaDS@SUyxo)F7a1|Z-8Vi_Q=0dbJP9Uz+#i0=Y18xY?IVh$jF2E?2|{2quw;y;0y z1&Be4LGr9X8e}FPkY)wa(ok9vNQ2a=1L;SM4D}2;Kn62VfFDSJ3=)RYQa~DHfg+Tz z4W*5sv?Y)h1pDCBHl`CqFTT!6Uz1A-6O+ z!=Aw>KRv&czl6arF*lVVAhEc(JijPqawSW?nW3ewfu*jIiGrb-m8qGwfsug$SAf56 zP-u7Qz)fq|8Q(PTMRaaq@#%&Nqs)RGK^;EdFwqWt7+ z1skAHRb`5~p}}Nt)($pDzhGTwzsc8Fr Date: Thu, 23 Apr 2020 10:22:50 +0200 Subject: [PATCH 15/47] Pin WTForms 2.2.1 --- .../translations/cs/LC_MESSAGES/messages.mo | Bin 0 -> 447 bytes .../translations/id/LC_MESSAGES/messages.mo | Bin 0 -> 11040 bytes .../translations/uk/LC_MESSAGES/messages.mo | Bin 0 -> 1652 bytes setup.cfg | 1 + 4 files changed, 1 insertion(+) create mode 100644 ihatemoney/translations/cs/LC_MESSAGES/messages.mo create mode 100644 ihatemoney/translations/id/LC_MESSAGES/messages.mo create mode 100644 ihatemoney/translations/uk/LC_MESSAGES/messages.mo diff --git a/ihatemoney/translations/cs/LC_MESSAGES/messages.mo b/ihatemoney/translations/cs/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..3e48ab6462922f0a114fce410e2fe8d814b547e1 GIT binary patch literal 447 zcmYjNO;5r=5XHn(kDfiu!4L=zwv_`}tfoLkqNM~0iQbm7)S9wOcDF`;h6n$izs0Fv zILRdQ-n^Z+GapBX?=^}8%45ot3jB*xs^6%I6*txDS)>-nD_jU|awQo|!@+GhieM4V z?#Ic*nTf5^7Gsm;E9{qoJ)`&K)-v=bB4XaH}+fu(WDJ^HW|FJII6-nrv1ilv&9$ zGEB`Mz`5WX22x4kOp8+U0`* zdPMq7CmzSq{w!YGbp}dWA?cU9ExB9qYR|R>&t(tNC$5dKL21|6-Rr7t)Q?<%v a#-O{*tuy-F1^YV&eZCY0`0Xw^)II^6ih#oa literal 0 HcmV?d00001 diff --git a/ihatemoney/translations/id/LC_MESSAGES/messages.mo b/ihatemoney/translations/id/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..b52a56fcadecc622ab48a40923fd53eddf26e347 GIT binary patch literal 11040 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 njc#LxLPx3)HYCO)$NT>eLc@rg literal 0 HcmV?d00001 diff --git a/ihatemoney/translations/uk/LC_MESSAGES/messages.mo b/ihatemoney/translations/uk/LC_MESSAGES/messages.mo new file mode 100644 index 0000000000000000000000000000000000000000..0bcb78748bde08a7f13fd06cf0aeb413fcc78c5e GIT binary patch literal 1652 zcmZXS&u<$=6vqc>5i(GTB9JOTJcJ0XqP2HTRE2GvkOnsjP1-0m?S;$Qp4iiPXRY0F z8bc3hf=ZC0A|W>%5L6Wi35i1#IbiaucSNOGxPv%x=O2LYtmC8+md2lXGw;3cdvErS zlgI8d{GP{p8LMrKM}Cu!F?Is>6!8FM!{I z&w*Q@@&6Tk2K)^)`TpFu{{fBOzu+nG#N*w%PJ<>c559B8qqwTm@eNe*lf{ zFQBRCckp%aFVOUO97&AsDez6O59|jofkyX3(CB^&n*87F+YiB)VE+wX0G~jUChvP7 zj+it}kCuHQsqRJ5jUX(uQ9o!%1zVKaSjauaNmV)3!{9nEDfTW7Sl;(UjpY{<52aV5 znvipBoGTKNP51KjHdG4atO$KiiQw>>d=cTOR7F6Ohip0&^G2!^lsSwk;=BXfb zsnGO;S#g~vn`*u(xtt4VNQqi49nA~%PQ~3e!TUetSfJ6V4@}~?rMKcG zrdvrWxZSmoWiMWV53DaBy^-jx;J<|++}(l_bdY~H{*39blS(>9rJH!;NZBw@aywDq zgk)R)s5iT@CS9++J4}Ct^9|!`RQ7khR?+>TFGTMpoh~6yM{gO4MQqSCWX#deq_>cx z&Gc=ggPf@>{us%(5+BU$$N=JHBfqYHGCBTtb01M1!>ISiuvmVG<~G yClOrRFM(ifV`0o@;HGoT@Q&%HJ7yS6e+Lf~{m7dT{5HwFbfVm1`g^@M!u|uabA&el literal 0 HcmV?d00001 diff --git a/setup.cfg b/setup.cfg index be62af27..86cce6a5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,6 +34,7 @@ install_requires = Flask-Script==2.0.6 Flask-SQLAlchemy==2.4.1 Flask-WTF==0.14.3 + WTForms==2.2.1 Flask==1.1.2 itsdangerous==1.1.0 Jinja2==2.11.2 From abf1eea842284f6e147d9acf25a13c4e0c076e66 Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Thu, 23 Apr 2020 11:12:16 +0200 Subject: [PATCH 16/47] Translated using Weblate (French) (#566) Currently translated at 80.7% (184 of 228 strings) Translation: I Hate Money/I Hate Money Translate-URL: https://hosted.weblate.org/projects/i-hate-money/i-hate-money/fr/ Co-authored-by: Glandos --- .../translations/fr/LC_MESSAGES/messages.po | 60 ++++++++++--------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/ihatemoney/translations/fr/LC_MESSAGES/messages.po b/ihatemoney/translations/fr/LC_MESSAGES/messages.po index 48864aa9..730f9426 100644 --- a/ihatemoney/translations/fr/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/fr/LC_MESSAGES/messages.po @@ -8,15 +8,16 @@ msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2020-04-21 14:18+0200\n" -"PO-Revision-Date: 2019-10-07 22:56+0000\n" -"Last-Translator: Alexis Metaireau \n" +"PO-Revision-Date: 2020-04-22 22:11+0000\n" +"Last-Translator: Glandos \n" +"Language-Team: French \n" "Language: fr\n" -"Language-Team: French \n" -"Plural-Forms: nplurals=2; plural=n > 1\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.0.2-dev\n" "Generated-By: Babel 2.7.0\n" msgid "" @@ -42,7 +43,7 @@ msgid "Use IP tracking for project history" msgstr "" msgid "Import previously exported JSON file" -msgstr "" +msgstr "Importer un fichier JSON précédemment exporté" msgid "Import" msgstr "Importer" @@ -147,7 +148,7 @@ msgid "Person" msgstr "" msgid "Bill" -msgstr "" +msgstr "Facture" msgid "Project" msgstr "Projets" @@ -294,10 +295,10 @@ msgid "Edit project" msgstr "Éditer le projet" msgid "Import JSON" -msgstr "" +msgstr "Import JSON" msgid "Choose file" -msgstr "" +msgstr "Choisir un fichier" msgid "Download project's data" msgstr "Télécharger les données du projet" @@ -321,7 +322,7 @@ msgid "Cancel" msgstr "Annuler" msgid "Privacy Settings" -msgstr "" +msgstr "Vie privée" msgid "Edit the project" msgstr "Éditer le projet" @@ -354,37 +355,37 @@ msgid "Download" msgstr "Télécharger" msgid "Disabled Project History" -msgstr "" +msgstr "Historisation du projet désactivée" msgid "Disabled Project History & IP Address Recording" -msgstr "" +msgstr "Historisation du projet et enregistrement des adresses IP désactivés" msgid "Enabled Project History" -msgstr "" +msgstr "Historisation du projet activée" msgid "Disabled IP Address Recording" -msgstr "" +msgstr "Enregistrement des adresses IP désactivé" msgid "Enabled Project History & IP Address Recording" -msgstr "" +msgstr "Historisation du projet et enregistrement des adresses IP activés" msgid "Enabled IP Address Recording" -msgstr "" +msgstr "Enregistrement des adresses IP activé" msgid "History Settings Changed" -msgstr "" +msgstr "Changement des paramètres d’historisation" msgid "changed" -msgstr "" +msgstr "modifié" msgid "from" -msgstr "" +msgstr "depuis" msgid "to" -msgstr "" +msgstr "vers" msgid "Confirm Remove IP Adresses" -msgstr "" +msgstr "Confirmer la suppression des adresses IP" msgid "" "Are you sure you want to delete all recorded IP addresses from this " @@ -392,26 +393,32 @@ msgid "" " The rest of the project history will be unaffected. This " "action cannot be undone." msgstr "" +"Êtes vous sûr de supprimer toutes les adresses IP enregistrées dans ce " +"projet ?\n" +"Le reste de l’historique du projet restera inchangé. Cette action est " +"irréversible." msgid "Close" -msgstr "" +msgstr "Fermer" msgid "Confirm Delete" -msgstr "" +msgstr "Confirmer la suppression" msgid "Delete Confirmation" -msgstr "" +msgstr "Confirmation de suppression" msgid "" "Are you sure you want to erase all history for this project? This action " "cannot be undone." msgstr "" +"Êtes vous sûr de supprimer la totalité de l’historique de ce projet ? Cette " +"action est irréversible." msgid "Added" -msgstr "" +msgstr "Ajouté" msgid "Removed" -msgstr "" +msgstr "Supprimé" msgid "and" msgstr "" @@ -906,4 +913,3 @@ msgstr "" #~ msgid "A link to reset your password has been sent to your email." #~ msgstr "Un lien pour changer votre mot de passe vous a été envoyé par mail." - From 7587e292fb6b8322891636e785b63425778ab7c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Fri, 24 Apr 2020 12:32:52 +0200 Subject: [PATCH 17/47] Remove obsolete python code (<3.6). (#571) --- .travis.yml | 1 - README.rst | 2 +- docs/conf.py | 4 -- ihatemoney/api/common.py | 1 - ihatemoney/api/v1/resources.py | 1 - ihatemoney/manage.py | 2 +- ihatemoney/models.py | 13 +++--- ihatemoney/tests/tests.py | 85 +++++++++++++++------------------- ihatemoney/web.py | 10 ++-- setup.cfg | 1 - tox.ini | 3 +- 11 files changed, 51 insertions(+), 72 deletions(-) diff --git a/.travis.yml b/.travis.yml index b3753ea0..ca72fb95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ sudo: false language: python python: - - "3.5" - "3.6" - "3.7" - "3.8" diff --git a/README.rst b/README.rst index c2166955..675ec318 100644 --- a/README.rst +++ b/README.rst @@ -21,7 +21,7 @@ encouraged to do so. Requirements ============ -* **Python**: 3.5, 3.6, 3.7. +* **Python**: 3.6, 3.7, 3.8. * **Backends**: MySQL, PostgreSQL, SQLite, Memory. Contributing diff --git a/docs/conf.py b/docs/conf.py index 4789396e..1ec26a5d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,7 +1,3 @@ -# coding: utf8 -import os -import sys - templates_path = ["_templates"] source_suffix = ".rst" master_doc = "index" diff --git a/ihatemoney/api/common.py b/ihatemoney/api/common.py index 51ce96e8..9aefa2c8 100644 --- a/ihatemoney/api/common.py +++ b/ihatemoney/api/common.py @@ -1,4 +1,3 @@ -# coding: utf8 from functools import wraps from flask import current_app, request diff --git a/ihatemoney/api/v1/resources.py b/ihatemoney/api/v1/resources.py index 87950f65..dc1708ce 100644 --- a/ihatemoney/api/v1/resources.py +++ b/ihatemoney/api/v1/resources.py @@ -1,4 +1,3 @@ -# coding: utf8 from flask import Blueprint from flask_cors import CORS from flask_restful import Api diff --git a/ihatemoney/manage.py b/ihatemoney/manage.py index a192844c..eb1e24c2 100755 --- a/ihatemoney/manage.py +++ b/ihatemoney/manage.py @@ -51,7 +51,7 @@ class GenerateConfig(Command): def run(self, config_file): env = create_jinja_env("conf-templates", strict_rendering=True) - template = env.get_template("%s.j2" % config_file) + template = env.get_template(f"{config_file}.j2") bin_path = os.path.dirname(sys.executable) pkg_path = os.path.abspath(os.path.dirname(__file__)) diff --git a/ihatemoney/models.py b/ihatemoney/models.py index eae442ac..dca86110 100644 --- a/ihatemoney/models.py +++ b/ihatemoney/models.py @@ -323,7 +323,7 @@ class Project(db.Model): return self.name def __repr__(self): - return "" % self.name + return f"" class Person(db.Model): @@ -381,7 +381,7 @@ class Person(db.Model): return self.name def __repr__(self): - return "" % (self.name, self.project.name) + return f"" # We need to manually define a join table for m2m relations @@ -460,13 +460,12 @@ class Bill(db.Model): return 0 def __str__(self): - return "%s for %s" % (self.amount, self.what) + return f"{self.amount} for {self.what}" def __repr__(self): - return "" % ( - self.amount, - self.payer, - ", ".join([o.name for o in self.owers]), + return ( + f"" ) diff --git a/ihatemoney/tests/tests.py b/ihatemoney/tests/tests.py index b27fafcc..c836c970 100644 --- a/ihatemoney/tests/tests.py +++ b/ihatemoney/tests/tests.py @@ -1,4 +1,3 @@ -# coding: utf8 import base64 from collections import defaultdict import datetime @@ -59,7 +58,7 @@ class BaseTestCase(TestCase): "name": name, "id": name, "password": name, - "contact_email": "%s@notmyidea.org" % name, + "contact_email": f"{name}@notmyidea.org", }, ) @@ -68,7 +67,7 @@ class BaseTestCase(TestCase): id=name, name=str(name), password=generate_password_hash(name), - contact_email="%s@notmyidea.org" % name, + contact_email=f"{name}@notmyidea.org", ) models.db.session.add(project) models.db.session.commit() @@ -83,7 +82,7 @@ class IhatemoneyTestCase(BaseTestCase): return self.assertEqual( expected, resp.status_code, - "%s expected %s, got %s" % (url, expected, resp.status_code), + f"{url} expected {expected}, got {resp.status_code}", ) @@ -410,7 +409,7 @@ class BudgetTestCase(IhatemoneyTestCase): ) # remove fred - self.client.post("/raclette/members/%s/delete" % fred_id) + self.client.post(f"/raclette/members/{fred_id}/delete") # he is still in the database, but is deactivated self.assertEqual(len(models.Project.query.get("raclette").members), 2) @@ -420,7 +419,7 @@ class BudgetTestCase(IhatemoneyTestCase): # a bill or displaying the balance result = self.client.get("/raclette/") self.assertNotIn( - ("/raclette/members/%s/delete" % fred_id), result.data.decode("utf-8") + (f"/raclette/members/{fred_id}/delete"), result.data.decode("utf-8") ) result = self.client.get("/raclette/add") @@ -619,7 +618,7 @@ class BudgetTestCase(IhatemoneyTestCase): # edit the bill self.client.post( - "/raclette/edit/%s" % bill.id, + f"/raclette/edit/{bill.id}", data={ "date": "2011-08-10", "what": "fromage à raclette", @@ -633,7 +632,7 @@ class BudgetTestCase(IhatemoneyTestCase): self.assertEqual(bill.amount, 10, "bill edition") # delete the bill - self.client.get("/raclette/delete/%s" % bill.id) + self.client.get(f"/raclette/delete/{bill.id}") self.assertEqual(0, len(models.Bill.query.all()), "bill deletion") # test balance @@ -1079,7 +1078,7 @@ class BudgetTestCase(IhatemoneyTestCase): self.assertNotEqual( 0.0, rounded_amount, - msg="%f is equal to zero after rounding" % t["amount"], + msg=f"{t['amount']} is equal to zero after rounding", ) def test_export(self): @@ -1417,7 +1416,7 @@ class APITestCase(IhatemoneyTestCase): def api_create(self, name, id=None, password=None, contact=None): id = id or name password = password or name - contact = contact or "%s@notmyidea.org" % name + contact = contact or f"{name}@notmyidea.org" return self.client.post( "/api/projects", @@ -1431,7 +1430,7 @@ class APITestCase(IhatemoneyTestCase): def api_add_member(self, project, name, weight=1): self.client.post( - "/api/projects/%s/members" % project, + f"/api/projects/{project}/members", data={"name": name, "weight": weight}, headers=self.get_auth(project), ) @@ -1439,11 +1438,11 @@ class APITestCase(IhatemoneyTestCase): def get_auth(self, username, password=None): password = password or username base64string = ( - base64.encodebytes(("%s:%s" % (username, password)).encode("utf-8")) + base64.encodebytes(f"{username}:{password}".encode("utf-8")) .decode("utf-8") .replace("\n", "") ) - return {"Authorization": "Basic %s" % base64string} + return {"Authorization": f"Basic {base64string}"} def test_cors_requests(self): # Create a project and test that CORS headers are present if requested. @@ -1599,7 +1598,7 @@ class APITestCase(IhatemoneyTestCase): # Access with token resp = self.client.get( "/api/projects/raclette/token", - headers={"Authorization": "Basic %s" % decoded_resp["token"]}, + headers={"Authorization": f"Basic {decoded_resp['token']}"}, ) self.assertEqual(200, resp.status_code) @@ -2124,10 +2123,10 @@ class APITestCase(IhatemoneyTestCase): resp = self.client.get("/raclette/history", follow_redirects=True) self.assertEqual(resp.status_code, 200) self.assertIn( - "Person %s added" % em_surround("alexis"), resp.data.decode("utf-8") + f"Person {em_surround('alexis')} added", resp.data.decode("utf-8") ) self.assertIn( - "Project %s added" % em_surround("raclette"), resp.data.decode("utf-8"), + f"Project {em_surround('raclette')} added", resp.data.decode("utf-8"), ) self.assertEqual(resp.data.decode("utf-8").count(" -- "), 2) self.assertNotIn("127.0.0.1", resp.data.decode("utf-8")) @@ -2263,7 +2262,7 @@ class HistoryTestCase(IhatemoneyTestCase): resp = self.client.get("/demo/history") self.assertEqual(resp.status_code, 200) self.assertIn( - "Project %s added" % em_surround("demo"), resp.data.decode("utf-8"), + f"Project {em_surround('demo')} added", resp.data.decode("utf-8"), ) self.assertEqual(resp.data.decode("utf-8").count(" -- "), 1) self.assertNotIn("127.0.0.1", resp.data.decode("utf-8")) @@ -2319,7 +2318,7 @@ class HistoryTestCase(IhatemoneyTestCase): self.assertNotIn("127.0.0.1", resp.data.decode("utf-8")) self.assertNotIn(" -- ", resp.data.decode("utf-8")) self.assertNotIn( - "Project %s added" % em_surround("demo"), resp.data.decode("utf-8") + f"Project {em_surround('demo')} added", resp.data.decode("utf-8") ) def test_project_edit(self): @@ -2335,18 +2334,16 @@ class HistoryTestCase(IhatemoneyTestCase): 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( - "Project %s added" % em_surround("demo"), resp.data.decode("utf-8") - ) - self.assertIn( - "Project contact email changed to %s" % em_surround("demo2@notmyidea.org"), + 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( - "Project renamed to %s" % em_surround("demo2"), resp.data.decode("utf-8"), + f"Project renamed to {em_surround('demo2')}", resp.data.decode("utf-8"), ) self.assertLess( resp.data.decode("utf-8").index("Project renamed "), @@ -2462,7 +2459,7 @@ class HistoryTestCase(IhatemoneyTestCase): # edit the bill resp = self.client.post( - "/demo/edit/%i" % bill_id, + f"/demo/edit/{bill_id}", data={ "date": "2011-08-10", "what": "fromage à raclette", @@ -2474,12 +2471,12 @@ class HistoryTestCase(IhatemoneyTestCase): ) self.assertEqual(resp.status_code, 200) # delete the bill - resp = self.client.get("/demo/delete/%i" % bill_id, follow_redirects=True) + 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( - "/demo/members/%i/delete" % user_id, follow_redirects=True + f"/demo/members/{user_id}/delete", follow_redirects=True ) self.assertEqual(resp.status_code, 200) @@ -2581,7 +2578,7 @@ class HistoryTestCase(IhatemoneyTestCase): resp = self.client.get("/demo/history") self.assertEqual(resp.status_code, 200) self.assertIn( - "Person %s added" % em_surround("alexis"), resp.data.decode("utf-8") + f"Person {em_surround('alexis')} added", resp.data.decode("utf-8") ) # create a bill @@ -2601,7 +2598,7 @@ class HistoryTestCase(IhatemoneyTestCase): resp = self.client.get("/demo/history") self.assertEqual(resp.status_code, 200) self.assertIn( - "Bill %s added" % em_surround("25.0 for fromage à raclette"), + f"Bill {em_surround('25.0 for fromage à raclette')} added", resp.data.decode("utf-8"), ) @@ -2622,7 +2619,7 @@ class HistoryTestCase(IhatemoneyTestCase): resp = self.client.get("/demo/history") self.assertEqual(resp.status_code, 200) self.assertIn( - "Bill %s added" % em_surround("25.0 for fromage à raclette"), + f"Bill {em_surround('25.0 for fromage à raclette')} added", resp.data.decode("utf-8"), ) self.assertRegex( @@ -2641,7 +2638,7 @@ class HistoryTestCase(IhatemoneyTestCase): ) self.assertLess( resp.data.decode("utf-8").index( - "Bill %s renamed to" % em_surround("25.0 for fromage à raclette") + f"Bill {em_surround('25.0 for fromage à raclette')} renamed to" ), resp.data.decode("utf-8").index("Amount changed"), ) @@ -2653,7 +2650,7 @@ class HistoryTestCase(IhatemoneyTestCase): resp = self.client.get("/demo/history") self.assertEqual(resp.status_code, 200) self.assertIn( - "Bill %s removed" % em_surround("10.0 for new thing"), + f"Bill {em_surround('10.0 for new thing')} removed", resp.data.decode("utf-8"), ) @@ -2682,9 +2679,7 @@ class HistoryTestCase(IhatemoneyTestCase): resp.data.decode("utf-8"), ) self.assertLess( - resp.data.decode("utf-8").index( - "Person %s renamed" % em_surround("alexis") - ), + resp.data.decode("utf-8").index(f"Person {em_surround('alexis')} renamed"), resp.data.decode("utf-8").index("Weight changed"), ) @@ -2695,7 +2690,7 @@ class HistoryTestCase(IhatemoneyTestCase): resp = self.client.get("/demo/history") self.assertEqual(resp.status_code, 200) self.assertIn( - "Person %s removed" % em_surround("new name"), resp.data.decode("utf-8") + f"Person {em_surround('new name')} removed", resp.data.decode("utf-8") ) def test_double_bill_double_person_edit_second(self): @@ -2748,8 +2743,7 @@ class HistoryTestCase(IhatemoneyTestCase): self.assertEqual(resp.status_code, 200) self.assertRegex( resp.data.decode("utf-8"), - r"Bill %s:\s* Amount changed\s* from %s\s* to %s" - % ( + r"Bill {}:\s* Amount changed\s* from {}\s* to {}".format( em_surround("25.0 for Bill 1", regex_escape=True), em_surround("25.0", regex_escape=True), em_surround("88.0", regex_escape=True), @@ -2758,8 +2752,7 @@ class HistoryTestCase(IhatemoneyTestCase): self.assertNotRegex( resp.data.decode("utf-8"), - r"Removed\s* %s\s* and\s* %s\s* from\s* owers list" - % ( + 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), ), @@ -2795,11 +2788,10 @@ class HistoryTestCase(IhatemoneyTestCase): self.assertEqual(resp.data.decode("utf-8").count(" -- "), 5) self.assertNotIn("127.0.0.1", resp.data.decode("utf-8")) self.assertIn( - "Bill %s added" % em_surround("25.0 for Bill 1"), resp.data.decode("utf-8") + f"Bill {em_surround('25.0 for Bill 1')} added", resp.data.decode("utf-8") ) self.assertIn( - "Bill %s removed" % em_surround("25.0 for Bill 1"), - resp.data.decode("utf-8"), + f"Bill {em_surround('25.0 for Bill 1')} removed", resp.data.decode("utf-8"), ) # Add a new bill @@ -2819,20 +2811,19 @@ class HistoryTestCase(IhatemoneyTestCase): self.assertEqual(resp.data.decode("utf-8").count(" -- "), 6) self.assertNotIn("127.0.0.1", resp.data.decode("utf-8")) self.assertIn( - "Bill %s added" % em_surround("25.0 for Bill 1"), resp.data.decode("utf-8") + f"Bill {em_surround('25.0 for Bill 1')} added", resp.data.decode("utf-8") ) self.assertEqual( resp.data.decode("utf-8").count( - "Bill %s added" % em_surround("25.0 for Bill 1") + f"Bill {em_surround('25.0 for Bill 1')} added" ), 1, ) self.assertIn( - "Bill %s added" % em_surround("20.0 for Bill 2"), resp.data.decode("utf-8") + f"Bill {em_surround('20.0 for Bill 2')} added", resp.data.decode("utf-8") ) self.assertIn( - "Bill %s removed" % em_surround("25.0 for Bill 1"), - resp.data.decode("utf-8"), + f"Bill {em_surround('25.0 for Bill 1')} removed", resp.data.decode("utf-8"), ) def test_double_bill_double_person_edit_second_no_web(self): diff --git a/ihatemoney/web.py b/ihatemoney/web.py index a12eae19..a2f25e29 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -301,9 +301,7 @@ def create_project(): project=g.project.name, ) - message_body = render_template( - "reminder_mail.%s.j2" % get_locale().language - ) + message_body = render_template(f"reminder_mail.{get_locale().language}.j2") msg = Message( message_title, body=message_body, recipients=[project.contact_email] @@ -337,7 +335,7 @@ def remind_password(): # get the project project = Project.query.get(form.id.data) # send a link to reset the password - password_reminder = "password_reminder.%s.j2" % get_locale().language + password_reminder = f"password_reminder.{get_locale().language}.j2" current_app.mail.send( Message( "password recovery", @@ -520,7 +518,7 @@ def export_project(file, format): return send_file( file2export, - attachment_filename="%s-%s.%s" % (g.project.id, file, format), + attachment_filename=f"{g.project.id}-{file}.{format}", as_attachment=True, ) @@ -570,7 +568,7 @@ def invite(): # send the email message_body = render_template( - "invitation_mail.%s.j2" % get_locale().language + f"invitation_mail.{get_locale().language}.j2" ) message_title = _( diff --git a/setup.cfg b/setup.cfg index 86cce6a5..50a24a41 100644 --- a/setup.cfg +++ b/setup.cfg @@ -11,7 +11,6 @@ license = Custom BSD Beerware classifiers = Programming Language :: Python Programming Language :: Python :: 3 - Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 diff --git a/tox.ini b/tox.ini index 7632ed83..372f60f9 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py38,py37,py36,py35,docs,flake8,black +envlist = py38,py37,py36,docs,flake8,black skip_missing_interpreters = True [testenv] @@ -39,7 +39,6 @@ extend-ignore = [travis] python = - 3.5: py35 3.6: py36 3.7: py37 3.8: py38, docs, black, flake8 From d4ad149a63c6e7dc1e9c30b7c53d83e5daa219ef Mon Sep 17 00:00:00 2001 From: zorun Date: Fri, 24 Apr 2020 13:45:39 +0200 Subject: [PATCH 18/47] Improve documentation regarding database migrations (#569) --- docs/contributing.rst | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index c88d0c35..27f890b3 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -48,21 +48,36 @@ In case you want to update to newer versions (from Git), you can just run the "u Create database migrations -------------------------- -In case you need to modify the database schema, first update the models in -``ihatemoney/models.py``. Then run the following command to create a new -database revision file:: +In case you need to modify the database schema, first make sure that you have +an up-to-date database by running the dev server at least once (the quick way +or the hard way, see above). The dev server applies all existing migrations +when starting up. + +You can now update the models in ``ihatemoney/models.py``. Then run the following +command to create a new database revision file:: make create-database-revision If your changes are simple enough, the generated script will be populated with -the necessary migrations steps. You can edit the generated script. e.g: To add -data migrations. +the necessary migrations steps. You can view and edit the generated script, which +is useful to review that the expected model changes have been properly detected. +Usually the auto-detection works well in most cases, but you can of course edit the +script to fix small issues. You could also edit the script to add data migrations. + +When you are done with your changes, don't forget to add the migration script to +your final git commit! + +If the migration script looks completely wrong, remove the script and start again +with an empty database. The simplest way is to remove or rename the dev database +located at ``/tmp/ihatemoney.db``, and run the dev server at least once. For complex migrations, it is recommended to start from an empty revision file which can be created with the following command:: make create-empty-database-revision +You then need to write the migration steps yourself. + Useful settings ---------------- From 10c35e41ce7ef79ff3593b85aebac03e43eb4445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Fri, 24 Apr 2020 15:22:37 +0200 Subject: [PATCH 19/47] Update install docs. --- docs/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index 4994499e..ca2b9bdf 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -17,7 +17,7 @@ Requirements «Ihatemoney» depends on: -* **Python**: either 3.5, 3.6 or 3.7 will work. +* **Python**: either 3.6, 3.7 or 3.8 will work. * **A Backend**: to choose among MySQL, PostgreSQL, SQLite or Memory. * **Virtualenv** (recommended): `virtualenv` package under Debian/Ubuntu. From d0fa723877b78e2cac264c3d7b0b1f430bc05a6c Mon Sep 17 00:00:00 2001 From: zorun Date: Sat, 25 Apr 2020 11:48:32 +0200 Subject: [PATCH 20/47] Add Indonesian and Norwegian to the list of supported languages (#572) According to https://hosted.weblate.org/projects/i-hate-money/i-hate-money/ these translations are almost complete (69% and 58% currently, but that's because there have been lots of new strings to translate recently) Co-authored-by: Baptiste Jonglez --- ihatemoney/default_settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ihatemoney/default_settings.py b/ihatemoney/default_settings.py index 7ce44220..4895ab98 100644 --- a/ihatemoney/default_settings.py +++ b/ihatemoney/default_settings.py @@ -8,4 +8,4 @@ ACTIVATE_DEMO_PROJECT = True ADMIN_PASSWORD = "" ALLOW_PUBLIC_PROJECT_CREATION = True ACTIVATE_ADMIN_DASHBOARD = False -SUPPORTED_LANGUAGES = ["en", "fr", "de", "nl", "es_419"] +SUPPORTED_LANGUAGES = ["en", "fr", "de", "nl", "es_419", "nb_NO", "id"] From e458da954d008635515f75e6aa1ac2520b5254f2 Mon Sep 17 00:00:00 2001 From: zorun Date: Sat, 25 Apr 2020 11:49:50 +0200 Subject: [PATCH 21/47] Reorganize "Contributing" documentation to be more accessible to new contributors (#573) * Reorganize "Contributing" documentation to be more accessible to new contributors The following changes were done: - move "How to contribute" first, and "Set up a dev environment" as the second section. This way, a new contributor has access to the most general information first, instead of the very specific "dev environment" documentation. - reduce "How to contribute" / "As a developer" by moving the part about tests to a new "Contributing as a developer" section (see below). This way, all types of contributions get roughly the same amount of text in the first "How to contribute" section. - add a new "Contributing as a developer" section, which lists items that are useful when preparing a code contribution (running tests, formatting code, create database migration). These items were moved either from "How to contribute" or from "Set up a dev environment". * Add brief documentation about updating and adding tests Co-authored-by: Baptiste Jonglez --- docs/contributing.rst | 185 +++++++++++++++++++++++++----------------- 1 file changed, 109 insertions(+), 76 deletions(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 27f890b3..34015241 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -1,6 +1,56 @@ Contributing ############ +.. _how-to-contribute: + +How to contribute +================= + +You would like to contribute? First, thanks a bunch! This project is a small +project with just a few people behind it, so any help is appreciated! + +There are different ways to help us, regarding if you are a designer, +a developer or an user. + +As a developer +-------------- + +If you want to contribute code, you can write it and then issue a pull request +on github. To get started, please read :ref:`setup-dev-environment` and +:ref:`contributing-developer`. + +As a designer / Front-end developer +----------------------------------- + +Feel free to provide mockups, or to involve yourself in the discussions +happening on the GitHub issue tracker. All ideas are welcome. Of course, if you +know how to implement them, feel free to fork and make a pull request. + +As a translator +--------------- + +If you're able to translate Ihatemoney in your own language, +head over to `the website we use for translations `_ +and start translating. + +All the heavy lifting will be done automatically, and your strings will +eventually be integrated. + +Once a language is ready to be integrated, add it to the +``SUPPORTED_LANGUAGES`` list, in ``ihatemoney/default_settings.py``. + +End-user +-------- + +You are using the application and found a bug? You have some ideas about how to +improve the project? Please tell us `by filling a new issue `_. +Or, if you prefer, you can send me an e-mail to `alexis@notmyidea.org` and I +will update the issue tracker with your feedback. + +Thanks again! + +.. _setup-dev-environment: + Set up a dev environment ======================== @@ -45,8 +95,65 @@ In case you want to update to newer versions (from Git), you can just run the "u make update -Create database migrations --------------------------- +Useful settings +---------------- + +It is better to actually turn the debugging mode on when you're developing. +You can create a ``settings.cfg`` file, with the following content:: + + DEBUG = True + SQLACHEMY_ECHO = DEBUG + +You can also set the `TESTING` flag to `True` so no mails are sent +(and no exception is raised) while you're on development mode. +Then before running the application, declare its path with :: + + export IHATEMONEY_SETTINGS_FILE_PATH="$(pwd)/settings.cfg" + +.. _contributing-developer: + +Contributing as a developer +=========================== + +All code contributions should be submitted as Pull Requests on the +`github project `_. + +Below are some points that you should check to help you prepare your Pull Request. + +Running tests +------------- + +Please, think about updating and running the tests before asking for a pull request +as it will help us to maintain the code clean and running. + +To run the tests:: + + make test + +Tests can be edited in ``ihatemoney/tests/tests.py``. If some test cases fail because +of your changes, first check whether your code correctly handle these cases. +If you are confident that your code is correct and that the test cases simply need +to be updated to match your changes, update the test cases and send them as part of +your pull request. + +If you are introducing a new feature, you need to either add tests to existing classes, +or add a new class (if your new feature is significantly different from existing code). + +Formatting code +--------------- + +We are using `black `_ and +`isort `_ formatters for all the Python +files in this project. Be sure to run it locally on your files. +To do so, just run:: + + make black isort + +You can also integrate them with your dev environment (as a *format-on-save* +hook, for instance). + +Creating database migrations +---------------------------- In case you need to modify the database schema, first make sure that you have an up-to-date database by running the dev server at least once (the quick way @@ -78,80 +185,6 @@ which can be created with the following command:: You then need to write the migration steps yourself. -Useful settings ----------------- - -It is better to actually turn the debugging mode on when you're developing. -You can create a ``settings.cfg`` file, with the following content:: - - DEBUG = True - SQLACHEMY_ECHO = DEBUG - -You can also set the `TESTING` flag to `True` so no mails are sent -(and no exception is raised) while you're on development mode. -Then before running the application, declare its path with :: - - export IHATEMONEY_SETTINGS_FILE_PATH="$(pwd)/settings.cfg" - -How to contribute -================= - -You would like to contribute? First, thanks a bunch! This project is a small -project with just a few people behind it, so any help is appreciated! - -There are different ways to help us, regarding if you are a designer, -a developer or an user. - -As a developer --------------- - -If you want to contribute code, you can write it and then issue a pull request -on github. Please, think about updating and running the tests before asking for -a pull request as it will help us to maintain the code clean and running. - -To do so:: - - make test - -We are using `black `_ and -`isort `_ formatters for all the Python -files in this project. Be sure to run it locally on your files. -To do so, just run:: - - make black isort - -You can also integrate them with your dev environment (as a *format-on-save* -hook, for instance). - -As a designer / Front-end developer ------------------------------------ - -Feel free to provide mockups, or to involve yourself in the discussions -happening on the GitHub issue tracker. All ideas are welcome. Of course, if you -know how to implement them, feel free to fork and make a pull request. - -As a translator ---------------- - -If you're able to translate Ihatemoney in your own language, -head over to `the website we use for translations `_ -and start translating. - -All the heavy lifting will be done automatically, and your strings will -eventually be integrated. - -Once a language is ready to be integrated, add it to the -``SUPPORTED_LANGUAGES`` list, in ``ihatemoney/default_settings.py``. - -End-user --------- - -You are using the application and found a bug? You have some ideas about how to -improve the project? Please tell us `by filling a new issue `_. -Or, if you prefer, you can send me an e-mail to `alexis@notmyidea.org` and I -will update the issue tracker with your feedback. - -Thanks again! How to build the documentation ? ================================ From c2afed269a2f0785852f5ffd0ae9ac840b56927c Mon Sep 17 00:00:00 2001 From: zorun Date: Sat, 25 Apr 2020 11:50:45 +0200 Subject: [PATCH 22/47] Add weblate translation status to the README (#574) Co-authored-by: Baptiste Jonglez --- README.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.rst b/README.rst index 675ec318..84d73b4a 100644 --- a/README.rst +++ b/README.rst @@ -5,6 +5,10 @@ I hate money :target: https://travis-ci.org/spiral-project/ihatemoney :alt: Travis CI Build Status +.. image:: https://hosted.weblate.org/widgets/i-hate-money/-/i-hate-money/svg-badge.svg + :target: https://hosted.weblate.org/engage/i-hate-money/?utm_source=widget + :alt: Translation status from Weblate + *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 bills. @@ -31,3 +35,9 @@ Do you wish to contribute to IHateMoney? Fantastic! There's a lot of very useful help on the official `contributing `_ page. +Translation status +================== + +.. image:: https://hosted.weblate.org/widgets/i-hate-money/-/i-hate-money/multi-blue.svg + :target: https://hosted.weblate.org/engage/i-hate-money/?utm_source=widget + :alt: Translation status for each language From d6d084f26a9de543527486e3c1fbc4e9100fddbd Mon Sep 17 00:00:00 2001 From: zorun Date: Sat, 25 Apr 2020 11:55:20 +0200 Subject: [PATCH 23/47] Fix translations (#575) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix user-facing string and update translation catalog In the flash message confirming member creation, change "member had been added" into the correct form "member has been added". No translation has been changed. Some translators seem to have already spotted the mistake while translating, but I can't tell for all languages. * Change "Person" to "Participant" in history view Currently, the main user-facing term is "Participant", as seen for instance in the "Add participant" form. "Person" is not used anywhere in the interface. See #302 for a more general discussion on choosing the right terminology. * Fix obsolete translations. Co-authored-by: Baptiste Jonglez Co-authored-by: Rémy HUBSCHER --- ihatemoney/history.py | 2 +- ihatemoney/messages.pot | 4 +- ihatemoney/tests/tests.py | 14 +- .../translations/cs/LC_MESSAGES/messages.po | 9 +- .../translations/de/LC_MESSAGES/messages.po | 11 +- .../translations/el/LC_MESSAGES/messages.po | 91 +--------- .../es_419/LC_MESSAGES/messages.po | 11 +- .../translations/fr/LC_MESSAGES/messages.po | 168 ++---------------- .../translations/id/LC_MESSAGES/messages.po | 11 +- .../nb_NO/LC_MESSAGES/messages.po | 125 +------------ .../translations/nl/LC_MESSAGES/messages.po | 125 +------------ .../translations/tr/LC_MESSAGES/messages.po | 85 +-------- .../translations/uk/LC_MESSAGES/messages.po | 9 +- .../zh_HANS-CN/LC_MESSAGES/messages.po | 102 +---------- ihatemoney/web.py | 2 +- 15 files changed, 67 insertions(+), 702 deletions(-) diff --git a/ihatemoney/history.py b/ihatemoney/history.py index 40aa7619..9dda3de6 100644 --- a/ihatemoney/history.py +++ b/ihatemoney/history.py @@ -70,7 +70,7 @@ def get_history(project, human_readable_names=True): for version_list in [person_query.all(), project_query.all(), bill_query.all()]: for version in version_list: object_type = { - "Person": _("Person"), + "Person": _("Participant"), "Bill": _("Bill"), "Project": _("Project"), }[parent_class(type(version)).__name__] diff --git a/ihatemoney/messages.pot b/ihatemoney/messages.pot index 18782fed..a03f8e26 100644 --- a/ihatemoney/messages.pot +++ b/ihatemoney/messages.pot @@ -118,7 +118,7 @@ msgstr "" msgid "The email %(email)s is not valid" msgstr "" -msgid "Person" +msgid "Participant" msgstr "" msgid "Bill" @@ -177,7 +177,7 @@ msgid "Your invitations have been sent" msgstr "" #, python-format -msgid "%(member)s had been added" +msgid "%(member)s has been added" msgstr "" #, python-format diff --git a/ihatemoney/tests/tests.py b/ihatemoney/tests/tests.py index c836c970..b50fae6c 100644 --- a/ihatemoney/tests/tests.py +++ b/ihatemoney/tests/tests.py @@ -2123,7 +2123,7 @@ class APITestCase(IhatemoneyTestCase): resp = self.client.get("/raclette/history", follow_redirects=True) self.assertEqual(resp.status_code, 200) self.assertIn( - f"Person {em_surround('alexis')} added", resp.data.decode("utf-8") + f"Participant {em_surround('alexis')} added", resp.data.decode("utf-8") ) self.assertIn( f"Project {em_surround('raclette')} added", resp.data.decode("utf-8"), @@ -2578,7 +2578,7 @@ class HistoryTestCase(IhatemoneyTestCase): resp = self.client.get("/demo/history") self.assertEqual(resp.status_code, 200) self.assertIn( - f"Person {em_surround('alexis')} added", resp.data.decode("utf-8") + f"Participant {em_surround('alexis')} added", resp.data.decode("utf-8") ) # create a bill @@ -2666,7 +2666,7 @@ class HistoryTestCase(IhatemoneyTestCase): self.assertEqual(resp.status_code, 200) self.assertRegex( resp.data.decode("utf-8"), - r"Person %s:\s* Weight changed\s* from %s\s* to %s" + r"Participant %s:\s* Weight changed\s* from %s\s* to %s" % ( em_surround("alexis", regex_escape=True), em_surround("1.0", regex_escape=True), @@ -2674,12 +2674,14 @@ class HistoryTestCase(IhatemoneyTestCase): ), ) self.assertIn( - "Person %s renamed to %s" + "Participant %s renamed to %s" % (em_surround("alexis"), em_surround("new name"),), resp.data.decode("utf-8"), ) self.assertLess( - resp.data.decode("utf-8").index(f"Person {em_surround('alexis')} renamed"), + resp.data.decode("utf-8").index( + f"Participant {em_surround('alexis')} renamed" + ), resp.data.decode("utf-8").index("Weight changed"), ) @@ -2690,7 +2692,7 @@ class HistoryTestCase(IhatemoneyTestCase): resp = self.client.get("/demo/history") self.assertEqual(resp.status_code, 200) self.assertIn( - f"Person {em_surround('new name')} removed", resp.data.decode("utf-8") + f"Participant {em_surround('new name')} removed", resp.data.decode("utf-8") ) def test_double_bill_double_person_edit_second(self): diff --git a/ihatemoney/translations/cs/LC_MESSAGES/messages.po b/ihatemoney/translations/cs/LC_MESSAGES/messages.po index b5ebf740..3687aad1 100644 --- a/ihatemoney/translations/cs/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/cs/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-21 14:18+0200\n" +"POT-Creation-Date: 2020-04-24 19:59+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Automatically generated\n" "Language: cs\n" @@ -12,7 +12,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.7.0\n" +"Generated-By: Babel 2.8.0\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " @@ -134,7 +134,7 @@ msgstr "" msgid "The email %(email)s is not valid" msgstr "" -msgid "Person" +msgid "Participant" msgstr "" msgid "Bill" @@ -193,7 +193,7 @@ msgid "Your invitations have been sent" msgstr "" #, python-format -msgid "%(member)s had been added" +msgid "%(member)s has been added" msgstr "" #, python-format @@ -738,4 +738,3 @@ msgstr "" msgid "Period" msgstr "" - diff --git a/ihatemoney/translations/de/LC_MESSAGES/messages.po b/ihatemoney/translations/de/LC_MESSAGES/messages.po index 2a93670a..763dfdcb 100644 --- a/ihatemoney/translations/de/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/de/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-21 14:18+0200\n" +"POT-Creation-Date: 2020-04-24 19:59+0200\n" "PO-Revision-Date: 2020-02-12 10:50+0000\n" "Last-Translator: flolilo \n" "Language: de\n" @@ -13,7 +13,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.7.0\n" +"Generated-By: Babel 2.8.0\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " @@ -139,7 +139,7 @@ msgstr "Einladung senden" msgid "The email %(email)s is not valid" msgstr "Die E-Mail-Adresse(n) %(email)s ist/sind nicht gültig" -msgid "Person" +msgid "Participant" msgstr "" msgid "Bill" @@ -202,8 +202,8 @@ msgid "Your invitations have been sent" msgstr "Deine Einladungen wurden versendet" #, python-format -msgid "%(member)s had been added" -msgstr "%(member)s wurde(n) hinzugefügt" +msgid "%(member)s has been added" +msgstr "" #, python-format msgid "%(name)s is part of this project again" @@ -760,4 +760,3 @@ msgstr "" msgid "Period" msgstr "" - diff --git a/ihatemoney/translations/el/LC_MESSAGES/messages.po b/ihatemoney/translations/el/LC_MESSAGES/messages.po index 74da58c7..e7c0ef95 100644 --- a/ihatemoney/translations/el/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/el/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-21 14:18+0200\n" +"POT-Creation-Date: 2020-04-24 19:59+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Automatically generated\n" "Language: el\n" @@ -12,7 +12,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.7.0\n" +"Generated-By: Babel 2.8.0\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " @@ -134,7 +134,7 @@ msgstr "" msgid "The email %(email)s is not valid" msgstr "" -msgid "Person" +msgid "Participant" msgstr "" msgid "Bill" @@ -193,7 +193,7 @@ msgid "Your invitations have been sent" msgstr "" #, python-format -msgid "%(member)s had been added" +msgid "%(member)s has been added" msgstr "" #, python-format @@ -738,86 +738,3 @@ msgstr "" msgid "Period" msgstr "" - -#~ msgid "" -#~ "Not a valid amount or expression.Only" -#~ " numbers and + - * / " -#~ "operatorsare accepted." -#~ msgstr "" - -#~ msgid "What do you want to download ?" -#~ msgstr "" - -#~ msgid "bills" -#~ msgstr "" - -#~ msgid "transactions" -#~ msgstr "" - -#~ msgid "Export file format" -#~ msgstr "" - -#~ msgid "Edit this project" -#~ msgstr "" - -#~ msgid "Download this project's data" -#~ msgstr "" - -#~ msgid "Type user name here" -#~ msgstr "" - -#~ msgid "No, thanks" -#~ msgstr "" - -#~ msgid "Manage your shared
expenses, easily" -#~ msgstr "" - -#~ msgid "Log to an existing project" -#~ msgstr "" - -#~ msgid "log in" -#~ msgstr "" - -#~ msgid "or create a new one" -#~ msgstr "" - -#~ msgid "let's get started" -#~ msgstr "" - -#~ msgid "options" -#~ msgstr "" - -#~ msgid "Project settings" -#~ msgstr "" - -#~ msgid "This is a free software" -#~ msgstr "" - -#~ msgid "Invite people to join this project!" -#~ msgstr "" - -#~ msgid "Added on" -#~ msgstr "" - -#~ msgid "Nothing to list yet. You probably want to" -#~ 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 "" -#~ "If you prefer, you can share the project identifier and the shared\n" -#~ "password by other communication means. " -#~ "Or even directly share the following " -#~ "link:" -#~ msgstr "" - -#~ msgid "A link to reset your password has been sent to your email." -#~ msgstr "" - diff --git a/ihatemoney/translations/es_419/LC_MESSAGES/messages.po b/ihatemoney/translations/es_419/LC_MESSAGES/messages.po index adf12ba7..ff0c742f 100644 --- a/ihatemoney/translations/es_419/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/es_419/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-21 14:18+0200\n" +"POT-Creation-Date: 2020-04-24 19:59+0200\n" "PO-Revision-Date: 2019-09-25 22:28+0000\n" "Last-Translator: Diego Caraballo \n" "Language: es_419\n" @@ -13,7 +13,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.7.0\n" +"Generated-By: Babel 2.8.0\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " @@ -139,7 +139,7 @@ msgstr "Enviar invitaciones" msgid "The email %(email)s is not valid" msgstr "El correo electrónico %(email)s no es válido" -msgid "Person" +msgid "Participant" msgstr "" msgid "Bill" @@ -202,8 +202,8 @@ msgid "Your invitations have been sent" msgstr "Sus invitaciones han sido enviadas" #, python-format -msgid "%(member)s had been added" -msgstr "se han añadido %(member)s" +msgid "%(member)s has been added" +msgstr "" #, python-format msgid "%(name)s is part of this project again" @@ -763,4 +763,3 @@ msgstr "" msgid "Period" msgstr "" - diff --git a/ihatemoney/translations/fr/LC_MESSAGES/messages.po b/ihatemoney/translations/fr/LC_MESSAGES/messages.po index 730f9426..26f0da45 100644 --- a/ihatemoney/translations/fr/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/fr/LC_MESSAGES/messages.po @@ -7,18 +7,17 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-04-21 14:18+0200\n" +"POT-Creation-Date: 2020-04-24 19:59+0200\n" "PO-Revision-Date: 2020-04-22 22:11+0000\n" "Last-Translator: Glandos \n" -"Language-Team: French \n" "Language: fr\n" +"Language-Team: French \n" +"Plural-Forms: nplurals=2; plural=n > 1\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.0.2-dev\n" -"Generated-By: Babel 2.7.0\n" +"Generated-By: Babel 2.8.0\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " @@ -144,7 +143,7 @@ msgstr "Envoyer les invitations" msgid "The email %(email)s is not valid" msgstr "L’email %(email)s est invalide" -msgid "Person" +msgid "Participant" msgstr "" msgid "Bill" @@ -205,8 +204,8 @@ msgid "Your invitations have been sent" msgstr "Vos invitations ont bien été envoyées" #, python-format -msgid "%(member)s had been added" -msgstr "%(member)s a bien été ajouté" +msgid "%(member)s has been added" +msgstr "" #, python-format msgid "%(name)s is part of this project again" @@ -411,8 +410,8 @@ msgid "" "Are you sure you want to erase all history for this project? This action " "cannot be undone." msgstr "" -"Êtes vous sûr de supprimer la totalité de l’historique de ce projet ? Cette " -"action est irréversible." +"Êtes vous sûr de supprimer la totalité de l’historique de ce projet ? " +"Cette action est irréversible." msgid "Added" msgstr "Ajouté" @@ -766,150 +765,3 @@ msgstr "" msgid "Period" msgstr "" - -#~ msgid "" -#~ "The project identifier is used to " -#~ "log in and for the URL of " -#~ "the project. We tried to generate " -#~ "an identifier for you but a " -#~ "project with this identifier already " -#~ "exists. Please create a new identifier" -#~ " that you will be able to " -#~ "remember." -#~ msgstr "" -#~ "L’identifiant du projet est utilisé pour" -#~ " se connecter.Nous avons essayé de " -#~ "générer un identifiant mais celui ci " -#~ "existe déjà. Merci de créer un " -#~ "nouvel identifiant que vous serez " -#~ "capable de retenir" - -#~ msgid "Start date" -#~ msgstr "Date de départ" - -#~ msgid "End date" -#~ msgstr "Date de fin" - -#~ msgid "\"No token provided\"" -#~ msgstr "Aucun token n’a été fourni." - -#~ msgid "User '%(name)s' has been deactivated" -#~ msgstr "Le membre '%(name)s' a été désactivé" - -#~ msgid "Invite" -#~ msgstr "Invitez" - -#~ msgid "" -#~ "Not a valid amount or expression.Only" -#~ " numbers and + - * / operators" -#~ " are accepted." -#~ msgstr "" -#~ "Pas un montant ou une expression " -#~ "valide. Seuls les nombres et les " -#~ "opérateurs+ - * / sont acceptés" - -#~ msgid "" -#~ "The project identifier is used to " -#~ "log in and for the URL of " -#~ "the project. We tried to generate " -#~ "an identifier for you but a " -#~ "project with this identifier already " -#~ "exists. Please create a new identifier" -#~ " that you will be able to " -#~ "remember" -#~ msgstr "" -#~ "L’identifiant du projet est utilisé pour" -#~ " se connecter et pour l’URL du " -#~ "projet. Nous avons essayé de générer " -#~ "un identifiant mais celui ci existe " -#~ "déjà. Merci de créer un nouvel " -#~ "identifiant que vous serez capable de" -#~ " retenir" - -#~ msgid "" -#~ "Not a valid amount or expression.Only" -#~ " numbers and + - * / " -#~ "operatorsare accepted." -#~ msgstr "" - -#~ msgid "What do you want to download ?" -#~ msgstr "Que voulez-vous télécharger ?" - -#~ msgid "bills" -#~ msgstr "factures" - -#~ msgid "transactions" -#~ msgstr "remboursements" - -#~ msgid "Export file format" -#~ msgstr "Format du fichier d’export" - -#~ msgid "Edit this project" -#~ msgstr "Éditer ce projet" - -#~ msgid "Download this project's data" -#~ msgstr "Télécharger les données de ce projet" - -#~ msgid "Type user name here" -#~ msgstr "Nouveau participant" - -#~ msgid "No, thanks" -#~ msgstr "Non merci" - -#~ msgid "Manage your shared
expenses, easily" -#~ msgstr "Gérez vos dépenses
partagées, facilement" - -#~ msgid "Log to an existing project" -#~ msgstr "Se connecter à un projet existant" - -#~ msgid "log in" -#~ msgstr "se connecter" - -#~ msgid "or create a new one" -#~ msgstr "ou créez en un nouveau" - -#~ msgid "let's get started" -#~ msgstr "c’est parti !" - -#~ msgid "options" -#~ msgstr "options" - -#~ msgid "Project settings" -#~ msgstr "Options du projet" - -#~ msgid "This is a free software" -#~ msgstr "Ceci est un logiciel libre" - -#~ msgid "Invite people to join this project!" -#~ msgstr "Invitez d’autres personnes à rejoindre ce projet !" - -#~ msgid "Added on" -#~ msgstr "Ajouté le" - -#~ msgid "Nothing to list yet. You probably want to" -#~ msgstr "Rien à lister pour l’instant. Vous voulez surement" - -#~ 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 "" -#~ "Entrez les adresses des personnes que vous souhaitez inviter,\n" -#~ "séparées par des virgules, on s’occupe de leur envoyer un email." - -#~ msgid "" -#~ "If you prefer, you can share the project identifier and the shared\n" -#~ "password by other communication means. " -#~ "Or even directly share the following " -#~ "link:" -#~ msgstr "" -#~ "Si vous préférez vous pouvez partager l’identifiant du projet\n" -#~ "et son mot de passe par un " -#~ "autre moyen de communication. Ou " -#~ "directement partager le lien suivant :" - -#~ msgid "A link to reset your password has been sent to your email." -#~ msgstr "Un lien pour changer votre mot de passe vous a été envoyé par mail." diff --git a/ihatemoney/translations/id/LC_MESSAGES/messages.po b/ihatemoney/translations/id/LC_MESSAGES/messages.po index a28ce9e6..68228a11 100644 --- a/ihatemoney/translations/id/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/id/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-21 14:18+0200\n" +"POT-Creation-Date: 2020-04-24 19:59+0200\n" "PO-Revision-Date: 2019-11-16 10:04+0000\n" "Last-Translator: Muhammad Fauzi \n" "Language: id\n" @@ -13,7 +13,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.7.0\n" +"Generated-By: Babel 2.8.0\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " @@ -139,7 +139,7 @@ msgstr "Kirim undangan" msgid "The email %(email)s is not valid" msgstr "Surel %(email)s tidak valid" -msgid "Person" +msgid "Participant" msgstr "" msgid "Bill" @@ -198,8 +198,8 @@ msgid "Your invitations have been sent" msgstr "Undangan Anda telah dikirim" #, python-format -msgid "%(member)s had been added" -msgstr "%(member)s telah ditambahkan" +msgid "%(member)s has been added" +msgstr "" #, python-format msgid "%(name)s is part of this project again" @@ -757,4 +757,3 @@ msgstr "" msgid "Period" msgstr "" - diff --git a/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po b/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po index 4ea69e97..6c11b335 100644 --- a/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-21 14:18+0200\n" +"POT-Creation-Date: 2020-04-24 19:59+0200\n" "PO-Revision-Date: 2019-11-12 09:04+0000\n" "Last-Translator: Allan Nordhøy \n" "Language: nb_NO\n" @@ -13,7 +13,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.7.0\n" +"Generated-By: Babel 2.8.0\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " @@ -141,7 +141,7 @@ msgstr "Send invitasjoner" msgid "The email %(email)s is not valid" msgstr "E-posten \"%(email)s\" er ikke gyldig" -msgid "Person" +msgid "Participant" msgstr "" msgid "Bill" @@ -206,8 +206,8 @@ msgid "Your invitations have been sent" msgstr "Invitasjonene dine har blitt sendt" #, python-format -msgid "%(member)s had been added" -msgstr "%(member)s lagt til" +msgid "%(member)s has been added" +msgstr "" #, python-format msgid "%(name)s is part of this project again" @@ -780,118 +780,3 @@ msgstr "" msgid "Period" msgstr "" - -#~ msgid "" -#~ "The project identifier is used to " -#~ "log in and for the URL of " -#~ "the project. We tried to generate " -#~ "an identifier for you but a " -#~ "project with this identifier already " -#~ "exists. Please create a new identifier" -#~ " that you will be able to " -#~ "remember" -#~ msgstr "" -#~ "Prosjektidentifikatoren brukes til og logge" -#~ " inn og for prosjektets nettadresse. " -#~ "Vi prøvde å generere en identifikator" -#~ " for deg, men et prosjekt hadde " -#~ "den identifikatoren allerede. Opprett en " -#~ "ny identifikator du husker." - -#~ msgid "" -#~ "Not a valid amount or expression.Only" -#~ " numbers and + - * / " -#~ "operatorsare accepted." -#~ msgstr "" -#~ "Ikke gyldig beløp eller uttrykk. Kun " -#~ "tall og + - * / operatorer " -#~ "tillates." - -#~ msgid "What do you want to download ?" -#~ msgstr "Hva ønsker du å laste ned?" - -#~ msgid "bills" -#~ msgstr "regninger" - -#~ msgid "transactions" -#~ msgstr "overøfringer" - -#~ msgid "Export file format" -#~ msgstr "Eksport-filformat" - -#~ msgid "Edit this project" -#~ msgstr "Rediger dette prosjektet" - -#~ msgid "Download this project's data" -#~ msgstr "Last ned data for dette prosjektet" - -#~ msgid "Type user name here" -#~ msgstr "Skriv inn brukernavn her" - -#~ msgid "No, thanks" -#~ msgstr "Nei takk" - -#~ msgid "Manage your shared
expenses, easily" -#~ msgstr "Behandle dine delte
utgifter, enkelt" - -#~ msgid "Log to an existing project" -#~ msgstr "Logg inn i et eksisterende prosjekt" - -#~ msgid "log in" -#~ msgstr "logg inn" - -#~ msgid "or create a new one" -#~ msgstr "eller opprett et nytt" - -#~ msgid "let's get started" -#~ msgstr "la oss komme i gang" - -#~ msgid "options" -#~ msgstr "innstillinger" - -#~ msgid "Project settings" -#~ msgstr "Prosjektinnstillinger" - -#~ msgid "This is a free software" -#~ msgstr "Dette er fri programvare" - -#~ msgid "Invite people to join this project!" -#~ msgstr "Inviter folk til dette prosjektet." - -#~ msgid "Added on" -#~ msgstr "Lagt til" - -#~ msgid "Nothing to list yet. You probably want to" -#~ msgstr "ingenting å liste opp enda. Du ønsker antagelig å" - -#~ 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 "" -#~ "Angi en (kommainndelt) liste over " -#~ "e-postadresser du ønsker å gi nyss " -#~ "om\n" -#~ "opprettelsen av dette budsjetthåndteringsprosjektet," -#~ " og de vil motta en e-post." - -#~ msgid "" -#~ "If you prefer, you can share the project identifier and the shared\n" -#~ "password by other communication means. " -#~ "Or even directly share the following " -#~ "link:" -#~ msgstr "" -#~ "Hvis du foretrekker det, kan du " -#~ "dele prosjektidentifikatoeren og det delte" -#~ "\n" -#~ "passordet på annet vis. Du kan også dele det følgende lenke direkte:" - -#~ msgid "A link to reset your password has been sent to your email." -#~ msgstr "" -#~ "En lenke for å tilbakestille passordet" -#~ " har blitt sent til deg per " -#~ "e-post." - diff --git a/ihatemoney/translations/nl/LC_MESSAGES/messages.po b/ihatemoney/translations/nl/LC_MESSAGES/messages.po index 02142022..c164ec50 100644 --- a/ihatemoney/translations/nl/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/nl/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-04-21 14:18+0200\n" +"POT-Creation-Date: 2020-04-24 19:59+0200\n" "PO-Revision-Date: 2019-10-07 22:56+0000\n" "Last-Translator: Heimen Stoffels \n" "Language: nl\n" @@ -13,7 +13,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.7.0\n" +"Generated-By: Babel 2.8.0\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " @@ -135,7 +135,7 @@ msgstr "Uitnodigingen versturen" msgid "The email %(email)s is not valid" msgstr "Het e-mailadres '%(email)s' is onjuist" -msgid "Person" +msgid "Participant" msgstr "" msgid "Bill" @@ -196,8 +196,8 @@ msgid "Your invitations have been sent" msgstr "Je uitnodigingen zijn verstuurd" #, python-format -msgid "%(member)s had been added" -msgstr "%(member)s is toegevoegd" +msgid "%(member)s has been added" +msgstr "" #, python-format msgid "%(name)s is part of this project again" @@ -755,118 +755,3 @@ msgstr "" msgid "Period" msgstr "" - -#~ msgid "" -#~ "The project identifier is used to " -#~ "log in and for the URL of " -#~ "the project. We tried to generate " -#~ "an identifier for you but a " -#~ "project with this identifier already " -#~ "exists. Please create a new identifier" -#~ " that you will be able to " -#~ "remember" -#~ msgstr "" -#~ "De project-id wordt gebruikt om in" -#~ " te loggen en als url van het" -#~ " project. We hebben geprobeerd om een" -#~ " id voor je te genereren, maar " -#~ "er is al een project met deze " -#~ "id. Creëer een nieuwe id die je" -#~ " makkelijk kunt onthouden." - -#~ msgid "" -#~ "Not a valid amount or expression.Only" -#~ " numbers and + - * / " -#~ "operatorsare accepted." -#~ msgstr "" -#~ "Geen geldig bedrag of geldige expressie." -#~ " Alleen getallen en + - * / " -#~ "zijn toegestaan." - -#~ msgid "What do you want to download ?" -#~ msgstr "Wat wil je downloaden?" - -#~ msgid "bills" -#~ msgstr "rekeningen" - -#~ msgid "transactions" -#~ msgstr "transacties" - -#~ msgid "Export file format" -#~ msgstr "Bestandsformaat voor exporteren" - -#~ msgid "Edit this project" -#~ msgstr "Dit project bewerken" - -#~ msgid "Download this project's data" -#~ msgstr "Projectgegevens downloaden" - -#~ msgid "Type user name here" -#~ msgstr "Typ hier de gebruikersnaam" - -#~ msgid "No, thanks" -#~ msgstr "Nee, bedankt" - -#~ msgid "Manage your shared
expenses, easily" -#~ msgstr "Beheer eenvoudig je gedeelde
uitgaven" - -#~ msgid "Log to an existing project" -#~ msgstr "Log in op een bestaand project" - -#~ msgid "log in" -#~ msgstr "inloggen" - -#~ msgid "or create a new one" -#~ msgstr "of creëer een nieuwe" - -#~ msgid "let's get started" -#~ msgstr "aan de slag" - -#~ msgid "options" -#~ msgstr "opties" - -#~ msgid "Project settings" -#~ msgstr "Projectinstellingen" - -#~ msgid "This is a free software" -#~ msgstr "Dit is vrije software" - -#~ msgid "Invite people to join this project!" -#~ msgstr "Nodig mensen uit voor dit project!" - -#~ msgid "Added on" -#~ msgstr "Toegevoegd op" - -#~ msgid "Nothing to list yet. You probably want to" -#~ msgstr "Er kan nog geen opsomming worden gemaakt. Voeg" - -#~ 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 "" -#~ "Geef een kommagescheiden lijst van " -#~ "e-mailadressen op. Deze mensen worden op" -#~ " de\n" -#~ "hoogte gebracht van het bestaan van " -#~ "dit project en wij sturen hen een" -#~ " e-mail." - -#~ msgid "" -#~ "If you prefer, you can share the project identifier and the shared\n" -#~ "password by other communication means. " -#~ "Or even directly share the following " -#~ "link:" -#~ msgstr "" -#~ "Als je wilt, dan kun je de project-id en het gedeelde wachtwoord\n" -#~ "delen via andere kanalen. Of deel gewoon de volgende link:" - -#~ msgid "A link to reset your password has been sent to your email." -#~ msgstr "" -#~ "Er is een link met " -#~ "wachtwoordherstelinstructies naar je e-mailadres " -#~ "verstuurd." - diff --git a/ihatemoney/translations/tr/LC_MESSAGES/messages.po b/ihatemoney/translations/tr/LC_MESSAGES/messages.po index defa954d..f86a7ed5 100644 --- a/ihatemoney/translations/tr/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/tr/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-21 14:18+0200\n" +"POT-Creation-Date: 2020-04-24 19:59+0200\n" "PO-Revision-Date: 2019-08-07 13:24+0000\n" "Last-Translator: Mesut Akcan \n" "Language: tr\n" @@ -13,7 +13,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.7.0\n" +"Generated-By: Babel 2.8.0\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " @@ -139,7 +139,7 @@ msgstr "" msgid "The email %(email)s is not valid" msgstr "" -msgid "Person" +msgid "Participant" msgstr "" msgid "Bill" @@ -198,7 +198,7 @@ msgid "Your invitations have been sent" msgstr "" #, python-format -msgid "%(member)s had been added" +msgid "%(member)s has been added" msgstr "" #, python-format @@ -743,80 +743,3 @@ msgstr "" msgid "Period" msgstr "" - -#~ msgid "What do you want to download ?" -#~ msgstr "" - -#~ msgid "bills" -#~ msgstr "" - -#~ msgid "transactions" -#~ msgstr "" - -#~ msgid "Export file format" -#~ msgstr "" - -#~ msgid "Edit this project" -#~ msgstr "" - -#~ msgid "Download this project's data" -#~ msgstr "" - -#~ msgid "Type user name here" -#~ msgstr "" - -#~ msgid "No, thanks" -#~ msgstr "" - -#~ msgid "Manage your shared
expenses, easily" -#~ msgstr "" - -#~ msgid "Log to an existing project" -#~ msgstr "" - -#~ msgid "log in" -#~ msgstr "" - -#~ msgid "or create a new one" -#~ msgstr "" - -#~ msgid "let's get started" -#~ msgstr "" - -#~ msgid "options" -#~ msgstr "" - -#~ msgid "Project settings" -#~ msgstr "" - -#~ msgid "This is a free software" -#~ msgstr "" - -#~ msgid "Invite people to join this project!" -#~ msgstr "" - -#~ msgid "Added on" -#~ msgstr "" - -#~ msgid "Nothing to list yet. You probably want to" -#~ 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 "" -#~ "If you prefer, you can share the project identifier and the shared\n" -#~ "password by other communication means. " -#~ "Or even directly share the following " -#~ "link:" -#~ msgstr "" - -#~ msgid "A link to reset your password has been sent to your email." -#~ msgstr "" - diff --git a/ihatemoney/translations/uk/LC_MESSAGES/messages.po b/ihatemoney/translations/uk/LC_MESSAGES/messages.po index 6b7c3a24..a893f11e 100644 --- a/ihatemoney/translations/uk/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/uk/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-21 14:18+0200\n" +"POT-Creation-Date: 2020-04-24 19:59+0200\n" "PO-Revision-Date: 2019-12-08 16:26+0000\n" "Last-Translator: Tymofij Lytvynenko \n" "Language: uk\n" @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.7.0\n" +"Generated-By: Babel 2.8.0\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " @@ -136,7 +136,7 @@ msgstr "" msgid "The email %(email)s is not valid" msgstr "" -msgid "Person" +msgid "Participant" msgstr "" msgid "Bill" @@ -195,7 +195,7 @@ msgid "Your invitations have been sent" msgstr "" #, python-format -msgid "%(member)s had been added" +msgid "%(member)s has been added" msgstr "" #, python-format @@ -740,4 +740,3 @@ msgstr "" msgid "Period" msgstr "" - diff --git a/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po b/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po index 906c9f6c..77436237 100644 --- a/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-21 14:18+0200\n" +"POT-Creation-Date: 2020-04-24 19:59+0200\n" "PO-Revision-Date: 2020-02-09 12:01+0000\n" "Last-Translator: Muge Niu \n" "Language: zh_HANS_CN\n" @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.7.0\n" +"Generated-By: Babel 2.8.0\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " @@ -136,7 +136,7 @@ msgstr "" msgid "The email %(email)s is not valid" msgstr "" -msgid "Person" +msgid "Participant" msgstr "" msgid "Bill" @@ -195,7 +195,7 @@ msgid "Your invitations have been sent" msgstr "" #, python-format -msgid "%(member)s had been added" +msgid "%(member)s has been added" msgstr "" #, python-format @@ -740,97 +740,3 @@ msgstr "" msgid "Period" msgstr "" - -#~ msgid "" -#~ "The project identifier is used to " -#~ "log in and for the URL of " -#~ "the project. We tried to generate " -#~ "an identifier for you but a " -#~ "project with this identifier already " -#~ "exists. Please create a new identifier" -#~ " that you will be able to " -#~ "remember" -#~ msgstr "" - -#~ msgid "" -#~ "Not a valid amount or expression.Only" -#~ " numbers and + - * / " -#~ "operatorsare accepted." -#~ msgstr "" - -#~ msgid "What do you want to download ?" -#~ msgstr "你想下载什么?" - -#~ msgid "bills" -#~ msgstr "" - -#~ msgid "transactions" -#~ msgstr "" - -#~ msgid "Export file format" -#~ msgstr "" - -#~ msgid "Edit this project" -#~ msgstr "" - -#~ msgid "Download this project's data" -#~ msgstr "" - -#~ msgid "Type user name here" -#~ msgstr "" - -#~ msgid "No, thanks" -#~ msgstr "" - -#~ msgid "Manage your shared
expenses, easily" -#~ msgstr "" - -#~ msgid "Log to an existing project" -#~ msgstr "" - -#~ msgid "log in" -#~ msgstr "" - -#~ msgid "or create a new one" -#~ msgstr "" - -#~ msgid "let's get started" -#~ msgstr "" - -#~ msgid "options" -#~ msgstr "" - -#~ msgid "Project settings" -#~ msgstr "" - -#~ msgid "This is a free software" -#~ msgstr "" - -#~ msgid "Invite people to join this project!" -#~ msgstr "" - -#~ msgid "Added on" -#~ msgstr "" - -#~ msgid "Nothing to list yet. You probably want to" -#~ 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 "" -#~ "If you prefer, you can share the project identifier and the shared\n" -#~ "password by other communication means. " -#~ "Or even directly share the following " -#~ "link:" -#~ msgstr "" - -#~ msgid "A link to reset your password has been sent to your email." -#~ msgstr "" - diff --git a/ihatemoney/web.py b/ihatemoney/web.py index a2f25e29..d799420b 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -618,7 +618,7 @@ def add_member(): if form.validate(): member = form.save(g.project, Person()) db.session.commit() - flash(_("%(member)s had been added", member=member.name)) + flash(_("%(member)s has been added", member=member.name)) return redirect(url_for(".list_bills")) return render_template("add_member.html", form=form) From f5d861199de53b63502da864e47e2867cfd8c9fa Mon Sep 17 00:00:00 2001 From: Baptiste Date: Fri, 24 Apr 2020 17:00:43 +0000 Subject: [PATCH 24/47] Translated using Weblate (French) Currently translated at 81.5% (186 of 228 strings) Translation: I Hate Money/I Hate Money Translate-URL: https://hosted.weblate.org/projects/i-hate-money/i-hate-money/fr/ --- ihatemoney/translations/fr/LC_MESSAGES/messages.po | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ihatemoney/translations/fr/LC_MESSAGES/messages.po b/ihatemoney/translations/fr/LC_MESSAGES/messages.po index 730f9426..fba2a870 100644 --- a/ihatemoney/translations/fr/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/fr/LC_MESSAGES/messages.po @@ -8,8 +8,8 @@ msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2020-04-21 14:18+0200\n" -"PO-Revision-Date: 2020-04-22 22:11+0000\n" -"Last-Translator: Glandos \n" +"PO-Revision-Date: 2020-04-25 09:55+0000\n" +"Last-Translator: Baptiste \n" "Language-Team: French \n" "Language: fr\n" @@ -24,8 +24,8 @@ msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " "accepted." msgstr "" -"Ceci n'est pas pas un montant ou une expression valide. Seuls les nombres" -" et les opérateurs + - * / sont acceptés." +"Ceci n'est pas un montant ou une expression valide. Seuls les nombres et les " +"opérateurs + - * / sont acceptés." msgid "Project name" msgstr "Nom de projet" @@ -37,10 +37,10 @@ msgid "Email" msgstr "Email" msgid "Enable project history" -msgstr "" +msgstr "Activer l'historique de projet" msgid "Use IP tracking for project history" -msgstr "" +msgstr "Collecter les adresses IP dans l'historique de projet" msgid "Import previously exported JSON file" msgstr "Importer un fichier JSON précédemment exporté" @@ -151,7 +151,7 @@ msgid "Bill" msgstr "Facture" msgid "Project" -msgstr "Projets" +msgstr "Projet" msgid "Too many failed login attempts, please retry later." msgstr "Trop d'échecs d’authentification successifs, veuillez réessayer plus tard." From 6129191b26784b895e203fa3eafb89cee7d88b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Sat, 25 Apr 2020 11:55:46 +0200 Subject: [PATCH 25/47] Fix sqlite only migration. (#579) --- .gitignore | 4 +- docs/contributing.rst | 2 +- ihatemoney/budget.db | 0 .../cb038f79982e_sqlite_autoincrement.py | 66 +++++++++++-------- 4 files changed, 41 insertions(+), 31 deletions(-) delete mode 100644 ihatemoney/budget.db diff --git a/.gitignore b/.gitignore index 1b9de4d9..927a8d64 100644 --- a/.gitignore +++ b/.gitignore @@ -10,5 +10,5 @@ dist build .vscode .env -.pytest_cache - +.pytest_cache +ihatemoney/budget.db diff --git a/docs/contributing.rst b/docs/contributing.rst index 34015241..8e0d69aa 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -220,7 +220,7 @@ In order to prepare a new release, we are following the following steps: make compress-assets - Build the translations:: - + make update-translations make build-translations diff --git a/ihatemoney/budget.db b/ihatemoney/budget.db deleted file mode 100644 index e69de29b..00000000 diff --git a/ihatemoney/migrations/versions/cb038f79982e_sqlite_autoincrement.py b/ihatemoney/migrations/versions/cb038f79982e_sqlite_autoincrement.py index ae5ab326..718aa75a 100644 --- a/ihatemoney/migrations/versions/cb038f79982e_sqlite_autoincrement.py +++ b/ihatemoney/migrations/versions/cb038f79982e_sqlite_autoincrement.py @@ -15,36 +15,46 @@ import sqlalchemy as sa def upgrade(): - alter_table_batches = [ - op.batch_alter_table( - "person", recreate="always", table_kwargs={"sqlite_autoincrement": True} - ), - op.batch_alter_table( - "bill", recreate="always", table_kwargs={"sqlite_autoincrement": True} - ), - op.batch_alter_table( - "billowers", recreate="always", table_kwargs={"sqlite_autoincrement": True} - ), - ] + bind = op.get_bind() + if bind.engine.name == "sqlite": + alter_table_batches = [ + op.batch_alter_table( + "person", recreate="always", table_kwargs={"sqlite_autoincrement": True} + ), + op.batch_alter_table( + "bill", recreate="always", table_kwargs={"sqlite_autoincrement": True} + ), + op.batch_alter_table( + "billowers", + recreate="always", + table_kwargs={"sqlite_autoincrement": True}, + ), + ] - for batch_op in alter_table_batches: - with batch_op: - pass + for batch_op in alter_table_batches: + with batch_op: + pass def downgrade(): - alter_table_batches = [ - op.batch_alter_table( - "person", recreate="always", table_kwargs={"sqlite_autoincrement": False} - ), - op.batch_alter_table( - "bill", recreate="always", table_kwargs={"sqlite_autoincrement": False} - ), - op.batch_alter_table( - "billowers", recreate="always", table_kwargs={"sqlite_autoincrement": False} - ), - ] + bind = op.get_bind() + if bind.engine.name == "sqlite": + alter_table_batches = [ + op.batch_alter_table( + "person", + recreate="always", + table_kwargs={"sqlite_autoincrement": False}, + ), + op.batch_alter_table( + "bill", recreate="always", table_kwargs={"sqlite_autoincrement": False} + ), + op.batch_alter_table( + "billowers", + recreate="always", + table_kwargs={"sqlite_autoincrement": False}, + ), + ] - for batch_op in alter_table_batches: - with batch_op: - pass + for batch_op in alter_table_batches: + with batch_op: + pass From 64fbda885cbc90c6c514201771c305825c73c271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Sat, 25 Apr 2020 12:16:24 +0200 Subject: [PATCH 26/47] @zorun review. Revert "Fix obsolete translations." This reverts commit a2a3b1e2feeb41fbf48b77b4f5273fbf7ff8a2bc. --- .../es_419/LC_MESSAGES/messages.po | 3 + .../translations/fr/LC_MESSAGES/messages.po | 150 ++++++++++++++++++ .../translations/id/LC_MESSAGES/messages.po | 3 + .../nb_NO/LC_MESSAGES/messages.po | 117 ++++++++++++++ .../translations/nl/LC_MESSAGES/messages.po | 117 ++++++++++++++ 5 files changed, 390 insertions(+) diff --git a/ihatemoney/translations/es_419/LC_MESSAGES/messages.po b/ihatemoney/translations/es_419/LC_MESSAGES/messages.po index ff0c742f..219d7f85 100644 --- a/ihatemoney/translations/es_419/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/es_419/LC_MESSAGES/messages.po @@ -763,3 +763,6 @@ msgstr "" msgid "Period" msgstr "" + +#~ msgid "%(member)s had been added" +#~ msgstr "se han añadido %(member)s" diff --git a/ihatemoney/translations/fr/LC_MESSAGES/messages.po b/ihatemoney/translations/fr/LC_MESSAGES/messages.po index 08e69a3e..a1d48d72 100644 --- a/ihatemoney/translations/fr/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/fr/LC_MESSAGES/messages.po @@ -765,3 +765,153 @@ msgstr "" msgid "Period" msgstr "" + +#~ msgid "" +#~ "The project identifier is used to " +#~ "log in and for the URL of " +#~ "the project. We tried to generate " +#~ "an identifier for you but a " +#~ "project with this identifier already " +#~ "exists. Please create a new identifier" +#~ " that you will be able to " +#~ "remember." +#~ msgstr "" +#~ "L’identifiant du projet est utilisé pour" +#~ " se connecter.Nous avons essayé de " +#~ "générer un identifiant mais celui ci " +#~ "existe déjà. Merci de créer un " +#~ "nouvel identifiant que vous serez " +#~ "capable de retenir" + +#~ msgid "Start date" +#~ msgstr "Date de départ" + +#~ msgid "End date" +#~ msgstr "Date de fin" + +#~ msgid "\"No token provided\"" +#~ msgstr "Aucun token n’a été fourni." + +#~ msgid "User '%(name)s' has been deactivated" +#~ msgstr "Le membre '%(name)s' a été désactivé" + +#~ msgid "Invite" +#~ msgstr "Invitez" + +#~ msgid "" +#~ "Not a valid amount or expression.Only" +#~ " numbers and + - * / operators" +#~ " are accepted." +#~ msgstr "" +#~ "Pas un montant ou une expression " +#~ "valide. Seuls les nombres et les " +#~ "opérateurs+ - * / sont acceptés" + +#~ msgid "" +#~ "The project identifier is used to " +#~ "log in and for the URL of " +#~ "the project. We tried to generate " +#~ "an identifier for you but a " +#~ "project with this identifier already " +#~ "exists. Please create a new identifier" +#~ " that you will be able to " +#~ "remember" +#~ msgstr "" +#~ "L’identifiant du projet est utilisé pour" +#~ " se connecter et pour l’URL du " +#~ "projet. Nous avons essayé de générer " +#~ "un identifiant mais celui ci existe " +#~ "déjà. Merci de créer un nouvel " +#~ "identifiant que vous serez capable de" +#~ " retenir" + +#~ msgid "" +#~ "Not a valid amount or expression.Only" +#~ " numbers and + - * / " +#~ "operatorsare accepted." +#~ msgstr "" + +#~ msgid "What do you want to download ?" +#~ msgstr "Que voulez-vous télécharger ?" + +#~ msgid "bills" +#~ msgstr "factures" + +#~ msgid "transactions" +#~ msgstr "remboursements" + +#~ msgid "Export file format" +#~ msgstr "Format du fichier d’export" + +#~ msgid "Edit this project" +#~ msgstr "Éditer ce projet" + +#~ msgid "Download this project's data" +#~ msgstr "Télécharger les données de ce projet" + +#~ msgid "Type user name here" +#~ msgstr "Nouveau participant" + +#~ msgid "No, thanks" +#~ msgstr "Non merci" + +#~ msgid "Manage your shared
expenses, easily" +#~ msgstr "Gérez vos dépenses
partagées, facilement" + +#~ msgid "Log to an existing project" +#~ msgstr "Se connecter à un projet existant" + +#~ msgid "log in" +#~ msgstr "se connecter" + +#~ msgid "or create a new one" +#~ msgstr "ou créez en un nouveau" + +#~ msgid "let's get started" +#~ msgstr "c’est parti !" + +#~ msgid "options" +#~ msgstr "options" + +#~ msgid "Project settings" +#~ msgstr "Options du projet" + +#~ msgid "This is a free software" +#~ msgstr "Ceci est un logiciel libre" + +#~ msgid "Invite people to join this project!" +#~ msgstr "Invitez d’autres personnes à rejoindre ce projet !" + +#~ msgid "Added on" +#~ msgstr "Ajouté le" + +#~ msgid "Nothing to list yet. You probably want to" +#~ msgstr "Rien à lister pour l’instant. Vous voulez surement" + +#~ 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 "" +#~ "Entrez les adresses des personnes que vous souhaitez inviter,\n" +#~ "séparées par des virgules, on s’occupe de leur envoyer un email." + +#~ msgid "" +#~ "If you prefer, you can share the project identifier and the shared\n" +#~ "password by other communication means. " +#~ "Or even directly share the following " +#~ "link:" +#~ msgstr "" +#~ "Si vous préférez vous pouvez partager l’identifiant du projet\n" +#~ "et son mot de passe par un " +#~ "autre moyen de communication. Ou " +#~ "directement partager le lien suivant :" + +#~ msgid "A link to reset your password has been sent to your email." +#~ msgstr "Un lien pour changer votre mot de passe vous a été envoyé par mail." + +#~ msgid "%(member)s had been added" +#~ msgstr "%(member)s a bien été ajouté" diff --git a/ihatemoney/translations/id/LC_MESSAGES/messages.po b/ihatemoney/translations/id/LC_MESSAGES/messages.po index 68228a11..ebe70535 100644 --- a/ihatemoney/translations/id/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/id/LC_MESSAGES/messages.po @@ -757,3 +757,6 @@ msgstr "" msgid "Period" msgstr "" + +#~ msgid "%(member)s had been added" +#~ msgstr "%(member)s telah ditambahkan" diff --git a/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po b/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po index 6c11b335..0b773e60 100644 --- a/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po @@ -780,3 +780,120 @@ msgstr "" msgid "Period" msgstr "" + +#~ msgid "" +#~ "The project identifier is used to " +#~ "log in and for the URL of " +#~ "the project. We tried to generate " +#~ "an identifier for you but a " +#~ "project with this identifier already " +#~ "exists. Please create a new identifier" +#~ " that you will be able to " +#~ "remember" +#~ msgstr "" +#~ "Prosjektidentifikatoren brukes til og logge" +#~ " inn og for prosjektets nettadresse. " +#~ "Vi prøvde å generere en identifikator" +#~ " for deg, men et prosjekt hadde " +#~ "den identifikatoren allerede. Opprett en " +#~ "ny identifikator du husker." + +#~ msgid "" +#~ "Not a valid amount or expression.Only" +#~ " numbers and + - * / " +#~ "operatorsare accepted." +#~ msgstr "" +#~ "Ikke gyldig beløp eller uttrykk. Kun " +#~ "tall og + - * / operatorer " +#~ "tillates." + +#~ msgid "What do you want to download ?" +#~ msgstr "Hva ønsker du å laste ned?" + +#~ msgid "bills" +#~ msgstr "regninger" + +#~ msgid "transactions" +#~ msgstr "overøfringer" + +#~ msgid "Export file format" +#~ msgstr "Eksport-filformat" + +#~ msgid "Edit this project" +#~ msgstr "Rediger dette prosjektet" + +#~ msgid "Download this project's data" +#~ msgstr "Last ned data for dette prosjektet" + +#~ msgid "Type user name here" +#~ msgstr "Skriv inn brukernavn her" + +#~ msgid "No, thanks" +#~ msgstr "Nei takk" + +#~ msgid "Manage your shared
expenses, easily" +#~ msgstr "Behandle dine delte
utgifter, enkelt" + +#~ msgid "Log to an existing project" +#~ msgstr "Logg inn i et eksisterende prosjekt" + +#~ msgid "log in" +#~ msgstr "logg inn" + +#~ msgid "or create a new one" +#~ msgstr "eller opprett et nytt" + +#~ msgid "let's get started" +#~ msgstr "la oss komme i gang" + +#~ msgid "options" +#~ msgstr "innstillinger" + +#~ msgid "Project settings" +#~ msgstr "Prosjektinnstillinger" + +#~ msgid "This is a free software" +#~ msgstr "Dette er fri programvare" + +#~ msgid "Invite people to join this project!" +#~ msgstr "Inviter folk til dette prosjektet." + +#~ msgid "Added on" +#~ msgstr "Lagt til" + +#~ msgid "Nothing to list yet. You probably want to" +#~ msgstr "ingenting å liste opp enda. Du ønsker antagelig å" + +#~ 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 "" +#~ "Angi en (kommainndelt) liste over " +#~ "e-postadresser du ønsker å gi nyss " +#~ "om\n" +#~ "opprettelsen av dette budsjetthåndteringsprosjektet," +#~ " og de vil motta en e-post." + +#~ msgid "" +#~ "If you prefer, you can share the project identifier and the shared\n" +#~ "password by other communication means. " +#~ "Or even directly share the following " +#~ "link:" +#~ msgstr "" +#~ "Hvis du foretrekker det, kan du " +#~ "dele prosjektidentifikatoeren og det delte" +#~ "\n" +#~ "passordet på annet vis. Du kan også dele det følgende lenke direkte:" + +#~ msgid "A link to reset your password has been sent to your email." +#~ msgstr "" +#~ "En lenke for å tilbakestille passordet" +#~ " har blitt sent til deg per " +#~ "e-post." + +#~ msgid "%(member)s had been added" +#~ msgstr "%(member)s lagt til" diff --git a/ihatemoney/translations/nl/LC_MESSAGES/messages.po b/ihatemoney/translations/nl/LC_MESSAGES/messages.po index c164ec50..0cd41422 100644 --- a/ihatemoney/translations/nl/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/nl/LC_MESSAGES/messages.po @@ -755,3 +755,120 @@ msgstr "" msgid "Period" msgstr "" + +#~ msgid "" +#~ "The project identifier is used to " +#~ "log in and for the URL of " +#~ "the project. We tried to generate " +#~ "an identifier for you but a " +#~ "project with this identifier already " +#~ "exists. Please create a new identifier" +#~ " that you will be able to " +#~ "remember" +#~ msgstr "" +#~ "De project-id wordt gebruikt om in" +#~ " te loggen en als url van het" +#~ " project. We hebben geprobeerd om een" +#~ " id voor je te genereren, maar " +#~ "er is al een project met deze " +#~ "id. Creëer een nieuwe id die je" +#~ " makkelijk kunt onthouden." + +#~ msgid "" +#~ "Not a valid amount or expression.Only" +#~ " numbers and + - * / " +#~ "operatorsare accepted." +#~ msgstr "" +#~ "Geen geldig bedrag of geldige expressie." +#~ " Alleen getallen en + - * / " +#~ "zijn toegestaan." + +#~ msgid "What do you want to download ?" +#~ msgstr "Wat wil je downloaden?" + +#~ msgid "bills" +#~ msgstr "rekeningen" + +#~ msgid "transactions" +#~ msgstr "transacties" + +#~ msgid "Export file format" +#~ msgstr "Bestandsformaat voor exporteren" + +#~ msgid "Edit this project" +#~ msgstr "Dit project bewerken" + +#~ msgid "Download this project's data" +#~ msgstr "Projectgegevens downloaden" + +#~ msgid "Type user name here" +#~ msgstr "Typ hier de gebruikersnaam" + +#~ msgid "No, thanks" +#~ msgstr "Nee, bedankt" + +#~ msgid "Manage your shared
expenses, easily" +#~ msgstr "Beheer eenvoudig je gedeelde
uitgaven" + +#~ msgid "Log to an existing project" +#~ msgstr "Log in op een bestaand project" + +#~ msgid "log in" +#~ msgstr "inloggen" + +#~ msgid "or create a new one" +#~ msgstr "of creëer een nieuwe" + +#~ msgid "let's get started" +#~ msgstr "aan de slag" + +#~ msgid "options" +#~ msgstr "opties" + +#~ msgid "Project settings" +#~ msgstr "Projectinstellingen" + +#~ msgid "This is a free software" +#~ msgstr "Dit is vrije software" + +#~ msgid "Invite people to join this project!" +#~ msgstr "Nodig mensen uit voor dit project!" + +#~ msgid "Added on" +#~ msgstr "Toegevoegd op" + +#~ msgid "Nothing to list yet. You probably want to" +#~ msgstr "Er kan nog geen opsomming worden gemaakt. Voeg" + +#~ 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 "" +#~ "Geef een kommagescheiden lijst van " +#~ "e-mailadressen op. Deze mensen worden op" +#~ " de\n" +#~ "hoogte gebracht van het bestaan van " +#~ "dit project en wij sturen hen een" +#~ " e-mail." + +#~ msgid "" +#~ "If you prefer, you can share the project identifier and the shared\n" +#~ "password by other communication means. " +#~ "Or even directly share the following " +#~ "link:" +#~ msgstr "" +#~ "Als je wilt, dan kun je de project-id en het gedeelde wachtwoord\n" +#~ "delen via andere kanalen. Of deel gewoon de volgende link:" + +#~ msgid "A link to reset your password has been sent to your email." +#~ msgstr "" +#~ "Er is een link met " +#~ "wachtwoordherstelinstructies naar je e-mailadres " +#~ "verstuurd." + +#~ msgid "%(member)s had been added" +#~ msgstr "%(member)s is toegevoegd" From db47683e4e34c7b65f23ea7d7fb4f953413242ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Sat, 25 Apr 2020 12:44:06 +0200 Subject: [PATCH 27/47] Fix history translations. (#580) --- ihatemoney/messages.pot | 38 ++--- ihatemoney/templates/history.html | 32 ++-- .../translations/cs/LC_MESSAGES/messages.po | 41 ++--- .../translations/de/LC_MESSAGES/messages.po | 41 ++--- .../translations/el/LC_MESSAGES/messages.po | 41 ++--- .../es_419/LC_MESSAGES/messages.po | 41 ++--- .../translations/fr/LC_MESSAGES/messages.po | 149 +++++++++++------ .../translations/id/LC_MESSAGES/messages.po | 41 ++--- .../nb_NO/LC_MESSAGES/messages.po | 41 ++--- .../translations/nl/LC_MESSAGES/messages.po | 156 ++---------------- .../translations/tr/LC_MESSAGES/messages.po | 41 ++--- .../translations/uk/LC_MESSAGES/messages.po | 41 ++--- .../zh_HANS-CN/LC_MESSAGES/messages.po | 41 ++--- 13 files changed, 317 insertions(+), 427 deletions(-) diff --git a/ihatemoney/messages.pot b/ihatemoney/messages.pot index a03f8e26..dfd1877a 100644 --- a/ihatemoney/messages.pot +++ b/ihatemoney/messages.pot @@ -396,23 +396,23 @@ msgstr "" msgid "Balance" msgstr "" +#, python-format msgid "" -"This project has history disabled. New actions won't appear below. You " -"can enable history on the" -msgstr "" - -msgid "settings page" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " msgstr "" msgid "" -"The table below reflects actions recorded prior to disabling project " -"history. You can " -msgstr "" - -msgid "clear project history" -msgstr "" - -msgid "to remove them." +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\n" +" " msgstr "" msgid "" @@ -441,16 +441,10 @@ msgstr "" msgid "Event" msgstr "" -msgid "IP address recording can be" +msgid "IP address recording can be enabled on the settings page" msgstr "" -msgid "enabled" -msgstr "" - -msgid "disabled" -msgstr "" - -msgid "on the Settings page" +msgid "IP address recording can be disabled on the settings page" msgstr "" msgid "From IP" @@ -477,7 +471,7 @@ msgstr "" msgid "reactivated" msgstr "" -msgid "renamed" +msgid "renamed to" msgstr "" msgid "External link changed to" diff --git a/ihatemoney/templates/history.html b/ihatemoney/templates/history.html index 875040e4..6bd7e260 100644 --- a/ihatemoney/templates/history.html +++ b/ihatemoney/templates/history.html @@ -124,18 +124,25 @@ {% if current_log_pref == LoggingMode.DISABLED or (current_log_pref != LoggingMode.RECORD_IP and any_ip_addresses) %}
{% if current_log_pref == LoggingMode.DISABLED %} -

- {{ _("This project has history disabled. New actions won't appear below. You can enable history on the") }} - {{ _("settings page") }} +

{% set url = url_for(".edit_project") %} + {% trans %} + This project has history disabled. New actions won't appear below. You can enable history on the + settings page + {% endtrans %}

{% if history %} -

{{ _("The table below reflects actions recorded prior to disabling project history. You can ") }} - {{ _("clear project history") }} {{ _("to remove them.") }}

+

+ {% trans %} + The table below reflects actions recorded prior to disabling project history. You can + clear project history to remove them.

+ {% endtrans %} {% endif %} {% endif %} {% if current_log_pref != LoggingMode.RECORD_IP and any_ip_addresses %} -

{{ _("Some entries below contain IP addresses, even though this project has IP recording disabled. ") }} - {{ _("Delete stored IP addresses") }}

+

+ {{ _("Some entries below contain IP addresses, even though this project has IP recording disabled. ") }} + {{ _("Delete stored IP addresses") }} +

{% endif %}
{% endif %} @@ -160,10 +167,11 @@ {{ _("Time") }} {{ _("Event") }} - + {{ _("From IP") }} @@ -201,7 +209,7 @@ {{ event.object_type }} {{ event.object_desc }} {% if event.val_after == False %}{{ _("deactivated") }}{% else %}{{ _("reactivated") }}{% endif %} {% elif event.prop_changed == "name" or event.prop_changed == "what" %} - {{ describe_object(event) }} {{ _("renamed") }} {{ _("to") }} {{ event.val_after }} + {{ describe_object(event) }} {{ _("renamed to") }} {{ event.val_after }} {% elif event.prop_changed == "weight" %} {{ simple_property_change(event, _("Weight")) }} {% elif event.prop_changed == "external_link" %} diff --git a/ihatemoney/translations/cs/LC_MESSAGES/messages.po b/ihatemoney/translations/cs/LC_MESSAGES/messages.po index 3687aad1..cdfa96a1 100644 --- a/ihatemoney/translations/cs/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/cs/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-24 19:59+0200\n" +"POT-Creation-Date: 2020-04-25 12:43+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Automatically generated\n" "Language: cs\n" @@ -412,23 +412,23 @@ msgstr "" msgid "Balance" msgstr "" +#, python-format msgid "" -"This project has history disabled. New actions won't appear below. You " -"can enable history on the" -msgstr "" - -msgid "settings page" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " msgstr "" msgid "" -"The table below reflects actions recorded prior to disabling project " -"history. You can " -msgstr "" - -msgid "clear project history" -msgstr "" - -msgid "to remove them." +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\n" +" " msgstr "" msgid "" @@ -457,16 +457,10 @@ msgstr "" msgid "Event" msgstr "" -msgid "IP address recording can be" +msgid "IP address recording can be enabled on the settings page" msgstr "" -msgid "enabled" -msgstr "" - -msgid "disabled" -msgstr "" - -msgid "on the Settings page" +msgid "IP address recording can be disabled on the settings page" msgstr "" msgid "From IP" @@ -493,7 +487,7 @@ msgstr "" msgid "reactivated" msgstr "" -msgid "renamed" +msgid "renamed to" msgstr "" msgid "External link changed to" @@ -738,3 +732,4 @@ msgstr "" msgid "Period" msgstr "" + diff --git a/ihatemoney/translations/de/LC_MESSAGES/messages.po b/ihatemoney/translations/de/LC_MESSAGES/messages.po index 763dfdcb..b0abcd92 100644 --- a/ihatemoney/translations/de/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/de/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-24 19:59+0200\n" +"POT-Creation-Date: 2020-04-25 12:43+0200\n" "PO-Revision-Date: 2020-02-12 10:50+0000\n" "Last-Translator: flolilo \n" "Language: de\n" @@ -423,23 +423,23 @@ msgstr "Wer?" msgid "Balance" msgstr "Bilanz" +#, python-format msgid "" -"This project has history disabled. New actions won't appear below. You " -"can enable history on the" -msgstr "" - -msgid "settings page" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " msgstr "" msgid "" -"The table below reflects actions recorded prior to disabling project " -"history. You can " -msgstr "" - -msgid "clear project history" -msgstr "" - -msgid "to remove them." +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\n" +" " msgstr "" msgid "" @@ -468,16 +468,10 @@ msgstr "" msgid "Event" msgstr "" -msgid "IP address recording can be" +msgid "IP address recording can be enabled on the settings page" msgstr "" -msgid "enabled" -msgstr "" - -msgid "disabled" -msgstr "" - -msgid "on the Settings page" +msgid "IP address recording can be disabled on the settings page" msgstr "" msgid "From IP" @@ -504,7 +498,7 @@ msgstr "" msgid "reactivated" msgstr "" -msgid "renamed" +msgid "renamed to" msgstr "" msgid "External link changed to" @@ -760,3 +754,4 @@ msgstr "" msgid "Period" msgstr "" + diff --git a/ihatemoney/translations/el/LC_MESSAGES/messages.po b/ihatemoney/translations/el/LC_MESSAGES/messages.po index e7c0ef95..114a117c 100644 --- a/ihatemoney/translations/el/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/el/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-24 19:59+0200\n" +"POT-Creation-Date: 2020-04-25 12:43+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Automatically generated\n" "Language: el\n" @@ -412,23 +412,23 @@ msgstr "" msgid "Balance" msgstr "" +#, python-format msgid "" -"This project has history disabled. New actions won't appear below. You " -"can enable history on the" -msgstr "" - -msgid "settings page" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " msgstr "" msgid "" -"The table below reflects actions recorded prior to disabling project " -"history. You can " -msgstr "" - -msgid "clear project history" -msgstr "" - -msgid "to remove them." +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\n" +" " msgstr "" msgid "" @@ -457,16 +457,10 @@ msgstr "" msgid "Event" msgstr "" -msgid "IP address recording can be" +msgid "IP address recording can be enabled on the settings page" msgstr "" -msgid "enabled" -msgstr "" - -msgid "disabled" -msgstr "" - -msgid "on the Settings page" +msgid "IP address recording can be disabled on the settings page" msgstr "" msgid "From IP" @@ -493,7 +487,7 @@ msgstr "" msgid "reactivated" msgstr "" -msgid "renamed" +msgid "renamed to" msgstr "" msgid "External link changed to" @@ -738,3 +732,4 @@ msgstr "" msgid "Period" msgstr "" + diff --git a/ihatemoney/translations/es_419/LC_MESSAGES/messages.po b/ihatemoney/translations/es_419/LC_MESSAGES/messages.po index 219d7f85..fb0a2be0 100644 --- a/ihatemoney/translations/es_419/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/es_419/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-24 19:59+0200\n" +"POT-Creation-Date: 2020-04-25 12:43+0200\n" "PO-Revision-Date: 2019-09-25 22:28+0000\n" "Last-Translator: Diego Caraballo \n" "Language: es_419\n" @@ -425,23 +425,23 @@ msgstr "¿Quién?" msgid "Balance" msgstr "Balance" +#, python-format msgid "" -"This project has history disabled. New actions won't appear below. You " -"can enable history on the" -msgstr "" - -msgid "settings page" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " msgstr "" msgid "" -"The table below reflects actions recorded prior to disabling project " -"history. You can " -msgstr "" - -msgid "clear project history" -msgstr "" - -msgid "to remove them." +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\n" +" " msgstr "" msgid "" @@ -470,16 +470,10 @@ msgstr "" msgid "Event" msgstr "" -msgid "IP address recording can be" +msgid "IP address recording can be enabled on the settings page" msgstr "" -msgid "enabled" -msgstr "" - -msgid "disabled" -msgstr "" - -msgid "on the Settings page" +msgid "IP address recording can be disabled on the settings page" msgstr "" msgid "From IP" @@ -506,7 +500,7 @@ msgstr "" msgid "reactivated" msgstr "" -msgid "renamed" +msgid "renamed to" msgstr "" msgid "External link changed to" @@ -766,3 +760,4 @@ msgstr "" #~ msgid "%(member)s had been added" #~ msgstr "se han añadido %(member)s" + diff --git a/ihatemoney/translations/fr/LC_MESSAGES/messages.po b/ihatemoney/translations/fr/LC_MESSAGES/messages.po index a1d48d72..846dfc5c 100644 --- a/ihatemoney/translations/fr/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/fr/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-04-24 19:59+0200\n" +"POT-Creation-Date: 2020-04-25 12:43+0200\n" "PO-Revision-Date: 2020-04-22 22:11+0000\n" "Last-Translator: Glandos \n" "Language: fr\n" @@ -23,8 +23,8 @@ msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " "accepted." msgstr "" -"Ceci n'est pas un montant ou une expression valide. Seuls les nombres et les " -"opérateurs + - * / sont acceptés." +"Ceci n'est pas un montant ou une expression valide. Seuls les nombres et " +"les opérateurs + - * / sont acceptés." msgid "Project name" msgstr "Nom de projet" @@ -354,37 +354,37 @@ msgid "Download" msgstr "Télécharger" msgid "Disabled Project History" -msgstr "Historisation du projet désactivée" +msgstr "" msgid "Disabled Project History & IP Address Recording" -msgstr "Historisation du projet et enregistrement des adresses IP désactivés" +msgstr "" msgid "Enabled Project History" -msgstr "Historisation du projet activée" +msgstr "" msgid "Disabled IP Address Recording" -msgstr "Enregistrement des adresses IP désactivé" +msgstr "" msgid "Enabled Project History & IP Address Recording" -msgstr "Historisation du projet et enregistrement des adresses IP activés" +msgstr "" msgid "Enabled IP Address Recording" -msgstr "Enregistrement des adresses IP activé" +msgstr "" msgid "History Settings Changed" -msgstr "Changement des paramètres d’historisation" +msgstr "" msgid "changed" -msgstr "modifié" +msgstr "" msgid "from" -msgstr "depuis" +msgstr "" msgid "to" -msgstr "vers" +msgstr "" msgid "Confirm Remove IP Adresses" -msgstr "Confirmer la suppression des adresses IP" +msgstr "" msgid "" "Are you sure you want to delete all recorded IP addresses from this " @@ -392,32 +392,26 @@ msgid "" " The rest of the project history will be unaffected. This " "action cannot be undone." msgstr "" -"Êtes vous sûr de supprimer toutes les adresses IP enregistrées dans ce " -"projet ?\n" -"Le reste de l’historique du projet restera inchangé. Cette action est " -"irréversible." msgid "Close" -msgstr "Fermer" +msgstr "" msgid "Confirm Delete" -msgstr "Confirmer la suppression" +msgstr "" msgid "Delete Confirmation" -msgstr "Confirmation de suppression" +msgstr "" msgid "" "Are you sure you want to erase all history for this project? This action " "cannot be undone." msgstr "" -"Êtes vous sûr de supprimer la totalité de l’historique de ce projet ? " -"Cette action est irréversible." msgid "Added" -msgstr "Ajouté" +msgstr "" msgid "Removed" -msgstr "Supprimé" +msgstr "" msgid "and" msgstr "" @@ -431,23 +425,23 @@ msgstr "Qui ?" msgid "Balance" msgstr "Solde" +#, python-format msgid "" -"This project has history disabled. New actions won't appear below. You " -"can enable history on the" -msgstr "" - -msgid "settings page" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " msgstr "" msgid "" -"The table below reflects actions recorded prior to disabling project " -"history. You can " -msgstr "" - -msgid "clear project history" -msgstr "" - -msgid "to remove them." +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\n" +" " msgstr "" msgid "" @@ -476,16 +470,10 @@ msgstr "" msgid "Event" msgstr "" -msgid "IP address recording can be" +msgid "IP address recording can be enabled on the settings page" msgstr "" -msgid "enabled" -msgstr "" - -msgid "disabled" -msgstr "" - -msgid "on the Settings page" +msgid "IP address recording can be disabled on the settings page" msgstr "" msgid "From IP" @@ -512,7 +500,7 @@ msgstr "" msgid "reactivated" msgstr "" -msgid "renamed" +msgid "renamed to" msgstr "" msgid "External link changed to" @@ -915,3 +903,70 @@ msgstr "" #~ msgid "%(member)s had been added" #~ msgstr "%(member)s a bien été ajouté" + +#~ msgid "Disabled Project History" +#~ msgstr "Historisation du projet désactivée" + +#~ msgid "Disabled Project History & IP Address Recording" +#~ msgstr "Historisation du projet et enregistrement des adresses IP désactivés" + +#~ msgid "Enabled Project History" +#~ msgstr "Historisation du projet activée" + +#~ msgid "Disabled IP Address Recording" +#~ msgstr "Enregistrement des adresses IP désactivé" + +#~ msgid "Enabled Project History & IP Address Recording" +#~ msgstr "Historisation du projet et enregistrement des adresses IP activés" + +#~ msgid "Enabled IP Address Recording" +#~ msgstr "Enregistrement des adresses IP activé" + +#~ msgid "History Settings Changed" +#~ msgstr "Changement des paramètres d’historisation" + +#~ msgid "changed" +#~ msgstr "modifié" + +#~ msgid "from" +#~ msgstr "depuis" + +#~ msgid "to" +#~ msgstr "vers" + +#~ msgid "Confirm Remove IP Adresses" +#~ msgstr "Confirmer la suppression des adresses IP" + +#~ 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 "" +#~ "Êtes vous sûr de supprimer toutes " +#~ "les adresses IP enregistrées dans ce " +#~ "projet ?\n" +#~ "Le reste de l’historique du projet " +#~ "restera inchangé. Cette action est " +#~ "irréversible." + +#~ msgid "Close" +#~ msgstr "Fermer" + +#~ msgid "Confirm Delete" +#~ msgstr "Confirmer la suppression" + +#~ msgid "Delete Confirmation" +#~ msgstr "Confirmation de suppression" + +#~ msgid "" +#~ "Are you sure you want to erase " +#~ "all history for this project? This " +#~ "action cannot be undone." +#~ msgstr "" +#~ "Êtes vous sûr de supprimer la " +#~ "totalité de l’historique de ce projet" +#~ " ? Cette action est irréversible." + diff --git a/ihatemoney/translations/id/LC_MESSAGES/messages.po b/ihatemoney/translations/id/LC_MESSAGES/messages.po index ebe70535..41f8f16f 100644 --- a/ihatemoney/translations/id/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/id/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-24 19:59+0200\n" +"POT-Creation-Date: 2020-04-25 12:43+0200\n" "PO-Revision-Date: 2019-11-16 10:04+0000\n" "Last-Translator: Muhammad Fauzi \n" "Language: id\n" @@ -419,23 +419,23 @@ msgstr "Siapa?" msgid "Balance" msgstr "Saldo" +#, python-format msgid "" -"This project has history disabled. New actions won't appear below. You " -"can enable history on the" -msgstr "" - -msgid "settings page" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " msgstr "" msgid "" -"The table below reflects actions recorded prior to disabling project " -"history. You can " -msgstr "" - -msgid "clear project history" -msgstr "" - -msgid "to remove them." +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\n" +" " msgstr "" msgid "" @@ -464,16 +464,10 @@ msgstr "" msgid "Event" msgstr "" -msgid "IP address recording can be" +msgid "IP address recording can be enabled on the settings page" msgstr "" -msgid "enabled" -msgstr "" - -msgid "disabled" -msgstr "" - -msgid "on the Settings page" +msgid "IP address recording can be disabled on the settings page" msgstr "" msgid "From IP" @@ -500,7 +494,7 @@ msgstr "" msgid "reactivated" msgstr "" -msgid "renamed" +msgid "renamed to" msgstr "" msgid "External link changed to" @@ -760,3 +754,4 @@ msgstr "" #~ msgid "%(member)s had been added" #~ msgstr "%(member)s telah ditambahkan" + diff --git a/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po b/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po index 0b773e60..696db04a 100644 --- a/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-24 19:59+0200\n" +"POT-Creation-Date: 2020-04-25 12:43+0200\n" "PO-Revision-Date: 2019-11-12 09:04+0000\n" "Last-Translator: Allan Nordhøy \n" "Language: nb_NO\n" @@ -435,23 +435,23 @@ msgstr "Hvem?" msgid "Balance" msgstr "Kontobalanse" +#, python-format msgid "" -"This project has history disabled. New actions won't appear below. You " -"can enable history on the" -msgstr "" - -msgid "settings page" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " msgstr "" msgid "" -"The table below reflects actions recorded prior to disabling project " -"history. You can " -msgstr "" - -msgid "clear project history" -msgstr "" - -msgid "to remove them." +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\n" +" " msgstr "" msgid "" @@ -480,16 +480,10 @@ msgstr "" msgid "Event" msgstr "" -msgid "IP address recording can be" +msgid "IP address recording can be enabled on the settings page" msgstr "" -msgid "enabled" -msgstr "" - -msgid "disabled" -msgstr "" - -msgid "on the Settings page" +msgid "IP address recording can be disabled on the settings page" msgstr "" msgid "From IP" @@ -516,7 +510,7 @@ msgstr "" msgid "reactivated" msgstr "" -msgid "renamed" +msgid "renamed to" msgstr "" msgid "External link changed to" @@ -897,3 +891,4 @@ msgstr "" #~ msgid "%(member)s had been added" #~ msgstr "%(member)s lagt til" + diff --git a/ihatemoney/translations/nl/LC_MESSAGES/messages.po b/ihatemoney/translations/nl/LC_MESSAGES/messages.po index 0cd41422..ed063bce 100644 --- a/ihatemoney/translations/nl/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/nl/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-04-24 19:59+0200\n" +"POT-Creation-Date: 2020-04-25 12:43+0200\n" "PO-Revision-Date: 2019-10-07 22:56+0000\n" "Last-Translator: Heimen Stoffels \n" "Language: nl\n" @@ -419,23 +419,23 @@ msgstr "Wie?" msgid "Balance" msgstr "Saldo" +#, python-format msgid "" -"This project has history disabled. New actions won't appear below. You " -"can enable history on the" -msgstr "" - -msgid "settings page" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " msgstr "" msgid "" -"The table below reflects actions recorded prior to disabling project " -"history. You can " -msgstr "" - -msgid "clear project history" -msgstr "" - -msgid "to remove them." +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\n" +" " msgstr "" msgid "" @@ -464,16 +464,10 @@ msgstr "" msgid "Event" msgstr "" -msgid "IP address recording can be" +msgid "IP address recording can be enabled on the settings page" msgstr "" -msgid "enabled" -msgstr "" - -msgid "disabled" -msgstr "" - -msgid "on the Settings page" +msgid "IP address recording can be disabled on the settings page" msgstr "" msgid "From IP" @@ -500,7 +494,7 @@ msgstr "" msgid "reactivated" msgstr "" -msgid "renamed" +msgid "renamed to" msgstr "" msgid "External link changed to" @@ -756,119 +750,3 @@ msgstr "" msgid "Period" msgstr "" -#~ msgid "" -#~ "The project identifier is used to " -#~ "log in and for the URL of " -#~ "the project. We tried to generate " -#~ "an identifier for you but a " -#~ "project with this identifier already " -#~ "exists. Please create a new identifier" -#~ " that you will be able to " -#~ "remember" -#~ msgstr "" -#~ "De project-id wordt gebruikt om in" -#~ " te loggen en als url van het" -#~ " project. We hebben geprobeerd om een" -#~ " id voor je te genereren, maar " -#~ "er is al een project met deze " -#~ "id. Creëer een nieuwe id die je" -#~ " makkelijk kunt onthouden." - -#~ msgid "" -#~ "Not a valid amount or expression.Only" -#~ " numbers and + - * / " -#~ "operatorsare accepted." -#~ msgstr "" -#~ "Geen geldig bedrag of geldige expressie." -#~ " Alleen getallen en + - * / " -#~ "zijn toegestaan." - -#~ msgid "What do you want to download ?" -#~ msgstr "Wat wil je downloaden?" - -#~ msgid "bills" -#~ msgstr "rekeningen" - -#~ msgid "transactions" -#~ msgstr "transacties" - -#~ msgid "Export file format" -#~ msgstr "Bestandsformaat voor exporteren" - -#~ msgid "Edit this project" -#~ msgstr "Dit project bewerken" - -#~ msgid "Download this project's data" -#~ msgstr "Projectgegevens downloaden" - -#~ msgid "Type user name here" -#~ msgstr "Typ hier de gebruikersnaam" - -#~ msgid "No, thanks" -#~ msgstr "Nee, bedankt" - -#~ msgid "Manage your shared
expenses, easily" -#~ msgstr "Beheer eenvoudig je gedeelde
uitgaven" - -#~ msgid "Log to an existing project" -#~ msgstr "Log in op een bestaand project" - -#~ msgid "log in" -#~ msgstr "inloggen" - -#~ msgid "or create a new one" -#~ msgstr "of creëer een nieuwe" - -#~ msgid "let's get started" -#~ msgstr "aan de slag" - -#~ msgid "options" -#~ msgstr "opties" - -#~ msgid "Project settings" -#~ msgstr "Projectinstellingen" - -#~ msgid "This is a free software" -#~ msgstr "Dit is vrije software" - -#~ msgid "Invite people to join this project!" -#~ msgstr "Nodig mensen uit voor dit project!" - -#~ msgid "Added on" -#~ msgstr "Toegevoegd op" - -#~ msgid "Nothing to list yet. You probably want to" -#~ msgstr "Er kan nog geen opsomming worden gemaakt. Voeg" - -#~ 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 "" -#~ "Geef een kommagescheiden lijst van " -#~ "e-mailadressen op. Deze mensen worden op" -#~ " de\n" -#~ "hoogte gebracht van het bestaan van " -#~ "dit project en wij sturen hen een" -#~ " e-mail." - -#~ msgid "" -#~ "If you prefer, you can share the project identifier and the shared\n" -#~ "password by other communication means. " -#~ "Or even directly share the following " -#~ "link:" -#~ msgstr "" -#~ "Als je wilt, dan kun je de project-id en het gedeelde wachtwoord\n" -#~ "delen via andere kanalen. Of deel gewoon de volgende link:" - -#~ msgid "A link to reset your password has been sent to your email." -#~ msgstr "" -#~ "Er is een link met " -#~ "wachtwoordherstelinstructies naar je e-mailadres " -#~ "verstuurd." - -#~ msgid "%(member)s had been added" -#~ msgstr "%(member)s is toegevoegd" diff --git a/ihatemoney/translations/tr/LC_MESSAGES/messages.po b/ihatemoney/translations/tr/LC_MESSAGES/messages.po index f86a7ed5..69464b82 100644 --- a/ihatemoney/translations/tr/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/tr/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-24 19:59+0200\n" +"POT-Creation-Date: 2020-04-25 12:43+0200\n" "PO-Revision-Date: 2019-08-07 13:24+0000\n" "Last-Translator: Mesut Akcan \n" "Language: tr\n" @@ -417,23 +417,23 @@ msgstr "" msgid "Balance" msgstr "" +#, python-format msgid "" -"This project has history disabled. New actions won't appear below. You " -"can enable history on the" -msgstr "" - -msgid "settings page" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " msgstr "" msgid "" -"The table below reflects actions recorded prior to disabling project " -"history. You can " -msgstr "" - -msgid "clear project history" -msgstr "" - -msgid "to remove them." +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\n" +" " msgstr "" msgid "" @@ -462,16 +462,10 @@ msgstr "" msgid "Event" msgstr "" -msgid "IP address recording can be" +msgid "IP address recording can be enabled on the settings page" msgstr "" -msgid "enabled" -msgstr "" - -msgid "disabled" -msgstr "" - -msgid "on the Settings page" +msgid "IP address recording can be disabled on the settings page" msgstr "" msgid "From IP" @@ -498,7 +492,7 @@ msgstr "" msgid "reactivated" msgstr "" -msgid "renamed" +msgid "renamed to" msgstr "" msgid "External link changed to" @@ -743,3 +737,4 @@ msgstr "" msgid "Period" msgstr "" + diff --git a/ihatemoney/translations/uk/LC_MESSAGES/messages.po b/ihatemoney/translations/uk/LC_MESSAGES/messages.po index a893f11e..ed96cbd4 100644 --- a/ihatemoney/translations/uk/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/uk/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-24 19:59+0200\n" +"POT-Creation-Date: 2020-04-25 12:43+0200\n" "PO-Revision-Date: 2019-12-08 16:26+0000\n" "Last-Translator: Tymofij Lytvynenko \n" "Language: uk\n" @@ -414,23 +414,23 @@ msgstr "" msgid "Balance" msgstr "" +#, python-format msgid "" -"This project has history disabled. New actions won't appear below. You " -"can enable history on the" -msgstr "" - -msgid "settings page" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " msgstr "" msgid "" -"The table below reflects actions recorded prior to disabling project " -"history. You can " -msgstr "" - -msgid "clear project history" -msgstr "" - -msgid "to remove them." +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\n" +" " msgstr "" msgid "" @@ -459,16 +459,10 @@ msgstr "" msgid "Event" msgstr "" -msgid "IP address recording can be" +msgid "IP address recording can be enabled on the settings page" msgstr "" -msgid "enabled" -msgstr "" - -msgid "disabled" -msgstr "" - -msgid "on the Settings page" +msgid "IP address recording can be disabled on the settings page" msgstr "" msgid "From IP" @@ -495,7 +489,7 @@ msgstr "" msgid "reactivated" msgstr "" -msgid "renamed" +msgid "renamed to" msgstr "" msgid "External link changed to" @@ -740,3 +734,4 @@ msgstr "" msgid "Period" msgstr "" + diff --git a/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po b/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po index 77436237..565ffc0c 100644 --- a/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-24 19:59+0200\n" +"POT-Creation-Date: 2020-04-25 12:43+0200\n" "PO-Revision-Date: 2020-02-09 12:01+0000\n" "Last-Translator: Muge Niu \n" "Language: zh_HANS_CN\n" @@ -414,23 +414,23 @@ msgstr "谁?" msgid "Balance" msgstr "" +#, python-format msgid "" -"This project has history disabled. New actions won't appear below. You " -"can enable history on the" -msgstr "" - -msgid "settings page" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " msgstr "" msgid "" -"The table below reflects actions recorded prior to disabling project " -"history. You can " -msgstr "" - -msgid "clear project history" -msgstr "" - -msgid "to remove them." +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\n" +" " msgstr "" msgid "" @@ -459,16 +459,10 @@ msgstr "" msgid "Event" msgstr "" -msgid "IP address recording can be" +msgid "IP address recording can be enabled on the settings page" msgstr "" -msgid "enabled" -msgstr "" - -msgid "disabled" -msgstr "" - -msgid "on the Settings page" +msgid "IP address recording can be disabled on the settings page" msgstr "" msgid "From IP" @@ -495,7 +489,7 @@ msgstr "" msgid "reactivated" msgstr "" -msgid "renamed" +msgid "renamed to" msgstr "" msgid "External link changed to" @@ -740,3 +734,4 @@ msgstr "" msgid "Period" msgstr "" + From 84c8949a8179e52a5cfb98f80f71207dbb9e424d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Hubscher?= Date: Sat, 25 Apr 2020 10:19:15 +0000 Subject: [PATCH 28/47] Translated using Weblate (French) Currently translated at 83.3% (190 of 228 strings) Translation: I Hate Money/I Hate Money Translate-URL: https://hosted.weblate.org/projects/i-hate-money/i-hate-money/fr/ --- .../translations/fr/LC_MESSAGES/messages.po | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/ihatemoney/translations/fr/LC_MESSAGES/messages.po b/ihatemoney/translations/fr/LC_MESSAGES/messages.po index a1d48d72..aedba0fc 100644 --- a/ihatemoney/translations/fr/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/fr/LC_MESSAGES/messages.po @@ -8,15 +8,16 @@ msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2020-04-24 19:59+0200\n" -"PO-Revision-Date: 2020-04-22 22:11+0000\n" -"Last-Translator: Glandos \n" +"PO-Revision-Date: 2020-04-25 10:44+0000\n" +"Last-Translator: Rémy Hubscher \n" +"Language-Team: French \n" "Language: fr\n" -"Language-Team: French \n" -"Plural-Forms: nplurals=2; plural=n > 1\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.0.2-dev\n" "Generated-By: Babel 2.8.0\n" msgid "" @@ -144,7 +145,7 @@ msgid "The email %(email)s is not valid" msgstr "L’email %(email)s est invalide" msgid "Participant" -msgstr "" +msgstr "Participant" msgid "Bill" msgstr "Facture" @@ -205,7 +206,7 @@ msgstr "Vos invitations ont bien été envoyées" #, python-format msgid "%(member)s has been added" -msgstr "" +msgstr "%(member)s a été ajouté" #, python-format msgid "%(name)s is part of this project again" @@ -420,10 +421,10 @@ msgid "Removed" msgstr "Supprimé" msgid "and" -msgstr "" +msgstr "et" msgid "owers list" -msgstr "" +msgstr "Liste des débiteurs" msgid "Who?" msgstr "Qui ?" @@ -435,6 +436,8 @@ msgid "" "This project has history disabled. New actions won't appear below. You " "can enable history on the" msgstr "" +"L'historique de ce projet a été désactivé. Les nouvelles actions n’" +"apparaîtront pas ci-dessous. Vous pouvez réactiver l'historique sur le" msgid "settings page" msgstr "" From 1167a64b50d2c6890674969e1bcf7c324348dc07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Hubscher?= Date: Sat, 25 Apr 2020 10:48:46 +0000 Subject: [PATCH 29/47] Translated using Weblate (French) Currently translated at 97.7% (218 of 223 strings) Translation: I Hate Money/I Hate Money Translate-URL: https://hosted.weblate.org/projects/i-hate-money/i-hate-money/fr/ --- .../translations/fr/LC_MESSAGES/messages.po | 112 +++++++++++------- 1 file changed, 69 insertions(+), 43 deletions(-) diff --git a/ihatemoney/translations/fr/LC_MESSAGES/messages.po b/ihatemoney/translations/fr/LC_MESSAGES/messages.po index a95abaff..692ac5c9 100644 --- a/ihatemoney/translations/fr/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/fr/LC_MESSAGES/messages.po @@ -8,8 +8,10 @@ msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2020-04-25 12:43+0200\n" -"PO-Revision-Date: 2020-04-22 22:11+0000\n" -"Last-Translator: Glandos \n" +"PO-Revision-Date: 2020-04-25 11:01+0000\n" +"Last-Translator: Rémy Hubscher \n" +"Language-Team: French \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" @@ -353,37 +355,37 @@ msgid "Download" msgstr "Télécharger" msgid "Disabled Project History" -msgstr "" +msgstr "Désactiver l'historique du projet." msgid "Disabled Project History & IP Address Recording" -msgstr "" +msgstr "Désactiver l'historique du projet et l'enregistrement des adresses IP" msgid "Enabled Project History" -msgstr "" +msgstr "Activer l'historique du projet" msgid "Disabled IP Address Recording" -msgstr "" +msgstr "Désactiver l'enregistrement des adresses IP" msgid "Enabled Project History & IP Address Recording" -msgstr "" +msgstr "Activer l'historique du projet et l’enregistrement des adresses IP" msgid "Enabled IP Address Recording" -msgstr "" +msgstr "Activer l'enregistrement des adresses IP" msgid "History Settings Changed" -msgstr "" +msgstr "Paramètres d'historique modifiés" msgid "changed" -msgstr "" +msgstr "modifié" msgid "from" -msgstr "" +msgstr "du" msgid "to" -msgstr "" +msgstr "au" msgid "Confirm Remove IP Adresses" -msgstr "" +msgstr "Confirmer la suppression des adresses IP" msgid "" "Are you sure you want to delete all recorded IP addresses from this " @@ -391,26 +393,32 @@ msgid "" " The rest of the project history will be unaffected. This " "action cannot be undone." msgstr "" +"Êtes-vous sur de vouloir supprimer toutes les adresses IP enregistrées pour " +"ce projet?\n" +"Le reste de l'historique ne sera pas affecté. Cette action n'est pas " +"réversible." msgid "Close" -msgstr "" +msgstr "Fermer" msgid "Confirm Delete" -msgstr "" +msgstr "Confirmer la suppression" msgid "Delete Confirmation" -msgstr "" +msgstr "Confirmation de suppression" msgid "" "Are you sure you want to erase all history for this project? This action " "cannot be undone." msgstr "" +"Êtes-vous sur de vouloir supprimer tout l'historique du projet? Cette action " +"n'est pas réversible." msgid "Added" -msgstr "" +msgstr "Ajouté" msgid "Removed" -msgstr "" +msgstr "Supprimé" msgid "and" msgstr "et" @@ -432,6 +440,12 @@ msgid "" " settings page\n" " " msgstr "" +"\n" +" L'historique de ce projet a été désactivé. Les nouvelles " +"actions n'apparaîtront pas ci-dessous. Vous pouvez réactiver l'historique du " +"projet dans les \n" +" paramètres du projet\n" +" " msgid "" "\n" @@ -442,89 +456,102 @@ msgid "" "them.

\n" " " msgstr "" +"\n" +" Le tableau ci-dessous liste les actions enregistrées avant la " +"désactivation de l'historique du projet. Vous pouvez\n" +" clear project history cliquer ici pour les " +"supprimer.

\n" +" " msgid "" "Some entries below contain IP addresses, even though this project has IP " "recording disabled. " msgstr "" +"Certaines entrées de l'historique contiennent une adresse IP, bien que ce " +"projet ait désactivé l'enregistrement des adresses IP. " msgid "Delete stored IP addresses" -msgstr "" +msgstr "Supprimer toutes les adresses IP enregistrées" msgid "No history to erase" -msgstr "" +msgstr "Aucun historique à supprimer" msgid "Clear Project History" -msgstr "" +msgstr "Supprimer les entrées de l'historique du projet" msgid "No IP Addresses to erase" -msgstr "" +msgstr "Aucune adresse IP à supprimer" msgid "Delete Stored IP Addresses" -msgstr "" +msgstr "Supprimer les adresses IP enregistrées" msgid "Time" -msgstr "" +msgstr "Heure" msgid "Event" -msgstr "" +msgstr "Évènement" msgid "IP address recording can be enabled on the settings page" msgstr "" +"L'enregistrement des adresses IP peut-être activé dans les paramètres de la " +"page" msgid "IP address recording can be disabled on the settings page" msgstr "" +"L'enregistrement des adresses IP peut-être désactivé dans les paramètres de " +"la page" msgid "From IP" -msgstr "" +msgstr "Depuis l'IP" msgid "added" -msgstr "" +msgstr "ajouté" msgid "Project private code changed" -msgstr "" +msgstr "Le mot de passe du projet a été modifié" msgid "Project renamed to" -msgstr "" +msgstr "Le projet a été renommé" msgid "Project contact email changed to" -msgstr "" +msgstr "L'adresse email de contact du projet a été modifié en" msgid "Project settings modified" -msgstr "" +msgstr "Les paramètres du projet ont été modifiés" msgid "deactivated" -msgstr "" +msgstr "désactivé" msgid "reactivated" -msgstr "" +msgstr "réactivé" msgid "renamed to" -msgstr "" +msgstr "renommé en" msgid "External link changed to" -msgstr "" +msgstr "Le lien d'accès a été modifié en" msgid "Amount" -msgstr "" +msgstr "Montant" msgid "modified" -msgstr "" +msgstr "modifié" msgid "removed" -msgstr "" +msgstr "supprimé" msgid "changed in a unknown way" -msgstr "" +msgstr "modifié d'une manière inconnue" msgid "Nothing to list" -msgstr "" +msgstr "Rien à afficher" msgid "Someone probably" -msgstr "" +msgstr "Quelqu'un a probablement" msgid "cleared the project history." -msgstr "" +msgstr "vidé l'historique du projet." msgid "Manage your shared
expenses, easily" msgstr "Gérez vos dépenses
partagées, facilement" @@ -968,4 +995,3 @@ msgstr "" #~ "Êtes vous sûr de supprimer la " #~ "totalité de l’historique de ce projet" #~ " ? Cette action est irréversible." - From 741e4023b4384fa762e1a67ec9874e812cd7ad1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Sat, 25 Apr 2020 13:04:47 +0200 Subject: [PATCH 30/47] Fix last history string. --- ihatemoney/messages.pot | 5 +- ihatemoney/templates/history.html | 3 +- .../translations/cs/LC_MESSAGES/messages.mo | Bin 447 -> 447 bytes .../translations/cs/LC_MESSAGES/messages.po | 8 +-- .../translations/de/LC_MESSAGES/messages.mo | Bin 11121 -> 11046 bytes .../translations/de/LC_MESSAGES/messages.po | 13 +++-- .../translations/el/LC_MESSAGES/messages.mo | Bin 418 -> 418 bytes .../translations/el/LC_MESSAGES/messages.po | 8 +-- .../es_419/LC_MESSAGES/messages.mo | Bin 11626 -> 11557 bytes .../es_419/LC_MESSAGES/messages.po | 8 +-- .../translations/fr/LC_MESSAGES/messages.mo | Bin 11776 -> 16937 bytes .../translations/fr/LC_MESSAGES/messages.po | 50 ++++++++---------- .../translations/id/LC_MESSAGES/messages.mo | Bin 11040 -> 10969 bytes .../translations/id/LC_MESSAGES/messages.po | 13 +++-- .../nb_NO/LC_MESSAGES/messages.mo | Bin 8891 -> 8829 bytes .../nb_NO/LC_MESSAGES/messages.po | 8 +-- .../translations/nl/LC_MESSAGES/messages.mo | Bin 11153 -> 11086 bytes .../translations/nl/LC_MESSAGES/messages.po | 8 +-- .../translations/tr/LC_MESSAGES/messages.mo | Bin 1724 -> 1724 bytes .../translations/tr/LC_MESSAGES/messages.po | 8 +-- .../translations/uk/LC_MESSAGES/messages.mo | Bin 1652 -> 1652 bytes .../translations/uk/LC_MESSAGES/messages.po | 8 +-- .../zh_HANS-CN/LC_MESSAGES/messages.mo | Bin 2158 -> 2158 bytes .../zh_HANS-CN/LC_MESSAGES/messages.po | 8 +-- 24 files changed, 57 insertions(+), 91 deletions(-) diff --git a/ihatemoney/messages.pot b/ihatemoney/messages.pot index dfd1877a..63f16cd0 100644 --- a/ihatemoney/messages.pot +++ b/ihatemoney/messages.pot @@ -492,10 +492,7 @@ msgstr "" msgid "Nothing to list" msgstr "" -msgid "Someone probably" -msgstr "" - -msgid "cleared the project history." +msgid "Someone probably cleared the project history." msgstr "" msgid "Manage your shared
expenses, easily" diff --git a/ihatemoney/templates/history.html b/ihatemoney/templates/history.html index 6bd7e260..1ac3284f 100644 --- a/ihatemoney/templates/history.html +++ b/ihatemoney/templates/history.html @@ -248,8 +248,7 @@ {{ static_include("images/hand-holding-heart.svg") | safe }}

{{ _('Nothing to list')}}

- {{ _("Someone probably") }}
- {{ _("cleared the project history.") }} + {{ _("Someone probably cleared the project history.") }}

diff --git a/ihatemoney/translations/cs/LC_MESSAGES/messages.mo b/ihatemoney/translations/cs/LC_MESSAGES/messages.mo index 3e48ab6462922f0a114fce410e2fe8d814b547e1..58260758d08b6d81ff8ce0ae59636fe36c09932a 100644 GIT binary patch delta 18 Zcmdnbyq|eO3%jX;p^=q|@y2cwMgTY?1!@2Q delta 18 Zcmdnbyq|eO3%j9$p^25D#l~(EMgTYt1!@2Q diff --git a/ihatemoney/translations/cs/LC_MESSAGES/messages.po b/ihatemoney/translations/cs/LC_MESSAGES/messages.po index cdfa96a1..ed2fddf0 100644 --- a/ihatemoney/translations/cs/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/cs/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-25 12:43+0200\n" +"POT-Creation-Date: 2020-04-25 13:02+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Automatically generated\n" "Language: cs\n" @@ -508,10 +508,7 @@ msgstr "" msgid "Nothing to list" msgstr "" -msgid "Someone probably" -msgstr "" - -msgid "cleared the project history." +msgid "Someone probably cleared the project history." msgstr "" msgid "Manage your shared
expenses, easily" @@ -732,4 +729,3 @@ msgstr "" msgid "Period" msgstr "" - diff --git a/ihatemoney/translations/de/LC_MESSAGES/messages.mo b/ihatemoney/translations/de/LC_MESSAGES/messages.mo index 5887acc14c8f10c9b0d2cc60c2f865d033a144f2..8cf55064b9d2ee8e9f5c186579c8566f0f551d80 100644 GIT binary patch delta 2556 zcmYM#e@xVM9LMoDb|-RO{5a}F!t*)_IH$;AI>KOx(j=#JtZ0dqnKYZsNle>x_04J| zf3z5oP2Ad~jht)6yv;w<$Z{*ja#EzlT5L3&xn^aP+;YvHFYmK;JMQuMeDCx9eBST( z=kqj=$^+)`~yoc7BI`eM%;)S@EJUeId~H@ zG4pP-yD$g2Wciql5oDZa%V^|rp~ijDg!Ab?i%W4Y^0p88$i+`l6Q4y*IEsFpzDpsu{ze8QWjJokJ)B-u&MNC$J+Urv1YSdY1 zLIt=Pb^nW~l6RsKdIy=x22t~!$ff=&)oCv1hA&ZjeF3%571Zhf8>_H@v`%0Wm5GmN z6-WRTKm;{k91E}lOR*7au>&>#FemJ;SI&7D)1dB-HL0pTf z%uA?Dx^M-)i^OW@P?>&@?Kp!vTS@jOiXF(5=JnE0=0m8+Q>cJWp)$Pa{0Vi~rk%f` z_I?)Y@gIB=YrJ+zQ2_8Ug#W5_#GpK~7QQu!iRXE52(>#T!fMTdKlkjLzJ*z=2 z(26=V+mZ8P`(6KiR6w6NKX;C!?w>{lavK$3KIv-VGSn8Wa@L^E#yV60-WD2B8auES zyYV9&MLj;d7pF_LA64>x)Quk?RkY)%OvkVeuOqu+m6StgDv6v!Ye$`}Zq)d*cu3Fx z6&lT4c#WSm*0gVNIo?1`RLp3VZY{3E4X7>ZL1jFMd+{We;j+^70xhUYzKR;xk4oqm zGPR}9$NDx&!_S2&REcL$1846Hpuw!`!H-YjCTzqZtiwNX6DH#6O1+Lt=^sXw`YTjo zQ>eYq;AHFY8}$RS59i_Ar~rE~fQPUgkD|tnqqgK{)WTO$r$5{` enH5hJ1#V_%u8bxss~=jCDqPT&k@})=IQKtztLjMr delta 2644 zcmYM#drZ}39LMo52_j(J6i`6;K?s~;AWBSx3|Sc}Hl>m!S>etJTLQ(U0<5#9IP6B7 z!`YOTTf@0&IZhjMqW^eVEn2L(wghA~w9BC7ZOwV>{o(vt49@F$e!u7UJm2s4d47lf zO;hExcpsPI!br1htilj%!S&dNTks6VU`CW# zI2Ph8EJ1GBV;F7bw@MlsSc7p`AG~4hm_)xD^YC-z*S_Z?7Jo)f{3mL{YZ!)iaURZ^ z8%!t(XVWi2G{Q| z=L>KV7Q6jt(L=u$m1q|#!Tsph#ClP zz0uW&It%Tn0C%D0{RCC=K2$=3$ka9*OZ_$B7#CE!%cuvYPUv#!Q(Lw(K8q94&sLV%Dk&mMSnnY!I-!&{T zc-W#`6Ht4fjun`N&tW~5;3+J_e^75t5or^PH6a!8+b$X^#Zf*K*;&*npTwE>8kNai z)Txf9o;vM$sQbmJfLEacsdQbBDtR?(TnFm8F4SAoGt+1P2WXrQp#qq}jZV^bun+U` zG%mquWSFI;n0e8`m#_;Jz-81HOrZ|nO;lw=*dJ9k0V#rIB1>5bMzg+EyBF%PkbVbh z!lTIfvVhw^hpNOdYN2sd#jcVKS-`S#IBh6wj8S=3D1p--3SaZ9NT@yuq~- zN!IpYF@AwsXcRf8cH1>NE!fXMj)xVY0$+=ocO&X>*PveOH&6k#yY5V5|Fst%abf24 zqW(#oKt*~A_4@sQ591}&xCo+=@u=%5sEJqOqqqU}{BBew_M_f{KGb~2Q0oq*`^{da zF~J4xNx2g&<@2bF8c-AMM3uf5l}SG;fG<&}c@VR47_}AGF$=>vP)aBdb$afNbU1oY0USmL1Go||;9;EiQ1CT6iK^6jRLLh$&;5ZE(QcwLO(6YpEJJq9-a(zI zgUETcLF8=t?E(!w5XINoK3s~`_${)wrE;?XA4g5pgeu*~_yq1lZP6$y<7s>oLvqY= z@onUi9YR&|8`QW7jAVVgPJ^}V9)@BTPlcfeRnh{~7f3nk{yMD04OoMp;u^e)FgbgNKEuKZ1pvJTDakLw)%XHPMz25 z^9KHkxE&o{=oA*MC|n-+d%^CIMgI+atF77V%Wd>H+g@$#Xsh?Va%QN$HPD>=b?m=+ Cy$Z?z diff --git a/ihatemoney/translations/de/LC_MESSAGES/messages.po b/ihatemoney/translations/de/LC_MESSAGES/messages.po index b0abcd92..ee83f826 100644 --- a/ihatemoney/translations/de/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/de/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-25 12:43+0200\n" +"POT-Creation-Date: 2020-04-25 13:02+0200\n" "PO-Revision-Date: 2020-02-12 10:50+0000\n" "Last-Translator: flolilo \n" "Language: de\n" @@ -519,10 +519,7 @@ msgstr "" msgid "Nothing to list" msgstr "" -msgid "Someone probably" -msgstr "" - -msgid "cleared the project history." +msgid "Someone probably cleared the project history." msgstr "" msgid "Manage your shared
expenses, easily" @@ -755,3 +752,9 @@ msgstr "" msgid "Period" msgstr "" +#~ msgid "Someone probably" +#~ msgstr "" + +#~ msgid "cleared the project history." +#~ msgstr "" + diff --git a/ihatemoney/translations/el/LC_MESSAGES/messages.mo b/ihatemoney/translations/el/LC_MESSAGES/messages.mo index c316b44adfac9c845a8f08068ef2bb2a66ec256d..69086172c2024955047fb8f3b65b6109aed82d8a 100644 GIT binary patch delta 18 ZcmZ3)yoh;13%jX;p^=q|@y2d(MgTMq1rq=O delta 18 ZcmZ3)yoh;13%j9$p^25D#l~)NMgTMV1rq=O diff --git a/ihatemoney/translations/el/LC_MESSAGES/messages.po b/ihatemoney/translations/el/LC_MESSAGES/messages.po index 114a117c..337012bb 100644 --- a/ihatemoney/translations/el/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/el/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-25 12:43+0200\n" +"POT-Creation-Date: 2020-04-25 13:02+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Automatically generated\n" "Language: el\n" @@ -508,10 +508,7 @@ msgstr "" msgid "Nothing to list" msgstr "" -msgid "Someone probably" -msgstr "" - -msgid "cleared the project history." +msgid "Someone probably cleared the project history." msgstr "" msgid "Manage your shared
expenses, easily" @@ -732,4 +729,3 @@ msgstr "" msgid "Period" msgstr "" - diff --git a/ihatemoney/translations/es_419/LC_MESSAGES/messages.mo b/ihatemoney/translations/es_419/LC_MESSAGES/messages.mo index ced1f3ad34e7ab0b16f82d9d69d12bcc8b3c91f2..97e55c96113a0c1a561e705f9f86808a0ee03f98 100644 GIT binary patch delta 2605 zcmYM!drZ}39LMo5h+Iyb2so5SD-IkE28wmO5JG}El`h5>%Ry-3AF=5)b0uD4>}NFB z%&~TI;7007YA&0`JVv@{YwBih;TZKtO>yBAo&Ljg)HJ%hKb&XFA+P88U7qKAd4Ak( z`m)Kpnv>FH{5#11$N8T*RkQ#9O=OrAF#Q|nV!qF;80#?!ci?<%!&k5m-@tz`3s*m6 zmWCT~3T{De*>-%`%(D*|=)q4g8xJLJ*a>`$`8k}8mysV!&op}k1E_@~s0GVVu~%R& zR-+QC$5eb9Q*f)Bw_$+&t%E@hH})Y(+7Z-)C(w_lFdZ+T0vg0hyoJj!%tH)qJu0xR zNM`n-n|GrEJB(WACizBb1bS|M085yEflBxiddhT!ffgP`MR*t0iodWP{q!e*Yf-Ig<(Ka7LcO;Sm3c2t zRt~k!Da^yOsONum-bS@%B8&Q~G(q0h0{Q$>DW5_0b`dJlW$t<->ctk+1|3L@wg=Vo z9_KOCnK+9IZ~(RLZ>Z9bq7t%f>Q6A1M|fH=f-2n{)C&txJzs*_s0sBotj7x6gU9ha zDv@nOt3cXO0mM-2?Z;`@i!<>wR^xS#fi?*9mLjXd>9`U@xEY_v7`Ecis6+Q6;TPk_ z7{Pv2Wv-wSxsUTOnfjBgm7@}^#f{j2I$Pd(1|bI5k+p5=qlwIesK|>^0hOULe8E|V zI&7~w*Pwd84wv9txDxwtA*Pb$bGR7w^|T`~dUle5N-}`_*f_rwnV)*;l$W7OS%u1E zIqFn5paN)h_dQg=AE5$?IlEEoe~Mb?9O@6zCCt$GKg2+v&y~pwX8+=75;y5bnCoMt zuM7e+%$~wJ7ES#go{ALHfXPFb~y=80s+hpelR_)#`o>u)hszfH#n8*#jg7 z%O=gmSc>Z12GqiBs0BMw?{%RzI)WjL(jPL{Sec zL|v~zmADRx$r`a1TT#6|g9oe~SGmzyBVJY({DuLCgh2KQA>RmVAk5T4dqXHd9ot3eWm-q|yCl?fm zzaVk=rsFE+m8i_SQJKY^7f_|YjB3dkYQbcp)*qY<Z@TQyJLBAFpXP`q9*qh-iiLdZgXQeF&Mdwz|pBIk>k0!-mpOKyOA9eTi Am;e9( delta 2671 zcmYM!eN5F=9LMp)^Mi1O3rZl#Pl(4T!F1fnK}wAA2a(L;p_#(&4QLuB$=Y=O(y`Xl z=8Ddww7$MR*g0^nbaCmtr|Ddt@np}wiw*kIp=qN=X}ridoCwi zer<85y^%)@KmGh=@|PN=-v2)d@y4v7n~3SS7S~}d=HY$}!xOk3PhuTT;WjK-X3TPY z4rA~&jKFu0DXuwA!^6NC)Wq|cj9=UFX-uPk1B)>#!5Erm9VTG~YTFjT=(%{!D@}Z4mc}sdx5ocl+=GgHnR0ir$?=@T7F`NEg)cbFs z-an4Fg1Pk zDRZcGW^e`0q2`A(Nv0-If7K?B0i~u2wLmQ&N@WYGw(Y1uyX^QO)O&|f8=OYYU`9|i zzi9mdbtmRf0WP4{jbL|O=A>luuM-t9KyaoKwO~Cebxo)jwxepk6SYw<>RZu=J{-aK zaUOM$V??V!PN4!AMXh%UZ^O%&kF&~u1q~0gwLu*!vH)hFiw?epn{X8O;w{vr>n8d< z{1|ibDk?M4H!F#Y6IlS3{I_Oil6WxO}bh+lyLC?xitJwSN^i+!YMc66Uev6HK%B(1lLe0SwMbG7I{)&WvE-;h)QJu zb&}nvTYV4}K)-!HgbMfrR3M|)G1U6wsC8~&1pAvH4J~jJ_4SD+|LPawY#8ao9Qqln zLK&z)ounBHun(DL&ZA2CDek~q7{JG<2iL+}M3v+_)TO?HDeP~4rokTOUsNVma4cDb zWX)6}v6)Bke(XZk@GNTKG1P*SsQ0E&8~uh325~i}^PzDcYW^m4Rm)l$N_jo%cDLIJ zJ*ejg?07FKGkr*`<|x+SC#V{SQ!fS9gxqV>f!tHG&wAK;0#(uvv&g?gW1InPJd3(? zf7^aI4;4T%sx)b++Lfc`SEKI2R%-x@==Y#bcnmdf2n+Bd+y4nm>HqGyp-8jWgf7hn zg+ZlY?P#(ybgBo{Sa zjQRTh*U%_upbPoNn0HYrzJy#{GlO?y7_)s?f`_mZ8*mPpVk#*xdzr^k2YMNm`a#sZ zv#5hb5Vcb8#i!ZdJGWB+D$K0?)pS14Ym%rlEln)Pm)xOVix3z^=Byp2BXYqt)-U1p-ex zt$u&NKfF4A^YWNdr*wUJsc*PF{Y+R!cYrxO{^DG#zti94\n" "Language: es_419\n" @@ -521,10 +521,7 @@ msgstr "" msgid "Nothing to list" msgstr "" -msgid "Someone probably" -msgstr "" - -msgid "cleared the project history." +msgid "Someone probably cleared the project history." msgstr "" msgid "Manage your shared
expenses, easily" @@ -760,4 +757,3 @@ msgstr "" #~ msgid "%(member)s had been added" #~ msgstr "se han añadido %(member)s" - diff --git a/ihatemoney/translations/fr/LC_MESSAGES/messages.mo b/ihatemoney/translations/fr/LC_MESSAGES/messages.mo index f67a9edf2a0efca28266023a0da939c295e0f9cb..21076f19edba29df8566f2cbd7a45838495ab494 100644 GIT binary patch literal 16937 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\n" -"Language-Team: French \n" "Language: fr\n" +"Language-Team: French \n" +"Plural-Forms: nplurals=2; plural=n > 1\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.0.2-dev\n" "Generated-By: Babel 2.8.0\n" msgid "" @@ -393,8 +392,8 @@ msgid "" " The rest of the project history will be unaffected. This " "action cannot be undone." msgstr "" -"Êtes-vous sur de vouloir supprimer toutes les adresses IP enregistrées pour " -"ce projet?\n" +"Êtes-vous sur de vouloir supprimer toutes les adresses IP enregistrées " +"pour ce projet?\n" "Le reste de l'historique ne sera pas affecté. Cette action n'est pas " "réversible." @@ -411,8 +410,8 @@ msgid "" "Are you sure you want to erase all history for this project? This action " "cannot be undone." msgstr "" -"Êtes-vous sur de vouloir supprimer tout l'historique du projet? Cette action " -"n'est pas réversible." +"Êtes-vous sur de vouloir supprimer tout l'historique du projet? Cette " +"action n'est pas réversible." msgid "Added" msgstr "Ajouté" @@ -442,8 +441,8 @@ msgid "" msgstr "" "\n" " L'historique de ce projet a été désactivé. Les nouvelles " -"actions n'apparaîtront pas ci-dessous. Vous pouvez réactiver l'historique du " -"projet dans les \n" +"actions n'apparaîtront pas ci-dessous. Vous pouvez réactiver l'historique" +" du projet dans les \n" " paramètres du projet\n" " " @@ -457,19 +456,19 @@ msgid "" " " msgstr "" "\n" -" Le tableau ci-dessous liste les actions enregistrées avant la " -"désactivation de l'historique du projet. Vous pouvez\n" -" clear project history cliquer ici pour les " -"supprimer.

\n" +" Le tableau ci-dessous liste les actions enregistrées avant" +" la désactivation de l'historique du projet. Vous pouvez\n" +" clear project history cliquer ici pour" +" les supprimer.

\n" " " msgid "" "Some entries below contain IP addresses, even though this project has IP " "recording disabled. " msgstr "" -"Certaines entrées de l'historique contiennent une adresse IP, bien que ce " -"projet ait désactivé l'enregistrement des adresses IP. " +"Certaines entrées de l'historique contiennent une adresse IP, bien que ce" +" projet ait désactivé l'enregistrement des adresses IP. " msgid "Delete stored IP addresses" msgstr "Supprimer toutes les adresses IP enregistrées" @@ -494,13 +493,13 @@ msgstr "Évènement" msgid "IP address recording can be enabled on the settings page" msgstr "" -"L'enregistrement des adresses IP peut-être activé dans les paramètres de la " -"page" +"L'enregistrement des adresses IP peut-être activé dans les paramètres de " +"la page" msgid "IP address recording can be disabled on the settings page" msgstr "" -"L'enregistrement des adresses IP peut-être désactivé dans les paramètres de " -"la page" +"L'enregistrement des adresses IP peut-être désactivé dans les paramètres " +"de la page" msgid "From IP" msgstr "Depuis l'IP" @@ -547,11 +546,8 @@ msgstr "modifié d'une manière inconnue" msgid "Nothing to list" msgstr "Rien à afficher" -msgid "Someone probably" -msgstr "Quelqu'un a probablement" - -msgid "cleared the project history." -msgstr "vidé l'historique du projet." +msgid "Someone probably cleared the project history." +msgstr "Quelqu'un a probablement vidé l'historique du projet." msgid "Manage your shared
expenses, easily" msgstr "Gérez vos dépenses
partagées, facilement" diff --git a/ihatemoney/translations/id/LC_MESSAGES/messages.mo b/ihatemoney/translations/id/LC_MESSAGES/messages.mo index b52a56fcadecc622ab48a40923fd53eddf26e347..ad2962c190b2ac7328d4660fd69710ccecc798b5 100644 GIT binary patch delta 2606 zcmYM#e@vBC9LMo5bp=E(gh6%v!M#c#5ttzsf`GbATm*}Ol&e;oR&G$%L=k4s!Z{27 zXg5dxDgAn6`#e!_!8d66nt@# zSpqiTy|@m!WzCpu=GkT%dhjDm#V`CDb_5@!--~%Tg#23KWV8D)4K;BVYQlU}>_vD# zmZ1`=!FYTN1GwJxTQQCITN{lj+~`1(v;(LIk6;jwVtP3^IK@8zh4Dx;(q@fp&IIo~09>Xx+aMwf3stRNxm+UcTDbAw*3~HV? zQRAC&270dl89qXPA1dJi^pxrEG&J#LRD@%wrT7E6DoixYQ9hLA>50z@g$bvs7FID$YhivE5WH)hY?(hi!q8#cn-DcmJ@z9 zeu!Ck6jhmFR3bNU9^OO!N!Fe~CAth7upYIyygnKc8l%YEHsJw3^AIZXY*aw`s0=Hd zRjAEY>wFot_HW=4Y{WV|j0-THEEnP;)aluT#OT>E8Y)RY@@v=mP-H>srCpwnDrE^O zlc!O;x*iokle_Ps0&YhI5_RrG&A%HpPcQ0=XaFbb{GX+v<1>8sg4rEB9mh@9BaiF9 zkiL%1ZG04SrupA|wYZG_3arLGSc!k50xw}b6v%Q^U{$C+REMhcD%Ae7W*S=ic2tJ@ z+ygy0m;Mi^&3F^pXO=+vT8a?rdKeQh54BW<7{O}PURa9?WTW$4)O$9gr{nQ44MiA3 zP1J?DehBrV6Q~z|i=}uDm3eB0|J)1C)u@TzcDA9$Z+G`QF+zX8>wlj?{k0}%xu8rg zq6S<=lC^87k_FiiTC?e>Kq9E;3oswcQ3*7n#;-$$T8q2hiFz)Enr{GAk&9u^KNf#* zK@*RmmLd@G|C?o?0%<@E{J{AMD$_31u{wsT+!<6tgUErhA>;tqKge#k#F_s0#|+fc zlzTKDrcr^)s1cP(3+gnyhgynG*Wd5%e}j5KA8O5iL-ws*M?Ig+j#gk(QGw?ot7Z#a zzaF&-z1L_c;ucg%wxBX=M^$7uYJ!7EaqJ`(;V}M)>6!lcOQ`4nL>tSAz$$mY4vEQDqULEsJr~79?9lZ*8ZjE0s6TgmQc_NLWl~v6!u-hN1;vH)x}%|8 LaorWu&ZqnbiM01| delta 2671 zcmYM#eN5F=9LMp)Gx97V1`=GJK`4c2pfe2dVNQYOBB<5!(!GI&5~8b?^B2~bt3Plt z$kYUF&74>(bmeFZT4p+Rv9)F7=uTI(g>1H_j&Sw<@H;Jcy{~i5{hf2Z-|sm;{i%N7 z31=cPwAb*bpTBARO$t-*|35KN#$?is#S~nMrMLm}a5o0w2Uvz5VhxVtGguI9OgwgB z1omMF9zh;)%rP2q44gte_$AKAOLlw$7tz0o#TXW23{6vt30R3*xDHv+G@x>5!UfoZ zN^CcV<9is219N?ch-oA-Fo=mbiu3RX)PoZki#IS5Z=nL3!4;Uuk880888SVnzy?r> zeQNt7sKCZh>->l*>~8`z_?Q{Kv~eV}WFji!G|a$kJ6?^dKn-f%lh$U;qQ46@{{U+K zF}xp7*#3Deq<;k+Wqg;0GL5GGS~vj}VH)Zva&a@3qbl_l@-h8<>Gw}i^F~pbU&gu0 zq1L&93vmkdd@v8mqy)}iXOqW(N>hzmU;|$&a9ew@gXcmk~dpWiMC@aI-N9hxu(&BamjAvOHr9uqauF{6;J~z!yVRF zP?v3wbsy^N-@(=RF4p5XF2`kLxe{MM-X6ysr=cUbjw;C=_V*L0fKQ_W8Mcm~)<1_@=O%`*zqw083(TTkpK$80ej%O@qI_6P|8LS) zX$uy+ug_X6qThx*W)9(cd>`xZSKNdTGf4^TMFq4U6<{yMvA;P?gX1(Ok^5u5LiRLc zs7(K`zt7?_`U#}1qp3nYUyC}DEq45QjG*6vIizM?)K3M7<_I zqavI{Ei`S%Z=*H}PIots#7F3-qB3tp%^$E1qSpPwdI2?m-2NU&r~V!WrtCm02d=Y8 zL1mbOnoxoyZ^}`x-{YwNM4m%cpc(c2tM~wR;oKcS%^ya#Fr#)nfO>8+!*Lf}=y6Mu zgL*v*Q423e9mPhhK|d;xAygpWTYo`iI*pqD52|wUnQlUhkQdBkAuocdKwbJehXxo-sVccTLAwZ9)maxh0x>s-KeJ$RKyBu-#4PNEh{D(ab;SCH)A*5uz&*x_mM`aDg3 z|8|ep=kxo9(xX<#N0fL<%2t$A3^k`53`+U$!JYnAZ;Qvbb*Fb*legtX@Ajd4sn_EF E1v|G1i~s-t diff --git a/ihatemoney/translations/id/LC_MESSAGES/messages.po b/ihatemoney/translations/id/LC_MESSAGES/messages.po index 41f8f16f..079048c7 100644 --- a/ihatemoney/translations/id/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/id/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-25 12:43+0200\n" +"POT-Creation-Date: 2020-04-25 13:02+0200\n" "PO-Revision-Date: 2019-11-16 10:04+0000\n" "Last-Translator: Muhammad Fauzi \n" "Language: id\n" @@ -515,10 +515,7 @@ msgstr "" msgid "Nothing to list" msgstr "" -msgid "Someone probably" -msgstr "" - -msgid "cleared the project history." +msgid "Someone probably cleared the project history." msgstr "" msgid "Manage your shared
expenses, easily" @@ -755,3 +752,9 @@ msgstr "" #~ msgid "%(member)s had been added" #~ msgstr "%(member)s telah ditambahkan" +#~ msgid "Someone probably" +#~ msgstr "" + +#~ msgid "cleared the project history." +#~ msgstr "" + diff --git a/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.mo b/ihatemoney/translations/nb_NO/LC_MESSAGES/messages.mo index 1542f52144109dd8e2d32881ae96ba1c96d9aa1b..ae0a3ca3c6731092bf3412cd4032f25d7d8f7696 100644 GIT binary patch delta 2217 zcmYM!e`u9e7{Ku}n$B`_dYwAmZQg4-jjh18Y+G|!ZutXstxfuACfFZZ7o)@oyuGd{ zgGhrk{}?RNG(u_0!hbA-6%v%mEFz(8q(z1}%7XO+UEi-9Xx!b;dCz;^bDrlp=e;Ld zueKyZslvU1zgPKB^S`RltN;JDPY9uk%RJWMd$QGW00|?(d#Uh;Q~zIVq|Ez zA077ymf(6M_K?FFtRJ?~Xr*Hp7UQ>QAU~oRT#45OL}@@Nbb@l6iCJ{wyU_(#L_2Uc z*X!bS9{Gfwd^!FtW&Q9jjXBthPH+~@=m)$RFW{|MKy+qSjb_x0+zLz4fZEU!KZFn9 zX0-I5#QxLh_+j+Tk3*l=dkR%M!u%s7}Il}MACyXO}k`3wT?P!Ke z(16#X89j$29lGNEJ!oJbpyT?`y&galx`ZZl1&e(DM`?Ii#?Xn%xiFw=bYLC2Py=57 zr9&rd!%p0UmhvR}{264ba6bAEx^RkzoNp#pU?pCE{~Kwz;Bqwbb~N%w(bwe#v}CVD z_n>dZ0lW>5q6-Y6^Zbmr;0StnQ=B-**P{WnqVui9#8dk)4NJcX*I*va=&R@;`oIXf z&{eb&g`{D|#YmE2Hu_vWdVd8HLuf}6c?u2idGz;YM+NmavbX8*R31S0_(S9qKI6*= zhS3QwqG#eybmH;6lTMUDw`dVs!4@>IHJHT>ScxyA^X*5^*x@w$@524@#%Xl#zC#}z z!9_Tk{h%3^A!~!X|tj4g8CQhFdU%IUK>c z_!uv(d)I~T+52e5N8`#;ef> zo<#R>7y4emg9g}-Zp~Trto(vz@GrWBQyA=?SE7Mcp@G-L{)OlnYCyMOIZ~mL&`!e) fwqW0(31btB?#wK_qp_~G??~B;1%1ua^Tq!GEAz_> delta 2277 zcmYM!Z%oxy7{KvEB7cM{{(&sH)J1||(2BAGBP#^gq{x}t=A?z*8`8j*GRT(PA{CuF zUSwmorp~sQ>(554nYm=HxzTd9xq87`4quqFF;}lz3##uoe=Bz3bI!Tv_nhZE=lqy$ zI@_GSyeRXXz|SDRaemil+WY_KP)-Q9(>;t8ID*UZTWrHQxgiu_J7(i6I0tv(Jlu`* zaX&h57#HHm&GB?NLt_a86PSlnxB#co0JAt3bLcF_`DmicFbf|;b6y?wTdy!YF@YtRKF#f#2XVoJ0f6pgYVWn-Yv+6;`7=+koz98!|O?qY3RoOFV$< z@CaJ^Yti`c==@w3O&g$yh7T^qA}m7#)JL|UJ8nZOuoa0BdeAd}6HVwqH2xkM?-W|O zPtl`0j}$fhfF>{%qy7e(X225ufu7xBo-#lsT7g=0ULBTVGuB}Tn%D_+fe+9HzCfS5 zfVbgAyc@6LN{mqskNl|u>hHoy29{z!K7mKkyYM4cU@6-!$0yOtw;fIJAU=RckWZN4 z508XN?858l*>9wr3G77^8%EbVmZsqj&P0x*XMZ8`JM@Squ@Nuh1}vrC_1K3EIEpLq z23o-?%HfVzqC0&NO{5xU0%a4aF8G!0mcmbLMnc zVuyY-@wd^PjUq(|(Gj>#Z1-@&(SEx&1m3P(FOORnGd0vA4OlA z(`d!MioArr9ar!kyn!wd=Y|=l49l`~MaV1MWv}?=V{W5p2b?=#J)* zr52;}YtV%rK`YUS?syHd`Ot>W?~T46L~;v5=tfQzQ-3r3i~;}goI^AF9=!`!&@-M! zJ|Tm5&-o>2fC}_Z+>ZusLgPG-Ri^J?L{M(Zt5nG#Y4pjb@(3OX?BC zu^VgfE_@d~yK(dqUPX8OOVrOy-26Y1i|)K2vLqU>#!AL(@mbu2Ph\n" "Language: nb_NO\n" @@ -531,10 +531,7 @@ msgstr "" msgid "Nothing to list" msgstr "" -msgid "Someone probably" -msgstr "" - -msgid "cleared the project history." +msgid "Someone probably cleared the project history." msgstr "" msgid "Manage your shared
expenses, easily" @@ -891,4 +888,3 @@ msgstr "" #~ msgid "%(member)s had been added" #~ msgstr "%(member)s lagt til" - diff --git a/ihatemoney/translations/nl/LC_MESSAGES/messages.mo b/ihatemoney/translations/nl/LC_MESSAGES/messages.mo index 1d0195126501ba90cb054501c6141542fcbd9f45..7ce4bd35292ad8a52381474cf438648a7dabde9a 100644 GIT binary patch delta 2605 zcmYM#e@xVM9LMoDiTpUc5XADLytC^r$v^~D;(!?p!G*N36vv9(sue}$A3>I5-_3F^ zY#_LBt8@!>&01!0VK)D0ddtlX#^MihI=0N5*dI-+O$J8Km-pFX2anJ9*ZcE+zdxVv z(cdz*)tkyq{mA$^%pW}1*I9@_Nma)ieG3KEHM^FI^QMs4n z60AlQ)QoBPCZ=MSJKlwP%x}9Hx-pJ^JdGK69+l8IR^WB4!!S27w02Zt zT}WlN*BuX{68jt#=PL~02>O}d#u;ehDd%-m#Jd3*j7v~Ms(#&Pkf3+sS(+Uvek6KxbTH7jArgiT8Hq?VJp(fakeVRgn3Gt#qa^#f+5_2PhvlI;sk2bZ6f_B z_F)7^P@TDqDr5#r@gDk5v9=CXXgzjd3uQQ3LBhF zsLl3_vkkTOuV4+nj$7~~K7naeS&17^Z%;Rpqi5eUP)kOUkNv|RW#*?}+U13)R>n}3 zY((wq7E}VA?z)FcxCfO;zjF{3{}WW4bEq$(G0fEa|1$%PqUUet3RqUIYwPZJ(zpc{X1 zHzZKI{{kxTBvQOx!3Mm8TX7?^u<`8>D$duaz(1l2m_)sPf1)PN#4?PdmS`H)kr~{B zKE4c?!uDf?`RzLf3UCRv6n|qnrW0LzAsbV%2sJ?|sza5iN}EyFpGR`E7g65_Jy?Uk zV+>aom_4oQsORGtWq!NBK%46(YO^eOEV)_2s5LD?t<@$}LT#vtyHR_i$2sU6!VJ!z zK>ZImg}VO_OvBr#Lg&#>a+bR)c_MZo(^oLu=&Q<3UmIFeQc+eqyg$&JGQ2*&b@6{? Cuky

9(F`Uj(&tv`@uYXe!X-XHI2vCDm(bAIRHd%oxV;Pkeh z8gDW&>VWan$8Q?HNefi_|7UTmStivuOu+&y#!Ae=eHejdQ z#MQ@8flZ+1`3X~4-=-+=v3b6b>?3= ze@5MjX;gr-sCgqoF(l{65Xtw&8*jY{49r~wb7&U_bYp%+kZMK7+#WB4h~ zpf=J^v!NwTk#y;hK1~M9X^V@J)R9x&=LHKO35tpu?+I0z)DfKyatuZ5Nan+ zqHc8uDu6!s{4gru&rpGkI>%7+e~p^wB1W>l%~8+_u?_q2WA}XXjp1<*qULKx1=@~WE8C9+tZyGu zD5T*>R7Ae)u$idWZ7u3A+}!z^?U#|-yrJm!8n#< zZXTP$$FQ39ZIFT{m_>rLxRv3{Rf4)KccCsz1L{m$QAhO(DxiMU!egkrG44F;ynr#Z zUqbyam`C-$nO9(WG=;Skw9|4VNZab_?Y);5<|T(7uM6$TYY8;f)(7fBp(g^h_4T3p r;q=&zOMFFvqLMX5tA`s>UX57#U&oy-fxWv!jiENa>WBYG-QoWitjY!B diff --git a/ihatemoney/translations/nl/LC_MESSAGES/messages.po b/ihatemoney/translations/nl/LC_MESSAGES/messages.po index ed063bce..63cec532 100644 --- a/ihatemoney/translations/nl/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/nl/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-04-25 12:43+0200\n" +"POT-Creation-Date: 2020-04-25 13:02+0200\n" "PO-Revision-Date: 2019-10-07 22:56+0000\n" "Last-Translator: Heimen Stoffels \n" "Language: nl\n" @@ -515,10 +515,7 @@ msgstr "" msgid "Nothing to list" msgstr "" -msgid "Someone probably" -msgstr "" - -msgid "cleared the project history." +msgid "Someone probably cleared the project history." msgstr "" msgid "Manage your shared
expenses, easily" @@ -749,4 +746,3 @@ msgstr "" msgid "Period" msgstr "" - diff --git a/ihatemoney/translations/tr/LC_MESSAGES/messages.mo b/ihatemoney/translations/tr/LC_MESSAGES/messages.mo index eb572330deeacc5caf52a29e18619aa88b2ec4fb..b8383048bb2008790ff2d91095ce637d0b0f8530 100644 GIT binary patch delta 20 bcmdnPyN7o}8#BA9f}xR>iSg!MW_@M=LqY|i delta 20 bcmdnPyN7o}8#BA1f}x3(p~dE2W_@M=LoEfN diff --git a/ihatemoney/translations/tr/LC_MESSAGES/messages.po b/ihatemoney/translations/tr/LC_MESSAGES/messages.po index 69464b82..7e2d6a36 100644 --- a/ihatemoney/translations/tr/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/tr/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-25 12:43+0200\n" +"POT-Creation-Date: 2020-04-25 13:02+0200\n" "PO-Revision-Date: 2019-08-07 13:24+0000\n" "Last-Translator: Mesut Akcan \n" "Language: tr\n" @@ -513,10 +513,7 @@ msgstr "" msgid "Nothing to list" msgstr "" -msgid "Someone probably" -msgstr "" - -msgid "cleared the project history." +msgid "Someone probably cleared the project history." msgstr "" msgid "Manage your shared
expenses, easily" @@ -737,4 +734,3 @@ msgstr "" msgid "Period" msgstr "" - diff --git a/ihatemoney/translations/uk/LC_MESSAGES/messages.mo b/ihatemoney/translations/uk/LC_MESSAGES/messages.mo index 0bcb78748bde08a7f13fd06cf0aeb413fcc78c5e..699828d953c271ba0326025f6f7261408546cda3 100644 GIT binary patch delta 20 ccmeyu^Mz-_A|`fI1w$h%6XVS*nNBkU08Xg};Q#;t delta 20 ccmeyu^Mz-_A|`f21w#`nLyOHTnNBkU08W$!;Q#;t diff --git a/ihatemoney/translations/uk/LC_MESSAGES/messages.po b/ihatemoney/translations/uk/LC_MESSAGES/messages.po index ed96cbd4..3fa6e99d 100644 --- a/ihatemoney/translations/uk/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/uk/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-25 12:43+0200\n" +"POT-Creation-Date: 2020-04-25 13:02+0200\n" "PO-Revision-Date: 2019-12-08 16:26+0000\n" "Last-Translator: Tymofij Lytvynenko \n" "Language: uk\n" @@ -510,10 +510,7 @@ msgstr "" msgid "Nothing to list" msgstr "" -msgid "Someone probably" -msgstr "" - -msgid "cleared the project history." +msgid "Someone probably cleared the project history." msgstr "" msgid "Manage your shared
expenses, easily" @@ -734,4 +731,3 @@ msgstr "" msgid "Period" msgstr "" - diff --git a/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.mo b/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.mo index 380fa1589b6889626f3e0780384b91379fe7bfc1..89f8f30246872146054a7a16b6d94e94112f5b3d 100644 GIT binary patch delta 20 bcmaDS@J?XEdlq(61w$h%6XVU_SSpwSQ-}vB delta 20 bcmaDS@J?XEdlq&>1w#`nLyOJdSSpwSQ*#F> diff --git a/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po b/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po index 565ffc0c..ba1d920d 100644 --- a/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/zh_HANS-CN/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-04-25 12:43+0200\n" +"POT-Creation-Date: 2020-04-25 13:02+0200\n" "PO-Revision-Date: 2020-02-09 12:01+0000\n" "Last-Translator: Muge Niu \n" "Language: zh_HANS_CN\n" @@ -510,10 +510,7 @@ msgstr "" msgid "Nothing to list" msgstr "" -msgid "Someone probably" -msgstr "" - -msgid "cleared the project history." +msgid "Someone probably cleared the project history." msgstr "" msgid "Manage your shared
expenses, easily" @@ -734,4 +731,3 @@ msgstr "" msgid "Period" msgstr "" - From ab3240ed349f6abfba72813bce4e968692a3df92 Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Sat, 25 Apr 2020 13:15:02 +0200 Subject: [PATCH 31/47] Translated using Weblate (French) (#582) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 100.0% (222 of 222 strings) Translation: I Hate Money/I Hate Money Translate-URL: https://hosted.weblate.org/projects/i-hate-money/i-hate-money/fr/ Co-authored-by: Rémy Hubscher --- .../translations/fr/LC_MESSAGES/messages.po | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/ihatemoney/translations/fr/LC_MESSAGES/messages.po b/ihatemoney/translations/fr/LC_MESSAGES/messages.po index 6cd336a7..56f19c9b 100644 --- a/ihatemoney/translations/fr/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/fr/LC_MESSAGES/messages.po @@ -8,15 +8,16 @@ msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2020-04-25 13:02+0200\n" -"PO-Revision-Date: 2020-04-25 11:01+0000\n" +"PO-Revision-Date: 2020-04-25 11:14+0000\n" "Last-Translator: Rémy Hubscher \n" +"Language-Team: French \n" "Language: fr\n" -"Language-Team: French \n" -"Plural-Forms: nplurals=2; plural=n > 1\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.0.2-dev\n" "Generated-By: Babel 2.8.0\n" msgid "" @@ -354,7 +355,7 @@ msgid "Download" msgstr "Télécharger" msgid "Disabled Project History" -msgstr "Désactiver l'historique du projet." +msgstr "Désactiver l'historique du projet" msgid "Disabled Project History & IP Address Recording" msgstr "Désactiver l'historique du projet et l'enregistrement des adresses IP" @@ -392,8 +393,8 @@ msgid "" " The rest of the project history will be unaffected. This " "action cannot be undone." msgstr "" -"Êtes-vous sur de vouloir supprimer toutes les adresses IP enregistrées " -"pour ce projet?\n" +"Êtes-vous sur de vouloir supprimer toutes les adresses IP enregistrées pour " +"ce projet ?\n" "Le reste de l'historique ne sera pas affecté. Cette action n'est pas " "réversible." @@ -410,7 +411,7 @@ msgid "" "Are you sure you want to erase all history for this project? This action " "cannot be undone." msgstr "" -"Êtes-vous sur de vouloir supprimer tout l'historique du projet? Cette " +"Êtes-vous sur de vouloir supprimer tout l'historique du projet ? Cette " "action n'est pas réversible." msgid "Added" @@ -599,7 +600,7 @@ msgid "Statistics" msgstr "Statistiques" msgid "History" -msgstr "" +msgstr "Historique" msgid "Settings" msgstr "Options" @@ -659,10 +660,10 @@ msgid "Add a new bill" msgstr "Nouvelle facture" msgid "Newer bills" -msgstr "" +msgstr "Nouvelles factures" msgid "Older bills" -msgstr "" +msgstr "Ancienne factures" msgid "When?" msgstr "Quand ?" @@ -771,10 +772,10 @@ msgid "Spent" msgstr "A dépensé" msgid "Expenses by Month" -msgstr "" +msgstr "Dépenses par mois" msgid "Period" -msgstr "" +msgstr "Période" #~ msgid "" #~ "The project identifier is used to " From 27cac869d3131d09c7e0ca73e110288a7db324ac Mon Sep 17 00:00:00 2001 From: zorun Date: Sat, 25 Apr 2020 14:03:40 +0200 Subject: [PATCH 32/47] Fix missing HTML tag (#583) --- ihatemoney/templates/404.html | 1 + 1 file changed, 1 insertion(+) diff --git a/ihatemoney/templates/404.html b/ihatemoney/templates/404.html index 7e282c2e..353f0be1 100644 --- a/ihatemoney/templates/404.html +++ b/ihatemoney/templates/404.html @@ -10,4 +10,5 @@

+ {% endblock %} From 2c32c6190c391b165000584b9d15c668000d1dcc Mon Sep 17 00:00:00 2001 From: Andrew Dickinson Date: Sun, 26 Apr 2020 08:20:24 -0400 Subject: [PATCH 33/47] Direct Alembic to ignore the sqlite_sequence table (#586) * Direct Alembic to ignore the sqlite_sequence table * Direct Alembic to ignore the sqlite_sequence table * Fix "Skipping unsupported ALTER" warning on database migration --- ihatemoney/migrations/env.py | 9 ++++- .../versions/2dcb0c0048dc_autologger.py | 38 ++++++++++++++----- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/ihatemoney/migrations/env.py b/ihatemoney/migrations/env.py index 4d4729c5..0bd0031e 100755 --- a/ihatemoney/migrations/env.py +++ b/ihatemoney/migrations/env.py @@ -41,7 +41,7 @@ def run_migrations_offline(): """ url = config.get_main_option("sqlalchemy.url") - context.configure(url=url) + context.configure(url=url, include_object=include_object) with context.begin_transaction(): context.run_migrations() @@ -75,6 +75,7 @@ def run_migrations_online(): context.configure( connection=connection, target_metadata=target_metadata, + include_object=include_object, process_revision_directives=process_revision_directives, **current_app.extensions["migrate"].configure_args ) @@ -86,6 +87,12 @@ def run_migrations_online(): connection.close() +def include_object(object, name, type_, reflected, compare_to): + if name == "sqlite_sequence": + return False + return True + + if context.is_offline_mode(): run_migrations_offline() else: diff --git a/ihatemoney/migrations/versions/2dcb0c0048dc_autologger.py b/ihatemoney/migrations/versions/2dcb0c0048dc_autologger.py index 08008355..b0b4f44c 100644 --- a/ihatemoney/migrations/versions/2dcb0c0048dc_autologger.py +++ b/ihatemoney/migrations/versions/2dcb0c0048dc_autologger.py @@ -165,21 +165,39 @@ def upgrade(): sa.Column("remote_addr", sa.String(length=50), nullable=True), sa.PrimaryKeyConstraint("id"), ) - op.add_column( - "project", - sa.Column( - "logging_preference", - sa.Enum("DISABLED", "ENABLED", "RECORD_IP", name="loggingmode"), - server_default="ENABLED", - nullable=False, - ), - ) + bind = op.get_bind() + if bind.engine.name == "sqlite": + with op.batch_alter_table("project", recreate="always") as batch_op: + batch_op.add_column( + sa.Column( + "logging_preference", + sa.Enum("DISABLED", "ENABLED", "RECORD_IP", name="loggingmode"), + server_default="ENABLED", + nullable=False, + ), + ) + else: + op.add_column( + "project", + sa.Column( + "logging_preference", + sa.Enum("DISABLED", "ENABLED", "RECORD_IP", name="loggingmode"), + server_default="ENABLED", + nullable=False, + ), + ) # ### end Alembic commands ### def downgrade(): # ### commands auto generated by Alembic - please adjust! ### - op.drop_column("project", "logging_preference") + + bind = op.get_bind() + if bind.engine.name == "sqlite": + with op.batch_alter_table("project", recreate="always") as batch_op: + batch_op.drop_column("logging_preference") + else: + op.drop_column("project", "logging_preference") op.drop_table("transaction") op.drop_index( op.f("ix_project_version_transaction_id"), table_name="project_version" From 55419ab94ba7fee1f3f80d864f86016a9642da31 Mon Sep 17 00:00:00 2001 From: Andrew Dickinson Date: Sun, 26 Apr 2020 08:22:21 -0400 Subject: [PATCH 34/47] Add .idea/ folder to gitignore (#585) --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 927a8d64..d8d18940 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ build .env .pytest_cache ihatemoney/budget.db +.idea/ From d9dc38947c88f211f7deef2454f3a15251ed23d3 Mon Sep 17 00:00:00 2001 From: zorun Date: Sun, 26 Apr 2020 14:22:54 +0200 Subject: [PATCH 35/47] Fix string representation of bills (#584) Currently the string representation of a Bill is: " for " It is used in the History Page to describe changes that were applied to Bills, for instance: Bill "42.0 for Test" renamed to "Another Test" This is inconsistent, not easy to read, and the "for" in the middle is not translatable. To solve this issue, simply switch the string representation of a bill to its description. Co-authored-by: Baptiste Jonglez --- ihatemoney/models.py | 2 +- ihatemoney/tests/tests.py | 36 +++++++++++++----------------------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/ihatemoney/models.py b/ihatemoney/models.py index dca86110..742bc8ca 100644 --- a/ihatemoney/models.py +++ b/ihatemoney/models.py @@ -460,7 +460,7 @@ class Bill(db.Model): return 0 def __str__(self): - return f"{self.amount} for {self.what}" + return self.what def __repr__(self): return ( diff --git a/ihatemoney/tests/tests.py b/ihatemoney/tests/tests.py index b50fae6c..62cb0485 100644 --- a/ihatemoney/tests/tests.py +++ b/ihatemoney/tests/tests.py @@ -2598,7 +2598,7 @@ class HistoryTestCase(IhatemoneyTestCase): resp = self.client.get("/demo/history") self.assertEqual(resp.status_code, 200) self.assertIn( - f"Bill {em_surround('25.0 for fromage à raclette')} added", + f"Bill {em_surround('fromage à raclette')} added", resp.data.decode("utf-8"), ) @@ -2619,26 +2619,26 @@ class HistoryTestCase(IhatemoneyTestCase): resp = self.client.get("/demo/history") self.assertEqual(resp.status_code, 200) self.assertIn( - f"Bill {em_surround('25.0 for fromage à raclette')} added", + 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("25.0 for fromage à raclette", regex_escape=True), + 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("25.0 for fromage à raclette"), em_surround("new thing"),), + % (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('25.0 for fromage à raclette')} renamed to" + f"Bill {em_surround('fromage à raclette')} renamed to" ), resp.data.decode("utf-8").index("Amount changed"), ) @@ -2650,8 +2650,7 @@ class HistoryTestCase(IhatemoneyTestCase): resp = self.client.get("/demo/history") self.assertEqual(resp.status_code, 200) self.assertIn( - f"Bill {em_surround('10.0 for new thing')} removed", - resp.data.decode("utf-8"), + f"Bill {em_surround('new thing')} removed", resp.data.decode("utf-8"), ) # edit user @@ -2746,7 +2745,7 @@ class HistoryTestCase(IhatemoneyTestCase): self.assertRegex( resp.data.decode("utf-8"), r"Bill {}:\s* Amount changed\s* from {}\s* to {}".format( - em_surround("25.0 for Bill 1", regex_escape=True), + em_surround("Bill 1", regex_escape=True), em_surround("25.0", regex_escape=True), em_surround("88.0", regex_escape=True), ), @@ -2789,11 +2788,9 @@ class HistoryTestCase(IhatemoneyTestCase): self.assertEqual(resp.status_code, 200) self.assertEqual(resp.data.decode("utf-8").count(" -- "), 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('25.0 for Bill 1')} added", resp.data.decode("utf-8") - ) - self.assertIn( - f"Bill {em_surround('25.0 for Bill 1')} removed", resp.data.decode("utf-8"), + f"Bill {em_surround('Bill 1')} removed", resp.data.decode("utf-8"), ) # Add a new bill @@ -2812,20 +2809,13 @@ class HistoryTestCase(IhatemoneyTestCase): self.assertEqual(resp.status_code, 200) self.assertEqual(resp.data.decode("utf-8").count(" -- "), 6) self.assertNotIn("127.0.0.1", resp.data.decode("utf-8")) - self.assertIn( - f"Bill {em_surround('25.0 for Bill 1')} added", 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('25.0 for Bill 1')} added" - ), - 1, + 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('20.0 for Bill 2')} added", resp.data.decode("utf-8") - ) - self.assertIn( - f"Bill {em_surround('25.0 for Bill 1')} removed", resp.data.decode("utf-8"), + f"Bill {em_surround('Bill 1')} removed", resp.data.decode("utf-8"), ) def test_double_bill_double_person_edit_second_no_web(self): From 342292ca9f080d2600edf07f28d1798ebe814559 Mon Sep 17 00:00:00 2001 From: zorun Date: Sun, 26 Apr 2020 22:48:30 +0200 Subject: [PATCH 36/47] Fix language code parsing (#589) --- ihatemoney/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ihatemoney/utils.py b/ihatemoney/utils.py index d8c887bb..c8daa567 100644 --- a/ihatemoney/utils.py +++ b/ihatemoney/utils.py @@ -97,7 +97,7 @@ def static_include(filename): def locale_from_iso(iso_code): - return Locale(iso_code) + return Locale.parse(iso_code) def list_of_dicts2json(dict_to_convert): From 08bb95422bd43ce729992673b27117088f5454d9 Mon Sep 17 00:00:00 2001 From: zorun Date: Sun, 26 Apr 2020 23:12:33 +0200 Subject: [PATCH 37/47] Fix crash when a localized email template is missing (#592) --- ihatemoney/utils.py | 17 ++++++++++++++++- ihatemoney/web.py | 16 +++++++--------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/ihatemoney/utils.py b/ihatemoney/utils.py index c8daa567..7fdad61a 100644 --- a/ihatemoney/utils.py +++ b/ihatemoney/utils.py @@ -9,7 +9,8 @@ import os import re from babel import Locale -from flask import current_app, redirect +from flask import current_app, redirect, render_template +from flask_babel import get_locale import jinja2 from werkzeug.routing import HTTPException, RoutingException @@ -278,3 +279,17 @@ class FormEnum(Enum): def __str__(self): return str(self.value) + + +def render_localized_template(template_name_prefix, **context): + """Like render_template(), but selects the right template according to the + current user language. Fallback to English if a template for the + current language does not exist. + """ + fallback = "en" + templates = [ + f"{template_name_prefix}.{lang}.j2" + for lang in (get_locale().language, fallback) + ] + # render_template() supports a list of templates to try in order + return render_template(templates, **context) diff --git a/ihatemoney/web.py b/ihatemoney/web.py index d799420b..b5998c68 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -30,7 +30,7 @@ from flask import ( session, url_for, ) -from flask_babel import get_locale, gettext as _ +from flask_babel import gettext as _ from flask_mail import Message from sqlalchemy import orm from sqlalchemy_continuum import Operation @@ -57,6 +57,7 @@ from ihatemoney.utils import ( get_members, list_of_dicts2csv, list_of_dicts2json, + render_localized_template, same_bill, ) @@ -301,7 +302,7 @@ def create_project(): project=g.project.name, ) - message_body = render_template(f"reminder_mail.{get_locale().language}.j2") + message_body = render_localized_template("reminder_mail") msg = Message( message_title, body=message_body, recipients=[project.contact_email] @@ -335,11 +336,12 @@ def remind_password(): # get the project project = Project.query.get(form.id.data) # send a link to reset the password - password_reminder = f"password_reminder.{get_locale().language}.j2" current_app.mail.send( Message( "password recovery", - body=render_template(password_reminder, project=project), + body=render_localized_template( + "password_reminder", project=project + ), recipients=[project.contact_email], ) ) @@ -566,11 +568,7 @@ def invite(): if request.method == "POST": if form.validate(): # send the email - - message_body = render_template( - f"invitation_mail.{get_locale().language}.j2" - ) - + message_body = render_localized_template("invitation_mail") message_title = _( "You have been invited to share your " "expenses for %(project)s", project=g.project.name, From c509896b8c0fa46cd845dc87fa42a8fca8bb7f5b Mon Sep 17 00:00:00 2001 From: zorun Date: Sun, 26 Apr 2020 23:17:48 +0200 Subject: [PATCH 38/47] Add support for different categories of "flash alerts" (#594) --- ihatemoney/templates/layout.html | 10 +++++++--- ihatemoney/web.py | 15 +++------------ 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/ihatemoney/templates/layout.html b/ihatemoney/templates/layout.html index eaf13a6e..35d27976 100644 --- a/ihatemoney/templates/layout.html +++ b/ihatemoney/templates/layout.html @@ -125,9 +125,13 @@
- {% for message in get_flashed_messages() %} -
{{ message }}
- {% endfor %} + {% for category, message in get_flashed_messages(with_categories=true) %} + {% if category == "message" %}{# Default category for flash(msg) #} +
{{ message }}
+ {% else %} +
{{ message }}
+ {% endif %} + {% endfor %}
{% block footer %} diff --git a/ihatemoney/web.py b/ihatemoney/web.py index b5998c68..18ce0c7a 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -310,19 +310,10 @@ def create_project(): try: current_app.mail.send(msg) except SMTPRecipientsRefused: - msg_compl = "Problem sending mail. " - # TODO: destroy the project and cancel instead? - else: - msg_compl = "" + flash(_("Error while sending reminder email"), category="danger") # redirect the user to the next step (invite) - flash( - _( - "%(msg_compl)sThe project identifier is %(project)s", - msg_compl=msg_compl, - project=project.id, - ) - ) + flash(_("The project identifier is %(project)s", project=project.id)) return redirect(url_for(".list_bills", project_id=project.id)) return render_template("create_project.html", form=form) @@ -395,7 +386,7 @@ def edit_project(): return redirect(url_for("main.list_bills")) except ValueError: - flash(_("Invalid JSON"), category="error") + flash(_("Invalid JSON"), category="danger") # Edit form if edit_form.validate_on_submit(): From 68f6df6abc907f8e48a2dc9883e0166630eb0810 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2020 08:42:10 +0200 Subject: [PATCH 39/47] Bump sphinx from 3.0.2 to 3.0.3 (#596) Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.0.2 to 3.0.3. - [Release notes](https://github.com/sphinx-doc/sphinx/releases) - [Changelog](https://github.com/sphinx-doc/sphinx/blob/3.x/CHANGES) - [Commits](https://github.com/sphinx-doc/sphinx/compare/v3.0.2...v3.0.3) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 3cfd193c..67e98eb8 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,2 +1,2 @@ -Sphinx==3.0.2 +Sphinx==3.0.3 docutils==0.16 From 8b8606d2f0e8031480a277b7953b6827d5ba1e26 Mon Sep 17 00:00:00 2001 From: Vsevolod Date: Sun, 26 Apr 2020 17:51:02 +0000 Subject: [PATCH 40/47] Added translation using Weblate (Russian) --- .../translations/ru/LC_MESSAGES/messages.po | 729 ++++++++++++++++++ 1 file changed, 729 insertions(+) create mode 100644 ihatemoney/translations/ru/LC_MESSAGES/messages.po diff --git a/ihatemoney/translations/ru/LC_MESSAGES/messages.po b/ihatemoney/translations/ru/LC_MESSAGES/messages.po new file mode 100644 index 00000000..96f3b80d --- /dev/null +++ b/ihatemoney/translations/ru/LC_MESSAGES/messages.po @@ -0,0 +1,729 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-04-26 19:50+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Translate Toolkit 2.5.0\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 "" + +msgid "Enable project history" +msgstr "" + +msgid "Use IP tracking for project history" +msgstr "" + +msgid "Import previously exported JSON file" +msgstr "" + +msgid "Import" +msgstr "" + +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 "" + +msgid "Send me the code by email" +msgstr "" + +msgid "This project does not exists" +msgstr "" + +msgid "Password mismatch" +msgstr "" + +msgid "Password" +msgstr "" + +msgid "Password confirmation" +msgstr "" + +msgid "Reset password" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "What?" +msgstr "" + +msgid "Payer" +msgstr "" + +msgid "Amount paid" +msgstr "" + +msgid "External link" +msgstr "" + +msgid "A link to an external document, related to this bill" +msgstr "" + +msgid "For whom?" +msgstr "" + +msgid "Submit" +msgstr "" + +msgid "Submit and add a new one" +msgstr "" + +msgid "Bills can't be null" +msgstr "" + +msgid "Name" +msgstr "" + +msgid "Weights should be positive" +msgstr "" + +msgid "Weight" +msgstr "" + +msgid "Add" +msgstr "" + +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 "" + +msgid "Participant" +msgstr "" + +msgid "Bill" +msgstr "" + +msgid "Project" +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 "" + +#, python-format +msgid "%(msg_compl)sThe project identifier is %(project)s" +msgstr "" + +msgid "No token provided" +msgstr "" + +msgid "Invalid token" +msgstr "" + +msgid "Unknown project" +msgstr "" + +msgid "Password successfully reset." +msgstr "" + +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 "" + +#, 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 "" + +#, python-format +msgid "User '%(name)s' has been edited" +msgstr "" + +msgid "The bill has been added" +msgstr "" + +msgid "The bill has been deleted" +msgstr "" + +msgid "The bill has been modified" +msgstr "" + +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 "" + +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 "" + +msgid "Number of bills" +msgstr "" + +msgid "Newest bill" +msgstr "" + +msgid "Oldest bill" +msgstr "" + +msgid "Actions" +msgstr "" + +msgid "edit" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "see" +msgstr "" + +msgid "The Dashboard is currently deactivated." +msgstr "" + +msgid "you sure?" +msgstr "" + +msgid "Edit project" +msgstr "" + +msgid "Import JSON" +msgstr "" + +msgid "Choose file" +msgstr "" + +msgid "Download project's data" +msgstr "" + +msgid "Bill items" +msgstr "" + +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 "" + +msgid "Privacy Settings" +msgstr "" + +msgid "Edit the project" +msgstr "" + +msgid "Edit this bill" +msgstr "" + +msgid "Add a bill" +msgstr "" + +msgid "Select all" +msgstr "" + +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 "" + +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 "" + +msgid "Removed" +msgstr "" + +msgid "and" +msgstr "" + +msgid "owers list" +msgstr "" + +msgid "Who?" +msgstr "" + +msgid "Balance" +msgstr "" + +#, python-format +msgid "" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " +msgstr "" + +msgid "" +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\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 "" + +msgid "Event" +msgstr "" + +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 "" + +msgid "modified" +msgstr "" + +msgid "removed" +msgstr "" + +msgid "changed in a unknown way" +msgstr "" + +msgid "Nothing to list" +msgstr "" + +msgid "Someone probably cleared the project history." +msgstr "" + +msgid "Manage your shared
expenses, easily" +msgstr "" + +msgid "Try out the demo" +msgstr "" + +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 "" +"This access code will be sent to your friends. It is stored as-is by the " +"server, so don\\'t reuse a personal password!" +msgstr "" + +msgid "Account manager" +msgstr "" + +msgid "Bills" +msgstr "" + +msgid "Settle" +msgstr "" + +msgid "Statistics" +msgstr "" + +msgid "History" +msgstr "" + +msgid "Settings" +msgstr "" + +msgid "Languages" +msgstr "" + +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 "" + +msgid "Mobile Application" +msgstr "" + +msgid "Documentation" +msgstr "" + +msgid "Administation Dashboard" +msgstr "" + +msgid "\"I hate money\" is a free software" +msgstr "" + +msgid "you can contribute and improve it!" +msgstr "" + +msgid "deactivate" +msgstr "" + +msgid "reactivate" +msgstr "" + +msgid "Invite people" +msgstr "" + +msgid "You should start by adding participants" +msgstr "" + +msgid "Add a new bill" +msgstr "" + +msgid "Newer bills" +msgstr "" + +msgid "Older bills" +msgstr "" + +msgid "When?" +msgstr "" + +msgid "Who paid?" +msgstr "" + +msgid "For what?" +msgstr "" + +msgid "How much?" +msgstr "" + +#, python-format +msgid "Added on %(date)s" +msgstr "" + +msgid "Everyone" +msgstr "" + +#, python-format +msgid "Everyone but %(excluded)s" +msgstr "" + +msgid "each" +msgstr "" + +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 "" + +msgid "Your projects" +msgstr "" + +msgid "Reset your password" +msgstr "" + +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 "" + +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 "" + +msgid "To whom?" +msgstr "" + +msgid "Paid" +msgstr "" + +msgid "Spent" +msgstr "" + +msgid "Expenses by Month" +msgstr "" + +msgid "Period" +msgstr "" From d8a9fc2e85f42c890741da35a64a85277f4cedb9 Mon Sep 17 00:00:00 2001 From: Vsevolod Date: Sun, 26 Apr 2020 17:52:34 +0000 Subject: [PATCH 41/47] Translated using Weblate (Russian) Currently translated at 21.1% (47 of 222 strings) Translation: I Hate Money/I Hate Money Translate-URL: https://hosted.weblate.org/projects/i-hate-money/i-hate-money/ru/ --- .../translations/ru/LC_MESSAGES/messages.po | 103 ++++++++++-------- 1 file changed, 55 insertions(+), 48 deletions(-) diff --git a/ihatemoney/translations/ru/LC_MESSAGES/messages.po b/ihatemoney/translations/ru/LC_MESSAGES/messages.po index 96f3b80d..2330bc32 100644 --- a/ihatemoney/translations/ru/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/ru/LC_MESSAGES/messages.po @@ -3,170 +3,177 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-04-26 19:50+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" +"PO-Revision-Date: 2020-04-26 20:48+0000\n" +"Last-Translator: Vsevolod \n" +"Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Translate Toolkit 2.5.0\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.0.2-dev\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " "accepted." msgstr "" +"Недопустимая сумма выражения. Принимаются только цифры и операторы + - * / ." msgid "Project name" -msgstr "" +msgstr "Имя проекта" msgid "Private code" -msgstr "" +msgstr "Приватный код" msgid "Email" -msgstr "" +msgstr "Email" msgid "Enable project history" -msgstr "" +msgstr "Включить историю проекта" msgid "Use IP tracking for project history" -msgstr "" +msgstr "Использовать отслеживание по IP для истории проекта" msgid "Import previously exported JSON file" -msgstr "" +msgstr "Импортировать ранее экспортированный JSON файл" msgid "Import" -msgstr "" +msgstr "Импортировать" msgid "Project identifier" -msgstr "" +msgstr "Идентификатор проекта" msgid "Create the project" -msgstr "" +msgstr "Создать проект" #, python-format msgid "" "A project with this identifier (\"%(project)s\") already exists. Please " "choose a new identifier" msgstr "" +"Проект с идентификатором (\"%(project)s\") уже существует. Пожалуйста, " +"выберете новый идентификатор" msgid "Get in" -msgstr "" +msgstr "Войти" msgid "Admin password" -msgstr "" +msgstr "Пароль администратора" msgid "Send me the code by email" -msgstr "" +msgstr "Отправить код мне на Email" msgid "This project does not exists" -msgstr "" +msgstr "Такой проект не существует" msgid "Password mismatch" -msgstr "" +msgstr "Пароли не совпадают" msgid "Password" -msgstr "" +msgstr "Пароль" msgid "Password confirmation" -msgstr "" +msgstr "Подтвердите пароль" msgid "Reset password" -msgstr "" +msgstr "Восстановить пароль" msgid "Date" -msgstr "" +msgstr "Дата" msgid "What?" -msgstr "" +msgstr "Что?" msgid "Payer" -msgstr "" +msgstr "Плательщик" msgid "Amount paid" -msgstr "" +msgstr "Уплаченная сумма" msgid "External link" -msgstr "" +msgstr "Внешняя ссылка" msgid "A link to an external document, related to this bill" -msgstr "" +msgstr "Ссылка на внешний документ, относящийся к этому счёту" msgid "For whom?" -msgstr "" +msgstr "Кому?" msgid "Submit" -msgstr "" +msgstr "Отправить" msgid "Submit and add a new one" -msgstr "" +msgstr "Отправить и добавить новый" msgid "Bills can't be null" -msgstr "" +msgstr "Счета не могут быть нулевыми" msgid "Name" -msgstr "" +msgstr "Имя" msgid "Weights should be positive" -msgstr "" +msgstr "Вес должен быть положительным" msgid "Weight" -msgstr "" +msgstr "Вес" msgid "Add" -msgstr "" +msgstr "Добавить" msgid "User name incorrect" -msgstr "" +msgstr "Неправильное имя пользователя" msgid "This project already have this member" -msgstr "" +msgstr "В этом проекте уже есть такой участник" msgid "People to notify" msgstr "" msgid "Send invites" -msgstr "" +msgstr "Отправить приглашения" #, python-format msgid "The email %(email)s is not valid" -msgstr "" +msgstr "Email %(email)s не правильный" msgid "Participant" -msgstr "" +msgstr "Участник" msgid "Bill" -msgstr "" +msgstr "Счёт" msgid "Project" -msgstr "" +msgstr "Проект" msgid "Too many failed login attempts, please retry later." -msgstr "" +msgstr "Слишком много неудачных попыток входа, попробуйте позже." #, python-format msgid "This admin password is not the right one. Only %(num)d attempts left." msgstr "" +"Этот пароль администратора неправильный. Осталось только %(num)d попыток." msgid "You either provided a bad token or no project identifier." msgstr "" msgid "This private code is not the right one" -msgstr "" +msgstr "Этот приватный код не подходит" #, python-format msgid "You have just created '%(project)s' to share your expenses" -msgstr "" +msgstr "Вы только что создали '%(project)s' , чтобы разделить расходы" #, python-format msgid "%(msg_compl)sThe project identifier is %(project)s" -msgstr "" +msgstr "%(msg_compl)sИдентификатор проекта это %(project)s" msgid "No token provided" -msgstr "" +msgstr "Не предоставлен токен" msgid "Invalid token" -msgstr "" +msgstr "Неправильный токен" msgid "Unknown project" msgstr "" From a75ad93dc10715061cd2e11ca90573297fadab7f Mon Sep 17 00:00:00 2001 From: Vsevolod Date: Mon, 27 Apr 2020 06:03:31 +0000 Subject: [PATCH 42/47] Translated using Weblate (Russian) Currently translated at 100.0% (222 of 222 strings) Translation: I Hate Money/I Hate Money Translate-URL: https://hosted.weblate.org/projects/i-hate-money/i-hate-money/ru/ --- .../translations/ru/LC_MESSAGES/messages.po | 360 ++++++++++-------- 1 file changed, 196 insertions(+), 164 deletions(-) diff --git a/ihatemoney/translations/ru/LC_MESSAGES/messages.po b/ihatemoney/translations/ru/LC_MESSAGES/messages.po index 2330bc32..75d24e31 100644 --- a/ihatemoney/translations/ru/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/ru/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-04-26 19:50+0200\n" -"PO-Revision-Date: 2020-04-26 20:48+0000\n" +"PO-Revision-Date: 2020-04-28 07:11+0000\n" "Last-Translator: Vsevolod \n" "Language-Team: Russian \n" @@ -13,7 +13,7 @@ msgstr "" "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.0.2-dev\n" +"X-Generator: Weblate 4.0.2\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " @@ -129,7 +129,7 @@ msgid "This project already have this member" msgstr "В этом проекте уже есть такой участник" msgid "People to notify" -msgstr "" +msgstr "Люди для уведомления" msgid "Send invites" msgstr "Отправить приглашения" @@ -157,6 +157,7 @@ msgstr "" msgid "You either provided a bad token or no project identifier." msgstr "" +"Вы либо предоставили неверный токен, либо не указали идентификатор проекта." msgid "This private code is not the right one" msgstr "Этот приватный код не подходит" @@ -176,207 +177,210 @@ msgid "Invalid token" msgstr "Неправильный токен" msgid "Unknown project" -msgstr "" +msgstr "Неизвестный проект" msgid "Password successfully reset." -msgstr "" +msgstr "Пароль успешно восстановлен." msgid "Project successfully uploaded" -msgstr "" +msgstr "Проект успешно загружен" msgid "Invalid JSON" -msgstr "" +msgstr "Неправильный JSON" msgid "Project successfully deleted" -msgstr "" +msgstr "Проект удалён" #, python-format msgid "You have been invited to share your expenses for %(project)s" -msgstr "" +msgstr "Вас пригласили разделить расходы в проект %(project)s" msgid "Your invitations have been sent" -msgstr "" +msgstr "Ваш код приглашения был отправлен" #, python-format msgid "%(member)s has been added" -msgstr "" +msgstr "%(member)s был добавлен" #, python-format msgid "%(name)s is part of this project again" -msgstr "" +msgstr "%(name)s снова часть этого проекта" #, python-format msgid "" "User '%(name)s' has been deactivated. It will still appear in the users " "list until its balance becomes zero." msgstr "" +"Пользователь '%(name)s' был деактивирован. Он будет отображаться в списке " +"пользователей до тех пор, пока его баланс не станет равным нулю." #, python-format msgid "User '%(name)s' has been removed" -msgstr "" +msgstr "Пользователь '%(name)s' был удалён" #, python-format msgid "User '%(name)s' has been edited" -msgstr "" +msgstr "Пользователь '%(name)s' был изменён" msgid "The bill has been added" -msgstr "" +msgstr "Счёт был добавлен" msgid "The bill has been deleted" -msgstr "" +msgstr "Счёт был удалён" msgid "The bill has been modified" -msgstr "" +msgstr "Счёт был изменён" 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." -msgstr "" +msgstr "Лучше всего вернуться на главную страницу." msgid "Back to the list" -msgstr "" +msgstr "Вернутся к списку" msgid "Administration tasks are currently disabled." -msgstr "" +msgstr "Задачи администратора в данный момент отключены." msgid "The project you are trying to access do not exist, do you want to" msgstr "" +"Проект, к которому вы пытаетесь получить доступ, не существует, вы хотите" msgid "create it" -msgstr "" +msgstr "создать его" msgid "?" -msgstr "" +msgstr "?" msgid "Create a new project" -msgstr "" +msgstr "Создать новый проект" msgid "Number of members" -msgstr "" +msgstr "Число участников" msgid "Number of bills" -msgstr "" +msgstr "Число счетов" msgid "Newest bill" -msgstr "" +msgstr "Новейший счёт" msgid "Oldest bill" -msgstr "" +msgstr "Старейший счёт" msgid "Actions" -msgstr "" +msgstr "Действия" msgid "edit" -msgstr "" +msgstr "изменить" msgid "delete" -msgstr "" +msgstr "удалить" msgid "see" -msgstr "" +msgstr "просмотреть" msgid "The Dashboard is currently deactivated." -msgstr "" +msgstr "Панель инструментов в данный момент отключена." msgid "you sure?" -msgstr "" +msgstr "вы уверены?" msgid "Edit project" -msgstr "" +msgstr "Изменить проект" msgid "Import JSON" -msgstr "" +msgstr "Импортировать JSON" msgid "Choose file" -msgstr "" +msgstr "Выбрать файл" msgid "Download project's data" -msgstr "" +msgstr "Скачать данные проекта" msgid "Bill items" -msgstr "" +msgstr "Пункты счета" msgid "Download the list of bills with owner, amount, reason,... " -msgstr "" +msgstr "Скачать список счетов с владельцем, суммой, причиной, .. " msgid "Settle plans" -msgstr "" +msgstr "Урегулировать планы" msgid "Download the list of transactions needed to settle the current bills." -msgstr "" +msgstr "Скачать список переводов нужных, чтобы урегулировать данные счета." msgid "Can't remember the password?" -msgstr "" +msgstr "Не помните пароль?" msgid "Cancel" -msgstr "" +msgstr "Отменить" msgid "Privacy Settings" -msgstr "" +msgstr "Настройки приватности" msgid "Edit the project" -msgstr "" +msgstr "Изменить проект" msgid "Edit this bill" -msgstr "" +msgstr "Изменить счёт" msgid "Add a bill" -msgstr "" +msgstr "Добавить счёт" msgid "Select all" -msgstr "" +msgstr "Выбрать всё" msgid "Select none" -msgstr "" +msgstr "Отменить выбор" msgid "Add participant" -msgstr "" +msgstr "Добавить участника" msgid "Edit this member" -msgstr "" +msgstr "Изменить этого участника" msgid "john.doe@example.com, mary.moe@site.com" -msgstr "" +msgstr "john.doe@example.com, mary.moe@site.com" msgid "Send the invitations" -msgstr "" +msgstr "Отправить приглашения" msgid "Download" -msgstr "" +msgstr "Скачать" msgid "Disabled Project History" -msgstr "" +msgstr "История отключенных проектов" msgid "Disabled Project History & IP Address Recording" -msgstr "" +msgstr "Отключенная история проекта и запись IP-адреса" msgid "Enabled Project History" -msgstr "" +msgstr "Включить историю проекта" msgid "Disabled IP Address Recording" -msgstr "" +msgstr "Выключить запись IP-адрессов" msgid "Enabled Project History & IP Address Recording" -msgstr "" +msgstr "Включить историю проекта и запись IP адрессов" msgid "Enabled IP Address Recording" -msgstr "" +msgstr "Включить запись IP адрессов" msgid "History Settings Changed" -msgstr "" +msgstr "Настройки истории изменены" msgid "changed" -msgstr "" +msgstr "изменены" msgid "from" -msgstr "" +msgstr "от" msgid "to" -msgstr "" +msgstr "кому" msgid "Confirm Remove IP Adresses" -msgstr "" +msgstr "Подтвердите удаление IP-адресов" msgid "" "Are you sure you want to delete all recorded IP addresses from this " @@ -384,38 +388,42 @@ msgid "" " The rest of the project history will be unaffected. This " "action cannot be undone." msgstr "" +"Вы уверены, что хотите удалить все записанные IP-адреса из этого проекта?\n" +" Остальная часть истории проекта не будет затронута. Это " +"действие не может быть отменено." msgid "Close" -msgstr "" +msgstr "Закрыть" msgid "Confirm Delete" -msgstr "" +msgstr "Подтвердить удаление" msgid "Delete Confirmation" -msgstr "" +msgstr "Подтверждение удаления" msgid "" "Are you sure you want to erase all history for this project? This action " "cannot be undone." msgstr "" +"Вы уверены, что хотите стереть историю проекта? Это действие нельзя отменить." msgid "Added" -msgstr "" +msgstr "Добавлен" msgid "Removed" -msgstr "" +msgstr "Удалён" msgid "and" -msgstr "" +msgstr "и" msgid "owers list" -msgstr "" +msgstr "список владельцев" msgid "Who?" -msgstr "" +msgstr "Кто?" msgid "Balance" -msgstr "" +msgstr "Баланс" #, python-format msgid "" @@ -425,6 +433,11 @@ msgid "" " settings page\n" " " msgstr "" +"\n" +" У этого проекта история отключена. Новые действия не появятся " +"ниже. Вы можете включить историю в\n" +" настройках\n" +" " msgid "" "\n" @@ -435,280 +448,295 @@ msgid "" "them.

\n" " " msgstr "" +"\n" +" В таблице ниже отражены действия, записанные до отключения " +"истории проекта. Вы можете\n" +" очистить историю проекта to remove " +"them.

\n" +" " msgid "" "Some entries below contain IP addresses, even though this project has IP " "recording disabled. " msgstr "" +"Некоторые записи ниже содержат IP-адреса, хотя в этом проекте запись IP " +"отключена. " msgid "Delete stored IP addresses" -msgstr "" +msgstr "Удалить сохраненные IP-адреса" msgid "No history to erase" -msgstr "" +msgstr "Нечего стирать" msgid "Clear Project History" -msgstr "" +msgstr "Стереть историю проекта" msgid "No IP Addresses to erase" -msgstr "" +msgstr "Нечего стирать" msgid "Delete Stored IP Addresses" -msgstr "" +msgstr "Удалить сохраненные IP-адреса" msgid "Time" -msgstr "" +msgstr "Время" msgid "Event" -msgstr "" +msgstr "Событие" 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" -msgstr "" +msgstr "Запись IP-адреса может быть отключена на странице настроек" msgid "From IP" -msgstr "" +msgstr "От IP" msgid "added" -msgstr "" +msgstr "добавлен" msgid "Project private code changed" -msgstr "" +msgstr "Приватный код проекта изменен" msgid "Project renamed to" -msgstr "" +msgstr "Проект переименован в" msgid "Project contact email changed to" -msgstr "" +msgstr "Контактная почта проекта изменена на" msgid "Project settings modified" -msgstr "" +msgstr "Настройки проекта изменены" msgid "deactivated" -msgstr "" +msgstr "отключено" msgid "reactivated" -msgstr "" +msgstr "реактивирован" msgid "renamed to" -msgstr "" +msgstr "переименован в" msgid "External link changed to" -msgstr "" +msgstr "Внешняя ссылка изменена на" msgid "Amount" -msgstr "" +msgstr "Количество" msgid "modified" -msgstr "" +msgstr "изменено" msgid "removed" -msgstr "" +msgstr "удалено" msgid "changed in a unknown way" -msgstr "" +msgstr "изменилось неизвестным образом" msgid "Nothing to list" -msgstr "" +msgstr "Нечего перечислять" msgid "Someone probably cleared the project history." -msgstr "" +msgstr "Кто-то скорее всего стёр историю проекта." msgid "Manage your shared
expenses, easily" -msgstr "" +msgstr "Управляйте своими общими
расходами проще" msgid "Try out the demo" -msgstr "" +msgstr "Попробуйте" msgid "You're sharing a house?" -msgstr "" +msgstr "Вы живете в одном доме с другими людьми?" msgid "Going on holidays with friends?" -msgstr "" +msgstr "Собираетесь в отпуск с друзьями?" msgid "Simply sharing money with others?" -msgstr "" +msgstr "Просто делиться деньгами с другими?" msgid "We can help!" -msgstr "" +msgstr "Мы поможем!" msgid "Log in to an existing project" -msgstr "" +msgstr "Войти в существующий проект" msgid "Log in" -msgstr "" +msgstr "Войти" msgid "can't remember your password?" -msgstr "" +msgstr "не помните пароль?" msgid "Create" -msgstr "" +msgstr "Создать" msgid "" "This access code will be sent to your friends. It is stored as-is by the " "server, so don\\'t reuse a personal password!" msgstr "" +"Этот код доступа будет отправлен вашим друзьям. Он хранится на сервере как " +"есть, поэтому не используйте личный пароль!" msgid "Account manager" -msgstr "" +msgstr "Менеджер аккаунтов" msgid "Bills" -msgstr "" +msgstr "Счета" msgid "Settle" -msgstr "" +msgstr "Отрегулировать" msgid "Statistics" -msgstr "" +msgstr "Статистика" msgid "History" -msgstr "" +msgstr "История" msgid "Settings" -msgstr "" +msgstr "Настройки" msgid "Languages" -msgstr "" +msgstr "Языки" msgid "Projects" -msgstr "" +msgstr "Проекты" msgid "Start a new project" -msgstr "" +msgstr "Начать новый проект" msgid "Other projects :" -msgstr "" +msgstr "Остальные проекты :" msgid "switch to" -msgstr "" +msgstr "сменён на" msgid "Dashboard" -msgstr "" +msgstr "Панель инструментов" msgid "Logout" -msgstr "" +msgstr "Выйти" msgid "Code" -msgstr "" +msgstr "Код" msgid "Mobile Application" -msgstr "" +msgstr "Мобильное приложение" msgid "Documentation" -msgstr "" +msgstr "Документация" msgid "Administation Dashboard" -msgstr "" +msgstr "Панель инструментов администратора" msgid "\"I hate money\" is a free software" -msgstr "" +msgstr "\" I hate money \" - бесплатная программа" msgid "you can contribute and improve it!" -msgstr "" +msgstr "вы можете способствовать развитию и улучшать её!" msgid "deactivate" -msgstr "" +msgstr "отключить" msgid "reactivate" -msgstr "" +msgstr "включить" msgid "Invite people" -msgstr "" +msgstr "Пригласить людей" msgid "You should start by adding participants" -msgstr "" +msgstr "Вам стоит начать с добавления пользователей" msgid "Add a new bill" -msgstr "" +msgstr "Добавить новый счёт" msgid "Newer bills" -msgstr "" +msgstr "Новые счета" msgid "Older bills" -msgstr "" +msgstr "Старые счета" msgid "When?" -msgstr "" +msgstr "Когда?" msgid "Who paid?" -msgstr "" +msgstr "Кто заплатил?" msgid "For what?" -msgstr "" +msgstr "За что?" msgid "How much?" -msgstr "" +msgstr "Сколько?" #, python-format msgid "Added on %(date)s" -msgstr "" +msgstr "Добавлено %(date)s" msgid "Everyone" -msgstr "" +msgstr "Каждый" #, python-format msgid "Everyone but %(excluded)s" -msgstr "" +msgstr "Каждый, кроме %(excluded)s" msgid "each" -msgstr "" +msgstr "каждый" msgid "No bills" -msgstr "" +msgstr "Нет счетов" msgid "Nothing to list yet." -msgstr "" +msgstr "Нечего перечислять еще." msgid "You probably want to" -msgstr "" +msgstr "Возможно вы хотите" msgid "add a bill" -msgstr "" +msgstr "добавить счёт" msgid "add participants" -msgstr "" +msgstr "добавить пользователя" msgid "Password reminder" -msgstr "" +msgstr "Напоминание пароля" msgid "" "A link to reset your password has been sent to you, please check your " "emails." msgstr "" +"Ссылка для восстановления пароля отправлена, пожалуйста, проверьте Email." msgid "Return to home page" -msgstr "" +msgstr "Вернуться на главную страницу" msgid "Your projects" -msgstr "" +msgstr "Ваши проекты" msgid "Reset your password" -msgstr "" +msgstr "Восстановить пароль" msgid "Invite people to join this project" -msgstr "" +msgstr "Пригласить людей присоединиться к этому проекту" msgid "Share Identifier & code" -msgstr "" +msgstr "Поделиться идентификатором и кодом" msgid "" "You can share the project identifier and the private code by any " "communication means." msgstr "" +"Вы можете поделиться идентификатором проекта и личным кодом любым способом " +"связи." msgid "Identifier:" -msgstr "" +msgstr "Идентификатор:" msgid "Share the Link" -msgstr "" +msgstr "Поделиться ссылкой" msgid "You can directly share the following link via your prefered medium" msgstr "" +"Вы можете напрямую поделиться следующей ссылкой через любой способ связи" msgid "Send via Emails" -msgstr "" +msgstr "Отправить по почте" msgid "" "Specify a (comma separated) list of email adresses you want to notify " @@ -716,21 +744,25 @@ msgid "" " creation of this budget management project and we will " "send them an email for you." msgstr "" +"Укажите (разделенный запятыми) список адресов электронной почты, которые вы " +"хотите уведомить о\n" +" создание этого проекта управления бюджетом, и мы вышлем им " +"письмо." msgid "Who pays?" -msgstr "" +msgstr "Кто платит?" msgid "To whom?" -msgstr "" +msgstr "Кому?" msgid "Paid" -msgstr "" +msgstr "Оплачено" msgid "Spent" -msgstr "" +msgstr "Потрачено" msgid "Expenses by Month" -msgstr "" +msgstr "Расходы по месяцам" msgid "Period" -msgstr "" +msgstr "Период" From d2f4b60ef0364ed384679ec7e6e1e0b71011f8d3 Mon Sep 17 00:00:00 2001 From: Matteo Haenen Date: Tue, 28 Apr 2020 08:30:42 +0000 Subject: [PATCH 43/47] Added translation using Weblate (Italian) --- .../translations/it/LC_MESSAGES/messages.po | 729 ++++++++++++++++++ 1 file changed, 729 insertions(+) create mode 100644 ihatemoney/translations/it/LC_MESSAGES/messages.po diff --git a/ihatemoney/translations/it/LC_MESSAGES/messages.po b/ihatemoney/translations/it/LC_MESSAGES/messages.po new file mode 100644 index 00000000..f9c05c9e --- /dev/null +++ b/ihatemoney/translations/it/LC_MESSAGES/messages.po @@ -0,0 +1,729 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-04-28 10:30+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Translate Toolkit 2.5.1\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 "" + +msgid "Enable project history" +msgstr "" + +msgid "Use IP tracking for project history" +msgstr "" + +msgid "Import previously exported JSON file" +msgstr "" + +msgid "Import" +msgstr "" + +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 "" + +msgid "Send me the code by email" +msgstr "" + +msgid "This project does not exists" +msgstr "" + +msgid "Password mismatch" +msgstr "" + +msgid "Password" +msgstr "" + +msgid "Password confirmation" +msgstr "" + +msgid "Reset password" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "What?" +msgstr "" + +msgid "Payer" +msgstr "" + +msgid "Amount paid" +msgstr "" + +msgid "External link" +msgstr "" + +msgid "A link to an external document, related to this bill" +msgstr "" + +msgid "For whom?" +msgstr "" + +msgid "Submit" +msgstr "" + +msgid "Submit and add a new one" +msgstr "" + +msgid "Bills can't be null" +msgstr "" + +msgid "Name" +msgstr "" + +msgid "Weights should be positive" +msgstr "" + +msgid "Weight" +msgstr "" + +msgid "Add" +msgstr "" + +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 "" + +msgid "Participant" +msgstr "" + +msgid "Bill" +msgstr "" + +msgid "Project" +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 "" + +#, python-format +msgid "%(msg_compl)sThe project identifier is %(project)s" +msgstr "" + +msgid "No token provided" +msgstr "" + +msgid "Invalid token" +msgstr "" + +msgid "Unknown project" +msgstr "" + +msgid "Password successfully reset." +msgstr "" + +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 "" + +#, 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 "" + +#, python-format +msgid "User '%(name)s' has been edited" +msgstr "" + +msgid "The bill has been added" +msgstr "" + +msgid "The bill has been deleted" +msgstr "" + +msgid "The bill has been modified" +msgstr "" + +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 "" + +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 "" + +msgid "Number of bills" +msgstr "" + +msgid "Newest bill" +msgstr "" + +msgid "Oldest bill" +msgstr "" + +msgid "Actions" +msgstr "" + +msgid "edit" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "see" +msgstr "" + +msgid "The Dashboard is currently deactivated." +msgstr "" + +msgid "you sure?" +msgstr "" + +msgid "Edit project" +msgstr "" + +msgid "Import JSON" +msgstr "" + +msgid "Choose file" +msgstr "" + +msgid "Download project's data" +msgstr "" + +msgid "Bill items" +msgstr "" + +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 "" + +msgid "Privacy Settings" +msgstr "" + +msgid "Edit the project" +msgstr "" + +msgid "Edit this bill" +msgstr "" + +msgid "Add a bill" +msgstr "" + +msgid "Select all" +msgstr "" + +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 "" + +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 "" + +msgid "Removed" +msgstr "" + +msgid "and" +msgstr "" + +msgid "owers list" +msgstr "" + +msgid "Who?" +msgstr "" + +msgid "Balance" +msgstr "" + +#, python-format +msgid "" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " +msgstr "" + +msgid "" +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\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 "" + +msgid "Event" +msgstr "" + +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 "" + +msgid "modified" +msgstr "" + +msgid "removed" +msgstr "" + +msgid "changed in a unknown way" +msgstr "" + +msgid "Nothing to list" +msgstr "" + +msgid "Someone probably cleared the project history." +msgstr "" + +msgid "Manage your shared
expenses, easily" +msgstr "" + +msgid "Try out the demo" +msgstr "" + +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 "" +"This access code will be sent to your friends. It is stored as-is by the " +"server, so don\\'t reuse a personal password!" +msgstr "" + +msgid "Account manager" +msgstr "" + +msgid "Bills" +msgstr "" + +msgid "Settle" +msgstr "" + +msgid "Statistics" +msgstr "" + +msgid "History" +msgstr "" + +msgid "Settings" +msgstr "" + +msgid "Languages" +msgstr "" + +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 "" + +msgid "Mobile Application" +msgstr "" + +msgid "Documentation" +msgstr "" + +msgid "Administation Dashboard" +msgstr "" + +msgid "\"I hate money\" is a free software" +msgstr "" + +msgid "you can contribute and improve it!" +msgstr "" + +msgid "deactivate" +msgstr "" + +msgid "reactivate" +msgstr "" + +msgid "Invite people" +msgstr "" + +msgid "You should start by adding participants" +msgstr "" + +msgid "Add a new bill" +msgstr "" + +msgid "Newer bills" +msgstr "" + +msgid "Older bills" +msgstr "" + +msgid "When?" +msgstr "" + +msgid "Who paid?" +msgstr "" + +msgid "For what?" +msgstr "" + +msgid "How much?" +msgstr "" + +#, python-format +msgid "Added on %(date)s" +msgstr "" + +msgid "Everyone" +msgstr "" + +#, python-format +msgid "Everyone but %(excluded)s" +msgstr "" + +msgid "each" +msgstr "" + +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 "" + +msgid "Your projects" +msgstr "" + +msgid "Reset your password" +msgstr "" + +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 "" + +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 "" + +msgid "To whom?" +msgstr "" + +msgid "Paid" +msgstr "" + +msgid "Spent" +msgstr "" + +msgid "Expenses by Month" +msgstr "" + +msgid "Period" +msgstr "" From 162193c787341118621b36b4c8933bbe8af092df Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Wed, 29 Apr 2020 12:08:24 +0200 Subject: [PATCH 44/47] Translations update from Weblate (#591) RU : 100% --- .../translations/it/LC_MESSAGES/messages.po | 729 +++++++++++++++++ .../translations/ru/LC_MESSAGES/messages.po | 768 ++++++++++++++++++ 2 files changed, 1497 insertions(+) create mode 100644 ihatemoney/translations/it/LC_MESSAGES/messages.po create mode 100644 ihatemoney/translations/ru/LC_MESSAGES/messages.po diff --git a/ihatemoney/translations/it/LC_MESSAGES/messages.po b/ihatemoney/translations/it/LC_MESSAGES/messages.po new file mode 100644 index 00000000..f9c05c9e --- /dev/null +++ b/ihatemoney/translations/it/LC_MESSAGES/messages.po @@ -0,0 +1,729 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-04-28 10:30+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Translate Toolkit 2.5.1\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 "" + +msgid "Enable project history" +msgstr "" + +msgid "Use IP tracking for project history" +msgstr "" + +msgid "Import previously exported JSON file" +msgstr "" + +msgid "Import" +msgstr "" + +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 "" + +msgid "Send me the code by email" +msgstr "" + +msgid "This project does not exists" +msgstr "" + +msgid "Password mismatch" +msgstr "" + +msgid "Password" +msgstr "" + +msgid "Password confirmation" +msgstr "" + +msgid "Reset password" +msgstr "" + +msgid "Date" +msgstr "" + +msgid "What?" +msgstr "" + +msgid "Payer" +msgstr "" + +msgid "Amount paid" +msgstr "" + +msgid "External link" +msgstr "" + +msgid "A link to an external document, related to this bill" +msgstr "" + +msgid "For whom?" +msgstr "" + +msgid "Submit" +msgstr "" + +msgid "Submit and add a new one" +msgstr "" + +msgid "Bills can't be null" +msgstr "" + +msgid "Name" +msgstr "" + +msgid "Weights should be positive" +msgstr "" + +msgid "Weight" +msgstr "" + +msgid "Add" +msgstr "" + +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 "" + +msgid "Participant" +msgstr "" + +msgid "Bill" +msgstr "" + +msgid "Project" +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 "" + +#, python-format +msgid "%(msg_compl)sThe project identifier is %(project)s" +msgstr "" + +msgid "No token provided" +msgstr "" + +msgid "Invalid token" +msgstr "" + +msgid "Unknown project" +msgstr "" + +msgid "Password successfully reset." +msgstr "" + +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 "" + +#, 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 "" + +#, python-format +msgid "User '%(name)s' has been edited" +msgstr "" + +msgid "The bill has been added" +msgstr "" + +msgid "The bill has been deleted" +msgstr "" + +msgid "The bill has been modified" +msgstr "" + +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 "" + +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 "" + +msgid "Number of bills" +msgstr "" + +msgid "Newest bill" +msgstr "" + +msgid "Oldest bill" +msgstr "" + +msgid "Actions" +msgstr "" + +msgid "edit" +msgstr "" + +msgid "delete" +msgstr "" + +msgid "see" +msgstr "" + +msgid "The Dashboard is currently deactivated." +msgstr "" + +msgid "you sure?" +msgstr "" + +msgid "Edit project" +msgstr "" + +msgid "Import JSON" +msgstr "" + +msgid "Choose file" +msgstr "" + +msgid "Download project's data" +msgstr "" + +msgid "Bill items" +msgstr "" + +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 "" + +msgid "Privacy Settings" +msgstr "" + +msgid "Edit the project" +msgstr "" + +msgid "Edit this bill" +msgstr "" + +msgid "Add a bill" +msgstr "" + +msgid "Select all" +msgstr "" + +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 "" + +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 "" + +msgid "Removed" +msgstr "" + +msgid "and" +msgstr "" + +msgid "owers list" +msgstr "" + +msgid "Who?" +msgstr "" + +msgid "Balance" +msgstr "" + +#, python-format +msgid "" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " +msgstr "" + +msgid "" +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\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 "" + +msgid "Event" +msgstr "" + +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 "" + +msgid "modified" +msgstr "" + +msgid "removed" +msgstr "" + +msgid "changed in a unknown way" +msgstr "" + +msgid "Nothing to list" +msgstr "" + +msgid "Someone probably cleared the project history." +msgstr "" + +msgid "Manage your shared
expenses, easily" +msgstr "" + +msgid "Try out the demo" +msgstr "" + +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 "" +"This access code will be sent to your friends. It is stored as-is by the " +"server, so don\\'t reuse a personal password!" +msgstr "" + +msgid "Account manager" +msgstr "" + +msgid "Bills" +msgstr "" + +msgid "Settle" +msgstr "" + +msgid "Statistics" +msgstr "" + +msgid "History" +msgstr "" + +msgid "Settings" +msgstr "" + +msgid "Languages" +msgstr "" + +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 "" + +msgid "Mobile Application" +msgstr "" + +msgid "Documentation" +msgstr "" + +msgid "Administation Dashboard" +msgstr "" + +msgid "\"I hate money\" is a free software" +msgstr "" + +msgid "you can contribute and improve it!" +msgstr "" + +msgid "deactivate" +msgstr "" + +msgid "reactivate" +msgstr "" + +msgid "Invite people" +msgstr "" + +msgid "You should start by adding participants" +msgstr "" + +msgid "Add a new bill" +msgstr "" + +msgid "Newer bills" +msgstr "" + +msgid "Older bills" +msgstr "" + +msgid "When?" +msgstr "" + +msgid "Who paid?" +msgstr "" + +msgid "For what?" +msgstr "" + +msgid "How much?" +msgstr "" + +#, python-format +msgid "Added on %(date)s" +msgstr "" + +msgid "Everyone" +msgstr "" + +#, python-format +msgid "Everyone but %(excluded)s" +msgstr "" + +msgid "each" +msgstr "" + +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 "" + +msgid "Your projects" +msgstr "" + +msgid "Reset your password" +msgstr "" + +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 "" + +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 "" + +msgid "To whom?" +msgstr "" + +msgid "Paid" +msgstr "" + +msgid "Spent" +msgstr "" + +msgid "Expenses by Month" +msgstr "" + +msgid "Period" +msgstr "" diff --git a/ihatemoney/translations/ru/LC_MESSAGES/messages.po b/ihatemoney/translations/ru/LC_MESSAGES/messages.po new file mode 100644 index 00000000..75d24e31 --- /dev/null +++ b/ihatemoney/translations/ru/LC_MESSAGES/messages.po @@ -0,0 +1,768 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-04-26 19:50+0200\n" +"PO-Revision-Date: 2020-04-28 07:11+0000\n" +"Last-Translator: Vsevolod \n" +"Language-Team: Russian \n" +"Language: ru\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.0.2\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 "Использовать отслеживание по IP для истории проекта" + +msgid "Import previously exported JSON file" +msgstr "Импортировать ранее экспортированный JSON файл" + +msgid "Import" +msgstr "Импортировать" + +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 "" +"Проект с идентификатором (\"%(project)s\") уже существует. Пожалуйста, " +"выберете новый идентификатор" + +msgid "Get in" +msgstr "Войти" + +msgid "Admin password" +msgstr "Пароль администратора" + +msgid "Send me the code by email" +msgstr "Отправить код мне на Email" + +msgid "This project does not exists" +msgstr "Такой проект не существует" + +msgid "Password mismatch" +msgstr "Пароли не совпадают" + +msgid "Password" +msgstr "Пароль" + +msgid "Password confirmation" +msgstr "Подтвердите пароль" + +msgid "Reset password" +msgstr "Восстановить пароль" + +msgid "Date" +msgstr "Дата" + +msgid "What?" +msgstr "Что?" + +msgid "Payer" +msgstr "Плательщик" + +msgid "Amount paid" +msgstr "Уплаченная сумма" + +msgid "External link" +msgstr "Внешняя ссылка" + +msgid "A link to an external document, related to this bill" +msgstr "Ссылка на внешний документ, относящийся к этому счёту" + +msgid "For whom?" +msgstr "Кому?" + +msgid "Submit" +msgstr "Отправить" + +msgid "Submit and add a new one" +msgstr "Отправить и добавить новый" + +msgid "Bills can't be null" +msgstr "Счета не могут быть нулевыми" + +msgid "Name" +msgstr "Имя" + +msgid "Weights should be positive" +msgstr "Вес должен быть положительным" + +msgid "Weight" +msgstr "Вес" + +msgid "Add" +msgstr "Добавить" + +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 не правильный" + +msgid "Participant" +msgstr "Участник" + +msgid "Bill" +msgstr "Счёт" + +msgid "Project" +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 "" +"Этот пароль администратора неправильный. Осталось только %(num)d попыток." + +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 "Вы только что создали '%(project)s' , чтобы разделить расходы" + +#, python-format +msgid "%(msg_compl)sThe project identifier is %(project)s" +msgstr "%(msg_compl)sИдентификатор проекта это %(project)s" + +msgid "No token provided" +msgstr "Не предоставлен токен" + +msgid "Invalid token" +msgstr "Неправильный токен" + +msgid "Unknown project" +msgstr "Неизвестный проект" + +msgid "Password successfully reset." +msgstr "Пароль успешно восстановлен." + +msgid "Project successfully uploaded" +msgstr "Проект успешно загружен" + +msgid "Invalid JSON" +msgstr "Неправильный JSON" + +msgid "Project successfully deleted" +msgstr "Проект удалён" + +#, python-format +msgid "You have been invited to share your expenses for %(project)s" +msgstr "Вас пригласили разделить расходы в проект %(project)s" + +msgid "Your invitations have been sent" +msgstr "Ваш код приглашения был отправлен" + +#, python-format +msgid "%(member)s has been added" +msgstr "%(member)s был добавлен" + +#, python-format +msgid "%(name)s is part of this project again" +msgstr "%(name)s снова часть этого проекта" + +#, python-format +msgid "" +"User '%(name)s' has been deactivated. It will still appear in the users " +"list until its balance becomes zero." +msgstr "" +"Пользователь '%(name)s' был деактивирован. Он будет отображаться в списке " +"пользователей до тех пор, пока его баланс не станет равным нулю." + +#, python-format +msgid "User '%(name)s' has been removed" +msgstr "Пользователь '%(name)s' был удалён" + +#, python-format +msgid "User '%(name)s' has been edited" +msgstr "Пользователь '%(name)s' был изменён" + +msgid "The bill has been added" +msgstr "Счёт был добавлен" + +msgid "The bill has been deleted" +msgstr "Счёт был удалён" + +msgid "The bill has been modified" +msgstr "Счёт был изменён" + +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 "Вернутся к списку" + +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 "Число участников" + +msgid "Number of bills" +msgstr "Число счетов" + +msgid "Newest bill" +msgstr "Новейший счёт" + +msgid "Oldest bill" +msgstr "Старейший счёт" + +msgid "Actions" +msgstr "Действия" + +msgid "edit" +msgstr "изменить" + +msgid "delete" +msgstr "удалить" + +msgid "see" +msgstr "просмотреть" + +msgid "The Dashboard is currently deactivated." +msgstr "Панель инструментов в данный момент отключена." + +msgid "you sure?" +msgstr "вы уверены?" + +msgid "Edit project" +msgstr "Изменить проект" + +msgid "Import JSON" +msgstr "Импортировать JSON" + +msgid "Choose file" +msgstr "Выбрать файл" + +msgid "Download project's data" +msgstr "Скачать данные проекта" + +msgid "Bill items" +msgstr "Пункты счета" + +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 "Отменить" + +msgid "Privacy Settings" +msgstr "Настройки приватности" + +msgid "Edit the project" +msgstr "Изменить проект" + +msgid "Edit this bill" +msgstr "Изменить счёт" + +msgid "Add a bill" +msgstr "Добавить счёт" + +msgid "Select all" +msgstr "Выбрать всё" + +msgid "Select none" +msgstr "Отменить выбор" + +msgid "Add participant" +msgstr "Добавить участника" + +msgid "Edit this member" +msgstr "Изменить этого участника" + +msgid "john.doe@example.com, mary.moe@site.com" +msgstr "john.doe@example.com, mary.moe@site.com" + +msgid "Send the invitations" +msgstr "Отправить приглашения" + +msgid "Download" +msgstr "Скачать" + +msgid "Disabled Project History" +msgstr "История отключенных проектов" + +msgid "Disabled Project History & IP Address Recording" +msgstr "Отключенная история проекта и запись IP-адреса" + +msgid "Enabled Project History" +msgstr "Включить историю проекта" + +msgid "Disabled IP Address Recording" +msgstr "Выключить запись IP-адрессов" + +msgid "Enabled Project History & IP Address Recording" +msgstr "Включить историю проекта и запись IP адрессов" + +msgid "Enabled IP Address Recording" +msgstr "Включить запись IP адрессов" + +msgid "History Settings Changed" +msgstr "Настройки истории изменены" + +msgid "changed" +msgstr "изменены" + +msgid "from" +msgstr "от" + +msgid "to" +msgstr "кому" + +msgid "Confirm Remove IP Adresses" +msgstr "Подтвердите удаление IP-адресов" + +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 "" +"Вы уверены, что хотите удалить все записанные IP-адреса из этого проекта?\n" +" Остальная часть истории проекта не будет затронута. Это " +"действие не может быть отменено." + +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 "Добавлен" + +msgid "Removed" +msgstr "Удалён" + +msgid "and" +msgstr "и" + +msgid "owers list" +msgstr "список владельцев" + +msgid "Who?" +msgstr "Кто?" + +msgid "Balance" +msgstr "Баланс" + +#, python-format +msgid "" +"\n" +" This project has history disabled. New actions won't " +"appear below. You can enable history on the\n" +" settings page\n" +" " +msgstr "" +"\n" +" У этого проекта история отключена. Новые действия не появятся " +"ниже. Вы можете включить историю в\n" +" настройках\n" +" " + +msgid "" +"\n" +" The table below reflects actions recorded prior to " +"disabling project history. You can\n" +" clear project history to remove " +"them.

\n" +" " +msgstr "" +"\n" +" В таблице ниже отражены действия, записанные до отключения " +"истории проекта. Вы можете\n" +" очистить историю проекта to remove " +"them.

\n" +" " + +msgid "" +"Some entries below contain IP addresses, even though this project has IP " +"recording disabled. " +msgstr "" +"Некоторые записи ниже содержат IP-адреса, хотя в этом проекте запись IP " +"отключена. " + +msgid "Delete stored IP addresses" +msgstr "Удалить сохраненные IP-адреса" + +msgid "No history to erase" +msgstr "Нечего стирать" + +msgid "Clear Project History" +msgstr "Стереть историю проекта" + +msgid "No IP Addresses to erase" +msgstr "Нечего стирать" + +msgid "Delete Stored IP Addresses" +msgstr "Удалить сохраненные IP-адреса" + +msgid "Time" +msgstr "Время" + +msgid "Event" +msgstr "Событие" + +msgid "IP address recording can be enabled on the settings page" +msgstr "Запись IP-адреса может быть включена на странице настроек" + +msgid "IP address recording can be disabled on the settings page" +msgstr "Запись IP-адреса может быть отключена на странице настроек" + +msgid "From IP" +msgstr "От IP" + +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 "Количество" + +msgid "modified" +msgstr "изменено" + +msgid "removed" +msgstr "удалено" + +msgid "changed in a unknown way" +msgstr "изменилось неизвестным образом" + +msgid "Nothing to list" +msgstr "Нечего перечислять" + +msgid "Someone probably cleared the project history." +msgstr "Кто-то скорее всего стёр историю проекта." + +msgid "Manage your shared
expenses, easily" +msgstr "Управляйте своими общими
расходами проще" + +msgid "Try out the demo" +msgstr "Попробуйте" + +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 "" +"This access code will be sent to your friends. It is stored as-is by the " +"server, so don\\'t reuse a personal password!" +msgstr "" +"Этот код доступа будет отправлен вашим друзьям. Он хранится на сервере как " +"есть, поэтому не используйте личный пароль!" + +msgid "Account manager" +msgstr "Менеджер аккаунтов" + +msgid "Bills" +msgstr "Счета" + +msgid "Settle" +msgstr "Отрегулировать" + +msgid "Statistics" +msgstr "Статистика" + +msgid "History" +msgstr "История" + +msgid "Settings" +msgstr "Настройки" + +msgid "Languages" +msgstr "Языки" + +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 "Код" + +msgid "Mobile Application" +msgstr "Мобильное приложение" + +msgid "Documentation" +msgstr "Документация" + +msgid "Administation Dashboard" +msgstr "Панель инструментов администратора" + +msgid "\"I hate money\" is a free software" +msgstr "\" I hate money \" - бесплатная программа" + +msgid "you can contribute and improve it!" +msgstr "вы можете способствовать развитию и улучшать её!" + +msgid "deactivate" +msgstr "отключить" + +msgid "reactivate" +msgstr "включить" + +msgid "Invite people" +msgstr "Пригласить людей" + +msgid "You should start by adding participants" +msgstr "Вам стоит начать с добавления пользователей" + +msgid "Add a new bill" +msgstr "Добавить новый счёт" + +msgid "Newer bills" +msgstr "Новые счета" + +msgid "Older bills" +msgstr "Старые счета" + +msgid "When?" +msgstr "Когда?" + +msgid "Who paid?" +msgstr "Кто заплатил?" + +msgid "For what?" +msgstr "За что?" + +msgid "How much?" +msgstr "Сколько?" + +#, python-format +msgid "Added on %(date)s" +msgstr "Добавлено %(date)s" + +msgid "Everyone" +msgstr "Каждый" + +#, python-format +msgid "Everyone but %(excluded)s" +msgstr "Каждый, кроме %(excluded)s" + +msgid "each" +msgstr "каждый" + +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 "" +"Ссылка для восстановления пароля отправлена, пожалуйста, проверьте Email." + +msgid "Return to home page" +msgstr "Вернуться на главную страницу" + +msgid "Your projects" +msgstr "Ваши проекты" + +msgid "Reset your password" +msgstr "Восстановить пароль" + +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 "Поделиться ссылкой" + +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 "" +"Укажите (разделенный запятыми) список адресов электронной почты, которые вы " +"хотите уведомить о\n" +" создание этого проекта управления бюджетом, и мы вышлем им " +"письмо." + +msgid "Who pays?" +msgstr "Кто платит?" + +msgid "To whom?" +msgstr "Кому?" + +msgid "Paid" +msgstr "Оплачено" + +msgid "Spent" +msgstr "Потрачено" + +msgid "Expenses by Month" +msgstr "Расходы по месяцам" + +msgid "Period" +msgstr "Период" From f389c562595f74bea86e49c29949f4a7b0e78900 Mon Sep 17 00:00:00 2001 From: dark0dave <52840419+dark0dave@users.noreply.github.com> Date: Wed, 29 Apr 2020 21:57:08 +0100 Subject: [PATCH 45/47] Feature/currencies (#541) Now each project can have a currency, default to None. Each bill can use a different currency, and a conversion to project default currency is done on settle. Fix #512 --- .gitignore | 6 +- ihatemoney/currency_convertor.py | 46 ++++++++++++ ihatemoney/forms.py | 62 +++++++++++++++- ihatemoney/history.py | 8 ++ .../versions/927ed575acbd_add_currencies.py | 73 +++++++++++++++++++ ihatemoney/models.py | 21 +++++- ihatemoney/run.py | 4 + ihatemoney/templates/forms.html | 5 ++ ihatemoney/templates/history.html | 4 + ihatemoney/templates/list_bills.html | 23 +++++- ihatemoney/tests/tests.py | 51 ++++++++++++- ihatemoney/web.py | 19 ++++- setup.cfg | 2 + 13 files changed, 313 insertions(+), 11 deletions(-) create mode 100644 ihatemoney/currency_convertor.py create mode 100644 ihatemoney/migrations/versions/927ed575acbd_add_currencies.py diff --git a/.gitignore b/.gitignore index d8d18940..9e3c42ce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -ihatemoney.cfg *.pyc *.egg-info dist @@ -13,3 +12,8 @@ build .pytest_cache ihatemoney/budget.db .idea/ +.envrc +.DS_Store +.idea +.python-version + diff --git a/ihatemoney/currency_convertor.py b/ihatemoney/currency_convertor.py new file mode 100644 index 00000000..75fa8342 --- /dev/null +++ b/ihatemoney/currency_convertor.py @@ -0,0 +1,46 @@ +from cachetools import TTLCache, cached +import requests + + +class Singleton(type): + _instances = {} + + def __call__(cls, *args, **kwargs): + if cls not in cls._instances: + cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) + return cls._instances[cls] + + +class CurrencyConverter(object, metaclass=Singleton): + # Get exchange rates + default = "No Currency" + api_url = "https://api.exchangeratesapi.io/latest?base=USD" + + def __init__(self): + pass + + @cached(cache=TTLCache(maxsize=1, ttl=86400)) + def get_rates(self): + rates = requests.get(self.api_url).json()["rates"] + rates[self.default] = 1.0 + return rates + + def get_currencies(self): + rates = [rate for rate in self.get_rates()] + rates.sort(key=lambda rate: "" if rate == self.default else rate) + return rates + + def exchange_currency(self, amount, source_currency, dest_currency): + if ( + source_currency == dest_currency + or source_currency == self.default + or dest_currency == self.default + ): + return amount + + rates = self.get_rates() + source_rate = rates[source_currency] + dest_rate = rates[dest_currency] + new_amount = (float(amount) / source_rate) * dest_rate + # round to two digits because we are dealing with money + return round(new_amount, 2) diff --git a/ihatemoney/forms.py b/ihatemoney/forms.py index 989b3022..7a6a57e4 100644 --- a/ihatemoney/forms.py +++ b/ihatemoney/forms.py @@ -1,3 +1,4 @@ +import copy from datetime import datetime from re import match @@ -8,7 +9,7 @@ from flask_wtf.file import FileAllowed, FileField, FileRequired from flask_wtf.form import FlaskForm from jinja2 import Markup from werkzeug.security import check_password_hash, generate_password_hash -from wtforms.fields.core import SelectField, SelectMultipleField +from wtforms.fields.core import Label, SelectField, SelectMultipleField from wtforms.fields.html5 import DateField, DecimalField, URLField from wtforms.fields.simple import BooleanField, PasswordField, StringField, SubmitField from wtforms.validators import ( @@ -20,6 +21,7 @@ from wtforms.validators import ( ValidationError, ) +from ihatemoney.currency_convertor import CurrencyConverter from ihatemoney.models import LoggingMode, Person, Project from ihatemoney.utils import eval_arithmetic_expression, slugify @@ -31,6 +33,18 @@ def strip_filter(string): return string +def get_editprojectform_for(project, **kwargs): + """Return an instance of EditProjectForm configured for a particular project. + """ + form = EditProjectForm(**kwargs) + choices = copy.copy(form.default_currency.choices) + choices.sort( + key=lambda rates: "" if rates[0] == project.default_currency else rates[0] + ) + form.default_currency.choices = choices + return form + + def get_billform_for(project, set_default=True, **kwargs): """Return an instance of BillForm configured for a particular project. @@ -39,6 +53,23 @@ def get_billform_for(project, set_default=True, **kwargs): """ form = BillForm(**kwargs) + if form.original_currency.data == "None": + form.original_currency.data = project.default_currency + + if form.original_currency.data != CurrencyConverter.default: + choices = copy.copy(form.original_currency.choices) + choices.remove((CurrencyConverter.default, CurrencyConverter.default)) + choices.sort( + key=lambda rates: "" if rates[0] == project.default_currency else rates[0] + ) + form.original_currency.choices = choices + else: + form.original_currency.render_kw = {"default": True} + form.original_currency.data = CurrencyConverter.default + + form.original_currency.label = Label( + "original_currency", "Currency (Default: %s)" % (project.default_currency) + ) active_members = [(m.id, m.name) for m in project.active_members] form.payed_for.choices = form.payer.choices = active_members @@ -89,6 +120,15 @@ class EditProjectForm(FlaskForm): contact_email = StringField(_("Email"), validators=[DataRequired(), Email()]) project_history = BooleanField(_("Enable project history")) ip_recording = BooleanField(_("Use IP tracking for project history")) + currency_helper = CurrencyConverter() + default_currency = SelectField( + _("Default Currency"), + choices=[ + (currency_name, currency_name) + for currency_name in currency_helper.get_currencies() + ], + validators=[DataRequired()], + ) @property def logging_preference(self): @@ -112,6 +152,7 @@ class EditProjectForm(FlaskForm): password=generate_password_hash(self.password.data), contact_email=self.contact_email.data, logging_preference=self.logging_preference, + default_currency=self.default_currency.data, ) return project @@ -125,6 +166,7 @@ class EditProjectForm(FlaskForm): project.contact_email = self.contact_email.data project.logging_preference = self.logging_preference + project.default_currency = self.default_currency.data return project @@ -199,6 +241,15 @@ class BillForm(FlaskForm): what = StringField(_("What?"), validators=[DataRequired()]) payer = SelectField(_("Payer"), validators=[DataRequired()], coerce=int) amount = CalculatorStringField(_("Amount paid"), validators=[DataRequired()]) + currency_helper = CurrencyConverter() + original_currency = SelectField( + _("Currency"), + choices=[ + (currency_name, currency_name) + for currency_name in currency_helper.get_currencies() + ], + validators=[DataRequired()], + ) external_link = URLField( _("External link"), validators=[Optional()], @@ -217,6 +268,10 @@ class BillForm(FlaskForm): bill.external_link = self.external_link.data bill.date = self.date.data bill.owers = [Person.query.get(ower, project) for ower in self.payed_for.data] + bill.original_currency = self.original_currency.data + bill.converted_amount = self.currency_helper.exchange_currency( + bill.amount, bill.original_currency, project.default_currency + ) return bill def fake_form(self, bill, project): @@ -226,6 +281,10 @@ class BillForm(FlaskForm): bill.external_link = "" bill.date = self.date bill.owers = [Person.query.get(ower, project) for ower in self.payed_for] + bill.original_currency = CurrencyConverter.default + bill.converted_amount = self.currency_helper.exchange_currency( + bill.amount, bill.original_currency, project.default_currency + ) return bill @@ -234,6 +293,7 @@ class BillForm(FlaskForm): self.amount.data = bill.amount self.what.data = bill.what self.external_link.data = bill.external_link + self.original_currency.data = bill.original_currency self.date.data = bill.date self.payed_for.data = [int(ower.id) for ower in bill.owers] diff --git a/ihatemoney/history.py b/ihatemoney/history.py index 9dda3de6..faa12c09 100644 --- a/ihatemoney/history.py +++ b/ihatemoney/history.py @@ -105,6 +105,14 @@ def get_history(project, human_readable_names=True): if removed: changeset["owers_removed"] = (None, removed) + # Remove converted_amount if amount changed in the same way. + if ( + "amount" in changeset + and "converted_amount" in changeset + and changeset["amount"] == changeset["converted_amount"] + ): + del changeset["converted_amount"] + for (prop, (val_before, val_after),) in changeset.items(): if human_readable_names: if prop == "payer_id": diff --git a/ihatemoney/migrations/versions/927ed575acbd_add_currencies.py b/ihatemoney/migrations/versions/927ed575acbd_add_currencies.py new file mode 100644 index 00000000..b70d9025 --- /dev/null +++ b/ihatemoney/migrations/versions/927ed575acbd_add_currencies.py @@ -0,0 +1,73 @@ +"""Add currencies + +Revision ID: 927ed575acbd +Revises: cb038f79982e +Create Date: 2020-04-25 14:49:41.136602 + +""" + +# revision identifiers, used by Alembic. +revision = "927ed575acbd" +down_revision = "cb038f79982e" + +from alembic import op +import sqlalchemy as sa +from ihatemoney.currency_convertor import CurrencyConverter + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column("bill", sa.Column("converted_amount", sa.Float(), nullable=True)) + op.add_column( + "bill", + sa.Column( + "original_currency", + sa.String(length=3), + server_default=CurrencyConverter.default, + nullable=True, + ), + ) + op.add_column( + "bill_version", + sa.Column("converted_amount", sa.Float(), autoincrement=False, nullable=True), + ) + op.add_column( + "bill_version", + sa.Column( + "original_currency", sa.String(length=3), autoincrement=False, nullable=True + ), + ) + op.add_column( + "project", + sa.Column( + "default_currency", + sa.String(length=3), + server_default=CurrencyConverter.default, + nullable=True, + ), + ) + op.add_column( + "project_version", + sa.Column( + "default_currency", sa.String(length=3), autoincrement=False, nullable=True + ), + ) + # ### end Alembic commands ### + op.execute( + """ + UPDATE bill + SET converted_amount = amount + WHERE converted_amount IS NULL + """ + ) + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("project_version", "default_currency") + op.drop_column("project", "default_currency") + op.drop_column("bill_version", "original_currency") + op.drop_column("bill_version", "converted_amount") + op.drop_column("bill", "original_currency") + op.drop_column("bill", "converted_amount") + # ### end Alembic commands ### diff --git a/ihatemoney/models.py b/ihatemoney/models.py index 742bc8ca..9e474c60 100644 --- a/ihatemoney/models.py +++ b/ihatemoney/models.py @@ -71,6 +71,7 @@ class Project(db.Model): members = db.relationship("Person", backref="project") query_class = ProjectQuery + default_currency = db.Column(db.String(3)) @property def _to_serialize(self): @@ -80,6 +81,7 @@ class Project(db.Model): "contact_email": self.contact_email, "logging_preference": self.logging_preference.value, "members": [], + "default_currency": self.default_currency, } balance = self.balance @@ -128,7 +130,10 @@ class Project(db.Model): { "member": member, "paid": sum( - [bill.amount for bill in self.get_member_bills(member.id).all()] + [ + bill.converted_amount + for bill in self.get_member_bills(member.id).all() + ] ), "spent": sum( [ @@ -151,7 +156,7 @@ class Project(db.Model): """ monthly = defaultdict(lambda: defaultdict(float)) for bill in self.get_bills().all(): - monthly[bill.date.year][bill.date.month] += bill.amount + monthly[bill.date.year][bill.date.month] += bill.converted_amount return monthly @property @@ -432,6 +437,9 @@ class Bill(db.Model): what = db.Column(db.UnicodeText) external_link = db.Column(db.UnicodeText) + original_currency = db.Column(db.String(3)) + converted_amount = db.Column(db.Float) + archive = db.Column(db.Integer, db.ForeignKey("archive.id")) @property @@ -445,9 +453,11 @@ class Bill(db.Model): "creation_date": self.creation_date, "what": self.what, "external_link": self.external_link, + "original_currency": self.original_currency, + "converted_amount": self.converted_amount, } - def pay_each(self): + def pay_each_default(self, amount): """Compute what each share has to pay""" if self.owers: weights = ( @@ -455,13 +465,16 @@ class Bill(db.Model): .join(billowers, Bill) .filter(Bill.id == self.id) ).scalar() - return self.amount / weights + return amount / weights else: return 0 def __str__(self): return self.what + def pay_each(self): + return self.pay_each_default(self.converted_amount) + def __repr__(self): return ( f" + {{ input(form.default_currency) }}
{{ _("delete") }} @@ -122,6 +124,9 @@ {{ input(form.what, inline=True) }} {{ input(form.payer, inline=True, class="form-control custom-select") }} {{ input(form.amount, inline=True) }} + {% if not form.original_currency.render_kw %} + {{ input(form.original_currency, inline=True) }} + {% endif %} {{ input(form.external_link, inline=True) }}
diff --git a/ihatemoney/templates/history.html b/ihatemoney/templates/history.html index 1ac3284f..a9a9a4db 100644 --- a/ihatemoney/templates/history.html +++ b/ihatemoney/templates/history.html @@ -225,6 +225,10 @@ {{ simple_property_change(event, _("Amount")) }} {% elif event.prop_changed == "date" %} {{ simple_property_change(event, _("Date")) }} + {% elif event.prop_changed == "original_currency" %} + {{ simple_property_change(event, _("Currency")) }} + {% elif event.prop_changed == "converted_amount" %} + {{ simple_property_change(event, _("Amount in %(currency)s", currency=g.project.default_currency)) }} {% else %} {{ describe_object(event) }} {{ _("modified") }} {% endif %} diff --git a/ihatemoney/templates/list_bills.html b/ihatemoney/templates/list_bills.html index 0f2a68a5..95088eb3 100644 --- a/ihatemoney/templates/list_bills.html +++ b/ihatemoney/templates/list_bills.html @@ -111,7 +111,19 @@
- + + + {% for bill in bills.items %} @@ -130,7 +142,14 @@ {%- else -%} {{ bill.owers|join(', ', 'name') }} {%- endif %} - + + - {% for stat in members_stats| sort(attribute='member.name') %} + {% for stat in members_stats|sort(attribute='member.name') %}
{{ _("When?") }}{{ _("Who paid?") }}{{ _("For what?") }}{{ _("For whom?") }}{{ _("How much?") }}{{ _("Actions") }}
{{ _("When?") }} + {{ _("Who paid?") }} + {{ _("For what?") }} + {{ _("For whom?") }} + {{ _("How much?") }} + {% if g.project.default_currency != "No Currency" %} + {{ _("Amount in %(currency)s", currency=g.project.default_currency) }} + {%- else -%} + {{ _("Amount") }} + {% endif %} + {{ _("Actions") }}
{{ "%0.2f"|format(bill.amount) }} ({{ "%0.2f"|format(bill.pay_each()) }} {{ _("each") }}) + {% if bill.original_currency != "No Currency" %} + {{ "%0.2f"|format(bill.amount) }} {{bill.original_currency}} ({{ "%0.2f"|format(bill.pay_each_default(bill.amount)) }} {{bill.original_currency}} {{ _(" each") }}) + {%- else -%} + {{ "%0.2f"|format(bill.amount) }} ({{ "%0.2f"|format(bill.pay_each_default(bill.amount)) }} {{ _(" each") }}) + {% endif %} + {{ "%0.2f"|format(bill.converted_amount) }} {{ _('edit') }} {{ _('delete') }} diff --git a/ihatemoney/tests/tests.py b/ihatemoney/tests/tests.py index 62cb0485..fb314bfc 100644 --- a/ihatemoney/tests/tests.py +++ b/ihatemoney/tests/tests.py @@ -6,7 +6,7 @@ import json import os from time import sleep import unittest -from unittest.mock import patch +from unittest.mock import MagicMock, patch from flask import session from flask_testing import TestCase @@ -14,6 +14,7 @@ from sqlalchemy import orm from werkzeug.security import check_password_hash, generate_password_hash from ihatemoney import history, models, utils +from ihatemoney.currency_convertor import CurrencyConverter from ihatemoney.manage import DeleteProject, GenerateConfig, GeneratePasswordHash from ihatemoney.run import create_app, db, load_configuration from ihatemoney.versioning import LoggingMode @@ -59,6 +60,7 @@ class BaseTestCase(TestCase): "id": name, "password": name, "contact_email": f"{name}@notmyidea.org", + "default_currency": "USD", }, ) @@ -68,6 +70,7 @@ class BaseTestCase(TestCase): 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() @@ -254,6 +257,7 @@ class BudgetTestCase(IhatemoneyTestCase): "id": "raclette", "password": "party", "contact_email": "raclette@notmyidea.org", + "default_currency": "USD", }, ) @@ -273,6 +277,7 @@ class BudgetTestCase(IhatemoneyTestCase): "id": "raclette", # already used ! "password": "party", "contact_email": "raclette@notmyidea.org", + "default_currency": "USD", }, ) @@ -290,6 +295,7 @@ class BudgetTestCase(IhatemoneyTestCase): "id": "raclette", "password": "party", "contact_email": "raclette@notmyidea.org", + "default_currency": "USD", }, ) @@ -310,6 +316,7 @@ class BudgetTestCase(IhatemoneyTestCase): "id": "raclette", "password": "party", "contact_email": "raclette@notmyidea.org", + "default_currency": "USD", }, ) @@ -329,6 +336,7 @@ class BudgetTestCase(IhatemoneyTestCase): "id": "raclette", "password": "party", "contact_email": "raclette@notmyidea.org", + "default_currency": "USD", }, ) @@ -841,6 +849,7 @@ class BudgetTestCase(IhatemoneyTestCase): "contact_email": "alexis@notmyidea.org", "password": "didoudida", "logging_preference": LoggingMode.ENABLED.value, + "default_currency": "USD", } resp = self.client.post("/raclette/edit", data=new_data, follow_redirects=True) @@ -849,6 +858,7 @@ class BudgetTestCase(IhatemoneyTestCase): self.assertEqual(project.name, new_data["name"]) self.assertEqual(project.contact_email, new_data["contact_email"]) + self.assertEqual(project.default_currency, new_data["default_currency"]) self.assertTrue(check_password_hash(project.password, new_data["password"])) # Editing a project with a wrong email address should fail @@ -1099,6 +1109,7 @@ class BudgetTestCase(IhatemoneyTestCase): "payer": 1, "payed_for": [1, 2, 3, 4], "amount": "10.0", + "original_currency": "USD", }, ) @@ -1110,6 +1121,7 @@ class BudgetTestCase(IhatemoneyTestCase): "payer": 2, "payed_for": [1, 3], "amount": "200", + "original_currency": "USD", }, ) @@ -1121,6 +1133,7 @@ class BudgetTestCase(IhatemoneyTestCase): "payer": 3, "payed_for": [2], "amount": "13.33", + "original_currency": "USD", }, ) @@ -1425,6 +1438,7 @@ class APITestCase(IhatemoneyTestCase): "id": id, "password": password, "contact_email": contact, + "default_currency": "USD", }, ) @@ -1486,6 +1500,7 @@ class APITestCase(IhatemoneyTestCase): "id": "raclette", "password": "raclette", "contact_email": "not-an-email", + "default_currency": "USD", }, ) @@ -1514,6 +1529,7 @@ class APITestCase(IhatemoneyTestCase): "members": [], "name": "raclette", "contact_email": "raclette@notmyidea.org", + "default_currency": "USD", "id": "raclette", "logging_preference": 1, } @@ -1525,6 +1541,7 @@ class APITestCase(IhatemoneyTestCase): "/api/projects/raclette", data={ "contact_email": "yeah@notmyidea.org", + "default_currency": "USD", "password": "raclette", "name": "The raclette party", "project_history": "y", @@ -1542,6 +1559,7 @@ class APITestCase(IhatemoneyTestCase): expected = { "name": "The raclette party", "contact_email": "yeah@notmyidea.org", + "default_currency": "USD", "members": [], "id": "raclette", "logging_preference": 1, @@ -1554,6 +1572,7 @@ class APITestCase(IhatemoneyTestCase): "/api/projects/raclette", data={ "contact_email": "yeah@notmyidea.org", + "default_currency": "USD", "password": "tartiflette", "name": "The raclette party", }, @@ -1776,6 +1795,8 @@ class APITestCase(IhatemoneyTestCase): "amount": 25.0, "date": "2011-08-10", "id": 1, + "converted_amount": 25.0, + "original_currency": "USD", "external_link": "https://raclette.fr", } @@ -1845,6 +1866,8 @@ class APITestCase(IhatemoneyTestCase): "amount": 25.0, "date": "2011-09-10", "external_link": "https://raclette.fr", + "converted_amount": 25.0, + "original_currency": "USD", "id": 1, } @@ -1922,6 +1945,8 @@ class APITestCase(IhatemoneyTestCase): "date": "2011-08-10", "id": id, "external_link": "", + "original_currency": "USD", + "converted_amount": expected_amount, } got = json.loads(req.data.decode("utf-8")) @@ -2064,6 +2089,8 @@ class APITestCase(IhatemoneyTestCase): "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( @@ -2106,6 +2133,7 @@ class APITestCase(IhatemoneyTestCase): "id": "raclette", "name": "raclette", "logging_preference": 1, + "default_currency": "USD", } self.assertStatus(200, req) @@ -2273,6 +2301,7 @@ class HistoryTestCase(IhatemoneyTestCase): "name": "demo", "contact_email": "demo@notmyidea.org", "password": "demo", + "default_currency": "USD", } if logging_preference != LoggingMode.DISABLED: @@ -2327,6 +2356,7 @@ class HistoryTestCase(IhatemoneyTestCase): "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) @@ -2422,6 +2452,7 @@ class HistoryTestCase(IhatemoneyTestCase): "name": "demo2", "contact_email": "demo2@notmyidea.org", "password": "123456", + "default_currency": "USD", } # Keep privacy settings where they were @@ -2850,5 +2881,23 @@ class HistoryTestCase(IhatemoneyTestCase): self.assertEqual(len(history_list), 6) +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() diff --git a/ihatemoney/web.py b/ihatemoney/web.py index 18ce0c7a..bbc98c4d 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -37,10 +37,10 @@ from sqlalchemy_continuum import Operation from werkzeug.exceptions import NotFound from werkzeug.security import check_password_hash, generate_password_hash +from ihatemoney.currency_convertor import CurrencyConverter from ihatemoney.forms import ( AdminAuthenticationForm, AuthenticationForm, - EditProjectForm, InviteForm, MemberForm, PasswordReminder, @@ -48,6 +48,7 @@ from ihatemoney.forms import ( ResetPasswordForm, UploadForm, get_billform_for, + get_editprojectform_for, ) from ihatemoney.history import get_history, get_history_queries from ihatemoney.models import Bill, LoggingMode, Person, Project, db @@ -376,7 +377,7 @@ def reset_password(): @main.route("//edit", methods=["GET", "POST"]) def edit_project(): - edit_form = EditProjectForm() + edit_form = get_editprojectform_for(g.project) import_form = UploadForm() # Import form if import_form.validate_on_submit(): @@ -391,6 +392,18 @@ def edit_project(): # Edit form if edit_form.validate_on_submit(): project = edit_form.update(g.project) + # Update converted currency + if project.default_currency != CurrencyConverter.default: + for bill in project.get_bills(): + + if bill.original_currency == CurrencyConverter.default: + bill.original_currency = project.default_currency + + bill.converted_amount = CurrencyConverter().exchange_currency( + bill.amount, bill.original_currency, project.default_currency + ) + db.session.add(bill) + db.session.add(project) db.session.commit() @@ -478,6 +491,7 @@ def import_project(file, project): form.date = parse(b["date"]) form.payer = id_dict[b["payer_name"]] form.payed_for = owers_id + form.original_currency = b.get("original_currency") db.session.add(form.fake_form(bill, project)) @@ -543,6 +557,7 @@ def demo(): name="demonstration", password=generate_password_hash("demo"), contact_email="demo@notmyidea.org", + default_currency="EUR", ) db.session.add(project) db.session.commit() diff --git a/setup.cfg b/setup.cfg index 50a24a41..d632d515 100644 --- a/setup.cfg +++ b/setup.cfg @@ -23,6 +23,7 @@ include_package_data = True zip_safe = False install_requires = blinker==1.4 + cachetools==4.1.0 debts==0.5 email_validator==1.0.5 Flask-Babel==1.0.0 @@ -37,6 +38,7 @@ install_requires = Flask==1.1.2 itsdangerous==1.1.0 Jinja2==2.11.2 + requests==2.22.0 SQLAlchemy-Continuum==1.3.9 [options.extras_require] From 15ab04e636f1c267da3ef1c6bd4cdc68449b2e97 Mon Sep 17 00:00:00 2001 From: "Weblate (bot)" Date: Sun, 3 May 2020 17:28:27 +0200 Subject: [PATCH 46/47] Translations update from Weblate (#606) Fix #605 --- .../es_419/LC_MESSAGES/messages.po | 156 ++++++++++-------- 1 file changed, 89 insertions(+), 67 deletions(-) diff --git a/ihatemoney/translations/es_419/LC_MESSAGES/messages.po b/ihatemoney/translations/es_419/LC_MESSAGES/messages.po index f6358b02..216edcc6 100644 --- a/ihatemoney/translations/es_419/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/es_419/LC_MESSAGES/messages.po @@ -1,18 +1,18 @@ - msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-04-25 13:02+0200\n" -"PO-Revision-Date: 2019-09-25 22:28+0000\n" -"Last-Translator: Diego Caraballo \n" +"PO-Revision-Date: 2020-05-03 15:20+0000\n" +"Last-Translator: Fabian Rodriguez \n" +"Language-Team: Spanish (Latin America) \n" "Language: es_419\n" -"Language-Team: Spanish (Latin America) " -"\n" -"Plural-Forms: nplurals=2; plural=n != 1\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.1-dev\n" "Generated-By: Babel 2.8.0\n" msgid "" @@ -32,16 +32,16 @@ msgid "Email" msgstr "Correo Electrónico" msgid "Enable project history" -msgstr "" +msgstr "Habilitar historial del proyecto" msgid "Use IP tracking for project history" -msgstr "" +msgstr "Registrar la IPs para el historial del proyecto" msgid "Import previously exported JSON file" -msgstr "" +msgstr "Importar archivo JSON previamente exportado" msgid "Import" -msgstr "" +msgstr "Importar" msgid "Project identifier" msgstr "Identificador de proyecto" @@ -140,10 +140,10 @@ msgid "The email %(email)s is not valid" msgstr "El correo electrónico %(email)s no es válido" msgid "Participant" -msgstr "" +msgstr "Participante" msgid "Bill" -msgstr "" +msgstr "Factura" msgid "Project" msgstr "Proyecto" @@ -186,10 +186,10 @@ msgid "Password successfully reset." msgstr "Contraseña restablecida con éxito." msgid "Project successfully uploaded" -msgstr "" +msgstr "El proyecto se subió exitosamente" msgid "Invalid JSON" -msgstr "" +msgstr "JSON inválido" msgid "Project successfully deleted" msgstr "Proyecto eliminado correctamente" @@ -203,7 +203,7 @@ msgstr "Sus invitaciones han sido enviadas" #, python-format msgid "%(member)s has been added" -msgstr "" +msgstr "Se añadieron %(member)s" #, python-format msgid "%(name)s is part of this project again" @@ -292,10 +292,10 @@ msgid "Edit project" msgstr "Editar proyecto" msgid "Import JSON" -msgstr "" +msgstr "Importar JSON" msgid "Choose file" -msgstr "" +msgstr "Escoger un archivo" msgid "Download project's data" msgstr "Descargar datos del proyecto" @@ -321,7 +321,7 @@ msgid "Cancel" msgstr "Cancelar" msgid "Privacy Settings" -msgstr "" +msgstr "Ajustes de privacidad" msgid "Edit the project" msgstr "Editar el proyecto" @@ -345,7 +345,7 @@ msgid "Edit this member" msgstr "Editar este miembro" msgid "john.doe@example.com, mary.moe@site.com" -msgstr "john.doe@example.com, mary.moe@site.com" +msgstr "juan.perez@example.com, ana.rodriguez@site.com" msgid "Send the invitations" msgstr "Enviar las invitaciones" @@ -354,37 +354,37 @@ msgid "Download" msgstr "Descargar" msgid "Disabled Project History" -msgstr "" +msgstr "Historial de proyecto activo" msgid "Disabled Project History & IP Address Recording" -msgstr "" +msgstr "Historial de proyecto y registros de dirección IP inactivos" msgid "Enabled Project History" -msgstr "" +msgstr "Historial de proyecto activo" msgid "Disabled IP Address Recording" -msgstr "" +msgstr "Registro de direcciones IP activo" msgid "Enabled Project History & IP Address Recording" -msgstr "" +msgstr "Historial de proyecto y registros de dirección IP activos" msgid "Enabled IP Address Recording" -msgstr "" +msgstr "Se activó el registros de dirección IP" msgid "History Settings Changed" -msgstr "" +msgstr "Se cambiaron los ajustes del historial" msgid "changed" -msgstr "" +msgstr "cambió" msgid "from" -msgstr "" +msgstr "de" msgid "to" -msgstr "" +msgstr "a" msgid "Confirm Remove IP Adresses" -msgstr "" +msgstr "Confirmar eliminación de direcciones IP" msgid "" "Are you sure you want to delete all recorded IP addresses from this " @@ -392,32 +392,38 @@ msgid "" " The rest of the project history will be unaffected. This " "action cannot be undone." msgstr "" +"Por favor confirme la eliminación completa del registro de direcciones IP " +"del proyecto.\n" +" El resto de historial del proyecto no será afectado. Este " +"cambio es irreversible." msgid "Close" -msgstr "" +msgstr "Cerrar" msgid "Confirm Delete" -msgstr "" +msgstr "Confirmar eliminación" msgid "Delete Confirmation" -msgstr "" +msgstr "Confirmación de eliminación" msgid "" "Are you sure you want to erase all history for this project? This action " "cannot be undone." msgstr "" +"Por favor confirme la eliminación completa del historial del proyecto. Esta " +"acción es irreversible." msgid "Added" -msgstr "" +msgstr "Agregado" msgid "Removed" -msgstr "" +msgstr "Eliminado" msgid "and" -msgstr "" +msgstr "y" msgid "owers list" -msgstr "" +msgstr "lista de deudores" msgid "Who?" msgstr "¿Quién?" @@ -433,6 +439,12 @@ msgid "" " settings page\n" " " msgstr "" +"\n" +" El historial de este proyecto ha sido desactivado. Nuevas " +"operaciones no apareceran a continuacion. El historial se puede agregar " +"\n" +" en la página de ajustes\n" +" " msgid "" "\n" @@ -443,86 +455,96 @@ msgid "" "them.

\n" " " msgstr "" +"\n" +" Este registro muestra la actividad previa a la desactivación " +"del historial del proyecto. Use la opción \n" +" Eliminar historial del proyecto para " +"borrarlo.

\n" +" " msgid "" "Some entries below contain IP addresses, even though this project has IP " "recording disabled. " msgstr "" +"Algunos registros contienen direcciones IP, a pesar de que el registro de " +"direcciones IP del proyecto no está activo. " msgid "Delete stored IP addresses" -msgstr "" +msgstr "Borrar las direcciones IP registradas" msgid "No history to erase" -msgstr "" +msgstr "No hay historial para borrar" msgid "Clear Project History" -msgstr "" +msgstr "Borrar el historial del proyecto" msgid "No IP Addresses to erase" -msgstr "" +msgstr "No hay direcciones IP para borrar" msgid "Delete Stored IP Addresses" -msgstr "" +msgstr "Borrar direcciones IP registradas" msgid "Time" -msgstr "" +msgstr "Hora" msgid "Event" -msgstr "" +msgstr "Evento" msgid "IP address recording can be enabled on the settings page" -msgstr "" +msgstr "El registro de direcciones IP se puede activar en la página de ajustes" msgid "IP address recording can be disabled on the settings page" msgstr "" +"El registro de direcciones IP se puede desactivar en la página de ajustes" msgid "From IP" -msgstr "" +msgstr "IP de origen" msgid "added" -msgstr "" +msgstr "agregado" msgid "Project private code changed" -msgstr "" +msgstr "Se cambió el código privado del proyecto" msgid "Project renamed to" -msgstr "" +msgstr "Se cambió el nombre del proyecto a" msgid "Project contact email changed to" -msgstr "" +msgstr "Se cambió el correo electrónico de contacto a" msgid "Project settings modified" -msgstr "" +msgstr "Ajustes del proyecto modificados" msgid "deactivated" -msgstr "" +msgstr "desactivado" msgid "reactivated" -msgstr "" +msgstr "reactivado" msgid "renamed to" -msgstr "" +msgstr "se cambió de nombre a" msgid "External link changed to" -msgstr "" +msgstr "Se cambió el enlace externo por" msgid "Amount" -msgstr "" +msgstr "Monto" msgid "modified" -msgstr "" +msgstr "modificado" msgid "removed" -msgstr "" +msgstr "removido" msgid "changed in a unknown way" -msgstr "" +msgstr "se cambió de manera desconocida" msgid "Nothing to list" -msgstr "" +msgstr "Nada por listar" msgid "Someone probably cleared the project history." -msgstr "" +msgstr "Es probable que alguien borrara el historial del proyecto." msgid "Manage your shared
expenses, easily" msgstr "Gestione sus gastos compartidos
fácilmente" @@ -574,7 +596,7 @@ msgid "Statistics" msgstr "Estadísticas" msgid "History" -msgstr "" +msgstr "Historial" msgid "Settings" msgstr "Configuración" @@ -634,10 +656,10 @@ msgid "Add a new bill" msgstr "Añadir una nueva factura" msgid "Newer bills" -msgstr "" +msgstr "Nuevas facturas" msgid "Older bills" -msgstr "" +msgstr "Facturas anteriores" msgid "When?" msgstr "¿Cuando?" @@ -691,7 +713,7 @@ msgstr "" "correos electrónicos." msgid "Return to home page" -msgstr "Regresar a la página principal" +msgstr "Regresar al inicio" msgid "Your projects" msgstr "Sus proyectos" @@ -750,10 +772,10 @@ msgid "Spent" msgstr "Gastado" msgid "Expenses by Month" -msgstr "" +msgstr "Gastos por mes" msgid "Period" -msgstr "" +msgstr "Período" #~ msgid "%(member)s had been added" #~ msgstr "se han añadido %(member)s" From 795efd6b58a0d4eec002eddeb4c9b0b16461a4a0 Mon Sep 17 00:00:00 2001 From: zorun Date: Mon, 4 May 2020 23:06:35 +0200 Subject: [PATCH 47/47] Fix order of participants in the statistics page (#608) This fixes #607 and add a test case for this bug. It also renames participants in test cases to avoid alphabetical ordering. Inserting participants in alphabetical order is a special case, because ordering by ID will be the same as ordering by name. This is a bad idea in test cases, as #607 has shown. --- ihatemoney/templates/statistics.html | 4 +- ihatemoney/tests/tests.py | 206 +++++++++++++-------------- 2 files changed, 100 insertions(+), 110 deletions(-) diff --git a/ihatemoney/templates/statistics.html b/ihatemoney/templates/statistics.html index 73211883..b38abb12 100644 --- a/ihatemoney/templates/statistics.html +++ b/ihatemoney/templates/statistics.html @@ -9,7 +9,7 @@
{{ _("Balance") }}
{{ stat.member.name }} @@ -27,7 +27,7 @@ - {% for stat in members_stats %} + {% for stat in members_stats|sort(attribute='member.name') %} diff --git a/ihatemoney/tests/tests.py b/ihatemoney/tests/tests.py index fb314bfc..b13c7c07 100644 --- a/ihatemoney/tests/tests.py +++ b/ihatemoney/tests/tests.py @@ -4,6 +4,7 @@ import datetime import io import json import os +import re from time import sleep import unittest from unittest.mock import MagicMock, patch @@ -141,24 +142,24 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") self.client.post( - "/raclette/invite", data={"emails": "alexis@notmyidea.org"} + "/raclette/invite", data={"emails": "zorglub@notmyidea.org"} ) self.assertEqual(len(outbox), 2) self.assertEqual(outbox[0].recipients, ["raclette@notmyidea.org"]) - self.assertEqual(outbox[1].recipients, ["alexis@notmyidea.org"]) + self.assertEqual(outbox[1].recipients, ["zorglub@notmyidea.org"]) # sending a message to multiple persons with self.app.mail.record_messages() as outbox: self.client.post( "/raclette/invite", - data={"emails": "alexis@notmyidea.org, toto@notmyidea.org"}, + data={"emails": "zorglub@notmyidea.org, toto@notmyidea.org"}, ) # only one message is sent to multiple persons self.assertEqual(len(outbox), 1) self.assertEqual( - outbox[0].recipients, ["alexis@notmyidea.org", "toto@notmyidea.org"] + outbox[0].recipients, ["zorglub@notmyidea.org", "toto@notmyidea.org"] ) # mail address checking @@ -170,7 +171,7 @@ class BudgetTestCase(IhatemoneyTestCase): # mixing good and wrong addresses shouldn't send any messages with self.app.mail.record_messages() as outbox: self.client.post( - "/raclette/invite", data={"emails": "alexis@notmyidea.org, alexis"} + "/raclette/invite", data={"emails": "zorglub@notmyidea.org, zorglub"} ) # not valid # only one message is sent to multiple persons @@ -360,7 +361,7 @@ class BudgetTestCase(IhatemoneyTestCase): result.data.decode("utf-8"), ) - result = self.client.post("/raclette/members/add", data={"name": "alexis"}) + result = self.client.post("/raclette/members/add", data={"name": "zorglub"}) result = self.client.get("/raclette/") @@ -374,11 +375,11 @@ class BudgetTestCase(IhatemoneyTestCase): self.login("raclette") # adds a member to this project - self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post("/raclette/members/add", data={"name": "zorglub"}) self.assertEqual(len(models.Project.query.get("raclette").members), 1) # adds him twice - result = self.client.post("/raclette/members/add", data={"name": "alexis"}) + result = self.client.post("/raclette/members/add", data={"name": "zorglub"}) # should not accept him self.assertEqual(len(models.Project.query.get("raclette").members), 1) @@ -449,11 +450,11 @@ class BudgetTestCase(IhatemoneyTestCase): self.login("raclette") # adds a member to this project - self.client.post("/raclette/members/add", data={"name": "alexis"}) - alexis = models.Project.query.get("raclette").members[-1] + self.client.post("/raclette/members/add", data={"name": "zorglub"}) + zorglub = models.Project.query.get("raclette").members[-1] # should not have any bills - self.assertFalse(alexis.has_bills()) + self.assertFalse(zorglub.has_bills()) # bound him to a bill self.client.post( @@ -461,22 +462,22 @@ class BudgetTestCase(IhatemoneyTestCase): data={ "date": "2011-08-10", "what": "fromage à raclette", - "payer": alexis.id, - "payed_for": [alexis.id], + "payer": zorglub.id, + "payed_for": [zorglub.id], "amount": "25", }, ) # should have a bill now - alexis = models.Project.query.get("raclette").members[-1] - self.assertTrue(alexis.has_bills()) + zorglub = models.Project.query.get("raclette").members[-1] + self.assertTrue(zorglub.has_bills()) def test_member_delete_method(self): self.post_project("raclette") self.login("raclette") # adds a member to this project - self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post("/raclette/members/add", data={"name": "zorglub"}) # try to remove the member using GET method response = self.client.get("/raclette/members/1/delete") @@ -604,7 +605,7 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") # add two persons - self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post("/raclette/members/add", data={"name": "zorglub"}) self.client.post("/raclette/members/add", data={"name": "fred"}) members_ids = [m.id for m in models.Project.query.get("raclette").members] @@ -712,7 +713,7 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") # add two persons - self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post("/raclette/members/add", data={"name": "zorglub"}) self.client.post( "/raclette/members/add", data={"name": "freddy familly", "weight": 4} ) @@ -749,8 +750,8 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") # Add two times the same person (with a space at the end). - self.client.post("/raclette/members/add", data={"name": "alexis"}) - self.client.post("/raclette/members/add", data={"name": "alexis "}) + self.client.post("/raclette/members/add", data={"name": "zorglub"}) + self.client.post("/raclette/members/add", data={"name": "zorglub "}) members = models.Project.query.get("raclette").members self.assertEqual(len(members), 1) @@ -759,7 +760,7 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") # add two persons - self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post("/raclette/members/add", data={"name": "zorglub"}) self.client.post("/raclette/members/add", data={"name": "tata", "weight": 1}) resp = self.client.get("/raclette/") @@ -776,9 +777,9 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") # Add one user and edit it to have a negative share - self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post("/raclette/members/add", data={"name": "zorglub"}) resp = self.client.post( - "/raclette/members/1/edit", data={"name": "alexis", "weight": -1} + "/raclette/members/1/edit", data={"name": "zorglub", "weight": -1} ) # An error should be generated, and its weight should still be 1. @@ -790,7 +791,7 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") # add members - self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post("/raclette/members/add", data={"name": "zorglub"}) self.client.post("/raclette/members/add", data={"name": "fred"}) self.client.post("/raclette/members/add", data={"name": "tata"}) @@ -846,7 +847,7 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") new_data = { "name": "Super raclette party!", - "contact_email": "alexis@notmyidea.org", + "contact_email": "zorglub@notmyidea.org", "password": "didoudida", "logging_preference": LoggingMode.ENABLED.value, "default_currency": "USD", @@ -898,11 +899,11 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") # add members - self.client.post("/raclette/members/add", data={"name": "alexis", "weight": 2}) + 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": "toto"}) + self.client.post("/raclette/members/add", data={"name": "pépé"}) # create bills self.client.post( @@ -939,45 +940,34 @@ class BudgetTestCase(IhatemoneyTestCase): ) response = self.client.get("/raclette/statistics") - first_cell = '" - + indent - + "" - + indent - + "\n", - response.data.decode("utf-8"), + regex = r"\s+\s+" + self.assertRegex( + response.data.decode("utf-8"), regex.format("zorglub", "20.00", "31.67"), ) - self.assertIn( - first_cell - + "fred" - + indent - + "" - + indent - + "\n", - response.data.decode("utf-8"), + self.assertRegex( + response.data.decode("utf-8"), regex.format("fred", "20.00", "5.83"), ) - self.assertIn( - first_cell - + "tata" - + indent - + "" - + indent - + "\n", - response.data.decode("utf-8"), + self.assertRegex( + response.data.decode("utf-8"), regex.format("tata", "0.00", "2.50"), ) - self.assertIn( - first_cell - + "toto" - + indent - + "" - + indent - + "\n", - response.data.decode("utf-8"), + self.assertRegex( + response.data.decode("utf-8"), regex.format("pépé", "0.00", "0.00"), ) + # Check that the order of participants in the sidebar table is the + # same as in the main table. + order = ["fred", "pépé", "tata", "zorglub"] + regex1 = r".*".join( + r"".format(name) for name in order + ) + regex2 = r".*".join( + r"".format(name) for name in order + ) + # Build the regexp ourselves to be able to pass the DOTALL flag + # (so that ".*" matches newlines) + self.assertRegex(response.data.decode("utf-8"), re.compile(regex1, re.DOTALL)) + self.assertRegex(response.data.decode("utf-8"), re.compile(regex2, re.DOTALL)) + def test_settle_page(self): self.post_project("raclette") response = self.client.get("/raclette/settle_bills") @@ -987,11 +977,11 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") # add members - self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post("/raclette/members/add", data={"name": "zorglub"}) 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": "toto"}) + self.client.post("/raclette/members/add", data={"name": "pépé"}) # create bills self.client.post( @@ -1042,7 +1032,7 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") # add members - self.client.post("/raclette/members/add", data={"name": "alexis"}) + self.client.post("/raclette/members/add", data={"name": "zorglub"}) self.client.post("/raclette/members/add", data={"name": "fred"}) self.client.post("/raclette/members/add", data={"name": "tata"}) @@ -1095,7 +1085,7 @@ class BudgetTestCase(IhatemoneyTestCase): self.post_project("raclette") # add members - self.client.post("/raclette/members/add", data={"name": "alexis", "weight": 2}) + 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"}) self.client.post("/raclette/members/add", data={"name": "pépé"}) @@ -1154,15 +1144,15 @@ class BudgetTestCase(IhatemoneyTestCase): "amount": 200.0, "payer_name": "fred", "payer_weight": 1.0, - "owers": ["alexis", "tata"], + "owers": ["zorglub", "tata"], }, { "date": "2016-12-31", "what": "fromage \xe0 raclette", "amount": 10.0, - "payer_name": "alexis", + "payer_name": "zorglub", "payer_weight": 2.0, - "owers": ["alexis", "fred", "tata", "p\xe9p\xe9"], + "owers": ["zorglub", "fred", "tata", "p\xe9p\xe9"], }, ] self.assertEqual(json.loads(resp.data.decode("utf-8")), expected) @@ -1172,8 +1162,8 @@ class BudgetTestCase(IhatemoneyTestCase): expected = [ "date,what,amount,payer_name,payer_weight,owers", "2017-01-01,refund,13.33,tata,1.0,fred", - '2016-12-31,red wine,200.0,fred,1.0,"alexis, tata"', - '2016-12-31,fromage à raclette,10.0,alexis,2.0,"alexis, fred, tata, pépé"', + '2016-12-31,red wine,200.0,fred,1.0,"zorglub, tata"', + '2016-12-31,fromage à raclette,10.0,zorglub,2.0,"zorglub, fred, tata, pépé"', ] received_lines = resp.data.decode("utf-8").split("\n") @@ -1187,7 +1177,7 @@ class BudgetTestCase(IhatemoneyTestCase): expected = [ {"amount": 2.00, "receiver": "fred", "ower": "p\xe9p\xe9"}, {"amount": 55.34, "receiver": "fred", "ower": "tata"}, - {"amount": 127.33, "receiver": "fred", "ower": "alexis"}, + {"amount": 127.33, "receiver": "fred", "ower": "zorglub"}, ] self.assertEqual(json.loads(resp.data.decode("utf-8")), expected) @@ -1199,7 +1189,7 @@ class BudgetTestCase(IhatemoneyTestCase): "amount,receiver,ower", "2.0,fred,pépé", "55.34,fred,tata", - "127.33,fred,alexis", + "127.33,fred,zorglub", ] received_lines = resp.data.decode("utf-8").split("\n") @@ -1235,15 +1225,15 @@ class BudgetTestCase(IhatemoneyTestCase): "amount": 200.0, "payer_name": "fred", "payer_weight": 1.0, - "owers": ["alexis", "tata"], + "owers": ["zorglub", "tata"], }, { "date": "2016-12-31", "what": "fromage a raclette", "amount": 10.0, - "payer_name": "alexis", + "payer_name": "zorglub", "payer_weight": 2.0, - "owers": ["alexis", "fred", "tata", "pepe"], + "owers": ["zorglub", "fred", "tata", "pepe"], }, ] @@ -1291,7 +1281,7 @@ class BudgetTestCase(IhatemoneyTestCase): project = models.Project.query.get("raclette") - self.client.post("/raclette/members/add", data={"name": "alexis", "weight": 2}) + 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"}) self.client.post( @@ -1320,15 +1310,15 @@ class BudgetTestCase(IhatemoneyTestCase): "amount": 200.0, "payer_name": "fred", "payer_weight": 1.0, - "owers": ["alexis", "tata"], + "owers": ["zorglub", "tata"], }, { "date": "2016-12-31", "what": "fromage a raclette", "amount": 10.0, - "payer_name": "alexis", + "payer_name": "zorglub", "payer_weight": 2.0, - "owers": ["alexis", "fred", "tata", "pepe"], + "owers": ["zorglub", "fred", "tata", "pepe"], }, ] @@ -1648,7 +1638,7 @@ class APITestCase(IhatemoneyTestCase): # add a member req = self.client.post( "/api/projects/raclette/members", - data={"name": "Alexis"}, + data={"name": "Zorglub"}, headers=self.get_auth("raclette"), ) @@ -1667,7 +1657,7 @@ class APITestCase(IhatemoneyTestCase): # Try to add another member with the same name. req = self.client.post( "/api/projects/raclette/members", - data={"name": "Alexis"}, + data={"name": "Zorglub"}, headers=self.get_auth("raclette"), ) self.assertStatus(400, req) @@ -1748,9 +1738,9 @@ class APITestCase(IhatemoneyTestCase): self.api_create("raclette") # add members - self.api_add_member("raclette", "alexis") + self.api_add_member("raclette", "zorglub") self.api_add_member("raclette", "fred") - self.api_add_member("raclette", "arnaud") + self.api_add_member("raclette", "quentin") # get the list of bills (should be empty) req = self.client.get( @@ -1789,7 +1779,7 @@ class APITestCase(IhatemoneyTestCase): "what": "fromage", "payer_id": 1, "owers": [ - {"activated": True, "id": 1, "name": "alexis", "weight": 1}, + {"activated": True, "id": 1, "name": "zorglub", "weight": 1}, {"activated": True, "id": 2, "name": "fred", "weight": 1}, ], "amount": 25.0, @@ -1860,7 +1850,7 @@ class APITestCase(IhatemoneyTestCase): "what": "beer", "payer_id": 2, "owers": [ - {"activated": True, "id": 1, "name": "alexis", "weight": 1}, + {"activated": True, "id": 1, "name": "zorglub", "weight": 1}, {"activated": True, "id": 2, "name": "fred", "weight": 1}, ], "amount": 25.0, @@ -1896,7 +1886,7 @@ class APITestCase(IhatemoneyTestCase): self.api_create("raclette") # add members - self.api_add_member("raclette", "alexis") + self.api_add_member("raclette", "zorglub") self.api_add_member("raclette", "fred") # valid amounts @@ -1938,7 +1928,7 @@ class APITestCase(IhatemoneyTestCase): "what": "fromage", "payer_id": 1, "owers": [ - {"activated": True, "id": 1, "name": "alexis", "weight": 1}, + {"activated": True, "id": 1, "name": "zorglub", "weight": 1}, {"activated": True, "id": 2, "name": "fred", "weight": 1}, ], "amount": expected_amount, @@ -1985,7 +1975,7 @@ class APITestCase(IhatemoneyTestCase): self.api_create("raclette") # add members - self.api_add_member("raclette", "alexis") + self.api_add_member("raclette", "zorglub") self.api_add_member("raclette", "fred") # add a bill @@ -2013,7 +2003,7 @@ class APITestCase(IhatemoneyTestCase): "member": { "activated": True, "id": 1, - "name": "alexis", + "name": "zorglub", "weight": 1.0, }, "paid": 25.0, @@ -2051,9 +2041,9 @@ class APITestCase(IhatemoneyTestCase): self.api_create("raclette") # add members - self.api_add_member("raclette", "alexis") + self.api_add_member("raclette", "zorglub") self.api_add_member("raclette", "freddy familly", 4) - self.api_add_member("raclette", "arnaud") + self.api_add_member("raclette", "quentin") # add a bill req = self.client.post( @@ -2082,7 +2072,7 @@ class APITestCase(IhatemoneyTestCase): "what": "fromage", "payer_id": 1, "owers": [ - {"activated": True, "id": 1, "name": "alexis", "weight": 1}, + {"activated": True, "id": 1, "name": "zorglub", "weight": 1}, {"activated": True, "id": 2, "name": "freddy familly", "weight": 4}, ], "amount": 25.0, @@ -2110,7 +2100,7 @@ class APITestCase(IhatemoneyTestCase): { "activated": True, "id": 1, - "name": "alexis", + "name": "zorglub", "weight": 1.0, "balance": 20.0, }, @@ -2124,7 +2114,7 @@ class APITestCase(IhatemoneyTestCase): { "activated": True, "id": 3, - "name": "arnaud", + "name": "quentin", "weight": 1.0, "balance": 0, }, @@ -2146,12 +2136,12 @@ class APITestCase(IhatemoneyTestCase): self.login("raclette") # add members - self.api_add_member("raclette", "alexis") + 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('alexis')} added", resp.data.decode("utf-8") + f"Participant {em_surround('zorglub')} added", resp.data.decode("utf-8") ) self.assertIn( f"Project {em_surround('raclette')} added", resp.data.decode("utf-8"), @@ -2216,11 +2206,11 @@ class ModelsTestCase(IhatemoneyTestCase): self.post_project("raclette") # add members - self.client.post("/raclette/members/add", data={"name": "alexis", "weight": 2}) + 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": "toto"}) + self.client.post("/raclette/members/add", data={"name": "pépé"}) # create bills self.client.post( @@ -2257,11 +2247,11 @@ class ModelsTestCase(IhatemoneyTestCase): ) project = models.Project.query.get_by_name(name="raclette") - alexis = models.Person.query.get_by_name(name="alexis", project=project) - alexis_bills = models.Bill.query.options( + 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(alexis)) - for bill in alexis_bills.all(): + ).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) @@ -2466,7 +2456,7 @@ class HistoryTestCase(IhatemoneyTestCase): # adds a member to this project resp = self.client.post( - "/demo/members/add", data={"name": "alexis"}, follow_redirects=True + "/demo/members/add", data={"name": "zorglub"}, follow_redirects=True ) self.assertEqual(resp.status_code, 200) @@ -2602,14 +2592,14 @@ class HistoryTestCase(IhatemoneyTestCase): def test_logs_for_common_actions(self): # adds a member to this project resp = self.client.post( - "/demo/members/add", data={"name": "alexis"}, follow_redirects=True + "/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('alexis')} added", resp.data.decode("utf-8") + f"Participant {em_surround('zorglub')} added", resp.data.decode("utf-8") ) # create a bill @@ -2698,19 +2688,19 @@ class HistoryTestCase(IhatemoneyTestCase): resp.data.decode("utf-8"), r"Participant %s:\s* Weight changed\s* from %s\s* to %s" % ( - em_surround("alexis", regex_escape=True), + 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("alexis"), em_surround("new name"),), + % (em_surround("zorglub"), em_surround("new name"),), resp.data.decode("utf-8"), ) self.assertLess( resp.data.decode("utf-8").index( - f"Participant {em_surround('alexis')} renamed" + f"Participant {em_surround('zorglub')} renamed" ), resp.data.decode("utf-8").index("Weight changed"), )
{{ _("Who?") }}{{ _("Paid") }}{{ _("Spent") }}
{{ stat.member.name }} {{ "%0.2f"|format(stat.paid) }}' - indent = "\n " - self.assertIn( - first_cell - + "alexis20.0031.67{}{}{}20.005.830.002.500.000.00{}{}