mirror of
https://github.com/docmost/docmost.git
synced 2025-11-16 10:11:11 +10:00
feat: save language to BE
This commit is contained in:
@ -28,7 +28,6 @@
|
|||||||
"emoji-mart": "^5.6.0",
|
"emoji-mart": "^5.6.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"i18next": "^23.14.0",
|
"i18next": "^23.14.0",
|
||||||
"i18next-browser-languagedetector": "^8.0.0",
|
|
||||||
"i18next-http-backend": "^2.6.1",
|
"i18next-http-backend": "^2.6.1",
|
||||||
"jotai": "^2.9.3",
|
"jotai": "^2.9.3",
|
||||||
"jotai-optics": "^0.4.0",
|
"jotai-optics": "^0.4.0",
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
import { Group, Text, Select } from "@mantine/core";
|
import { Group, Text, Select } from "@mantine/core";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { updateUser } from "../services/user-service";
|
||||||
|
import { IUser } from "../types/user.types";
|
||||||
|
import { useAtom } from "jotai";
|
||||||
|
import { userAtom } from "../atoms/current-user-atom";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
export default function AccountLanguage() {
|
export default function AccountLanguage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -19,8 +24,17 @@ export default function AccountLanguage() {
|
|||||||
|
|
||||||
function LanguageSwitcher() {
|
function LanguageSwitcher() {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
|
const [user, setUser] = useAtom(userAtom);
|
||||||
|
const [language, setLanguage] = useState(
|
||||||
|
user.settings?.preferences?.language || "en-US",
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleChange = async (value: string) => {
|
||||||
|
const updatedUser = await updateUser({ language: value });
|
||||||
|
|
||||||
|
setLanguage(value);
|
||||||
|
setUser(updatedUser);
|
||||||
|
|
||||||
const handleChange = (value: string) => {
|
|
||||||
i18n.changeLanguage(value);
|
i18n.changeLanguage(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -28,13 +42,14 @@ function LanguageSwitcher() {
|
|||||||
<Select
|
<Select
|
||||||
label={t("Select language")}
|
label={t("Select language")}
|
||||||
data={[
|
data={[
|
||||||
{ value: "zh", label: "中文" },
|
{ value: "en-US", label: "English (United States)" },
|
||||||
{ value: "en", label: "English" },
|
{ value: "zh-CN", label: "中文 (简体)" },
|
||||||
]}
|
]}
|
||||||
value={i18n.language}
|
value={language}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
allowDeselect={false}
|
allowDeselect={false}
|
||||||
checkIconPosition="right"
|
checkIconPosition="right"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
import { IWorkspace } from "@/features/workspace/types/workspace.types";
|
import { IWorkspace } from "@/features/workspace/types/workspace.types";
|
||||||
|
|
||||||
export interface IUser {
|
type IUserPreferences = {
|
||||||
|
fullPageWidth: boolean;
|
||||||
|
language: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface IUser extends IUserPreferences {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
@ -17,7 +22,6 @@ export interface IUser {
|
|||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
deactivatedAt: Date;
|
deactivatedAt: Date;
|
||||||
deletedAt: Date;
|
deletedAt: Date;
|
||||||
fullPageWidth: boolean; // used for update
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICurrentUser {
|
export interface ICurrentUser {
|
||||||
@ -26,7 +30,5 @@ export interface ICurrentUser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IUserSettings {
|
export interface IUserSettings {
|
||||||
preferences: {
|
preferences: IUserPreferences
|
||||||
fullPageWidth: boolean;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,14 +2,19 @@ import { useAtom } from "jotai";
|
|||||||
import { currentUserAtom } from "@/features/user/atoms/current-user-atom";
|
import { currentUserAtom } from "@/features/user/atoms/current-user-atom";
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import useCurrentUser from "@/features/user/hooks/use-current-user";
|
import useCurrentUser from "@/features/user/hooks/use-current-user";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
export function UserProvider({ children }: React.PropsWithChildren) {
|
export function UserProvider({ children }: React.PropsWithChildren) {
|
||||||
const [, setCurrentUser] = useAtom(currentUserAtom);
|
const [, setCurrentUser] = useAtom(currentUserAtom);
|
||||||
const { data, isLoading, error } = useCurrentUser();
|
const { data, isLoading, error } = useCurrentUser();
|
||||||
|
const { i18n } = useTranslation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data && data.user && data.workspace) {
|
if (data && data.user && data.workspace) {
|
||||||
setCurrentUser(data);
|
setCurrentUser(data);
|
||||||
|
i18n.changeLanguage(
|
||||||
|
data.user?.settings?.preferences?.language || "en-US",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, [data, isLoading]);
|
}, [data, isLoading]);
|
||||||
|
|
||||||
|
|||||||
@ -2,25 +2,18 @@ import i18n from "i18next";
|
|||||||
import { initReactI18next } from "react-i18next";
|
import { initReactI18next } from "react-i18next";
|
||||||
|
|
||||||
import Backend from "i18next-http-backend";
|
import Backend from "i18next-http-backend";
|
||||||
import LanguageDetector from "i18next-browser-languagedetector";
|
|
||||||
// don't want to use this?
|
|
||||||
// have a look at the Quick start guide
|
|
||||||
// for passing in lng and translations on init
|
|
||||||
|
|
||||||
i18n
|
i18n
|
||||||
// load translation using http -> see /public/locales (i.e. https://github.com/i18next/react-i18next/tree/master/example/react/public/locales)
|
// load translation using http -> see /public/locales (i.e. https://github.com/i18next/react-i18next/tree/master/example/react/public/locales)
|
||||||
// learn more: https://github.com/i18next/i18next-http-backend
|
// learn more: https://github.com/i18next/i18next-http-backend
|
||||||
// want your translations to be loaded from a professional CDN? => https://github.com/locize/react-tutorial#step-2---use-the-locize-cdn
|
// want your translations to be loaded from a professional CDN? => https://github.com/locize/react-tutorial#step-2---use-the-locize-cdn
|
||||||
.use(Backend)
|
.use(Backend)
|
||||||
// detect user language
|
|
||||||
// learn more: https://github.com/i18next/i18next-browser-languageDetector
|
|
||||||
.use(LanguageDetector)
|
|
||||||
// pass the i18n instance to react-i18next.
|
// pass the i18n instance to react-i18next.
|
||||||
.use(initReactI18next)
|
.use(initReactI18next)
|
||||||
// init i18next
|
// init i18next
|
||||||
// for all options read: https://www.i18next.com/overview/configuration-options
|
// for all options read: https://www.i18next.com/overview/configuration-options
|
||||||
.init({
|
.init({
|
||||||
fallbackLng: "en",
|
fallbackLng: "en-US",
|
||||||
debug: true,
|
debug: true,
|
||||||
|
|
||||||
interpolation: {
|
interpolation: {
|
||||||
|
|||||||
@ -12,4 +12,8 @@ export class UpdateUserDto extends PartialType(
|
|||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
fullPageWidth: boolean;
|
fullPageWidth: boolean;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
language: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,13 @@ export class UserService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof updateUserDto.language !== 'undefined') {
|
||||||
|
return this.updateUserLanguagePreference(
|
||||||
|
userId,
|
||||||
|
updateUserDto.language,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (updateUserDto.name) {
|
if (updateUserDto.name) {
|
||||||
user.name = updateUserDto.name;
|
user.name = updateUserDto.name;
|
||||||
}
|
}
|
||||||
@ -59,4 +66,8 @@ export class UserService {
|
|||||||
fullPageWidth,
|
fullPageWidth,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateUserLanguagePreference(userId: string, language: string) {
|
||||||
|
return this.userRepo.updatePreference(userId, 'language', language);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@ -231,9 +231,6 @@ importers:
|
|||||||
i18next:
|
i18next:
|
||||||
specifier: ^23.14.0
|
specifier: ^23.14.0
|
||||||
version: 23.14.0
|
version: 23.14.0
|
||||||
i18next-browser-languagedetector:
|
|
||||||
specifier: ^8.0.0
|
|
||||||
version: 8.0.0
|
|
||||||
i18next-http-backend:
|
i18next-http-backend:
|
||||||
specifier: ^2.6.1
|
specifier: ^2.6.1
|
||||||
version: 2.6.1
|
version: 2.6.1
|
||||||
@ -5468,9 +5465,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
|
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
|
||||||
engines: {node: '>=10.17.0'}
|
engines: {node: '>=10.17.0'}
|
||||||
|
|
||||||
i18next-browser-languagedetector@8.0.0:
|
|
||||||
resolution: {integrity: sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==}
|
|
||||||
|
|
||||||
i18next-http-backend@2.6.1:
|
i18next-http-backend@2.6.1:
|
||||||
resolution: {integrity: sha512-rCilMAnlEQNeKOZY1+x8wLM5IpYOj10guGvEpeC59tNjj6MMreLIjIW8D1RclhD3ifLwn6d/Y9HEM1RUE6DSog==}
|
resolution: {integrity: sha512-rCilMAnlEQNeKOZY1+x8wLM5IpYOj10guGvEpeC59tNjj6MMreLIjIW8D1RclhD3ifLwn6d/Y9HEM1RUE6DSog==}
|
||||||
|
|
||||||
@ -13961,10 +13955,6 @@ snapshots:
|
|||||||
|
|
||||||
human-signals@2.1.0: {}
|
human-signals@2.1.0: {}
|
||||||
|
|
||||||
i18next-browser-languagedetector@8.0.0:
|
|
||||||
dependencies:
|
|
||||||
'@babel/runtime': 7.23.7
|
|
||||||
|
|
||||||
i18next-http-backend@2.6.1:
|
i18next-http-backend@2.6.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-fetch: 4.0.0
|
cross-fetch: 4.0.0
|
||||||
@ -16335,7 +16325,7 @@ snapshots:
|
|||||||
terser@5.29.2:
|
terser@5.29.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/source-map': 0.3.6
|
'@jridgewell/source-map': 0.3.6
|
||||||
acorn: 8.11.3
|
acorn: 8.12.1
|
||||||
commander: 2.20.3
|
commander: 2.20.3
|
||||||
source-map-support: 0.5.21
|
source-map-support: 0.5.21
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user