= ({
open,
onClose,
diff --git a/web/apps/photos/src/pages/index.tsx b/web/apps/photos/src/pages/index.tsx
index d276aad67b..1796318bca 100644
--- a/web/apps/photos/src/pages/index.tsx
+++ b/web/apps/photos/src/pages/index.tsx
@@ -7,7 +7,11 @@ import { EnteLogo } from "ente-base/components/EnteLogo";
import { ActivityIndicator } from "ente-base/components/mui/ActivityIndicator";
import { FocusVisibleButton } from "ente-base/components/mui/FocusVisibleButton";
import { useBaseContext } from "ente-base/context";
-import { albumsAppOrigin, customAPIHost } from "ente-base/origins";
+import {
+ albumsAppOrigin,
+ customAPIHost,
+ shouldOnlyServeAlbumsApp,
+} from "ente-base/origins";
import {
masterKeyFromSession,
updateSessionFromElectronSafeStorageIfNeeded,
@@ -41,7 +45,8 @@ const Page: React.FC = () => {
const albumsURL = new URL(albumsAppOrigin());
currentURL.pathname = router.pathname;
if (
- currentURL.host == albumsURL.host &&
+ (shouldOnlyServeAlbumsApp ||
+ currentURL.host == albumsURL.host) &&
currentURL.pathname != "/shared-albums"
) {
const end = currentURL.hash.lastIndexOf("&");
diff --git a/web/packages/base/locales/pl-PL/translation.json b/web/packages/base/locales/pl-PL/translation.json
index ecbbff918f..064add62dc 100644
--- a/web/packages/base/locales/pl-PL/translation.json
+++ b/web/packages/base/locales/pl-PL/translation.json
@@ -62,8 +62,8 @@
"processed_counts": "{{count, number}} / {{total, number}}",
"upload_reading_metadata_files": "Czytanie plików metadanych",
"upload_cancelling": "Anulowanie pozostałych przesłań",
- "upload_done": "",
- "upload_skipped": "",
+ "upload_done": "Przesłano {{count, number}}",
+ "upload_skipped": "Pominięto {{count, number}}",
"initial_load_delay_warning": "Pierwsze ładowanie może zająć trochę czasu",
"no_account": "Nie mam konta",
"existing_account": "Posiadam już konto",
@@ -84,12 +84,12 @@
"tap_outside_image": "Dotknij na zewnątrz obrazu",
"shortcuts": "Skróty",
"show_shortcuts": "Pokaż skróty",
- "zoom_preset": "",
- "toggle_controls": "",
+ "zoom_preset": "Ustawienie powiększenia",
+ "toggle_controls": "Przełącz kontrolki",
"toggle_live": "",
- "toggle_audio": "",
- "toggle_favorite": "",
- "toggle_archive": "",
+ "toggle_audio": "Przełącz dźwięk",
+ "toggle_favorite": "Przełącz ulubione",
+ "toggle_archive": "Przełącz archiwizację",
"view_info": "Zobacz informacje",
"copy_as_png": "Kopiuj jako PNG",
"toggle_fullscreen": "Przełącz tryb pełnoekranowy",
diff --git a/web/packages/base/locales/vi-VN/translation.json b/web/packages/base/locales/vi-VN/translation.json
index f3dec27f76..fdd39566fb 100644
--- a/web/packages/base/locales/vi-VN/translation.json
+++ b/web/packages/base/locales/vi-VN/translation.json
@@ -515,7 +515,7 @@
"enter_name": "Nhập tên",
"uploader_name_hint": "Thêm tên để bạn bè biết ai là người chụp những tấm ảnh tuyệt vời này!",
"name_placeholder": "Tên...",
- "more_details": "Thêm chi tiết",
+ "more_details": "Thông tin thêm",
"ml_search": "Học máy",
"ml_search_description": "Ente hỗ trợ học máy trên-thiết-bị nhằm nhận diện khuôn mặt, tìm kiếm vi diệu và các tính năng tìm kiếm nâng cao khác",
"ml_search_footnote": "Tìm kiếm vi diệu cho phép tìm ảnh theo nội dung của chúng, ví dụ: 'xe hơi', 'xe hơi đỏ', 'Ferrari'",
@@ -560,13 +560,13 @@
"delete_account_reason_placeholder": "Chọn một lý do",
"delete_reason": {
"missing_feature": "Thiếu một tính năng quan trọng mà tôi cần",
- "behaviour": "Ứng dụng hoặc một tính năng nhất định không hoạt động như tôi muốn",
+ "behaviour": "Ứng dụng hoặc một tính năng không hoạt động như tôi muốn",
"found_another_service": "Tôi tìm thấy một dịch vụ khác mà tôi thích hơn",
"not_listed": "Lý do không có trong danh sách"
},
"delete_account_feedback_label": "Chúng tôi rất tiếc khi thấy bạn ra đi. Vui lòng giải thích lý do bạn rời đi để giúp chúng tôi cải thiện.",
"delete_account_feedback_placeholder": "Phản hồi",
- "delete_account_confirm_checkbox_label": "Có, tôi muốn xóa vĩnh viễn tài khoản này và tất cả dữ liệu của nó",
+ "delete_account_confirm_checkbox_label": "Có, tôi muốn xóa vĩnh viễn tài khoản này và tất cả dữ liệu",
"delete_account_confirm": "Xác nhận xóa tài khoản",
"delete_account_confirm_message": "Tài khoản này được liên kết với các ứng dụng Ente khác, nếu bạn có dùng.
Dữ liệu bạn đã tải lên, trên tất cả ứng dụng Ente, sẽ được lên lịch để xóa, và tài khoản của bạn sẽ bị xóa vĩnh viễn.
",
"feedback_required": "Mong bạn giúp chúng tôi thông tin này",
diff --git a/web/packages/base/origins.ts b/web/packages/base/origins.ts
index 8e1ef1ddac..e6c8b89ebd 100644
--- a/web/packages/base/origins.ts
+++ b/web/packages/base/origins.ts
@@ -97,3 +97,9 @@ export const isCustomAlbumsAppOrigin =
*/
export const albumsAppOrigin = () =>
process.env.NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT ?? "https://albums.ente.io";
+
+/**
+ * Return true if this build is meant to only serve public albums.
+ */
+export const shouldOnlyServeAlbumsApp =
+ !!process.env.NEXT_PUBLIC_ENTE_ONLY_SERVE_ALBUMS_APP;
diff --git a/web/packages/new/photos/services/settings.ts b/web/packages/new/photos/services/settings.ts
index aedda42384..e09844ce7b 100644
--- a/web/packages/new/photos/services/settings.ts
+++ b/web/packages/new/photos/services/settings.ts
@@ -8,7 +8,11 @@ import log from "ente-base/log";
import { updateShouldDisableCFUploadProxy } from "ente-gallery/services/upload";
import { nullToUndefined } from "ente-utils/transform";
import { z } from "zod/v4";
-import { fetchFeatureFlags, updateRemoteFlag } from "./remote-store";
+import {
+ fetchFeatureFlags,
+ updateRemoteFlag,
+ updateRemoteValue,
+} from "./remote-store";
/**
* In-memory flags that tracks various settings.
@@ -66,6 +70,24 @@ export interface Settings {
* Default: "https://cast.ente.io"
*/
castURL: string;
+
+ /**
+ * Set to the domain (host, e.g. "photos.example.org") that the user wishes
+ * to use for sharing their public albums.
+ *
+ * An empty string is treated as `undefined`.
+ */
+ customDomain?: string;
+
+ /**
+ * The URL we should ask the user to CNAME their {@link customDomain} to
+ * for wiring up their domain to the public albums app.
+ *
+ * See also `apps.custom-domain.cname` in `server/local.yaml`.
+ *
+ * Default: "my.ente.io"
+ */
+ customDomainCNAME: string;
}
const createDefaultSettings = (): Settings => ({
@@ -73,6 +95,7 @@ const createDefaultSettings = (): Settings => ({
mapEnabled: false,
cfUploadProxyDisabled: false,
castURL: "https://cast.ente.io",
+ customDomainCNAME: "my.ente.io",
});
/**
@@ -147,6 +170,8 @@ const FeatureFlags = z.object({
betaUser: z.boolean().nullish().transform(nullToUndefined),
mapEnabled: z.boolean().nullish().transform(nullToUndefined),
castUrl: z.string().nullish().transform(nullToUndefined),
+ customDomain: z.string().nullish().transform(nullToUndefined),
+ customDomainCNAME: z.string().nullish().transform(nullToUndefined),
});
type FeatureFlags = z.infer;
@@ -158,6 +183,9 @@ const syncSettingsSnapshotWithLocalStorage = () => {
settings.mapEnabled = flags?.mapEnabled || false;
settings.cfUploadProxyDisabled = savedCFProxyDisabled();
if (flags?.castUrl) settings.castURL = flags.castUrl;
+ if (flags?.customDomain) settings.customDomain = flags.customDomain;
+ if (flags?.customDomainCNAME)
+ settings.customDomainCNAME = flags.customDomainCNAME;
setSettingsSnapshot(settings);
};
@@ -198,6 +226,17 @@ export const isDevBuildAndUser = () => isDevBuild && isDevUserViaEmail();
const isDevUserViaEmail = () =>
!!savedPartialLocalUser()?.email?.endsWith("@ente.io");
+/**
+ * Persist the user's custom domain preference both locally and on remote.
+ *
+ * Setting the value to a blank string is equivalent to deleting the custom
+ * domain value altogether.
+ */
+export const updateCustomDomain = async (customDomain: string) => {
+ await updateRemoteValue("customDomain", customDomain);
+ return pullSettings();
+};
+
/**
* Persist the user's map enabled preference both locally and on remote.
*/