Compare commits

...
25 changed files with 234 additions and 7 deletions
@@ -287,6 +287,10 @@ nav
<div class="pure-control-group">
{{ render_checkbox_field(form.application.form.ui.use_page_title_in_list) }}
</div>
<div class="pure-control-group">
{{ render_checkbox_field(form.application.form.ui.use_share_watch) }}
<span class="pure-form-message-inline">{{ _('This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other people') }}</span>
</div>
<div class="pure-control-group">
{{ render_field(form.application.form.pager_size) }}
<span class="pure-form-message-inline">{{ _('Number of items per page in the watch overview list, 0 to disable.') }}</span>
+4 -2
View File
@@ -1,7 +1,7 @@
import time
import threading
from blinker import signal
from flask import Blueprint, request, redirect, url_for, flash, render_template, session, current_app
from flask import Blueprint, request, redirect, url_for, flash, render_template, session, current_app, abort
from flask_babel import gettext
from loguru import logger
@@ -406,10 +406,12 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, worker_pool,
return redirect(url_for('watchlist.index'))
@ui_blueprint.route("/share-url/<uuid_str:uuid>", methods=['POST'])
@login_optionally_required
def form_share_put_watch(uuid):
if not datastore.data['settings']['application']['ui'].get('use_share_watch'):
abort(403, description="Access denied")
"""Given a watch UUID, upload the info and return a share-link
the share-link can be imported/added"""
import requests
@@ -16,6 +16,7 @@
{%- set open_link = watch.open_link -%}
{%- set error_texts = watch.compile_error_texts(has_proxies=has_proxies) -%}
{%- set system_use_url_watchlist = datastore.data['settings']['application']['ui'].get('use_page_title_in_list') -%}
{%- set system_use_share = datastore.data['settings']['application']['ui'].get('use_share_watch') -%}
{# Class settings mirrored in changedetectionio/static/js/realtime.js for the frontend #}
{# loop.cycle('pure-table-odd', 'pure-table-even'),#}
{%- set row_classes = [
@@ -94,7 +95,7 @@
</div>
<div class="status-icons">
<button type="submit" formmethod="post" formaction="{{url_for('ui.form_share_put_watch', uuid=watch.uuid)}}" class="bare-btn link-spread"><img src="{{url_for('static_content', group='images', filename='spread.svg')}}" class="status-icon icon icon-spread" title="{{ _('Create a link to share watch config with others') }}" ></button>
{%- if system_use_share -%} <button type="submit" formmethod="post" formaction="{{url_for('ui.form_share_put_watch', uuid=watch.uuid)}}" class="bare-btn link-spread"><img src="{{url_for('static_content', group='images', filename='spread.svg')}}" class="status-icon icon icon-spread" title="{{ _('Create a link to share watch config with others') }}" ></button>{%- endif -%}
{%- set effective_fetcher = watch.get_fetch_backend if watch.get_fetch_backend != "system" else system_default_fetcher -%}
{%- if effective_fetcher and ("html_webdriver" in effective_fetcher or "html_" in effective_fetcher or "extra_browser_" in effective_fetcher) -%}
{{ effective_fetcher|fetcher_status_icons }}
@@ -108,7 +109,7 @@
</td>
{%- if any_has_restock_price_processor -%}
<td class="restock-and-price">
<td class="restock-and-price col-restock-price">
{%- if watch['processor'] == 'restock_diff' -%}
{#- @todo - this could be injected somehow watch.extra_row_info or something -#}
<div class="restock-info-wrap">
@@ -339,7 +339,7 @@ window.watchOverviewI18n = {
<th><!-- processor/mode --></th>
<th id="th-webpage"><a class="{{ 'active '+link_order if sort_attribute == 'label' else 'inactive' }}" href="{{url_for('watchlist.index', sort='label', order=link_order, **active_filters)}}">{{ _('Web page') }} <span class='arrow {{link_order}}'></span></a></th>
{%- if any_has_restock_price_processor -%}
<th>{{ _('Restock & Price') }}</th>
<th class="col-restock-price">{{ _('Restock & Price') }}</th>
{%- endif -%}
<th id="h-lastchecked"><a class="{{ 'active '+link_order if sort_attribute == 'last_checked' else 'inactive' }}" href="{{url_for('watchlist.index', sort='last_checked', order=link_order, **active_filters)}}"><span class="hide-on-mobile">{{ _('Checked') }}</span><span class="hide-on-desktop">{{ _('Checked') }}</span> <span class='arrow {{link_order}}'></span></a></th>
<th id="h-lastchanged"><a class="{{ 'active '+link_order if sort_attribute == 'last_changed' else 'inactive' }}" href="{{url_for('watchlist.index', sort='last_changed', order=link_order, **active_filters)}}"><span class="hide-on-mobile">{{ _('Changed') }}</span><span class="hide-on-desktop">{{ _('Changed') }}</span> <span class='arrow {{link_order}}'></span></a></th>
@@ -353,12 +353,24 @@ window.watchOverviewI18n = {
</tr>
{%- endif -%}
{%- set ns = namespace(any_in_page_had_restock=false) -%}
{%- for watch in (watches|sort(attribute=sort_attribute, reverse=sort_order == 'asc'))|pagination_slice(skip=pagination.skip) -%}
{%- include "watch-overview-single-row.html" -%}
{%- if watch['processor'] == 'restock_diff' -%}
{%- set ns.any_in_page_had_restock = true -%}
{%- endif -%}
{%- endfor -%}
</tbody>
</table>
</div>
{%- if not ns.any_in_page_had_restock %}
<style>
.col-restock-price {
display: none;
}
</style>
{%- endif %}
{{ pagination.links }}
</div>
</form>
+1
View File
@@ -1179,6 +1179,7 @@ class globalSettingsApplicationUIForm(Form):
socket_io_enabled = BooleanField(_l('Realtime UI Updates Enabled'), default=True, validators=[validators.Optional()])
favicons_enabled = BooleanField(_l('Favicons Enabled'), default=True, validators=[validators.Optional()])
use_page_title_in_list = BooleanField(_l('Use page <title> in watch overview list')) #BooleanField=True
use_share_watch = BooleanField(_l('Enable watch "sharing"'))
timeago_format = SelectField(_l('Relative time format'),
choices=[('long', _l('Long (1 minute ago)')), ('short', _l('Short (1m ago)'))],
default='long', validators=[validators.Optional()])
+1
View File
@@ -77,6 +77,7 @@ class model(dict):
'webdriver_delay': None , # Extra delay in seconds before extracting text
'ui': {
'use_page_title_in_list': True,
'use_share_watch': False, # "Share watch" link is a power-user feature, off by default
'open_diff_in_new_tab': True,
'socket_io_enabled': True,
'favicons_enabled': True,
+27 -1
View File
@@ -9,8 +9,17 @@ import re
def test_share_watch(client, live_server, measure_memory_usage, datastore_path):
set_original_response(datastore_path=datastore_path)
# live_server_setup(live_server) # Setup on conftest per function
# Turn it on
res = client.post(
url_for('settings.settings_page'),
data={
'application-ui-use_share_watch': '1',
'requests-timeout': '60',
},
follow_redirects=True,
)
assert res.status_code == 200
test_url = url_for('test_endpoint', _external=True)
include_filters = ".nice-filter"
@@ -72,4 +81,21 @@ def test_share_watch(client, live_server, measure_memory_usage, datastore_path):
res = client.get(url_for("watchlist.index"))
assert bytes(test_url.encode('utf-8')) in res.data
# Turn it off
res = client.post(
url_for('settings.settings_page'),
data={
'application-ui-use_share_watch': '',
'requests-timeout': '60',
},
follow_redirects=True,
)
# click share the link
res = client.post(
url_for("ui.form_share_put_watch", uuid=uuid),
follow_redirects=True
)
assert res.status_code == 403
delete_all_watches(client)
@@ -841,6 +841,12 @@ msgstr ""
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr ""
@@ -3495,6 +3501,10 @@ msgstr "Povolit favikony"
msgid "Use page <title> in watch overview list"
msgstr "Použijte stránku <title> v přehledu sledování"
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr ""
@@ -857,6 +857,12 @@ msgstr ""
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr ""
@@ -3545,6 +3551,10 @@ msgstr "Favicons Aktiviert"
msgid "Use page <title> in watch overview list"
msgstr "Verwenden Sie die Seite <title> in der Übersichtsliste der Beobachtungen"
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr ""
@@ -839,6 +839,12 @@ msgstr ""
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr ""
@@ -3487,6 +3493,10 @@ msgstr ""
msgid "Use page <title> in watch overview list"
msgstr ""
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr ""
@@ -839,6 +839,12 @@ msgstr ""
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr ""
@@ -3487,6 +3493,10 @@ msgstr ""
msgid "Use page <title> in watch overview list"
msgstr ""
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr ""
@@ -875,6 +875,12 @@ msgstr "Habilitar o deshabilitar favicons junto a la lista de monitores"
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr "Número de elementos por página en la lista general de monitores, 0 para desactivar."
@@ -3560,6 +3566,10 @@ msgstr "Favicones habilitados"
msgid "Use page <title> in watch overview list"
msgstr "Usar <title> de la página en la lista general de monitores"
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr ""
@@ -845,6 +845,12 @@ msgstr ""
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr ""
@@ -3500,6 +3506,10 @@ msgstr "Favicons Activés"
msgid "Use page <title> in watch overview list"
msgstr "Utiliser la page <title> dans la liste de présentation des moniteurs"
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr ""
@@ -870,6 +870,12 @@ msgstr "Aktifkan atau Nonaktifkan Favicon di samping daftar monitor"
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr "Jumlah item per halaman dalam daftar ringkasan monitor, 0 untuk menonaktifkan."
@@ -3600,6 +3606,10 @@ msgstr "Favicon Diaktifkan"
msgid "Use page <title> in watch overview list"
msgstr "Gunakan <title> halaman dalam daftar ringkasan monitor"
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr "Format waktu relatif"
@@ -841,6 +841,12 @@ msgstr ""
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr ""
@@ -3489,6 +3495,10 @@ msgstr "Favicon attive"
msgid "Use page <title> in watch overview list"
msgstr "Usa <title> pagina nell'elenco osservati"
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr ""
@@ -846,6 +846,12 @@ msgstr "ウォッチリスト横のファビコンを有効または無効にす
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr "ウォッチ一覧ページの1ページあたりの表示件数(0で無効化)。"
@@ -3506,6 +3512,10 @@ msgstr "ファビコンを有効化"
msgid "Use page <title> in watch overview list"
msgstr "ウォッチ一覧リストでページの <title> を使用"
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr ""
@@ -841,6 +841,12 @@ msgstr "모니터링 목록 옆 파비콘 표시 여부"
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr "모니터링 목록 페이지당 항목 수입니다. 0이면 비활성화됩니다."
@@ -3497,6 +3503,10 @@ msgstr "파비콘 활성화"
msgid "Use page <title> in watch overview list"
msgstr "모니터링 목록에 페이지 <title> 사용"
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr ""
+11 -1
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: changedetection.io 0.60.6\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2026-09-16 18:43+0200\n"
"POT-Creation-Date: 2026-09-17 08:45+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -838,6 +838,12 @@ msgstr ""
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr ""
@@ -3486,6 +3492,10 @@ msgstr ""
msgid "Use page <title> in watch overview list"
msgstr ""
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr ""
@@ -893,6 +893,12 @@ msgstr "Włącz lub wyłącz wyświetlanie ikon favicon obok listy obserwacji"
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr "Liczba pozycji na stronie listy obserwacji; wartość 0 oznacza wyłączenie tej funkcji."
@@ -3646,6 +3652,10 @@ msgstr "Włączono favikony"
msgid "Use page <title> in watch overview list"
msgstr "Użyj elementu <title> strony na liście obserwacji"
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr "Format czasu względnego"
@@ -862,6 +862,12 @@ msgstr "Ativar ou Desativar Favicons ao lado da lista de monitoramento"
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr "Número de itens por página na lista de visão geral, 0 para desativar."
@@ -3537,6 +3543,10 @@ msgstr "Favicons Ativados"
msgid "Use page <title> in watch overview list"
msgstr "Usar <title> da página na lista de visão geral"
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr ""
@@ -876,6 +876,12 @@ msgstr "Включить или отключить значки рядом со
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr "Количество элементов на странице в обзорном списке наблюдения: 0, чтобы отключить."
@@ -3605,6 +3611,10 @@ msgstr "Фавиконки включены"
msgid "Use page <title> in watch overview list"
msgstr "Использовать страницу <title> в обзорном списке просмотра"
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr ""
@@ -872,6 +872,12 @@ msgstr "İzleme listesinin yanındaki Favicon'ları Etkinleştir veya Devre Dı
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr "İzleyici genel bakış listesinde sayfa başına öğe sayısı, devre dışı bırakmak için 0."
@@ -3540,6 +3546,10 @@ msgstr "Favicon'lar Etkin"
msgid "Use page <title> in watch overview list"
msgstr "İzleyici genel bakış listesinde sayfa <title>'ını kullan"
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr ""
@@ -852,6 +852,12 @@ msgstr "Увімкнути або вимкнути значки (фавікон
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr "Кількість елементів на сторінці у списку завдань, 0 для вимкнення."
@@ -3519,6 +3525,10 @@ msgstr "Фавіконки увімкнено"
msgid "Use page <title> in watch overview list"
msgstr "Використовувати <title> сторінки у списку огляду завдань"
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr ""
@@ -844,6 +844,12 @@ msgstr "在监控列表中启用或禁用站点图标"
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr "监控概览列表每页数量,0 为禁用。"
@@ -3493,6 +3499,10 @@ msgstr "启用站点图标"
msgid "Use page <title> in watch overview list"
msgstr "在监控概览列表中使用页面 <title>"
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr ""
@@ -843,6 +843,12 @@ msgstr "啟用或停用監測列表旁的網站圖示(Favicons)"
msgid "Disabling this can speed up your page fetches because the favicon does not need to be fetched."
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid ""
"This copies your watch to a temporary hosted database and returns a link to make sharing/copying the watch to other "
"people"
msgstr ""
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Number of items per page in the watch overview list, 0 to disable."
msgstr "監測概覽列表中每頁的項目數量,設為 0 以停用。"
@@ -3498,6 +3504,10 @@ msgstr "啟用網站圖示 (Favicons)"
msgid "Use page <title> in watch overview list"
msgstr "在監測概覽列表中使用頁面 <title>"
#: changedetectionio/forms.py
msgid "Enable watch \"sharing\""
msgstr ""
#: changedetectionio/forms.py
msgid "Relative time format"
msgstr "相對時間格式"