Skip to content

Commit a30b032

Browse files
committed
next/config: add simple language dropdown config
1 parent 65c99b2 commit a30b032

File tree

5 files changed

+163
-101
lines changed

5 files changed

+163
-101
lines changed

src/packages/frontend/i18n/index.ts

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
MessageFormatElement,
1212
} from "react-intl";
1313

14+
import { NAMES, OTHER_SETTINGS_LOCALE_KEY } from "@cocalc/util/i18n";
1415
import { AccountState } from "@cocalc/frontend/account/types";
1516
import { redux } from "@cocalc/frontend/app-framework";
1617
import {
@@ -23,12 +24,10 @@ import { IntlMessage, isIntlMessage } from "./types";
2324

2425
export { dialogs, editor, jupyter, labels, menu } from "./common";
2526

26-
export { DEFAULT_LOCALE, isIntlMessage };
27+
export { DEFAULT_LOCALE, isIntlMessage, OTHER_SETTINGS_LOCALE_KEY };
2728

2829
export type { IntlMessage, Locale };
2930

30-
export const OTHER_SETTINGS_LOCALE_KEY = "i18n";
31-
3231
export type Messages =
3332
| Record<string, string>
3433
| Record<string, MessageFormatElement[]>;
@@ -117,7 +116,7 @@ export const LOCALIZATIONS: {
117116
};
118117
} = {
119118
en: {
120-
name: "English",
119+
name: NAMES.en,
121120
flag: "🇺🇸",
122121
native: "English",
123122
trans: defineMessage({
@@ -126,7 +125,7 @@ export const LOCALIZATIONS: {
126125
}),
127126
},
128127
de: {
129-
name: "German",
128+
name: NAMES.de,
130129
flag: "🇩🇪",
131130
native: "Deutsch",
132131
trans: defineMessage({
@@ -135,7 +134,7 @@ export const LOCALIZATIONS: {
135134
}),
136135
},
137136
es: {
138-
name: "Spanish",
137+
name: NAMES.es,
139138
flag: "🇪🇸",
140139
native: "Español",
141140
trans: defineMessage({
@@ -144,7 +143,7 @@ export const LOCALIZATIONS: {
144143
}),
145144
},
146145
fr: {
147-
name: "French",
146+
name: NAMES.fr,
148147
flag: "🇫🇷",
149148
native: "Français",
150149
trans: defineMessage({
@@ -153,7 +152,7 @@ export const LOCALIZATIONS: {
153152
}),
154153
},
155154
it: {
156-
name: "Italian",
155+
name: NAMES.it,
157156
flag: "🇮🇹",
158157
native: "Italiano",
159158
trans: defineMessage({
@@ -162,7 +161,7 @@ export const LOCALIZATIONS: {
162161
}),
163162
},
164163
pl: {
165-
name: "Polish",
164+
name: NAMES.pl,
166165
flag: "🇵🇱",
167166
native: "Polski",
168167
trans: defineMessage({
@@ -171,7 +170,7 @@ export const LOCALIZATIONS: {
171170
}),
172171
},
173172
hu: {
174-
name: "Hungarian",
173+
name: NAMES.hu,
175174
flag: "🇭🇺",
176175
native: "Magyar",
177176
trans: defineMessage({
@@ -180,7 +179,7 @@ export const LOCALIZATIONS: {
180179
}),
181180
},
182181
ar: {
183-
name: "Arabic",
182+
name: NAMES.ar,
184183
flag: "🇪🇬",
185184
native: "العربية",
186185
trans: defineMessage({
@@ -189,7 +188,7 @@ export const LOCALIZATIONS: {
189188
}),
190189
},
191190
pt: {
192-
name: "Portuguese",
191+
name: NAMES.pt,
193192
flag: "🇵🇹",
194193
native: "Português",
195194
trans: defineMessage({
@@ -198,7 +197,7 @@ export const LOCALIZATIONS: {
198197
}),
199198
},
200199
tr: {
201-
name: "Turkish",
200+
name: NAMES.tr,
202201
flag: "🇹🇷",
203202
native: "Türkçe",
204203
trans: defineMessage({
@@ -207,7 +206,7 @@ export const LOCALIZATIONS: {
207206
}),
208207
},
209208
he: {
210-
name: "Hebrew",
209+
name: NAMES.he,
211210
flag: "🇮🇱",
212211
native: "עִבְרִית",
213212
trans: defineMessage({
@@ -216,7 +215,7 @@ export const LOCALIZATIONS: {
216215
}),
217216
},
218217
zh: {
219-
name: "Chinese",
218+
name: NAMES.zh,
220219
flag: "🇨🇳",
221220
native: "中文",
222221
trans: defineMessage({
@@ -225,7 +224,7 @@ export const LOCALIZATIONS: {
225224
}),
226225
},
227226
ja: {
228-
name: "Japanese",
227+
name: NAMES.ja,
229228
flag: "🇯🇵",
230229
native: "日本語",
231230
trans: defineMessage({
@@ -234,7 +233,7 @@ export const LOCALIZATIONS: {
234233
}),
235234
},
236235
hi: {
237-
name: "Hindi",
236+
name: NAMES.hi,
238237
flag: "🇮🇳",
239238
native: "हिन्दी",
240239
trans: defineMessage({
@@ -243,7 +242,7 @@ export const LOCALIZATIONS: {
243242
}),
244243
},
245244
ko: {
246-
name: "Korean",
245+
name: NAMES.ko,
247246
flag: "🇰🇷",
248247
native: "한국어",
249248
trans: defineMessage({
@@ -252,7 +251,7 @@ export const LOCALIZATIONS: {
252251
}),
253252
},
254253
ru: {
255-
name: "Russian",
254+
name: NAMES.ru,
256255
flag: "🇷🇺",
257256
native: "Русский",
258257
trans: defineMessage({

src/packages/next/components/account/config/system/appearance.tsx

Lines changed: 77 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
import { Space } from "antd";
2+
3+
import {
4+
KEEP_EN_LOCALE,
5+
NAMES,
6+
OTHER_SETTINGS_LOCALE_KEY,
7+
} from "@cocalc/util/i18n";
8+
import A from "components/misc/A";
29
import Loading from "components/share/loading";
3-
import register from "../register";
410
import useEditTable from "lib/hooks/edit-table";
5-
import A from "components/misc/A";
11+
import register from "../register";
612

7-
const desc = {
13+
const DESC = {
814
time_ago_absolute: `
915
You can display timestamps either as absolute points in time or relative to
1016
the current time.`,
1117
dark_mode: `Use Dark mode to reduce eye strain and save power by showing light text on a dark background.`,
1218
extra: "dark reader",
13-
};
19+
i18n: "Change the user-interface language",
20+
} as const;
1421

1522
interface Data {
1623
other_settings: {
@@ -28,20 +35,80 @@ register({
2835
title: "Appearance",
2936
icon: "calendar-week",
3037
desc: "Configure dark mode and how times are displayed.",
31-
search: desc,
38+
search: DESC,
3239
Component: () => {
33-
const { edited, original, Save, EditBoolean, EditNumber } =
40+
const { edited, original, Save, EditBoolean, EditNumber, EditSelect } =
3441
useEditTable<Data>({
3542
accounts: { other_settings: null },
3643
});
44+
3745
if (original == null || edited == null) {
3846
return <Loading />;
3947
}
4048

49+
function renderDarkMode() {
50+
if (edited == null || !edited.other_settings.dark_mode) return;
51+
52+
return (
53+
<div style={{ width: "100%" }}>
54+
<div
55+
style={{
56+
margin: "15px auto",
57+
maxWidth: "700px",
58+
border: "1px solid lightgrey",
59+
padding: "15px",
60+
borderRadius: "5px",
61+
}}
62+
>
63+
<h2 style={{ textAlign: "center" }}>Parameters</h2>
64+
<EditNumber
65+
path="other_settings.dark_mode_brightness"
66+
title="Brightness"
67+
min={20}
68+
max={100}
69+
/>
70+
<EditNumber
71+
path="other_settings.dark_mode_contrast"
72+
title="Contrast"
73+
min={20}
74+
max={100}
75+
/>
76+
<EditNumber
77+
path="other_settings.dark_mode_sepia"
78+
title="Sepia"
79+
min={0}
80+
max={100}
81+
/>
82+
<EditNumber
83+
path="other_settings.dark_mode_grayscale"
84+
title="Grayscale"
85+
min={0}
86+
max={100}
87+
/>
88+
</div>
89+
</div>
90+
);
91+
}
92+
93+
// make a copy of NAMES and replace the en with en-keep entry
94+
const langs: { [key: string]: string } = { ...NAMES };
95+
// add the "keep english" option
96+
langs[KEEP_EN_LOCALE] = langs.en;
97+
delete langs.en;
98+
4199
return (
42100
<Space direction="vertical" style={{ width: "100%" }}>
43101
<Save />
44102

103+
<EditSelect
104+
path={`other_settings.${OTHER_SETTINGS_LOCALE_KEY}`}
105+
icon="translation-outlined"
106+
title="Language"
107+
desc={DESC.i18n}
108+
options={langs}
109+
defaultValue={KEEP_EN_LOCALE}
110+
/>
111+
45112
<EditBoolean
46113
path="other_settings.dark_mode"
47114
icon="caret-square-right"
@@ -55,7 +122,7 @@ register({
55122
borderRadius: "3px",
56123
}}
57124
>
58-
{desc.dark_mode} Dark mode is implemented using{" "}
125+
{DESC.dark_mode} Dark mode is implemented using{" "}
59126
<A
60127
style={{ color: "#e96c4d", fontWeight: 700 }}
61128
href="https://darkreader.org/"
@@ -68,50 +135,13 @@ register({
68135
}
69136
/>
70137

71-
{edited.other_settings.dark_mode && (
72-
<div style={{ width: "100%" }}>
73-
<div
74-
style={{
75-
margin: "15px auto",
76-
maxWidth: "700px",
77-
border: "1px solid lightgrey",
78-
padding: "15px",
79-
borderRadius: "5px",
80-
}}
81-
>
82-
<h2 style={{ textAlign: "center" }}>Parameters</h2>
83-
<EditNumber
84-
path="other_settings.dark_mode_brightness"
85-
title="Brightness"
86-
min={20}
87-
max={100}
88-
/>
89-
<EditNumber
90-
path="other_settings.dark_mode_contrast"
91-
title="Contrast"
92-
min={20}
93-
max={100}
94-
/>
95-
<EditNumber
96-
path="other_settings.dark_mode_sepia"
97-
title="Sepia"
98-
min={0}
99-
max={100}
100-
/>
101-
<EditNumber
102-
path="other_settings.dark_mode_grayscale"
103-
title="Grayscale"
104-
min={0}
105-
max={100}
106-
/>
107-
</div>
108-
</div>
109-
)}
138+
{renderDarkMode()}
139+
110140
<EditBoolean
111141
path="other_settings.time_ago_absolute"
112142
icon="clock"
113143
title="Timestamp Display"
114-
desc={desc.time_ago_absolute}
144+
desc={DESC.time_ago_absolute}
115145
label="Display timestamps as absolute points in time"
116146
/>
117147
</Space>

src/packages/next/lib/hooks/edit-table.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ interface EditBooleanProps {
5858

5959
export default function useEditTable<T extends object>(
6060
query: object,
61-
options?: Options
61+
options?: Options,
6262
) {
6363
const { loading, value } = useDatabase(query);
6464
const [original, setOriginal] = useState<T | undefined>(undefined);
@@ -125,7 +125,7 @@ export default function useEditTable<T extends object>(
125125
<Checkbox
126126
defaultValue={get(
127127
SCHEMA[keys(query)[0]].user_query?.get?.fields,
128-
path
128+
path,
129129
)}
130130
checked={get(edited, path)}
131131
onChange={(checked) => {
@@ -167,7 +167,7 @@ export default function useEditTable<T extends object>(
167167
<IntegerSlider
168168
defaultValue={get(
169169
SCHEMA[keys(query)[0]].user_query?.get?.fields,
170-
path
170+
path,
171171
)}
172172
initialValue={get(edited, path)}
173173
onChange={(value) => {
@@ -190,22 +190,24 @@ export default function useEditTable<T extends object>(
190190
icon,
191191
options,
192192
style,
193+
defaultValue,
193194
}: {
194195
path: string;
195196
title?: string;
196197
desc?: ReactNode;
197198
icon?: IconName;
198199
options: { [value: string]: ReactNode } | string[];
199200
style?: CSSProperties;
201+
defaultValue?: string;
200202
}) => (
201203
<Space direction="vertical">
202204
<Heading path={path} title={title} icon={icon} desc={desc} />
203205
<SelectWithDefault
204206
style={style}
205-
defaultValue={get(
206-
SCHEMA[keys(query)[0]].user_query?.get?.fields,
207-
path
208-
)}
207+
defaultValue={
208+
defaultValue ??
209+
get(SCHEMA[keys(query)[0]].user_query?.get?.fields, path)
210+
}
209211
initialValue={get(edited, path)}
210212
onChange={(value) => {
211213
setEdited(value, path);

0 commit comments

Comments
 (0)