Skip to content

fix language switch issue on login + added missing translations #836

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions client/packages/lowcoder/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ const AppIndexWithProps = connect(mapStateToProps, mapDispatchToProps)(AppIndex)
export function bootstrap() {
initApp();
loadComps();

const uiLanguage = localStorage.getItem('lowcoder_uiLanguage');

const container = document.getElementById("root");
const root = createRoot(container!);
root.render(
Expand Down
2 changes: 1 addition & 1 deletion client/packages/lowcoder/src/i18n/LanguageProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ import React, { ReactNode } from 'react';
// Define the props expected by the LanguageProvider component
export interface LanguageProviderProps {
children: ReactNode;
}
}
30 changes: 23 additions & 7 deletions client/packages/lowcoder/src/i18n/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,35 @@ import { getI18nObjects, Translator } from "lowcoder-core";
import * as localeData from "./locales";
import { I18nObjects } from "./locales/types";
import { languagesMetadata } from "./languagesMeta";
import { ReactNode } from "react";

const uiLanguage = localStorage.getItem('lowcoder_uiLanguage');
type transType = (key: any, variables?: any) => string;
type transToNodeType = (key: any, variables?: any) => ReactNode;

export const { trans, transToNode, language } = new Translator<typeof localeData.en>(
localeData,
REACT_APP_LANGUAGES,
[uiLanguage || 'en']
);
let trans: transType;
let transToNode: transToNodeType;
let language = 'en';

export const initTranslator = (lang?: string) => {
const translator = new Translator<typeof localeData.en>(
localeData,
REACT_APP_LANGUAGES,
[lang || 'en']
);

language = translator.language;
transToNode = translator.transToNode;
trans = translator.trans;
}

export const i18nObjs = getI18nObjects<I18nObjects>(localeData, REACT_APP_LANGUAGES);

export const languageList = Object.keys(languagesMetadata).map(code => ({
languageCode: code,
languageName: languagesMetadata[code].languageName,
flag: languagesMetadata[code].flag
}));
}));

initTranslator();

