feat(TournamentStats): refine internal tournament scoring and enhance UI features
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 36s

- Updated the scoring logic for internal tournaments to reflect percentage-based placements, improving clarity and fairness in rankings.
- Refactored the `groupPointsFromRankings` function to `groupPercentFromRankings` for better readability and accuracy in calculations.
- Enhanced the InternalTournamentStats component with a new PDF export feature and improved dialog positioning for better user experience.
- Updated localization strings across multiple languages to align with the new scoring system and UI enhancements, ensuring better accessibility and understanding for users.
This commit is contained in:
Torsten Schulz (local)
2026-04-08 11:20:46 +02:00
parent 43dbd5442a
commit c1b8b2c665
18 changed files with 294 additions and 81 deletions

View File

@@ -59,7 +59,7 @@ export const getTournaments = async (req, res) => {
}
};
/** Ranglisten interne Einzel-Turniere (Gruppen- + K.-o.-Punkte) */
/** Ranglisten interne Einzel-Turniere (Gruppen-% + K.-o.-Bonus wie im Service) */
export const getInternalTournamentStats = async (req, res) => {
const { authcode: token } = req.headers;
const { clubId } = req.params;

View File

@@ -1,10 +1,11 @@
/**
* Statistik-Punkte für interne Einzel-Turniere (Gruppenphase + K.-o.-Runde).
* Statistik-Werte für interne Einzel-Turniere (Gruppenphase + K.-o.-Runde).
*
* Gruppe: 1. Platz = 100, 2. = 99, 3. = 98, … (Platzierung aus API: 1 = bestes Ergebnis).
* Gleiche Platzierung = gleiche Punkte. Ab Platz 101 wird mit 0 gekappt.
* K.-o.: Wer die K.-o.-Runde erreicht: höchste Gruppenpunkte dieser Klasse + 1,
* danach +1 pro gewonnenes K.-o.-Spiel.
* Gruppe: Platzierung als Prozent relativ zur Feldgröße N (alle mit Platzierung > 0),
* Formel (N pos) / (N 1) × 100 für N ≥ 2 (1. = 100 %, Letzter = 0 %),
* bei N = 1: 100 %. Nur Vereinsmitglieder werden gewertet; N zählt alle Platzierten.
* K.-o.: Wer die K.-o.-Runde erreicht: höchster Gruppen-Prozentwert dieser Klasse + 1,
* danach +1 pro gewonnenes K.-o.-Spiel (wie bisher, jetzt auf %-Skala).
*/
export function parseWinnerFromMatch(match) {
@@ -50,19 +51,32 @@ export function parseWinnerFromMatch(match) {
}
/**
* @param {Array<{ position: number, id: number }>} rankings Platz 1 = bestes Ergebnis; id = Turnier-Mitglied-ID
* @returns {Map<number, number>} tournamentMemberId -> Punkte (1. Platz 100, 2. 99, …)
* @param {Array<{ position: number, id: number }>} rankings zu wertende Spieler; id = Turnier-Mitglied-ID
* @param {number} nInGroup Anzahl Teilnehmer in der Gruppe mit Platzierung > 0 (inkl. Externe)
* @returns {Map<number, number>} tournamentMemberId -> Prozent 0100 (Gleitkomma)
*/
export function groupPointsFromRankings(rankings) {
export function groupPercentFromRankings(rankings, nInGroup) {
const map = new Map();
if (!rankings || rankings.length === 0) return map;
const N = Number(nInGroup);
if (!rankings || rankings.length === 0 || !Number.isFinite(N) || N < 1) return map;
if (N === 1) {
for (const r of rankings) {
const id = r.id;
if (id == null) continue;
map.set(Number(id), 100);
}
return map;
}
for (const r of rankings) {
const pos = Number(r.position);
if (!Number.isFinite(pos) || pos < 1) continue;
const id = r.id;
if (id == null) continue;
const pts = Math.max(0, 101 - pos);
map.set(Number(id), pts);
const raw = ((N - pos) / (N - 1)) * 100;
const pct = Math.max(0, Math.min(100, raw));
map.set(Number(id), pct);
}
return map;
}
@@ -130,12 +144,15 @@ export function computeInternalSinglesStatsForTournament({
});
const groupPointsByTm = new Map();
let maxGroupPoints = 0;
let maxGroupPct = 0;
for (const g of classGroups) {
const parts = g.participants || [];
if (parts.length === 0) continue;
const nInGroup = parts.filter((p) => Number(p.position) > 0).length;
if (nInGroup < 1) continue;
const singlesRankings = parts
.filter((p) => !p.isExternal && p.id && tmToMemberId.has(Number(p.id)))
.map((p) => ({
@@ -144,10 +161,10 @@ export function computeInternalSinglesStatsForTournament({
}))
.filter((r) => r.position > 0);
const m = groupPointsFromRankings(singlesRankings);
const m = groupPercentFromRankings(singlesRankings, nInGroup);
for (const [tmId, pts] of m) {
groupPointsByTm.set(tmId, pts);
if (pts > maxGroupPoints) maxGroupPoints = pts;
if (pts > maxGroupPct) maxGroupPct = pts;
}
}
@@ -184,7 +201,7 @@ export function computeInternalSinglesStatsForTournament({
const inKo = playedKo.has(tmId);
let total;
if (inKo) {
total = maxGroupPoints + 1 + wins;
total = maxGroupPct + 1 + wins;
} else {
total = gPts;
}
@@ -199,7 +216,7 @@ export function computeInternalSinglesStatsForTournament({
}
export default {
groupPointsFromRankings,
groupPercentFromRankings,
computeInternalSinglesStatsForTournament,
parseWinnerFromMatch,
};

View File

@@ -3,13 +3,24 @@
:model-value="modelValue"
:title="$t('tournaments.internalStatsTitle')"
size="large"
:is-modal="false"
:position="dialogPosition"
:closable="true"
:close-on-overlay="true"
:close-on-overlay="false"
@update:model-value="$emit('update:modelValue', $event)"
@update:position="dialogPosition = $event"
@close="$emit('update:modelValue', false)"
>
<div class="internal-tournament-stats" v-if="clubId">
<div class="stats-toolbar">
<button
type="button"
class="pdf-button"
:disabled="pdfDisabled"
@click="exportPdf"
>
{{ $t('tournaments.internalStatsExportPdf') }}
</button>
<label class="period-label">
<span>{{ $t('tournaments.internalStatsPeriod') }}</span>
<select v-model="months" @change="load" :disabled="loading">
@@ -41,7 +52,7 @@
<tr v-for="(row, i) in stats.absoluteRanking" :key="'a-' + row.memberId">
<td class="col-rank">{{ i + 1 }}</td>
<td>{{ row.firstName }} {{ row.lastName }}</td>
<td>{{ row.totalPoints }}</td>
<td>{{ formatTotal(row.totalPoints) }}</td>
</tr>
</tbody>
</table>
@@ -74,6 +85,8 @@
<script>
import { mapState } from 'vuex';
import jsPDF from 'jspdf';
import autoTable from 'jspdf-autotable';
import apiClient from '../../apiClient.js';
import BaseDialog from '../BaseDialog.vue';
@@ -92,6 +105,7 @@ export default {
months: 12,
loading: false,
error: null,
dialogPosition: { x: 80, y: 80 },
stats: {
tournamentCount: 0,
absoluteRanking: [],
@@ -103,18 +117,162 @@ export default {
...mapState({
clubId: (state) => state.currentClub,
}),
pdfDisabled() {
return (
this.loading ||
!!this.error ||
(!this.stats.absoluteRanking?.length && !this.stats.averageRanking?.length)
);
},
},
watch: {
clubId() {
if (this.modelValue) this.load();
},
modelValue(open) {
if (open && this.clubId) {
this.load();
if (open) {
this.placeDialog();
if (this.clubId) this.load();
}
},
},
methods: {
placeDialog() {
if (typeof window === 'undefined') return;
const panelW = Math.min(900, window.innerWidth - 32);
this.dialogPosition = {
x: Math.max(16, Math.floor((window.innerWidth - panelW) / 2)),
y: Math.max(24, Math.floor(window.innerHeight * 0.08)),
};
},
periodLabel() {
const key =
this.months === 12
? 'internalStatsLast12Months'
: this.months === 6
? 'internalStatsLast6Months'
: 'internalStatsLast3Months';
return this.$t(`tournaments.${key}`);
},
exportPdf() {
const t = this.$t;
const margin = 14;
const pdf = new jsPDF('p', 'mm', 'a4');
const pageW = pdf.internal.pageSize.getWidth();
pdf.setFontSize(14);
pdf.setFont('helvetica', 'bold');
pdf.text(t('tournaments.internalStatsTitle'), margin, 18);
pdf.setFontSize(9);
pdf.setFont('helvetica', 'normal');
let y = 24;
pdf.text(`${t('tournaments.internalStatsPeriod')}: ${this.periodLabel()}`, margin, y);
y += 5;
pdf.text(
t('tournaments.internalStatsTournamentsInPeriod', {
count: this.stats.tournamentCount || 0,
}),
margin,
y,
);
y += 6;
const explain = t('tournaments.internalStatsPointsExplain');
const explainLines = pdf.splitTextToSize(explain, pageW - margin * 2);
pdf.setFontSize(8);
pdf.setTextColor(60);
pdf.text(explainLines, margin, y);
y += explainLines.length * 3.6 + 4;
pdf.setTextColor(0);
pdf.setFontSize(11);
pdf.setFont('helvetica', 'bold');
pdf.text(t('tournaments.internalStatsAbsoluteRank'), margin, y);
y += 6;
pdf.setFont('helvetica', 'normal');
pdf.setFontSize(9);
const absRows =
this.stats.absoluteRanking?.map((row, i) => [
String(i + 1),
`${row.firstName || ''} ${row.lastName || ''}`.trim(),
this.formatTotal(row.totalPoints),
]) || [];
autoTable(pdf, {
startY: y,
margin: { left: margin, right: margin },
head: [
[
'#',
t('tournaments.player'),
t('tournaments.internalStatsPoints'),
],
],
body: absRows.length ? absRows : [['', t('tournaments.internalStatsEmpty'), '']],
styles: { fontSize: 9, cellPadding: 2 },
headStyles: { fillColor: [55, 120, 180], textColor: 255, fontStyle: 'bold' },
theme: 'striped',
});
let nextY = pdf.lastAutoTable?.finalY != null ? pdf.lastAutoTable.finalY + 10 : y + 40;
pdf.setFontSize(11);
pdf.setFont('helvetica', 'bold');
pdf.text(t('tournaments.internalStatsAverageRank'), margin, nextY);
nextY += 6;
pdf.setFont('helvetica', 'normal');
pdf.setFontSize(9);
const avgRows =
this.stats.averageRanking?.map((row, i) => [
String(i + 1),
`${row.firstName || ''} ${row.lastName || ''}`.trim(),
this.formatAvg(row.averagePoints),
]) || [];
autoTable(pdf, {
startY: nextY,
margin: { left: margin, right: margin },
head: [
[
'#',
t('tournaments.player'),
t('tournaments.internalStatsAvgPoints'),
],
],
body: avgRows.length ? avgRows : [['', t('tournaments.internalStatsEmpty'), '']],
styles: { fontSize: 9, cellPadding: 2 },
headStyles: { fillColor: [55, 120, 180], textColor: 255, fontStyle: 'bold' },
theme: 'striped',
});
const ts = new Date();
const stamp = `${ts.getFullYear()}-${String(ts.getMonth() + 1).padStart(2, '0')}-${String(ts.getDate()).padStart(2, '0')}_${String(ts.getHours()).padStart(2, '0')}${String(ts.getMinutes()).padStart(2, '0')}`;
const pageCount = pdf.internal.getNumberOfPages();
for (let i = 1; i <= pageCount; i++) {
pdf.setPage(i);
pdf.setFontSize(8);
pdf.setTextColor(120);
pdf.text(
`${t('pdfGenerator.generatedAt')} ${ts.toLocaleString()}`,
margin,
pdf.internal.pageSize.getHeight() - 8,
);
pdf.setTextColor(0);
}
pdf.save(`turnier-statistik-einzel_${stamp}.pdf`);
},
formatTotal(v) {
if (v == null || Number.isNaN(Number(v))) return '';
const n = Number(v);
return n.toLocaleString(undefined, {
maximumFractionDigits: 2,
minimumFractionDigits: 0,
});
},
formatAvg(v) {
if (v == null || Number.isNaN(v)) return '';
return String(v);
@@ -153,6 +311,29 @@ export default {
margin-bottom: 0.5rem;
}
.pdf-button {
margin-right: auto;
background: #f3f4f6;
border: 1px solid #d1d5db;
border-radius: 6px;
padding: 0.4rem 0.75rem;
font-size: 0.9rem;
font-weight: 600;
color: #374151;
cursor: pointer;
transition: background 0.2s ease, border-color 0.2s ease;
}
.pdf-button:hover:not(:disabled) {
background: #e5e7eb;
border-color: #9ca3af;
}
.pdf-button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.period-label {
display: flex;
align-items: center;

View File

@@ -177,15 +177,16 @@
"tournaments": {
"internalStatsTitle": "Statistik interne Turniere (Einzel)",
"internalStatsOpenButton": "Turnierstatistik (Einzel)",
"internalStatsExportPdf": "Als PDF exportieren",
"internalStatsPeriod": "Ziitruum",
"internalStatsLast12Months": "Letscht 12 Mönet",
"internalStatsLast6Months": "Letscht 6 Mönet",
"internalStatsLast3Months": "Letscht 3 Mönet",
"internalStatsTournamentsInPeriod": "{count} Turnier(e) im Ziitruum (ohni Minimeisterschafte).",
"internalStatsPointsExplain": "Pünkt: Pro Gruppe 1. Platz = 100, 2. = 99, 3. = 98 usw.; gliichi Platzierig = gliichi Pünkt. Wer d K.-o.-Rundi erreicht, bechunnt di höchschte Gruppepünkt vo de Chlass plus 1, deno no 1 Punkt pro gwunne K.-o.-Spiel. Nur Veräinsmitglieder (Einzel).",
"internalStatsAbsoluteRank": "Rangliste Gsamtpünkt",
"internalStatsAverageRank": "Rangliste Durchschnitt (Pünkt pro Turnier)",
"internalStatsPoints": "Pünkt",
"internalStatsPointsExplain": "Wertig: Pro Gruppe wird d Platzierig als Prozentzahl usdrückt (bi N Teilnehmer mit Platzierig: 1. = 100 %, Letschte = 0 %, dzwüsche linear; gliichi Platzierig = gliiche Wert). N umfasst alli Platzierte ide Gruppe (inkl. Gäscht). Bi nume einem Teilnehmer: 100 %. Wer d K.-o.-Rundi erreicht, bechunnt de höchschte Gruppewert vo de Chlass plus 1, deno no 1 Punkt pro gwunne K.-o.-Spiel. Nur Veräinsmitglieder (Einzel).",
"internalStatsAbsoluteRank": "Rangliste Gsamtwertig",
"internalStatsAverageRank": "Rangliste Durchschnitt (pro Turnier)",
"internalStatsPoints": "Summe",
"internalStatsAvgPoints": "Ø",
"internalStatsEmpty": "Kei uswertbari Date im gwählte Ziitruum.",
"numberOfTables": "Aazahl Tisch",

View File

@@ -408,15 +408,16 @@
"tournaments": {
"internalStatsTitle": "Statistik interne Turniere (Einzel)",
"internalStatsOpenButton": "Turnierstatistik (Einzel)",
"internalStatsExportPdf": "Als PDF exportieren",
"internalStatsPeriod": "Zeitraum",
"internalStatsLast12Months": "Letzte 12 Monate",
"internalStatsLast6Months": "Letzte 6 Monate",
"internalStatsLast3Months": "Letzte 3 Monate",
"internalStatsTournamentsInPeriod": "{count} Turnier(e) im Zeitraum (ohne Minimeisterschaften).",
"internalStatsPointsExplain": "Punkte: Pro Gruppe gilt 1. Platz = 100, 2. = 99, 3. = 98 usw.; gleiche Platzierung = gleiche Punkte. Wer die K.-o.-Runde erreicht, erhält die höchsten Gruppenpunkte der Klasse plus 1, danach je weiteren gewonnenen K.-o.-Spiel einen Punkt. Nur Vereinsmitglieder (Einzel).",
"internalStatsAbsoluteRank": "Rangliste Gesamtpunkte",
"internalStatsAverageRank": "Rangliste Durchschnitt (Punkte pro Turnier)",
"internalStatsPoints": "Punkte",
"internalStatsPointsExplain": "Wertung: Pro Gruppe wird die Platzierung als Prozentzahl ausgedrückt (bei N Teilnehmern mit Platzierung: 1. = 100 %, Letzter = 0 %, dazwischen linear; gleiche Platzierung = gleicher Wert). N umfasst alle Platzierten in der Gruppe (inkl. Gäste). Bei nur einem Teilnehmer: 100 %. Wer die K.-o.-Runde erreicht, erhält den höchsten Gruppenwert der Klasse plus 1, danach je gewonnenes K.-o.-Spiel einen weiteren Punkt. Nur Vereinsmitglieder (Einzel).",
"internalStatsAbsoluteRank": "Rangliste Gesamtwertung",
"internalStatsAverageRank": "Rangliste Durchschnitt (pro Turnier)",
"internalStatsPoints": "Summe",
"internalStatsAvgPoints": "Ø",
"internalStatsEmpty": "Keine auswertbaren Daten im gewählten Zeitraum.",
"title": "Turniere",

View File

@@ -700,15 +700,16 @@
"internalTournaments": "Interne Turniere",
"internalStatsTitle": "Statistik interne Turniere (Einzel)",
"internalStatsOpenButton": "Turnierstatistik (Einzel)",
"internalStatsExportPdf": "Als PDF exportieren",
"internalStatsPeriod": "Zeitraum",
"internalStatsLast12Months": "Letzte 12 Monate",
"internalStatsLast6Months": "Letzte 6 Monate",
"internalStatsLast3Months": "Letzte 3 Monate",
"internalStatsTournamentsInPeriod": "{count} Turnier(e) im Zeitraum (ohne Minimeisterschaften).",
"internalStatsPointsExplain": "Punkte: Pro Gruppe gilt 1. Platz = 100, 2. = 99, 3. = 98 usw.; gleiche Platzierung = gleiche Punkte. Wer die K.-o.-Runde erreicht, erhält die höchsten Gruppenpunkte der Klasse plus 1, danach je weiteren gewonnenen K.-o.-Spiel einen Punkt. Nur Vereinsmitglieder (Einzel).",
"internalStatsAbsoluteRank": "Rangliste Gesamtpunkte",
"internalStatsAverageRank": "Rangliste Durchschnitt (Punkte pro Turnier)",
"internalStatsPoints": "Punkte",
"internalStatsPointsExplain": "Wertung: Pro Gruppe wird die Platzierung als Prozentzahl ausgedrückt (bei N Teilnehmern mit Platzierung: 1. = 100 %, Letzter = 0 %, dazwischen linear; gleiche Platzierung = gleicher Wert). N umfasst alle Platzierten in der Gruppe (inkl. Gäste). Bei nur einem Teilnehmer: 100 %. Wer die K.-o.-Runde erreicht, erhält den höchsten Gruppenwert der Klasse plus 1, danach je gewonnenes K.-o.-Spiel einen weiteren Punkt. Nur Vereinsmitglieder (Einzel).",
"internalStatsAbsoluteRank": "Rangliste Gesamtwertung",
"internalStatsAverageRank": "Rangliste Durchschnitt (pro Turnier)",
"internalStatsPoints": "Summe",
"internalStatsAvgPoints": "Ø",
"internalStatsEmpty": "Keine auswertbaren Daten im gewählten Zeitraum.",
"openTournaments": "Offene Turniere",

View File

@@ -177,15 +177,16 @@
"tournaments": {
"internalStatsTitle": "Internal tournaments statistics (singles)",
"internalStatsOpenButton": "Tournament statistics (singles)",
"internalStatsExportPdf": "Export as PDF",
"internalStatsPeriod": "Period",
"internalStatsLast12Months": "Last 12 months",
"internalStatsLast6Months": "Last 6 months",
"internalStatsLast3Months": "Last 3 months",
"internalStatsTournamentsInPeriod": "{count} tournament(s) in this period (excluding mini championships).",
"internalStatsPointsExplain": "Points: Per group, 1st place = 100, 2nd = 99, 3rd = 98, and so on; tied ranks share the same score. Players who reach the knockout stage get the highest group score in that class plus 1, then one point per knockout match won. Club members in singles classes only.",
"internalStatsAbsoluteRank": "Total points ranking",
"internalStatsAverageRank": "Average points per tournament",
"internalStatsPoints": "Points",
"internalStatsPointsExplain": "Scoring: In each group, placement is expressed as a percentage (with N ranked players: 1st = 100%, last = 0%, linear in between; tied ranks share the same value). N counts everyone ranked in that group (including guests). With only one player: 100%. Players who reach the knockout get the highest group score in that class plus 1, then one extra point per knockout match won. Club members in singles classes only.",
"internalStatsAbsoluteRank": "Total score ranking",
"internalStatsAverageRank": "Average per tournament",
"internalStatsPoints": "Total",
"internalStatsAvgPoints": "Avg.",
"internalStatsEmpty": "No data for the selected period.",
"numberOfTables": "Number of tables",

View File

@@ -358,15 +358,16 @@
"tournaments": {
"internalStatsTitle": "Internal tournaments statistics (singles)",
"internalStatsOpenButton": "Tournament statistics (singles)",
"internalStatsExportPdf": "Export as PDF",
"internalStatsPeriod": "Period",
"internalStatsLast12Months": "Last 12 months",
"internalStatsLast6Months": "Last 6 months",
"internalStatsLast3Months": "Last 3 months",
"internalStatsTournamentsInPeriod": "{count} tournament(s) in this period (excluding mini championships).",
"internalStatsPointsExplain": "Points: Per group, 1st place = 100, 2nd = 99, 3rd = 98, and so on; tied ranks share the same score. Players who reach the knockout stage get the highest group score in that class plus 1, then one point per knockout match won. Club members in singles classes only.",
"internalStatsAbsoluteRank": "Total points ranking",
"internalStatsAverageRank": "Average points per tournament",
"internalStatsPoints": "Points",
"internalStatsPointsExplain": "Scoring: In each group, placement is expressed as a percentage (with N ranked players: 1st = 100%, last = 0%, linear in between; tied ranks share the same value). N counts everyone ranked in that group (including guests). With only one player: 100%. Players who reach the knockout get the highest group score in that class plus 1, then one extra point per knockout match won. Club members in singles classes only.",
"internalStatsAbsoluteRank": "Total score ranking",
"internalStatsAverageRank": "Average per tournament",
"internalStatsPoints": "Total",
"internalStatsAvgPoints": "Avg.",
"internalStatsEmpty": "No data for the selected period.",
"numberOfTables": "Number of tables",

View File

@@ -177,15 +177,16 @@
"tournaments": {
"internalStatsTitle": "Internal tournaments statistics (singles)",
"internalStatsOpenButton": "Tournament statistics (singles)",
"internalStatsExportPdf": "Export as PDF",
"internalStatsPeriod": "Period",
"internalStatsLast12Months": "Last 12 months",
"internalStatsLast6Months": "Last 6 months",
"internalStatsLast3Months": "Last 3 months",
"internalStatsTournamentsInPeriod": "{count} tournament(s) in this period (excluding mini championships).",
"internalStatsPointsExplain": "Points: Per group, 1st place = 100, 2nd = 99, 3rd = 98, and so on; tied ranks share the same score. Players who reach the knockout stage get the highest group score in that class plus 1, then one point per knockout match won. Club members in singles classes only.",
"internalStatsAbsoluteRank": "Total points ranking",
"internalStatsAverageRank": "Average points per tournament",
"internalStatsPoints": "Points",
"internalStatsPointsExplain": "Scoring: In each group, placement is expressed as a percentage (with N ranked players: 1st = 100%, last = 0%, linear in between; tied ranks share the same value). N counts everyone ranked in that group (including guests). With only one player: 100%. Players who reach the knockout get the highest group score in that class plus 1, then one extra point per knockout match won. Club members in singles classes only.",
"internalStatsAbsoluteRank": "Total score ranking",
"internalStatsAverageRank": "Average per tournament",
"internalStatsPoints": "Total",
"internalStatsAvgPoints": "Avg.",
"internalStatsEmpty": "No data for the selected period.",
"numberOfTables": "Number of tables",

View File

@@ -176,15 +176,16 @@
"tournaments": {
"internalStatsTitle": "Estadísticas de torneos internos (individual)",
"internalStatsOpenButton": "Estadísticas de torneos (individual)",
"internalStatsExportPdf": "Exportar como PDF",
"internalStatsPeriod": "Periodo",
"internalStatsLast12Months": "Últimos 12 meses",
"internalStatsLast6Months": "Últimos 6 meses",
"internalStatsLast3Months": "Últimos 3 meses",
"internalStatsTournamentsInPeriod": "{count} torneo(s) en el periodo (sin minicampeonatos).",
"internalStatsPointsExplain": "Puntos: por grupo, 1.º = 100, 2.º = 99, 3.º = 98, etc.; empate = mismos puntos. En KO: máximo de grupo de la clase + 1, más 1 por partido KO ganado. Solo socios en individual.",
"internalStatsAbsoluteRank": "Clasificación por puntos totales",
"internalStatsAverageRank": "Clasificación por media (puntos por torneo)",
"internalStatsPoints": "Puntos",
"internalStatsPointsExplain": "Puntuación: en cada grupo la posición se expresa en porcentaje (con N clasificados: 1.º = 100 %, último = 0 %, lineal entre medias; empates = mismo valor). N cuenta a todos los clasificados del grupo (invitados incluidos). Con un solo jugador: 100 %. En KO: máximo de grupo de la clase + 1, más 1 por partido KO ganado. Solo socios en individual.",
"internalStatsAbsoluteRank": "Clasificación por suma",
"internalStatsAverageRank": "Clasificación por media (por torneo)",
"internalStatsPoints": "Total",
"internalStatsAvgPoints": "Media",
"internalStatsEmpty": "No hay datos para el periodo seleccionado.",
"numberOfTables": "Número de mesas",

View File

@@ -176,15 +176,16 @@
"tournaments": {
"internalStatsTitle": "Estadistika ng internal na paligsahan (singles)",
"internalStatsOpenButton": "Buksan ang estadistika (singles)",
"internalStatsExportPdf": "I-export bilang PDF",
"internalStatsPeriod": "Saklaw",
"internalStatsLast12Months": "Huling 12 buwan",
"internalStatsLast6Months": "Huling 6 na buwan",
"internalStatsLast3Months": "Huling 3 buwan",
"internalStatsTournamentsInPeriod": "{count} paligsahan sa panahon (hindi kasama ang mini championships).",
"internalStatsPointsExplain": "Puntos: kada grupo, 1 = 100, 2 = 99, 3 = 98, atbp.; parehong ranggo = parehong puntos. Sa KO: pinakamataas na grupo ng klase + 1, +1 bawat panalong laro sa KO. Mga miyembro lamang (singles).",
"internalStatsAbsoluteRank": "Ranggo sa kabuuang puntos",
"internalStatsAverageRank": "Ranggo sa average (puntos bawat paligsahan)",
"internalStatsPoints": "Puntos",
"internalStatsPointsExplain": "Marka: sa bawat grupo ang puwesto ay nasa porsyento (may N na may ranggo: 1 = 100%, huli = 0%, linear sa gitna; parehong ranggo = parehong halaga). Kinakabilang ang lahat ng may ranggo sa grupo (kasama ang bisita). Isang manlalaro lamang: 100%. Sa KO: pinakamataas na grupo ng klase + 1, +1 bawat panalong laro sa KO. Mga miyembro lamang (singles).",
"internalStatsAbsoluteRank": "Ranggo sa kabuuang marka",
"internalStatsAverageRank": "Ranggo sa average (bawat paligsahan)",
"internalStatsPoints": "Kabuuan",
"internalStatsAvgPoints": "Avg.",
"internalStatsEmpty": "Walang datos sa napiling panahon.",
"numberOfTables": "Bilang ng mesa",

View File

@@ -176,15 +176,16 @@
"tournaments": {
"internalStatsTitle": "Statistiques des tournois internes (simple)",
"internalStatsOpenButton": "Statistiques (simple)",
"internalStatsExportPdf": "Exporter en PDF",
"internalStatsPeriod": "Période",
"internalStatsLast12Months": "12 derniers mois",
"internalStatsLast6Months": "6 derniers mois",
"internalStatsLast3Months": "3 derniers mois",
"internalStatsTournamentsInPeriod": "{count} tournoi(s) sur la période (hors mini-championnats).",
"internalStatsPointsExplain": "Points : par poule, 1er = 100, 2e = 99, 3e = 98, etc. ; ex æquo = même score. En KO : meilleur score de poule de la catégorie + 1, puis +1 par match KO gagné. Membres du club en simple uniquement.",
"internalStatsAbsoluteRank": "Classement des points totaux",
"internalStatsAverageRank": "Classement par moyenne (points par tournoi)",
"internalStatsPoints": "Points",
"internalStatsPointsExplain": "Barème : dans chaque poule, le classement est exprimé en pourcentage (avec N classés : 1er = 100 %, dernier = 0 %, linéaire entre les deux ; ex æquo = même valeur). N compte tous les classés de la poule (invités inclus). Un seul joueur : 100 %. En KO : meilleur score de poule de la catégorie + 1, puis +1 par match KO gagné. Membres du club en simple uniquement.",
"internalStatsAbsoluteRank": "Classement du total",
"internalStatsAverageRank": "Classement de la moyenne (par tournoi)",
"internalStatsPoints": "Total",
"internalStatsAvgPoints": "Moy.",
"internalStatsEmpty": "Aucune donnée pour la période choisie.",
"numberOfTables": "Nombre de tables",

View File

@@ -176,15 +176,16 @@
"tournaments": {
"internalStatsTitle": "Statistiche tornei interni (singolo)",
"internalStatsOpenButton": "Statistiche tornei (singolo)",
"internalStatsExportPdf": "Esporta PDF",
"internalStatsPeriod": "Periodo",
"internalStatsLast12Months": "Ultimi 12 mesi",
"internalStatsLast6Months": "Ultimi 6 mesi",
"internalStatsLast3Months": "Ultimi 3 mesi",
"internalStatsTournamentsInPeriod": "{count} torneo/i nel periodo (esclusi i mini-campionati).",
"internalStatsPointsExplain": "Punti: per girone, 1° = 100, 2° = 99, 3° = 98, ecc.; stesso posto = stessi punti. In KO: massimo girone della classe + 1, poi +1 per partita KO vinta. Solo soci al singolo.",
"internalStatsAbsoluteRank": "Classifica punti totali",
"internalStatsAverageRank": "Classifica media (punti per torneo)",
"internalStatsPoints": "Punti",
"internalStatsPointsExplain": "Punteggio: in ogni girone la posizione è in percentuale (con N classificati: 1° = 100 %, ultimo = 0 %, lineare in mezzo; stesso posto = stesso valore). N include tutti i classificati nel girone (ospiti inclusi). Un solo giocatore: 100 %. In KO: massimo girone della classe + 1, poi +1 per partita KO vinta. Solo soci al singolo.",
"internalStatsAbsoluteRank": "Classifica somma",
"internalStatsAverageRank": "Classifica media (per torneo)",
"internalStatsPoints": "Totale",
"internalStatsAvgPoints": "Media",
"internalStatsEmpty": "Nessun dato nel periodo selezionato.",
"numberOfTables": "Numero di tavoli",

View File

@@ -176,15 +176,16 @@
"tournaments": {
"internalStatsTitle": "内部大会の統計(シングルス)",
"internalStatsOpenButton": "統計を表示(シングルス)",
"internalStatsExportPdf": "PDFで出力",
"internalStatsPeriod": "期間",
"internalStatsLast12Months": "過去12か月",
"internalStatsLast6Months": "過去6か月",
"internalStatsLast3Months": "過去3か月",
"internalStatsTournamentsInPeriod": "期間内の大会 {count} 件(ミニ選手権は除く)。",
"internalStatsPointsExplain": "得点各グループで1位100点、2位99点、3位98点…同順位は同点。KO進出者はクラス内最高のグループ得点1、KO勝利ごとに1。クラブ会員シングルのみ。",
"internalStatsAbsoluteRank": "総得点ランキング",
"internalStatsAverageRank": "平均得点ランキング(大会あたり)",
"internalStatsPoints": "得点",
"internalStatsPointsExplain": "計算:各グループでは順位をパーセントで表します順位付きN人1位100%、最下位0%、その間は線形同順位は同値。Nはグループ内の順位付き全員ゲスト含む。1人のみの場合は100%。KO進出者はクラス内最高のグループ1、KO勝利ごとに1。クラブ会員シングルのみ。",
"internalStatsAbsoluteRank": "合計ランキング",
"internalStatsAverageRank": "平均ランキング(大会あたり)",
"internalStatsPoints": "合計",
"internalStatsAvgPoints": "平均",
"internalStatsEmpty": "選択した期間にデータがありません。",
"numberOfTables": "卓数",

View File

@@ -176,15 +176,16 @@
"tournaments": {
"internalStatsTitle": "Statystyki turniejów wewnętrznych (singel)",
"internalStatsOpenButton": "Statystyki turniejów (singel)",
"internalStatsExportPdf": "Eksportuj do PDF",
"internalStatsPeriod": "Okres",
"internalStatsLast12Months": "Ostatnie 12 miesięcy",
"internalStatsLast6Months": "Ostatnie 6 miesięcy",
"internalStatsLast3Months": "Ostatnie 3 miesiące",
"internalStatsTournamentsInPeriod": "{count} turniej(ów) w okresie (bez mini-mistrzostw).",
"internalStatsPointsExplain": "Punkty: w grupie miejsce 1 = 100, 2 = 99, 3 = 98 itd.; remis = te same punkty. W KO: maks. punktów grupowych klasy + 1, potem +1 za wygrany mecz KO. Tylko członkowie klubu, singel.",
"internalStatsAbsoluteRank": "Ranking sumy punktów",
"internalStatsAverageRank": "Ranking średniej (punkty na turniej)",
"internalStatsPoints": "Punkty",
"internalStatsPointsExplain": "Punktacja: w każdej grupie miejsce jest wyrażone w procentach (przy N sklasyfikowanych: 1. = 100%, ostatni = 0%, liniowo pomiędzy; remis = ten sam wynik). N liczy wszystkich z miejscem w grupie (goście włączenie). Przy jednym zawodniku: 100%. W KO: maks. wynik grupowy klasy + 1, potem +1 za wygrany mecz KO. Tylko członkowie klubu, singel.",
"internalStatsAbsoluteRank": "Ranking sumy",
"internalStatsAverageRank": "Ranking średniej (na turniej)",
"internalStatsPoints": "Suma",
"internalStatsAvgPoints": "Śr.",
"internalStatsEmpty": "Brak danych w wybranym okresie.",
"numberOfTables": "Liczba stołów",

View File

@@ -176,15 +176,16 @@
"tournaments": {
"internalStatsTitle": "สถิติการแข่งขันภายใน (เดี่ยว)",
"internalStatsOpenButton": "เปิดสถิติ (เดี่ยว)",
"internalStatsExportPdf": "ส่งออก PDF",
"internalStatsPeriod": "ช่วงเวลา",
"internalStatsLast12Months": "12 เดือนล่าสุด",
"internalStatsLast6Months": "6 เดือนล่าสุด",
"internalStatsLast3Months": "3 เดือนล่าสุด",
"internalStatsTournamentsInPeriod": "{count} การแข่งขันในช่วงเวลา (ไม่รวมมินิแชมเปียนชิป)",
"internalStatsPointsExplain": "คะแนน: ต่อกลุ่ม อันดับ 1 = 100, 2 = 99, 3 = 98 … อันดับเดียวกันได้คะแนนเท่ากัน รอบ KO: คะแนนกลุ่มสูงสุดของคลาส +1 แล้ว +1 ต่อชนะแมตช์ KO เฉพาะสมาชิก เดี่ยว",
"internalStatsAbsoluteRank": "อันดับคะแนนรวม",
"internalStatsAverageRank": "อันดับค่าเฉลี่ย (คะแนนต่อการแข่งขัน)",
"internalStatsPoints": "คะแนน",
"internalStatsPointsExplain": "การให้คะแนน: ในแต่ละกลุ่มใช้เปอร์เซ็นต์ตามอันดับ (มี N คนที่มีอันดับ: ที่ 1 = 100% คนสุดท้าย = 0% ระหว่างกลางเชิงเส้น; อันดับเดียวกันค่าเดียวกัน) N นับทุกคนที่มีอันดับในกลุ่ม (รวมแขก) มีผู้เล่นเพียงคนเดียว = 100% รอบ KO: ค่ากลุ่มสูงสุดของคลาส +1 แล้ว +1 ต่อชนะแมตช์ KO เฉพาะสมาชิก เดี่ยว",
"internalStatsAbsoluteRank": "อันดับผลรวม",
"internalStatsAverageRank": "อันดับเฉลี่ย (ต่อการแข่งขัน)",
"internalStatsPoints": "รวม",
"internalStatsAvgPoints": "เฉลี่ย",
"internalStatsEmpty": "ไม่มีข้อมูลในช่วงเวลาที่เลือก",
"numberOfTables": "จำนวนโต๊ะ",

View File

@@ -176,15 +176,16 @@
"tournaments": {
"internalStatsTitle": "Istatistika ng internal na tournament (singles)",
"internalStatsOpenButton": "Buksan ang istatistika (singles)",
"internalStatsExportPdf": "I-export bilang PDF",
"internalStatsPeriod": "Saklaw",
"internalStatsLast12Months": "Huling 12 buwan",
"internalStatsLast6Months": "Huling 6 na buwan",
"internalStatsLast3Months": "Huling 3 buwan",
"internalStatsTournamentsInPeriod": "{count} tournament sa panahon (hindi kasama ang mini championships).",
"internalStatsPointsExplain": "Puntos: bawat grupo, 1 = 100, 2 = 99, 3 = 98, atbp.; parehong ranggo = parehong puntos. Sa KO: pinakamataas na grupo ng klase + 1, +1 bawat panalong laro sa KO. Mga miyembro lamang (singles).",
"internalStatsAbsoluteRank": "Ranggo sa kabuuang puntos",
"internalStatsAverageRank": "Ranggo sa average (puntos bawat tournament)",
"internalStatsPoints": "Puntos",
"internalStatsPointsExplain": "Marka: sa bawat grupo ang puwesto ay nasa porsyento (may N na may ranggo: 1 = 100%, huli = 0%, linear sa gitna; parehong ranggo = parehong halaga). Kinakabilang ang lahat ng may ranggo sa grupo (kasama ang bisita). Isang manlalaro lamang: 100%. Sa KO: pinakamataas na grupo ng klase + 1, +1 bawat panalong laro sa KO. Mga miyembro lamang (singles).",
"internalStatsAbsoluteRank": "Ranggo sa kabuuang marka",
"internalStatsAverageRank": "Ranggo sa average (bawat tournament)",
"internalStatsPoints": "Kabuuan",
"internalStatsAvgPoints": "Avg.",
"internalStatsEmpty": "Walang datos sa napiling panahon.",
"numberOfTables": "Bilang ng mesa",

View File

@@ -176,15 +176,16 @@
"tournaments": {
"internalStatsTitle": "内部锦标赛统计(单打)",
"internalStatsOpenButton": "打开单打统计数据",
"internalStatsExportPdf": "导出 PDF",
"internalStatsPeriod": "时间范围",
"internalStatsLast12Months": "过去 12 个月",
"internalStatsLast6Months": "过去 6 个月",
"internalStatsLast3Months": "过去 3 个月",
"internalStatsTournamentsInPeriod": "该期间共 {count} 场锦标赛(不含迷你锦标赛)。",
"internalStatsPointsExplain": "计分:每组第 1 名 100 分,第 2 名 99 分,第 3 名 98 分,以此类推;相同名次得分相同。进入淘汰赛的选手获得该级别最高小组赛分数加 1之后每赢一场淘汰赛再加 1。仅统计俱乐部成员单打。",
"internalStatsAbsoluteRank": "总积分榜",
"internalStatsAverageRank": "平均分榜(每场锦标赛)",
"internalStatsPoints": "分数",
"internalStatsPointsExplain": "计分:每组用百分比表示名次(有 N 人排名:第 1 名 100%,最后一名 0%中间线性同名次同分。N 为该组所有有排名者(含嘉宾)。仅 1 人时记 100%。进入淘汰赛获得该级别最高小组加 1之后每赢一场淘汰赛再加 1。仅统计俱乐部成员单打。",
"internalStatsAbsoluteRank": "总分排名",
"internalStatsAverageRank": "平均排名(每场锦标赛)",
"internalStatsPoints": "合计",
"internalStatsAvgPoints": "平均",
"internalStatsEmpty": "所选期间没有可统计的数据。",
"numberOfTables": "球台数量",