Implements language selection

This commit is contained in:
Henning Dieterichs 2025-08-29 20:12:33 +02:00
parent 9e4368a8e9
commit 233b37138f
4 changed files with 95 additions and 6 deletions

View file

@ -19,6 +19,7 @@ export interface IMonacoSetup {
loaderConfigPaths: Record<string, string>; loaderConfigPaths: Record<string, string>;
codiconUrl: string; codiconUrl: string;
monacoTypesUrl: string | undefined; monacoTypesUrl: string | undefined;
language?: string;
} }
let loading = false; let loading = false;
@ -57,7 +58,18 @@ async function _loadMonaco(setup: IMonacoSetup): Promise<typeof monaco> {
/** @type {any} */ /** @type {any} */
const req = global.require as any; const req = global.require as any;
req.config({ paths: setup.loaderConfigPaths });
// Configure language if specified
const config: any = { paths: setup.loaderConfigPaths };
if (setup.language) {
config["vs/nls"] = {
availableLanguages: {
"*": setup.language,
},
};
}
req.config(config);
return new Promise((res) => { return new Promise((res) => {
// First load editor.main. If it inlines the plugins, we don't want to try to load them from the server. // First load editor.main. If it inlines the plugins, we don't want to try to load them from the server.
@ -97,7 +109,10 @@ export const prodMonacoSetup = getMonacoSetup(
"node_modules/monaco-editor/min/vs" "node_modules/monaco-editor/min/vs"
); );
export function getMonacoSetup(corePath: string): IMonacoSetup { export function getMonacoSetup(
corePath: string,
language?: string
): IMonacoSetup {
const loaderConfigPaths = { const loaderConfigPaths = {
vs: `${corePath}`, vs: `${corePath}`,
}; };
@ -107,5 +122,6 @@ export function getMonacoSetup(corePath: string): IMonacoSetup {
loaderConfigPaths, loaderConfigPaths,
codiconUrl: `${corePath}/base/browser/ui/codicons/codicon/codicon.ttf`, codiconUrl: `${corePath}/base/browser/ui/codicons/codicon/codicon.ttf`,
monacoTypesUrl: undefined, monacoTypesUrl: undefined,
language,
}; };
} }

View file

@ -1,7 +1,7 @@
import * as React from "react"; import * as React from "react";
import { PlaygroundModel } from "./PlaygroundModel"; import { PlaygroundModel } from "./PlaygroundModel";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { autorun, observable, reaction } from "mobx"; import { observable, reaction } from "mobx";
import { import {
IMessageFromRunner, IMessageFromRunner,
IMessageToRunner, IMessageToRunner,

View file

@ -390,6 +390,72 @@ export class SettingsDialog extends React.Component<{
</Vertical> </Vertical>
</div> </div>
</ListGroup.Item> </ListGroup.Item>
<ListGroup.Item>
<div className="d-flex gap-2">
<label className="d-flex gap-2">
<span>
Language/Localization
<small className="d-block text-muted">
Configure the Monaco Editor language
for UI elements. Leave unconfigured
to use default English.
</small>
</span>
</label>
<Select
value={ref(
modelSettings.settings,
"language"
)}
values={[
undefined,
"de",
"es",
"fr",
"it",
"ja",
"ko",
"ru",
"zh-cn",
"zh-tw",
]}
getLabel={(v) => {
switch (v) {
case undefined:
return "Unconfigured (English)";
case "de":
return "German (Deutsch)";
case "es":
return "Spanish (Español)";
case "fr":
return "French (Français)";
case "it":
return "Italian (Italiano)";
case "ja":
return "Japanese (日本語)";
case "ko":
return "Korean (한국어)";
case "ru":
return "Russian (Русский)";
case "zh-cn":
return "Chinese Simplified (简体中文)";
case "zh-tw":
return "Chinese Traditional (繁體中文)";
default:
return (
v ||
"Unconfigured (English)"
);
}
}}
style={{
width: 250,
marginLeft: "auto",
}}
/>
</div>
</ListGroup.Item>
</ListGroup> </ListGroup>
</Modal.Body> </Modal.Body>
<Modal.Footer> <Modal.Footer>

View file

@ -88,6 +88,8 @@ export interface Settings {
previewFullScreen: boolean; previewFullScreen: boolean;
autoReload: boolean | undefined; autoReload: boolean | undefined;
language?: string;
} }
export type JsonString<T> = string; export type JsonString<T> = string;
@ -97,14 +99,18 @@ export function toLoaderConfig(settings: Settings): IMonacoSetup {
case "latest": case "latest":
return { return {
...getMonacoSetup( ...getMonacoSetup(
`node_modules/monaco-editor/${settings.latestStability}/vs` `node_modules/monaco-editor/${settings.latestStability}/vs`,
settings.language
), ),
monacoTypesUrl: "node_modules/monaco-editor/monaco.d.ts", monacoTypesUrl: "node_modules/monaco-editor/monaco.d.ts",
}; };
case "npm": case "npm":
const url = `https://cdn.jsdelivr.net/npm/monaco-editor@${settings.npmVersion}`; const url = `https://cdn.jsdelivr.net/npm/monaco-editor@${settings.npmVersion}`;
return { return {
...getMonacoSetup(`${url}/${settings.npmStability}/vs`), ...getMonacoSetup(
`${url}/${settings.npmStability}/vs`,
settings.language
),
monacoTypesUrl: `${url}/monaco.d.ts`, monacoTypesUrl: `${url}/monaco.d.ts`,
}; };
case "custom": case "custom":
@ -143,7 +149,7 @@ export function toLoaderConfig(settings: Settings): IMonacoSetup {
break; break;
} }
const setup = { ...getMonacoSetup(coreUrl) }; const setup = { ...getMonacoSetup(coreUrl, settings.language) };
if ( if (
!setup.monacoTypesUrl && !setup.monacoTypesUrl &&
setup.loaderConfigPaths["vs"] && setup.loaderConfigPaths["vs"] &&
@ -186,6 +192,7 @@ export function getDefaultSettings(): Settings {
}), }),
previewFullScreen: false, previewFullScreen: false,
autoReload: true, autoReload: true,
language: undefined,
}; };
return defaultSettings; return defaultSettings;
} }