Kaynağa Gözat

Handle updates

Manav Rathi 1 yıl önce
ebeveyn
işleme
e1f5121b4f

+ 6 - 11
apps/photos/src/components/Sidebar/Preferences/LanguageSelector.tsx

@@ -1,14 +1,12 @@
 import DropdownInput, { DropdownOption } from 'components/DropdownInput';
-import { useLocalState } from '@ente/shared/hooks/useLocalState';
 import { t } from 'i18next';
 import { useRouter } from 'next/router';
 import {
     type SupportedLocale,
     supportedLocales,
-    closestSupportedLocale,
+    getLocaleInUse,
+    setLocaleInUse,
 } from '@/ui/i18n';
-import { LS_KEYS } from '@ente/shared/storage/localStorage';
-import { getUserLocaleString } from '@ente/shared/storage/localStorage/helpers';
 
 /**
  * Human readable name for each supported locale
@@ -38,15 +36,12 @@ const getLanguageOptions = (): DropdownOption<SupportedLocale>[] => {
 };
 
 export const LanguageSelector = () => {
-    const [userLocale, setUserLocale] = useLocalState(
-        LS_KEYS.LOCALE,
-        closestSupportedLocale(getUserLocaleString())
-    );
-
+    const locale = getLocaleInUse();
+    // Enhancement: Is this full reload needed?
     const router = useRouter();
 
     const updateCurrentLocale = (newLocale: SupportedLocale) => {
-        setUserLocale(newLocale);
+        setLocaleInUse(newLocale);
         router.reload();
     };
 
@@ -55,7 +50,7 @@ export const LanguageSelector = () => {
             options={getLanguageOptions()}
             label={t('LANGUAGE')}
             labelProps={{ color: 'text.muted' }}
-            selected={userLocale}
+            selected={locale}
             setSelected={updateCurrentLocale}
         />
     );

+ 0 - 4
packages/shared/storage/localStorage/helpers.ts

@@ -29,10 +29,6 @@ export function setLivePhotoInfoShownCount(count: boolean) {
     setData(LS_KEYS.LIVE_PHOTO_INFO_SHOWN_COUNT, { count });
 }
 
-export function getUserLocaleString(): string {
-    return getData(LS_KEYS.LOCALE)?.value;
-}
-
 export function getLocalMapEnabled(): boolean {
     return getData(LS_KEYS.MAP_ENABLED)?.value ?? false;
 }

+ 2 - 1
packages/shared/storage/localStorage/index.ts

@@ -21,7 +21,8 @@ export enum LS_KEYS {
     THEME = 'theme',
     WAIT_TIME = 'waitTime',
     API_ENDPOINT = 'apiEndpoint',
-    LOCALE = 'locale',
+    // Moved to the new wrapper @/utils/local-storage
+    // LOCALE = 'locale',
     MAP_ENABLED = 'mapEnabled',
     SRP_SETUP_ATTRIBUTES = 'srpSetupAttributes',
     SRP_ATTRIBUTES = 'srpAttributes',

+ 39 - 5
packages/ui/i18n.ts

@@ -36,6 +36,8 @@ export const supportedLocales = [
 /** The type of {@link supportedLocales}. */
 export type SupportedLocale = (typeof supportedLocales)[number];
 
+const defaultLocale: SupportedLocale = "en-US";
+
 /**
  * Load translations.
  *
@@ -82,7 +84,7 @@ export const setupI18n = async () => {
             returnEmptyString: false,
             // The language to use if translation for a particular key in the
             // current `lng` is not available.
-            fallbackLng: "en-US",
+            fallbackLng: defaultLocale,
             interpolation: {
                 escapeValue: false, // not needed for react as it escapes by default
             },
@@ -153,6 +155,7 @@ const savedLocaleStringMigratingIfNeeded = () => {
 
     const newValue = mapOldValue(value);
     if (newValue) setLSString("locale", newValue);
+
     return newValue;
 };
 
@@ -184,9 +187,9 @@ const mapOldValue = (value: string | undefined) => {
  * If {@link savedLocaleString} is `undefined`, it tries to deduce the closest
  * {@link SupportedLocale} that matches the browser's locale.
  */
-export function closestSupportedLocale(
+const closestSupportedLocale = (
     savedLocaleString?: string,
-): SupportedLocale {
+): SupportedLocale => {
     const ss = savedLocaleString;
     if (ss && includes(supportedLocales, ss)) return ss;
 
@@ -209,5 +212,36 @@ export function closestSupportedLocale(
     }
 
     // Fallback
-    return "en-US";
-}
+    return defaultLocale;
+};
+
+/**
+ * Return the locale that is currently being used to show the app's UI.
+ *
+ * Note that this may be different from the user's locale. For example, the
+ * browser might be set to en-GB, but since we don't support that specific
+ * variant of English, this value will be (say) en-US.
+ */
+export const getLocaleInUse = (): SupportedLocale => {
+    const locale = i18n.resolvedLanguage;
+    if (locale && includes(supportedLocales, locale)) {
+        return locale;
+    } else {
+        // This shouldn't have happened. Log an error to attract attention.
+        logError(
+            `Expected the i18next locale to be one of the supported values, but instead found ${locale}`,
+        );
+        return defaultLocale;
+    }
+};
+
+/**
+ * Set the locale that should be used to show the app's UI.
+ *
+ * This updates both the i18next state, and also the corresponding user
+ * preference that is stored in local storage.
+ */
+export const setLocaleInUse = async (locale: SupportedLocale) => {
+    setLSString("locale", locale);
+    return i18n.changeLanguage(locale);
+};

+ 13 - 7
packages/utils/logging.ts

@@ -1,11 +1,11 @@
 /**
  * Log an error
  *
- * The {@link message} property describes what went wrong. Generally in such
- * situations we also have an "error" object that has specific details about the
- * issue - that gets passed as the second parameter.
+ * The {@link message} property describes what went wrong. Generally (but not
+ * always) in such situations we also have an "error" object that has specific
+ * details about the issue - that gets passed as the second parameter.
  *
- * Note that the "error" {@link e} is not typed. This is because in JavaScript,
+ * Note that the "error" {@link e} is not typed. This is because in JavaScript
  * any arbitrary value can be thrown. So this function allows us to pass it an
  * arbitrary value as the error, and will internally figure out how best to deal
  * with it.
@@ -16,10 +16,16 @@
  * route and show this error elsewhere.
  *
  * TODO (MR): Currently this is a placeholder function to funnel error logs
- * through. This needs to do what the existing logError does, but it cannot have
- * a direct Sentry dependency here. For now, we just log on the console.
+ * through. This needs to do what the existing logError in @ente/shared does,
+ * but it cannot have a direct Electron/Sentry dependency here. For now, we just
+ * log on the console.
  */
-export const logError = (message: string, e: unknown) => {
+export const logError = (message: string, e?: unknown) => {
+    if (e === undefined || e === null) {
+        console.error(message);
+        return;
+    }
+
     let es: string;
     if (e instanceof Error) {
         // In practice, we expect ourselves to be called with Error objects, so