From 542e04db544476c84dc3699da89eafb84c6023a1 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Sun, 13 Nov 2022 01:00:11 +0100 Subject: [PATCH] Feat: Add biweekly and bimonthly and fix translations (#36) --- .github/workflows/release.yml | 7 +- CHANGELOG.md | 4 +- django_q/cluster.py | 70 +-- django_q/conf.py | 2 +- django_q/locale/de/LC_MESSAGES/django.mo | Bin 4333 -> 0 bytes django_q/locale/de/LC_MESSAGES/django.po | 512 ++++++++++-------- django_q/locale/fr/LC_MESSAGES/django.mo | Bin 6405 -> 0 bytes django_q/locale/fr/LC_MESSAGES/django.po | 434 ++++++++++----- django_q/locale/tr/LC_MESSAGES/django.po | 401 ++++++++------ .../0015_alter_schedule_schedule_type.py | 18 + django_q/models.py | 6 +- django_q/monitor.py | 19 +- django_q/signals.py | 6 +- django_q/tests/test_scheduler.py | 24 + docs/schedules.rst | 15 +- 15 files changed, 906 insertions(+), 612 deletions(-) delete mode 100644 django_q/locale/de/LC_MESSAGES/django.mo delete mode 100644 django_q/locale/fr/LC_MESSAGES/django.mo create mode 100644 django_q/migrations/0015_alter_schedule_schedule_type.py diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d9ab35e..8e97b7a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,8 +22,11 @@ jobs: - name: Install dependencies run: | - python -m pip install -U pip setuptools poetry - python -m pip install poetry + apt-get update + apt-get -y install gettext + python -m pip install pip setuptools django poetry + # compile messages to get .mo files + django-admin compilemessages - name: Build and publish package if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') run: poetry --build --username=__token__ --password=${{ secrets.PYPI_TOKEN }} publish diff --git a/CHANGELOG.md b/CHANGELOG.md index ec11595..4debe71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ ## [Unreleased](https://github.com/GDay/django-q2/tree/HEAD) **Merged pull requests:** -- Fix: Deprecation warning for Django 5.x +- Fix: Deprecation warning for Django 5.x https://github.com/GDay/django-q2/pull/34 +- Feat: Add biweekly and bimonthly https://github.com/GDay/django-q2/pull/36 +- Fix: Fix all translation strings and remove compiled https://github.com/GDay/django-q2/pull/36 ## [v1.4.3](https://github.com/GDay/django-q2/tree/v1.4.3) (2022-11-07) diff --git a/django_q/cluster.py b/django_q/cluster.py index 4848a4c..1e95390 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -74,7 +74,7 @@ class Cluster: ), ) self.sentinel.start() - logger.info(_(f"Q Cluster {self.name} starting.")) + logger.info(_("Q Cluster %(name)s starting.") % {'name': self.name}) while not self.start_event.is_set(): sleep(0.1) return self.pid @@ -82,10 +82,10 @@ class Cluster: def stop(self) -> bool: if not self.sentinel.is_alive(): return False - logger.info(_(f"Q Cluster {self.name} stopping.")) + logger.info(_("Q Cluster %(name)s stopping.") % {'name': self.name}) self.stop_event.set() self.sentinel.join() - logger.info(_(f"Q Cluster {self.name} has stopped.")) + logger.info(_("Q Cluster %(name)s has stopped.") % {'name': self.name}) self.start_event = None self.stop_event = None return True @@ -93,8 +93,8 @@ class Cluster: def sig_handler(self, signum, frame): logger.debug( _( - f'{current_process().name} got signal {Conf.SIGNAL_NAMES.get(signum, "UNKNOWN")}' - ) + '%(name)s got signal %(signal)s' + ) % {'name': current_process().name, 'signal': Conf.SIGNAL_NAMES.get(signum, "UNKNOWN")} ) self.stop() @@ -216,21 +216,21 @@ class Sentinel: db.connections.close_all() if process == self.monitor: self.monitor = self.spawn_monitor() - logger.error(_(f"reincarnated monitor {process.name} after sudden death")) + logger.error(_("reincarnated monitor %(name)s after sudden death") % {'name': process.name}) elif process == self.pusher: self.pusher = self.spawn_pusher() - logger.error(_(f"reincarnated pusher {process.name} after sudden death")) + logger.error(_("reincarnated pusher %(name)s after sudden death") % {'name': process.name}) else: self.pool.remove(process) self.spawn_worker() if process.timer.value == 0: # only need to terminate on timeout, otherwise we risk destabilizing the queues process.terminate() - logger.warning(_(f"reincarnated worker {process.name} after timeout")) + logger.warning(_("reincarnated worker %(name)s after timeout") % {'name': process.name}) elif int(process.timer.value) == -2: - logger.info(_(f"recycled worker {process.name}")) + logger.info(_("recycled worker %(name)s") % {'name': process.name}) else: - logger.error(_(f"reincarnated worker {process.name} after death")) + logger.error(_("reincarnated worker %(name)s after death") % {'name': process.name}) self.reincarnations += 1 @@ -253,12 +253,12 @@ class Sentinel: def guard(self): logger.info( _( - f"{current_process().name} guarding cluster {humanize(self.cluster_id.hex)}" - ) + "%(name)s guarding cluster %(cluster_name)s" + ) % {'name': current_process().name, 'cluster_name': humanize(self.cluster_id.hex)} ) self.start_event.set() Stat(self).save() - logger.info(_(f"Q Cluster {humanize(self.cluster_id.hex)} running.")) + logger.info(_("Q Cluster %(cluster_name)s running.") % {'cluster_name': humanize(self.cluster_id.hex)}) counter = 0 cycle = Conf.GUARD_CYCLE # guard loop sleep in seconds # Guard loop. Runs at least once @@ -292,7 +292,7 @@ class Sentinel: def stop(self): Stat(self).save() name = current_process().name - logger.info(_(f"{name} stopping cluster processes")) + logger.info(_("%(name)s stopping cluster processes") % {'name': name}) # Stopping pusher self.event_out.set() # Wait for it to stop @@ -317,7 +317,7 @@ class Sentinel: self.result_queue.close() # Wait for the result queue to empty self.result_queue.join_thread() - logger.info(_(f"{name} waiting for the monitor.")) + logger.info(_("%(name)s waiting for the monitor.") % {'name': name}) # Wait for everything to close or time out count = 0 if not self.timeout: @@ -339,7 +339,7 @@ def pusher(task_queue: Queue, event: Event, broker: Broker = None): """ if not broker: broker = get_broker() - logger.info(_(f"{current_process().name} pushing tasks at {current_process().pid}")) + logger.info(_("%(process_name)s pushing tasks at %(id)s") % {'process_name': current_process().name, 'id': current_process().pid}) while True: try: task_set = broker.dequeue() @@ -360,10 +360,10 @@ def pusher(task_queue: Queue, event: Event, broker: Broker = None): continue task["ack_id"] = ack_id task_queue.put(task) - logger.debug(_(f"queueing from {broker.list_key}")) + logger.debug(_("queueing from %(list_key)s") % {'list_key': broker.list_key}) if event.is_set(): break - logger.info(_(f"{current_process().name} stopped pushing tasks")) + logger.info(_("%(name)s stopped pushing tasks") % {'name': current_process().name}) def monitor(result_queue: Queue, broker: Broker = None): @@ -375,7 +375,7 @@ def monitor(result_queue: Queue, broker: Broker = None): if not broker: broker = get_broker() name = current_process().name - logger.info(_(f"{name} monitoring at {current_process().pid}")) + logger.info(_("%(name)s monitoring at %(id)s") % {'name': name, 'id': current_process().pid}) for task in iter(result_queue.get, "STOP"): # save the result if task.get("cached", False): @@ -392,11 +392,11 @@ def monitor(result_queue: Queue, broker: Broker = None): info_name = get_func_repr(task['func']) if task["success"]: # log success - logger.info(_(f"Processed '{info_name}' ({task['name']})")) + logger.info(_("Processed '%(info_name)s' (%(task_name)s)") % {'info_name': info_name, 'task_name': task['name']}) else: # log failure - logger.error(_(f"Failed '{info_name}' ({task['name']}) - {task['result']}")) - logger.info(_(f"{name} stopped monitoring results")) + logger.error(_("Failed '%(info_name)s' (%(task_name)s) - %(task_result)s") % {'info_name': info_name, 'task_name': task['name'], 'task_result': task['result']}) + logger.info(_("%(name)s stopped monitoring results") % {'name': name}) def worker( @@ -410,7 +410,7 @@ def worker( :type timer: multiprocessing.Value """ proc_name = current_process().name - logger.info(_(f"{proc_name} ready for work at {current_process().pid}")) + logger.info(_("%(proc_name)s ready for work at %(id)s") % {'proc_name': proc_name, 'id': current_process().pid}) task_count = 0 if timeout is None: timeout = -1 @@ -422,7 +422,7 @@ def worker( # Get the function from the task func = task["func"] func_name = get_func_repr(func) - logger.info(_(f"{proc_name} processing '{func_name}' ({task['name']})")) + logger.info(_("%(proc_name)s processing '%(func_name)s' (%(task_name)s)") % {'proc_name': proc_name, 'func_name': func_name, 'task_name': task['name']}) f = task["func"] # if it's not an instance try to get it from the string if not callable(task["func"]): @@ -437,7 +437,7 @@ def worker( res = f(*task["args"], **task["kwargs"]) result = (res, True) except Exception: - result = (f"Could not process '{func_name}'. Check the location of the function and the args/kwargs.", False) + result = (_("Could not process '%(func_name)s'. Check the location of the function and the args/kwargs.") % {'func_name': func_name}, False) if error_reporter: error_reporter.report() if task.get("sync", False): @@ -453,7 +453,7 @@ def worker( if task_count == Conf.RECYCLE or rss_check(): timer.value = -2 # Recycled break - logger.info(_(f"{proc_name} stopped doing work")) + logger.info(_("%(proc_name)s stopped doing work") % {'proc_name': proc_name}) def save_task(task, broker: Broker): """ @@ -632,8 +632,12 @@ def scheduler(broker: Broker = None): next_run = next_run + timedelta(days=1) elif s.schedule_type == s.WEEKLY: next_run = next_run + timedelta(weeks=1) + elif s.schedule_type == s.BIWEEKLY: + next_run = next_run + timedelta(weeks=2) elif s.schedule_type == s.MONTHLY: next_run = add_months(next_run, 1) + elif s.schedule_type == s.BIMONTHLY: + next_run = add_months(next_run, 2) elif s.schedule_type == s.QUARTERLY: next_run = add_months(next_run, 3) elif s.schedule_type == s.YEARLY: @@ -665,14 +669,14 @@ def scheduler(broker: Broker = None): if not s.task: logger.error( _( - f"{current_process().name} failed to create a task from schedule [{s.name or s.id}]" - ) + "%(process_name)s failed to create a task from schedule [%(schedule)s]" + ) % {'process_name': current_process().name, 'schedule': s.name or s.id} ) else: logger.info( _( - f"{current_process().name} created a task from schedule [{s.name or s.id}]" - ) + "%(process_name)s created a task from schedule [%(schedule)s]" + ) % {'process_name': current_process().name, 'schedule': s.name or s.id} ) # default behavior is to delete a ONCE schedule if s.schedule_type == s.ONCE: @@ -711,12 +715,12 @@ def set_cpu_affinity(n: int, process_ids: list, actual: bool = not Conf.TESTING) """ # check if we have the psutil module if not psutil: - logger.warning("Skipping cpu affinity because psutil was not found.") + logger.warning(_("Skipping cpu affinity because psutil was not found.")) return # check if the platform supports cpu_affinity if actual and not hasattr(psutil.Process(process_ids[0]), "cpu_affinity"): logger.warning( - "Faking cpu affinity because it is not supported on this platform" + _("Faking cpu affinity because it is not supported on this platform") ) actual = False # get the available processors @@ -737,7 +741,7 @@ def set_cpu_affinity(n: int, process_ids: list, actual: bool = not Conf.TESTING) p = psutil.Process(pid) if actual: p.cpu_affinity(affinity) - logger.info(_(f"{pid} will use cpu {affinity}")) + logger.info(_("%(pid)s will use cpu %(affinity)s") % {'pid': pid, 'affinity': affinity}) def rss_check(): diff --git a/django_q/conf.py b/django_q/conf.py index 13a1098..886a58e 100644 --- a/django_q/conf.py +++ b/django_q/conf.py @@ -82,7 +82,7 @@ class Conf: # Verify SAVE_LIMIT_PER is valid if SAVE_LIMIT_PER not in ["group", "name", "func", None]: - warn(f"SAVE_LIMIT_PER ({SAVE_LIMIT_PER}) is not a valid option. Options are: 'group', 'name', 'func' and None. Default is None.") + warn(_("SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', 'name', 'func' and None. Default is None.") % {'option': SAVE_LIMIT_PER}) # Guard loop sleep in seconds. Should be between 0 and 60 seconds. GUARD_CYCLE = conf.get("guard_cycle", 0.5) diff --git a/django_q/locale/de/LC_MESSAGES/django.mo b/django_q/locale/de/LC_MESSAGES/django.mo deleted file mode 100644 index 2a2ec938cbdb56022d0a52782fad7b09ed2d3edf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4333 zcmb`JU2Ggz6@V`#Eyewzl)nOn-lP!Qjc4n1TjDx#iyb?ulX&C5#A%}tjd$ledrFQo`?H)aG`zw&SLxncsJvJm)voeQlDph zACy<0fFFXRkXO`m@G)3}_rP^{FT4ar&Ntw0_+2R9{{r$;*SMg9dZnCy6@Gy6@8PH6 z^>X|c6ghYB@Kf*}xEt<M$ z--aUhN06WTDVNW{E)>09hqA9XAWN$^%lZF8+2>s>CVJctKL#I#qR-PM_d{9tStxRj zmOKtczb`>K*8!AxxCF)DFTq{#Whi?5s^o8=#K~(=*8c}Q0sjS$!5W*Z!S6xBAwOdv z_r1iowB2-BTl^zU_AhJ5zNLMZK1kmy1Dg1$*G9P!`^lbq?b+T9l-Q9bdlElAP5&bO zb9C8Pg)Vj=4D)ybx&2T-j|&+~+(~hGoH<#k`<>AFQFy@&3|`b5dRJvvP(WV1928Lw2hsv$JUy<(=OJ&UDs1#dM-0O zX&By0Vw+#IIp0Z4nud(0{4iQq2f3PtKDFWeboErf_1mWZ^u^PfJrpy%o<)wi-m5Zw z<9(VBGTu{%j5UcLu^0B#_8rUUc+Di*k0M^ z#Yw8?b-79H*Il?4x^;Qx0=}u4^G+{hR@LI0_9-@KhAmWSs9M%uVd1!`+lA!Z%q}px zTuHn2j#0;K-Ke?9_^Cnb6gQzL)(Ww%n9^8(B{KQc4Yo_wTpUMgOT~>KYx`C_oSLXv zDYtqiY*Yes9_J;QwV`cQ)O_YAh-MS>naR+zfX|WCB;p) z(hi+wA>57YLweEk9J` zkwc`5I~_F7nSYVh>%^2=EQk}!yJi*@8+*q%RZH{gct-D%bE*OjTXD!MwPM}~C&;W)7U#mxC}=GMoVl?Wa$9|gpiD*Ugk9@jQM zJ?W74s*H$HLvX6p5H}6AQO}aZSa+tA#Im1(!HUSbs9T(_G;CP{yExa2GlyyuN6*wI zW~Ub`E#n5{Y1SUnyN=h6)Q&CJb`4(qKjH|12K($C2z{I2d3Q;jEDc0Z5dpr_+ial| zHZH2UBtA>9cry*}1eWGlj_E!^D^8p@o3_G+H<`6kZz*Pa?wGe=)J9UIN>@k6Mn?Axj|>m@9raV^EhWB9BcB61rVq!~PxW$WS0j_~*tRmiWxOThw-MVL zkLiZ-rl$L5XJ)6jl&MyR`$(A%^LrAvW7=`XAMZqdX!q%Q;3uhZwn=;{OX@*d56Cets^}L?=z95F9U+N3qc3E7)r8ix%k<_QA;TN1 ziPn|SHcXMs^Nj9IWN9PG>Z@w0d$|>b^+4T{%fr;^rU{~!Vc7_$*lpAMO>Y=Iku_WX zictr*pSSq~5y-kmO+<)qi_&^#EBmuj_p0P!@~Y`2^dkQ+y6#om$Q7mr95p0GELPS5 ztLDAU^uJ2_FT}j)liaM-0pI0c*1DImB^JX9&FTMUbeAVp$GXKgL@wQxlDYJD~L zpD$YHua~uAb3eB^?pnNs$q0*zIwAU+=xq0LkmMUisg^tooak5HZux4PIjf3FvK*R* zNrE_tun|VA8U8}#B?a5H%!@1$<%Z0?Zna6Q$(;5}!}5hhDksv)38mD_?bZjkO!VIG zUbaRphe<;dezKr(Qb>f_@TaFJGv21Zi!zhRpNUi|jobP-A5ACCIBKZ^rX&_2GB!iD zczE-q?G>Hw6$zpuekPI?Hbo66Z=5>3Y3fr`N$$9KX|Q$#1D*B1}7> ziEb`QH$Be-^KT?Osz<= q=w5Xf3dz0Gc$?^b_hLov>RxF!OUpa)l`r|l5@ICETZ?aAx&8+mTVNCb diff --git a/django_q/locale/de/LC_MESSAGES/django.po b/django_q/locale/de/LC_MESSAGES/django.po index f2fb630..4110726 100644 --- a/django_q/locale/de/LC_MESSAGES/django.po +++ b/django_q/locale/de/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-01-15 15:53+0100\n" +"POT-Creation-Date: 2022-11-12 01:47+0000\n" "PO-Revision-Date: 2018-08-05 18:28+0200\n" "Last-Translator: Jonas Winkler\n" "Language-Team: \n" @@ -17,431 +17,471 @@ msgstr "" "X-Generator: Poedit 2.1.1\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: admin.py:40 +#: django_q/admin.py:43 msgid "Resubmit selected tasks to queue" msgstr "Ausgewählte Aufgaben erneut ausführen" -#: brokers/disque.py:59 -msgid "No Disque nodes configured" -msgstr "Keine Disque-Knoten konfiguriert" +#: django_q/admin.py:98 django_q/models.py:228 +#, fuzzy +#| msgid "Success" +msgid "success" +msgstr "erfolg" -#: brokers/disque.py:76 -msgid "Could not connect to any Disque nodes" -msgstr "Konnte zu keinem Disque-Knoten verbinden" +#: django_q/admin.py:109 django_q/models.py:230 +msgid "last_run" +msgstr "" -#: cluster.py:76 -#, fuzzy, python-brace-format -#| msgid "Q Cluster-{} starting." -msgid "Q Cluster {self.name} starting." -msgstr "Q-Cluster {self.name} wird gestartet." +#: django_q/cluster.py:77 +#, python-format +msgid "Q Cluster %(name)s starting." +msgstr "Q-Cluster %(name)s wird gestartet." -#: cluster.py:84 -#, fuzzy, python-brace-format +#: django_q/cluster.py:85 +#, fuzzy, python-format #| msgid "Q Cluster-{} stopping." -msgid "Q Cluster {self.name} stopping." -msgstr "Q-Cluster {self.name} wird gestoppt." +msgid "Q Cluster %(name)s stopping." +msgstr "Q-Cluster {name} wird gestoppt." -#: cluster.py:87 -#, fuzzy, python-brace-format -#| msgid "Q Cluster-{} has stopped." -msgid "Q Cluster {self.name} has stopped." -msgstr "Q-Cluster {self.name} wurde gestoppt." +#: django_q/cluster.py:88 +#, python-format +msgid "Q Cluster %(name)s has stopped." +msgstr "Q-Cluster %(name)s wurde gestoppt." -#: cluster.py:95 +#: django_q/cluster.py:96 +#, python-format +msgid "%(name)s got signal %(signal)s" +msgstr "%(name)s erhielt das Signal %(signal)s" + +#: django_q/cluster.py:219 +#, python-format +msgid "reincarnated monitor %(name)s after sudden death" +msgstr "Monitor %(name)s wurde nach unerwartetem Absturz neu gestartet" + +#: django_q/cluster.py:222 +#, python-format +msgid "reincarnated pusher %(name)s after sudden death" +msgstr "Pusher %(name)s wurde nach unerwartetem Absturz neu gestartet" + +#: django_q/cluster.py:229 +#, python-format +msgid "reincarnated worker %(name)s after timeout" +msgstr "Worker %(name)s wurde nach Zeitüberschreitung neu gestartet" + +#: django_q/cluster.py:231 +#, python-format +msgid "recycled worker %(name)s" +msgstr "Worker %(name)s wurde wiederverwendet" + +#: django_q/cluster.py:233 +#, python-format +msgid "reincarnated worker %(name)s after death" +msgstr "Worker %(name)s wurde nach unerwartetem Absturz neu gestartet" + +#: django_q/cluster.py:256 +#, python-format +msgid "%(name)s guarding cluster %(cluster_name)s" +msgstr "%(name)s beschützt das Cluster %(cluster_name)s" + +#: django_q/cluster.py:261 +#, python-format +msgid "Q Cluster %(cluster_name)s running." +msgstr "Q-Cluster %(cluster_name)s läuft." + +#: django_q/cluster.py:295 +#, python-format +msgid "%(name)s stopping cluster processes" +msgstr "%(name)s hält Cluster-Prozesse an" + +#: django_q/cluster.py:320 +#, python-format +msgid "%(name)s waiting for the monitor." +msgstr "%(name)s wartet auf den Monitor." + +#: django_q/cluster.py:342 +#, python-format +msgid "%(process_name)s pushing tasks at %(id)s" +msgstr "%(process_name)s veröffentlicht Aufagaben auf %(id)s" + +#: django_q/cluster.py:363 +#, python-format +msgid "queueing from %(list_key)s" +msgstr "Einreihen von %(list_key)s" + +#: django_q/cluster.py:366 +#, python-format +msgid "%(name)s stopped pushing tasks" +msgstr "%(name)s veröffentlicht keine Aufgaben mehr" + +#: django_q/cluster.py:378 +#, python-format +msgid "%(name)s monitoring at %(id)s" +msgstr "%(name)s beobachtet auf %(id)s" + +#: django_q/cluster.py:395 +#, python-format +msgid "Processed '%(info_name)s' (%(task_name)s)" +msgstr "[%(task_name)s] - '%(info_name)s' wurde verarbeitet" + +#: django_q/cluster.py:398 +#, python-format +msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s" +msgstr "'%(info_name)s' (%(task_name)s) ist fehlgeschlagen - %(task_result)s" + +#: django_q/cluster.py:399 +#, python-format +msgid "%(name)s stopped monitoring results" +msgstr "%(name)s überwacht keine Ergebnisse mehr" + +#: django_q/cluster.py:413 +#, python-format +msgid "%(proc_name)s ready for work at %(id)s" +msgstr "%(proc_name)s ist bereit für Arbeit auf %(id)s" + +#: django_q/cluster.py:425 +#, python-format +msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" +msgstr "%(proc_name)s verarbeitet '%(func_name)s' (%(task_name)s)" + +#: django_q/cluster.py:440 +#, python-format msgid "" -"{current_process().name} got signal {Conf.SIGNAL_NAMES.get(signum, \"UNKNOWN" -"\")}" +"Could not process '%(func_name)s'. Check the location of the function and " +"the args/kwargs." msgstr "" -"{current_process().name} erhielt das Signal {Conf.SIGNAL_NAMES.get(signum, " -"\"UNKNOWN\")}" +"Konnte '%(func_name)s' nicht verarbeiten. Überprüfen Sie den Ort der " +"Funktion und die args/kwargs." -#: cluster.py:216 -#, fuzzy, python-brace-format -#| msgid "reincarnated monitor {} after sudden death" -msgid "reincarnated monitor {process.name} after sudden death" -msgstr "Monitor {process.name} wurde nach unerwartetem Absturz neu gestartet" +#: django_q/cluster.py:456 +#, python-format +msgid "%(proc_name)s stopped doing work" +msgstr "%(proc_name)s hat die Arbeit beendet" -#: cluster.py:219 -#, fuzzy, python-brace-format -#| msgid "reincarnated pusher {} after sudden death" -msgid "reincarnated pusher {process.name} after sudden death" -msgstr "Pusher {process.name} wurde nach unerwartetem Absturz neu gestartet" - -#: cluster.py:226 -#, fuzzy, python-brace-format -#| msgid "reincarnated worker {} after timeout" -msgid "reincarnated worker {process.name} after timeout" -msgstr "Worker {process.name} wurde nach Zeitüberschreitung neu gestartet" - -#: cluster.py:228 -#, fuzzy, python-brace-format -#| msgid "recycled worker {}" -msgid "recycled worker {process.name}" -msgstr "Worker {process.name} wurde wiederverwendet" - -#: cluster.py:230 -#, fuzzy, python-brace-format -#| msgid "reincarnated worker {} after death" -msgid "reincarnated worker {process.name} after death" -msgstr "Worker {process.name} wurde nach unerwartetem Absturz neu gestartet" - -#: cluster.py:251 -msgid "" -"{current_process().name} guarding cluster {humanize(self.cluster_id.hex)}" -msgstr "" -"{current_process().name} beschützt das Cluster {humanize(self.cluster_id." -"hex)}" - -#: cluster.py:256 -msgid "Q Cluster {humanize(self.cluster_id.hex)} running." -msgstr "Q-Cluster {humanize(self.cluster_id.hex)} ist bereit." - -#: cluster.py:290 -#, fuzzy, python-brace-format -#| msgid "{} stopping cluster processes" -msgid "{name} stopping cluster processes" -msgstr "{name} hält Cluster-Prozesse an" - -#: cluster.py:315 -#, fuzzy, python-brace-format -#| msgid "{} waiting for the monitor." -msgid "{name} waiting for the monitor." -msgstr "{name} wartet auf den Monitor." - -#: cluster.py:337 -msgid "{current_process().name} pushing tasks at {current_process().pid}" -msgstr "" -"{current_process().name} veröffentlicht Aufagaben auf {current_process().pid}" - -#: cluster.py:358 -#, fuzzy, python-brace-format -#| msgid "queueing from {}" -msgid "queueing from {broker.list_key}" -msgstr "Einreihen von {broker.list_key}" - -#: cluster.py:361 -#, fuzzy -#| msgid "{} stopped pushing tasks" -msgid "{current_process().name} stopped pushing tasks" -msgstr "{current_process().name} veröffentlicht keine Aufgaben mehr" - -#: cluster.py:373 -#, fuzzy -#| msgid "{} monitoring at {}" -msgid "{name} monitoring at {current_process().pid}" -msgstr "{name} beobachtet auf {current_process().pid}" - -#: cluster.py:387 -#, fuzzy -#| msgid "Processed [{}]" -msgid "Processed [{task['name']}]" -msgstr "[{task['name']}] wurde verarbeitet" - -#: cluster.py:390 -msgid "Failed [{task['name']}] - {task['result']}" -msgstr "[{task['name']}] ist fehlgeschlagen - {task['result']}" - -#: cluster.py:391 -#, fuzzy, python-brace-format -#| msgid "{} stopped monitoring results" -msgid "{name} stopped monitoring results" -msgstr "{name} überwacht keine Ergebnisse mehr" - -#: cluster.py:405 -#, fuzzy -#| msgid "{} ready for work at {}" -msgid "{name} ready for work at {current_process().pid}" -msgstr "{name} ist bereit für Arbeit auf {current_process().pid}" - -#: cluster.py:415 -#, fuzzy -#| msgid "{} processing [{}]" -msgid "{name} processing [{task[\"name\"]}]" -msgstr "{name} verarbeitet [{task[\"name\"]}]" - -#: cluster.py:455 -#, fuzzy, python-brace-format -#| msgid "{} stopped doing work" -msgid "{name} stopped doing work" -msgstr "{name} hat die Arbeit beendet" - -#: cluster.py:619 models.py:143 +#: django_q/cluster.py:649 django_q/models.py:144 msgid "Please install croniter to enable cron expressions" msgstr "Bitte installieren Sie croniter, um Cron-Ausdrücke zu aktivieren" -#: cluster.py:644 -#, fuzzy -#| msgid "{} failed to create a task from schedule [{}]" -msgid "" -"{current_process().name} failed to create a task from schedule [{s.name or s." -"id}]" +#: django_q/cluster.py:672 +#, python-format +msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]" msgstr "" -"{current_process().name} konnte keine Aufgabe von Zeitplan [{s.name or s." -"id}] erstellen" +"%(process_name)s konnte keine Aufgabe von Zeitplan [%(schedule)s] erstellen" -#: cluster.py:650 -#, fuzzy -#| msgid "{} created a task from schedule [{}]" -msgid "" -"{current_process().name} created a task from schedule [{s.name or s.id}]" +#: django_q/cluster.py:678 +#, python-format +msgid "%(process_name)s created a task from schedule [%(schedule)s]" msgstr "" -"{current_process().name} hat eine Aufgabe des Zeitplans [{s.name or s.id}] " -"erstellt" +"%(process_name)s hat eine Aufgabe des Zeitplans [%(schedule)s] erstellt" -#: cluster.py:716 -#, fuzzy, python-brace-format -#| msgid "{} will use cpu {}" -msgid "{pid} will use cpu {affinity}" -msgstr "{pid} wird CPU {affinity} benutzen" +#: django_q/cluster.py:718 +msgid "Skipping cpu affinity because psutil was not found." +msgstr "Cpu-Affinität wird übersprungen, da psutil nicht gefunden wurde." + +#: django_q/cluster.py:723 +msgid "Faking cpu affinity because it is not supported on this platform" +msgstr "" +"Vortäuschen von CPU-Affinität, da diese auf dieser Plattform nicht " +"unterstützt wird" + +#: django_q/cluster.py:744 +#, python-format +msgid "%(pid)s will use cpu %(affinity)s" +msgstr "%(pid)s wird CPU %(affinity)s benutzen" + +#: django_q/conf.py:85 +#, python-format +msgid "" +"SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " +"'name', 'func' and None. Default is None." +msgstr "" +"SAVE_LIMIT_PER (%(option)s) ist keine gültige Option. Optionen sind: " +"'group', 'name', 'func' und None. Standard ist None." #. Translators: Cluster status descriptions -#: conf.py:184 +#: django_q/conf.py:194 msgid "Starting" msgstr "Wird gestartet" -#: conf.py:185 +#: django_q/conf.py:195 msgid "Working" msgstr "Arbeitet" -#: conf.py:186 +#: django_q/conf.py:196 msgid "Idle" msgstr "Leerlauf" -#: conf.py:187 +#: django_q/conf.py:197 msgid "Stopped" msgstr "Gestoppt" -#: conf.py:188 +#: django_q/conf.py:198 msgid "Stopping" msgstr "Wird gestoppt" #. Translators: help text for qcluster management command -#: management/commands/qcluster.py:9 +#: django_q/management/commands/qcluster.py:9 msgid "Starts a Django Q Cluster." msgstr "Startet ein Django-Q-Cluster." #. Translators: help text for qinfo management command -#: management/commands/qinfo.py:11 +#: django_q/management/commands/qinfo.py:11 msgid "General information over all clusters." msgstr "Allgemeine Informationen über alle Cluster" +#. Translators: help text for qmemory management command +#: django_q/management/commands/qmemory.py:9 +msgid "Monitors Q Cluster memory usage" +msgstr "Überwacht die Speichernutzung von Q Cluster" + #. Translators: help text for qmonitor management command -#: management/commands/qmonitor.py:9 +#: django_q/management/commands/qmonitor.py:9 msgid "Monitors Q Cluster activity" msgstr "Q-Cluster aktiv überwachen" -#: models.py:118 +#: django_q/models.py:119 msgid "Successful task" msgstr "Erfolgreiche Aufgabe" -#: models.py:119 +#: django_q/models.py:120 msgid "Successful tasks" msgstr "Erfolgreiche Aufgaben" -#: models.py:134 +#: django_q/models.py:135 msgid "Failed task" msgstr "Fehlgeschlagene Aufgabe" -#: models.py:135 +#: django_q/models.py:136 msgid "Failed tasks" msgstr "Fehlgeschlagene Aufgaben" -#: models.py:159 +#: django_q/models.py:160 msgid "e.g. 1, 2, 'John'" msgstr "zum Beispiel 1, 2, 'John'" -#: models.py:161 +#: django_q/models.py:162 msgid "e.g. x=1, y=2, name='John'" msgstr "zum Beispiel x=1, y=2, name='John'" -#: models.py:173 +#: django_q/models.py:176 msgid "Once" msgstr "Einmal" -#: models.py:174 +#: django_q/models.py:177 msgid "Minutes" msgstr "Minuten" -#: models.py:175 +#: django_q/models.py:178 msgid "Hourly" msgstr "Stündlich" -#: models.py:176 +#: django_q/models.py:179 msgid "Daily" msgstr "Täglich" -#: models.py:177 +#: django_q/models.py:180 msgid "Weekly" msgstr "Wöchentlich" -#: models.py:178 +#: django_q/models.py:181 +msgid "Biweekly" +msgstr "Zweiwöchentlich" + +#: django_q/models.py:182 msgid "Monthly" msgstr "Monatlich" -#: models.py:179 +#: django_q/models.py:183 +msgid "Bimonthly" +msgstr "Zweimonatlich" + +#: django_q/models.py:184 msgid "Quarterly" msgstr "Vierteljährlich" -#: models.py:180 +#: django_q/models.py:185 msgid "Yearly" msgstr "Jährlich" -#: models.py:181 +#: django_q/models.py:186 msgid "Cron" msgstr "Cron" -#: models.py:184 +#: django_q/models.py:189 msgid "Schedule Type" msgstr "Zeitplan-Typ" -#: models.py:187 +#: django_q/models.py:192 msgid "Number of minutes for the Minutes type" msgstr "Anzahl Minuten für den Typ 'Minuten'" -#: models.py:190 +#: django_q/models.py:195 msgid "Repeats" msgstr "Wiederhohlungen" -#: models.py:190 +#: django_q/models.py:195 msgid "n = n times, -1 = forever" msgstr "n = n mal, -1 = für immer" -#: models.py:193 +#: django_q/models.py:198 msgid "Next Run" msgstr "Nächste Ausführung" -#: models.py:200 +#: django_q/models.py:205 msgid "Cron expression" msgstr "Cron-Ausdruck" -#: models.py:226 +#: django_q/models.py:235 msgid "Scheduled task" msgstr "Geplante Aufgabe" -#: models.py:227 +#: django_q/models.py:236 msgid "Scheduled tasks" msgstr "Geplante Aufgaben" -#: models.py:250 +#: django_q/models.py:262 msgid "Queued task" msgstr "Eingereihte Aufgabe" -#: models.py:251 +#: django_q/models.py:263 msgid "Queued tasks" msgstr "Eingereihte Aufgaben" -#: monitor.py:35 +#: django_q/monitor.py:62 django_q/monitor.py:339 msgid "Host" msgstr "Host" -#: monitor.py:39 +#: django_q/monitor.py:66 django_q/monitor.py:343 django_q/monitor.py:450 msgid "Id" msgstr "Id" -#: monitor.py:43 +#: django_q/monitor.py:70 msgid "State" msgstr "Status" -#: monitor.py:47 +#: django_q/monitor.py:74 msgid "Pool" msgstr "Pool" -#: monitor.py:51 +#: django_q/monitor.py:78 msgid "TQ" msgstr "TQ" -#: monitor.py:55 +#: django_q/monitor.py:82 msgid "RQ" msgstr "RQ" -#: monitor.py:59 +#: django_q/monitor.py:86 msgid "RC" msgstr "RC" -#: monitor.py:63 +#: django_q/monitor.py:90 msgid "Up" msgstr "Up" -#: monitor.py:143 monitor.py:247 +#: django_q/monitor.py:170 django_q/monitor.py:279 msgid "Queued" msgstr "Eingereiht" -#: monitor.py:151 +#: django_q/monitor.py:178 msgid "Success" msgstr "Erfolg" -#: monitor.py:161 monitor.py:255 +#: django_q/monitor.py:188 django_q/monitor.py:287 msgid "Failures" msgstr "Fehlschläge" -#: monitor.py:172 +#: django_q/monitor.py:199 django_q/monitor.py:485 msgid "[Press q to quit]" msgstr "[Drücken Sie q zum Beenden]" -#: monitor.py:191 +#: django_q/monitor.py:223 msgid "day" msgstr "Tag" -#: monitor.py:212 +#: django_q/monitor.py:244 msgid "second" msgstr "Sekunde" -#: monitor.py:215 +#: django_q/monitor.py:247 msgid "minute" msgstr "Minute" -#: monitor.py:218 +#: django_q/monitor.py:250 msgid "hour" msgstr "Stunde" -#: monitor.py:228 -msgid "" -"-- {Conf.PREFIX.capitalize()} { \".\".join(str(v) for v in VERSION)} on " -"{broker.info()} --" -msgstr "" -"-- {Conf.PREFIX.capitalize()} { \".\".join(str(v) for v in VERSION)} auf " -"{broker.info()} --" +#: django_q/monitor.py:260 +#, python-format +msgid "-- %(prefix)s %(version)s on %(info)s --" +msgstr "-- %(prefix)s %(version)s auf %(info)s --" -#: monitor.py:234 +#: django_q/monitor.py:266 msgid "Clusters" msgstr "Cluster" -#: monitor.py:238 +#: django_q/monitor.py:270 msgid "Workers" msgstr "Arbeiter" -#: monitor.py:242 +#: django_q/monitor.py:274 msgid "Restarts" msgstr "Neustarts" -#: monitor.py:251 +#: django_q/monitor.py:283 msgid "Successes" msgstr "Erfolge" -#: monitor.py:260 +#: django_q/monitor.py:292 msgid "Schedules" msgstr "Zeitpläne" -#: monitor.py:264 -#, fuzzy, python-brace-format -#| msgid "Tasks/{}" -msgid "Tasks/{per}" -msgstr "Aufgaben/{per}" +#: django_q/monitor.py:296 +#, python-format +msgid "Tasks/%(per)s" +msgstr "Aufgaben/%(per)s" -#: monitor.py:268 +#: django_q/monitor.py:300 msgid "Avg time" msgstr "Durchschnittl. Zeit" -#: signals.py:22 -#, fuzzy, python-brace-format -#| msgid "malformed return hook '{}' for [{}]" -msgid "malformed return hook '{instance.hook}' for [{instance.name}]" -msgstr "Ungültiger Return-Hook '{instance.hook}' für [{instance.name}]" +#: django_q/monitor.py:348 +msgid "Available (%)" +msgstr "Verfügbar (%)" -#: signals.py:30 -#, fuzzy -#| msgid "return hook {} failed on [{}] because {}" -msgid "" -"return hook {instance.hook} failed on [{instance.name}] because {str(e)}" -msgstr "" -"Return-Hook {instance.hook} für [{instance.name}] ist gescheitert: {str(e)}" +#: django_q/monitor.py:354 +msgid "Available (MB)" +msgstr "Verfügbar (MB)" + +#: django_q/monitor.py:359 +msgid "Total (MB)" +msgstr "Insgesamt (MB)" + +#: django_q/monitor.py:364 +msgid "Sentinel (MB)" +msgstr "Sentinel (MB)" + +#: django_q/monitor.py:370 +msgid "Monitor (MB)" +msgstr "Monitor (MB)" + +#: django_q/monitor.py:376 +msgid "Workers (MB)" +msgstr "Arbeiter (MB)" + +#: django_q/monitor.py:478 +#, python-format +msgid "Available lowest (): %(memory_percent)s ((at)s)" +msgstr "Niedrigste verfügbar (): %(memory_percent)s ((at)s)" + +#: django_q/monitor.py:496 +msgid "No clusters appear to be running." +msgstr "Es scheinen keine Cluster zu laufen." + +#: django_q/signals.py:22 +#, python-format +msgid "malformed return hook '%(hook)s' for [%(name)s]" +msgstr "Ungültiger Return-Hook '%(hook)s' für [%(name)s]" + +#: django_q/signals.py:30 +#, python-format +msgid "return hook %(hook)s failed on [%(name)s] because %(error)s" +msgstr "Return-Hook %(hook)s für [%(name)s] ist gescheitert: %(error)s" diff --git a/django_q/locale/fr/LC_MESSAGES/django.mo b/django_q/locale/fr/LC_MESSAGES/django.mo deleted file mode 100644 index 347a8392b0bad5b6c5dcafb3a4f107caa35a2a93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6405 zcmb7{Ym6jS6~`}#D2w<2e5|5e0e67i?wuLfWte4vW#727J2N}WQ(SAi?o8KicU4b4 zmK_NR(TJbaL}TJ3CWMf{kYI=yO)w;e_7O>l@9@PC0VDAX!DM695904%b-R1^(Jof{ z_OI@(bI-l^oO5rTdimn>zG=7)QZA$X>|A4(VC$XyagDyqn2X^Ud^gEbR9sC+R5B>j-p#D9m@gIkp@AskR`z+Lae(CuFWGM3@hx(7<%=lt`guP;G2f>*$o;8pP7@M?HD#+07jQ0@C+4dzh#9);5X47>!s2&MlOC_kNmABGp= z4EgU$_;Gk6{0O|$*E>-0@l~k)Pr?%{=sBoye!${UWx7!I`88z8<|QcmzT)|JsQ%~h zCx2cFH^M8R{51y=F?T`v;Rs}@rVXX{IJ_J_XOQ}BrWvAz${Pwzk{wCyS{>k4b z;Ds1L_P-WtJ^P^6e*|j1Uw|6_yT1Mul>L4IHJ?9wz6Q0vze26!O?VUh50qWEFe&Mo zgEW~CDsGQMt>?>7cK$k)|DJ}L_m83Ee+sqUKY0EL%8q}5(t84GKIh{!>AL`y@da^- zSqnA4bx?L4g&Jow)Oj-nC4Ub@l{o}I1#>9*??A=ZBT)T*1!bS#K=uC{lwHqfv76vp z&;4+O`j_Bs@F_R}--KGvH5hvgj=@`D14{2>(8A{+s?Ez#{yG8qnM)8-eLa*vZikv* z2(N%&@q8L;zx^IEqWS8LM# zzL~OvqF9t26a(uhy0jl;qurEA%6iHiWiMq5Wt?Iuz3Y?Q%uuwx?UaKQ?P2*t*G|er zd1p-BQ#e4m%GVVe)0A6%y@wmPQM|}UiU-+Fmwcf8`f182<(WN+^FYoXR)ILzG&r;5%;DXXeimPiWiVt1d_lnik*Y&=l7?6Jz+xyj4tJw!0 z)GvwkZ)-KP_1L1#qqZ~KT1A$-G&9?SsI_c%^6x@>?*k9sXVt6MkO$e()%RIhDN>i2 zT`qQM(6UjykfiM(j~FF6=29E9TDIZU*Uj!E%lRu(M%fecYdJF=#YK*a=_HQwB+cxs z_4BboBae_wtkpHMd19BO(Hv+rU0Af7o!2sZ zwMy)iYSyoF=VxBsWHzwdj|A~zGO&4Fk8)I2_Nd6B%z>gI1NMl+e9J=7sup%iJu~yO zW?s|YNC+M5m^+<2ib?KF(xZwsQHt+&fh=|J3~`j%rD}~)exC`0W#j6Lbvw4fj&HCd zw95Y z#^nykHrU!2HF`Rt)|5tOa&{q2+S&oBYb-akDef<4Uo}N>BS>Sc720+cytLb30oU8C z2tya!5WhC*y-KuGWK9I#hGc&%uk#GbP8HF1PKuln2Ww}fg=$B$Da%cL*foM8b6Q2_ z8c7@)WEv@RWhp`F&1&UYFU(4_4HOZFmH7XbUQCGKXfftsU?{pTvN1y0)gK8q$o&&< zKt1cXb*eq9w%+(Mp6b)5-%SpRtX8(L` zn|wgEwjEbY+VRn`iP|W?O?GV4dJTrgsd+8>^45*~YQz;=HCqWYXpwt{Xe8Ad0uxMl(n=mros>-&va&$fZG?Ex5F{ zBW@(}Y2NnFUuHC`X9kMX3c)@}+>_u8!@^cI=uhYxV{iGt|hfpd4Vn8M!oFwzus+xOe}qeLL(; zgmBKg;?_J~ta0CPojj{IlJ?DXu52(#JP#&wfFq~ToMAe((MfwaO>`h_Oqq9fsH)XF z%V!iH8;CRWVN&A*DZ*ee876n#KrTv?xVHHy5hbqBW)e$vZ3vMc32*V}t&spro{zW8ot>H@WNVC8Tq$ACt)5ZP`UQ&n7wk&MU zPFNVK2jk*%cH}ULajbh52aRLipwk(;qH$~+guHAu1_>yqq|VnuFF(@HdDre_b~;&h zvDuZPh=X*tNb)F*XxYK5r?Dyro$o$Mi|wv7c+GcLOjXbN4Rqe#UD1oK6>tJ%X3roM z&Fo@#CGM_p;y6-0CXgpZW>xV^%*aiNDlhhYlqZ@LCdUlRl7Mz z$Au)y%uJLu&|)|U8A5wjV&!Y`q+B+@AUU%N(zN>|H>aeoq$CZ7%4|3?m``1nYtw_% zKw4KTtedT+rqkQ8RAr|nWxKWT)rY=aT1?hj-~)modPeiUWAHOR$n5D)d}7>P>98J` zk{XBoIhOfxQnX#3V@0_tFM|Wuc2|@yV`IEcd-oCB3Qil8x1E;5tB&k`A!?MbTpv(n zD~)vThnNJbCj3y{SAEKm^M>o$(AfeTS6@8+?7GUT$;&EZ622J8I|92^&MFh??h{pF zEqb%1-IXHCqQQK64M>n-S4&rpy*prp-R^Lhw1Y5+Qa*jE464YC;&s7njbjDny==B( z*?qp;3QM*OzNI1}#MArC5oOWtcrWdK^`URw?t++EnogY{uG`}z%1XZh2{^IL%_^xX z2+FJ*Ba?_Kw8_eq8MV7BBRT^{$|1|>Jt-GgsBb7UaiU8T$;j2on@)=l`HvO*42(dm z5_Ak(p2OOMSSgCx0gK#d%%GEERC%W|H{YskBn}-JhWYSu_<#56nRnP=-m$BudA3Ov zY(y_r15OR@FZMOJ~ZYwnKK~^vaTnss!JeQnrCDu!aVy zwv2WN;(3(HqP_3Pe!5*9!aQLYsc-dRACA0j1*lJ5_whn!+eu#n9Ky$(KdV$x< zO!mM@0_9R@B@q0!VFiPuu=jc37vu=BmHLM* z&K#MnclZ%u-4%T!@SQHP)${kZ<@2>tQ3aFE^Zv5@C5g=kr?Wg>v}~ T!JDJSR!9Sxa@)*7i<$llGe`#c diff --git a/django_q/locale/fr/LC_MESSAGES/django.po b/django_q/locale/fr/LC_MESSAGES/django.po index 9740bc5..26dbaef 100644 --- a/django_q/locale/fr/LC_MESSAGES/django.po +++ b/django_q/locale/fr/LC_MESSAGES/django.po @@ -6,349 +6,489 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-08-05 15:48+0200\n" +"POT-Creation-Date: 2022-11-12 01:47+0000\n" "PO-Revision-Date: 2018-08-05 18:28+0200\n" +"Last-Translator: Thierry BOULOGNE \n" "Language-Team: \n" +"Language: fr-FR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.1.1\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -"Last-Translator: Thierry BOULOGNE \n" -"Language: fr-FR\n" -#: admin.py:48 +#: django_q/admin.py:43 msgid "Resubmit selected tasks to queue" msgstr "Resoumettre les tâches sélectionnées à la file d'attente" -#: cluster.py:54 -msgid "Q Cluster-{} starting." -msgstr "Démarrage de Q Cluster-{}." +#: django_q/admin.py:98 django_q/models.py:228 +#, fuzzy +#| msgid "Success" +msgid "success" +msgstr "succès" -#: cluster.py:62 -msgid "Q Cluster-{} stopping." -msgstr "Arrêt de Q Cluster-{}." +#: django_q/admin.py:109 django_q/models.py:230 +msgid "last_run" +msgstr "" -#: cluster.py:65 -msgid "Q Cluster-{} has stopped." -msgstr "Q Cluster-{} a été arrêté." +#: django_q/cluster.py:77 +#, python-format +msgid "Q Cluster %(name)s starting." +msgstr "Démarrage de Q Cluster-%(name)s." -#: cluster.py:71 -msgid "{} got signal {}" -msgstr "{} à reçu le signal {}" +#: django_q/cluster.py:85 +#, python-format +msgid "Q Cluster %(name)s stopping." +msgstr "Arrêt de Q Cluster-%(name)s." -#: cluster.py:169 -msgid "reincarnated monitor {} after sudden death" -msgstr "moniteur réintégré {} après un arrêt intempestif" +#: django_q/cluster.py:88 +#, python-format +msgid "Q Cluster %(name)s has stopped." +msgstr "Q Cluster-%(name)s a été arrêté." -#: cluster.py:172 -msgid "reincarnated pusher {} after sudden death" -msgstr "pousseur réintégré {} après un arrêt intempestif" +#: django_q/cluster.py:96 +#, python-format +msgid "%(name)s got signal %(signal)s" +msgstr "%(name)s à reçu le signal %(signal)s" -#: cluster.py:179 -msgid "reincarnated worker {} after timeout" -msgstr "processus réintégré {} après un arrêt une attente trop longue" +#: django_q/cluster.py:219 +#, python-format +msgid "reincarnated monitor %(name)s after sudden death" +msgstr "moniteur réintégré %(name)s après un arrêt intempestif" -#: cluster.py:181 -msgid "recycled worker {}" -msgstr "processus recyclé" +#: django_q/cluster.py:222 +#, python-format +msgid "reincarnated pusher %(name)s after sudden death" +msgstr "pousseur réintégré %(name)s après un arrêt intempestif" -#: cluster.py:183 -msgid "reincarnated worker {} after death" -msgstr "processus réintégré {} après arrêt" +#: django_q/cluster.py:229 +#, python-format +msgid "reincarnated worker %(name)s after timeout" +msgstr "processus réintégré %(name)s après un arrêt une attente trop longue" -#: cluster.py:202 -msgid "{} guarding cluster at {}" -msgstr "{} surveillance du cluster à {}" +#: django_q/cluster.py:231 +#, python-format +msgid "recycled worker %(name)s" +msgstr "processus recyclé %(name)s" -#: cluster.py:205 -msgid "Q Cluster-{} running." -msgstr "Q Cluster-{} en cours d'exécution." +#: django_q/cluster.py:233 +#, python-format +msgid "reincarnated worker %(name)s after death" +msgstr "processus réintégré %(name)s après arrêt" -#: cluster.py:239 -msgid "{} stopping cluster processes" -msgstr "{} arrêt des processus de cluster" +#: django_q/cluster.py:256 +#, python-format +msgid "%(name)s guarding cluster %(cluster_name)s" +msgstr "%(name)s surveillance du cluster à %(cluster_name)s" -#: cluster.py:264 -msgid "{} waiting for the monitor." -msgstr "{} en attente du moniteur." +#: django_q/cluster.py:261 +#, python-format +msgid "Q Cluster %(cluster_name)s running." +msgstr "Démarrage de Q Cluster-%(cluster_name)s." -#: cluster.py:285 -msgid "{} pushing tasks at {}" -msgstr "{} tâche envoyé à {}" +#: django_q/cluster.py:295 +#, python-format +msgid "%(name)s stopping cluster processes" +msgstr "%(name)s arrêt des processus de cluster" -#: cluster.py:306 -msgid "queueing from {}" -msgstr "mise en file d'attente de {}" +#: django_q/cluster.py:320 +#, python-format +msgid "%(name)s waiting for the monitor." +msgstr "%(name)s en attente du moniteur." -#: cluster.py:309 -msgid "{} stopped pushing tasks" -msgstr "{} a cessé de pousser les tâches" +#: django_q/cluster.py:342 +#, python-format +msgid "%(process_name)s pushing tasks at %(id)s" +msgstr "%(process_name)s tâche envoyé à %(id)s" -#: cluster.py:320 -msgid "{} monitoring at {}" -msgstr "{} Surveillance de {}" +#: django_q/cluster.py:363 +#, python-format +msgid "queueing from %(list_key)s" +msgstr "mise en file d'attente de %(list_key)s" -#: cluster.py:334 -msgid "Processed [{}]" -msgstr "Traitement de [{}]" +#: django_q/cluster.py:366 +#, python-format +msgid "%(name)s stopped pushing tasks" +msgstr "%(name)s a cessé de pousser les tâches" -#: cluster.py:337 -msgid "Failed [{}] - {}" -msgstr "Echec [{}] - {}" +#: django_q/cluster.py:378 +#, python-format +msgid "%(name)s monitoring at %(id)s" +msgstr "%(name)s Surveillance de %(id)s" -#: cluster.py:338 -msgid "{} stopped monitoring results" -msgstr "{} arrêt des résultats de surveillance" +#: django_q/cluster.py:395 +#, python-format +msgid "Processed '%(info_name)s' (%(task_name)s)" +msgstr "traité '%(info_name)s' (%(task_name)s)" -#: cluster.py:349 -msgid "{} ready for work at {}" -msgstr "{} prêt pour le travail à {}" +#: django_q/cluster.py:398 +#, python-format +msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s" +msgstr "Manqué '%(info_name)s' (%(task_name)s) - %(task_result)s" -#: cluster.py:357 -msgid "{} processing [{}]" -msgstr "{} en cours de traitement [{}]" +#: django_q/cluster.py:399 +#, python-format +msgid "%(name)s stopped monitoring results" +msgstr "%(name)s arrêt des résultats de surveillance" -#: cluster.py:398 -msgid "{} stopped doing work" -msgstr "{} arrêté de travailler" +#: django_q/cluster.py:413 +#, python-format +msgid "%(proc_name)s ready for work at %(id)s" +msgstr "%(proc_name)s prêt pour le travail à %(id)s" -#: cluster.py:543 -msgid "{} failed to create a task from schedule [{}]" -msgstr "{} Echec de la création d'une tâche à partir de Schedule [{}]" +#: django_q/cluster.py:425 +#, python-format +msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" +msgstr "%(proc_name)s en traitement '%(func_name)s' (%(task_name)s)" -#: cluster.py:547 -msgid "{} created a task from schedule [{}]" -msgstr "{} a créé une tâche à partir de Schedule [{}]" +#: django_q/cluster.py:440 +#, python-format +msgid "" +"Could not process '%(func_name)s'. Check the location of the function and " +"the args/kwargs." +msgstr "" +"Impossible de traiter '%(func_name)s'. Vérifiez l'emplacement de la fonction " +"et les args/kwargs." -#: cluster.py:595 -msgid "{} will use cpu {}" -msgstr "{} utilisera le CPU {}" +#: django_q/cluster.py:456 +#, python-format +msgid "%(proc_name)s stopped doing work" +msgstr "%(proc_name)s arrêté de travailler" -#: conf.py:169 +#: django_q/cluster.py:649 django_q/models.py:144 +msgid "Please install croniter to enable cron expressions" +msgstr "Veuillez installer croniter pour activer les expressions croniques." + +#: django_q/cluster.py:672 +#, python-format +msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]" +msgstr "" +"%(process_name)s Echec de la création d'une tâche à partir de Schedule " +"[%(schedule)s]" + +#: django_q/cluster.py:678 +#, python-format +msgid "%(process_name)s created a task from schedule [%(schedule)s]" +msgstr "%(process_name)s a créé une tâche à partir de Schedule [%(schedule)s]" + +#: django_q/cluster.py:718 +msgid "Skipping cpu affinity because psutil was not found." +msgstr "Sauter l'affinité du processeur parce que psutil n'a pas été trouvé." + +#: django_q/cluster.py:723 +msgid "Faking cpu affinity because it is not supported on this platform" +msgstr "" +"Simulation de l'affinité du processeur parce qu'elle n'est pas supportée sur " +"cette plateforme." + +#: django_q/cluster.py:744 +#, python-format +msgid "%(pid)s will use cpu %(affinity)s" +msgstr "%(pid)s utilisera le CPU %(affinity)s" + +#: django_q/conf.py:85 +#, python-format +msgid "" +"SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " +"'name', 'func' and None. Default is None." +msgstr "" +"SAVE_LIMIT_PER (%(option)s) n'est pas une option valide. Les options sont : " +"'group', 'name', 'func' et None. La valeur par défaut est None." + +#. Translators: Cluster status descriptions +#: django_q/conf.py:194 msgid "Starting" msgstr "Démarrage" -#: conf.py:170 +#: django_q/conf.py:195 msgid "Working" msgstr "Actif" -#: conf.py:171 +#: django_q/conf.py:196 msgid "Idle" msgstr "En attente" -#: conf.py:172 +#: django_q/conf.py:197 msgid "Stopped" msgstr "Arrêté" -#: conf.py:173 +#: django_q/conf.py:198 msgid "Stopping" msgstr "En cours d’arrêt" -#: management/commands/qcluster.py:9 +#. Translators: help text for qcluster management command +#: django_q/management/commands/qcluster.py:9 msgid "Starts a Django Q Cluster." msgstr "Démarre un cluster Django Q." -#: management/commands/qinfo.py:11 +#. Translators: help text for qinfo management command +#: django_q/management/commands/qinfo.py:11 msgid "General information over all clusters." msgstr "Informations générales sur tous les clusters." -#: management/commands/qmonitor.py:9 +#. Translators: help text for qmemory management command +#: django_q/management/commands/qmemory.py:9 +#, fuzzy +#| msgid "Monitors Q Cluster activity" +msgid "Monitors Q Cluster memory usage" +msgstr "Surveille l'utilisation de la mémoire du cluster Q" + +#. Translators: help text for qmonitor management command +#: django_q/management/commands/qmonitor.py:9 msgid "Monitors Q Cluster activity" msgstr "Activité du cluster Moniteur Q" -#: models.py:104 +#: django_q/models.py:119 msgid "Successful task" msgstr "Tâche réussie" -#: models.py:105 +#: django_q/models.py:120 msgid "Successful tasks" msgstr "Tâches réussies" -#: models.py:121 +#: django_q/models.py:135 msgid "Failed task" msgstr "Tâche échoué" -#: models.py:122 +#: django_q/models.py:136 msgid "Failed tasks" msgstr "Tâches échouées" -#: models.py:131 +#: django_q/models.py:160 msgid "e.g. 1, 2, 'John'" msgstr "ex. 1, 2, ‘Jean’" -#: models.py:132 +#: django_q/models.py:162 msgid "e.g. x=1, y=2, name='John'" msgstr "p. ex. x = 1, y = 2, Nom = ‘Jean’" -#: models.py:142 +#: django_q/models.py:176 msgid "Once" msgstr "Une fois" -#: models.py:143 +#: django_q/models.py:177 msgid "Minutes" msgstr "Minutes" -#: models.py:144 +#: django_q/models.py:178 msgid "Hourly" msgstr "Toutes les heures" -#: models.py:145 +#: django_q/models.py:179 msgid "Daily" msgstr "Quotidien" -#: models.py:146 +#: django_q/models.py:180 msgid "Weekly" msgstr "Hebdomadaire" -#: models.py:147 +#: django_q/models.py:181 +#, fuzzy +#| msgid "Weekly" +msgid "Biweekly" +msgstr "Bihebdomadaire" + +#: django_q/models.py:182 msgid "Monthly" msgstr "Mensuel" -#: models.py:148 +#: django_q/models.py:183 +#, fuzzy +#| msgid "Monthly" +msgid "Bimonthly" +msgstr "Bimestriel" + +#: django_q/models.py:184 msgid "Quarterly" msgstr "Tous les quart-d’heure" -#: models.py:149 +#: django_q/models.py:185 msgid "Yearly" msgstr "Annuel" -#: models.py:151 +#: django_q/models.py:186 +msgid "Cron" +msgstr "Cron" + +#: django_q/models.py:189 msgid "Schedule Type" msgstr "Type de plannification" -#: models.py:153 +#: django_q/models.py:192 msgid "Number of minutes for the Minutes type" msgstr "Nombre de minutes pour le type de minutes" -#: models.py:154 +#: django_q/models.py:195 msgid "Repeats" msgstr "Répéter" -#: models.py:154 +#: django_q/models.py:195 msgid "n = n times, -1 = forever" msgstr "n = n fois,-1 = Toujours" -#: models.py:155 +#: django_q/models.py:198 msgid "Next Run" msgstr "Prochaine exécution" -#: models.py:180 +#: django_q/models.py:205 +msgid "Cron expression" +msgstr "Expression du Cron" + +#: django_q/models.py:235 msgid "Scheduled task" msgstr "Tâche planifiée" -#: models.py:181 +#: django_q/models.py:236 msgid "Scheduled tasks" msgstr "Tâches planifiées" -#: models.py:204 +#: django_q/models.py:262 msgid "Queued task" msgstr "Tâche en file d'attente" -#: models.py:205 +#: django_q/models.py:263 msgid "Queued tasks" msgstr "Tâches en file d'attente" -#: monitor.py:33 +#: django_q/monitor.py:62 django_q/monitor.py:339 msgid "Host" msgstr "Hôte" -#: monitor.py:34 +#: django_q/monitor.py:66 django_q/monitor.py:343 django_q/monitor.py:450 msgid "Id" msgstr "Id" -#: monitor.py:35 +#: django_q/monitor.py:70 msgid "State" msgstr "Statut" -#: monitor.py:36 +#: django_q/monitor.py:74 msgid "Pool" msgstr "Piscine" -#: monitor.py:37 +#: django_q/monitor.py:78 msgid "TQ" msgstr "TQ" -#: monitor.py:38 +#: django_q/monitor.py:82 msgid "RQ" msgstr "RQ" -#: monitor.py:39 +#: django_q/monitor.py:86 msgid "RC" msgstr "RC" -#: monitor.py:40 +#: django_q/monitor.py:90 msgid "Up" msgstr "Haut" -#: monitor.py:90 monitor.py:165 +#: django_q/monitor.py:170 django_q/monitor.py:279 msgid "Queued" msgstr "En file d'attente" -#: monitor.py:92 +#: django_q/monitor.py:178 msgid "Success" msgstr "Succès" -#: monitor.py:95 monitor.py:173 +#: django_q/monitor.py:188 django_q/monitor.py:287 msgid "Failures" msgstr "Défaillances" -#: monitor.py:101 +#: django_q/monitor.py:199 django_q/monitor.py:485 msgid "[Press q to quit]" msgstr "[appuyez sur q pour quitter]" -#: monitor.py:120 +#: django_q/monitor.py:223 msgid "day" msgstr "jour" -#: monitor.py:137 +#: django_q/monitor.py:244 msgid "second" msgstr "seconde" -#: monitor.py:140 +#: django_q/monitor.py:247 msgid "minute" msgstr "minute" -#: monitor.py:143 +#: django_q/monitor.py:250 msgid "hour" msgstr "heure" -#: monitor.py:151 -msgid "-- {} {} on {} --" -msgstr "--{} {} sur {}--" +#: django_q/monitor.py:260 +#, python-format +msgid "-- %(prefix)s %(version)s on %(info)s --" +msgstr "--%(prefix)s %(version)s sur %(info)s --" -#: monitor.py:153 +#: django_q/monitor.py:266 msgid "Clusters" msgstr "Grappes" -#: monitor.py:157 +#: django_q/monitor.py:270 msgid "Workers" msgstr "Processus" -#: monitor.py:161 +#: django_q/monitor.py:274 msgid "Restarts" msgstr "Redémarrages" -#: monitor.py:169 +#: django_q/monitor.py:283 msgid "Successes" msgstr "Succès" -#: monitor.py:177 +#: django_q/monitor.py:292 msgid "Schedules" msgstr "Planifications" -#: monitor.py:181 -msgid "Tasks/{}" -msgstr "Tâches/{}" +#: django_q/monitor.py:296 +#, python-format +msgid "Tasks/%(per)s" +msgstr "Tâches/%(per)s" -#: monitor.py:185 +#: django_q/monitor.py:300 msgid "Avg time" msgstr "Temps Moyen" -#: signals.py:21 -msgid "malformed return hook '{}' for [{}]" -msgstr "hook de retour mal formé' {} 'pour [{}]" +#: django_q/monitor.py:348 +msgid "Available (%)" +msgstr "" -#: signals.py:26 -msgid "return hook {} failed on [{}] because {}" -msgstr "le crochet de retour {} a échoué sur [{}] parce que {}" +#: django_q/monitor.py:354 +msgid "Available (MB)" +msgstr "Disponible sur (MB)" + +#: django_q/monitor.py:359 +msgid "Total (MB)" +msgstr "Total (MB)" + +#: django_q/monitor.py:364 +msgid "Sentinel (MB)" +msgstr "Sentinel (MB)" + +#: django_q/monitor.py:370 +msgid "Monitor (MB)" +msgstr "Monitor (MB)" + +#: django_q/monitor.py:376 +#, fuzzy +#| msgid "Workers" +msgid "Workers (MB)" +msgstr "Processus (MB)" + +#: django_q/monitor.py:478 +#, python-format +msgid "Available lowest (): %(memory_percent)s ((at)s)" +msgstr "Disponible le plus bas () : %(memory_percent)s ((at)s)" + +#: django_q/monitor.py:496 +msgid "No clusters appear to be running." +msgstr "Aucun cluster ne semble être en cours d'exécution." + +#: django_q/signals.py:22 +#, python-format +msgid "malformed return hook '%(hook)s' for [%(name)s]" +msgstr "hook de retour mal formé' %(hook)s 'pour [%(name)s]" + +#: django_q/signals.py:30 +#, python-format +msgid "return hook %(hook)s failed on [%(name)s] because %(error)s" +msgstr "le crochet de retour %(hook)s a échoué sur [%(name)s] parce que %(error)s" diff --git a/django_q/locale/tr/LC_MESSAGES/django.po b/django_q/locale/tr/LC_MESSAGES/django.po index 88092ef..8b73b63 100644 --- a/django_q/locale/tr/LC_MESSAGES/django.po +++ b/django_q/locale/tr/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2022-06-18 23:55+0300\n" +"POT-Creation-Date: 2022-11-12 01:47+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Ethem Güner \n" "Language-Team: \n" @@ -17,166 +17,199 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: django_q/admin.py:40 + +#: django_q/admin.py:43 msgid "Resubmit selected tasks to queue" msgstr "Seçili işleri kuyruğa tekrar gönder" -#: django_q/brokers/disque.py:60 -msgid "No Disque nodes configured" -msgstr "Disque nodları konfigüre edilmemiş" +#: django_q/admin.py:98 django_q/models.py:228 +#, fuzzy +#| msgid "Success" +msgid "success" +msgstr "başarılı olanlar" -#: django_q/brokers/disque.py:77 -msgid "Could not connect to any Disque nodes" -msgstr "Herhangi bir Disque noduna bağlanılamadı" - -#: django_q/cluster.py:79 -#, python-brace-format -msgid "Q Cluster {self.name} starting." -msgstr "Q Cluster {self.name} başlatılıyor." - -#: django_q/cluster.py:87 -#, python-brace-format -msgid "Q Cluster {self.name} stopping." -msgstr "Q Cluster {self.name} durduruluyor." - -#: django_q/cluster.py:90 -#, python-brace-format -msgid "Q Cluster {self.name} has stopped." -msgstr "Q Cluster {self.name} durduruldu." - -#: django_q/cluster.py:98 -msgid "" -"{current_process().name} got signal {Conf.SIGNAL_NAMES.get(signum, \"UNKNOWN" -"\")}" +#: django_q/admin.py:109 django_q/models.py:230 +msgid "last_run" msgstr "" -"{current_process().name} şu sinyali aldı {Conf.SIGNAL_NAMES.get(signum, \"UNKNOWN" -"\")}" -#: django_q/cluster.py:220 -#, python-brace-format -msgid "reincarnated monitor {process.name} after sudden death" -msgstr "Monitor {process.name} ani ölüm sonrası tekrar dirildi" +#: django_q/cluster.py:77 +#, python-format +msgid "Q Cluster %(name)s starting." +msgstr "Q Cluster %(name)s başlatılıyor." -#: django_q/cluster.py:223 -#, python-brace-format -msgid "reincarnated pusher {process.name} after sudden death" -msgstr "Pusher {process.name} ani ölüm sonrası tekrar dirildi" +#: django_q/cluster.py:85 +#, python-format +msgid "Q Cluster %(name)s stopping." +msgstr "Q Cluster %(name)s durduruluyor." -#: django_q/cluster.py:230 -#, python-brace-format -msgid "reincarnated worker {process.name} after timeout" -msgstr "Worker {process.name} zaman aşımı sonrası tekrar dirildi" +#: django_q/cluster.py:88 +#, python-format +msgid "Q Cluster %(name)s has stopped." +msgstr "Q Cluster %(name)s durduruldu." -#: django_q/cluster.py:232 -#, python-brace-format -msgid "recycled worker {process.name}" -msgstr "Worker {process.name} geri döndürüldü" +#: django_q/cluster.py:96 +#, python-format +msgid "%(name)s got signal %(signal)s" +msgstr "%(name)s, %(signal)s pid'inde izleniyor/monitoring yapılıyor." -#: django_q/cluster.py:234 -#, python-brace-format -msgid "reincarnated worker {process.name} after death" -msgstr "Worker {process.name} ani ölüm sonrası tekrar dirildi" +#: django_q/cluster.py:219 +#, python-format +msgid "reincarnated monitor %(name)s after sudden death" +msgstr "Monitor %(name)s ani ölüm sonrası tekrar dirildi" + +#: django_q/cluster.py:222 +#, python-format +msgid "reincarnated pusher %(name)s after sudden death" +msgstr "Pusher %(name)s ani ölüm sonrası tekrar dirildi" + +#: django_q/cluster.py:229 +#, python-format +msgid "reincarnated worker %(name)s after timeout" +msgstr "Worker %(name)s zaman aşımı sonrası tekrar dirildi" + +#: django_q/cluster.py:231 +#, python-format +msgid "recycled worker %(name)s" +msgstr "Worker %(name)s geri döndürüldü" + +#: django_q/cluster.py:233 +#, python-format +msgid "reincarnated worker %(name)s after death" +msgstr "Worker %(name)s ani ölüm sonrası tekrar dirildi" #: django_q/cluster.py:256 -msgid "" -"{current_process().name} guarding cluster {humanize(self.cluster_id.hex)}" -msgstr "{current_process().name}, {humanize(self.cluster_id.hex)} cluster'ını koruyor" +#, python-format +msgid "%(name)s guarding cluster %(cluster_name)s" +msgstr "%(name)s, %(cluster_name)s cluster'ını koruyor" #: django_q/cluster.py:261 -msgid "Q Cluster {humanize(self.cluster_id.hex)} running." -msgstr "Q Cluster {humanize(self.cluster_id.hex)} çalışıyor." +#, python-format +msgid "Q Cluster %(cluster_name)s running." +msgstr "Q Cluster %(cluster_name)s başlatılıyor." #: django_q/cluster.py:295 -#, python-brace-format -msgid "{name} stopping cluster processes" -msgstr "Cluster {name} işlemleri durduruluyor." +#, python-format +msgid "%(name)s stopping cluster processes" +msgstr "Cluster %(name)s işlemleri durduruluyor." #: django_q/cluster.py:320 -#, python-brace-format -msgid "{name} waiting for the monitor." -msgstr "{name} monitor için bekliyor." +#, python-format +msgid "%(name)s waiting for the monitor." +msgstr "%(name)s monitor için bekliyor." #: django_q/cluster.py:342 -msgid "{current_process().name} pushing tasks at {current_process().pid}" -msgstr "{current_process().name, işleri {current_process().pid} pid'ine gönderiyor." +#, python-format +msgid "%(process_name)s pushing tasks at %(id)s" +msgstr "%(process_name)s, işleri %(id)s pid'ine gönderiyor." #: django_q/cluster.py:363 -#, python-brace-format -msgid "queueing from {broker.list_key}" +#, python-format +msgid "queueing from %(list_key)s" msgstr "" #: django_q/cluster.py:366 -msgid "{current_process().name} stopped pushing tasks" -msgstr "{current_process().name} işleri göndermeyi durdurdu" +#, python-format +msgid "%(name)s stopped pushing tasks" +msgstr "%(name)s işleri göndermeyi durdurdu" #: django_q/cluster.py:378 -msgid "{name} monitoring at {current_process().pid}" -msgstr "{name}, {current_process().pid} pid'inde izleniyor/monitoring yapılıyor." +#, python-format +msgid "%(name)s monitoring at %(id)s" +msgstr "%(name)s, %(id)s pid'inde izleniyor/monitoring yapılıyor." -#: django_q/cluster.py:394 -msgid "Processed [{task['name']}]" -msgstr "[{task['name']}] işlendi." - -#: django_q/cluster.py:397 -msgid "Failed [{task['name']}] - {task['result']}" -msgstr "[{task['name']}] - {task['result']} başarısız oldu" +#: django_q/cluster.py:395 +#, python-format +msgid "Processed '%(info_name)s' (%(task_name)s)" +msgstr "[%(task_name)s] - '%(info_name)s işlendi." #: django_q/cluster.py:398 -#, python-brace-format -msgid "{name} stopped monitoring results" -msgstr "{name} sonuçları göstermeyi bıraktı" +#, python-format +msgid "Failed '%(info_name)s' (%(task_name)s) - %(task_result)s" +msgstr "[%(task_name)s] - '%(info_name)s' - %(task_result)s başarısız oldu" -#: django_q/cluster.py:412 -msgid "{name} ready for work at {current_process().pid}" -msgstr "{name}, {current_process().pid} pid'inde çalışmaya hazır" +#: django_q/cluster.py:399 +#, python-format +msgid "%(name)s stopped monitoring results" +msgstr "%(name)s sonuçları göstermeyi bıraktı" -#: django_q/cluster.py:422 -msgid "{name} processing [{task[\"name\"]}]" -msgstr "{name}, [{task[\"name\"]}] işlerini işiyor" +#: django_q/cluster.py:413 +#, python-format +msgid "%(proc_name)s ready for work at %(id)s" +msgstr "%(proc_name)s, %(id)s pid'inde çalışmaya hazır" -#: django_q/cluster.py:453 -#, python-brace-format -msgid "{name} stopped doing work" -msgstr "{name} çalışmayı bıraktı" +#: django_q/cluster.py:425 +#, python-format +msgid "%(proc_name)s processing '%(func_name)s' (%(task_name)s)" +msgstr "%(proc_name)s, '%(func_name)s' [%(task_name)s] işlerini işiyor" -#: django_q/cluster.py:635 django_q/models.py:143 +#: django_q/cluster.py:440 +#, python-format +msgid "" +"Could not process '%(func_name)s'. Check the location of the function and " +"the args/kwargs." +msgstr "" +"%(func_name)s' işlenemedi. İşlevin konumunu ve args/kwargs öğelerini kontrol " +"edin." + +#: django_q/cluster.py:456 +#, python-format +msgid "%(proc_name)s stopped doing work" +msgstr "%(proc_name)s çalışmayı bıraktı" + +#: django_q/cluster.py:649 django_q/models.py:144 msgid "Please install croniter to enable cron expressions" msgstr "Cron expressions'ları açmak için croniter yükleyin" -#: django_q/cluster.py:665 -msgid "" -"{current_process().name} failed to create a task from schedule [{s.name or s." -"id}]" -msgstr "" +#: django_q/cluster.py:672 +#, python-format +msgid "%(process_name)s failed to create a task from schedule [%(schedule)s]" +msgstr "%(process_name)s programdan bir görev oluşturamadı [%(schedule)s]" -#: django_q/cluster.py:671 -msgid "" -"{current_process().name} created a task from schedule [{s.name or s.id}]" -msgstr "" +#: django_q/cluster.py:678 +#, python-format +msgid "%(process_name)s created a task from schedule [%(schedule)s]" +msgstr "%(process_name)s programdan bir görev oluşturamadı [%(schedule)s]" -#: django_q/cluster.py:737 -#, python-brace-format -msgid "{pid} will use cpu {affinity}" +#: django_q/cluster.py:718 +msgid "Skipping cpu affinity because psutil was not found." +msgstr "Psutil bulunamadığı için cpu benzeşimi atlanıyor." + +#: django_q/cluster.py:723 +msgid "Faking cpu affinity because it is not supported on this platform" +msgstr "Bu platformda desteklenmediği için sahte cpu benzeşimi" + +#: django_q/cluster.py:744 +#, python-format +msgid "%(pid)s will use cpu %(affinity)s" +msgstr "%(pid)s cpu %(affinity)s kullanacaktır" + +#: django_q/conf.py:85 +#, python-format +msgid "" +"SAVE_LIMIT_PER (%(option)s) is not a valid option. Options are: 'group', " +"'name', 'func' and None. Default is None." msgstr "" +"SAVE_LIMIT_PER (%(option)s) geçerli bir seçenek değil. Seçenekler şunlardır: " +"'group', 'name', 'func' ve None. Varsayılan değer None'dır." #. Translators: Cluster status descriptions -#: django_q/conf.py:196 +#: django_q/conf.py:194 msgid "Starting" msgstr "Başlıyor" -#: django_q/conf.py:197 +#: django_q/conf.py:195 msgid "Working" msgstr "Çalışıyor" -#: django_q/conf.py:198 +#: django_q/conf.py:196 msgid "Idle" msgstr "Boşta" -#: django_q/conf.py:199 +#: django_q/conf.py:197 msgid "Stopped" msgstr "Durdu" -#: django_q/conf.py:200 +#: django_q/conf.py:198 msgid "Stopping" msgstr "Durduruluyor" @@ -200,239 +233,255 @@ msgstr "Q Cluster'ın bellek kullanımını izler" msgid "Monitors Q Cluster activity" msgstr "Q Cluster'ın aktivitelerini izler" -#: django_q/models.py:118 +#: django_q/models.py:119 msgid "Successful task" msgstr "Başarılı iş" -#: django_q/models.py:119 +#: django_q/models.py:120 msgid "Successful tasks" msgstr "Başarılı işler" -#: django_q/models.py:134 +#: django_q/models.py:135 msgid "Failed task" msgstr "Başarısız iş" -#: django_q/models.py:135 +#: django_q/models.py:136 msgid "Failed tasks" msgstr "Başarısız işler" -#: django_q/models.py:159 +#: django_q/models.py:160 msgid "e.g. 1, 2, 'John'" msgstr "Örneğin: 1, 2, 'Melih'" -#: django_q/models.py:161 +#: django_q/models.py:162 msgid "e.g. x=1, y=2, name='John'" msgstr "Örneğin: x=1, y=2, name='Melih'" -#: django_q/models.py:173 +#: django_q/models.py:176 msgid "Once" msgstr "Bir kere" -#: django_q/models.py:174 +#: django_q/models.py:177 msgid "Minutes" msgstr "Dakika" -#: django_q/models.py:175 +#: django_q/models.py:178 msgid "Hourly" msgstr "Saatlik" -#: django_q/models.py:176 +#: django_q/models.py:179 msgid "Daily" msgstr "Günlük" -#: django_q/models.py:177 +#: django_q/models.py:180 msgid "Weekly" msgstr "Haftalık" -#: django_q/models.py:178 +#: django_q/models.py:181 +#, fuzzy +#| msgid "Weekly" +msgid "Biweekly" +msgstr "İki haftada bir" + +#: django_q/models.py:182 msgid "Monthly" msgstr "Aylık" -#: django_q/models.py:179 +#: django_q/models.py:183 +#, fuzzy +#| msgid "Monthly" +msgid "Bimonthly" +msgstr "İki ayda bir" + +#: django_q/models.py:184 msgid "Quarterly" msgstr "Bir Çeyrek (3 Ay)" -#: django_q/models.py:180 +#: django_q/models.py:185 msgid "Yearly" msgstr "Yıllık" -#: django_q/models.py:181 +#: django_q/models.py:186 msgid "Cron" msgstr "" -#: django_q/models.py:184 +#: django_q/models.py:189 msgid "Schedule Type" msgstr "Zamanlama Tipi" -#: django_q/models.py:187 +#: django_q/models.py:192 msgid "Number of minutes for the Minutes type" msgstr "Dakika tipine göre dakika sayısı" -#: django_q/models.py:190 +#: django_q/models.py:195 msgid "Repeats" msgstr "Tekrar eder" -#: django_q/models.py:190 +#: django_q/models.py:195 msgid "n = n times, -1 = forever" msgstr "n = n kere, -1 = sonsuza kadar" -#: django_q/models.py:193 +#: django_q/models.py:198 msgid "Next Run" msgstr "Bir dahaki çalışma tarihi" -#: django_q/models.py:200 +#: django_q/models.py:205 msgid "Cron expression" msgstr "" -#: django_q/models.py:227 +#: django_q/models.py:235 msgid "Scheduled task" msgstr "Zamanlanmış iş" -#: django_q/models.py:228 +#: django_q/models.py:236 msgid "Scheduled tasks" msgstr "Zamanlanmış işler" -#: django_q/models.py:251 +#: django_q/models.py:262 msgid "Queued task" msgstr "Sıraya alınmış iş" -#: django_q/models.py:252 +#: django_q/models.py:263 msgid "Queued tasks" msgstr "Sıraya alınmış işler" -#: django_q/monitor.py:54 django_q/monitor.py:322 +#: django_q/monitor.py:62 django_q/monitor.py:339 msgid "Host" msgstr "" -#: django_q/monitor.py:58 django_q/monitor.py:326 django_q/monitor.py:433 +#: django_q/monitor.py:66 django_q/monitor.py:343 django_q/monitor.py:450 msgid "Id" msgstr "" -#: django_q/monitor.py:62 +#: django_q/monitor.py:70 msgid "State" msgstr "Durum" -#: django_q/monitor.py:66 +#: django_q/monitor.py:74 msgid "Pool" msgstr "Havuz" -#: django_q/monitor.py:70 +#: django_q/monitor.py:78 msgid "TQ" msgstr "" -#: django_q/monitor.py:74 +#: django_q/monitor.py:82 msgid "RQ" msgstr "" -#: django_q/monitor.py:78 +#: django_q/monitor.py:86 msgid "RC" msgstr "" -#: django_q/monitor.py:82 +#: django_q/monitor.py:90 msgid "Up" msgstr "" -#: django_q/monitor.py:162 django_q/monitor.py:266 +#: django_q/monitor.py:170 django_q/monitor.py:279 msgid "Queued" msgstr "Sıraya alınmış" -#: django_q/monitor.py:170 +#: django_q/monitor.py:178 msgid "Success" msgstr "Başarılı olanlar" -#: django_q/monitor.py:180 django_q/monitor.py:274 +#: django_q/monitor.py:188 django_q/monitor.py:287 msgid "Failures" msgstr "Başarısız olanlar" -#: django_q/monitor.py:191 +#: django_q/monitor.py:199 django_q/monitor.py:485 msgid "[Press q to quit]" msgstr "[Çıkmak için q'ya basın]" -#: django_q/monitor.py:210 +#: django_q/monitor.py:223 msgid "day" msgstr "gün" -#: django_q/monitor.py:231 +#: django_q/monitor.py:244 msgid "second" msgstr "saniye" -#: django_q/monitor.py:234 +#: django_q/monitor.py:247 msgid "minute" msgstr "dakika" -#: django_q/monitor.py:237 +#: django_q/monitor.py:250 msgid "hour" msgstr "saat" -#: django_q/monitor.py:247 -msgid "" -"-- {Conf.PREFIX.capitalize()} { \".\".join(str(v) for v in VERSION)} on " -"{broker.info()} --" -msgstr "" +#: django_q/monitor.py:260 +#, python-format +msgid "-- %(prefix)s %(version)s on %(info)s --" +msgstr "-- %(prefix)s %(version)s üzerinde %(info)s --" -#: django_q/monitor.py:253 +#: django_q/monitor.py:266 msgid "Clusters" msgstr "" -#: django_q/monitor.py:257 +#: django_q/monitor.py:270 msgid "Workers" msgstr "" -#: django_q/monitor.py:261 +#: django_q/monitor.py:274 msgid "Restarts" msgstr "Yeniden çalıştırmalar" -#: django_q/monitor.py:270 +#: django_q/monitor.py:283 msgid "Successes" msgstr "Başarılı olanlar" -#: django_q/monitor.py:279 +#: django_q/monitor.py:292 msgid "Schedules" msgstr "Zamanlanmışlar" -#: django_q/monitor.py:283 -#, python-brace-format -msgid "Tasks/{per}" -msgstr "İş/{per}" +#: django_q/monitor.py:296 +#, python-format +msgid "Tasks/%(per)s" +msgstr "İş/%(per)s" -#: django_q/monitor.py:287 +#: django_q/monitor.py:300 msgid "Avg time" msgstr "Ortalama süre" -#: django_q/monitor.py:331 +#: django_q/monitor.py:348 msgid "Available (%)" msgstr "Müsait (%) " -#: django_q/monitor.py:337 +#: django_q/monitor.py:354 msgid "Available (MB)" msgstr "Müsait (MB)" -#: django_q/monitor.py:342 +#: django_q/monitor.py:359 msgid "Total (MB)" msgstr "Toplam (MB)" -#: django_q/monitor.py:347 +#: django_q/monitor.py:364 msgid "Sentinel (MB)" msgstr "" -#: django_q/monitor.py:353 +#: django_q/monitor.py:370 msgid "Monitor (MB)" msgstr "İzleme (MB)" -#: django_q/monitor.py:359 +#: django_q/monitor.py:376 msgid "Workers (MB)" msgstr "" -#: django_q/monitor.py:461 -msgid "Available lowest (%): {} ({})" -msgstr "Mevcut en düşük (%): {} ({})" +#: django_q/monitor.py:478 +#, python-format +msgid "Available lowest (): %(memory_percent)s ((at)s)" +msgstr "Mevcut en düşük (): %(memory_percent)s ((at)s)" + +#: django_q/monitor.py:496 +msgid "No clusters appear to be running." +msgstr "Hiçbir küme çalışıyor görünmüyor." #: django_q/signals.py:22 -#, python-brace-format -msgid "malformed return hook '{instance.hook}' for [{instance.name}]" +#, python-format +msgid "malformed return hook '%(hook)s' for [%(name)s]" msgstr "" #: django_q/signals.py:30 -msgid "" -"return hook {instance.hook} failed on [{instance.name}] because {str(e)}" +#, python-format +msgid "return hook %(hook)s failed on [%(name)s] because %(error)s" msgstr "" diff --git a/django_q/migrations/0015_alter_schedule_schedule_type.py b/django_q/migrations/0015_alter_schedule_schedule_type.py new file mode 100644 index 0000000..fd3fcec --- /dev/null +++ b/django_q/migrations/0015_alter_schedule_schedule_type.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.2 on 2022-11-10 01:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('django_q', '0014_schedule_cluster'), + ] + + operations = [ + migrations.AlterField( + model_name='schedule', + name='schedule_type', + field=models.CharField(choices=[('O', 'Once'), ('I', 'Minutes'), ('H', 'Hourly'), ('D', 'Daily'), ('W', 'Weekly'), ('BW', 'Biweekly'), ('M', 'Monthly'), ('BM', 'Bimonthly'), ('Q', 'Quarterly'), ('Y', 'Yearly'), ('C', 'Cron')], default='O', max_length=2, verbose_name='Schedule Type'), + ), + ] diff --git a/django_q/models.py b/django_q/models.py index d90c8d0..05aa0fe 100644 --- a/django_q/models.py +++ b/django_q/models.py @@ -166,7 +166,9 @@ class Schedule(models.Model): HOURLY = "H" DAILY = "D" WEEKLY = "W" + BIWEEKLY = "BW" MONTHLY = "M" + BIMONTHLY = "BM" QUARTERLY = "Q" YEARLY = "Y" CRON = "C" @@ -176,13 +178,15 @@ class Schedule(models.Model): (HOURLY, _("Hourly")), (DAILY, _("Daily")), (WEEKLY, _("Weekly")), + (BIWEEKLY, _("Biweekly")), (MONTHLY, _("Monthly")), + (BIMONTHLY, _("Bimonthly")), (QUARTERLY, _("Quarterly")), (YEARLY, _("Yearly")), (CRON, _("Cron")), ) schedule_type = models.CharField( - max_length=1, choices=TYPE, default=TYPE[0][0], verbose_name=_("Schedule Type") + max_length=2, choices=TYPE, default=TYPE[0][0], verbose_name=_("Schedule Type") ) minutes = models.PositiveSmallIntegerField( null=True, blank=True, help_text=_("Number of minutes for the Minutes type") diff --git a/django_q/monitor.py b/django_q/monitor.py index 0ce0d79..20a670d 100644 --- a/django_q/monitor.py +++ b/django_q/monitor.py @@ -257,8 +257,8 @@ def info(broker=None): term.black_on_green( term.center( _( - f'-- {Conf.PREFIX.capitalize()} { ".".join(str(v) for v in VERSION)} on {broker.info()} --' - ) + '-- %(prefix)s %(version)s on %(info)s --' + ) % {'prefix': Conf.PREFIX.capitalize(), 'version': ".".join(str(v) for v in VERSION), 'info': broker.info()} ) ) ) @@ -293,7 +293,7 @@ def info(broker=None): + term.move_x(1 * col_width) + term.white(str(models.Schedule.objects.count())) + term.move_x(2 * col_width) - + term.cyan(_(f"Tasks/{per}")) + + term.cyan(_("Tasks/%(per)s") % {'per': per}) + term.move_x(3 * col_width) + term.white(f"{tasks_per:.2f}") + term.move_x(4 * col_width) @@ -475,17 +475,14 @@ def memory(run_once=False, workers=False, broker=None): row += 1 print( term.move(row, 0) - + _("Available lowest (%): {} ({})").format( - str(MEMORY_AVAILABLE_LOWEST_PERCENTAGE), - MEMORY_AVAILABLE_LOWEST_PERCENTAGE_AT.strftime( - "%Y-%m-%d %H:%M:%S+00:00" - ), - ) + + _("Available lowest (): %(memory_percent)s ((at)s)") % { 'memory_percent': str(MEMORY_AVAILABLE_LOWEST_PERCENTAGE), 'at': MEMORY_AVAILABLE_LOWEST_PERCENTAGE_AT.strftime( + "%Y-%m-%d %H:%M:%S+00:00" + )} ) # for testing if run_once: return Stat.get_all(broker=broker) - print(term.move(row + 2, 0) + term.center("[Press q to quit]")) + print(term.move(row + 2, 0) + term.center(_("[Press q to quit]"))) val = term.inkey(timeout=1) @@ -496,5 +493,5 @@ def get_ids(): for s in stat: print(s.cluster_id) else: - print("No clusters appear to be running.") + print(_("No clusters appear to be running.")) return True diff --git a/django_q/signals.py b/django_q/signals.py index 109b473..0b7dd61 100644 --- a/django_q/signals.py +++ b/django_q/signals.py @@ -19,7 +19,7 @@ def call_hook(sender, instance, **kwargs): f = getattr(m, func) except (ValueError, ImportError, AttributeError): logger.error( - _(f"malformed return hook '{instance.hook}' for [{instance.name}]") + _("malformed return hook '%(hook)s' for [%(name)s]") % {'hook': instance.hook, 'name': instance.name} ) return try: @@ -27,8 +27,8 @@ def call_hook(sender, instance, **kwargs): except Exception as e: logger.error( _( - f"return hook {instance.hook} failed on [{instance.name}] because {str(e)}" - ) + "return hook %(hook)s failed on [%(name)s] because %(error)s" + ) % {'hook': instance.hook, 'name': instance.name, 'error': str(e)} ) diff --git a/django_q/tests/test_scheduler.py b/django_q/tests/test_scheduler.py index a9441a1..c3c0ffc 100644 --- a/django_q/tests/test_scheduler.py +++ b/django_q/tests/test_scheduler.py @@ -21,6 +21,7 @@ from django_q.tests.testing_utilities.multiple_database_routers import ( TestingMultipleAppsDatabaseRouter, TestingReplicaDatabaseRouter, ) +from django_q.utils import add_months, add_years @pytest.fixture @@ -228,6 +229,29 @@ def test_scheduler(broker, monkeypatch): # Done broker.delete_queue() + # test bimonthly + schedule = create_schedule( + "django_q.tests.tasks.word_multiply", + 2, + word="catch_up", + schedule_type=Schedule.BIMONTHLY + ) + scheduler(broker=broker) + schedule = Schedule.objects.get(pk=schedule.pk) + assert schedule.next_run.date() == add_months(timezone.now(), 2).date() + + # test biweekly + schedule = create_schedule( + "django_q.tests.tasks.word_multiply", + 2, + word="catch_up", + schedule_type=Schedule.BIWEEKLY + ) + scheduler(broker=broker) + schedule = Schedule.objects.get(pk=schedule.pk) + assert schedule.next_run.date() == (timezone.now() + timedelta(weeks=2)).date() + broker.delete_queue() + monkeypatch.setattr(Conf, "PREFIX", "some_cluster_name") # create a schedule on another cluster schedule = create_schedule( diff --git a/docs/schedules.rst b/docs/schedules.rst index 5687000..b7b4f5b 100644 --- a/docs/schedules.rst +++ b/docs/schedules.rst @@ -165,7 +165,7 @@ Reference .. py:attribute:: TYPE - :attr:`ONCE`, :attr:`MINUTES`, :attr:`HOURLY`, :attr:`DAILY`, :attr:`WEEKLY`, :attr:`MONTHLY`, :attr:`QUARTERLY`, :attr:`YEARLY`, :attr:`CRON` + :attr:`ONCE`, :attr:`MINUTES`, :attr:`HOURLY`, :attr:`DAILY`, :attr:`WEEKLY`, :attr:`BIWEEKLY`, :attr:`MONTHLY`, :attr:`BIMONTHLY`, :attr:`QUARTERLY`, :attr:`YEARLY`, :attr:`CRON` .. py:attribute:: minutes @@ -224,10 +224,23 @@ Reference `'W'` the task will run every week on they day and time of the first run. + .. py:attribute:: BIWEEKLY + + `'BW'` the task will run once every two weeks on they day and time of the first run. + .. py:attribute:: MONTHLY `'M'` the tasks runs every month on they day and time of the last run. + .. note:: + + Months are tricky. If you schedule something on the 31st of the month and the next month has only 30 days or less, the task will run on the last day of the next month. + It will however continue to run on that day, e.g. the 28th, in subsequent months. + + .. py:attribute:: BIMONTHLY + + `'BM'` the tasks runs once every two months on they day and time of the last run. + .. note:: Months are tricky. If you schedule something on the 31st of the month and the next month has only 30 days or less, the task will run on the last day of the next month.