diff --git a/app/features/front-page/components/PWAInstallBanner.module.css b/app/features/front-page/components/PWAInstallBanner.module.css
new file mode 100644
index 000000000..aeac4abe1
--- /dev/null
+++ b/app/features/front-page/components/PWAInstallBanner.module.css
@@ -0,0 +1,62 @@
+.banner {
+ /* needed for firefox to have a valid output */
+ --l: 50%;
+
+ position: relative;
+ background: linear-gradient(
+ to right,
+ var(--color-bg),
+ var(--l),
+ var(--color-bg-higher)
+ );
+ border: var(--border-style-high);
+ border-radius: var(--radius-box);
+ padding: var(--s-4);
+ overflow: hidden;
+}
+
+.bannerContent {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: var(--s-2);
+ padding-inline-end: min(130px, 30%);
+ line-height: 1.15;
+}
+
+.bannerTitle {
+ font-size: var(--font-lg);
+ font-weight: var(--weight-bold);
+ margin: 0;
+}
+
+.homeScreenIcon {
+ position: absolute;
+ right: var(--s-6);
+ top: 50%;
+ translate: 0 -50%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--s-1);
+}
+
+.homeScreenIconImg {
+ width: 56px;
+ border-radius: 22.5%;
+ box-shadow: 0 2px 6px rgb(0 0 0 / 25%);
+}
+
+.homeScreenIconLabel {
+ font-size: var(--font-2xs);
+ font-weight: var(--weight-semi);
+ color: var(--color-text);
+}
+
+.instructionsList {
+ display: flex;
+ flex-direction: column;
+ gap: var(--s-2);
+ margin: 0;
+ padding-inline-start: var(--s-6);
+}
diff --git a/app/features/front-page/components/PWAInstallBanner.tsx b/app/features/front-page/components/PWAInstallBanner.tsx
new file mode 100644
index 000000000..88b09d04d
--- /dev/null
+++ b/app/features/front-page/components/PWAInstallBanner.tsx
@@ -0,0 +1,188 @@
+import { Download } from "lucide-react";
+import * as React from "react";
+import { useTranslation } from "react-i18next";
+import { SendouButton } from "~/components/elements/Button";
+import { SendouDialog } from "~/components/elements/Dialog";
+import styles from "./PWAInstallBanner.module.css";
+
+interface BeforeInstallPromptEvent extends Event {
+ prompt: () => Promise<{ outcome: "accepted" | "dismissed" }>;
+}
+
+type InstallState = "hidden" | "native" | "ios" | "safari";
+
+const SAFARI_MIN_INSTALL_VERSION = 17;
+const BANNER_DISMISSED_KEY = "pwa-install-banner-dismissed";
+
+let deferredInstallPrompt: BeforeInstallPromptEvent | null = null;
+let bannerDismissed = false;
+const installStateListeners = new Set<() => void>();
+
+if (typeof window !== "undefined") {
+ try {
+ bannerDismissed = localStorage.getItem(BANNER_DISMISSED_KEY) === "true";
+ } catch {
+ // localStorage may be unavailable
+ }
+
+ window.addEventListener("beforeinstallprompt", (event) => {
+ event.preventDefault();
+ deferredInstallPrompt = event as BeforeInstallPromptEvent;
+ notifyInstallStateChanged();
+ });
+ window.addEventListener("appinstalled", () => {
+ deferredInstallPrompt = null;
+ notifyInstallStateChanged();
+ });
+}
+
+export function PWAInstallBanner() {
+ const { t } = useTranslation(["front", "common"]);
+ const installState = useInstallState();
+
+ if (installState === "hidden") return null;
+
+ return (
+
+
+
+ {t("front:install.banner.title")}
+
+
+ {t("front:install.banner.description")}
+
+
+
+
+ {t("common:actions.dismiss")}
+
+
+
+
+

+
sendou.ink
+
+
+ );
+}
+
+function InstallAction({
+ installState,
+}: {
+ installState: Exclude;
+}) {
+ const { t } = useTranslation(["front"]);
+
+ const installButton = (
+ }
+ onPress={
+ installState === "native"
+ ? () => deferredInstallPrompt?.prompt()
+ : undefined
+ }
+ >
+ {t("front:install.button")}
+
+ );
+
+ if (installState === "native") {
+ return installButton;
+ }
+
+ return (
+
+
+ - {t(`front:install.${installState}.step1`)}
+ - {t(`front:install.${installState}.step2`)}
+ - {t(`front:install.${installState}.step3`)}
+
+
+ );
+}
+
+function useInstallState() {
+ return React.useSyncExternalStore(
+ subscribeToInstallState,
+ getInstallStateSnapshot,
+ getServerInstallStateSnapshot,
+ );
+}
+
+function subscribeToInstallState(callback: () => void) {
+ installStateListeners.add(callback);
+ return () => installStateListeners.delete(callback);
+}
+
+function dismissBanner() {
+ bannerDismissed = true;
+ try {
+ localStorage.setItem(BANNER_DISMISSED_KEY, "true");
+ } catch {
+ // localStorage may be unavailable
+ }
+ notifyInstallStateChanged();
+}
+
+function getInstallStateSnapshot(): InstallState {
+ if (bannerDismissed) return "hidden";
+ if (isStandalone()) return "hidden";
+ if (deferredInstallPrompt) return "native";
+ if (isIos()) return "ios";
+ if (isInstallCapableSafariDesktop()) return "safari";
+ return "hidden";
+}
+
+function getServerInstallStateSnapshot(): InstallState {
+ return "hidden";
+}
+
+function notifyInstallStateChanged() {
+ for (const listener of installStateListeners) {
+ listener();
+ }
+}
+
+function isStandalone() {
+ return (
+ window.matchMedia("(display-mode: standalone)").matches ||
+ window.matchMedia("(display-mode: tabbed)").matches ||
+ (navigator as { standalone?: boolean }).standalone === true
+ );
+}
+
+function isIos() {
+ return (
+ /iPad|iPhone|iPod/.test(navigator.userAgent) ||
+ (navigator.userAgent.includes("Mac") && navigator.maxTouchPoints > 1)
+ );
+}
+
+function isInstallCapableSafariDesktop() {
+ const userAgent = navigator.userAgent;
+ const isSafari =
+ userAgent.includes("Safari") &&
+ !userAgent.includes("Chrome") &&
+ !userAgent.includes("Chromium");
+ if (!isSafari || !userAgent.includes("Mac")) return false;
+
+ const versionMatch = userAgent.match(/Version\/(\d+)/);
+ if (!versionMatch) return false;
+
+ return Number(versionMatch[1]) >= SAFARI_MIN_INSTALL_VERSION;
+}
diff --git a/app/features/front-page/routes/index.tsx b/app/features/front-page/routes/index.tsx
index c5b8b3ea6..330aee54d 100644
--- a/app/features/front-page/routes/index.tsx
+++ b/app/features/front-page/routes/index.tsx
@@ -14,6 +14,7 @@ import { LocaleTimeRange } from "~/components/LocaleTimeRange";
import { navItems } from "~/components/layout/nav-items";
import { Main } from "~/components/Main";
import { TournamentCard } from "~/features/calendar/components/TournamentCard";
+import { PWAInstallBanner } from "~/features/front-page/components/PWAInstallBanner";
import { SplatoonRotations } from "~/features/front-page/components/SplatoonRotations";
import type * as Changelog from "~/features/front-page/core/Changelog.server";
import * as Seasons from "~/features/mmr/core/Seasons";
@@ -309,6 +310,7 @@ function DiscoverFeatures() {
))}
+
);
}
diff --git a/locales/da/common.json b/locales/da/common.json
index ee4958a23..66d8575e1 100644
--- a/locales/da/common.json
+++ b/locales/da/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "",
"actions.create": "Skab",
"actions.close": "Luk",
+ "actions.dismiss": "",
"actions.cancel": "Annuller",
"actions.loading": "Indlæser...",
"actions.clear": "Ryd",
diff --git a/locales/da/front.json b/locales/da/front.json
index 0d3964023..c9c33047c 100644
--- a/locales/da/front.json
+++ b/locales/da/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "",
"rotations.credit": "",
"rotations.filter.all": "",
- "discover.header": ""
+ "discover.header": "",
+ "install.button": "",
+ "install.header": "",
+ "install.banner.title": "",
+ "install.banner.description": "",
+ "install.ios.step1": "",
+ "install.ios.step2": "",
+ "install.ios.step3": "",
+ "install.safari.step1": "",
+ "install.safari.step2": "",
+ "install.safari.step3": ""
}
diff --git a/locales/de/common.json b/locales/de/common.json
index 08a744b64..c6d200f64 100644
--- a/locales/de/common.json
+++ b/locales/de/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "Discord-Zeitstempel kopieren",
"actions.create": "Erstellen",
"actions.close": "Schließen",
+ "actions.dismiss": "",
"actions.cancel": "Abbrechen",
"actions.loading": "Lädt...",
"actions.clear": "Leeren",
diff --git a/locales/de/front.json b/locales/de/front.json
index 0d3964023..c9c33047c 100644
--- a/locales/de/front.json
+++ b/locales/de/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "",
"rotations.credit": "",
"rotations.filter.all": "",
- "discover.header": ""
+ "discover.header": "",
+ "install.button": "",
+ "install.header": "",
+ "install.banner.title": "",
+ "install.banner.description": "",
+ "install.ios.step1": "",
+ "install.ios.step2": "",
+ "install.ios.step3": "",
+ "install.safari.step1": "",
+ "install.safari.step2": "",
+ "install.safari.step3": ""
}
diff --git a/locales/en/common.json b/locales/en/common.json
index aa8742261..a78581ef4 100644
--- a/locales/en/common.json
+++ b/locales/en/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "Copy Discord timestamp",
"actions.create": "Create",
"actions.close": "Close",
+ "actions.dismiss": "Dismiss",
"actions.cancel": "Cancel",
"actions.loading": "Loading...",
"actions.clear": "Clear",
diff --git a/locales/en/front.json b/locales/en/front.json
index 424cd6274..23c31e255 100644
--- a/locales/en/front.json
+++ b/locales/en/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "Next",
"rotations.credit": "Data from splatoon3.ink",
"rotations.filter.all": "All",
- "discover.header": "Discover all the features"
+ "discover.header": "Discover all the features",
+ "install.button": "Install app",
+ "install.header": "Install sendou.ink",
+ "install.banner.title": "Get the sendou.ink app",
+ "install.banner.description": "Add sendou.ink to your home screen for quick access",
+ "install.ios.step1": "Tap the share button in your browser",
+ "install.ios.step2": "Select \"Add to Home Screen\"",
+ "install.ios.step3": "Tap \"Add\"",
+ "install.safari.step1": "Click the share button in Safari's toolbar",
+ "install.safari.step2": "Select \"Add to Dock\"",
+ "install.safari.step3": "Click \"Add\""
}
diff --git a/locales/es-ES/common.json b/locales/es-ES/common.json
index 66115f914..6c2fe3263 100644
--- a/locales/es-ES/common.json
+++ b/locales/es-ES/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "Copiar timestamp para Discord",
"actions.create": "Crear",
"actions.close": "Cerrar",
+ "actions.dismiss": "",
"actions.cancel": "Cancelar",
"actions.loading": "Cargando...",
"actions.clear": "Limpiar",
diff --git a/locales/es-ES/front.json b/locales/es-ES/front.json
index eee79a690..546b20009 100644
--- a/locales/es-ES/front.json
+++ b/locales/es-ES/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "",
"rotations.credit": "",
"rotations.filter.all": "",
- "discover.header": ""
+ "discover.header": "",
+ "install.button": "",
+ "install.header": "",
+ "install.banner.title": "",
+ "install.banner.description": "",
+ "install.ios.step1": "",
+ "install.ios.step2": "",
+ "install.ios.step3": "",
+ "install.safari.step1": "",
+ "install.safari.step2": "",
+ "install.safari.step3": ""
}
diff --git a/locales/es-US/common.json b/locales/es-US/common.json
index 492b77686..a60d00b23 100644
--- a/locales/es-US/common.json
+++ b/locales/es-US/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "",
"actions.create": "Crear",
"actions.close": "Cerrar",
+ "actions.dismiss": "",
"actions.cancel": "Cancelar",
"actions.loading": "Cargando...",
"actions.clear": "Aclarar",
diff --git a/locales/es-US/front.json b/locales/es-US/front.json
index 0d3964023..c9c33047c 100644
--- a/locales/es-US/front.json
+++ b/locales/es-US/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "",
"rotations.credit": "",
"rotations.filter.all": "",
- "discover.header": ""
+ "discover.header": "",
+ "install.button": "",
+ "install.header": "",
+ "install.banner.title": "",
+ "install.banner.description": "",
+ "install.ios.step1": "",
+ "install.ios.step2": "",
+ "install.ios.step3": "",
+ "install.safari.step1": "",
+ "install.safari.step2": "",
+ "install.safari.step3": ""
}
diff --git a/locales/fr-CA/common.json b/locales/fr-CA/common.json
index 60613675e..09ca5f2de 100644
--- a/locales/fr-CA/common.json
+++ b/locales/fr-CA/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "",
"actions.create": "Créer",
"actions.close": "Fermer",
+ "actions.dismiss": "",
"actions.cancel": "Annuler",
"actions.loading": "Chargement...",
"actions.clear": "Effacer",
diff --git a/locales/fr-CA/front.json b/locales/fr-CA/front.json
index 0d3964023..c9c33047c 100644
--- a/locales/fr-CA/front.json
+++ b/locales/fr-CA/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "",
"rotations.credit": "",
"rotations.filter.all": "",
- "discover.header": ""
+ "discover.header": "",
+ "install.button": "",
+ "install.header": "",
+ "install.banner.title": "",
+ "install.banner.description": "",
+ "install.ios.step1": "",
+ "install.ios.step2": "",
+ "install.ios.step3": "",
+ "install.safari.step1": "",
+ "install.safari.step2": "",
+ "install.safari.step3": ""
}
diff --git a/locales/fr-EU/common.json b/locales/fr-EU/common.json
index 19d40ac1f..7490ad3ed 100644
--- a/locales/fr-EU/common.json
+++ b/locales/fr-EU/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "",
"actions.create": "Créer",
"actions.close": "Fermer",
+ "actions.dismiss": "",
"actions.cancel": "Annuler le match",
"actions.loading": "Chargement...",
"actions.clear": "Effacer",
diff --git a/locales/fr-EU/front.json b/locales/fr-EU/front.json
index b30b52a3e..901ccea24 100644
--- a/locales/fr-EU/front.json
+++ b/locales/fr-EU/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "",
"rotations.credit": "",
"rotations.filter.all": "",
- "discover.header": ""
+ "discover.header": "",
+ "install.button": "",
+ "install.header": "",
+ "install.banner.title": "",
+ "install.banner.description": "",
+ "install.ios.step1": "",
+ "install.ios.step2": "",
+ "install.ios.step3": "",
+ "install.safari.step1": "",
+ "install.safari.step2": "",
+ "install.safari.step3": ""
}
diff --git a/locales/he/common.json b/locales/he/common.json
index 8b2170c9a..7ecb65f0f 100644
--- a/locales/he/common.json
+++ b/locales/he/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "",
"actions.create": "יצירה",
"actions.close": "סגירה",
+ "actions.dismiss": "",
"actions.cancel": "ביטול",
"actions.loading": "טוען...",
"actions.clear": "ניקוי",
diff --git a/locales/he/front.json b/locales/he/front.json
index 0d3964023..c9c33047c 100644
--- a/locales/he/front.json
+++ b/locales/he/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "",
"rotations.credit": "",
"rotations.filter.all": "",
- "discover.header": ""
+ "discover.header": "",
+ "install.button": "",
+ "install.header": "",
+ "install.banner.title": "",
+ "install.banner.description": "",
+ "install.ios.step1": "",
+ "install.ios.step2": "",
+ "install.ios.step3": "",
+ "install.safari.step1": "",
+ "install.safari.step2": "",
+ "install.safari.step3": ""
}
diff --git a/locales/it/common.json b/locales/it/common.json
index 971d99064..b77569349 100644
--- a/locales/it/common.json
+++ b/locales/it/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "",
"actions.create": "Crea",
"actions.close": "Chiudi",
+ "actions.dismiss": "",
"actions.cancel": "Cancella",
"actions.loading": "Caricamento in corso...",
"actions.clear": "Svuota",
diff --git a/locales/it/front.json b/locales/it/front.json
index 335f984d0..7f0e3a871 100644
--- a/locales/it/front.json
+++ b/locales/it/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "",
"rotations.credit": "",
"rotations.filter.all": "",
- "discover.header": ""
+ "discover.header": "",
+ "install.button": "",
+ "install.header": "",
+ "install.banner.title": "",
+ "install.banner.description": "",
+ "install.ios.step1": "",
+ "install.ios.step2": "",
+ "install.ios.step3": "",
+ "install.safari.step1": "",
+ "install.safari.step2": "",
+ "install.safari.step3": ""
}
diff --git a/locales/ja/common.json b/locales/ja/common.json
index 877d54a76..4082df256 100644
--- a/locales/ja/common.json
+++ b/locales/ja/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "",
"actions.create": "作成",
"actions.close": "閉じる",
+ "actions.dismiss": "",
"actions.cancel": "キャンセル",
"actions.loading": "Loading...",
"actions.clear": "クリア",
diff --git a/locales/ja/front.json b/locales/ja/front.json
index 0d3964023..c9c33047c 100644
--- a/locales/ja/front.json
+++ b/locales/ja/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "",
"rotations.credit": "",
"rotations.filter.all": "",
- "discover.header": ""
+ "discover.header": "",
+ "install.button": "",
+ "install.header": "",
+ "install.banner.title": "",
+ "install.banner.description": "",
+ "install.ios.step1": "",
+ "install.ios.step2": "",
+ "install.ios.step3": "",
+ "install.safari.step1": "",
+ "install.safari.step2": "",
+ "install.safari.step3": ""
}
diff --git a/locales/ko/common.json b/locales/ko/common.json
index fc2ec26b1..23294439f 100644
--- a/locales/ko/common.json
+++ b/locales/ko/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "",
"actions.create": "생성",
"actions.close": "닫기",
+ "actions.dismiss": "",
"actions.cancel": "취소",
"actions.loading": "로딩 중...",
"actions.clear": "비우기",
diff --git a/locales/ko/front.json b/locales/ko/front.json
index 0d3964023..c9c33047c 100644
--- a/locales/ko/front.json
+++ b/locales/ko/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "",
"rotations.credit": "",
"rotations.filter.all": "",
- "discover.header": ""
+ "discover.header": "",
+ "install.button": "",
+ "install.header": "",
+ "install.banner.title": "",
+ "install.banner.description": "",
+ "install.ios.step1": "",
+ "install.ios.step2": "",
+ "install.ios.step3": "",
+ "install.safari.step1": "",
+ "install.safari.step2": "",
+ "install.safari.step3": ""
}
diff --git a/locales/nl/common.json b/locales/nl/common.json
index 2dfd88b5d..8282032fe 100644
--- a/locales/nl/common.json
+++ b/locales/nl/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "",
"actions.create": "",
"actions.close": "",
+ "actions.dismiss": "",
"actions.cancel": "",
"actions.loading": "",
"actions.clear": "",
diff --git a/locales/nl/front.json b/locales/nl/front.json
index 0d3964023..c9c33047c 100644
--- a/locales/nl/front.json
+++ b/locales/nl/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "",
"rotations.credit": "",
"rotations.filter.all": "",
- "discover.header": ""
+ "discover.header": "",
+ "install.button": "",
+ "install.header": "",
+ "install.banner.title": "",
+ "install.banner.description": "",
+ "install.ios.step1": "",
+ "install.ios.step2": "",
+ "install.ios.step3": "",
+ "install.safari.step1": "",
+ "install.safari.step2": "",
+ "install.safari.step3": ""
}
diff --git a/locales/pl/common.json b/locales/pl/common.json
index c3408e935..347b56286 100644
--- a/locales/pl/common.json
+++ b/locales/pl/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "",
"actions.create": "Stwórz",
"actions.close": "Zamknij",
+ "actions.dismiss": "",
"actions.cancel": "Anuluj",
"actions.loading": "Ładowanie...",
"actions.clear": "Wyczyść",
diff --git a/locales/pl/front.json b/locales/pl/front.json
index 0d3964023..c9c33047c 100644
--- a/locales/pl/front.json
+++ b/locales/pl/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "",
"rotations.credit": "",
"rotations.filter.all": "",
- "discover.header": ""
+ "discover.header": "",
+ "install.button": "",
+ "install.header": "",
+ "install.banner.title": "",
+ "install.banner.description": "",
+ "install.ios.step1": "",
+ "install.ios.step2": "",
+ "install.ios.step3": "",
+ "install.safari.step1": "",
+ "install.safari.step2": "",
+ "install.safari.step3": ""
}
diff --git a/locales/pt-BR/common.json b/locales/pt-BR/common.json
index bdd3bdbfd..0b9a927bc 100644
--- a/locales/pt-BR/common.json
+++ b/locales/pt-BR/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "",
"actions.create": "Criar",
"actions.close": "Fechar",
+ "actions.dismiss": "",
"actions.cancel": "Cancelar",
"actions.loading": "Carregando...",
"actions.clear": "Limpar",
diff --git a/locales/pt-BR/front.json b/locales/pt-BR/front.json
index 0d3964023..c9c33047c 100644
--- a/locales/pt-BR/front.json
+++ b/locales/pt-BR/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "",
"rotations.credit": "",
"rotations.filter.all": "",
- "discover.header": ""
+ "discover.header": "",
+ "install.button": "",
+ "install.header": "",
+ "install.banner.title": "",
+ "install.banner.description": "",
+ "install.ios.step1": "",
+ "install.ios.step2": "",
+ "install.ios.step3": "",
+ "install.safari.step1": "",
+ "install.safari.step2": "",
+ "install.safari.step3": ""
}
diff --git a/locales/ru/common.json b/locales/ru/common.json
index 6c5d3deb4..0a0623af4 100644
--- a/locales/ru/common.json
+++ b/locales/ru/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "",
"actions.create": "Создать",
"actions.close": "Закрыть",
+ "actions.dismiss": "",
"actions.cancel": "Отменить",
"actions.loading": "Загрузка...",
"actions.clear": "Очистить",
diff --git a/locales/ru/front.json b/locales/ru/front.json
index 97c7cd0c2..5a870e114 100644
--- a/locales/ru/front.json
+++ b/locales/ru/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "",
"rotations.credit": "",
"rotations.filter.all": "",
- "discover.header": ""
+ "discover.header": "",
+ "install.button": "",
+ "install.header": "",
+ "install.banner.title": "",
+ "install.banner.description": "",
+ "install.ios.step1": "",
+ "install.ios.step2": "",
+ "install.ios.step3": "",
+ "install.safari.step1": "",
+ "install.safari.step2": "",
+ "install.safari.step3": ""
}
diff --git a/locales/zh/common.json b/locales/zh/common.json
index 89f7952ca..70d9e7dc1 100644
--- a/locales/zh/common.json
+++ b/locales/zh/common.json
@@ -126,6 +126,7 @@
"actions.copyTimestampForDiscord": "",
"actions.create": "创建",
"actions.close": "关闭",
+ "actions.dismiss": "",
"actions.cancel": "取消",
"actions.loading": "加载中...",
"actions.clear": "清除",
diff --git a/locales/zh/front.json b/locales/zh/front.json
index 0d3964023..c9c33047c 100644
--- a/locales/zh/front.json
+++ b/locales/zh/front.json
@@ -40,5 +40,15 @@
"rotations.nextLabel": "",
"rotations.credit": "",
"rotations.filter.all": "",
- "discover.header": ""
+ "discover.header": "",
+ "install.button": "",
+ "install.header": "",
+ "install.banner.title": "",
+ "install.banner.description": "",
+ "install.ios.step1": "",
+ "install.ios.step2": "",
+ "install.ios.step3": "",
+ "install.safari.step1": "",
+ "install.safari.step2": "",
+ "install.safari.step3": ""
}