Files
eminuxandCursor cc95fcacbf Permette all’admin di forzare anagrafica, fiscali, owner, staff e inviti.
Ops può correggere dati clienti errati (es. email titolare) dalla scheda società senza interventi manuali sul DB.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 18:18:18 +02:00

735 lines
28 KiB
YAML

en:
admin:
layout:
title: "Match Live TV — Admin"
nav:
dashboard: Dashboard
ops: Ops
announcements: Notices
clubs: Clubs & teams
billing: Billing
youtube: YouTube
sessions: Sessions
stream_concurrency: Account abuse
analytics: Analytics
costs: Costs
stream_nodes: Stream nodes
password: Password
logout: Log out
flash:
login_required: Please log in to continue
login_success: Signed in successfully
invalid_credentials: Invalid username or password
logout_success: Signed out
password_current_incorrect: Current password is incorrect
password_too_short: The new password must be at least 8 characters long
password_too_long: New password cannot exceed 72 characters
password_too_weak: "New password must include at least 3 of: lowercase, uppercase, numbers and symbols"
password_same_as_current: New password must be different from the current password
password_mismatch: Passwords do not match
password_updated: Password updated
ops_acknowledged: Incident acknowledged
ops_resolved: Incident resolved
ops_muted: Notifications muted for 24 hours
stream_node_created: "Lab node %{slug} provisioned."
stream_node_destroyed: "Node %{slug} removed."
stream_node_draining: "Node %{slug} is draining (no new sessions)."
autoscale_kill_on: "Autoscaler kill-switch engaged. No automatic scale-out."
autoscale_kill_off: "Autoscaler kill-switch cleared (still needs STREAM_AUTOSCALE_ENABLED=1)."
comped_granted: "%{plan} complimentary subscription activated for %{club}."
comped_revoked: "Complimentary subscription revoked for %{club}."
session_already_terminated: "Session already ended (%{status})."
session_stopped: Session ended.
session_stop_error: "Error while stopping: %{error}"
session_terminated_no_regia: "Session ended: unable to generate the control link."
session_regia_generated: Control link generated.
invoice_upload_hint: Upload the PDF from the "Payments to invoice" list.
invoice_draft_created: Draft created. Upload the PDF from the Billing page or below.
invoice_issued: "Invoice %{number} issued and sent to %{email}."
invoice_updated: "Invoice %{number} updated."
invoice_uploaded: "Invoice uploaded and sent to %{email}."
club_updated: "Data updated for %{club}."
youtube_not_configured: Configure YOUTUBE_CLIENT_ID and YOUTUBE_CLIENT_SECRET in .env
announcement_created: Notice saved
announcement_updated: Notice updated
announcement_destroyed: Notice deleted
cost_entry_created: Cost entry saved.
cost_entry_updated: Cost entry updated.
cost_entry_destroyed: Cost entry deleted.
common:
free_plan: Free
yes: "Yes"
no: "No"
dash: "—"
live_page: Live page
auth:
new:
title: Admin login
username_label: Username
password_label: Password
submit: Log in
initial_credentials_html: "Initial credentials: <code>admin</code> / <code>AdminPass123</code>. Change the password after the first login."
passwords:
edit:
title: Change password
current_password_label: Current password
new_password_label: "New password (min. 8, at least 3 character types)"
confirm_password_label: Confirm new password
submit: Save password
cancel: Cancel
dashboard:
kpi:
active_sessions: Active sessions
active_sessions_sub: live right now
today: Streamed today
today_sub: "%{duration} of streaming"
month: Streamed this month
month_sub: "%{duration} total"
teams: Teams
teams_sub: "%{count} users"
cpu: CPU
cpu_sub: "load %{one} / %{five} / %{fifteen}"
ram: RAM
ram_sub: "%{used} / %{total}"
network: Bandwidth (total)
network_sub: "↑ %{tx} · ↓ %{rx}"
recordings: Recordings in archive
recordings_sub: "%{count} recordings"
charts:
cpu: CPU (%)
ram: RAM (%)
ops_panel:
title: Platform status (Ops)
critical: "%{count} critical incident(s) open"
view_dashboard: View Ops dashboard
warnings: "%{count} warning(s)"
dashboard_link: Ops dashboard
none_html: "No open incidents. %{link}"
concurrency_panel:
title: Account abuse (second live)
count: "%{count} attempt(s) in the last 30 days"
view_all: View all
none: No attempts recorded.
none_html: "No second-live attempts from the same account. %{link}"
disk:
system_title: System disk
free_label: "Free: %{free} (%{percent}% used)"
not_available: Disk metrics not available
recordings_title: Recordings archive
recordings_content: "Recordings content: %{size}"
recordings_not_mounted: "Path %{path} not mounted"
sessions:
title: Active sessions
table:
match: Match
status: Status
client: Client
ingest: Ingest
start: Start
link: Link
none: No active session right now.
detail: Details
stop: Stop
stop_confirm: End this session?
regia: Control
teams:
title: Teams
matches_count: "%{count} matches"
view_all: "View clubs (%{count} teams)"
stream_nodes:
title: Streaming nodes
providers: "Cloud: %{cloud} · DNS: %{dns}"
actions_title: Actions
table_title: Registered nodes
empty: No nodes registered.
free_slots:
one: "%{count} free"
other: "%{count} free"
kpi:
autoscaler: Autoscaler
kill_switch: KILL
kind: "%{kind} mode"
free_slots: Free slots
soft_slots: "soft threshold ≤ %{soft}"
spare: Spare
warm_spare: warm spares ready
overflow: Overflow
overflow_nodes: cloud/lab nodes
budget: Estimated budget
budget_of: "of €%{budget}/mo (%{ok})"
autoscale: "Autoscaler %{enabled} · free_slots=%{free} (soft≤%{soft}) · spare=%{spare}/%{warm} · overflow=%{overflow}/%{max} · kind=%{kind}"
autoscale_budget: "budget €%{eur}/€%{budget} (%{ok})"
kill_switch_active: "KILL-SWITCH ACTIVE"
engage_kill_switch: "Kill-switch ON"
clear_kill_switch: "Kill-switch OFF"
kill_switch_confirm: "Immediately block the autoscaler? Existing nodes stay up."
provision_lab: Provision lab
provision_cloud: Provision Hetzner
provision_cloud_confirm: "Create a Hetzner Cloud server + DNS record on mltv-stream.net? Billing applies until destroyed."
hetzner_token_missing: "Set HCLOUD_TOKEN to enable Cloud provisioning."
drain: Drain
destroy: Delete
destroy_confirm: "Delete node %{slug}?"
hosts_title: Lab DNS records (/etc/hosts snippet)
col:
slug: Slug
role: Role
status: Status
slots: Slots
hostname: Hostname
provider: Provider
ops:
kpi:
critical: Critical open
warning: Warnings open
total: Total open
open:
title: Open incidents
table:
severity: Severity
kind: Type
title: Title
occurrences: Occ.
last_seen: Last seen
none: No open incidents. The platform looks healthy.
actions:
acknowledge: Acknowledge
resolve: Resolve
mute: Mute 24h
resolved:
title: Resolved (last 30 days)
table:
resolved_at: Resolved
none: No incidents resolved recently.
stream_concurrency:
index:
title: Account abuse
lead: Attempts to start a second live with the same account while another was already running (connecting, live, reconnecting or paused).
results: "Showing %{shown} of %{total}"
none: No attempts recorded.
kpi:
lookback: Last 30 days
lookback_sub: blocked attempts
two_devices: Two devices
two_devices_sub: different phone models
filters:
q: Search
q_placeholder: Email, club, match…
two_devices: Filter
two_devices_hint: Only attempts from different devices
apply: Filter
reset: Reset
table:
when: When
account: Account
club: Club
occupying: Live already running
attempted: Blocked attempt
action:
start: start
resume: resume
badge:
two_devices: 2 phones
same_or_unknown: same device / n.a.
clubs:
index:
title: Clubs & teams
subtitle_html: "Complimentary subscriptions (sponsors / promotions) and YouTube status per team. Stripe payments: %{billing_link}."
billing_link: Billing
table:
club: Club
plan: Plan
teams: Teams
billing_profile: Billing data
comped: Comp
stripe: Stripe
quote: Quoted
manage: Manage
invoices: Invoices
show:
back: "← Clubs & teams"
sport_label: "Sport: %{sport}"
recordings_archive: Recordings archive
billing_link: Payments & invoices
youtube_platform_link: Platform YouTube channel
youtube_club_label: "Club YouTube:"
youtube_connected: (connected)
youtube_premium_full_not_connected: Premium Full — club channel not connected (using Match Live TV)
no_channel_hint_html: "Without a connected channel, the app uses the Match Live TV channel. %{link}."
link_channel: Connect channel (club page)
profile_title: Contact & billing details
owner_title: Account owner
owner_name: Name
owner_email: Email
owner_none: No owner associated.
billing_title: Billing details
billing_none: No billing details provided.
teams_title: Teams
no_teams: No teams registered.
table:
team: Team
sport: Sport
matches_and_details: Matches & details
replay: Replays
concurrency_title: Second-live attempts
concurrency_lead: Same account tried to start another live while one was already running.
concurrency_none: No attempts recorded for this club.
concurrency_all: View all account abuse
edit_link: Edit data
edit:
back: "← Back to club"
title: "Edit %{club}"
lead: "Override client-entered data: profile, billing, owner, staff, invitations and teams."
cancel: Cancel
submit: Save changes
billing_hint: You can save an incomplete profile; the badge on the club page will reflect the status.
staff_hint: Users already linked to this club's teams (including owners if also staff).
staff_none: No staff linked to teams.
invitations_hint: Only invitations still awaiting acceptance.
invitations_none: No pending invitations.
sections:
club: Club profile
billing: Billing details
owner: Account owner
staff: Accepted staff
invitations: Pending invitations
teams: Teams
fields:
name: Club name
sport: Sport
primary_color: Primary colour
secondary_color: Secondary colour
logo_url: Logo URL
owner_name: Owner name
owner_email: Owner email
staff_name: Name
staff_email: Email
invitation_team: Team
invitation_email: Invitation email
team_name: Team name
team_sport: Team sport
errors:
owner_missing: No owner associated with this club.
email_taken: "Email already in use: %{email}"
billing_status:
complete: Complete
incomplete: Incomplete
absent: Missing
comped:
title: Complimentary subscription
description: "Sponsor or promotion: grant Premium Light/Full without a Stripe payment. Revocable at any time."
active_label: "Active:"
since_label_html: "Since %{date}"
by_admin: "· admin %{username}"
stripe_note: "Note: a linked Stripe subscription also exists; the comp takes priority over the plan."
revoke_button: Revoke comp (revert to Free or restore Stripe)
revoke_confirm: "Revoke the complimentary subscription for %{club}?"
current_plan: "Current plan: %{plan}"
stripe_active: "· active Stripe payment"
plan_label: Plan
reason_label: "Reason (e.g. 2026 sponsor)"
reason_placeholder: "Sponsor, promotion…"
grant_button: Grant comp
teams:
show:
back: "← %{club}"
sport_label: "Sport: %{sport}"
club_label_html: "Club: %{club} · %{replay_link} · %{billing_link}"
replay_link: Team replays
billing_link: Payments & invoices
youtube_label: "YouTube:"
youtube_platform_default_no_oauth: ", default without club OAuth"
youtube_platform_channel: "(platform channel%{suffix})"
youtube_club_channel: (club channel)
youtube_not_ready: not ready
no_channel_hint_html: "Without a connected channel, the app uses the Match Live TV channel. %{link}."
link_channel: Connect channel (club page)
matches_title: Matches
sessions:
index:
title: Stream sessions
lead: Search by club, team, opponent or venue. Filter by status, platform, node and date range.
results: "Showing %{shown} of %{total}"
none: No sessions match these filters.
filters:
q: Search
q_placeholder: Club, team, opponent…
status: Status
platform: Platform
club: Club
node: Ingest node
from: From
to: To
any: All
apply: Filter
reset: Reset
table:
club: Club
match: Match
status: Status
started: Started
ended: Ended
duration: Duration
ingest: Ingest
disconnects: Disconnects
client: Client
link: Link
detail: Details
regia: Control
show:
title: "Session %{id}"
heading: Session details
back: "← Back to sessions"
club_label: "Club:"
summary_title: Summary
timing_title: Timing
ingest_title: Ingest & media
devices_title: Devices
events_title: Events
events_none: No events recorded.
concurrency_title: Second-live attempts
concurrency_lead: This account tried to start another live while this one was already running (or was blocked by another session of the same account).
status_label: "Status:"
stop_button: End session
stop_confirm: "End the broadcast? The RTMP path will be removed and the status will move to ended."
match_label: "Match: %{team} vs %{opponent}"
youtube_studio: YouTube Studio
broadcast: Broadcast
open_replays: Open club replays
audio_muted: Audio muted
audio_on: Audio on
ingest_node: "Ingest node:"
rtmp_ingest: "RTMP ingest:"
fields:
id: ID
club: Club
team: Team
opponent: Opponent
operator: Operator
platform: Platform
client_os: OS
app_version: App version
device: Device
os_version: OS version
carrier: Carrier
privacy: Privacy
quality: Quality
min_quality: Min quality
audio: Audio
created: Created
started: Started
ended: Ended
duration: Duration
disconnects: Disconnects
scheduled: Scheduled match
location: Venue
node: Node
rtmp: RTMP ingest
hls: HLS
recording: Replay
devices:
role: Role
network: Network
battery: Battery
bitrate: Bitrate
fps: FPS
last_seen: Last seen
table:
type: Type
when: When
meta: Details
links:
watch_title: Live link
none: No video link available for this session.
regia_title: Control link
terminated: Session ended — control link not available.
regia_label: Control
valid_until: "Valid until %{date}"
active_exists: An active control link already exists (the URL cannot be retrieved). Generate a new one if you need to share it again.
none_active: No active control link. Generate a link to share with whoever manages the score.
generate_button: Generate control link
ingest:
none: "—"
decommissioned: "(node removed)"
role:
home: Home-lab
lab: Lab
cloud: Hetzner
analytics:
missing_path: Select a page.
filters:
from: From
to: To
device: Device
any: All
apply: Filter
reset: Reset
chart_path: Page (chart)
chart_path_all: All pages
layer: Layer
layer_move: Mouse moves
layer_click: Clicks
devices:
mobile: Mobile
tablet: Tablet
desktop: Desktop
index:
title: Site analytics
lead: Aggregated first-party move/click heatmaps and scroll depth, only with analytics consent. No personal data.
none: No data in the selected period.
heatmap: Heatmap
chart_for_path: Chart
trend_title: Pageview trend
trend_lead: Total pageviews across all pages, day by day. Uses the same From / To / Device filters. Pick a page in the filter or click «Chart» in the table.
trend_lead_path: "Day-by-day pageviews for %{path} only (same From / To / Device filters)."
trend_total_label: Total pageviews (all pages)
trend_total_label_path: Pageviews for selected page
trend_total_hint: "%{from} → %{to}"
hide_chart: Hide chart
show_chart: Show chart
pages_title: Breakdown by page
pages_lead: Pageviews and engagement for the filtered period, split by path. Use «Chart» to see one page over time.
table:
path: Page
pageviews: Pageviews
moves: Moves
clicks: Clicks
avg_scroll: Avg scroll
max_scroll: Max scroll
show:
title: Page heatmap
back: "← Back to Analytics"
summary: Summary
scroll_depth: Scroll depth
scroll_hint: "Average %{avg}% · max %{max}%"
heatmap_moves: Mouse-move map
heatmap_clicks: Click map
heatmap_hint: Colored overlay on the %{device} screenshot. Green = low, red = high. Data is never mixed across devices.
device_tabs_label: Device
preview_title: Page screenshot
preview_unavailable: Preview unavailable for paths with placeholders (e.g. /clubs/:id).
snapshot_missing: No screenshot for %{device} yet. Visit the page on that device with analytics consent, then retry in a few seconds.
snapshot_meta: "Screenshot %{device} · captured %{at}"
no_points: No aggregated points for this layer in the period.
heatmap_title: Click map
no_clicks: No aggregated clicks for this page in the period.
preview:
title: Preview without tracking
lead: Browse the public site without recording pageviews, clicks, moves or heatmap screenshots. Useful for production smoke tests.
active: Staff preview is active in this browser (7 days or until disabled).
enable: Enable staff preview
disable: Disable preview
open_site: Open site
enabled: Staff preview enabled. This browser will not record analytics.
disabled: Staff preview disabled.
costs:
index:
title: Cost analysis
lead: Enter monthly platform costs and compare cost, usage and revenue. KPIs recalculate automatically when you edit entries.
month: Month
apply: Apply
entries_title: Cost entries for the month
entries_lead: Add multiple line items (e.g. servers, storage, bandwidth). Month total is the sum of entries.
add_entry: Add entry
no_entries: No cost entries for this month. Add platform cost to see KPIs.
clubs_title: Allocated cost per club
clubs_lead: Infrastructure cost is split proportionally by streamed hours in the month.
no_clubs: No ended streams in this month.
trends_title: Trends (last 12 months)
kpi:
platform_cost: Platform cost
revenue: Revenue collected
margin: Margin
margin_pct: Margin %
hours: Streamed hours
sessions: Streams
clubs_active: Active clubs
storage: Replay storage
cost_per_hour: Cost / stream hour
cost_per_session: Cost / stream
cost_per_club: Cost / active club
revenue_per_hour: Revenue / stream hour
cost_per_gb: Cost / GB storage
storage_note: Current cumulative storage (not monthly).
charts:
cost_revenue: Cost vs revenue
cost_per_hour: Cost per streamed hour
hours: Streamed hours
table:
label: Item
amount: Amount
notes: Notes
club: Club
plan: Plan
hours: Hours
hours_share: Hour share
allocated_cost: Allocated cost
revenue: Revenue
margin: Margin
cost_per_hour: €/hour
cost_per_session: €/stream
storage: Storage
entries:
new_title: New cost entry
edit_title: Edit cost entry
month: Month
label: Description
label_hint: E.g. Hetzner, stream nodes, S3, egress.
amount: Amount (€)
notes: Notes
save: Save
cancel: Cancel
delete: Delete
delete_confirm: Delete this cost entry?
billing:
index:
title: Payments to invoice
description: Stripe payments that are paid but have no invoice PDF yet. Generate the PDF in your systems, then upload it here — it will be linked to the payment and emailed to the customer.
filter_label: "Filter clubs:"
filter_all: All
incomplete_profile_warning: Billing details incomplete
no_billing_data: No billing details — the customer must complete their profile.
pdf_label: Invoice PDF
upload_button: Upload PDF and send to customer
none_pending: "No payments awaiting an invoice%{club}."
none_pending_for_club: " for %{club}"
uploaded_title: Invoices already uploaded
table:
date: Date
club: Club
description: Description
amount: Amount
invoice: Invoice
status: Status
back_dashboard: "← Dashboard"
billing_invoices:
index:
title: "Billing — %{club}"
back_dashboard: "← Dashboard"
new_invoice: New invoice (no payment)
payments_title: Payments
table:
date: Date
description: Description
amount: Amount
invoice: Invoice
pdf_suffix: " (PDF)"
edit_send_pdf: Edit / send PDF
create_invoice: Create invoice
no_payments: No payments recorded for this club.
all_invoices_title: All invoices
table2:
number: Number
date: Date
amount: Amount
status: Status
payment: Payment
edit: Edit
no_invoices: No invoices.
new:
title: "New invoice — %{club}"
linked_payment: "Linked to the payment of %{date} (%{amount})."
number_label: Invoice number
issued_on_label: Issue date
amount_label: "Amount (€)"
notes_label: Internal notes (optional)
hint: Save the draft, then upload the PDF and send it to the customer from the next screen.
submit: Create invoice draft
back: "← Payments & invoices"
edit:
title: "Invoice %{number} — %{club}"
status_label: "Status:"
sent_at: "· Sent on %{date}"
number_label: Invoice number
issued_on_label: Issue date
amount_label: "Amount (€)"
payment_info: "Payment: %{description} — %{amount}"
pdf_label: Invoice PDF
pdf_already: "PDF already uploaded: %{filename}"
notes_label: Internal notes
save_draft: Save draft
issue_send: Issue and send by email
issue_confirm: "Send the invoice to %{email}?"
back: "← Payments & invoices"
youtube:
platform_token:
title: Match Live TV channel token
page_title: "YouTube token — Match Live TV"
channel_label: "Channel: %{title}"
success: "Connection successful. Copy this line right away:"
env_hint_html: "Add to <code>/opt/matchlivetv/infra/.env</code>:"
not_shown_again_html: "It won't be shown again. Then run: <code>docker compose -f docker-compose.prod.yml restart rails sidekiq</code>"
no_refresh_token_html: "Google did not return a refresh token. In your <a href=\"https://myaccount.google.com/permissions\" target=\"_blank\" rel=\"noopener\">Google account → app access</a>, revoke «Match Live TV», then repeat from <a href=\"/admin/youtube/platform\">/admin/youtube/platform</a>."
back_dashboard: "← Admin dashboard"
club_recordings:
index:
title: "Replays — %{club}"
announcements:
index:
title: Notices
lead: Messages for the apps, the public website and the logged-in area — maintenance, updates or announcements.
new: New notice
table_title: Notices
none: No notices yet. Create one to notify the apps and the website.
new:
title: New notice
edit:
title: Edit notice
table:
status: Status
kind: Type
title: Message
channels: Destinations
window: Window
actions:
edit: Edit
delete: Delete
delete_confirm: Delete this notice? It will no longer appear in the selected destinations.
kind:
info: Information
maintenance: Maintenance
update: App update
severity:
info: Info
warning: Warning
critical: Critical
status:
draft: Draft
published: Published
archived: Archived
channels:
android: Android app
ios: iOS app
web_public: Public website
web_private: Logged-in area
window:
always: Always (while published)
from: "From %{time}"
until: "Until %{time}"
form:
kind: Type
severity: Severity
status: Status
channels: Where to show it
channels_hint: "Select one or more destinations. Android and iOS are independent: create two notices if the copy should differ. The logged-in area is visible after sign-in (club, teams, account)."
title: Title
body: Body
starts_at: Visible from
ends_at: Visible until
window_hint: Leave empty to show immediately while published.
action_url: Link (optional)
action_url_hint: For updates, an empty URL opens that platform's store (Play Store on Android, App Store on iOS).
action_label: Button label
locales_legend: Copy by language
locales_hint: Fill in every app language (Italian, English, French, German, Spanish). Italian is required; missing languages fall back to English, then Italian.
locale_required: required
dismissible: Users can dismiss the notice
dismissible_hint: Uncheck for maintenance notices that should stay visible.
submit_create: Save notice
submit_update: Update notice
cancel: Cancel