mirror of
https://github.com/excalidraw/excalidraw.git
synced 2024-11-02 03:25:53 +01:00
feat: smarter preferred lang detection (#8205)
This commit is contained in:
parent
d9258a736b
commit
148b895f46
@ -1,5 +1,4 @@
|
|||||||
import polyfill from "../packages/excalidraw/polyfill";
|
import polyfill from "../packages/excalidraw/polyfill";
|
||||||
import LanguageDetector from "i18next-browser-languagedetector";
|
|
||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { trackEvent } from "../packages/excalidraw/analytics";
|
import { trackEvent } from "../packages/excalidraw/analytics";
|
||||||
import { getDefaultAppState } from "../packages/excalidraw/appState";
|
import { getDefaultAppState } from "../packages/excalidraw/appState";
|
||||||
@ -22,7 +21,6 @@ import { useCallbackRefState } from "../packages/excalidraw/hooks/useCallbackRef
|
|||||||
import { t } from "../packages/excalidraw/i18n";
|
import { t } from "../packages/excalidraw/i18n";
|
||||||
import {
|
import {
|
||||||
Excalidraw,
|
Excalidraw,
|
||||||
defaultLang,
|
|
||||||
LiveCollaborationTrigger,
|
LiveCollaborationTrigger,
|
||||||
TTDDialog,
|
TTDDialog,
|
||||||
TTDDialogTrigger,
|
TTDDialogTrigger,
|
||||||
@ -93,7 +91,7 @@ import {
|
|||||||
import { AppMainMenu } from "./components/AppMainMenu";
|
import { AppMainMenu } from "./components/AppMainMenu";
|
||||||
import { AppWelcomeScreen } from "./components/AppWelcomeScreen";
|
import { AppWelcomeScreen } from "./components/AppWelcomeScreen";
|
||||||
import { AppFooter } from "./components/AppFooter";
|
import { AppFooter } from "./components/AppFooter";
|
||||||
import { atom, Provider, useAtom, useAtomValue } from "jotai";
|
import { Provider, useAtom, useAtomValue } from "jotai";
|
||||||
import { useAtomWithInitialValue } from "../packages/excalidraw/jotai";
|
import { useAtomWithInitialValue } from "../packages/excalidraw/jotai";
|
||||||
import { appJotaiStore } from "./app-jotai";
|
import { appJotaiStore } from "./app-jotai";
|
||||||
|
|
||||||
@ -121,6 +119,8 @@ import {
|
|||||||
youtubeIcon,
|
youtubeIcon,
|
||||||
} from "../packages/excalidraw/components/icons";
|
} from "../packages/excalidraw/components/icons";
|
||||||
import { appThemeAtom, useHandleAppTheme } from "./useHandleAppTheme";
|
import { appThemeAtom, useHandleAppTheme } from "./useHandleAppTheme";
|
||||||
|
import { getPreferredLanguage } from "./app-language/language-detector";
|
||||||
|
import { useAppLangCode } from "./app-language/language-state";
|
||||||
|
|
||||||
polyfill();
|
polyfill();
|
||||||
|
|
||||||
@ -172,11 +172,6 @@ if (window.self !== window.top) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const languageDetector = new LanguageDetector();
|
|
||||||
languageDetector.init({
|
|
||||||
languageUtils: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
const shareableLinkConfirmDialog = {
|
const shareableLinkConfirmDialog = {
|
||||||
title: t("overwriteConfirm.modal.shareableLink.title"),
|
title: t("overwriteConfirm.modal.shareableLink.title"),
|
||||||
description: (
|
description: (
|
||||||
@ -322,19 +317,15 @@ const initializeScene = async (opts: {
|
|||||||
return { scene: null, isExternalScene: false };
|
return { scene: null, isExternalScene: false };
|
||||||
};
|
};
|
||||||
|
|
||||||
const detectedLangCode = languageDetector.detect() || defaultLang.code;
|
|
||||||
export const appLangCodeAtom = atom(
|
|
||||||
Array.isArray(detectedLangCode) ? detectedLangCode[0] : detectedLangCode,
|
|
||||||
);
|
|
||||||
|
|
||||||
const ExcalidrawWrapper = () => {
|
const ExcalidrawWrapper = () => {
|
||||||
const [errorMessage, setErrorMessage] = useState("");
|
const [errorMessage, setErrorMessage] = useState("");
|
||||||
const [langCode, setLangCode] = useAtom(appLangCodeAtom);
|
|
||||||
const isCollabDisabled = isRunningInIframe();
|
const isCollabDisabled = isRunningInIframe();
|
||||||
|
|
||||||
const [appTheme, setAppTheme] = useAtom(appThemeAtom);
|
const [appTheme, setAppTheme] = useAtom(appThemeAtom);
|
||||||
const { editorTheme } = useHandleAppTheme();
|
const { editorTheme } = useHandleAppTheme();
|
||||||
|
|
||||||
|
const [langCode, setLangCode] = useAppLangCode();
|
||||||
|
|
||||||
// initial state
|
// initial state
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -490,11 +481,7 @@ const ExcalidrawWrapper = () => {
|
|||||||
if (isBrowserStorageStateNewer(STORAGE_KEYS.VERSION_DATA_STATE)) {
|
if (isBrowserStorageStateNewer(STORAGE_KEYS.VERSION_DATA_STATE)) {
|
||||||
const localDataState = importFromLocalStorage();
|
const localDataState = importFromLocalStorage();
|
||||||
const username = importUsernameFromLocalStorage();
|
const username = importUsernameFromLocalStorage();
|
||||||
let langCode = languageDetector.detect() || defaultLang.code;
|
setLangCode(getPreferredLanguage());
|
||||||
if (Array.isArray(langCode)) {
|
|
||||||
langCode = langCode[0];
|
|
||||||
}
|
|
||||||
setLangCode(langCode);
|
|
||||||
excalidrawAPI.updateScene({
|
excalidrawAPI.updateScene({
|
||||||
...localDataState,
|
...localDataState,
|
||||||
storeAction: StoreAction.UPDATE,
|
storeAction: StoreAction.UPDATE,
|
||||||
@ -595,10 +582,6 @@ const ExcalidrawWrapper = () => {
|
|||||||
};
|
};
|
||||||
}, [excalidrawAPI]);
|
}, [excalidrawAPI]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
languageDetector.cacheUserLanguage(langCode);
|
|
||||||
}, [langCode]);
|
|
||||||
|
|
||||||
const onChange = (
|
const onChange = (
|
||||||
elements: readonly OrderedExcalidrawElement[],
|
elements: readonly OrderedExcalidrawElement[],
|
||||||
appState: AppState,
|
appState: AppState,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useSetAtom } from "jotai";
|
import { useSetAtom } from "jotai";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { appLangCodeAtom } from "../App";
|
|
||||||
import { useI18n, languages } from "../../packages/excalidraw/i18n";
|
import { useI18n, languages } from "../../packages/excalidraw/i18n";
|
||||||
|
import { appLangCodeAtom } from "./language-state";
|
||||||
|
|
||||||
export const LanguageList = ({ style }: { style?: React.CSSProperties }) => {
|
export const LanguageList = ({ style }: { style?: React.CSSProperties }) => {
|
||||||
const { t, langCode } = useI18n();
|
const { t, langCode } = useI18n();
|
25
excalidraw-app/app-language/language-detector.ts
Normal file
25
excalidraw-app/app-language/language-detector.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import LanguageDetector from "i18next-browser-languagedetector";
|
||||||
|
import { defaultLang, languages } from "../../packages/excalidraw";
|
||||||
|
|
||||||
|
export const languageDetector = new LanguageDetector();
|
||||||
|
|
||||||
|
languageDetector.init({
|
||||||
|
languageUtils: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getPreferredLanguage = () => {
|
||||||
|
const detectedLanguages = languageDetector.detect();
|
||||||
|
|
||||||
|
const detectedLanguage = Array.isArray(detectedLanguages)
|
||||||
|
? detectedLanguages[0]
|
||||||
|
: detectedLanguages;
|
||||||
|
|
||||||
|
const initialLanguage =
|
||||||
|
(detectedLanguage
|
||||||
|
? // region code may not be defined if user uses generic preferred language
|
||||||
|
// (e.g. chinese vs instead of chienese-simplified)
|
||||||
|
languages.find((lang) => lang.code.startsWith(detectedLanguage))?.code
|
||||||
|
: null) || defaultLang.code;
|
||||||
|
|
||||||
|
return initialLanguage;
|
||||||
|
};
|
15
excalidraw-app/app-language/language-state.ts
Normal file
15
excalidraw-app/app-language/language-state.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { atom, useAtom } from "jotai";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { getPreferredLanguage, languageDetector } from "./language-detector";
|
||||||
|
|
||||||
|
export const appLangCodeAtom = atom(getPreferredLanguage());
|
||||||
|
|
||||||
|
export const useAppLangCode = () => {
|
||||||
|
const [langCode, setLangCode] = useAtom(appLangCodeAtom);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
languageDetector.cacheUserLanguage(langCode);
|
||||||
|
}, [langCode]);
|
||||||
|
|
||||||
|
return [langCode, setLangCode] as const;
|
||||||
|
};
|
@ -6,7 +6,7 @@ import {
|
|||||||
import type { Theme } from "../../packages/excalidraw/element/types";
|
import type { Theme } from "../../packages/excalidraw/element/types";
|
||||||
import { MainMenu } from "../../packages/excalidraw/index";
|
import { MainMenu } from "../../packages/excalidraw/index";
|
||||||
import { isExcalidrawPlusSignedUser } from "../app_constants";
|
import { isExcalidrawPlusSignedUser } from "../app_constants";
|
||||||
import { LanguageList } from "./LanguageList";
|
import { LanguageList } from "../app-language/LanguageList";
|
||||||
|
|
||||||
export const AppMainMenu: React.FC<{
|
export const AppMainMenu: React.FC<{
|
||||||
onCollabDialogOpen: () => any;
|
onCollabDialogOpen: () => any;
|
||||||
|
Loading…
Reference in New Issue
Block a user