export { language, trans, transToNode };
14 changes: 13 additions & 1 deletion client/packages/lowcoder/src/i18n/locales/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2249,7 +2249,19 @@ export const de: typeof en = {
"alreadySetPassword": "Passwort setzen",
"setPassPlaceholder": "Du kannst dich mit Passwort anmelden",
"setPassAfterBind": "Du kannst das Passwort nach der Kontobindung festlegen",
"socialConnections": "Soziale Bindungen"
"socialConnections": "Soziale Bindungen",
"changeAvatar": "Avatar ändern",
"about": "Um",
"userId": "Benutzer-ID",
"createdAt": "Hergestellt in",
"currentOrg": "aktuelle Organisation",
"settings": "Einstellungen",
"uiLanguage": "UI-Sprache",
"info": "Die Info",
"createdApps": "Erstellte Apps",
"createdModules": "Erstellte Module",
"onMarketplace": "Auf dem Marktplatz",
"howToPublish": "So veröffentlichen Sie auf dem Marktplatz"
},
"shortcut": {
...en.shortcut,
Expand Down
14 changes: 13 additions & 1 deletion client/packages/lowcoder/src/i18n/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2302,7 +2302,19 @@ export const en = {
"alreadySetPassword": "Password Set",
"setPassPlaceholder": "You Can Login with Password",
"setPassAfterBind": "You Can Set Password After Account Bind",
"socialConnections": "Social Connections"
"socialConnections": "Social Connections",
"changeAvatar": "Change Avatar",
"about": "About",
"userId": "User ID",
"createdAt": "Created At",
"currentOrg": "Current Organization",
"settings": "Settings",
"uiLanguage": "UI Language",
"info": "Info",
"createdApps": "Created Apps",
"createdModules": "Created Modules",
"onMarketplace": "On Marketplace",
"howToPublish": "How to publish on Marketplace"
},
"shortcut": {
"shortcutList": "Keyboard Shortcuts",
Expand Down
13 changes: 13 additions & 0 deletions client/packages/lowcoder/src/i18n/locales/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2136,6 +2136,18 @@ profile: {
setPassPlaceholder: "您可以使用密码登录",
setPassAfterBind: "账号绑定后,您可以设置密码",
socialConnections: "社交连接",
changeAvatar: "更改头像",
about: "关于",
userId: "用户身份",
createdAt: "创建于",
currentOrg: "当前组织",
settings: "设置",
uiLanguage: "用户界面语言",
info: "信息",
createdApps: "创建的应用程序",
createdModules: "创建的模块",
onMarketplace: "在市场上",
howToPublish: "如何在 Marketplace 上发布",
},
shortcut: {
shortcutList: "键盘快捷键",
Expand Down Expand Up @@ -2287,6 +2299,7 @@ history: {
history: "历史记录",
},
home: {
profile: "你的个人资料",
allApplications: "所有应用",
allModules: "所有模块",
allFolders: "所有文件夹",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ export function UserProfileLayout(props: UserProfileLayoutProps) {
<StyleProfileContent>
<Row gutter={[24, 24]} style={{ display: 'flex', alignItems: 'end' }}>
<Col lg={4}>
<StyleAvatar src={<img src={user.avatarUrl} alt="avatar" />} shape="square" size={120} />
<StyleAvatar src={<img src={user.avatarUrl ?? `https://eu.ui-avatars.com/api/?name=${user.username}&size=250`} alt="avatar" />} shape="square" size={120} />
</Col>
<Col lg={20}>
<Space style={{paddingLeft : "80px"}}>
Expand All @@ -265,11 +265,12 @@ export function UserProfileLayout(props: UserProfileLayoutProps) {
beforeUpload={beforeImgUpload}
withCredentials
>
<Button style={{marginTop: "8px"}}>Change Avatar</Button>
<Button style={{marginTop: "8px"}}>
{trans("profile.changeAvatar")}
</Button>
</Upload>

<BlurFinishInput

valueCheck={{
rule: (val) => val.trim() !== "",
message: trans("profile.nameCheck"),
Expand All @@ -285,20 +286,20 @@ export function UserProfileLayout(props: UserProfileLayoutProps) {
</Card>

<Card style={{ marginBottom: "20px" }}>
<Title level={4}>About</Title>
<Title level={4}>{trans("profile.about")}</Title>
<Space direction="horizontal" size={10} wrap={true}>
<Text>User-ID: {user.id}</Text> |
<Text>Created At: {dayjs(user.createdTimeMs).format("YYYY-MM-DD HH:mm:ss")}</Text> |
<Text>Current Organization: {currentOrg?.name}</Text>
<Text>{trans("profile.userId")}: {user.id}</Text> |
<Text>{trans("profile.createdAt")}: {dayjs(user.createdTimeMs).format("YYYY-MM-DD HH:mm:ss")}</Text> |
<Text>{trans("profile.currentOrg")}: {currentOrg?.name}</Text>
</Space>
</Card>

<Card style={{ marginBottom: "20px" }}>
<Title level={4}>Settings</Title>
<Title level={4}>{trans("profile.settings")}</Title>
<Space direction="vertical" size={10}>
<Text>UI Language:</Text>
<Text>{trans("profile.uiLanguage")}:</Text>
<Select
defaultValue={currentUser.uiLanguage}
defaultValue={currentUser.uiLanguage ?? 'en'}
style={{ width: 200 }}
onChange={handleLanguageChange}
showSearch
Expand All @@ -316,14 +317,16 @@ export function UserProfileLayout(props: UserProfileLayoutProps) {
</Card>

<Card style={{ marginBottom: "20px" }}>
<Title level={4}>Info</Title>
<Title level={4}>{trans("profile.info")}</Title>
<Space direction="horizontal" size={10}>
<Row gutter={[24,24]}>
<Col xs={24} sm={12} xl={6} style={{marginBottom: "20px", minWidth: "300px"}} span={8}>
<Card hoverable>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<div>
<p style={{ textTransform: "uppercase", fontSize: "13px" }}>Created Apps</p>
<p style={{ textTransform: "uppercase", fontSize: "13px" }}>
{trans("profile.createdApps")}
</p>
<h4 style={{ fontSize: "22px" }}>
<span data-target={apps.filter(app => app.createBy === user.username && app.applicationType == 1).length}>
<CountUp start={0} end={apps.filter(app => app.createBy === user.username && app.applicationType == 1).length} duration={2} />
Expand All @@ -343,7 +346,9 @@ export function UserProfileLayout(props: UserProfileLayoutProps) {
<Card hoverable>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<div>
<p style={{ textTransform: "uppercase", fontSize: "13px" }}>Created Modules</p>
<p style={{ textTransform: "uppercase", fontSize: "13px" }}>
{trans("profile.createdModules")}
</p>
<h4 style={{ fontSize: "22px" }}>
<span data-target={apps.filter(app => app.createBy === user.username && app.applicationType == 2).length}>
<CountUp start={0} end={apps.filter(app => app.createBy === user.username && app.applicationType == 2).length} duration={2} />
Expand All @@ -363,14 +368,18 @@ export function UserProfileLayout(props: UserProfileLayoutProps) {
<Card hoverable>
<div style={{ display: "flex", justifyContent: "space-between" }}>
<div>
<p style={{ textTransform: "uppercase", fontSize: "13px" }}>on Marketplace</p>
<p style={{ textTransform: "uppercase", fontSize: "13px" }}>
{trans("profile.onMarketplace")}
</p>
<h4 style={{ fontSize: "22px" }}>
<span data-target={8}>
<CountUp start={0} end={8} duration={2} />
</span>
</h4>
<div style={{ display: "flex", alignItems: "center" }}>
<h5 style={{ color: "#55c27f", marginRight: "10px" }}>How to publish on Marketplce</h5>
<h5 style={{ color: "#55c27f", marginRight: "10px" }}>
{trans("profile.howToPublish")}
</h5>
</div>
</div>
<BgSuccess style={{ padding: '6px', width: '48px', height: '48px', borderRadius: '4px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
Expand Down
3 changes: 3 additions & 0 deletions client/packages/lowcoder/src/redux/sagas/userSagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { messageInstance } from "lowcoder-design/src/components/GlobalInstances"

import { AuthSearchParams } from "constants/authConstants";
import { saveAuthSearchParams } from "pages/userAuth/authUtils";
import { initTranslator } from "i18n";

function validResponseData(response: AxiosResponse<ApiResponse>) {
return response && response.data && response.data.data;
Expand Down Expand Up @@ -90,6 +91,8 @@ export function* getCurrentUserSaga() {
type: ReduxActionTypes.FETCH_CURRENT_USER_SUCCESS,
payload: response.data.data,
});
const { uiLanguage } = response.data.data;
initTranslator(uiLanguage);
}
} catch (error: any) {
yield put({
Expand Down
Loading