From 94a472be96e45b758cdf181c5f2b33cacf1da1a6 Mon Sep 17 00:00:00 2001 From: Jwen921 Date: Wed, 11 Nov 2020 17:28:44 +0100 Subject: [PATCH 01/47] Translated using Weblate (Japanese) Currently translated at 100.0% (231 of 231 strings) Translated using Weblate (Japanese) Currently translated at 77.9% (180 of 231 strings) Co-authored-by: Jwen921 Translate-URL: https://hosted.weblate.org/projects/i-hate-money/i-hate-money/ja/ Translation: I Hate Money/I Hate Money --- .../translations/ja/LC_MESSAGES/messages.mo | Bin 3113 -> 20661 bytes .../translations/ja/LC_MESSAGES/messages.po | 398 +++++++++--------- 2 files changed, 206 insertions(+), 192 deletions(-) diff --git a/ihatemoney/translations/ja/LC_MESSAGES/messages.mo b/ihatemoney/translations/ja/LC_MESSAGES/messages.mo index f65e99cb897b5ebcfde6236fa8c49f0f3a0e3dc7..42d4e701026496307a1f8eb00b943904935ddf58 100644 GIT binary patch literal 20661 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 delta 1281 zcmY+??{8C87{Ku}?AVw%VPm*%gWb86&dFe7V|E5DOavhWkPwL>!<6+RjqNSz+5wSd zX&Vg#mOviy2Z`Wh=;YTRgb;DWnCO3CjIT`0rDMc6Ul3pT&hOLRnRs%~`J7)p=k%QC z?pVn;wZp$v`OX_sfZRadTw=_6j4z-dZG6g@Zrp_ZID~xWXNpSv6`#gOSdCAx3d?-P zlw%$8nP!S5*ovjti_47}Heo8y(D4>7!YD38$1{U1v`-+P8Kc;PU!iXB57yuUR$Yp< zs2j9VEXEF8fv=z*Y`@p&)(Phq|uJ-%L}{iIt41HCT@gsQ)a4?YI-4#S^Ft zory1xlBbDzJaUo0qOxBdg=og4}>e} z520?n5A|RNuno`PTD<3tKl1u#QP=nL9$ZxMHofo~E-t9=M%R*85}&COwmjvGftXzENc2<@%W%M5OIQO z>!58pnRr~1{>JLGZ8qD7BAIyFdM%Sm+0MXmxme%Wax879oJib?$DH@fmSoC0dN`Q~ zo2_=*iaBOm;z%-;mh6gEzMYYTEx)YXE7uykmK?WJW_Kz!6iM6GKr(7e(h67Zu?P9p z{Hf$(Q-d@GnxraNFK2@-@<(f{Y*>AuyrbLd486SWr8{4)-d9rIwPsy=)E=sk*^ZD% z=euPy-#;jv`ohQ$Z`4+p>5nF-N6tSU8x?~C;Tyb-!jhh?SnfcG%{FIwN zDS-`L3kzpQ3nQcAdv(7A!h8L5n?AgM-%MZlWM*Q@%`ua;(rGI;ewC?Ep7lWns(f|Me diff --git a/ihatemoney/translations/ja/LC_MESSAGES/messages.po b/ihatemoney/translations/ja/LC_MESSAGES/messages.po index 543c4190..822c09f8 100644 --- a/ihatemoney/translations/ja/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/ja/LC_MESSAGES/messages.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-10-22 06:40+0200\n" -"PO-Revision-Date: 2020-11-04 17:27+0000\n" +"PO-Revision-Date: 2020-11-11 16:28+0000\n" "Last-Translator: Jwen921 \n" "Language-Team: Japanese \n" @@ -12,7 +12,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.3.2-dev\n" +"X-Generator: Weblate 4.4-dev\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " @@ -129,282 +129,283 @@ msgid "Add" msgstr "追加" msgid "User name incorrect" -msgstr "" +msgstr "ユーザー名が正しくない" msgid "This project already have this member" -msgstr "" +msgstr "プロジェクトはすでにこのメンバーを含めています" msgid "People to notify" -msgstr "" +msgstr "知らせたい人" msgid "Send invites" -msgstr "" +msgstr "招待状を出す" #, python-format msgid "The email %(email)s is not valid" -msgstr "" +msgstr "メールアドレス%(email)sは無効" msgid "Participant" -msgstr "" +msgstr "参加者" msgid "Bill" -msgstr "" +msgstr "明細" msgid "Project" -msgstr "" +msgstr "プロジェクト" msgid "No Currency" -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 "" +msgstr "この管理者パスワードは正しくないでウ。%(num)d試行しか残っていません。" msgid "You either provided a bad token or no project identifier." -msgstr "" +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が作られました" msgid "A reminder email has just been sent to you" -msgstr "" +msgstr "催促メールがただいまあなたに送りました" msgid "" "We tried to send you an reminder email, but there was an error. You can " "still use the project normally." -msgstr "" +msgstr "催促メールを送った時、エラーが発生しました。このプロジェクトはまだ使えます。" #, python-format msgid "The project identifier is %(project)s" -msgstr "" +msgstr "プロジェクト名は%(project)s" msgid "" "Sorry, there was an error while sending you an email with password reset " "instructions. Please check the email configuration of the server or " "contact the administrator." msgstr "" +"申し訳ございませんが、パスワード再設定の説明メールを送った時、エラーが発生しました。メールアドレスを一度確認してまたは管理者に連絡してください。" msgid "No token provided" -msgstr "" +msgstr "印が入力されていない" msgid "Invalid token" -msgstr "" +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 "あなたの招待状が送られました" msgid "" "Sorry, there was an error while trying to send the invitation emails. " "Please check the email configuration of the server or contact the " "administrator." -msgstr "" +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 "" +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 "" +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 "show" -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 " @@ -412,32 +413,34 @@ 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 "" +msgstr "本当にこのプロジェクトの歴史をすべて消しますか。この操作は元に戻せません。" msgid "Added" -msgstr "" +msgstr "追加された" msgid "Removed" -msgstr "" +msgstr "取り除かれた" msgid "and" -msgstr "" +msgstr "と" msgid "owers list" -msgstr "" +msgstr "全員リスト" #, python-format msgid "" @@ -447,6 +450,10 @@ msgid "" " settings page\n" " " msgstr "" +"\n" +" このプロジェクトの歴史は操作できません。新しい操作は下に出ません。で歴史を操作可能にすることができます。\n" +"設定ページ\n" +" " msgid "" "\n" @@ -457,279 +464,284 @@ msgid "" "them.

\n" " " msgstr "" +"\n" +" 下の表では操作不可になる前に、プロジェクトの歴史に対して記録された操作が反映されています。…できます。\n" +"プロジェクトの歴史を取り除く で取り除きます.

