Fix: localize the PWA install prompt
The PWA install prompt was hardcoded English regardless of the selected UI
language (and the large English block tripped Chrome's translate popup on
Android). Add a pwa_install namespace to all 17 locales, switch the component
to useTranslations, and move <PWAInstallPrompt /> from (main)/layout into
(main)/[locale]/layout so it renders inside the IntlProvider. The title keeps
the dynamic {appName}, so per-domain branding still applies.
This commit is contained in:
@@ -9,6 +9,7 @@ import { ProtocolLaunchHandlerProvider } from "@/components/protocol/protocol-la
|
|||||||
import { ProInterfaceRedirect } from "@/components/pro/pro-interface-redirect";
|
import { ProInterfaceRedirect } from "@/components/pro/pro-interface-redirect";
|
||||||
import { PluginDialogHost } from "@/components/plugins/plugin-dialog-host";
|
import { PluginDialogHost } from "@/components/plugins/plugin-dialog-host";
|
||||||
import { PluginConsentDialog } from "@/components/plugins/plugin-consent-dialog";
|
import { PluginConsentDialog } from "@/components/plugins/plugin-consent-dialog";
|
||||||
|
import { PWAInstallPrompt } from "@/components/pwa-install-prompt";
|
||||||
import { locales } from "@/i18n/routing";
|
import { locales } from "@/i18n/routing";
|
||||||
|
|
||||||
export default async function LocaleLayout({
|
export default async function LocaleLayout({
|
||||||
@@ -41,6 +42,7 @@ export default async function LocaleLayout({
|
|||||||
{children}
|
{children}
|
||||||
<PluginDialogHost />
|
<PluginDialogHost />
|
||||||
<PluginConsentDialog />
|
<PluginConsentDialog />
|
||||||
|
<PWAInstallPrompt />
|
||||||
</ProtocolLaunchHandlerProvider>
|
</ProtocolLaunchHandlerProvider>
|
||||||
</TourProvider>
|
</TourProvider>
|
||||||
</EmbeddedBridgeProvider>
|
</EmbeddedBridgeProvider>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import type { Metadata, Viewport } from "next";
|
|||||||
import { Geist, Geist_Mono } from "next/font/google";
|
import { Geist, Geist_Mono } from "next/font/google";
|
||||||
import { headers } from "next/headers";
|
import { headers } from "next/headers";
|
||||||
import { getLocale } from "next-intl/server";
|
import { getLocale } from "next-intl/server";
|
||||||
import { PWAInstallPrompt } from "@/components/pwa-install-prompt";
|
|
||||||
import { ServiceWorkerRegistration } from "@/components/service-worker-registration";
|
import { ServiceWorkerRegistration } from "@/components/service-worker-registration";
|
||||||
import { configManager } from "@/lib/admin/config-manager";
|
import { configManager } from "@/lib/admin/config-manager";
|
||||||
import { withBasePath } from "@/lib/browser-navigation";
|
import { withBasePath } from "@/lib/browser-navigation";
|
||||||
@@ -92,7 +91,6 @@ export default async function RootLayout({
|
|||||||
>
|
>
|
||||||
<ServiceWorkerRegistration />
|
<ServiceWorkerRegistration />
|
||||||
{children}
|
{children}
|
||||||
<PWAInstallPrompt />
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
import { X, Download } from "lucide-react";
|
import { X, Download } from "lucide-react";
|
||||||
import { useConfig } from "@/hooks/use-config";
|
import { useConfig } from "@/hooks/use-config";
|
||||||
import { withBasePath } from "@/lib/browser-navigation";
|
import { withBasePath } from "@/lib/browser-navigation";
|
||||||
@@ -17,6 +18,7 @@ export function PWAInstallPrompt() {
|
|||||||
useState<BeforeInstallPromptEvent | null>(null);
|
useState<BeforeInstallPromptEvent | null>(null);
|
||||||
const [showPrompt, setShowPrompt] = useState(false);
|
const [showPrompt, setShowPrompt] = useState(false);
|
||||||
const { appName, faviconUrl, appLogoLightUrl, appLogoDarkUrl } = useConfig();
|
const { appName, faviconUrl, appLogoLightUrl, appLogoDarkUrl } = useConfig();
|
||||||
|
const t = useTranslations("pwa_install");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (localStorage.getItem(DISMISSED_KEY)) return;
|
if (localStorage.getItem(DISMISSED_KEY)) return;
|
||||||
@@ -84,17 +86,17 @@ export function PWAInstallPrompt() {
|
|||||||
)}
|
)}
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold text-sm text-neutral-900 dark:text-white">
|
<h3 className="font-semibold text-sm text-neutral-900 dark:text-white">
|
||||||
Install {appName}
|
{t("title", { appName })}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-xs text-neutral-600 dark:text-neutral-400 mt-1">
|
<p className="text-xs text-neutral-600 dark:text-neutral-400 mt-1">
|
||||||
Install our app for quick access and offline support.
|
{t("description")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={handleDismiss}
|
onClick={handleDismiss}
|
||||||
className="text-neutral-400 hover:text-neutral-600 dark:hover:text-neutral-300 transition-colors"
|
className="text-neutral-400 hover:text-neutral-600 dark:hover:text-neutral-300 transition-colors"
|
||||||
aria-label="Dismiss install prompt"
|
aria-label={t("dismiss_aria")}
|
||||||
>
|
>
|
||||||
<X className="w-4 h-4" />
|
<X className="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
@@ -105,20 +107,20 @@ export function PWAInstallPrompt() {
|
|||||||
onClick={handleDismiss}
|
onClick={handleDismiss}
|
||||||
className="flex-1 px-3 py-2 text-sm font-medium text-neutral-700 dark:text-neutral-300 bg-neutral-100 dark:bg-neutral-800 rounded hover:bg-neutral-200 dark:hover:bg-neutral-700 transition-colors"
|
className="flex-1 px-3 py-2 text-sm font-medium text-neutral-700 dark:text-neutral-300 bg-neutral-100 dark:bg-neutral-800 rounded hover:bg-neutral-200 dark:hover:bg-neutral-700 transition-colors"
|
||||||
>
|
>
|
||||||
Not now
|
{t("not_now")}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={handleInstall}
|
onClick={handleInstall}
|
||||||
className="flex-1 px-3 py-2 text-sm font-medium text-white bg-blue-600 rounded hover:bg-blue-700 transition-colors"
|
className="flex-1 px-3 py-2 text-sm font-medium text-white bg-blue-600 rounded hover:bg-blue-700 transition-colors"
|
||||||
>
|
>
|
||||||
Install
|
{t("install")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={handleDismissForever}
|
onClick={handleDismissForever}
|
||||||
className="w-full text-xs text-neutral-400 hover:text-neutral-600 dark:hover:text-neutral-300 transition-colors text-center"
|
className="w-full text-xs text-neutral-400 hover:text-neutral-600 dark:hover:text-neutral-300 transition-colors text-center"
|
||||||
>
|
>
|
||||||
Don't remind me again
|
{t("dont_remind")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "Nainstalovat {appName}",
|
||||||
|
"description": "Nainstalujte si naši aplikaci pro rychlý přístup a offline podporu.",
|
||||||
|
"not_now": "Teď ne",
|
||||||
|
"install": "Nainstalovat",
|
||||||
|
"dont_remind": "Už mi to nepřipomínat",
|
||||||
|
"dismiss_aria": "Zavřít výzvu k instalaci"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Webmail",
|
"title": "Webmail",
|
||||||
"username_label": "E-mail",
|
"username_label": "E-mail",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "Installer {appName}",
|
||||||
|
"description": "Installer vores app for hurtig adgang og offline-understøttelse.",
|
||||||
|
"not_now": "Ikke nu",
|
||||||
|
"install": "Installer",
|
||||||
|
"dont_remind": "Påmind mig ikke igen",
|
||||||
|
"dismiss_aria": "Afvis installationsprompt"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Webmail",
|
"title": "Webmail",
|
||||||
"username_label": "Email",
|
"username_label": "Email",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "{appName} installieren",
|
||||||
|
"description": "Installiere unsere App für schnellen Zugriff und Offline-Unterstützung.",
|
||||||
|
"not_now": "Nicht jetzt",
|
||||||
|
"install": "Installieren",
|
||||||
|
"dont_remind": "Nicht mehr erinnern",
|
||||||
|
"dismiss_aria": "Installationshinweis schließen"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Webmail",
|
"title": "Webmail",
|
||||||
"username_label": "E-Mail",
|
"username_label": "E-Mail",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "Install {appName}",
|
||||||
|
"description": "Install our app for quick access and offline support.",
|
||||||
|
"not_now": "Not now",
|
||||||
|
"install": "Install",
|
||||||
|
"dont_remind": "Don't remind me again",
|
||||||
|
"dismiss_aria": "Dismiss install prompt"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Webmail",
|
"title": "Webmail",
|
||||||
"username_label": "Email",
|
"username_label": "Email",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "Instalar {appName}",
|
||||||
|
"description": "Instala nuestra app para un acceso rápido y soporte sin conexión.",
|
||||||
|
"not_now": "Ahora no",
|
||||||
|
"install": "Instalar",
|
||||||
|
"dont_remind": "No volver a recordármelo",
|
||||||
|
"dismiss_aria": "Cerrar aviso de instalación"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Correo Web",
|
"title": "Correo Web",
|
||||||
"username_label": "Correo electrónico",
|
"username_label": "Correo electrónico",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "Installer {appName}",
|
||||||
|
"description": "Installez notre application pour un accès rapide et un support hors ligne.",
|
||||||
|
"not_now": "Pas maintenant",
|
||||||
|
"install": "Installer",
|
||||||
|
"dont_remind": "Ne plus me le rappeler",
|
||||||
|
"dismiss_aria": "Fermer l'invite d'installation"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Webmail",
|
"title": "Webmail",
|
||||||
"username_label": "Email",
|
"username_label": "Email",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "Installa {appName}",
|
||||||
|
"description": "Installa la nostra app per un accesso rapido e il supporto offline.",
|
||||||
|
"not_now": "Non ora",
|
||||||
|
"install": "Installa",
|
||||||
|
"dont_remind": "Non ricordarmelo più",
|
||||||
|
"dismiss_aria": "Chiudi avviso di installazione"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Webmail",
|
"title": "Webmail",
|
||||||
"username_label": "Email",
|
"username_label": "Email",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "{appName} をインストール",
|
||||||
|
"description": "素早いアクセスとオフライン対応のため、アプリをインストールしましょう。",
|
||||||
|
"not_now": "後で",
|
||||||
|
"install": "インストール",
|
||||||
|
"dont_remind": "今後表示しない",
|
||||||
|
"dismiss_aria": "インストールプロンプトを閉じる"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "ウェブメール",
|
"title": "ウェブメール",
|
||||||
"username_label": "メールアドレス",
|
"username_label": "メールアドレス",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "{appName} 설치",
|
||||||
|
"description": "빠른 액세스와 오프라인 지원을 위해 앱을 설치하세요.",
|
||||||
|
"not_now": "나중에",
|
||||||
|
"install": "설치",
|
||||||
|
"dont_remind": "다시 알리지 않음",
|
||||||
|
"dismiss_aria": "설치 프롬프트 닫기"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "웹메일",
|
"title": "웹메일",
|
||||||
"username_label": "이메일",
|
"username_label": "이메일",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "Instalēt {appName}",
|
||||||
|
"description": "Instalējiet mūsu lietotni ātrai piekļuvei un bezsaistes atbalstam.",
|
||||||
|
"not_now": "Ne tagad",
|
||||||
|
"install": "Instalēt",
|
||||||
|
"dont_remind": "Vairs man neatgādināt",
|
||||||
|
"dismiss_aria": "Aizvērt instalēšanas paziņojumu"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Tīmekļa pasts",
|
"title": "Tīmekļa pasts",
|
||||||
"username_label": "E-pasta adrese",
|
"username_label": "E-pasta adrese",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "{appName} installeren",
|
||||||
|
"description": "Installeer onze app voor snelle toegang en offline-ondersteuning.",
|
||||||
|
"not_now": "Niet nu",
|
||||||
|
"install": "Installeren",
|
||||||
|
"dont_remind": "Niet meer herinneren",
|
||||||
|
"dismiss_aria": "Installatiemelding sluiten"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Webmail",
|
"title": "Webmail",
|
||||||
"username_label": "E-mail",
|
"username_label": "E-mail",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "Zainstaluj {appName}",
|
||||||
|
"description": "Zainstaluj naszą aplikację, aby uzyskać szybki dostęp i obsługę offline.",
|
||||||
|
"not_now": "Nie teraz",
|
||||||
|
"install": "Zainstaluj",
|
||||||
|
"dont_remind": "Nie przypominaj mi więcej",
|
||||||
|
"dismiss_aria": "Zamknij monit instalacji"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Webmail",
|
"title": "Webmail",
|
||||||
"username_label": "E-mail",
|
"username_label": "E-mail",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "Instalar {appName}",
|
||||||
|
"description": "Instale o nosso app para acesso rápido e suporte offline.",
|
||||||
|
"not_now": "Agora não",
|
||||||
|
"install": "Instalar",
|
||||||
|
"dont_remind": "Não lembrar novamente",
|
||||||
|
"dismiss_aria": "Dispensar aviso de instalação"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Webmail",
|
"title": "Webmail",
|
||||||
"username_label": "E-mail",
|
"username_label": "E-mail",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "Установить {appName}",
|
||||||
|
"description": "Установите наше приложение для быстрого доступа и работы офлайн.",
|
||||||
|
"not_now": "Не сейчас",
|
||||||
|
"install": "Установить",
|
||||||
|
"dont_remind": "Больше не напоминать",
|
||||||
|
"dismiss_aria": "Закрыть запрос на установку"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Веб-почта",
|
"title": "Веб-почта",
|
||||||
"username_label": "Электронная почта",
|
"username_label": "Электронная почта",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "{appName} uygulamasını yükle",
|
||||||
|
"description": "Hızlı erişim ve çevrimdışı destek için uygulamamızı yükleyin.",
|
||||||
|
"not_now": "Şimdi değil",
|
||||||
|
"install": "Yükle",
|
||||||
|
"dont_remind": "Bir daha hatırlatma",
|
||||||
|
"dismiss_aria": "Yükleme istemini kapat"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Webmail",
|
"title": "Webmail",
|
||||||
"username_label": "E-posta",
|
"username_label": "E-posta",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "Встановити {appName}",
|
||||||
|
"description": "Встановіть наш застосунок для швидкого доступу та офлайн-підтримки.",
|
||||||
|
"not_now": "Не зараз",
|
||||||
|
"install": "Встановити",
|
||||||
|
"dont_remind": "Більше не нагадувати",
|
||||||
|
"dismiss_aria": "Закрити запит на встановлення"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "Веб-пошта",
|
"title": "Веб-пошта",
|
||||||
"username_label": "Електронна пошта",
|
"username_label": "Електронна пошта",
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"pwa_install": {
|
||||||
|
"title": "安装 {appName}",
|
||||||
|
"description": "安装我们的应用,以获得快速访问和离线支持。",
|
||||||
|
"not_now": "暂不",
|
||||||
|
"install": "安装",
|
||||||
|
"dont_remind": "不再提醒",
|
||||||
|
"dismiss_aria": "关闭安装提示"
|
||||||
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "网页邮箱",
|
"title": "网页邮箱",
|
||||||
"username_label": "邮箱地址",
|
"username_label": "邮箱地址",
|
||||||
|
|||||||
Reference in New Issue
Block a user