;
+
+export const loader = async ({ params, url }: LoaderFunctionArgs) => {
+ const loggedInUser = requireUser();
+ const { identifier } = userParamsSchema.parse(params);
+ const parsedSearchParams = seasonSummaryGraphicSearchParamsSchema.safeParse(
+ Object.fromEntries(url.searchParams),
+ );
+ if (!parsedSearchParams.success) {
+ throw new Response(null, { status: 400 });
+ }
+ const { season } = parsedSearchParams.data;
+
+ const user = notFoundIfNullish(
+ await UserRepository.findIdByIdentifier(identifier),
+ );
+ const seasonsParticipatedIn =
+ await LeaderboardRepository.findSeasonsParticipatedInByUserId(user.id);
+ const skill = (await userSkills(season)).userSkills[user.id];
+
+ if (
+ !skill ||
+ skill.approximate ||
+ !SeasonSummary.canExportSeasonSummary({
+ loggedInUser,
+ profileUserId: user.id,
+ season,
+ seasonsParticipatedIn,
+ hasCalculatedSkill: true,
+ })
+ ) {
+ throw forbidden();
+ }
+
+ const setScores = await PlayerStatRepository.findSeasonSetScoresByUserId({
+ userId: user.id,
+ season,
+ });
+ const setWinrate = await PlayerStatRepository.findSeasonSetWinrateByUserId({
+ userId: user.id,
+ season,
+ });
+ const mapWinrate = await PlayerStatRepository.findSeasonMapWinrateByUserId({
+ userId: user.id,
+ season,
+ });
+
+ const soloRank = (
+ await LeaderboardRepository.findUserSPLeaderboard(season)
+ ).find((entry) => entry.id === user.id)?.placementRank;
+ const teamEntry = await findTeamEntry({ season, userId: user.id });
+
+ const mates = await PlayerStatRepository.findSeasonMatesEnemiesByUserId({
+ userId: user.id,
+ season,
+ type: "MATE",
+ });
+ const topMates = mates
+ .toSorted((a, b) => b.setWins + b.setLosses - (a.setWins + a.setLosses))
+ .slice(0, TOP_MATES_COUNT);
+
+ const countries = await UserRepository.findCountriesByUserIds([
+ ...(teamEntry?.entry.members.map((member) => member.id) ?? []),
+ ...topMates.map((mate) => mate.user.id),
+ ]);
+
+ const bestSets = await PlayerStatRepository.findSeasonBestSetsByUserId({
+ userId: user.id,
+ season,
+ limit: BEST_SETS_COUNT,
+ });
+ const bestRun = SeasonSummary.bestTournamentRun(
+ (
+ await PlayerStatRepository.findSeasonTournamentRunsByUserId({
+ userId: user.id,
+ season,
+ })
+ ).map((run) => ({
+ ...run,
+ topEightAvgSp:
+ typeof run.topEightAvgOrdinal === "number"
+ ? ordinalToSp(run.topEightAvgOrdinal)
+ : null,
+ })),
+ );
+
+ return {
+ season,
+ tier: skill.tier,
+ sp: ordinalToSp(skill.ordinal),
+ setsWon: setWinrate.wins,
+ setsLost: setWinrate.losses,
+ mapsWon: mapWinrate.wins,
+ mapsLost: mapWinrate.losses,
+ longestWinStreak: SeasonSummary.longestWinStreak(setScores),
+ clutch: SeasonSummary.clutchRecord(setScores),
+ soloRank,
+ teamRank: teamEntry
+ ? {
+ rank: teamEntry.rank,
+ sp: teamEntry.entry.power,
+ mates: teamEntry.entry.members
+ .filter((member) => member.id !== user.id)
+ .map((member) => ({
+ name: member.username,
+ countryCode: countries.get(member.id),
+ })),
+ team: teamEntry.entry.team
+ ? {
+ name: teamEntry.entry.team.name,
+ logoUrl: teamEntry.entry.team.avatarUrl ?? undefined,
+ }
+ : undefined,
+ }
+ : undefined,
+ topMates: topMates.map((mate) => ({
+ player: {
+ name: mate.user.username,
+ countryCode: countries.get(mate.user.id),
+ },
+ discordId: mate.user.discordId,
+ avatarUrl: resolveAvatarUrl({
+ customAvatarUrl: mate.user.customAvatarUrl,
+ discordId: mate.user.discordId,
+ discordAvatar: mate.user.discordAvatar,
+ size: "sm",
+ }),
+ setsCount: mate.setWins + mate.setLosses,
+ })),
+ bestStage: SeasonSummary.bestStage(
+ await PlayerStatRepository.findSeasonStagesByUserId({
+ userId: user.id,
+ season,
+ }),
+ ),
+ spProgression: (
+ await SkillRepository.findSeasonProgressionByUserId({
+ userId: user.id,
+ season,
+ })
+ ).map((point) => ({ date: point.date, sp: ordinalToSp(point.ordinal) })),
+ activeDays: await SkillRepository.findSeasonActiveDaysByUserId({
+ userId: user.id,
+ season,
+ }),
+ bestSets: bestSets.map((set) => ({
+ opponentPlayers: set.opponentPlayers.map((player) => ({
+ name: player.username,
+ countryCode: player.country ?? undefined,
+ })),
+ ownScore: set.ownScore,
+ opponentScore: set.opponentScore,
+ opponentSp: ordinalToSp(set.avgOpponentOrdinal),
+ context: set.tournamentName ?? "SendouQ",
+ })),
+ bestTournament: bestRun
+ ? {
+ name: bestRun.name,
+ logoUrl: bestRun.logoUrl,
+ tier: bestRun.tier ?? undefined,
+ placement: bestRun.placement,
+ teamsCount: bestRun.teamsCount,
+ }
+ : undefined,
+ topWeapons: SeasonSummary.topWeaponUsages(
+ await ReportedWeaponRepository.findSeasonReportedWeaponsByUserId({
+ userId: user.id,
+ season,
+ }),
+ ),
+ };
+};
+
+async function findTeamEntry({
+ season,
+ userId,
+}: {
+ season: number;
+ userId: number;
+}) {
+ const hasUser = (entry: { members: Array<{ id: number }> }) =>
+ entry.members.some((member) => member.id === userId);
+
+ const rankedEntry = (
+ await LeaderboardRepository.findTeamLeaderboardBySeason({
+ season,
+ onlyOneEntryPerUser: true,
+ })
+ ).find(hasUser);
+
+ if (rankedEntry)
+ return { entry: rankedEntry, rank: rankedEntry.placementRank };
+
+ // rosters that only show up on the "all entries" leaderboard have no
+ // placement comparable to the one shown on the main team leaderboard
+ const unrankedEntry = (
+ await LeaderboardRepository.findTeamLeaderboardBySeason({
+ season,
+ onlyOneEntryPerUser: false,
+ })
+ ).find(hasUser);
+
+ if (!unrankedEntry) return undefined;
+
+ return { entry: unrankedEntry, rank: undefined };
+}
diff --git a/app/features/user-page/routes/u.$identifier.builds.tsx b/app/features/user-page/routes/u.$identifier.builds.tsx
index 172738c70..4cbbb115e 100644
--- a/app/features/user-page/routes/u.$identifier.builds.tsx
+++ b/app/features/user-page/routes/u.$identifier.builds.tsx
@@ -34,7 +34,7 @@ import userStyles from "../user-page.module.css";
import styles from "./u.$identifier.builds.module.css";
export const handle: SendouRouteHandle = {
- i18n: ["weapons", "builds", "gear"],
+ i18n: ["weapons", "builds", "gear", "analyzer"],
};
type BuildFilter = "ALL" | "PUBLIC" | "PRIVATE" | MainWeaponId;
@@ -103,7 +103,13 @@ export default function UserBuildsPage() {
{builds.length > 0 ? (
{builds.map((build) => (
-
+
))}
) : (
diff --git a/app/features/user-page/routes/u.$identifier.index.tsx b/app/features/user-page/routes/u.$identifier.index.tsx
index 05152cc4d..59c7bc6ae 100644
--- a/app/features/user-page/routes/u.$identifier.index.tsx
+++ b/app/features/user-page/routes/u.$identifier.index.tsx
@@ -57,6 +57,7 @@ export const handle: SendouRouteHandle = {
"weapons",
"gear",
"game-badges",
+ "analyzer",
"trophies",
],
};
diff --git a/app/features/user-page/routes/u.$identifier.seasons.summary-graphic.ts b/app/features/user-page/routes/u.$identifier.seasons.summary-graphic.ts
new file mode 100644
index 000000000..9ffb02002
--- /dev/null
+++ b/app/features/user-page/routes/u.$identifier.seasons.summary-graphic.ts
@@ -0,0 +1 @@
+export { loader } from "../loaders/u.$identifier.seasons.summary-graphic.server";
diff --git a/app/features/user-page/routes/u.$identifier.seasons.tsx b/app/features/user-page/routes/u.$identifier.seasons.tsx
index 468156067..87609108d 100644
--- a/app/features/user-page/routes/u.$identifier.seasons.tsx
+++ b/app/features/user-page/routes/u.$identifier.seasons.tsx
@@ -1,10 +1,12 @@
import clsx from "clsx";
+import { HardDriveDownload } from "lucide-react";
import * as React from "react";
import { useTranslation } from "react-i18next";
import {
Link,
Outlet,
type ShouldRevalidateFunction,
+ useFetcher,
useLoaderData,
useLocation,
useMatches,
@@ -29,6 +31,10 @@ import { TierImage } from "~/components/Image";
import { LocaleTime } from "~/components/LocaleTime";
import { LocaleTimeRange } from "~/components/LocaleTimeRange";
import { mainStyles } from "~/components/Main";
+import { useUser } from "~/features/auth/core/user";
+import { ImageExportDialog } from "~/features/img-export/components/ImageExportDialog";
+import { SeasonSummaryGraphic } from "~/features/img-export/components/SeasonSummaryGraphic";
+import * as SeasonSummary from "~/features/img-export/core/SeasonSummary";
import { TopTenPlayer } from "~/features/leaderboards/components/TopTenPlayer";
import { playerTopTenPlacement } from "~/features/leaderboards/leaderboards-utils";
import * as Seasons from "~/features/mmr/core/Seasons";
@@ -37,9 +43,11 @@ import invariant from "~/utils/invariant";
import { isRevalidation } from "~/utils/remix";
import type { SendouRouteHandle } from "~/utils/remix.server";
import {
+ resolveAvatarUrl,
sendouQMatchPage,
TIERS_PAGE,
userPage,
+ userSeasonSummaryGraphicPage,
userSeasonsPage,
userSeasonsStatsPage,
} from "~/utils/urls";
@@ -48,13 +56,14 @@ import {
loader,
type UserSeasonsPageLoaderData,
} from "../loaders/u.$identifier.seasons.server";
+import type { UserSeasonSummaryGraphicLoaderData } from "../loaders/u.$identifier.seasons.summary-graphic.server";
import type { UserPageLoaderData } from "../loaders/u.$identifier.server";
import styles from "../user-page.module.css";
export { loader };
export const handle: SendouRouteHandle = {
- i18n: ["user"],
+ i18n: ["user", "calendar"],
};
export const shouldRevalidate: ShouldRevalidateFunction = (args) => {
@@ -103,10 +112,18 @@ export default function UserSeasonsLayout() {
user={layoutData.user}
backTo={userPage(layoutData.user)}
/>
-
+
+
+
+
{data.currentOrdinal ? (
}
+ >
+ {t("user:seasons.summary.export")}
+
+ }
+ >
+ {t("user:seasons.summary.export.supporterPerk")}
+
+ );
+ }
+
+ return (
+
+ );
+}
+
+function SeasonSummaryExportDialog({
+ profileUser,
+ season,
+}: {
+ profileUser: UserPageLoaderData["user"];
+ season: number;
+}) {
+ const { t } = useTranslation(["user"]);
+ const fetcher = useFetcher();
+
+ const handleOpen = () => {
+ if (fetcher.state === "idle" && !fetcher.data) {
+ fetcher.load(userSeasonSummaryGraphicPage({ user: profileUser, season }));
+ }
+ };
+
+ const data = fetcher.data;
+
+ return (
+ }
+ onPress={handleOpen}
+ >
+ {t("user:seasons.summary.export")}
+
+ }
+ heading={t("user:seasons.summary.export")}
+ filename={`season-${season}-summary`}
+ qrCodePath={userSeasonsPage({ user: profileUser, season })}
+ >
+ {data ? (
+
+ ) : null}
+
+ );
+}
+
function SeasonHeader({
seasonViewed,
seasonsParticipatedIn,
diff --git a/app/features/user-page/user-page-schemas.ts b/app/features/user-page/user-page-schemas.ts
index 7acad05fd..b7daf32c1 100644
--- a/app/features/user-page/user-page-schemas.ts
+++ b/app/features/user-page/user-page-schemas.ts
@@ -58,6 +58,12 @@ export const seasonsSearchParamsSchema = z.object({
.refine((nth) => !nth || Seasons.allStarted(new Date()).includes(nth)),
});
+export const seasonSummaryGraphicSearchParamsSchema = z.object({
+ season: z.coerce
+ .number()
+ .refine((nth) => Seasons.allStarted(new Date()).includes(nth)),
+});
+
const SENS_ITEMS = [
-50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35,
40, 45, 50,
diff --git a/app/routes.ts b/app/routes.ts
index 2ed096d53..f3c288f23 100644
--- a/app/routes.ts
+++ b/app/routes.ts
@@ -83,6 +83,10 @@ export default [
"edit-widgets",
"features/user-page/routes/u.$identifier.edit-widgets.tsx",
),
+ route(
+ "seasons/summary-graphic",
+ "features/user-page/routes/u.$identifier.seasons.summary-graphic.ts",
+ ),
route("seasons", "features/user-page/routes/u.$identifier.seasons.tsx", [
index("features/user-page/routes/u.$identifier.seasons.index.tsx"),
route(
diff --git a/app/styles/vars.css b/app/styles/vars.css
index b7f3f298c..793bcaaa0 100644
--- a/app/styles/vars.css
+++ b/app/styles/vars.css
@@ -15,8 +15,13 @@ These should not be consumed directly, only used as a base for other vars!
The hue and chroma values should not be edited manually, instead
use oklch-gamut.ts to generate valid color palettes!
+
+A subtree can force a color scheme regardless of the html class with
+[data-theme="dark"|"light"] and opt out of an active custom theme with
+[data-default-theme] (e.g. image export previews)
*/
-html {
+html,
+[data-default-theme] {
--_base-h: 268;
--_base-c-0: 0;
--_base-c-1: 0.02357547860966049;
@@ -81,7 +86,7 @@ Any changes here NEED to be reflected in oklch-gamut.ts as well
*/
html.dark,
html.dark [data-custom-theme],
-.dark-preview {
+[data-theme="dark"] {
--color-base-0: oklch(100% var(--_base-c-0) var(--_base-h));
--color-base-1: oklch(95% var(--_base-c-1) var(--_base-h));
--color-base-2: oklch(90% var(--_base-c-2) var(--_base-h));
@@ -133,7 +138,7 @@ html.dark [data-custom-theme],
html.light,
html.light [data-custom-theme],
-.light-preview {
+[data-theme="light"] {
--color-base-0: oklch(17% var(--_base-c-7) var(--_base-h));
--color-base-1: oklch(25% var(--_base-c-6) var(--_base-h));
--color-base-2: oklch(32% var(--_base-c-5) var(--_base-h));
@@ -187,10 +192,9 @@ html.light [data-custom-theme],
These are the vars you mainly want to use
*/
html,
-/* biome-ignore lint/style/noDescendingSpecificity: [data-custom-theme] re-declares theme vars for card subtrees; different properties than the html.dark/light blocks so no real override */
+/* biome-ignore lint/style/noDescendingSpecificity: [data-custom-theme] and [data-theme] re-declare theme vars for subtrees; different properties than the html.dark/light blocks so no real override */
[data-custom-theme],
-.dark-preview,
-.light-preview {
+[data-theme] {
--color-text: var(--color-base-0);
--color-text-high: var(--color-base-3);
--color-text-inverse: var(--color-base-7);
diff --git a/app/utils/urls.ts b/app/utils/urls.ts
index ab46ff591..3c67cd50e 100644
--- a/app/utils/urls.ts
+++ b/app/utils/urls.ts
@@ -39,6 +39,29 @@ export const discordAvatarUrl = ({
discordAvatar
}.webp${size === "lg" ? "?size=240" : "?size=80"}`;
+/**
+ * Resolves the avatar image url of an user, preferring their custom avatar over
+ * the Discord one. Returns undefined if the user has neither.
+ */
+export const resolveAvatarUrl = ({
+ customAvatarUrl,
+ discordId,
+ discordAvatar,
+ size,
+}: {
+ customAvatarUrl?: string | null;
+ discordId: string;
+ discordAvatar?: string | null;
+ size: "lg" | "sm";
+}) => {
+ if (customAvatarUrl) return customAvatarUrl;
+ if (discordAvatar) {
+ return discordAvatarUrl({ discordId, discordAvatar, size });
+ }
+
+ return undefined;
+};
+
export const SENDOU_INK_BASE_URL = "https://sendou.ink";
export const BADGES_DOC_LINK =
@@ -187,6 +210,13 @@ export const userSeasonsPage = ({
`${userPage(user)}/seasons${
typeof season === "number" ? `?season=${season}` : ""
}`;
+export const userSeasonSummaryGraphicPage = ({
+ user,
+ season,
+}: {
+ user: UserLinkArgs;
+ season: number;
+}) => `${userPage(user)}/seasons/summary-graphic?season=${season}`;
export const userSeasonsStatsPage = ({
user,
season,
diff --git a/e2e/helpers/factories.ts b/e2e/helpers/factories.ts
index 538657efe..d2fa61d5e 100644
--- a/e2e/helpers/factories.ts
+++ b/e2e/helpers/factories.ts
@@ -31,6 +31,7 @@ export async function loadFactories(parallelIndex: number) {
return {
backdate: (await import("~/db/seed/core/backdate")).backdate,
+ reseason: (await import("~/db/seed/core/reseason")).reseason,
ApiTokenFactory: await import("~/db/seed/factories/ApiTokenFactory"),
ArtFactory: await import("~/db/seed/factories/ArtFactory"),
AssociationFactory: await import("~/db/seed/factories/AssociationFactory"),
diff --git a/e2e/pages/user/user-seasons-page.ts b/e2e/pages/user/user-seasons-page.ts
new file mode 100644
index 000000000..58792f478
--- /dev/null
+++ b/e2e/pages/user/user-seasons-page.ts
@@ -0,0 +1,43 @@
+import type { Page } from "@playwright/test";
+import { userSeasonsPage } from "~/utils/urls";
+import { navigate } from "../../helpers/playwright";
+
+/** A user profile's `/seasons` page, including the season summary image export. */
+export class UserSeasonsPage {
+ private readonly page: Page;
+ readonly locators;
+
+ constructor(page: Page) {
+ this.page = page;
+ this.locators = {
+ exportImageButton: page.getByRole("button", { name: "Export image" }),
+ exportDialog: page.getByRole("dialog"),
+ downloadButton: page.getByRole("button", { name: "Download" }),
+ supporterPerkExplanation: page.getByText(/supporter perk/),
+ };
+ }
+
+ async goto(discordId: string, season?: number) {
+ await navigate({
+ page: this.page,
+ url: userSeasonsPage({ user: { discordId }, season }),
+ });
+ }
+
+ async openExportDialog() {
+ await this.locators.exportImageButton.click();
+ }
+
+ exportDialogText(content: string) {
+ return this.locators.exportDialog.getByText(content);
+ }
+
+ async downloadExportedImage() {
+ const downloadPromise = this.page.waitForEvent("download");
+ await this.locators.exportDialog
+ .getByRole("button", { name: "Download" })
+ .click();
+
+ return downloadPromise;
+ }
+}
diff --git a/e2e/user-page.spec.ts b/e2e/user-page.spec.ts
index 39aa87855..65526d5e5 100644
--- a/e2e/user-page.spec.ts
+++ b/e2e/user-page.spec.ts
@@ -1,9 +1,18 @@
+import { addDays } from "date-fns";
import { NZAP_TEST_DISCORD_ID, NZAP_TEST_ID } from "~/db/seed/constants";
import { ADMIN_DISCORD_ID, ADMIN_ID } from "~/features/admin/admin-constants";
+import { MATCHES_COUNT_NEEDED_FOR_LEADERBOARD } from "~/features/leaderboards/leaderboards-constants";
+import * as Seasons from "~/features/mmr/core/Seasons";
+import { FULL_GROUP_SIZE } from "~/features/sendouq/q-constants";
+import type { Factories } from "./helpers/factories";
import { expect, impersonate, isNotVisible, test } from "./helpers/playwright";
import { SettingsPage } from "./pages/settings/settings-page";
import { UserEditProfilePage } from "./pages/user/user-edit-profile-page";
import { UserPage } from "./pages/user/user-page";
+import { UserSeasonsPage } from "./pages/user/user-seasons-page";
+
+/** The only season the e2e seasons list has finished, i.e. the exportable one. */
+const FINISHED_SEASON = 0;
test.describe("User page", () => {
test("uses badge pagination", async ({ page, factories }) => {
@@ -147,6 +156,43 @@ test.describe("User page", () => {
await expect(settings.hasCustomTheme()).resolves.toBe(false);
});
+ test("exports season summary image as a supporter", async ({
+ page,
+ factories,
+ }) => {
+ await factories.UserFactory.grant(ADMIN_ID, { patronTier: 2 });
+ await playFinishedSeason(factories, ADMIN_ID);
+
+ await impersonate(page);
+
+ const seasonsPage = new UserSeasonsPage(page);
+ await seasonsPage.goto(ADMIN_DISCORD_ID);
+ await seasonsPage.openExportDialog();
+
+ await expect(seasonsPage.exportDialogText("Best win streak")).toBeVisible();
+
+ const download = await seasonsPage.downloadExportedImage();
+ expect(download.suggestedFilename()).toBe(
+ `season-${FINISHED_SEASON}-summary.png`,
+ );
+ });
+
+ test("shows supporter perk explanation instead of exporting for non-supporter mid-season", async ({
+ page,
+ factories,
+ }) => {
+ await playFinishedSeason(factories, NZAP_TEST_ID);
+
+ await impersonate(page, NZAP_TEST_ID);
+
+ const seasonsPage = new UserSeasonsPage(page);
+ await seasonsPage.goto(NZAP_TEST_DISCORD_ID);
+ await seasonsPage.openExportDialog();
+
+ await expect(seasonsPage.locators.supporterPerkExplanation).toBeVisible();
+ await isNotVisible(seasonsPage.locators.downloadButton);
+ });
+
test("edits weapon pool", async ({ page, factories }) => {
await factories.UserFactory.grant(ADMIN_ID, {
weapons: ([200, 1100, 2000, 4000] as const).map((weaponSplId) => ({
@@ -175,3 +221,32 @@ test.describe("User page", () => {
}
});
});
+
+/**
+ * Plays the user through a whole season of SendouQ, ending it with a calculated
+ * (i.e. non-approximate) skill. The matches are spread over the days of the only
+ * finished season so that the season summary has something to show.
+ */
+async function playFinishedSeason(factories: Factories, userId: number) {
+ const mates = await factories.UserFactory.createMany(FULL_GROUP_SIZE - 1);
+ const enemies = await factories.UserFactory.createMany(FULL_GROUP_SIZE);
+
+ const ownGroup = [userId, ...mates.map((mate) => mate.id)];
+ const opposingGroup = enemies.map((enemy) => enemy.id);
+ const { starts } = Seasons.nthToDateRange(FINISHED_SEASON);
+
+ for (let index = 0; index < MATCHES_COUNT_NEEDED_FOR_LEADERBOARD; index++) {
+ // alpha wins every map, so which side the user is on decides the set
+ const userWon = index % 3 !== 0;
+
+ await factories.SQMatchFactory.create(
+ {
+ alphaUserIds: userWon ? ownGroup : opposingGroup,
+ bravoUserIds: userWon ? opposingGroup : ownGroup,
+ },
+ { isConcluded: true, createdAt: addDays(starts, index) },
+ );
+ }
+
+ await factories.reseason(FINISHED_SEASON);
+}
diff --git a/locales/da/common.json b/locales/da/common.json
index ed626473b..112f3a52c 100644
--- a/locales/da/common.json
+++ b/locales/da/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "",
"actions.noOutline": "",
"actions.join": "Bliv medlem",
+ "imageExport.export": "",
+ "imageExport.download": "",
+ "imageExport.theme.light": "",
+ "imageExport.theme.dark": "",
+ "imageExport.theme.lightCustom": "",
+ "imageExport.theme.darkCustom": "",
+ "imageExport.qrCode": "",
+ "imageExport.buildTitle": "",
+ "imageExport.abilityPoints": "",
+ "imageExport.abilityChunks": "",
"host": "",
"seed": "",
"actions.nevermind": "",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "",
"support.perk.useBotToLogIn.extra": "",
"support.perk.earlyAccess": "",
+ "support.perk.seasonSummaryImage": "",
+ "support.perk.seasonSummaryImage.extra": "",
"custom.colors.title": "Tilpas farver",
"custom.colors.bg": "Baggrund",
"custom.colors.bg-darker": "Mørkere baggrund",
diff --git a/locales/da/tier-list-maker.json b/locales/da/tier-list-maker.json
index f8d8ab98b..d869c964f 100644
--- a/locales/da/tier-list-maker.json
+++ b/locales/da/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "",
- "download": "",
"mainWeapons": "",
"subWeapons": "",
"specialWeapons": "",
@@ -18,7 +17,8 @@
"resetConfirmation": "",
"noDuplicates": "",
"showTierHeaders": "",
- "titlePlaceholder": "",
+ "title": "",
+ "showUsername": "",
"by": "",
"custom": ""
}
diff --git a/locales/da/tournament.json b/locales/da/tournament.json
index dfaf4eda4..5b0deab6d 100644
--- a/locales/da/tournament.json
+++ b/locales/da/tournament.json
@@ -140,6 +140,12 @@
"finalize.receivingTeam.label": "",
"finalize.receivingTeam.placeholder": "",
"streams.none": "Der p.t. er ingen direkte udsendelser af denne turnering",
+ "run.sets": "",
+ "run.maps": "",
+ "run.qualifiedFor": "",
+ "run.firstTitle": "",
+ "run.latestTitle": "",
+ "run.seriesTitles": "",
"team.setWins": "Vundne sæt",
"team.mapWins": "Sejr på baner",
"team.seed": "Seed",
diff --git a/locales/da/user.json b/locales/da/user.json
index a93cf6e42..f908c7e83 100644
--- a/locales/da/user.json
+++ b/locales/da/user.json
@@ -186,6 +186,27 @@
"seasons.noReportedWeapons": "Der er endnu ikke blevet indrapporteret nogle våben",
"seasons.clickARow": "Tryk på en række for at se våbenbrugsstatistikker.",
"seasons.loading": "indlæser...",
+ "seasons.summary.sets": "",
+ "seasons.summary.maps": "",
+ "seasons.summary.winStreak": "",
+ "seasons.summary.soloRank": "",
+ "seasons.summary.teamRank": "",
+ "seasons.summary.activity": "",
+ "seasons.summary.activity.tournament": "",
+ "seasons.summary.activity.both": "",
+ "seasons.summary.bestStage": "",
+ "seasons.summary.topWeapons": "",
+ "seasons.summary.topMates": "",
+ "seasons.summary.clutch": "",
+ "seasons.summary.bestWins": "",
+ "seasons.summary.bestTournament": "",
+ "seasons.summary.opponentSp": "",
+ "seasons.summary.count.sets_one": "",
+ "seasons.summary.count.sets_other": "",
+ "seasons.summary.count.maps_one": "",
+ "seasons.summary.count.maps_other": "",
+ "seasons.summary.export": "",
+ "seasons.summary.export.supporterPerk": "",
"builds.sorting.changeButton": "Ændr sortering",
"builds.sorting.header": "Ændr sæt-sortering",
"builds.sorting.backToDefaults": "Nulstil visning",
diff --git a/locales/de/common.json b/locales/de/common.json
index 08c3d7504..4b9761897 100644
--- a/locales/de/common.json
+++ b/locales/de/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "",
"actions.noOutline": "",
"actions.join": "Beitreten",
+ "imageExport.export": "",
+ "imageExport.download": "",
+ "imageExport.theme.light": "",
+ "imageExport.theme.dark": "",
+ "imageExport.theme.lightCustom": "",
+ "imageExport.theme.darkCustom": "",
+ "imageExport.qrCode": "",
+ "imageExport.buildTitle": "",
+ "imageExport.abilityPoints": "",
+ "imageExport.abilityChunks": "",
"host": "",
"seed": "",
"actions.nevermind": "",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "",
"support.perk.useBotToLogIn.extra": "",
"support.perk.earlyAccess": "",
+ "support.perk.seasonSummaryImage": "",
+ "support.perk.seasonSummaryImage.extra": "",
"custom.colors.title": "Eigene Farben",
"custom.colors.bg": "Hintergrund",
"custom.colors.bg-darker": "Hintergrund dunkler",
diff --git a/locales/de/tier-list-maker.json b/locales/de/tier-list-maker.json
index f8d8ab98b..d869c964f 100644
--- a/locales/de/tier-list-maker.json
+++ b/locales/de/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "",
- "download": "",
"mainWeapons": "",
"subWeapons": "",
"specialWeapons": "",
@@ -18,7 +17,8 @@
"resetConfirmation": "",
"noDuplicates": "",
"showTierHeaders": "",
- "titlePlaceholder": "",
+ "title": "",
+ "showUsername": "",
"by": "",
"custom": ""
}
diff --git a/locales/de/tournament.json b/locales/de/tournament.json
index 3d4d92f2f..4788bfee6 100644
--- a/locales/de/tournament.json
+++ b/locales/de/tournament.json
@@ -140,6 +140,12 @@
"finalize.receivingTeam.label": "",
"finalize.receivingTeam.placeholder": "",
"streams.none": "Aktuell sind keine Livestreams von diesem Turnier verfügbar",
+ "run.sets": "",
+ "run.maps": "",
+ "run.qualifiedFor": "",
+ "run.firstTitle": "",
+ "run.latestTitle": "",
+ "run.seriesTitles": "",
"team.setWins": "Set-Siege",
"team.mapWins": "Arenen-Siege",
"team.seed": "Seed",
diff --git a/locales/de/user.json b/locales/de/user.json
index 1de21461a..842bbdbb7 100644
--- a/locales/de/user.json
+++ b/locales/de/user.json
@@ -186,6 +186,27 @@
"seasons.noReportedWeapons": "",
"seasons.clickARow": "",
"seasons.loading": "",
+ "seasons.summary.sets": "",
+ "seasons.summary.maps": "",
+ "seasons.summary.winStreak": "",
+ "seasons.summary.soloRank": "",
+ "seasons.summary.teamRank": "",
+ "seasons.summary.activity": "",
+ "seasons.summary.activity.tournament": "",
+ "seasons.summary.activity.both": "",
+ "seasons.summary.bestStage": "",
+ "seasons.summary.topWeapons": "",
+ "seasons.summary.topMates": "",
+ "seasons.summary.clutch": "",
+ "seasons.summary.bestWins": "",
+ "seasons.summary.bestTournament": "",
+ "seasons.summary.opponentSp": "",
+ "seasons.summary.count.sets_one": "",
+ "seasons.summary.count.sets_other": "",
+ "seasons.summary.count.maps_one": "",
+ "seasons.summary.count.maps_other": "",
+ "seasons.summary.export": "",
+ "seasons.summary.export.supporterPerk": "",
"builds.sorting.changeButton": "",
"builds.sorting.header": "",
"builds.sorting.backToDefaults": "",
diff --git a/locales/en/common.json b/locales/en/common.json
index e868ddb7c..8afa07bef 100644
--- a/locales/en/common.json
+++ b/locales/en/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "Outlined",
"actions.noOutline": "No outline",
"actions.join": "Join",
+ "imageExport.export": "Export image",
+ "imageExport.download": "Download",
+ "imageExport.theme.light": "Light",
+ "imageExport.theme.dark": "Dark",
+ "imageExport.theme.lightCustom": "Light (custom)",
+ "imageExport.theme.darkCustom": "Dark (custom)",
+ "imageExport.qrCode": "QR code",
+ "imageExport.buildTitle": "Build title",
+ "imageExport.abilityPoints": "Ability points",
+ "imageExport.abilityChunks": "Ability chunks",
"host": "Host",
"seed": "Seed {{number}}",
"actions.nevermind": "Nevermind",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "Log-in via Discord bot",
"support.perk.useBotToLogIn.extra": "Request a log-in link from the Lohi bot as an alternative to the normal website log-in",
"support.perk.earlyAccess": "Occasional early access to features",
+ "support.perk.seasonSummaryImage": "Export any season's summary image",
+ "support.perk.seasonSummaryImage.extra": "Export a summary image of any SendouQ season you played. Everyone can export the latest finished season's image during the off-season.",
"custom.colors.title": "Custom colors",
"custom.colors.bg": "Background",
"custom.colors.bg-darker": "Background darker",
diff --git a/locales/en/tier-list-maker.json b/locales/en/tier-list-maker.json
index 1961c941e..6df8867b8 100644
--- a/locales/en/tier-list-maker.json
+++ b/locales/en/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "Add tier",
- "download": "Download (.png)",
"mainWeapons": "Main Weapons",
"subWeapons": "Sub Weapons",
"specialWeapons": "Special Weapons",
@@ -18,7 +17,8 @@
"resetConfirmation": "Are you sure you want to reset the tier list? This will remove all items and restore default tiers.",
"noDuplicates": "No duplicates",
"showTierHeaders": "Show tier headers",
- "titlePlaceholder": "Click to add title...",
+ "title": "Title",
+ "showUsername": "Show username",
"by": "Made by",
"custom": "Custom"
}
diff --git a/locales/en/tournament.json b/locales/en/tournament.json
index 7f3b1c390..b1747cf4f 100644
--- a/locales/en/tournament.json
+++ b/locales/en/tournament.json
@@ -140,6 +140,12 @@
"finalize.receivingTeam.label": "Receiving team",
"finalize.receivingTeam.placeholder": "Select team…",
"streams.none": "No live streams of this tournament available currently",
+ "run.sets": "Sets",
+ "run.maps": "Maps",
+ "run.qualifiedFor": "Advanced to {{bracket}}",
+ "run.firstTitle": "First title",
+ "run.latestTitle": "Latest title",
+ "run.seriesTitles": "Series titles",
"team.setWins": "Set wins",
"team.mapWins": "Map wins",
"team.seed": "Seed",
diff --git a/locales/en/user.json b/locales/en/user.json
index e275369e5..1b4775ea1 100644
--- a/locales/en/user.json
+++ b/locales/en/user.json
@@ -186,6 +186,27 @@
"seasons.noReportedWeapons": "No reported weapons yet",
"seasons.clickARow": "Click a row to see weapon usage stats",
"seasons.loading": "Loading...",
+ "seasons.summary.sets": "Sets",
+ "seasons.summary.maps": "Maps",
+ "seasons.summary.winStreak": "Best win streak",
+ "seasons.summary.soloRank": "Solo rank",
+ "seasons.summary.teamRank": "Team rank",
+ "seasons.summary.activity": "Activity",
+ "seasons.summary.activity.tournament": "Tournament",
+ "seasons.summary.activity.both": "Both",
+ "seasons.summary.bestStage": "Best stage",
+ "seasons.summary.topWeapons": "Top weapons",
+ "seasons.summary.topMates": "Top teammates",
+ "seasons.summary.clutch": "Clutch",
+ "seasons.summary.bestWins": "Best wins",
+ "seasons.summary.bestTournament": "Best tournament",
+ "seasons.summary.opponentSp": "Opponent SP",
+ "seasons.summary.count.sets_one": "{{count}} set",
+ "seasons.summary.count.sets_other": "{{count}} sets",
+ "seasons.summary.count.maps_one": "{{count}} map",
+ "seasons.summary.count.maps_other": "{{count}} maps",
+ "seasons.summary.export": "Export image",
+ "seasons.summary.export.supporterPerk": "Exporting this season's summary image is a supporter perk. Everyone can export the latest finished season's image during the off-season.",
"builds.sorting.changeButton": "Change sorting",
"builds.sorting.header": "Change build sorting",
"builds.sorting.backToDefaults": "Back to defaults",
diff --git a/locales/es-ES/common.json b/locales/es-ES/common.json
index c1367a657..ef9be99dc 100644
--- a/locales/es-ES/common.json
+++ b/locales/es-ES/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "Con borde",
"actions.noOutline": "Sin borde",
"actions.join": "Unirse",
+ "imageExport.export": "",
+ "imageExport.download": "",
+ "imageExport.theme.light": "",
+ "imageExport.theme.dark": "",
+ "imageExport.theme.lightCustom": "",
+ "imageExport.theme.darkCustom": "",
+ "imageExport.qrCode": "",
+ "imageExport.buildTitle": "",
+ "imageExport.abilityPoints": "",
+ "imageExport.abilityChunks": "",
"host": "",
"seed": "",
"actions.nevermind": "Olvídalo",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "Iniciar sesión con el bot de Discord",
"support.perk.useBotToLogIn.extra": "Solicita un enlace de inicio de sesión al bot Lohi como alternativa a iniciar sesión desde la web.",
"support.perk.earlyAccess": "Acceso anticipado a nuevas funciones",
+ "support.perk.seasonSummaryImage": "",
+ "support.perk.seasonSummaryImage.extra": "",
"custom.colors.title": "Colores personalizados",
"custom.colors.bg": "Fondo",
"custom.colors.bg-darker": "Fondo más oscuro",
diff --git a/locales/es-ES/tier-list-maker.json b/locales/es-ES/tier-list-maker.json
index 17bcc50ac..f90a79497 100644
--- a/locales/es-ES/tier-list-maker.json
+++ b/locales/es-ES/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "Añadir tier",
- "download": "Descargar (.png)",
"mainWeapons": "Armas principales",
"subWeapons": "Armas secundarias",
"specialWeapons": "Armas especiales",
@@ -18,7 +17,8 @@
"resetConfirmation": "¿Seguro que quieres reiniciar la tier list? Esto eliminará todos los elementos y restaurará las tiers por defecto.",
"noDuplicates": "",
"showTierHeaders": "Mostrar encabezados de las tiers",
- "titlePlaceholder": "Haz clic para añadir un título...",
+ "title": "",
+ "showUsername": "",
"by": "Creado por",
"custom": "Personalizado"
}
diff --git a/locales/es-ES/tournament.json b/locales/es-ES/tournament.json
index 1b55f4b36..77d3df3ff 100644
--- a/locales/es-ES/tournament.json
+++ b/locales/es-ES/tournament.json
@@ -142,6 +142,12 @@
"finalize.receivingTeam.label": "Equipo receptor",
"finalize.receivingTeam.placeholder": "Seleccionar equipo...",
"streams.none": "No hay streams disponibles para este torneo al momento",
+ "run.sets": "",
+ "run.maps": "",
+ "run.qualifiedFor": "",
+ "run.firstTitle": "",
+ "run.latestTitle": "",
+ "run.seriesTitles": "",
"team.setWins": "Victorias de sets",
"team.mapWins": "Victorias de mapas",
"team.seed": "Colocado",
diff --git a/locales/es-ES/user.json b/locales/es-ES/user.json
index c8869db9f..f935de997 100644
--- a/locales/es-ES/user.json
+++ b/locales/es-ES/user.json
@@ -186,6 +186,29 @@
"seasons.noReportedWeapons": "No se han informado armas",
"seasons.clickARow": "Haga clic en una fila para ver estadísticas de armas",
"seasons.loading": "Cargando...",
+ "seasons.summary.sets": "",
+ "seasons.summary.maps": "",
+ "seasons.summary.winStreak": "",
+ "seasons.summary.soloRank": "",
+ "seasons.summary.teamRank": "",
+ "seasons.summary.activity": "",
+ "seasons.summary.activity.tournament": "",
+ "seasons.summary.activity.both": "",
+ "seasons.summary.bestStage": "",
+ "seasons.summary.topWeapons": "",
+ "seasons.summary.topMates": "",
+ "seasons.summary.clutch": "",
+ "seasons.summary.bestWins": "",
+ "seasons.summary.bestTournament": "",
+ "seasons.summary.opponentSp": "",
+ "seasons.summary.count.sets_one": "",
+ "seasons.summary.count.sets_many": "",
+ "seasons.summary.count.sets_other": "",
+ "seasons.summary.count.maps_one": "",
+ "seasons.summary.count.maps_many": "",
+ "seasons.summary.count.maps_other": "",
+ "seasons.summary.export": "",
+ "seasons.summary.export.supporterPerk": "",
"builds.sorting.changeButton": "Cambiar orden",
"builds.sorting.header": "Cambiar orden de las builds",
"builds.sorting.backToDefaults": "Volver por defecto",
diff --git a/locales/es-US/common.json b/locales/es-US/common.json
index eb9cc1e13..f6de7af79 100644
--- a/locales/es-US/common.json
+++ b/locales/es-US/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "",
"actions.noOutline": "",
"actions.join": "Unirse",
+ "imageExport.export": "",
+ "imageExport.download": "",
+ "imageExport.theme.light": "",
+ "imageExport.theme.dark": "",
+ "imageExport.theme.lightCustom": "",
+ "imageExport.theme.darkCustom": "",
+ "imageExport.qrCode": "",
+ "imageExport.buildTitle": "",
+ "imageExport.abilityPoints": "",
+ "imageExport.abilityChunks": "",
"host": "",
"seed": "",
"actions.nevermind": "Cancelar",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "",
"support.perk.useBotToLogIn.extra": "",
"support.perk.earlyAccess": "",
+ "support.perk.seasonSummaryImage": "",
+ "support.perk.seasonSummaryImage.extra": "",
"custom.colors.title": "Colores personalizados",
"custom.colors.bg": "Fondo",
"custom.colors.bg-darker": "Fondo más oscuro",
diff --git a/locales/es-US/tier-list-maker.json b/locales/es-US/tier-list-maker.json
index f8d8ab98b..d869c964f 100644
--- a/locales/es-US/tier-list-maker.json
+++ b/locales/es-US/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "",
- "download": "",
"mainWeapons": "",
"subWeapons": "",
"specialWeapons": "",
@@ -18,7 +17,8 @@
"resetConfirmation": "",
"noDuplicates": "",
"showTierHeaders": "",
- "titlePlaceholder": "",
+ "title": "",
+ "showUsername": "",
"by": "",
"custom": ""
}
diff --git a/locales/es-US/tournament.json b/locales/es-US/tournament.json
index 730191641..6e04fcfda 100644
--- a/locales/es-US/tournament.json
+++ b/locales/es-US/tournament.json
@@ -142,6 +142,12 @@
"finalize.receivingTeam.label": "",
"finalize.receivingTeam.placeholder": "",
"streams.none": "No hay streams disponibles para este torneo al momento",
+ "run.sets": "",
+ "run.maps": "",
+ "run.qualifiedFor": "",
+ "run.firstTitle": "",
+ "run.latestTitle": "",
+ "run.seriesTitles": "",
"team.setWins": "Victorias de sets",
"team.mapWins": "Victorias de juegos",
"team.seed": "Colocado",
diff --git a/locales/es-US/user.json b/locales/es-US/user.json
index 21358adf4..664981f95 100644
--- a/locales/es-US/user.json
+++ b/locales/es-US/user.json
@@ -186,6 +186,29 @@
"seasons.noReportedWeapons": "No se han informado armas",
"seasons.clickARow": "Haga clic en una fila para ver estadísticas de armas",
"seasons.loading": "Cargando...",
+ "seasons.summary.sets": "",
+ "seasons.summary.maps": "",
+ "seasons.summary.winStreak": "",
+ "seasons.summary.soloRank": "",
+ "seasons.summary.teamRank": "",
+ "seasons.summary.activity": "",
+ "seasons.summary.activity.tournament": "",
+ "seasons.summary.activity.both": "",
+ "seasons.summary.bestStage": "",
+ "seasons.summary.topWeapons": "",
+ "seasons.summary.topMates": "",
+ "seasons.summary.clutch": "",
+ "seasons.summary.bestWins": "",
+ "seasons.summary.bestTournament": "",
+ "seasons.summary.opponentSp": "",
+ "seasons.summary.count.sets_one": "",
+ "seasons.summary.count.sets_many": "",
+ "seasons.summary.count.sets_other": "",
+ "seasons.summary.count.maps_one": "",
+ "seasons.summary.count.maps_many": "",
+ "seasons.summary.count.maps_other": "",
+ "seasons.summary.export": "",
+ "seasons.summary.export.supporterPerk": "",
"builds.sorting.changeButton": "Cambiar ordenación",
"builds.sorting.header": "Cambiar ordenación de builds",
"builds.sorting.backToDefaults": "Volver a los valores predeterminados",
diff --git a/locales/fr-CA/common.json b/locales/fr-CA/common.json
index cc195a8ae..db450b543 100644
--- a/locales/fr-CA/common.json
+++ b/locales/fr-CA/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "",
"actions.noOutline": "",
"actions.join": "Joindre",
+ "imageExport.export": "",
+ "imageExport.download": "",
+ "imageExport.theme.light": "",
+ "imageExport.theme.dark": "",
+ "imageExport.theme.lightCustom": "",
+ "imageExport.theme.darkCustom": "",
+ "imageExport.qrCode": "",
+ "imageExport.buildTitle": "",
+ "imageExport.abilityPoints": "",
+ "imageExport.abilityChunks": "",
"host": "",
"seed": "",
"actions.nevermind": "",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "",
"support.perk.useBotToLogIn.extra": "",
"support.perk.earlyAccess": "",
+ "support.perk.seasonSummaryImage": "",
+ "support.perk.seasonSummaryImage.extra": "",
"custom.colors.title": "Couleurs personalisées",
"custom.colors.bg": "Arrière-plan",
"custom.colors.bg-darker": "Arrière-plan sombre",
diff --git a/locales/fr-CA/tier-list-maker.json b/locales/fr-CA/tier-list-maker.json
index f8d8ab98b..d869c964f 100644
--- a/locales/fr-CA/tier-list-maker.json
+++ b/locales/fr-CA/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "",
- "download": "",
"mainWeapons": "",
"subWeapons": "",
"specialWeapons": "",
@@ -18,7 +17,8 @@
"resetConfirmation": "",
"noDuplicates": "",
"showTierHeaders": "",
- "titlePlaceholder": "",
+ "title": "",
+ "showUsername": "",
"by": "",
"custom": ""
}
diff --git a/locales/fr-CA/tournament.json b/locales/fr-CA/tournament.json
index dfc02bfc7..a567af998 100644
--- a/locales/fr-CA/tournament.json
+++ b/locales/fr-CA/tournament.json
@@ -142,6 +142,12 @@
"finalize.receivingTeam.label": "",
"finalize.receivingTeam.placeholder": "",
"streams.none": "Aucune diffusion en direct de ce tournoi n'est disponible actuellement",
+ "run.sets": "",
+ "run.maps": "",
+ "run.qualifiedFor": "",
+ "run.firstTitle": "",
+ "run.latestTitle": "",
+ "run.seriesTitles": "",
"team.setWins": "Set wins",
"team.mapWins": "Map wins",
"team.seed": "Seed",
diff --git a/locales/fr-CA/user.json b/locales/fr-CA/user.json
index 0ebccd81a..da2712757 100644
--- a/locales/fr-CA/user.json
+++ b/locales/fr-CA/user.json
@@ -186,6 +186,29 @@
"seasons.noReportedWeapons": "",
"seasons.clickARow": "",
"seasons.loading": "",
+ "seasons.summary.sets": "",
+ "seasons.summary.maps": "",
+ "seasons.summary.winStreak": "",
+ "seasons.summary.soloRank": "",
+ "seasons.summary.teamRank": "",
+ "seasons.summary.activity": "",
+ "seasons.summary.activity.tournament": "",
+ "seasons.summary.activity.both": "",
+ "seasons.summary.bestStage": "",
+ "seasons.summary.topWeapons": "",
+ "seasons.summary.topMates": "",
+ "seasons.summary.clutch": "",
+ "seasons.summary.bestWins": "",
+ "seasons.summary.bestTournament": "",
+ "seasons.summary.opponentSp": "",
+ "seasons.summary.count.sets_one": "",
+ "seasons.summary.count.sets_many": "",
+ "seasons.summary.count.sets_other": "",
+ "seasons.summary.count.maps_one": "",
+ "seasons.summary.count.maps_many": "",
+ "seasons.summary.count.maps_other": "",
+ "seasons.summary.export": "",
+ "seasons.summary.export.supporterPerk": "",
"builds.sorting.changeButton": "",
"builds.sorting.header": "",
"builds.sorting.backToDefaults": "",
diff --git a/locales/fr-EU/common.json b/locales/fr-EU/common.json
index 109bbe446..262b476d2 100644
--- a/locales/fr-EU/common.json
+++ b/locales/fr-EU/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "Outlined",
"actions.noOutline": "No outline",
"actions.join": "Joindre",
+ "imageExport.export": "",
+ "imageExport.download": "",
+ "imageExport.theme.light": "",
+ "imageExport.theme.dark": "",
+ "imageExport.theme.lightCustom": "",
+ "imageExport.theme.darkCustom": "",
+ "imageExport.qrCode": "",
+ "imageExport.buildTitle": "",
+ "imageExport.abilityPoints": "",
+ "imageExport.abilityChunks": "",
"host": "",
"seed": "",
"actions.nevermind": "Laisser tomber",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "Se connecter via le bot Discord",
"support.perk.useBotToLogIn.extra": "Demander un lien de connexion au bot Lohi comme alternative à la connexion normale au site Web",
"support.perk.earlyAccess": "",
+ "support.perk.seasonSummaryImage": "",
+ "support.perk.seasonSummaryImage.extra": "",
"custom.colors.title": "Couleurs personalisées",
"custom.colors.bg": "Arrière-plan",
"custom.colors.bg-darker": "Arrière-plan sombre",
diff --git a/locales/fr-EU/tier-list-maker.json b/locales/fr-EU/tier-list-maker.json
index f8d8ab98b..d869c964f 100644
--- a/locales/fr-EU/tier-list-maker.json
+++ b/locales/fr-EU/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "",
- "download": "",
"mainWeapons": "",
"subWeapons": "",
"specialWeapons": "",
@@ -18,7 +17,8 @@
"resetConfirmation": "",
"noDuplicates": "",
"showTierHeaders": "",
- "titlePlaceholder": "",
+ "title": "",
+ "showUsername": "",
"by": "",
"custom": ""
}
diff --git a/locales/fr-EU/tournament.json b/locales/fr-EU/tournament.json
index bc11e3d1e..5dfdd1033 100644
--- a/locales/fr-EU/tournament.json
+++ b/locales/fr-EU/tournament.json
@@ -142,6 +142,12 @@
"finalize.receivingTeam.label": "",
"finalize.receivingTeam.placeholder": "",
"streams.none": "Aucune diffusion en direct de ce tournoi n'est disponible actuellement",
+ "run.sets": "",
+ "run.maps": "",
+ "run.qualifiedFor": "",
+ "run.firstTitle": "",
+ "run.latestTitle": "",
+ "run.seriesTitles": "",
"team.setWins": "Set gagné",
"team.mapWins": "Map gagnée",
"team.seed": "Seed",
diff --git a/locales/fr-EU/user.json b/locales/fr-EU/user.json
index 6ab57bff4..80a1346f2 100644
--- a/locales/fr-EU/user.json
+++ b/locales/fr-EU/user.json
@@ -186,6 +186,29 @@
"seasons.noReportedWeapons": "Aucune arme a été reporté",
"seasons.clickARow": "Cliquez sur une ligne pour voir les statistiques d'utilisation des armes",
"seasons.loading": "Chargement...",
+ "seasons.summary.sets": "",
+ "seasons.summary.maps": "",
+ "seasons.summary.winStreak": "",
+ "seasons.summary.soloRank": "",
+ "seasons.summary.teamRank": "",
+ "seasons.summary.activity": "",
+ "seasons.summary.activity.tournament": "",
+ "seasons.summary.activity.both": "",
+ "seasons.summary.bestStage": "",
+ "seasons.summary.topWeapons": "",
+ "seasons.summary.topMates": "",
+ "seasons.summary.clutch": "",
+ "seasons.summary.bestWins": "",
+ "seasons.summary.bestTournament": "",
+ "seasons.summary.opponentSp": "",
+ "seasons.summary.count.sets_one": "",
+ "seasons.summary.count.sets_many": "",
+ "seasons.summary.count.sets_other": "",
+ "seasons.summary.count.maps_one": "",
+ "seasons.summary.count.maps_many": "",
+ "seasons.summary.count.maps_other": "",
+ "seasons.summary.export": "",
+ "seasons.summary.export.supporterPerk": "",
"builds.sorting.changeButton": "Changer le tri",
"builds.sorting.header": "Modifier le tri des builds",
"builds.sorting.backToDefaults": "Revenir par défaut",
diff --git a/locales/he/common.json b/locales/he/common.json
index 9692ee650..8f48b66e0 100644
--- a/locales/he/common.json
+++ b/locales/he/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "",
"actions.noOutline": "",
"actions.join": "הצטרפות",
+ "imageExport.export": "",
+ "imageExport.download": "",
+ "imageExport.theme.light": "",
+ "imageExport.theme.dark": "",
+ "imageExport.theme.lightCustom": "",
+ "imageExport.theme.darkCustom": "",
+ "imageExport.qrCode": "",
+ "imageExport.buildTitle": "",
+ "imageExport.abilityPoints": "",
+ "imageExport.abilityChunks": "",
"host": "",
"seed": "",
"actions.nevermind": "",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "",
"support.perk.useBotToLogIn.extra": "",
"support.perk.earlyAccess": "",
+ "support.perk.seasonSummaryImage": "",
+ "support.perk.seasonSummaryImage.extra": "",
"custom.colors.title": "צבעים מותאמים אישית",
"custom.colors.bg": "רקע",
"custom.colors.bg-darker": "רקע חשוך",
diff --git a/locales/he/tier-list-maker.json b/locales/he/tier-list-maker.json
index f8d8ab98b..d869c964f 100644
--- a/locales/he/tier-list-maker.json
+++ b/locales/he/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "",
- "download": "",
"mainWeapons": "",
"subWeapons": "",
"specialWeapons": "",
@@ -18,7 +17,8 @@
"resetConfirmation": "",
"noDuplicates": "",
"showTierHeaders": "",
- "titlePlaceholder": "",
+ "title": "",
+ "showUsername": "",
"by": "",
"custom": ""
}
diff --git a/locales/he/tournament.json b/locales/he/tournament.json
index 808cd9a5b..cc77dc741 100644
--- a/locales/he/tournament.json
+++ b/locales/he/tournament.json
@@ -142,6 +142,12 @@
"finalize.receivingTeam.label": "",
"finalize.receivingTeam.placeholder": "",
"streams.none": "אין שידורים חיים לטורניר זה כרגע",
+ "run.sets": "",
+ "run.maps": "",
+ "run.qualifiedFor": "",
+ "run.firstTitle": "",
+ "run.latestTitle": "",
+ "run.seriesTitles": "",
"team.setWins": "נצחונות סטים",
"team.mapWins": "נצחונות במפות",
"team.seed": "דירוג",
diff --git a/locales/he/user.json b/locales/he/user.json
index 592912939..c1c016fdd 100644
--- a/locales/he/user.json
+++ b/locales/he/user.json
@@ -186,6 +186,29 @@
"seasons.noReportedWeapons": "",
"seasons.clickARow": "",
"seasons.loading": "",
+ "seasons.summary.sets": "",
+ "seasons.summary.maps": "",
+ "seasons.summary.winStreak": "",
+ "seasons.summary.soloRank": "",
+ "seasons.summary.teamRank": "",
+ "seasons.summary.activity": "",
+ "seasons.summary.activity.tournament": "",
+ "seasons.summary.activity.both": "",
+ "seasons.summary.bestStage": "",
+ "seasons.summary.topWeapons": "",
+ "seasons.summary.topMates": "",
+ "seasons.summary.clutch": "",
+ "seasons.summary.bestWins": "",
+ "seasons.summary.bestTournament": "",
+ "seasons.summary.opponentSp": "",
+ "seasons.summary.count.sets_one": "",
+ "seasons.summary.count.sets_two": "",
+ "seasons.summary.count.sets_other": "",
+ "seasons.summary.count.maps_one": "",
+ "seasons.summary.count.maps_two": "",
+ "seasons.summary.count.maps_other": "",
+ "seasons.summary.export": "",
+ "seasons.summary.export.supporterPerk": "",
"builds.sorting.changeButton": "",
"builds.sorting.header": "",
"builds.sorting.backToDefaults": "",
diff --git a/locales/it/common.json b/locales/it/common.json
index 537c5afb5..73d395e4b 100644
--- a/locales/it/common.json
+++ b/locales/it/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "Contornato",
"actions.noOutline": "Nessun contorno",
"actions.join": "Entra",
+ "imageExport.export": "",
+ "imageExport.download": "",
+ "imageExport.theme.light": "",
+ "imageExport.theme.dark": "",
+ "imageExport.theme.lightCustom": "",
+ "imageExport.theme.darkCustom": "",
+ "imageExport.qrCode": "",
+ "imageExport.buildTitle": "",
+ "imageExport.abilityPoints": "",
+ "imageExport.abilityChunks": "",
"host": "",
"seed": "",
"actions.nevermind": "Non importa",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "",
"support.perk.useBotToLogIn.extra": "",
"support.perk.earlyAccess": "",
+ "support.perk.seasonSummaryImage": "",
+ "support.perk.seasonSummaryImage.extra": "",
"custom.colors.title": "Colori personalizzati",
"custom.colors.bg": "Sfondo",
"custom.colors.bg-darker": "Sfondo più scuro",
diff --git a/locales/it/tier-list-maker.json b/locales/it/tier-list-maker.json
index f8d8ab98b..d869c964f 100644
--- a/locales/it/tier-list-maker.json
+++ b/locales/it/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "",
- "download": "",
"mainWeapons": "",
"subWeapons": "",
"specialWeapons": "",
@@ -18,7 +17,8 @@
"resetConfirmation": "",
"noDuplicates": "",
"showTierHeaders": "",
- "titlePlaceholder": "",
+ "title": "",
+ "showUsername": "",
"by": "",
"custom": ""
}
diff --git a/locales/it/tournament.json b/locales/it/tournament.json
index 8e5d1b208..a7b63cd84 100644
--- a/locales/it/tournament.json
+++ b/locales/it/tournament.json
@@ -142,6 +142,12 @@
"finalize.receivingTeam.label": "",
"finalize.receivingTeam.placeholder": "",
"streams.none": "Nessuna livestream di questo torneo disponibile al momento",
+ "run.sets": "",
+ "run.maps": "",
+ "run.qualifiedFor": "",
+ "run.firstTitle": "",
+ "run.latestTitle": "",
+ "run.seriesTitles": "",
"team.setWins": "Set vinti",
"team.mapWins": "Mappe vinte",
"team.seed": "Seed",
diff --git a/locales/it/user.json b/locales/it/user.json
index 0514319d9..8bd9658a2 100644
--- a/locales/it/user.json
+++ b/locales/it/user.json
@@ -186,6 +186,29 @@
"seasons.noReportedWeapons": "Nessun'arma riportata",
"seasons.clickARow": "Clicca una riga per visualizzare le statistiche d'uso delle armi",
"seasons.loading": "Caricamento...",
+ "seasons.summary.sets": "",
+ "seasons.summary.maps": "",
+ "seasons.summary.winStreak": "",
+ "seasons.summary.soloRank": "",
+ "seasons.summary.teamRank": "",
+ "seasons.summary.activity": "",
+ "seasons.summary.activity.tournament": "",
+ "seasons.summary.activity.both": "",
+ "seasons.summary.bestStage": "",
+ "seasons.summary.topWeapons": "",
+ "seasons.summary.topMates": "",
+ "seasons.summary.clutch": "",
+ "seasons.summary.bestWins": "",
+ "seasons.summary.bestTournament": "",
+ "seasons.summary.opponentSp": "",
+ "seasons.summary.count.sets_one": "",
+ "seasons.summary.count.sets_many": "",
+ "seasons.summary.count.sets_other": "",
+ "seasons.summary.count.maps_one": "",
+ "seasons.summary.count.maps_many": "",
+ "seasons.summary.count.maps_other": "",
+ "seasons.summary.export": "",
+ "seasons.summary.export.supporterPerk": "",
"builds.sorting.changeButton": "Cambia ordinamento",
"builds.sorting.header": "Cambia ordinamento build",
"builds.sorting.backToDefaults": "Torna al default",
diff --git a/locales/ja/common.json b/locales/ja/common.json
index cf8b5f538..c4cdb53f1 100644
--- a/locales/ja/common.json
+++ b/locales/ja/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "アウトラインあり",
"actions.noOutline": "アウトラインなし",
"actions.join": "参加する",
+ "imageExport.export": "",
+ "imageExport.download": "",
+ "imageExport.theme.light": "",
+ "imageExport.theme.dark": "",
+ "imageExport.theme.lightCustom": "",
+ "imageExport.theme.darkCustom": "",
+ "imageExport.qrCode": "",
+ "imageExport.buildTitle": "",
+ "imageExport.abilityPoints": "",
+ "imageExport.abilityChunks": "",
"host": "部屋を建てる",
"seed": "",
"actions.nevermind": "",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "Discord ボットを使用してログイン",
"support.perk.useBotToLogIn.extra": "Lohi ボットから直接ログインできる URL を貰える",
"support.perk.earlyAccess": "たまに新機能の事前お試し",
+ "support.perk.seasonSummaryImage": "",
+ "support.perk.seasonSummaryImage.extra": "",
"custom.colors.title": "カスタムカラー",
"custom.colors.bg": "背景",
"custom.colors.bg-darker": "背景 暗め",
diff --git a/locales/ja/tier-list-maker.json b/locales/ja/tier-list-maker.json
index f8d8ab98b..d869c964f 100644
--- a/locales/ja/tier-list-maker.json
+++ b/locales/ja/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "",
- "download": "",
"mainWeapons": "",
"subWeapons": "",
"specialWeapons": "",
@@ -18,7 +17,8 @@
"resetConfirmation": "",
"noDuplicates": "",
"showTierHeaders": "",
- "titlePlaceholder": "",
+ "title": "",
+ "showUsername": "",
"by": "",
"custom": ""
}
diff --git a/locales/ja/tournament.json b/locales/ja/tournament.json
index 1f750d1e5..9e32f75a5 100644
--- a/locales/ja/tournament.json
+++ b/locales/ja/tournament.json
@@ -136,6 +136,12 @@
"finalize.receivingTeam.label": "",
"finalize.receivingTeam.placeholder": "",
"streams.none": "現在このトーナメントのストリーミングはありません",
+ "run.sets": "",
+ "run.maps": "",
+ "run.qualifiedFor": "",
+ "run.firstTitle": "",
+ "run.latestTitle": "",
+ "run.seriesTitles": "",
"team.setWins": "勝利セット",
"team.mapWins": "勝利マップ",
"team.seed": "シード",
diff --git a/locales/ja/user.json b/locales/ja/user.json
index f6258057a..7fa933268 100644
--- a/locales/ja/user.json
+++ b/locales/ja/user.json
@@ -186,6 +186,23 @@
"seasons.noReportedWeapons": "報告された武器がありません",
"seasons.clickARow": "武器の使用統計を見るには行を選択してください",
"seasons.loading": "読み込み中...",
+ "seasons.summary.sets": "",
+ "seasons.summary.maps": "",
+ "seasons.summary.winStreak": "",
+ "seasons.summary.soloRank": "",
+ "seasons.summary.teamRank": "",
+ "seasons.summary.activity": "",
+ "seasons.summary.activity.tournament": "",
+ "seasons.summary.activity.both": "",
+ "seasons.summary.bestStage": "",
+ "seasons.summary.topWeapons": "",
+ "seasons.summary.topMates": "",
+ "seasons.summary.clutch": "",
+ "seasons.summary.bestWins": "",
+ "seasons.summary.bestTournament": "",
+ "seasons.summary.opponentSp": "",
+ "seasons.summary.export": "",
+ "seasons.summary.export.supporterPerk": "",
"builds.sorting.changeButton": "並べ替え変更",
"builds.sorting.header": "ギアの並べ替えを変更",
"builds.sorting.backToDefaults": "デフォルトに戻す",
diff --git a/locales/ko/common.json b/locales/ko/common.json
index c0c667bcf..bd7adc88a 100644
--- a/locales/ko/common.json
+++ b/locales/ko/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "",
"actions.noOutline": "",
"actions.join": "참여하기",
+ "imageExport.export": "",
+ "imageExport.download": "",
+ "imageExport.theme.light": "",
+ "imageExport.theme.dark": "",
+ "imageExport.theme.lightCustom": "",
+ "imageExport.theme.darkCustom": "",
+ "imageExport.qrCode": "",
+ "imageExport.buildTitle": "",
+ "imageExport.abilityPoints": "",
+ "imageExport.abilityChunks": "",
"host": "",
"seed": "",
"actions.nevermind": "",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "",
"support.perk.useBotToLogIn.extra": "",
"support.perk.earlyAccess": "",
+ "support.perk.seasonSummaryImage": "",
+ "support.perk.seasonSummaryImage.extra": "",
"custom.colors.title": "",
"custom.colors.bg": "",
"custom.colors.bg-darker": "",
diff --git a/locales/ko/tier-list-maker.json b/locales/ko/tier-list-maker.json
index f8d8ab98b..d869c964f 100644
--- a/locales/ko/tier-list-maker.json
+++ b/locales/ko/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "",
- "download": "",
"mainWeapons": "",
"subWeapons": "",
"specialWeapons": "",
@@ -18,7 +17,8 @@
"resetConfirmation": "",
"noDuplicates": "",
"showTierHeaders": "",
- "titlePlaceholder": "",
+ "title": "",
+ "showUsername": "",
"by": "",
"custom": ""
}
diff --git a/locales/ko/tournament.json b/locales/ko/tournament.json
index 87919d3fb..206a03945 100644
--- a/locales/ko/tournament.json
+++ b/locales/ko/tournament.json
@@ -136,6 +136,12 @@
"finalize.receivingTeam.label": "",
"finalize.receivingTeam.placeholder": "",
"streams.none": "",
+ "run.sets": "",
+ "run.maps": "",
+ "run.qualifiedFor": "",
+ "run.firstTitle": "",
+ "run.latestTitle": "",
+ "run.seriesTitles": "",
"team.setWins": "",
"team.mapWins": "",
"team.seed": "",
diff --git a/locales/ko/user.json b/locales/ko/user.json
index dac5ccd12..b862f89c8 100644
--- a/locales/ko/user.json
+++ b/locales/ko/user.json
@@ -186,6 +186,23 @@
"seasons.noReportedWeapons": "",
"seasons.clickARow": "",
"seasons.loading": "",
+ "seasons.summary.sets": "",
+ "seasons.summary.maps": "",
+ "seasons.summary.winStreak": "",
+ "seasons.summary.soloRank": "",
+ "seasons.summary.teamRank": "",
+ "seasons.summary.activity": "",
+ "seasons.summary.activity.tournament": "",
+ "seasons.summary.activity.both": "",
+ "seasons.summary.bestStage": "",
+ "seasons.summary.topWeapons": "",
+ "seasons.summary.topMates": "",
+ "seasons.summary.clutch": "",
+ "seasons.summary.bestWins": "",
+ "seasons.summary.bestTournament": "",
+ "seasons.summary.opponentSp": "",
+ "seasons.summary.export": "",
+ "seasons.summary.export.supporterPerk": "",
"builds.sorting.changeButton": "",
"builds.sorting.header": "",
"builds.sorting.backToDefaults": "",
diff --git a/locales/nl/common.json b/locales/nl/common.json
index dff60ef00..d45598651 100644
--- a/locales/nl/common.json
+++ b/locales/nl/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "",
"actions.noOutline": "",
"actions.join": "",
+ "imageExport.export": "",
+ "imageExport.download": "",
+ "imageExport.theme.light": "",
+ "imageExport.theme.dark": "",
+ "imageExport.theme.lightCustom": "",
+ "imageExport.theme.darkCustom": "",
+ "imageExport.qrCode": "",
+ "imageExport.buildTitle": "",
+ "imageExport.abilityPoints": "",
+ "imageExport.abilityChunks": "",
"host": "",
"seed": "",
"actions.nevermind": "",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "",
"support.perk.useBotToLogIn.extra": "",
"support.perk.earlyAccess": "",
+ "support.perk.seasonSummaryImage": "",
+ "support.perk.seasonSummaryImage.extra": "",
"custom.colors.title": "",
"custom.colors.bg": "",
"custom.colors.bg-darker": "",
diff --git a/locales/nl/tier-list-maker.json b/locales/nl/tier-list-maker.json
index f8d8ab98b..d869c964f 100644
--- a/locales/nl/tier-list-maker.json
+++ b/locales/nl/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "",
- "download": "",
"mainWeapons": "",
"subWeapons": "",
"specialWeapons": "",
@@ -18,7 +17,8 @@
"resetConfirmation": "",
"noDuplicates": "",
"showTierHeaders": "",
- "titlePlaceholder": "",
+ "title": "",
+ "showUsername": "",
"by": "",
"custom": ""
}
diff --git a/locales/nl/tournament.json b/locales/nl/tournament.json
index 763e46d1c..71b5963a0 100644
--- a/locales/nl/tournament.json
+++ b/locales/nl/tournament.json
@@ -140,6 +140,12 @@
"finalize.receivingTeam.label": "",
"finalize.receivingTeam.placeholder": "",
"streams.none": "",
+ "run.sets": "",
+ "run.maps": "",
+ "run.qualifiedFor": "",
+ "run.firstTitle": "",
+ "run.latestTitle": "",
+ "run.seriesTitles": "",
"team.setWins": "",
"team.mapWins": "",
"team.seed": "",
diff --git a/locales/nl/user.json b/locales/nl/user.json
index ba2709109..974ecd494 100644
--- a/locales/nl/user.json
+++ b/locales/nl/user.json
@@ -186,6 +186,27 @@
"seasons.noReportedWeapons": "",
"seasons.clickARow": "",
"seasons.loading": "",
+ "seasons.summary.sets": "",
+ "seasons.summary.maps": "",
+ "seasons.summary.winStreak": "",
+ "seasons.summary.soloRank": "",
+ "seasons.summary.teamRank": "",
+ "seasons.summary.activity": "",
+ "seasons.summary.activity.tournament": "",
+ "seasons.summary.activity.both": "",
+ "seasons.summary.bestStage": "",
+ "seasons.summary.topWeapons": "",
+ "seasons.summary.topMates": "",
+ "seasons.summary.clutch": "",
+ "seasons.summary.bestWins": "",
+ "seasons.summary.bestTournament": "",
+ "seasons.summary.opponentSp": "",
+ "seasons.summary.count.sets_one": "",
+ "seasons.summary.count.sets_other": "",
+ "seasons.summary.count.maps_one": "",
+ "seasons.summary.count.maps_other": "",
+ "seasons.summary.export": "",
+ "seasons.summary.export.supporterPerk": "",
"builds.sorting.changeButton": "",
"builds.sorting.header": "",
"builds.sorting.backToDefaults": "",
diff --git a/locales/pl/common.json b/locales/pl/common.json
index 531f845e6..b92241893 100644
--- a/locales/pl/common.json
+++ b/locales/pl/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "",
"actions.noOutline": "",
"actions.join": "Dołącz",
+ "imageExport.export": "",
+ "imageExport.download": "",
+ "imageExport.theme.light": "",
+ "imageExport.theme.dark": "",
+ "imageExport.theme.lightCustom": "",
+ "imageExport.theme.darkCustom": "",
+ "imageExport.qrCode": "",
+ "imageExport.buildTitle": "",
+ "imageExport.abilityPoints": "",
+ "imageExport.abilityChunks": "",
"host": "",
"seed": "",
"actions.nevermind": "",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "",
"support.perk.useBotToLogIn.extra": "",
"support.perk.earlyAccess": "",
+ "support.perk.seasonSummaryImage": "",
+ "support.perk.seasonSummaryImage.extra": "",
"custom.colors.title": "Niestandardowe kolory",
"custom.colors.bg": "Tło",
"custom.colors.bg-darker": "Ciemniejsze tło",
diff --git a/locales/pl/tier-list-maker.json b/locales/pl/tier-list-maker.json
index f8d8ab98b..d869c964f 100644
--- a/locales/pl/tier-list-maker.json
+++ b/locales/pl/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "",
- "download": "",
"mainWeapons": "",
"subWeapons": "",
"specialWeapons": "",
@@ -18,7 +17,8 @@
"resetConfirmation": "",
"noDuplicates": "",
"showTierHeaders": "",
- "titlePlaceholder": "",
+ "title": "",
+ "showUsername": "",
"by": "",
"custom": ""
}
diff --git a/locales/pl/tournament.json b/locales/pl/tournament.json
index fe45d19ab..ef79292d9 100644
--- a/locales/pl/tournament.json
+++ b/locales/pl/tournament.json
@@ -144,6 +144,12 @@
"finalize.receivingTeam.label": "",
"finalize.receivingTeam.placeholder": "",
"streams.none": "",
+ "run.sets": "",
+ "run.maps": "",
+ "run.qualifiedFor": "",
+ "run.firstTitle": "",
+ "run.latestTitle": "",
+ "run.seriesTitles": "",
"team.setWins": "",
"team.mapWins": "",
"team.seed": "",
diff --git a/locales/pl/user.json b/locales/pl/user.json
index 765dc91bc..8fa45d203 100644
--- a/locales/pl/user.json
+++ b/locales/pl/user.json
@@ -186,6 +186,31 @@
"seasons.noReportedWeapons": "",
"seasons.clickARow": "",
"seasons.loading": "",
+ "seasons.summary.sets": "",
+ "seasons.summary.maps": "",
+ "seasons.summary.winStreak": "",
+ "seasons.summary.soloRank": "",
+ "seasons.summary.teamRank": "",
+ "seasons.summary.activity": "",
+ "seasons.summary.activity.tournament": "",
+ "seasons.summary.activity.both": "",
+ "seasons.summary.bestStage": "",
+ "seasons.summary.topWeapons": "",
+ "seasons.summary.topMates": "",
+ "seasons.summary.clutch": "",
+ "seasons.summary.bestWins": "",
+ "seasons.summary.bestTournament": "",
+ "seasons.summary.opponentSp": "",
+ "seasons.summary.count.sets_one": "",
+ "seasons.summary.count.sets_few": "",
+ "seasons.summary.count.sets_many": "",
+ "seasons.summary.count.sets_other": "",
+ "seasons.summary.count.maps_one": "",
+ "seasons.summary.count.maps_few": "",
+ "seasons.summary.count.maps_many": "",
+ "seasons.summary.count.maps_other": "",
+ "seasons.summary.export": "",
+ "seasons.summary.export.supporterPerk": "",
"builds.sorting.changeButton": "",
"builds.sorting.header": "",
"builds.sorting.backToDefaults": "",
diff --git a/locales/pt-BR/common.json b/locales/pt-BR/common.json
index 3b3a84aab..5ab4b754b 100644
--- a/locales/pt-BR/common.json
+++ b/locales/pt-BR/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "",
"actions.noOutline": "",
"actions.join": "Entrar",
+ "imageExport.export": "",
+ "imageExport.download": "",
+ "imageExport.theme.light": "",
+ "imageExport.theme.dark": "",
+ "imageExport.theme.lightCustom": "",
+ "imageExport.theme.darkCustom": "",
+ "imageExport.qrCode": "",
+ "imageExport.buildTitle": "",
+ "imageExport.abilityPoints": "",
+ "imageExport.abilityChunks": "",
"host": "",
"seed": "",
"actions.nevermind": "Deixa pra lá...",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "",
"support.perk.useBotToLogIn.extra": "",
"support.perk.earlyAccess": "",
+ "support.perk.seasonSummaryImage": "",
+ "support.perk.seasonSummaryImage.extra": "",
"custom.colors.title": "Cores personalizadas",
"custom.colors.bg": "Plano de fundo",
"custom.colors.bg-darker": "Plano de fundo mais escuro",
diff --git a/locales/pt-BR/tier-list-maker.json b/locales/pt-BR/tier-list-maker.json
index f8d8ab98b..d869c964f 100644
--- a/locales/pt-BR/tier-list-maker.json
+++ b/locales/pt-BR/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "",
- "download": "",
"mainWeapons": "",
"subWeapons": "",
"specialWeapons": "",
@@ -18,7 +17,8 @@
"resetConfirmation": "",
"noDuplicates": "",
"showTierHeaders": "",
- "titlePlaceholder": "",
+ "title": "",
+ "showUsername": "",
"by": "",
"custom": ""
}
diff --git a/locales/pt-BR/tournament.json b/locales/pt-BR/tournament.json
index 5a1f53909..6e6cb3274 100644
--- a/locales/pt-BR/tournament.json
+++ b/locales/pt-BR/tournament.json
@@ -142,6 +142,12 @@
"finalize.receivingTeam.label": "",
"finalize.receivingTeam.placeholder": "",
"streams.none": "Nenhuma transmissão desse evento está disponível no momento",
+ "run.sets": "",
+ "run.maps": "",
+ "run.qualifiedFor": "",
+ "run.firstTitle": "",
+ "run.latestTitle": "",
+ "run.seriesTitles": "",
"team.setWins": "Vitórias de set",
"team.mapWins": "Vitórias em mapa",
"team.seed": "Semente",
diff --git a/locales/pt-BR/user.json b/locales/pt-BR/user.json
index feda07d9c..d09c981c4 100644
--- a/locales/pt-BR/user.json
+++ b/locales/pt-BR/user.json
@@ -186,6 +186,29 @@
"seasons.noReportedWeapons": "As armas ainda não foram declaradas",
"seasons.clickARow": "Clique em uma fileira pra ver as estatísticas de uso da arma",
"seasons.loading": "Carregando...",
+ "seasons.summary.sets": "",
+ "seasons.summary.maps": "",
+ "seasons.summary.winStreak": "",
+ "seasons.summary.soloRank": "",
+ "seasons.summary.teamRank": "",
+ "seasons.summary.activity": "",
+ "seasons.summary.activity.tournament": "",
+ "seasons.summary.activity.both": "",
+ "seasons.summary.bestStage": "",
+ "seasons.summary.topWeapons": "",
+ "seasons.summary.topMates": "",
+ "seasons.summary.clutch": "",
+ "seasons.summary.bestWins": "",
+ "seasons.summary.bestTournament": "",
+ "seasons.summary.opponentSp": "",
+ "seasons.summary.count.sets_one": "",
+ "seasons.summary.count.sets_many": "",
+ "seasons.summary.count.sets_other": "",
+ "seasons.summary.count.maps_one": "",
+ "seasons.summary.count.maps_many": "",
+ "seasons.summary.count.maps_other": "",
+ "seasons.summary.export": "",
+ "seasons.summary.export.supporterPerk": "",
"builds.sorting.changeButton": "",
"builds.sorting.header": "",
"builds.sorting.backToDefaults": "",
diff --git a/locales/ru/common.json b/locales/ru/common.json
index f99270bc3..d4891bcd4 100644
--- a/locales/ru/common.json
+++ b/locales/ru/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "Обводка",
"actions.noOutline": "Без обводки",
"actions.join": "Присоединиться",
+ "imageExport.export": "",
+ "imageExport.download": "",
+ "imageExport.theme.light": "",
+ "imageExport.theme.dark": "",
+ "imageExport.theme.lightCustom": "",
+ "imageExport.theme.darkCustom": "",
+ "imageExport.qrCode": "",
+ "imageExport.buildTitle": "",
+ "imageExport.abilityPoints": "",
+ "imageExport.abilityChunks": "",
"host": "",
"seed": "",
"actions.nevermind": "Отмена",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "Лог-ин через Discord бот",
"support.perk.useBotToLogIn.extra": "Возможность запрость лог-ин ссылку от бота Lohi как альтернатива обычному лог-ину",
"support.perk.earlyAccess": "",
+ "support.perk.seasonSummaryImage": "",
+ "support.perk.seasonSummaryImage.extra": "",
"custom.colors.title": "Пользовательские цвета",
"custom.colors.bg": "Фон",
"custom.colors.bg-darker": "Фон темнее",
diff --git a/locales/ru/tier-list-maker.json b/locales/ru/tier-list-maker.json
index f8d8ab98b..d869c964f 100644
--- a/locales/ru/tier-list-maker.json
+++ b/locales/ru/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "",
- "download": "",
"mainWeapons": "",
"subWeapons": "",
"specialWeapons": "",
@@ -18,7 +17,8 @@
"resetConfirmation": "",
"noDuplicates": "",
"showTierHeaders": "",
- "titlePlaceholder": "",
+ "title": "",
+ "showUsername": "",
"by": "",
"custom": ""
}
diff --git a/locales/ru/tournament.json b/locales/ru/tournament.json
index caa3438af..447a01c45 100644
--- a/locales/ru/tournament.json
+++ b/locales/ru/tournament.json
@@ -144,6 +144,12 @@
"finalize.receivingTeam.label": "",
"finalize.receivingTeam.placeholder": "",
"streams.none": "На данный момент нет трансляций этого турнира",
+ "run.sets": "",
+ "run.maps": "",
+ "run.qualifiedFor": "",
+ "run.firstTitle": "",
+ "run.latestTitle": "",
+ "run.seriesTitles": "",
"team.setWins": "Победы в раундах",
"team.mapWins": "Победы в матчах",
"team.seed": "Семя",
diff --git a/locales/ru/user.json b/locales/ru/user.json
index f07ae214c..cb5d0140d 100644
--- a/locales/ru/user.json
+++ b/locales/ru/user.json
@@ -186,6 +186,31 @@
"seasons.noReportedWeapons": "Нет записанного оружия",
"seasons.clickARow": "Нажмите на ряд, чтобы посмотреть на статистику использованного оружия.",
"seasons.loading": "Загрузка...",
+ "seasons.summary.sets": "",
+ "seasons.summary.maps": "",
+ "seasons.summary.winStreak": "",
+ "seasons.summary.soloRank": "",
+ "seasons.summary.teamRank": "",
+ "seasons.summary.activity": "",
+ "seasons.summary.activity.tournament": "",
+ "seasons.summary.activity.both": "",
+ "seasons.summary.bestStage": "",
+ "seasons.summary.topWeapons": "",
+ "seasons.summary.topMates": "",
+ "seasons.summary.clutch": "",
+ "seasons.summary.bestWins": "",
+ "seasons.summary.bestTournament": "",
+ "seasons.summary.opponentSp": "",
+ "seasons.summary.count.sets_one": "",
+ "seasons.summary.count.sets_few": "",
+ "seasons.summary.count.sets_many": "",
+ "seasons.summary.count.sets_other": "",
+ "seasons.summary.count.maps_one": "",
+ "seasons.summary.count.maps_few": "",
+ "seasons.summary.count.maps_many": "",
+ "seasons.summary.count.maps_other": "",
+ "seasons.summary.export": "",
+ "seasons.summary.export.supporterPerk": "",
"builds.sorting.changeButton": "Изменить сортировку",
"builds.sorting.header": "Изменить сортировку сборок",
"builds.sorting.backToDefaults": "По умолчанию",
diff --git a/locales/zh/common.json b/locales/zh/common.json
index 701fd99f9..5407ef986 100644
--- a/locales/zh/common.json
+++ b/locales/zh/common.json
@@ -149,6 +149,16 @@
"actions.outlined": "描边",
"actions.noOutline": "无描边",
"actions.join": "加入",
+ "imageExport.export": "",
+ "imageExport.download": "",
+ "imageExport.theme.light": "",
+ "imageExport.theme.dark": "",
+ "imageExport.theme.lightCustom": "",
+ "imageExport.theme.darkCustom": "",
+ "imageExport.qrCode": "",
+ "imageExport.buildTitle": "",
+ "imageExport.abilityPoints": "",
+ "imageExport.abilityChunks": "",
"host": "房主",
"seed": "{{number}} 号种子",
"actions.nevermind": "反悔",
@@ -287,6 +297,8 @@
"support.perk.useBotToLogIn": "通过 Discord 机器人登录",
"support.perk.useBotToLogIn.extra": "向 Lohi 机器人请求一个登录链接,以此作为网站常规登录方式的备选方案",
"support.perk.earlyAccess": "部分新功能的优先体验权",
+ "support.perk.seasonSummaryImage": "",
+ "support.perk.seasonSummaryImage.extra": "",
"custom.colors.title": "自定义颜色",
"custom.colors.bg": "背景",
"custom.colors.bg-darker": "更暗背景",
diff --git a/locales/zh/tier-list-maker.json b/locales/zh/tier-list-maker.json
index 405ae0a64..36577dc4e 100644
--- a/locales/zh/tier-list-maker.json
+++ b/locales/zh/tier-list-maker.json
@@ -1,6 +1,5 @@
{
"addTier": "添加分级",
- "download": "下载图片 (.png)",
"mainWeapons": "主要武器",
"subWeapons": "次要武器",
"specialWeapons": "特殊武器",
@@ -18,7 +17,8 @@
"resetConfirmation": "您确定要重置强度榜吗?这将移除所有项目并恢复默认分级。",
"noDuplicates": "",
"showTierHeaders": "显示分级标题",
- "titlePlaceholder": "点击添加标题...",
+ "title": "",
+ "showUsername": "",
"by": "制作者: ",
"custom": "自定义"
}
diff --git a/locales/zh/tournament.json b/locales/zh/tournament.json
index 32caa1c54..6aba89afa 100644
--- a/locales/zh/tournament.json
+++ b/locales/zh/tournament.json
@@ -138,6 +138,12 @@
"finalize.receivingTeam.label": "接收队伍",
"finalize.receivingTeam.placeholder": "选择队伍...",
"streams.none": "目前暂无此赛事的实时直播",
+ "run.sets": "",
+ "run.maps": "",
+ "run.qualifiedFor": "",
+ "run.firstTitle": "",
+ "run.latestTitle": "",
+ "run.seriesTitles": "",
"team.setWins": "胜利轮数",
"team.mapWins": "胜利局数",
"team.seed": "种子",
diff --git a/locales/zh/user.json b/locales/zh/user.json
index 0cf5b0a32..ec841dc0b 100644
--- a/locales/zh/user.json
+++ b/locales/zh/user.json
@@ -186,6 +186,23 @@
"seasons.noReportedWeapons": "暂无汇报的武器",
"seasons.clickARow": "点击一行以查看武器使用数据",
"seasons.loading": "加载中...",
+ "seasons.summary.sets": "",
+ "seasons.summary.maps": "",
+ "seasons.summary.winStreak": "",
+ "seasons.summary.soloRank": "",
+ "seasons.summary.teamRank": "",
+ "seasons.summary.activity": "",
+ "seasons.summary.activity.tournament": "",
+ "seasons.summary.activity.both": "",
+ "seasons.summary.bestStage": "",
+ "seasons.summary.topWeapons": "",
+ "seasons.summary.topMates": "",
+ "seasons.summary.clutch": "",
+ "seasons.summary.bestWins": "",
+ "seasons.summary.bestTournament": "",
+ "seasons.summary.opponentSp": "",
+ "seasons.summary.export": "",
+ "seasons.summary.export.supporterPerk": "",
"builds.sorting.changeButton": "更改排序方式",
"builds.sorting.header": "更改配装排序方式",
"builds.sorting.backToDefaults": "恢复默认",
diff --git a/scripts/benchmark-db/cases.ts b/scripts/benchmark-db/cases.ts
index 3cb73546e..90338ae71 100644
--- a/scripts/benchmark-db/cases.ts
+++ b/scripts/benchmark-db/cases.ts
@@ -369,6 +369,9 @@ export function buildCases(fx: Fixtures): {
add("SkillRepository.findSeasonProgressionByUserId", fx.sq, (sq) =>
SkillRepository.findSeasonProgressionByUserId(sq),
);
+ add("SkillRepository.findSeasonActiveDaysByUserId", fx.sq, (sq) =>
+ SkillRepository.findSeasonActiveDaysByUserId(sq),
+ );
// NotificationRepository
add("NotificationRepository.findByUserId", fx.notification, (notification) =>
@@ -480,6 +483,15 @@ export function buildCases(fx: Fixtures): {
type: "MATE",
}),
);
+ add("PlayerStatRepository.findSeasonSetScoresByUserId", fx.sq, (sq) =>
+ PlayerStatRepository.findSeasonSetScoresByUserId(sq),
+ );
+ add("PlayerStatRepository.findSeasonBestSetsByUserId", fx.sq, (sq) =>
+ PlayerStatRepository.findSeasonBestSetsByUserId({ ...sq, limit: 3 }),
+ );
+ add("PlayerStatRepository.findSeasonTournamentRunsByUserId", fx.sq, (sq) =>
+ PlayerStatRepository.findSeasonTournamentRunsByUserId(sq),
+ );
// ReportedWeaponRepository
add(
@@ -979,6 +991,9 @@ export function buildCases(fx: Fixtures): {
add("UserRepository.findIdByIdentifier", fx.heavyUser, (user) =>
UserRepository.findIdByIdentifier(user.identifier),
);
+ add("UserRepository.findCountriesByUserIds", fx.skillBatch, (skillBatch) =>
+ UserRepository.findCountriesByUserIds(skillBatch.userIds),
+ );
add("UserRepository.findBuildFieldsByIdentifier", fx.heavyUser, (user) =>
UserRepository.findBuildFieldsByIdentifier(user.identifier),
);
diff --git a/scripts/benchmark-db/fixtures.ts b/scripts/benchmark-db/fixtures.ts
index 983db3ac7..c39e82aad 100644
--- a/scripts/benchmark-db/fixtures.ts
+++ b/scripts/benchmark-db/fixtures.ts
@@ -557,7 +557,7 @@ async function resolveCalendarAuthorId() {
async function resolveCalendarWindow() {
const row = await db
.selectFrom("CalendarEventDate")
- .select(({ fn }) => fn.max("startTime").as("maxStartTime"))
+ .select(({ fn }) => fn.max("startsAt").as("maxStartTime"))
.executeTakeFirst();
if (typeof row?.maxStartTime !== "number") return null;
@@ -569,7 +569,7 @@ async function resolveCalendarWindow() {
async function resolveScrimWindow() {
const row = await db
.selectFrom("ScrimPost")
- .select(({ fn }) => fn.max("at").as("maxAt"))
+ .select(({ fn }) => fn.max("startsAt").as("maxAt"))
.executeTakeFirst();
if (typeof row?.maxAt !== "number") return null;