\n" +" " msgid "" "Some entries below contain IP addresses, even though this project has IP " "recording disabled. " -msgstr "" +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 "削除できるIPアドレスはない" 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 "金額" #, python-format msgid "Amount in %(currency)s" -msgstr "" +msgstr "%(currency)sでの金額" 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 "" "Don\\'t reuse a personal password. Choose a private code and send it to " "your friends" -msgstr "" +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 "あなたは貢献して、向上させることができます!" #, python-format msgid "%(amount)s each" -msgstr "" +msgstr "各自に%(amount)s" 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 "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 "" +msgstr "パスワードを再設定するリンクを送りました。メールをチェックしてください。" 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 "" +msgstr "プロジェクト名と私用コードは何の方法でも共有できます。" msgid "Identifier:" -msgstr "" +msgstr "名前:" msgid "Share the Link" -msgstr "" +msgstr "リンクを共有する" msgid "You can directly share the following link via your prefered medium" -msgstr "" +msgstr "好きの手段で以下のリンクを直接に共有できる" msgid "Send via Emails" -msgstr "" +msgstr "メールで送る" msgid "" "Specify a (comma separated) list of email adresses you want to notify " @@ -737,33 +749,35 @@ msgid "" " creation of this budget management project and we will " "send them an email for you." msgstr "" +"…を知らせたいメールアドレスのリストを特定する(カンマ区切り)\n" +"彼らにこの予算管理プロジェクトの作成をメールでお知らせします。" msgid "Who pays?" -msgstr "" +msgstr "誰が支払った?" msgid "To whom?" -msgstr "" +msgstr "誰まで?" msgid "Who?" -msgstr "" +msgstr "誰?" msgid "Balance" -msgstr "" +msgstr "残高" msgid "deactivate" -msgstr "" +msgstr "操作不可にする" msgid "reactivate" -msgstr "" +msgstr "再び調査可能にする" msgid "Paid" -msgstr "" +msgstr "支払われた" msgid "Spent" -msgstr "" +msgstr "使われた" msgid "Expenses by Month" -msgstr "" +msgstr "月別の費用" msgid "Period" -msgstr "" +msgstr "期間" From d8d006f8001b5a17bc9b746defe362e8dcd320d3 Mon Sep 17 00:00:00 2001 From: Puyma Date: Wed, 11 Nov 2020 17:28:44 +0100 Subject: [PATCH 02/47] Translated using Weblate (Spanish) Currently translated at 41.5% (96 of 231 strings) Translated using Weblate (Spanish (Latin America)) Currently translated at 98.2% (227 of 231 strings) Co-authored-by: Puyma Translate-URL: https://hosted.weblate.org/projects/i-hate-money/i-hate-money/es/ Translate-URL: https://hosted.weblate.org/projects/i-hate-money/i-hate-money/es_419/ Translation: I Hate Money/I Hate Money --- .../translations/es/LC_MESSAGES/messages.mo | Bin 512 -> 5667 bytes .../translations/es/LC_MESSAGES/messages.po | 202 +++++++++--------- .../es_419/LC_MESSAGES/messages.mo | Bin 19199 -> 19200 bytes .../es_419/LC_MESSAGES/messages.po | 14 +- 4 files changed, 111 insertions(+), 105 deletions(-) diff --git a/ihatemoney/translations/es/LC_MESSAGES/messages.mo b/ihatemoney/translations/es/LC_MESSAGES/messages.mo index 919f53477c8796ba7f468226a9d8d26b2e39c27c..337d4a0af4f6b2046c5e17541890ca66f48b9ee4 100644 GIT binary patch literal 5667 zcmZveZHygN8OIN=>Vl#O2qJijP$=!)ZEJ;c+tO}#@3ss3#_pC(4XhB;0W!53arMH|BltHb|Elh6AtxFM%`g0(d|C z5L|>GgI%a4z5%a*-+>pwXW{wqr%>~L1~u-CufOX1U-Rv+!%OLZ3v!#k@zDHt;D_P6 z@Jjf>4^ZG%I0yGYjeiVk+~ZL4J>lywKz;uVlzhK}lKXeQ{T=ub>hD3VdkLH7)m#Im zj~k)(GXy37K6pJm3^i^EUIQP3lK)#!az6nj*VAwoJ`XR0=dqaNyb@~MHmLOnd1!nc zUJgf~rLw)yqzWrIKbzb!Szl74qtMH@n4bQ(oL@F24dKdAy z3SJ2%=WeKVjzH;a25Oxals;FW=06H8d<@F2o`KreD^T-)4fWmEA-DMx56%CF=YOEa zpM&!C-3y`4;c6aQe;d@k_dv~SK)lbe;rD`A42v27;3*ihqB8zef!^i{awgyE=PE+a|6`8 zn&&N0av${lV^I5>g3|N6?{E6{2cXWm1FwT8p~gK0Pr#o*?dKAVM&qu6l6wc#xI?}^ z4K4L1{3QG;lpIe&jeFMfCC^u( zoQG|=1)hOSHGhN}_fM#C??Ft{3?RJx;0pM0xC2U#BffnGO23P~eHm)pmms(K0T1cp zN1iW2ozoe3HGB)oj^2T&&Rovn@@lri?Xd3ai%|P}1WN9&`1U7#`->2hF~9Krzk%H5 zZ63163)qD8Isn<4xe7||9Z>7;hqBL6D0!zLw>iN>>!wh0J?h&Zhtk8-@LKph)cn_c z`9x|d7eu!)b}rjYQGFh-fJOlP+kE~$$Wsaw`?IV!22n;`+5)h z<`m@y$^_+8lv^pf?x1Mxn<&aHmZF%V>kws-@_CA`5lX#$tM)D3>Dot8eEPI1T+)s9 zr%QIIGrf=UIf^drNtbkUoFZG(^;yah%BU(_(-fW8epR@1_PXXNW96GMJ3V{2lNZ_O z9*S&gE9ExI4$3i#&R4#yOE#$swVI<8>0IZ=F_?ptS;`zm*DVyC?KtHyMfQ0wbjY7H%0ME*9>I~rAGM-r9siPyMp-w9HQ(}eYjaf zX_A}aFjTRDU5MhieC-5T5jCSukQAyr4QNM+?F4zgl4iad}Zg;7ScfN?X;^o zB`h;;xT)FAGM6-0xACQ_xf4X8IjnE#k(-eqX}Z{q#A)u#NE-6UTu}62iK21;T-f#2C=V857uuO>ygiDLX|`%c(`L8rl1gA|$$d8#HgnzFvG0z{ z@-zwJ{{9B-NGnAe^<~jApR!HlvOyBs-0_GCTcmb1?Phi{i)hJNb0vw>AT*6oy&Giq z4N+bxc)i+o?FE;aMmvaN(?}$FZ=<&51+SX_cSDV3c4Hb3cU+P?R$jG}X;QRkDO{$# z#8L8~8A~&}(n{M0O-~WyA@ice$Ypgi-tMGX;lY>Pa+G%Sc-6Xx)qxuCn46xmi&5;% zM35|XgC&=niF8RP%l?Cek;oY(OFg;GWQr9zJKX8SQL{7;GZnO*nM%vu=e!iCbvcM5 zOs+Brgyf5v%X6%0&`u|akaVS+yj1yiTeCOYA)9hg0mn&e#$hy@u7i++TCyb>5Gh6+ zyXuNTGtCiXJ+X3IH#0K3nGKdb)3fH@3x}L6Mp?TOyWiT5a+;bgGvl%-Weu4`bJfnd zLR-(P25%!&DogEIVANN5ugfM4U=w_wrIa6$f z^DuKR#xZPwJI$4*nJh;I$5d7rBugxf7ZY)%rIkHujx@B~tcLr|%(bN4bu+PB%ju?S z*R%;))*Oacm^n?y0Ghd(r>9&WpD(#Bx0rmwahHe90ID7Dmtl(0s;@L4W=E)GKJ~_W zEa&K?B}8nd#1B0GINQMBS}yKvF~?g$age7=^h^($6KPj#FW^I~c7?cwF{p9f0!*+T z-2Uim<6-S?Y#gJn+c|=5l(+0nYqPkuzTwB6XbjKRCZ}to z!}jQOeR6#Jz0*^Tfr%h5YV%o;eFTI5a#uI@_3=yPcs` zB&f~1puH~m{#H?R^7_zFE6wGVD{g_M++dn54f#{ghoTw>=W1`q?$Ob6|uBht<{QS37LDa1R$loj8b+eYT0w;ynkB&5zagu8-4x7F||rU_~LW zTDN-_qGDhs?q)$;BRID6x=lJ|H9xR>pRHaGBzDUIyKCRTJ+&h)sbWsu9HF(1lmNcxZ3dA3qcrVJ=$&(*hTDsuk_nCn49yBVM?}3iY&+-3s~hBWm)_w3&J!b zRwXXp+}w=TPA5v3MHG^1dN0Nuy$eZbsV}NZ|0NoM@(mxXYl)&15LW3wB>7 z>(m^<$x>nJdB&WbW)Q#4jA*}V3YI>o#DWm8mZT44XZ+19X zX6Z706EblTWmBStzC0dAX*<9~NtPi&HIOcQ2U`VS%`n4dx-JjLw%1NC^FuO~q7d>6 zx!xOdX*Q+hSu|8;Y}q4m+%B)3BB2L^b}r>a^yj4HOuSCkUTV9HU9VdH@2V8eJ~(xs z)s?<&D0V#(>9x*LU`pHn@(qw{d)y&ZtKnC^y3I;*CuA2 z!yx(jYjQvv{9toO(cRQ{cN#C3=NaRRYp0f2N+J_J2ufsgR#SAU)QAO=>Upm+z7Jcp zpQ~(`f={{9>`Q0R?i=hqTzgJG z5!h)1Q7R8y|BK+5IFHK0%H&yUp1qX+4yE}XO$oJUInc4Z8}Prj{tLlee&Vq%8?1K2 zAlt%>ySi)79E2m?wNpvRkA#{k2jr;qJK-vq!YxSz{HPFW`i5wND)MiN_`SA`5uZPd zawPjb^D_J4kEZLgFvtmA8;@0g89r!c##I)=OBu=N^8Xo9Z~srDKaMui{tbSOD=cprj>`2C0F8$(wkixeY9Jjf@lw WO{@$IH%stEGqM}&rlgi}F#rJ2t_yVl diff --git a/ihatemoney/translations/es/LC_MESSAGES/messages.po b/ihatemoney/translations/es/LC_MESSAGES/messages.po index 4ba8b0db..13463e56 100644 --- a/ihatemoney/translations/es/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/es/LC_MESSAGES/messages.po @@ -3,49 +3,53 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-09-22 14:01+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-11-11 16:28+0000\n" +"Last-Translator: Puyma \n" +"Language-Team: Spanish \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Translate Toolkit 3.0.0\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.4-dev\n" msgid "" "Not a valid amount or expression. Only numbers and + - * / operators are " "accepted." msgstr "" +"Cantidad o expresión no válida. Solo se aceptan números y los operadores + - " +"* /." msgid "Project name" -msgstr "" +msgstr "Nombre del proyecto" msgid "Private code" -msgstr "" +msgstr "Código privado" msgid "Email" -msgstr "" +msgstr "Correo electrónico" msgid "Enable project history" -msgstr "" +msgstr "Habilitar historial del proyecto" msgid "Use IP tracking for project history" msgstr "" msgid "Default Currency" -msgstr "" +msgstr "Moneda por defecto" msgid "Import previously exported JSON file" -msgstr "" +msgstr "Importar .JSON previamente exportado" msgid "Import" -msgstr "" +msgstr "Importar" msgid "Project identifier" -msgstr "" +msgstr "Identificador del proyecto" msgid "Create the project" -msgstr "" +msgstr "Crear proyecto" #, python-format msgid "" @@ -57,49 +61,49 @@ msgid "Get in" msgstr "" msgid "Admin password" -msgstr "" +msgstr "Contraseña de administrador" msgid "Send me the code by email" -msgstr "" +msgstr "Envíame el código por correo electrónico" msgid "This project does not exists" -msgstr "" +msgstr "Proyecto inexistente" msgid "Password mismatch" -msgstr "" +msgstr "La contraseña no coincide" msgid "Password" -msgstr "" +msgstr "Contraseña" msgid "Password confirmation" -msgstr "" +msgstr "Confirmar contraseña" msgid "Reset password" -msgstr "" +msgstr "Reestablecer contraseña" msgid "Date" -msgstr "" +msgstr "Fecha" msgid "What?" -msgstr "" +msgstr "¿Qué?" msgid "Payer" msgstr "" msgid "Amount paid" -msgstr "" +msgstr "Cantidad pagada" msgid "Currency" -msgstr "" +msgstr "Divisa" msgid "External link" -msgstr "" +msgstr "Enlace externo" msgid "A link to an external document, related to this bill" msgstr "" msgid "For whom?" -msgstr "" +msgstr "¿Para quién?" msgid "Submit" msgstr "" @@ -115,7 +119,7 @@ msgid "Bills can't be null" msgstr "" msgid "Name" -msgstr "" +msgstr "Nombre" msgid "Weights should be positive" msgstr "" @@ -124,10 +128,10 @@ msgid "Weight" msgstr "" msgid "Add" -msgstr "" +msgstr "Añadir" msgid "User name incorrect" -msgstr "" +msgstr "Usuario incorrecto" msgid "This project already have this member" msgstr "" @@ -136,20 +140,20 @@ msgid "People to notify" msgstr "" msgid "Send invites" -msgstr "" +msgstr "Enviar invitaciones" #, python-format msgid "The email %(email)s is not valid" -msgstr "" +msgstr "El correo %(email)s no es válido" msgid "Participant" -msgstr "" +msgstr "Participante" msgid "Bill" -msgstr "" +msgstr "Factura" msgid "Project" -msgstr "" +msgstr "Proyecto" msgid "No Currency" msgstr "" @@ -291,16 +295,16 @@ msgid "Oldest bill" msgstr "" msgid "Actions" -msgstr "" +msgstr "Acciones" msgid "edit" -msgstr "" +msgstr "editar" msgid "delete" -msgstr "" +msgstr "eliminar" msgid "show" -msgstr "" +msgstr "mostrar" msgid "The Dashboard is currently deactivated." msgstr "" @@ -336,49 +340,49 @@ msgid "Can't remember the password?" msgstr "" msgid "Cancel" -msgstr "" +msgstr "Cancelar" msgid "Privacy Settings" -msgstr "" +msgstr "Ajustes de privacidad" msgid "Edit the project" -msgstr "" +msgstr "Editar el proyecto" msgid "Edit this bill" -msgstr "" +msgstr "Editar esta factura" msgid "Add a bill" -msgstr "" +msgstr "Añadir una factura" msgid "Select all" -msgstr "" +msgstr "Seleccionar todo" msgid "Select none" msgstr "" msgid "Add participant" -msgstr "" +msgstr "Añadir participante" msgid "Edit this member" -msgstr "" +msgstr "Editar miembro" msgid "john.doe@example.com, mary.moe@site.com" msgstr "" msgid "Send the invitations" -msgstr "" +msgstr "Enviar invitaciones" msgid "Download" -msgstr "" +msgstr "Descargar" msgid "Disabled Project History" -msgstr "" +msgstr "Historial del proyecto desactivado" msgid "Disabled Project History & IP Address Recording" msgstr "" msgid "Enabled Project History" -msgstr "" +msgstr "Historial del proyecto activado" msgid "Disabled IP Address Recording" msgstr "" @@ -396,10 +400,10 @@ msgid "changed" msgstr "" msgid "from" -msgstr "" +msgstr "de" msgid "to" -msgstr "" +msgstr "para" msgid "Confirm Remove IP Adresses" msgstr "" @@ -412,7 +416,7 @@ msgid "" msgstr "" msgid "Close" -msgstr "" +msgstr "Cerrar" msgid "Confirm Delete" msgstr "" @@ -426,10 +430,10 @@ msgid "" msgstr "" msgid "Added" -msgstr "" +msgstr "Añadido" msgid "Removed" -msgstr "" +msgstr "Eliminado" msgid "and" msgstr "" @@ -477,10 +481,10 @@ msgid "Delete Stored IP Addresses" msgstr "" msgid "Time" -msgstr "" +msgstr "Hora" msgid "Event" -msgstr "" +msgstr "Evento" msgid "IP address recording can be enabled on the settings page" msgstr "" @@ -492,7 +496,7 @@ msgid "From IP" msgstr "" msgid "added" -msgstr "" +msgstr "añadido" msgid "Project private code changed" msgstr "" @@ -519,17 +523,17 @@ msgid "External link changed to" msgstr "" msgid "Amount" -msgstr "" +msgstr "Cantidad" #, python-format msgid "Amount in %(currency)s" -msgstr "" +msgstr "Cantidad en %(currency)s" msgid "modified" -msgstr "" +msgstr "modificado" msgid "removed" -msgstr "" +msgstr "eliminado" msgid "changed in a unknown way" msgstr "" @@ -556,57 +560,59 @@ msgid "Simply sharing money with others?" msgstr "" msgid "We can help!" -msgstr "" +msgstr "Podemos ayudar!" msgid "Log in to an existing project" -msgstr "" +msgstr "Acceder a un proyecto existente" msgid "Log in" msgstr "" msgid "can't remember your password?" -msgstr "" +msgstr "¿no recuerdas tu contraseña?" msgid "Create" -msgstr "" +msgstr "Crear" msgid "" "Don\\'t reuse a personal password. Choose a private code and send it to " "your friends" msgstr "" +"No reutilizes una contraseña personal. Escoge un código privado i envíalo a " +"tus amigos" msgid "Account manager" msgstr "" msgid "Bills" -msgstr "" +msgstr "Facturas" msgid "Settle" msgstr "" msgid "Statistics" -msgstr "" +msgstr "Estadísticas" msgid "History" -msgstr "" +msgstr "Historia" msgid "Settings" -msgstr "" +msgstr "Ajustes" msgid "Languages" -msgstr "" +msgstr "Idiomas" msgid "Projects" -msgstr "" +msgstr "Proyectos" msgid "Start a new project" msgstr "" msgid "Other projects :" -msgstr "" +msgstr "Otros proyectos :" msgid "switch to" -msgstr "" +msgstr "cambiar a" msgid "Dashboard" msgstr "" @@ -615,16 +621,16 @@ msgid "Logout" msgstr "" msgid "Code" -msgstr "" +msgstr "Código" msgid "Mobile Application" -msgstr "" +msgstr "Aplicación móvil" msgid "Documentation" -msgstr "" +msgstr "Documentación" msgid "Administation Dashboard" -msgstr "" +msgstr "Panel de administración" msgid "\"I hate money\" is a free software" msgstr "" @@ -652,7 +658,7 @@ msgid "Older bills" msgstr "" msgid "When?" -msgstr "" +msgstr "¿Cuándo?" msgid "Who paid?" msgstr "" @@ -675,19 +681,19 @@ msgid "Everyone but %(excluded)s" msgstr "" msgid "No bills" -msgstr "" +msgstr "Sin facturas" msgid "Nothing to list yet." -msgstr "" +msgstr "No hay nada que mostrar todavía." msgid "You probably want to" -msgstr "" +msgstr "Probablemente quieras" msgid "add a bill" -msgstr "" +msgstr "añadir una factura" msgid "add participants" -msgstr "" +msgstr "añadir participantes" msgid "Password reminder" msgstr "" @@ -698,19 +704,19 @@ msgid "" msgstr "" msgid "Return to home page" -msgstr "" +msgstr "Volver a la página de inicio" msgid "Your projects" -msgstr "" +msgstr "Tus proyectos" msgid "Reset your password" -msgstr "" +msgstr "Reestablecer tu contraseña" msgid "Invite people to join this project" msgstr "" msgid "Share Identifier & code" -msgstr "" +msgstr "Compartir identificador i código" msgid "" "You can share the project identifier and the private code by any " @@ -718,10 +724,10 @@ msgid "" msgstr "" msgid "Identifier:" -msgstr "" +msgstr "Identificador:" msgid "Share the Link" -msgstr "" +msgstr "Compartir el enlace" msgid "You can directly share the following link via your prefered medium" msgstr "" @@ -740,28 +746,28 @@ msgid "Who pays?" msgstr "" msgid "To whom?" -msgstr "" +msgstr "¿Para quién?" msgid "Who?" -msgstr "" +msgstr "¿Quién?" msgid "Balance" msgstr "" msgid "deactivate" -msgstr "" +msgstr "desactivar" msgid "reactivate" -msgstr "" +msgstr "reactivar" msgid "Paid" -msgstr "" +msgstr "Pagado" msgid "Spent" -msgstr "" +msgstr "Gastado" msgid "Expenses by Month" -msgstr "" +msgstr "Gastos por mes" msgid "Period" -msgstr "" +msgstr "Período" diff --git a/ihatemoney/translations/es_419/LC_MESSAGES/messages.mo b/ihatemoney/translations/es_419/LC_MESSAGES/messages.mo index ccc7e5bbfa3b5c430610accbdf49e591199a3df3..68315f4438c31e50399fa2f28529b5e356973a7d 100644 GIT binary patch delta 1701 zcmXZcZ)}Zc7{~GJIqRIZj8=;tv<_wd?Wm`Y)afxRol~on;YH2yLaRpz+U>N7WHiSl z8h^jnx(KA zS;GFnLVS+7nCqGau@H+egdvQ$ma$?U>KM?6t5ID5t{1tf zqFzF?aTIYJhvEvw`kJE^gsLZ-z^gs*kV?akbii&?j%4^q9 zDF>^)BaKGYemssq7nN`wj>ly<1lv(P+>Yb$C?@e7YJMp0y`LJV2Sp4d7?7)cTd|mU z2db%uP?b84+Movq<2h6!12`IQqUOECi8ySoSq?@~<1tjlmZ0V}W_VCWoBbD^SV7!{ z++aI{A-s!9(BbZ@gdrpwDFc3v; z)PU+`6KdkuScX5LTGWR+$yHQ^{zA3jA!^}*kN7EIIc~uQr25v6eW>5mN%psX9vHLs z`DV8~7I>NdfVx~~Q7yRWk6*#b#P?AP7uTAN!KFABH)1L7!Wr0&AK*3Qep=vT zv*qk>aUOKr_u(WwjXLq4n1fGIz5XAUW6naa0*$Diu0yqKD|X-soP^~E1eFVjlY$v;K)ZYAn&G^0wM_Q$`%WyE`NJ>Ecav&14Zs&9L-3NNBAS>O}z z&XnLd;#!=5YcZqJcJZK|A3#kwhPiki9sC{3Z~%jN55xG#j|=&8$R`e=Dm4)`e(g2J#sA#(!}HwZM<4zr2(F`#w}cmrw~^M*YG3m;G#LXX#+q zjks>ut*Wk^lf5;)-EpGX#>jy{_I|~;PJUZ!N4lv!)qAQbyTg4F7~ascDc(j^kX(|0NVGRqZQ=Vu|-Ez_(s#B0_ z$*LDtMD${?tQd=;Q!k=|NDX5|LxjN+V?-_*vmwIh#c1DO&-3c@T=#wM=f3Xiy3cdu zoafzH&y5v{(SJNH_`3UphnPV80(FAdsKh2v6-i#| zBvgtsi9?u*4XAb7QR{Z25^u*$?8IE`?zxlnBC46^Wo8BV5|c40#4&INPQh}l$2GVX zPosAF4Rxe3oQiLdcG`dL{K9gxX~ZGdI$T7&6_r_6IX%#ePBNe)T|~tLNO^4-Rg#1X z=SbP8+WSyP@uL#1#o5?^A7TgQU=;K5B5uQbsP$RPo%sdJ=|MUJH4Mlm*EY-`K8kAU zIaE!rqBgjWDR>W+$RK`zlmA$CS47v`XF3AWg(MeQgqiOt^)T08-!XRp+^{8I% zKrQ?p^Y9X?MSZA~452FY4Ap|aQ7=xbG+T%T_zkW{s&D<+kMHmr`&)k%r(mFC6&Db1 zqAthzYA4elP?zg2ss)eT@n3O1@n5JHr>{1fg&Q#k_hK#{$71ZoB{+=SPxGuXYh-_` z;6bIwT|B7gJ*Wj&FbVIY2OnV`4q_tyi9USe#?$yX=sS^xs?;3R`VvgQ5XNC8 zsuk5Z1^3lk?fc7fkbz_dPPr53Q7`xr^~w9$o$o^>^aPdAQ`F@hk2R$p%1!Zyih_P$ zX`o_RdF+qHUwh(9ivzJwi_XNwUX}ECyshE=kyuw?A}+J-%l1f1*!NXOq$ScB>1g}B SJ=_wGomjdpKK8O~R{H-H8qwka diff --git a/ihatemoney/translations/es_419/LC_MESSAGES/messages.po b/ihatemoney/translations/es_419/LC_MESSAGES/messages.po index 38dcdc35..a7825934 100644 --- a/ihatemoney/translations/es_419/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/es_419/LC_MESSAGES/messages.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-05-30 21:50+0200\n" -"PO-Revision-Date: 2020-08-30 19:59+0000\n" -"Last-Translator: Miguel Victoria Villaquiran \n" +"PO-Revision-Date: 2020-11-11 16:28+0000\n" +"Last-Translator: Puyma \n" "Language-Team: Spanish (Latin America) \n" "Language: es_419\n" @@ -12,7 +12,7 @@ msgstr "" "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.2.1-dev\n" +"X-Generator: Weblate 4.4-dev\n" "Generated-By: Babel 2.8.0\n" msgid "" @@ -38,7 +38,7 @@ msgid "Use IP tracking for project history" msgstr "Registrar la IPs para el historial del proyecto" msgid "Default Currency" -msgstr "moneda predeterminada" +msgstr "Moneda por defecto" msgid "Import previously exported JSON file" msgstr "Importar archivo JSON previamente exportado" @@ -61,10 +61,10 @@ msgstr "" "favor, elija un nuevo identificador" msgid "Get in" -msgstr "Entra" +msgstr "Entrar" msgid "Admin password" -msgstr "Clave de Administrador" +msgstr "Contraseña de Administrador" msgid "Send me the code by email" msgstr "Envíame el código por correo electrónico" @@ -103,7 +103,7 @@ msgid "External link" msgstr "Enlace externo" msgid "A link to an external document, related to this bill" -msgstr "Un enlace a un documento externo relaccionado con esta factura" +msgstr "Un enlace a un documento externo relacionado con esta factura" msgid "For whom?" msgstr "¿Para quién?" From 6833c6eee8e69dc69133dc8df44447751d8b0921 Mon Sep 17 00:00:00 2001 From: mppmpp315 Date: Sun, 25 Oct 2020 19:48:19 -0400 Subject: [PATCH 03/47] Update messages.po --- ihatemoney/translations/ru/LC_MESSAGES/messages.po | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ihatemoney/translations/ru/LC_MESSAGES/messages.po b/ihatemoney/translations/ru/LC_MESSAGES/messages.po index ca6f1ad5..2f341aab 100644 --- a/ihatemoney/translations/ru/LC_MESSAGES/messages.po +++ b/ihatemoney/translations/ru/LC_MESSAGES/messages.po @@ -676,16 +676,16 @@ msgstr "вы можете способствовать развитию и ул #, python-format msgid "%(amount)s each" -msgstr "%(amount)s каждый" +msgstr "%(amount)s по каждому" 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 "Новые счета" @@ -749,7 +749,7 @@ msgid "Reset your password" msgstr "Восстановить пароль" msgid "Invite people to join this project" -msgstr "Пригласить людей присоединиться к этому проекту" +msgstr "Пригласите людей присоединиться к этому проекту" msgid "Share Identifier & code" msgstr "Поделиться идентификатором и кодом" From 106bc2df283dac4a667edceb978d8a8e0ab0768b Mon Sep 17 00:00:00 2001 From: Jingwen Yang <72591702+Jwen921@users.noreply.github.com> Date: Tue, 10 Nov 2020 17:50:58 +0900 Subject: [PATCH 04/47] Add Japanese to the supported languages --- ihatemoney/default_settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ihatemoney/default_settings.py b/ihatemoney/default_settings.py index a3cf4077..709c36d0 100644 --- a/ihatemoney/default_settings.py +++ b/ihatemoney/default_settings.py @@ -24,4 +24,5 @@ SUPPORTED_LANGUAGES = [ "tr", "uk", "zh_Hans", + "ja", ] From e1746e81f56f4b1aed937147bf6b6bc3e9c5fd10 Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Fri, 13 Nov 2020 00:28:52 +0100 Subject: [PATCH 05/47] Add portuguese to available languages --- ihatemoney/default_settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ihatemoney/default_settings.py b/ihatemoney/default_settings.py index 709c36d0..d16cf17d 100644 --- a/ihatemoney/default_settings.py +++ b/ihatemoney/default_settings.py @@ -18,6 +18,7 @@ SUPPORTED_LANGUAGES = [ "nb_NO", "nl", "pl", + "pt", "pt_BR", "ru", "ta", From de13945a914b648c2ae6ad9ef0795e83f4c357a9 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 13 Nov 2020 21:37:32 +0100 Subject: [PATCH 06/47] Bump sphinx from 3.3.0 to 3.3.1 (#696) Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.3.0 to 3.3.1. - [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.3.0...v3.3.1) 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 faa22bff..4fd60531 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,2 +1,2 @@ -Sphinx==3.3.0 +Sphinx==3.3.1 docutils==0.16 From 914482bc76954aef067ac73314a19f415a32c61c Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Sun, 26 Apr 2020 16:40:35 +0200 Subject: [PATCH 07/47] Use Flask-Babel to localize datetime in the History Page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By formatting datetime on the server, we get nice localized datetime strings that are adapted to the currently-selected language. Example: - English: "Apr 26, 2020, 3:58:54 PM" - French: "26 avr. 2020 à 15:58:54" - German: "26.04.2020, 15:58:54" - Spanish: "26 abr. 2020 15:58:54" - Indonesian: "26 Apr 2020 15.58.54" - Chinese: "2020年4月26日 下午3:58:54" However, there is a downside: time is not adapted to the user timezone. The solution is to define a timezone on the server: we use the server OS timezone by default, and it can be customized through the BABEL_DEFAULT_TIMEZONE setting. It's still not ideal, because it assumes that all users are in the same timezone (the one configured on the server). --- ihatemoney/history.py | 2 +- ihatemoney/run.py | 7 +++++-- ihatemoney/templates/history.html | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ihatemoney/history.py b/ihatemoney/history.py index 801e39e6..3f99420a 100644 --- a/ihatemoney/history.py +++ b/ihatemoney/history.py @@ -82,7 +82,7 @@ def get_history(project, human_readable_names=True): object_str = describe_version(version) common_properties = { - "time": version.transaction.issued_at.strftime("%Y-%m-%dT%H:%M:%SZ"), + "time": version.transaction.issued_at, "operation_type": version.operation_type, "object_type": object_type, "object_desc": object_str, diff --git a/ihatemoney/run.py b/ihatemoney/run.py index 0f32dfb9..1d2a575f 100644 --- a/ihatemoney/run.py +++ b/ihatemoney/run.py @@ -2,6 +2,7 @@ import os import os.path import warnings +from babel.dates import LOCALTZ from flask import Flask, g, render_template, request, session from flask_babel import Babel, format_currency from flask_mail import Mail @@ -150,8 +151,10 @@ def create_app( app.jinja_env.globals["locale_from_iso"] = locale_from_iso app.jinja_env.filters["minimal_round"] = minimal_round - # Translations - babel = Babel(app) + # Translations and time zone (used to display dates). The timezone is + # taken from the BABEL_DEFAULT_TIMEZONE settings, and falls back to + # the local timezone of the server OS by using LOCALTZ. + babel = Babel(app, default_timezone=str(LOCALTZ)) # Undocumented currencyformat filter from flask_babel is forwarding to Babel format_currency # We overwrite it to remove the currency sign ¤ when there is no currency diff --git a/ihatemoney/templates/history.html b/ihatemoney/templates/history.html index d9f2b4d2..d4965d86 100644 --- a/ihatemoney/templates/history.html +++ b/ihatemoney/templates/history.html @@ -161,7 +161,7 @@ {% for event in history %} - + {{ event.time|datetimeformat("medium") }}
Date: Sun, 26 Apr 2020 17:10:54 +0200 Subject: [PATCH 08/47] Document timezone settings --- docs/configuration.rst | 22 ++++++++++++++++++++- ihatemoney/conf-templates/ihatemoney.cfg.j2 | 4 ++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index 5b787075..7e29da1c 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -31,6 +31,7 @@ connection string. This will look like:: SQLALCHEMY_DATABASE_URI = 'postgresql://myuser:mypass@localhost/dbname?client_encoding=utf8' +.. _the SQLAlchemy documentation: http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls `SECRET_KEY` ------------ @@ -96,7 +97,26 @@ if set to ``"somestring"``, it will be served from a "folder" - **Default value:** ``""`` (empty string) -.. _the SQLAlchemy documentation: http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls +`BABEL_DEFAULT_TIMEZONE` +------------------------ + +The timezone that will be used to convert date and time when displaying them +to the user (all times are always stored in UTC internally). +If not set, it will default to the timezone configured on the Operating System +of the server running ihatemoney, which may or may not be what you want. + +- **Default value:** *unset* (use the timezone of the server Operating System) +- **Production value:** Set to the timezone of your expected users, with a + format such as ``"Europe/Paris"``. See `this list of TZ database names`_ + for a complete list. + +Note: this setting is actually interpreted by Flask-Babel, see the +`Flask-Babel guide for formatting dates`_ for details. + +.. _this list of TZ database name: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List + +.. _Flask-Babel guide for formatting dates: https://pythonhosted.org/Flask-Babel/#formatting-dates + Configuring emails sending -------------------------- diff --git a/ihatemoney/conf-templates/ihatemoney.cfg.j2 b/ihatemoney/conf-templates/ihatemoney.cfg.j2 index c0545912..0188c6b1 100644 --- a/ihatemoney/conf-templates/ihatemoney.cfg.j2 +++ b/ihatemoney/conf-templates/ihatemoney.cfg.j2 @@ -34,3 +34,7 @@ ALLOW_PUBLIC_PROJECT_CREATION = True # If set to True, an administration dashboard is available. ACTIVATE_ADMIN_DASHBOARD = False + +# You can change the timezone used to display time. By default it will be +#derived from the server OS. +#BABEL_DEFAULT_TIMEZONE = "Europe/Paris" From 8a5193f4433703e5f343b1f91a66bb3745473717 Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Sun, 26 Apr 2020 17:24:33 +0200 Subject: [PATCH 09/47] Localize date in the "Added on" tooltip in the list of bills --- ihatemoney/templates/list_bills.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ihatemoney/templates/list_bills.html b/ihatemoney/templates/list_bills.html index 12c50727..849fc15b 100644 --- a/ihatemoney/templates/list_bills.html +++ b/ihatemoney/templates/list_bills.html @@ -110,7 +110,7 @@ + title="{{ _('Added on %(date)s', date=bill.creation_date|dateformat("long") if bill.creation_date else bill.date|dateformat("long")) }}"> {{ bill.date }} From 6ec7dd607752dc750481d03ccba1e77af3f5711a Mon Sep 17 00:00:00 2001 From: Mayank Choudhary <7mayankchoudhary7@gmail.com> Date: Wed, 25 Nov 2020 02:52:46 +0530 Subject: [PATCH 10/47] Added a page for downloading mobile application (#688) Fixes #597 Fixes #697 Co-authored-by: Glandos --- ihatemoney/static/css/download_mobile_app.css | 13 ++ ihatemoney/static/images/app-store.svg | 129 ++++++++++++++++++ ihatemoney/static/images/f-droid.svg | 95 +++++++++++++ ihatemoney/static/images/google-play.png | Bin 0 -> 69751 bytes ihatemoney/templates/download_mobile_app.html | 26 ++++ ihatemoney/templates/layout.html | 5 +- ihatemoney/web.py | 5 + 7 files changed, 271 insertions(+), 2 deletions(-) create mode 100644 ihatemoney/static/css/download_mobile_app.css create mode 100644 ihatemoney/static/images/app-store.svg create mode 100644 ihatemoney/static/images/f-droid.svg create mode 100644 ihatemoney/static/images/google-play.png create mode 100644 ihatemoney/templates/download_mobile_app.html diff --git a/ihatemoney/static/css/download_mobile_app.css b/ihatemoney/static/css/download_mobile_app.css new file mode 100644 index 00000000..8fe87bb9 --- /dev/null +++ b/ihatemoney/static/css/download_mobile_app.css @@ -0,0 +1,13 @@ +.get-it-from { + width: 100px; + min-height: 110px; + border: 5px solid floralwhite; + background-color: white; margin: 10px; +} +.get-it-from:hover { + opacity: 80%; +} +main { + background: linear-gradient(150deg, #abe128 0%, #43ca61 100%); + font-family: 'Comfortaa', arial, serif; +} diff --git a/ihatemoney/static/images/app-store.svg b/ihatemoney/static/images/app-store.svg new file mode 100644 index 00000000..ac111e59 --- /dev/null +++ b/ihatemoney/static/images/app-store.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ihatemoney/static/images/f-droid.svg b/ihatemoney/static/images/f-droid.svg new file mode 100644 index 00000000..bac1d085 --- /dev/null +++ b/ihatemoney/static/images/f-droid.svg @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ihatemoney/static/images/google-play.png b/ihatemoney/static/images/google-play.png new file mode 100644 index 0000000000000000000000000000000000000000..a93fdeabb85e62fa7d1c6247b8f65f6027839811 GIT binary patch literal 69751 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 literal 0 HcmV?d00001 diff --git a/ihatemoney/templates/download_mobile_app.html b/ihatemoney/templates/download_mobile_app.html new file mode 100644 index 00000000..b343c71f --- /dev/null +++ b/ihatemoney/templates/download_mobile_app.html @@ -0,0 +1,26 @@ +{% extends "layout.html" %} + +{% block css %} + +{% endblock %} + +{% block body %} +
+
+

{{_("Download Mobile Application")}}

+
+

{{_("Get it on")}}

+ +
+{% endblock %} diff --git a/ihatemoney/templates/layout.html b/ihatemoney/templates/layout.html index 1e16c7e2..f79270e4 100644 --- a/ihatemoney/templates/layout.html +++ b/ihatemoney/templates/layout.html @@ -6,6 +6,7 @@ + {% block css %}{% endblock %} @@ -144,14 +145,14 @@ {{ static_include("images/git.svg") | safe }} - + {{ static_include("images/mobile-alt.svg") | safe }} {{ static_include("images/book.svg") | safe }} {% if g.show_admin_dashboard_link %} - + {{ static_include("images/cog.svg") | safe }} {% endif %} diff --git a/ihatemoney/web.py b/ihatemoney/web.py index 442779f7..6e4a2090 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -269,6 +269,11 @@ def home(): session=session, ) +@main.route("/mobile") +def mobile(): + return render_template( + "download_mobile_app.html" + ) @main.route("/create", methods=["GET", "POST"]) @requires_admin(bypass=("ALLOW_PUBLIC_PROJECT_CREATION", True)) From ce4d64da57d5f324db62e671780b6185cfe2abe0 Mon Sep 17 00:00:00 2001 From: Glandos Date: Tue, 24 Nov 2020 22:23:58 +0100 Subject: [PATCH 11/47] formatting --- ihatemoney/web.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ihatemoney/web.py b/ihatemoney/web.py index 6e4a2090..d16cf55e 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -269,11 +269,11 @@ def home(): session=session, ) + @main.route("/mobile") def mobile(): - return render_template( - "download_mobile_app.html" - ) + return render_template("download_mobile_app.html") + @main.route("/create", methods=["GET", "POST"]) @requires_admin(bypass=("ALLOW_PUBLIC_PROJECT_CREATION", True)) From 0380521b4a6f4a0efcc544ca57134def94ac19ba Mon Sep 17 00:00:00 2001 From: Glandos Date: Tue, 24 Nov 2020 22:51:51 +0100 Subject: [PATCH 12/47] Add python3.9 support --- README.rst | 2 +- docs/installation.rst | 2 +- setup.cfg | 1 + tox.ini | 3 ++- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 84d73b4a..9263e3fa 100644 --- a/README.rst +++ b/README.rst @@ -25,7 +25,7 @@ encouraged to do so. Requirements ============ -* **Python**: 3.6, 3.7, 3.8. +* **Python**: version 3.6 to 3.9. * **Backends**: MySQL, PostgreSQL, SQLite, Memory. Contributing diff --git a/docs/installation.rst b/docs/installation.rst index b33fb55d..82ac12f2 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -19,7 +19,7 @@ Requirements «Ihatemoney» depends on: -* **Python**: either 3.6, 3.7 or 3.8 will work. +* **Python**: version 3.6 to 3.9 included will work. * **A Backend**: to choose among MySQL, PostgreSQL, SQLite or Memory. * **Virtual environment** (recommended): `python3-venv` package under Debian/Ubuntu. diff --git a/setup.cfg b/setup.cfg index 43a33886..c56441bb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -14,6 +14,7 @@ classifiers = Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 Topic :: Internet :: WWW/HTTP Topic :: Internet :: WWW/HTTP :: WSGI :: Application diff --git a/tox.ini b/tox.ini index 372f60f9..2c9e1178 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py38,py37,py36,docs,flake8,black +envlist = py39,py38,py37,py36,docs,flake8,black skip_missing_interpreters = True [testenv] @@ -42,3 +42,4 @@ python = 3.6: py36 3.7: py37 3.8: py38, docs, black, flake8 + 3.9: py39 From 3f4b47276e8c81cde2542a00ce90f3a0ffc1639a Mon Sep 17 00:00:00 2001 From: Glandos Date: Tue, 24 Nov 2020 22:58:22 +0100 Subject: [PATCH 13/47] Set black target to python3.6 --- Makefile | 2 +- ihatemoney/migrations/env.py | 2 +- ihatemoney/patch_sqlalchemy_continuum.py | 2 +- ihatemoney/run.py | 2 +- tox.ini | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 63002664..30de0dd7 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ test: install-dev ## Run the tests .PHONY: black black: install-dev ## Run the tests - $(VENV)/bin/black --target-version=py34 . + $(VENV)/bin/black --target-version=py36 . .PHONY: isort isort: install-dev ## Run the tests diff --git a/ihatemoney/migrations/env.py b/ihatemoney/migrations/env.py index 0bd0031e..1a443181 100755 --- a/ihatemoney/migrations/env.py +++ b/ihatemoney/migrations/env.py @@ -77,7 +77,7 @@ def run_migrations_online(): target_metadata=target_metadata, include_object=include_object, process_revision_directives=process_revision_directives, - **current_app.extensions["migrate"].configure_args + **current_app.extensions["migrate"].configure_args, ) try: diff --git a/ihatemoney/patch_sqlalchemy_continuum.py b/ihatemoney/patch_sqlalchemy_continuum.py index dbbd9083..eecfe6fa 100644 --- a/ihatemoney/patch_sqlalchemy_continuum.py +++ b/ihatemoney/patch_sqlalchemy_continuum.py @@ -96,7 +96,7 @@ class PatchedRelationShipBuilder(RelationshipBuilder): association_col == self.association_version_table.c[association_col.name] for association_col in association_cols - ] + ], ) ) .group_by(*association_cols) diff --git a/ihatemoney/run.py b/ihatemoney/run.py index 1d2a575f..4ce8aaaf 100644 --- a/ihatemoney/run.py +++ b/ihatemoney/run.py @@ -170,7 +170,7 @@ def create_app( number, currency if currency != CurrencyConverter.no_currency else "", *args, - **kwargs + **kwargs, ).strip() app.jinja_env.filters["currency"] = currency diff --git a/tox.ini b/tox.ini index 2c9e1178..6b967871 100644 --- a/tox.ini +++ b/tox.ini @@ -22,7 +22,7 @@ changedir = {toxinidir} [testenv:black] commands = - black --check --target-version=py34 . + black --check --target-version=py36 . isort -c -rc . changedir = {toxinidir} From 336ade7d44667fda7f4e5546b179d601fbf0a48c Mon Sep 17 00:00:00 2001 From: Glandos Date: Wed, 25 Nov 2020 10:09:43 +0100 Subject: [PATCH 14/47] Use python 3.9 in Travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index ca72fb95..05533434 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ python: - "3.6" - "3.7" - "3.8" + - "3.9" script: tox install: - pip install tox-travis From e0bc285c92d42dc2318fd543779665f6a73aad2d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 5 Jan 2021 21:58:59 +0100 Subject: [PATCH 15/47] Bump sphinx from 3.3.1 to 3.4.2 (#707) Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 3.3.1 to 3.4.2. - [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.3.1...v3.4.2) 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 4fd60531..ff06c315 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,2 +1,2 @@ -Sphinx==3.3.1 +Sphinx==3.4.2 docutils==0.16 From 18068d76ca304a55dffdb4fb54c674bb1dcc148f Mon Sep 17 00:00:00 2001 From: Miguel Victoria Villaquiran Date: Tue, 5 Jan 2021 22:17:26 +0100 Subject: [PATCH 16/47] Simplify tests (#685) Fix #501 --- ihatemoney/tests/api_test.py | 748 ++++ ihatemoney/tests/budget_test.py | 1451 ++++++++ ihatemoney/tests/common/help_functions.py | 5 + .../tests/common/ihatemoney_testcase.py | 70 + ihatemoney/tests/history_test.py | 599 ++++ ihatemoney/tests/main_test.py | 265 ++ ihatemoney/tests/tests.py | 3106 ----------------- tox.ini | 2 +- 8 files changed, 3139 insertions(+), 3107 deletions(-) create mode 100644 ihatemoney/tests/api_test.py create mode 100644 ihatemoney/tests/budget_test.py create mode 100644 ihatemoney/tests/common/help_functions.py create mode 100644 ihatemoney/tests/common/ihatemoney_testcase.py create mode 100644 ihatemoney/tests/history_test.py create mode 100644 ihatemoney/tests/main_test.py delete mode 100644 ihatemoney/tests/tests.py diff --git a/ihatemoney/tests/api_test.py b/ihatemoney/tests/api_test.py new file mode 100644 index 00000000..41f5ab2d --- /dev/null +++ b/ihatemoney/tests/api_test.py @@ -0,0 +1,748 @@ +import base64 +import datetime +import json +import unittest + +from ihatemoney.tests.common.help_functions import em_surround +from ihatemoney.tests.common.ihatemoney_testcase import IhatemoneyTestCase + + +class APITestCase(IhatemoneyTestCase): + + """Tests the API""" + + def api_create(self, name, id=None, password=None, contact=None): + id = id or name + password = password or name + contact = contact or f"{name}@notmyidea.org" + + return self.client.post( + "/api/projects", + data={ + "name": name, + "id": id, + "password": password, + "contact_email": contact, + "default_currency": "USD", + }, + ) + + def api_add_member(self, project, name, weight=1): + self.client.post( + f"/api/projects/{project}/members", + data={"name": name, "weight": weight}, + headers=self.get_auth(project), + ) + + def get_auth(self, username, password=None): + password = password or username + base64string = ( + base64.encodebytes(f"{username}:{password}".encode("utf-8")) + .decode("utf-8") + .replace("\n", "") + ) + return {"Authorization": f"Basic {base64string}"} + + def test_cors_requests(self): + # Create a project and test that CORS headers are present if requested. + resp = self.api_create("raclette") + self.assertStatus(201, resp) + + # Try to do an OPTIONS requests and see if the headers are correct. + resp = self.client.options( + "/api/projects/raclette", headers=self.get_auth("raclette") + ) + self.assertEqual(resp.headers["Access-Control-Allow-Origin"], "*") + + def test_basic_auth(self): + # create a project + resp = self.api_create("raclette") + self.assertStatus(201, resp) + + # try to do something on it being unauth should return a 401 + resp = self.client.get("/api/projects/raclette") + self.assertStatus(401, resp) + + # PUT / POST / DELETE / GET on the different resources + # should also return a 401 + for verb in ("post",): + for resource in ("/raclette/members", "/raclette/bills"): + url = "/api/projects" + resource + self.assertStatus(401, getattr(self.client, verb)(url), verb + resource) + + for verb in ("get", "delete", "put"): + for resource in ("/raclette", "/raclette/members/1", "/raclette/bills/1"): + url = "/api/projects" + resource + + self.assertStatus(401, getattr(self.client, verb)(url), verb + resource) + + def test_project(self): + # wrong email should return an error + resp = self.client.post( + "/api/projects", + data={ + "name": "raclette", + "id": "raclette", + "password": "raclette", + "contact_email": "not-an-email", + "default_currency": "USD", + }, + ) + + self.assertTrue(400, resp.status_code) + self.assertEqual( + '{"contact_email": ["Invalid email address."]}\n', resp.data.decode("utf-8") + ) + + # create it + resp = self.api_create("raclette") + self.assertTrue(201, resp.status_code) + + # create it twice should return a 400 + resp = self.api_create("raclette") + + self.assertTrue(400, resp.status_code) + self.assertIn("id", json.loads(resp.data.decode("utf-8"))) + + # get information about it + resp = self.client.get( + "/api/projects/raclette", headers=self.get_auth("raclette") + ) + + self.assertTrue(200, resp.status_code) + expected = { + "members": [], + "name": "raclette", + "contact_email": "raclette@notmyidea.org", + "default_currency": "USD", + "id": "raclette", + "logging_preference": 1, + } + decoded_resp = json.loads(resp.data.decode("utf-8")) + self.assertDictEqual(decoded_resp, expected) + + # edit should work + resp = self.client.put( + "/api/projects/raclette", + data={ + "contact_email": "yeah@notmyidea.org", + "default_currency": "USD", + "password": "raclette", + "name": "The raclette party", + "project_history": "y", + }, + headers=self.get_auth("raclette"), + ) + + self.assertEqual(200, resp.status_code) + + resp = self.client.get( + "/api/projects/raclette", headers=self.get_auth("raclette") + ) + + self.assertEqual(200, resp.status_code) + expected = { + "name": "The raclette party", + "contact_email": "yeah@notmyidea.org", + "default_currency": "USD", + "members": [], + "id": "raclette", + "logging_preference": 1, + } + decoded_resp = json.loads(resp.data.decode("utf-8")) + self.assertDictEqual(decoded_resp, expected) + + # password change is possible via API + resp = self.client.put( + "/api/projects/raclette", + data={ + "contact_email": "yeah@notmyidea.org", + "default_currency": "USD", + "password": "tartiflette", + "name": "The raclette party", + }, + headers=self.get_auth("raclette"), + ) + + self.assertEqual(200, resp.status_code) + + resp = self.client.get( + "/api/projects/raclette", headers=self.get_auth("raclette", "tartiflette") + ) + self.assertEqual(200, resp.status_code) + + # delete should work + resp = self.client.delete( + "/api/projects/raclette", headers=self.get_auth("raclette", "tartiflette") + ) + + # get should return a 401 on an unknown resource + resp = self.client.get( + "/api/projects/raclette", headers=self.get_auth("raclette") + ) + self.assertEqual(401, resp.status_code) + + def test_token_creation(self): + """Test that token of project is generated""" + + # Create project + resp = self.api_create("raclette") + self.assertTrue(201, resp.status_code) + + # Get token + resp = self.client.get( + "/api/projects/raclette/token", headers=self.get_auth("raclette") + ) + + self.assertEqual(200, resp.status_code) + + decoded_resp = json.loads(resp.data.decode("utf-8")) + + # Access with token + resp = self.client.get( + "/api/projects/raclette/token", + headers={"Authorization": f"Basic {decoded_resp['token']}"}, + ) + + self.assertEqual(200, resp.status_code) + + def test_token_login(self): + resp = self.api_create("raclette") + # Get token + resp = self.client.get( + "/api/projects/raclette/token", headers=self.get_auth("raclette") + ) + decoded_resp = json.loads(resp.data.decode("utf-8")) + resp = self.client.get("/authenticate?token={}".format(decoded_resp["token"])) + # Test that we are redirected. + self.assertEqual(302, resp.status_code) + + def test_member(self): + # create a project + self.api_create("raclette") + + # get the list of members (should be empty) + req = self.client.get( + "/api/projects/raclette/members", headers=self.get_auth("raclette") + ) + + self.assertStatus(200, req) + self.assertEqual("[]\n", req.data.decode("utf-8")) + + # add a member + req = self.client.post( + "/api/projects/raclette/members", + data={"name": "Zorglub"}, + headers=self.get_auth("raclette"), + ) + + # the id of the new member should be returned + self.assertStatus(201, req) + self.assertEqual("1\n", req.data.decode("utf-8")) + + # the list of members should contain one member + req = self.client.get( + "/api/projects/raclette/members", headers=self.get_auth("raclette") + ) + + self.assertStatus(200, req) + self.assertEqual(len(json.loads(req.data.decode("utf-8"))), 1) + + # Try to add another member with the same name. + req = self.client.post( + "/api/projects/raclette/members", + data={"name": "Zorglub"}, + headers=self.get_auth("raclette"), + ) + self.assertStatus(400, req) + + # edit the member + req = self.client.put( + "/api/projects/raclette/members/1", + data={"name": "Fred", "weight": 2}, + headers=self.get_auth("raclette"), + ) + + self.assertStatus(200, req) + + # get should return the new name + req = self.client.get( + "/api/projects/raclette/members/1", headers=self.get_auth("raclette") + ) + + self.assertStatus(200, req) + self.assertEqual("Fred", json.loads(req.data.decode("utf-8"))["name"]) + self.assertEqual(2, json.loads(req.data.decode("utf-8"))["weight"]) + + # edit this member with same information + # (test PUT idemopotence) + req = self.client.put( + "/api/projects/raclette/members/1", + data={"name": "Fred"}, + headers=self.get_auth("raclette"), + ) + + self.assertStatus(200, req) + + # de-activate the user + req = self.client.put( + "/api/projects/raclette/members/1", + data={"name": "Fred", "activated": False}, + headers=self.get_auth("raclette"), + ) + self.assertStatus(200, req) + + req = self.client.get( + "/api/projects/raclette/members/1", headers=self.get_auth("raclette") + ) + self.assertStatus(200, req) + self.assertEqual(False, json.loads(req.data.decode("utf-8"))["activated"]) + + # re-activate the user + req = self.client.put( + "/api/projects/raclette/members/1", + data={"name": "Fred", "activated": True}, + headers=self.get_auth("raclette"), + ) + + req = self.client.get( + "/api/projects/raclette/members/1", headers=self.get_auth("raclette") + ) + self.assertStatus(200, req) + self.assertEqual(True, json.loads(req.data.decode("utf-8"))["activated"]) + + # delete a member + + req = self.client.delete( + "/api/projects/raclette/members/1", headers=self.get_auth("raclette") + ) + + self.assertStatus(200, req) + + # the list of members should be empty + req = self.client.get( + "/api/projects/raclette/members", headers=self.get_auth("raclette") + ) + + self.assertStatus(200, req) + self.assertEqual("[]\n", req.data.decode("utf-8")) + + def test_bills(self): + # create a project + self.api_create("raclette") + + # add members + self.api_add_member("raclette", "zorglub") + self.api_add_member("raclette", "fred") + self.api_add_member("raclette", "quentin") + + # get the list of bills (should be empty) + req = self.client.get( + "/api/projects/raclette/bills", headers=self.get_auth("raclette") + ) + self.assertStatus(200, req) + + self.assertEqual("[]\n", req.data.decode("utf-8")) + + # add a bill + req = self.client.post( + "/api/projects/raclette/bills", + data={ + "date": "2011-08-10", + "what": "fromage", + "payer": "1", + "payed_for": ["1", "2"], + "amount": "25", + "external_link": "https://raclette.fr", + }, + headers=self.get_auth("raclette"), + ) + + # should return the id + self.assertStatus(201, req) + self.assertEqual(req.data.decode("utf-8"), "1\n") + + # get this bill details + req = self.client.get( + "/api/projects/raclette/bills/1", headers=self.get_auth("raclette") + ) + + # compare with the added info + self.assertStatus(200, req) + expected = { + "what": "fromage", + "payer_id": 1, + "owers": [ + {"activated": True, "id": 1, "name": "zorglub", "weight": 1}, + {"activated": True, "id": 2, "name": "fred", "weight": 1}, + ], + "amount": 25.0, + "date": "2011-08-10", + "id": 1, + "converted_amount": 25.0, + "original_currency": "USD", + "external_link": "https://raclette.fr", + } + + got = json.loads(req.data.decode("utf-8")) + self.assertEqual( + datetime.date.today(), + datetime.datetime.strptime(got["creation_date"], "%Y-%m-%d").date(), + ) + del got["creation_date"] + self.assertDictEqual(expected, got) + + # the list of bills should length 1 + req = self.client.get( + "/api/projects/raclette/bills", headers=self.get_auth("raclette") + ) + self.assertStatus(200, req) + self.assertEqual(1, len(json.loads(req.data.decode("utf-8")))) + + # edit with errors should return an error + req = self.client.put( + "/api/projects/raclette/bills/1", + data={ + "date": "201111111-08-10", # not a date + "what": "fromage", + "payer": "1", + "payed_for": ["1", "2"], + "amount": "25", + "external_link": "https://raclette.fr", + }, + headers=self.get_auth("raclette"), + ) + + self.assertStatus(400, req) + self.assertEqual( + '{"date": ["This field is required."]}\n', req.data.decode("utf-8") + ) + + # edit a bill + req = self.client.put( + "/api/projects/raclette/bills/1", + data={ + "date": "2011-09-10", + "what": "beer", + "payer": "2", + "payed_for": ["1", "2"], + "amount": "25", + "external_link": "https://raclette.fr", + }, + headers=self.get_auth("raclette"), + ) + + # check its fields + req = self.client.get( + "/api/projects/raclette/bills/1", headers=self.get_auth("raclette") + ) + creation_date = datetime.datetime.strptime( + json.loads(req.data.decode("utf-8"))["creation_date"], "%Y-%m-%d" + ).date() + + expected = { + "what": "beer", + "payer_id": 2, + "owers": [ + {"activated": True, "id": 1, "name": "zorglub", "weight": 1}, + {"activated": True, "id": 2, "name": "fred", "weight": 1}, + ], + "amount": 25.0, + "date": "2011-09-10", + "external_link": "https://raclette.fr", + "converted_amount": 25.0, + "original_currency": "USD", + "id": 1, + } + + got = json.loads(req.data.decode("utf-8")) + self.assertEqual( + creation_date, + datetime.datetime.strptime(got["creation_date"], "%Y-%m-%d").date(), + ) + del got["creation_date"] + self.assertDictEqual(expected, got) + + # delete a bill + req = self.client.delete( + "/api/projects/raclette/bills/1", headers=self.get_auth("raclette") + ) + self.assertStatus(200, req) + + # getting it should return a 404 + req = self.client.get( + "/api/projects/raclette/bills/1", headers=self.get_auth("raclette") + ) + self.assertStatus(404, req) + + def test_bills_with_calculation(self): + # create a project + self.api_create("raclette") + + # add members + self.api_add_member("raclette", "zorglub") + self.api_add_member("raclette", "fred") + + # valid amounts + input_expected = [ + ("((100 + 200.25) * 2 - 100) / 2", 250.25), + ("3/2", 1.5), + ("2 + 1 * 5 - 2 / 1", 5), + ] + + for i, pair in enumerate(input_expected): + input_amount, expected_amount = pair + id = i + 1 + + req = self.client.post( + "/api/projects/raclette/bills", + data={ + "date": "2011-08-10", + "what": "fromage", + "payer": "1", + "payed_for": ["1", "2"], + "amount": input_amount, + }, + headers=self.get_auth("raclette"), + ) + + # should return the id + self.assertStatus(201, req) + self.assertEqual(req.data.decode("utf-8"), "{}\n".format(id)) + + # get this bill's details + req = self.client.get( + "/api/projects/raclette/bills/{}".format(id), + headers=self.get_auth("raclette"), + ) + + # compare with the added info + self.assertStatus(200, req) + expected = { + "what": "fromage", + "payer_id": 1, + "owers": [ + {"activated": True, "id": 1, "name": "zorglub", "weight": 1}, + {"activated": True, "id": 2, "name": "fred", "weight": 1}, + ], + "amount": expected_amount, + "date": "2011-08-10", + "id": id, + "external_link": "", + "original_currency": "USD", + "converted_amount": expected_amount, + } + + got = json.loads(req.data.decode("utf-8")) + self.assertEqual( + datetime.date.today(), + datetime.datetime.strptime(got["creation_date"], "%Y-%m-%d").date(), + ) + del got["creation_date"] + self.assertDictEqual(expected, got) + + # should raise errors + erroneous_amounts = [ + "lambda ", # letters + "(20 + 2", # invalid expression + "20/0", # invalid calc + "9999**99999999999999999", # exponents + "2" * 201, # greater than 200 chars, + ] + + for amount in erroneous_amounts: + req = self.client.post( + "/api/projects/raclette/bills", + data={ + "date": "2011-08-10", + "what": "fromage", + "payer": "1", + "payed_for": ["1", "2"], + "amount": amount, + }, + headers=self.get_auth("raclette"), + ) + self.assertStatus(400, req) + + def test_statistics(self): + # create a project + self.api_create("raclette") + + # add members + self.api_add_member("raclette", "zorglub") + self.api_add_member("raclette", "fred") + + # add a bill + req = self.client.post( + "/api/projects/raclette/bills", + data={ + "date": "2011-08-10", + "what": "fromage", + "payer": "1", + "payed_for": ["1", "2"], + "amount": "25", + }, + headers=self.get_auth("raclette"), + ) + + # get the list of bills (should be empty) + req = self.client.get( + "/api/projects/raclette/statistics", headers=self.get_auth("raclette") + ) + self.assertStatus(200, req) + self.assertEqual( + [ + { + "balance": 12.5, + "member": { + "activated": True, + "id": 1, + "name": "zorglub", + "weight": 1.0, + }, + "paid": 25.0, + "spent": 12.5, + }, + { + "balance": -12.5, + "member": { + "activated": True, + "id": 2, + "name": "fred", + "weight": 1.0, + }, + "paid": 0, + "spent": 12.5, + }, + ], + json.loads(req.data.decode("utf-8")), + ) + + def test_username_xss(self): + # create a project + # self.api_create("raclette") + self.post_project("raclette") + self.login("raclette") + + # add members + self.api_add_member("raclette", "