Skip to content

Commit e7d6003

Browse files
authored
Merge pull request #7784 from sagemathinc/i18n-ru_it_fr
I18N: ru it fr
2 parents 2ae8543 + b9dfa13 commit e7d6003

File tree

22 files changed

+9299
-129
lines changed

22 files changed

+9299
-129
lines changed

src/packages/frontend/admin/users/impersonate.tsx

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,54 @@
33
* License: MS-RSL – see LICENSE.md for details
44
*/
55

6-
import { Component, Rendered } from "@cocalc/frontend/app-framework";
7-
import { Loading } from "@cocalc/frontend/components";
8-
import { webapp_client } from "@cocalc/frontend/webapp-client";
6+
import { Alert } from "antd";
97
import { join } from "path";
8+
9+
import { Rendered, useEffect, useState } from "@cocalc/frontend/app-framework";
10+
import { Loading } from "@cocalc/frontend/components";
1011
import { appBasePath } from "@cocalc/frontend/customize/app-base-path";
11-
import { Alert } from "antd";
12+
import { webapp_client } from "@cocalc/frontend/webapp-client";
1213

1314
interface Props {
1415
account_id: string;
1516
first_name: string;
1617
last_name: string;
1718
}
1819

19-
interface State {
20-
auth_token?: string;
21-
err?: string;
22-
}
20+
export function Impersonate(props: Readonly<Props>) {
21+
const { first_name, last_name, account_id } = props;
2322

24-
export class Impersonate extends Component<Props, State> {
25-
constructor(props, state) {
26-
super(props, state);
27-
this.state = {};
28-
}
23+
const [auth_token, set_auth_token] = useState<string | null>(null);
24+
const [err, set_err] = useState<string | null>(null);
2925

30-
async get_token(): Promise<void> {
26+
async function get_token(): Promise<void> {
3127
try {
3228
const auth_token = await webapp_client.admin_client.get_user_auth_token(
33-
this.props.account_id
29+
account_id,
3430
);
35-
this.setState({ auth_token });
31+
set_auth_token(auth_token);
32+
set_err(null);
3633
} catch (err) {
37-
this.setState({ err: err.toString() });
34+
set_err(err.toString());
35+
set_auth_token(null);
3836
}
3937
}
4038

41-
componentDidMount(): void {
42-
this.get_token();
43-
}
39+
useEffect(() => {
40+
get_token();
41+
}, []);
4442

45-
render_link(): Rendered {
46-
if (this.state.auth_token == null) {
43+
function render_link(): Rendered {
44+
if (auth_token == null) {
4745
return <Loading />;
4846
}
49-
const link = join(appBasePath, `app?auth_token=${this.state.auth_token}`);
47+
// lang_temp: https://github.com/sagemathinc/cocalc/issues/7782
48+
const link = join(appBasePath, `app?auth_token=${auth_token}&lang_temp=en`);
5049
return (
5150
<div>
5251
<a href={link} target="_blank" rel="noopener noreferrer">
5352
Right click and open this link in a new incognito window, where you
54-
will be signed in as {this.props.first_name} {this.props.last_name}...
53+
will be signed in as {first_name} {last_name}...
5554
</a>
5655
<br />
5756
The actual link:
@@ -64,35 +63,31 @@ export class Impersonate extends Component<Props, State> {
6463
);
6564
}
6665

67-
render_err(): Rendered {
68-
if (this.state.err != null) {
66+
function render_err(): Rendered {
67+
if (err != null) {
6968
return (
7069
<div>
71-
<b>ERROR</b> {this.state.err}
70+
<b>ERROR</b> {err}
7271
</div>
7372
);
7473
}
7574
}
7675

77-
render(): Rendered {
78-
return (
79-
<Alert
80-
type="warning"
81-
style={{
82-
margin: "15px",
83-
}}
84-
message={
85-
<b>
86-
Impersonate user "{this.props.first_name} {this.props.last_name}"
87-
</b>
88-
}
89-
description={
90-
<>
91-
{this.render_err()}
92-
{this.render_link()}
93-
</>
94-
}
95-
/>
96-
);
97-
}
76+
return (
77+
<Alert
78+
type="warning"
79+
style={{ margin: "15px" }}
80+
message={
81+
<b>
82+
Impersonate user "{first_name} {last_name}"
83+
</b>
84+
}
85+
description={
86+
<>
87+
{render_err()}
88+
{render_link()}
89+
</>
90+
}
91+
/>
92+
);
9893
}

src/packages/frontend/app/localize.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ function loadAntdLocale(locale: Locale): Promise<AntdLocale> {
140140
return import("antd/locale/zh_CN");
141141
case "es":
142142
return import("antd/locale/es_ES");
143+
case "ru":
144+
return import("antd/locale/ru_RU");
145+
case "fr":
146+
return import("antd/locale/fr_FR");
147+
case "it":
148+
return import("antd/locale/it_IT");
143149
default:
144150
unreachable(locale);
145151
throw new Error(`Unknown locale '${locale}.`);

src/packages/frontend/app/render.tsx

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,29 +29,43 @@ function App({ children }) {
2929

3030
// setting via ?lang=[locale] takes precedece over account settings
3131
useAsyncEffect(async () => {
32-
const lang = QueryParams.get("lang");
32+
const lang_set = QueryParams.get("lang");
33+
// lang_temp sets the language *temporarily*, i.e. without changing the account settings and it is sticky
34+
// this is useful for impersonation – https://github.com/sagemathinc/cocalc/issues/7782
35+
const lang_temp = QueryParams.get("lang_temp");
36+
const temp = lang_temp != null;
37+
const lang = temp ? lang_temp : lang_set;
3338
if (lang != null) {
3439
if (lang in LOCALIZATIONS) {
3540
console.warn(
36-
`URL query parameter 'lang=${lang}' – overriding user configuration.`,
41+
`URL query parameter 'lang=${lang}' – overriding user configuration ${
42+
temp ? "temporary" : "permanent"
43+
}.`,
3744
);
38-
const store = redux.getStore("account");
39-
// we have to ensure the account store is available, because this code runs very early
40-
await store.async_wait({
41-
until: () => store.get_account_id() != null,
42-
});
43-
redux
44-
.getActions("account")
45-
.set_other_settings(OTHER_SETTINGS_LOCALE_KEY, lang);
45+
if (!temp) {
46+
const store = redux.getStore("account");
47+
// we have to ensure the account store is available, because this code runs very early
48+
await store.async_wait({
49+
until: () => store.get_account_id() != null,
50+
});
51+
redux
52+
.getActions("account")
53+
.set_other_settings(OTHER_SETTINGS_LOCALE_KEY, lang);
54+
}
4655
setLocale(lang);
4756
} else {
4857
console.warn(
49-
`URL query parameter 'lang=${lang}' provided, but not a valid locale.`,
58+
`URL query parameter '${JSON.stringify({
59+
lang_set,
60+
lang_temp,
61+
})}' provided, but not a valid locale.`,
5062
`Known values: ${Object.keys(LOCALIZATIONS)}`,
5163
);
5264
}
53-
// removing the parameter, otherwise this conflicts with further changes of account settings
54-
QueryParams.remove("lang");
65+
if (!temp) {
66+
// removing the parameter, otherwise this conflicts with further changes of account settings
67+
QueryParams.remove("lang");
68+
}
5569
} else {
5670
setLocale(getLocale(other_settings));
5771
}

src/packages/frontend/frame-editors/crm-editor/users/impersonate.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Button } from "antd";
22
import { useState } from "react";
3+
34
import { Impersonate as OldImpersonate } from "@cocalc/frontend/admin/users/impersonate";
45
import { Icon } from "@cocalc/frontend/components";
56

src/packages/frontend/frame-editors/crm-editor/users/user.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import { Card, Space, Tag } from "antd";
2+
13
import { Avatar } from "@cocalc/frontend/account/avatar/avatar";
2-
import { Tag, Card, Space } from "antd";
34
import { TimeAgo } from "@cocalc/frontend/components";
4-
import Projects from "./projects";
5+
import { PurchasesButton } from "@cocalc/frontend/purchases/purchases";
56
import Impersonate from "./impersonate";
67
import PayAsYouGoMinBalance from "./pay-as-you-go-min-balance";
7-
import { PurchasesButton } from "@cocalc/frontend/purchases/purchases";
8+
import Projects from "./projects";
89

910
export default function User({
1011
account_id,

0 commit comments

Comments
 (0)