feat(i18n): add English localization with per-user language preference
This commit is contained in:
@@ -76,45 +76,97 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
<script>
|
||||
(function() {
|
||||
var labels = {{ sent_country_stats|map(attribute=0)|list|tojson }};
|
||||
var data = {{ sent_country_stats|map(attribute=1)|list|tojson }};
|
||||
if (labels.length) {
|
||||
new Chart(document.getElementById('chart-sent'), {
|
||||
type: 'bar',
|
||||
data: { labels: labels, datasets: [{ data: data, backgroundColor: '#f59e0b', borderRadius: 4 }] },
|
||||
options: { responsive: true, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, ticks: { stepSize: 1 } } } }
|
||||
});
|
||||
}
|
||||
var rlabels = {{ received_country_stats|map(attribute=0)|list|tojson }};
|
||||
var rdata = {{ received_country_stats|map(attribute=1)|list|tojson }};
|
||||
if (rlabels.length) {
|
||||
new Chart(document.getElementById('chart-received'), {
|
||||
type: 'bar',
|
||||
data: { labels: rlabels, datasets: [{ data: rdata, backgroundColor: '#8b5cf6', borderRadius: 4 }] },
|
||||
options: { responsive: true, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, ticks: { stepSize: 1 } } } }
|
||||
});
|
||||
}
|
||||
})();
|
||||
{% if sent_country_stats %}
|
||||
new Chart(document.getElementById('chart-sent'), {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: [{% for code, _ in sent_country_stats %}'{{ code|flag }} {{ code }}',{% endfor %}],
|
||||
datasets: [{ data: [{% for _, count in sent_country_stats %}{{ count }},{% endfor %}], backgroundColor: '#3b82f6', borderRadius: 4, maxBarThickness: 40 }]
|
||||
},
|
||||
options: { responsive: true, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, ticks: { stepSize: 1 } }, x: { grid: { display: false } } } }
|
||||
});
|
||||
{% endif %}
|
||||
{% if received_country_stats %}
|
||||
new Chart(document.getElementById('chart-received'), {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: [{% for code, _ in received_country_stats %}'{{ code|flag }} {{ code }}',{% endfor %}],
|
||||
datasets: [{ data: [{% for _, count in received_country_stats %}{{ count }},{% endfor %}], backgroundColor: '#8b5cf6', borderRadius: 4, maxBarThickness: 40 }]
|
||||
},
|
||||
options: { responsive: true, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, ticks: { stepSize: 1 } }, x: { grid: { display: false } } } }
|
||||
});
|
||||
{% endif %}
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
{% if profiles %}
|
||||
<div class="dash-sections">
|
||||
{% for p in profiles %}
|
||||
<a href="/profiles/{{ p.id }}/postcards" class="card dashboard-card">
|
||||
<h3>{{ p.nickname }}</h3>
|
||||
<div class="stats">
|
||||
<span class="stat">{{ p.postcards|length }} {{ 'profiles.total'|t(user.language) }}</span>
|
||||
<div class="dash-section">
|
||||
<h2>{{ 'dash.recent'|t(user.language) }}</h2>
|
||||
{% if recent %}
|
||||
<div class="recent-list">
|
||||
{% for pc in recent %}
|
||||
<a href="/postcards/{{ pc.id }}" class="recent-item">
|
||||
<div class="recent-img">
|
||||
{% if pc.image_front %}
|
||||
<img src="{{ pc.image_front }}" alt="" loading="lazy">
|
||||
{% else %}
|
||||
<span>📷</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="recent-info">
|
||||
<strong>{{ pc.card_number }}</strong>
|
||||
<span class="badge badge-{{ pc.status }}">{{ {'sent':'已寄出','delivered':'已送达','received':'已收到'}.get(pc.status) if user.language=='zh' else {'sent':'Sent','delivered':'Delivered','received':'Received'}.get(pc.status) }}</span>
|
||||
</div>
|
||||
<div class="recent-meta">
|
||||
{% if pc.status in ('sent','delivered') %}
|
||||
<span>{{ pc.country|flag }} {{ pc.country or '' }}</span>
|
||||
<span>→ {{ pc.recipient_name or '-' }}</span>
|
||||
{% else %}
|
||||
<span>← {{ pc.sender_name or '-' }}</span>
|
||||
{% endif %}
|
||||
<span class="recent-time">
|
||||
{% if pc.status == 'sent' and pc.send_time %}
|
||||
{% set delta = (now.date() - pc.send_time.date()).days %}
|
||||
{% if delta == 0 %}{{ 'dash.today'|t(user.language) }}{% elif delta == 1 %}{{ 'dash.yesterday'|t(user.language) }}{% else %}{{ delta }}{{ 'dash.days_ago'|t(user.language) }}{% endif %}
|
||||
{% elif pc.status == 'delivered' and pc.arrival_time %}
|
||||
{% set delta = (now.date() - pc.arrival_time.date()).days %}
|
||||
{% if delta == 0 %}{{ 'dash.today'|t(user.language) }}{% elif delta == 1 %}{{ 'dash.yesterday'|t(user.language) }}{% else %}{{ delta }}{{ 'dash.days_ago'|t(user.language) }}{% endif %}
|
||||
{% elif pc.status == 'received' and pc.receive_time %}
|
||||
{% set delta = (now.date() - pc.receive_time.date()).days %}
|
||||
{% if delta == 0 %}{{ 'dash.today'|t(user.language) }}{% elif delta == 1 %}{{ 'dash.yesterday'|t(user.language) }}{% else %}{{ delta }}{{ 'dash.days_ago'|t(user.language) }}{% endif %}
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p class="empty">{{ 'dash.empty'|t(user.language) }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="dash-section">
|
||||
<h2>Profile</h2>
|
||||
<div class="dash-profiles">
|
||||
{% for p in profiles %}
|
||||
<a href="/profiles/{{ p.id }}/postcards" class="dash-profile-link">
|
||||
<span class="dash-profile-name">{{ p.nickname }}</span>
|
||||
<span class="dash-profile-arrow">→</span>
|
||||
</a>
|
||||
{% endfor %}
|
||||
<a href="/profiles" class="dash-profile-link dash-profile-more">
|
||||
<span class="dash-profile-name">{{ 'profiles.new_btn'|t(user.language) }}</span>
|
||||
<span class="dash-profile-arrow">→</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<p>{{ 'dash.welcome'|t(user.language) }}{{ user.username }} 👋</p>
|
||||
<div class="empty-icon">📮</div>
|
||||
<p>{{ 'dash.welcome_title'|t(user.language) }}</p>
|
||||
<p class="empty-sub">{{ 'dash.welcome_hint'|t(user.language) }} <a href="/profiles">{{ 'nav.profiles'|t(user.language) }}</a></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user