From 216508e0ab784ad19e253a7db741f0b0a101162f Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Mon, 12 Oct 2026 19:03:07 +0300 Subject: [PATCH 1/6] feat(Compilers): add Ocaml (JS) language support --- README.md | 2 +- docs/docs/languages/ocaml-js.mdx | 93 +++++++++++++++++++ docs/docs/languages/ocaml.mdx | 12 +++ docs/src/components/LanguageSliders.tsx | 1 + docs/src/components/TemplateList.tsx | 1 + e2e/specs/compilers.spec.ts | 24 +++++ functions/vendors/templates.js | 1 + scripts/build.js | 1 + server/php/inc/starter-templates.json | 1 + src/livecodes/UI/command-menu-actions.ts | 1 + src/livecodes/compiler/compile.page.ts | 2 + src/livecodes/html/language-info.html | 27 ++++++ .../locales/en/language-info.lokalise.json | 16 ++++ .../i18n/locales/en/language-info.ts | 8 ++ .../i18n/locales/en/translation.lokalise.json | 4 + src/livecodes/i18n/locales/en/translation.ts | 1 + src/livecodes/languages/languages.ts | 2 + src/livecodes/languages/ocaml-js/index.ts | 3 + .../ocaml-js/lang-ocaml-js-compiler-esm.ts | 38 ++++++++ .../languages/ocaml-js/lang-ocaml-js.ts | 29 ++++++ src/livecodes/languages/ocaml/lang-ocaml.ts | 8 +- src/livecodes/templates/starter/index.ts | 2 + .../templates/starter/ocaml-js-starter.ts | 61 ++++++++++++ src/livecodes/vendors.ts | 2 + src/sdk/models.ts | 5 + storybook/_stories/EmbedOptions/template.ts | 1 + vendor-licenses.md | 2 + 27 files changed, 345 insertions(+), 3 deletions(-) create mode 100644 docs/docs/languages/ocaml-js.mdx create mode 100644 src/livecodes/languages/ocaml-js/index.ts create mode 100644 src/livecodes/languages/ocaml-js/lang-ocaml-js-compiler-esm.ts create mode 100644 src/livecodes/languages/ocaml-js/lang-ocaml-js.ts create mode 100644 src/livecodes/templates/starter/ocaml-js-starter.ts diff --git a/README.md b/README.md index ad23bf4e4e..14fea73e0c 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ A [feature-rich](https://livecodes.io/docs/features/), open-source, **client-sid [![LiveCodes: npm version](https://img.shields.io/npm/v/livecodes)](https://www.npmjs.com/package/livecodes) [![LiveCodes: npm downloads](https://img.shields.io/npm/dm/livecodes)](https://www.npmjs.com/package/livecodes) [![LiveCodes: jsdelivr downloads](https://data.jsdelivr.com/v1/package/npm/livecodes/badge?style=rounded)](https://www.jsdelivr.com/package/npm/livecodes) -[![LiveCodes: languages](https://img.shields.io/badge/languages-123-blue)](https://livecodes.io/docs/languages/) +[![LiveCodes: languages](https://img.shields.io/badge/languages-124-blue)](https://livecodes.io/docs/languages/) [![LiveCodes: docs](https://img.shields.io/badge/Documentation-575757?logo=gitbook&logoColor=white)](https://livecodes.io/docs/) [![LiveCodes: llms.txt](https://img.shields.io/badge/llms.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms.txt) [![LiveCodes: llms-full.txt](https://img.shields.io/badge/llms--full.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms-full.txt) diff --git a/docs/docs/languages/ocaml-js.mdx b/docs/docs/languages/ocaml-js.mdx new file mode 100644 index 0000000000..2e4c118f37 --- /dev/null +++ b/docs/docs/languages/ocaml-js.mdx @@ -0,0 +1,93 @@ +# OCaml (JS) + +[OCaml](https://ocaml.org/) is an industrial-strength programming language supporting functional, imperative and object-oriented styles. + +LiveCodes runs the OCaml compiler itself, built with [js_of_ocaml](https://github.com/ocsigen/js_of_ocaml), so compilation happens in the browser and nothing is sent to a server. The compiler emits a JavaScript program, which the result page then runs. + +:::info Note + +LiveCodes also has an `ocaml` language, which runs the [ReScript](https://rescript-lang.org/) compiler. It is deprecated in favour of this one. Read documentation [here](./ocaml.mdx). + +::: + +## Demo + +import LiveCodes from '../../src/components/LiveCodes.tsx'; + +export const params = { + 'ocaml-js': 'let () =\n print_endline "Hello, World!"\n', + console: 'full', +}; + + + +## Usage + +LiveCodes runs OCaml in the browser, including the standard library. + +Because the compiled program *is* JavaScript by the time it runs, it can interact with the page. JavaScript interoperability and DOM access come from [js_of_ocaml](https://github.com/ocsigen/js_of_ocaml)'s `Js` and `Dom_html` with `open Js_of_ocaml` (see the [example below](#example-usage)). + +## Modules and Libraries + +The standard library is always available. Beyond it, these are linked on demand — the archive is fetched the first time a program names one of its modules, so a program that uses none of them downloads none of them. + +- **js_of_ocaml** — `Js`, `Dom_html`, and the rest of the browser APIs +- **Str**, **Unix**, **Graphics** — from the OCaml distribution +- **Lwt**, **js_of_ocaml-lwt** — promises and concurrency +- **Re** — regular expressions +- **jsonm**, **xmlm**, **uutf** — JSON, XML and Unicode text +- **fmt**, **logs** — formatting and logging +- **base64** — base64 encoding +- **Zarith** — `Z` and `Q`, arbitrary-precision integers and rationals + +Everything here runs in the browser, so a library has to be pure OCaml, or have a JavaScript replacement for its C stubs — Zarith's are provided by `zarith_stubs_js`. Anything needing real threads, processes or a filesystem will not work, whatever is linked. + +This is the set built with the compiler. Other opam packages are not available. + +## Language Info + +### Name + +`ocaml-js` + +### Extensions + +`js.ocaml`, `js.ml` + +### Editor + +`script` + +## Compiler + +The OCaml compiler — the same `compiler-libs` frontend that compiles ordinary OCaml — compiled to JavaScript with [js_of_ocaml](https://github.com/ocsigen/js_of_ocaml). It is published as [@live-codes/ocaml](https://www.npmjs.com/package/@live-codes/ocaml). + +### Version + +`@live-codes/ocaml`: v0.2.0 + +## Code Formatting + +Not supported. + +## Limitations + +There is no ppx support, since a ppx would have to run at compile time and compilation happens at run time here. So `##`, `##.` and `[%js]` are not available; use `Js.Unsafe` and the rest of the bindings instead. + +## Example Usage + +This example counts button clicks in the DOM, using `Dom_html`: + + + +## Starter Template + +https://livecodes.io/?template=ocaml-js + +## Links + +- [OCaml website](https://ocaml.org/) +- [OCaml documentation](https://ocaml.org/docs/) +- [@live-codes/ocaml on npm](https://www.npmjs.com/package/@live-codes/ocaml) +- [js_of_ocaml](https://github.com/ocsigen/js_of_ocaml) +- [OCaml with the ReScript compiler](./ocaml.mdx) in LiveCodes diff --git a/docs/docs/languages/ocaml.mdx b/docs/docs/languages/ocaml.mdx index fe5b1d5b0f..5b9b2c2e12 100644 --- a/docs/docs/languages/ocaml.mdx +++ b/docs/docs/languages/ocaml.mdx @@ -4,6 +4,14 @@ LiveCodes compiles OCaml code to JavaScript using the [ReScript compiler](https://rescript-lang.org/). OCaml in LiveCodes supports JSX via a ReasonReact-compatible syntax. +:::info Deprecation Note + +This language is deprecated in favour of [OCaml (JS)](./ocaml-js.mdx). + +To continue using this language use the language name `rescript-ocaml`. + +::: + ## Usage ### Demo @@ -66,6 +74,10 @@ OCaml React does not support React 19. Use an import map (in [custom settings](. `ocaml` +### Aliases + +`rescript-ocaml` + ### Extensions `.ml`, `.mli` diff --git a/docs/src/components/LanguageSliders.tsx b/docs/src/components/LanguageSliders.tsx index f9d6ce81aa..9c886360a0 100644 --- a/docs/src/components/LanguageSliders.tsx +++ b/docs/src/components/LanguageSliders.tsx @@ -77,6 +77,7 @@ export default function Sliders() { { name: 'elm', title: 'Elm' }, { name: 'rescript', title: 'ReScript' }, { name: 'reason', title: 'Reason' }, + { name: 'ocaml-js', title: 'OCaml (JS)' }, { name: 'ocaml', title: 'OCaml' }, { name: 'nim', title: 'Nim' }, { name: 'nim-wasm', title: 'Nim (Wasm)' }, diff --git a/docs/src/components/TemplateList.tsx b/docs/src/components/TemplateList.tsx index 4ae8323165..434be56784 100644 --- a/docs/src/components/TemplateList.tsx +++ b/docs/src/components/TemplateList.tsx @@ -37,6 +37,7 @@ const templates = [ { name: 'rescript', title: 'ReScript Starter', thumbnail: 'rescript.png' }, { name: 'reason', title: 'Reason Starter', thumbnail: 'reason.svg' }, { name: 'ocaml', title: 'Ocaml Starter', thumbnail: 'ocaml.svg' }, + { name: 'ocaml-js', title: 'OCaml (JS) Starter', thumbnail: 'ocaml.svg' }, { name: 'nim', title: 'Nim Starter', thumbnail: 'nim.svg' }, { name: 'nim-wasm', title: 'Nim (Wasm) Starter', thumbnail: 'nim.svg' }, { name: 'janet-wasm', title: 'Janet (Wasm) Starter', thumbnail: 'janet.png' }, diff --git a/e2e/specs/compilers.spec.ts b/e2e/specs/compilers.spec.ts index d94f4cf736..016031f5f8 100644 --- a/e2e/specs/compilers.spec.ts +++ b/e2e/specs/compilers.spec.ts @@ -1494,6 +1494,30 @@ export class App { };`); }); + test('OCaml (JS)', async ({ page, getTestUrl }) => { + await page.goto(getTestUrl()); + + const { app, getResult, waitForResultUpdate } = await getLoadedApp(page); + + await app.click(':nth-match([title="Change Language"], 3)'); + await app.click('text=OCaml (JS)'); + await waitForEditorFocus(app); + await page.keyboard.insertText( + [ + 'let () =', + ' let squares = List.init 5 (fun i -> i * i) in', + ' Printf.printf "sum=%d\\n" (List.fold_left (+) 0 squares)', + ].join('\n'), + ); + + await waitForResultUpdate(); + const resultText = await getResult().innerHTML('body > script'); + + // The real OCaml compiler, compiled to JavaScript, emitted a bundle the page runs. + expect(resultText).toContain('// Generated by js_of_ocaml'); + expect(resultText).toContain('sum='); + }); + test('LiveScript', async ({ page, getTestUrl, editor }) => { test.skip(editor === 'codejar', 'please fix'); diff --git a/functions/vendors/templates.js b/functions/vendors/templates.js index a9b989323d..523a9ba4c0 100644 --- a/functions/vendors/templates.js +++ b/functions/vendors/templates.js @@ -37,6 +37,7 @@ export const starterTemplates = { "rescript": "ReScript Starter", "reason": "Reason Starter", "ocaml": "Ocaml Starter", + "ocaml-js": "OCaml (JS) Starter", "nim": "Nim Starter", "nim-wasm": "Nim (Wasm) Starter", "crystal-wasm": "Crystal Starter", diff --git a/scripts/build.js b/scripts/build.js index 9436141539..5399a744b0 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -203,6 +203,7 @@ const esmBuild = () => 'languages/postgresql/lang-postgresql-compiler-esm.ts', 'languages/duckdb/lang-duckdb-compiler-esm.ts', 'languages/r/lang-r-script-esm.ts', + 'languages/ocaml-js/lang-ocaml-js-compiler-esm.ts', 'languages/rescript/lang-rescript-compiler-esm.ts', 'i18n/i18n.ts', ] diff --git a/server/php/inc/starter-templates.json b/server/php/inc/starter-templates.json index 6c14769131..af0fff7c46 100644 --- a/server/php/inc/starter-templates.json +++ b/server/php/inc/starter-templates.json @@ -37,6 +37,7 @@ "rescript": "ReScript Starter", "reason": "Reason Starter", "ocaml": "Ocaml Starter", + "ocaml-js": "OCaml (JS) Starter", "nim": "Nim Starter", "nim-wasm": "Nim (Wasm) Starter", "crystal-wasm": "Crystal Starter", diff --git a/src/livecodes/UI/command-menu-actions.ts b/src/livecodes/UI/command-menu-actions.ts index 45689e5e35..64d9c15564 100644 --- a/src/livecodes/UI/command-menu-actions.ts +++ b/src/livecodes/UI/command-menu-actions.ts @@ -293,6 +293,7 @@ export const getCommandMenuActions = ({ 'rescript', 'reason', 'ocaml', + 'ocaml-js', 'nim', 'nim-wasm', 'janet-wasm', diff --git a/src/livecodes/compiler/compile.page.ts b/src/livecodes/compiler/compile.page.ts index 85d1792872..8fbd92515b 100644 --- a/src/livecodes/compiler/compile.page.ts +++ b/src/livecodes/compiler/compile.page.ts @@ -1,6 +1,7 @@ import { runOutsideWorker as diagrams } from '../languages/diagrams'; import { runOutsideWorker as duckdb } from '../languages/duckdb'; import { runOutsideWorker as mdx } from '../languages/mdx'; +import { runOutsideWorker as ocamlJs } from '../languages/ocaml-js'; import { runOutsideWorker as postgresql } from '../languages/postgresql'; import { runOutsideWorker as rescript } from '../languages/rescript'; @@ -8,6 +9,7 @@ import { runOutsideWorker as rescript } from '../languages/rescript'; rescript, reason: rescript, ocaml: rescript, + 'ocaml-js': ocamlJs, mdx, diagrams, postgresql, diff --git a/src/livecodes/html/language-info.html b/src/livecodes/html/language-info.html index f3ace733f1..09f7d7a694 100644 --- a/src/livecodes/html/language-info.html +++ b/src/livecodes/html/language-info.html @@ -1834,6 +1834,33 @@

Objective-C++ (Wasm)

+
+

OCaml (JS)

+
+ OCaml is an industrial-strength programming language supporting functional, imperative and + object-oriented styles. +
+
+ The OCaml compiler runs in the browser and compiles to JavaScript. Nothing is sent to a server. +
+ +
+

OCaml

diff --git a/src/livecodes/i18n/locales/en/language-info.lokalise.json b/src/livecodes/i18n/locales/en/language-info.lokalise.json index bc97a3e294..9bdead6b5b 100644 --- a/src/livecodes/i18n/locales/en/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/en/language-info.lokalise.json @@ -848,6 +848,22 @@ "notes": "", "translation": "OCaml" }, + "ocamlJs.desc1": { + "notes": "", + "translation": "OCaml is an industrial-strength programming language supporting functional, imperative and object-oriented styles." + }, + "ocamlJs.desc2": { + "notes": "", + "translation": "The OCaml compiler runs in the browser and compiles to JavaScript. Nothing is sent to a server." + }, + "ocamlJs.link": { + "notes": "### ###\n
  • \n\n### ###\n\n\n### ###\n
  • \n\n### ###\n\n\n### ###\n
  • \n\n### ###\n\n\n### ###\n
  • \n\n### ###\n\n\n", + "translation": "OCaml website OCaml documentation Learn X in Y minutes, where X=OCaml Load starter template " + }, + "ocamlJs.name": { + "notes": "", + "translation": "OCaml (JS)" + }, "pascal.desc": { "notes": "", "translation": "Pascal running in the browser using pas2js (by the Free Pascal team) compiled to WebAssembly." diff --git a/src/livecodes/i18n/locales/en/language-info.ts b/src/livecodes/i18n/locales/en/language-info.ts index 00c565f32e..fb94cc5632 100644 --- a/src/livecodes/i18n/locales/en/language-info.ts +++ b/src/livecodes/i18n/locales/en/language-info.ts @@ -367,6 +367,14 @@ const languageInfo = { link: '<1><2>OCaml website <3> <4>OCaml documentation <5> <6>ReScript website <7> <8>Learn X in Y minutes, where X=OCaml <9> <10>Load starter template ', name: 'OCaml', }, + ocamlJs: { + desc1: + 'OCaml is an industrial-strength programming language supporting functional, imperative and object-oriented styles.', + desc2: + 'The OCaml compiler runs in the browser and compiles to JavaScript. Nothing is sent to a server.', + link: '<1><2>OCaml website <3> <4>OCaml documentation <5> <6>Learn X in Y minutes, where X=OCaml <7> <8>Load starter template ', + name: 'OCaml (JS)', + }, pascal: { desc: 'Pascal running in the browser using pas2js (by the Free Pascal team) compiled to WebAssembly.', link: '<1> <2>Free Pascal website <3> <4>pas2js documentation <5> <6>pas2js wiki <7> <8>LiveCodes Documentation <9> <10>Load starter template ', diff --git a/src/livecodes/i18n/locales/en/translation.lokalise.json b/src/livecodes/i18n/locales/en/translation.lokalise.json index 0b576592fc..96ea439984 100644 --- a/src/livecodes/i18n/locales/en/translation.lokalise.json +++ b/src/livecodes/i18n/locales/en/translation.lokalise.json @@ -2796,6 +2796,10 @@ "notes": "", "translation": "Ocaml Starter" }, + "templates.starter.ocaml-js": { + "notes": "", + "translation": "OCaml (JS) Starter" + }, "templates.starter.pascal": { "notes": "", "translation": "Pascal Starter" diff --git a/src/livecodes/i18n/locales/en/translation.ts b/src/livecodes/i18n/locales/en/translation.ts index d5d471fa69..e3940de1b2 100644 --- a/src/livecodes/i18n/locales/en/translation.ts +++ b/src/livecodes/i18n/locales/en/translation.ts @@ -1045,6 +1045,7 @@ const translation = { 'nim-wasm': 'Nim (Wasm) Starter', 'objc-wasm': 'Objective-C (Wasm) Starter', ocaml: 'Ocaml Starter', + 'ocaml-js': 'OCaml (JS) Starter', pascal: 'Pascal Starter', perl: 'Perl Starter', phaser: 'Phaser Starter', diff --git a/src/livecodes/languages/languages.ts b/src/livecodes/languages/languages.ts index 5f13c0f553..72b5ac0b3e 100644 --- a/src/livecodes/languages/languages.ts +++ b/src/livecodes/languages/languages.ts @@ -65,6 +65,7 @@ import { mustache } from './mustache'; import { nim, nimWasm } from './nim'; import { nunjucks } from './nunjucks'; import { ocaml } from './ocaml'; +import { ocamlJs } from './ocaml-js'; import { pascal } from './pascal'; import { perl } from './perl'; import { php } from './php'; @@ -165,6 +166,7 @@ export const languages: LanguageSpecs[] = [ rescript, reason, ocaml, + ocamlJs, nim, nimWasm, crystalWasm, diff --git a/src/livecodes/languages/ocaml-js/index.ts b/src/livecodes/languages/ocaml-js/index.ts new file mode 100644 index 0000000000..693576c050 --- /dev/null +++ b/src/livecodes/languages/ocaml-js/index.ts @@ -0,0 +1,3 @@ +export * from './lang-ocaml-js'; +// The compiler runs in the page, and `compile.page.ts` picks it up from here. +export * from './lang-ocaml-js-compiler-esm'; diff --git a/src/livecodes/languages/ocaml-js/lang-ocaml-js-compiler-esm.ts b/src/livecodes/languages/ocaml-js/lang-ocaml-js-compiler-esm.ts new file mode 100644 index 0000000000..cbcd6bf9fb --- /dev/null +++ b/src/livecodes/languages/ocaml-js/lang-ocaml-js-compiler-esm.ts @@ -0,0 +1,38 @@ +// The OCaml compiler is a package of its own (@live-codes/ocaml), loaded from the +// CDN. It runs in the page rather than in the compile worker because it creates its +// own workers, one per compiler program per compile, and because it is an ES module +// where the compile worker is a classic one. +import type { CompilerFunction } from '../../models'; +import { ocamlJsBaseUrl } from '../../vendors'; + +const ocamlJsCompilerUrl = ocamlJsBaseUrl + 'src/compiler/index.js'; +const ocamlJsAssetsBaseUrl = ocamlJsBaseUrl + 'assets/compiler/'; + +interface OcamlCompiler { + compile: (code: string) => Promise<{ js: string | null; diagnostics: string[]; error?: string }>; +} + +// One instance, reused: it holds no per-program state, and loading it means fetching +// and parsing two compilers. +let loading: Promise | undefined; + +const getCompiler = (): Promise => { + loading ??= import(ocamlJsCompilerUrl).then(({ createCompiler }) => + createCompiler({ baseUrl: ocamlJsAssetsBaseUrl }), + ); + return loading; +}; + +export const ocamlCompiler: CompilerFunction = async (code: string) => { + if (!code.trim()) return ''; + + const compiler = await getCompiler(); + const { js, diagnostics, error } = await compiler.compile(code); + + // `error` is the toolchain failing, as opposed to the program not compiling; + // `diagnostics` carries the compiler's own messages, errors and warnings alike. + if (!js) { + return { code: '', info: { errors: error ? [...diagnostics, error] : diagnostics } }; + } + return { code: js, info: {} }; +}; diff --git a/src/livecodes/languages/ocaml-js/lang-ocaml-js.ts b/src/livecodes/languages/ocaml-js/lang-ocaml-js.ts new file mode 100644 index 0000000000..3bca72d939 --- /dev/null +++ b/src/livecodes/languages/ocaml-js/lang-ocaml-js.ts @@ -0,0 +1,29 @@ +import { codemirrorLegacy } from '../../editor/codemirror/utils'; +import type { CompilerFunction, LanguageSpecs } from '../../models'; +import { codeMirrorBaseUrl, monacoLanguagesBaseUrl } from '../../vendors'; + +export const runOutsideWorker: CompilerFunction = async (code: string, { baseUrl, language }) => { + const { ocamlCompiler } = await import(baseUrl + '{{hash:lang-ocaml-js-compiler-esm.js}}'); + return ocamlCompiler(code, { baseUrl, language }); +}; + +export const ocamlJs: LanguageSpecs = { + name: 'ocaml-js', + title: 'OCaml (JS)', + longTitle: 'OCaml (compiled to JavaScript)', + compiler: { + factory: () => async (code) => code, + runOutsideWorker, + }, + extensions: ['ocaml-js', 'js.ocaml', 'js.ml'], + editor: 'script', + editorSupport: { + monaco: { languageSupport: monacoLanguagesBaseUrl + 'ocaml.js', language: 'ocaml' }, + codemirror: { + languageSupport: async () => + codemirrorLegacy((await import(codeMirrorBaseUrl + 'codemirror-lang-mllike.js')).oCaml), + }, + codejar: { language: 'ocaml' }, + }, + largeDownload: true, +}; diff --git a/src/livecodes/languages/ocaml/lang-ocaml.ts b/src/livecodes/languages/ocaml/lang-ocaml.ts index e99087f5cc..fc93fce159 100644 --- a/src/livecodes/languages/ocaml/lang-ocaml.ts +++ b/src/livecodes/languages/ocaml/lang-ocaml.ts @@ -1,12 +1,16 @@ import { codemirrorLegacy } from '../../editor/codemirror/utils'; -import type { LanguageSpecs } from '../../models'; +import type { Language, LanguageSpecs } from '../../models'; import { codeMirrorBaseUrl } from '../../vendors'; export const ocaml: LanguageSpecs = { name: 'ocaml', title: 'OCaml', compiler: 'rescript', - extensions: ['ml', 'mli'], + // This entry runs the ReScript compiler, not OCaml. `ocaml-js` is the real one; + // until the swap, `ocaml` still resolves here, with a warning. + deprecation: (lang: Language) => + ['ocaml', 'ml', 'mli'].includes(lang) ? { old: 'ocaml', new: 'ocaml-js' } : undefined, + extensions: ['ml', 'mli', 'rescript-ocaml'], editor: 'script', editorSupport: { monaco: { language: 'csharp' }, diff --git a/src/livecodes/templates/starter/index.ts b/src/livecodes/templates/starter/index.ts index 18a2a1e3b9..4fc6bd22a0 100644 --- a/src/livecodes/templates/starter/index.ts +++ b/src/livecodes/templates/starter/index.ts @@ -58,6 +58,7 @@ import { mdxStarter } from './mdx-starter'; import { minizincStarter } from './minizinc-starter'; import { nimStarter } from './nim-starter'; import { nimWasmStarter } from './nim-wasm-starter'; +import { ocamlJsStarter } from './ocaml-js-starter'; import { ocamlStarter } from './ocaml-starter'; import { pascalStarter } from './pascal-starter'; import { perlStarter } from './perl-starter'; @@ -135,6 +136,7 @@ export const starterTemplates = [ rescriptStarter, reasonStarter, ocamlStarter, + ocamlJsStarter, nimStarter, nimWasmStarter, crystalWasmStarter, diff --git a/src/livecodes/templates/starter/ocaml-js-starter.ts b/src/livecodes/templates/starter/ocaml-js-starter.ts new file mode 100644 index 0000000000..7c1b20af18 --- /dev/null +++ b/src/livecodes/templates/starter/ocaml-js-starter.ts @@ -0,0 +1,61 @@ +import type { Template } from '../../models'; + +export const ocamlJsStarter: Template = { + name: 'ocaml-js', + title: window.deps.translateString('templates.starter.ocaml-js', 'OCaml (JS) Starter'), + thumbnail: 'assets/templates/ocaml.svg', + activeEditor: 'script', + markup: { + language: 'html', + content: ` +
    +

    Hello, World!

    + +

    You clicked 0 times.

    + +
    +`.trimStart(), + }, + style: { + language: 'css', + content: ` +.container, +.container button { + text-align: center; + font: 1em sans-serif; +} +.logo { + width: 150px; +} +`.trimStart(), + }, + script: { + language: 'ocaml-js', + content: ` +open Js_of_ocaml + +let () = + let select id = + Js.Unsafe.meth_call Dom_html.document "querySelector" + [| Js.Unsafe.inject (Js.string ("#" ^ id)) |] + in + let title = select "title" in + let counter = select "counter" in + let button = select "counter-button" in + + Js.Unsafe.set title "innerText" (Js.string "OCaml"); + let count = ref 0 in + + ignore + (Js.Unsafe.meth_call button "addEventListener" + [| + Js.Unsafe.inject (Js.string "click"); + Js.Unsafe.inject + (Js.wrap_callback (fun _ -> + incr count; + Js.Unsafe.set counter "innerText" + (Js.string (string_of_int !count)))); + |]) +`.trimStart(), + }, +}; diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 5c60c99741..2aa4ae9235 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -477,6 +477,8 @@ export const reasonReactUrl = /* @__PURE__ */ getUrl( export const reasonStdLibBaseUrl = /* @__PURE__ */ getUrl('@rescript/std@9.1.3/lib/es6/'); +export const ocamlJsBaseUrl = /* @__PURE__ */ getUrl('@live-codes/ocaml@0.2.0/'); + export const rescriptCdnBaseUrl = /* @__PURE__ */ getUrl('https://cdn.rescript-lang.org/v11.1.2/'); export const rescriptStdLibBaseUrl = /* @__PURE__ */ getUrl('@rescript/std@11.1.2/lib/es6/'); diff --git a/src/sdk/models.ts b/src/sdk/models.ts index 956ec547e4..9b29b0bdac 100644 --- a/src/sdk/models.ts +++ b/src/sdk/models.ts @@ -316,6 +316,10 @@ export type Language = | 'ocaml' | 'ml' | 'mli' + | 'ocaml-js' + | 'js.ocaml' + | 'js.ml' + | 'rescript-ocaml' | 'cr' | 'crystal' | 'crystal-wasm' @@ -506,6 +510,7 @@ export type TemplateName = | 'rescript' | 'reason' | 'ocaml' + | 'ocaml-js' | 'nim' | 'nim-wasm' | 'janet-wasm' diff --git a/storybook/_stories/EmbedOptions/template.ts b/storybook/_stories/EmbedOptions/template.ts index b2408f34eb..12d299bfca 100644 --- a/storybook/_stories/EmbedOptions/template.ts +++ b/storybook/_stories/EmbedOptions/template.ts @@ -39,6 +39,7 @@ const storyDef: StoryDef = { ReScript: { props: { template: 'rescript' }, storyName: 'ReScript' }, Reason: { props: { template: 'reason' } }, Ocaml: { props: { template: 'ocaml' } }, + OcamlJs: { props: { template: 'ocaml-js' } }, Nim: { props: { template: 'nim' } }, NimWasm: { props: { template: 'nim-wasm' } }, JanetWasm: { props: { template: 'janet-wasm' } }, diff --git a/vendor-licenses.md b/vendor-licenses.md index 2c581b3e45..a7841eded0 100644 --- a/vendor-licenses.md +++ b/vendor-licenses.md @@ -268,6 +268,8 @@ quill-html-edit-button: [MIT License](https://github.com/benwinding/quill-html-e require.js: [MIT License](https://github.com/marella/require.js/blob/e88122fb11fdd10fb649dd8999723d34074ed647/LICENSE) +@live-codes/ocaml: [LGPL-2.1-or-later with OCaml linking exception](https://github.com/live-codes/browser-ocaml/blob/main/packages/ocaml/LICENSE) + ReScript: [License](https://github.com/rescript-lang/rescript-compiler/blob/d93260cb2d4be63e387959e69f3204af85e5b1b3/LICENSE) ReScript/React: [MIT License](https://github.com/rescript-lang/rescript-react/blob/c3017ec4bbce5847c3b2da8d2d536450a3e2fd6d/LICENSE) From 5847911900e128e3b71810ad65fe383190e8e0d5 Mon Sep 17 00:00:00 2001 From: "pullfrog[bot]" <226033991+pullfrog[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 18:01:14 +0000 Subject: [PATCH 2/6] fix(ocaml-js): address review feedback - drop unused compiler-esm re-export from barrel (avoids static pull-in) - clear cached compiler promise on failed boot so a transient CDN error is retryable - recommend rescript-ocaml, not the deprecated ocaml, in deprecation warning --- src/livecodes/languages/ocaml-js/index.ts | 2 -- .../languages/ocaml-js/lang-ocaml-js-compiler-esm.ts | 12 +++++++++--- src/livecodes/languages/ocaml/lang-ocaml.ts | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/livecodes/languages/ocaml-js/index.ts b/src/livecodes/languages/ocaml-js/index.ts index 693576c050..a771523b52 100644 --- a/src/livecodes/languages/ocaml-js/index.ts +++ b/src/livecodes/languages/ocaml-js/index.ts @@ -1,3 +1 @@ export * from './lang-ocaml-js'; -// The compiler runs in the page, and `compile.page.ts` picks it up from here. -export * from './lang-ocaml-js-compiler-esm'; diff --git a/src/livecodes/languages/ocaml-js/lang-ocaml-js-compiler-esm.ts b/src/livecodes/languages/ocaml-js/lang-ocaml-js-compiler-esm.ts index cbcd6bf9fb..ba6d27b3c7 100644 --- a/src/livecodes/languages/ocaml-js/lang-ocaml-js-compiler-esm.ts +++ b/src/livecodes/languages/ocaml-js/lang-ocaml-js-compiler-esm.ts @@ -17,9 +17,15 @@ interface OcamlCompiler { let loading: Promise | undefined; const getCompiler = (): Promise => { - loading ??= import(ocamlJsCompilerUrl).then(({ createCompiler }) => - createCompiler({ baseUrl: ocamlJsAssetsBaseUrl }), - ); + if (!loading) { + loading = import(ocamlJsCompilerUrl).then(({ createCompiler }) => + createCompiler({ baseUrl: ocamlJsAssetsBaseUrl }), + ); + // do not keep a failed boot (e.g. a transient network error) + loading.catch(() => { + loading = undefined; + }); + } return loading; }; diff --git a/src/livecodes/languages/ocaml/lang-ocaml.ts b/src/livecodes/languages/ocaml/lang-ocaml.ts index fc93fce159..6d9673ba97 100644 --- a/src/livecodes/languages/ocaml/lang-ocaml.ts +++ b/src/livecodes/languages/ocaml/lang-ocaml.ts @@ -9,7 +9,7 @@ export const ocaml: LanguageSpecs = { // This entry runs the ReScript compiler, not OCaml. `ocaml-js` is the real one; // until the swap, `ocaml` still resolves here, with a warning. deprecation: (lang: Language) => - ['ocaml', 'ml', 'mli'].includes(lang) ? { old: 'ocaml', new: 'ocaml-js' } : undefined, + ['ocaml', 'ml', 'mli'].includes(lang) ? { old: 'rescript-ocaml', new: 'ocaml-js' } : undefined, extensions: ['ml', 'mli', 'rescript-ocaml'], editor: 'script', editorSupport: { From 947895548117e247bdf1077da9a385a2b4a3f920 Mon Sep 17 00:00:00 2001 From: "pullfrog[bot]" <226033991+pullfrog[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 18:52:16 +0000 Subject: [PATCH 3/6] i18n: add OCaml (JS) translations to all locales Adds the ocamlJs language-info block (desc1, desc2, link, name) and the templates.starter.ocaml-js label to the 17 non-English locales with real localized text derived from each locale's existing ocaml entry. --- .../i18n/locales/ar/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/ar/language-info.ts | 6 ++++++ .../i18n/locales/ar/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/ar/translation.ts | 1 + .../i18n/locales/bn/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/bn/language-info.ts | 8 ++++++++ .../i18n/locales/bn/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/bn/translation.ts | 1 + .../i18n/locales/de/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/de/language-info.ts | 8 ++++++++ .../i18n/locales/de/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/de/translation.ts | 1 + .../i18n/locales/es/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/es/language-info.ts | 8 ++++++++ .../i18n/locales/es/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/es/translation.ts | 1 + .../i18n/locales/fa/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/fa/language-info.ts | 8 ++++++++ .../i18n/locales/fa/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/fa/translation.ts | 1 + .../i18n/locales/fr/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/fr/language-info.ts | 8 ++++++++ .../i18n/locales/fr/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/fr/translation.ts | 1 + .../i18n/locales/hi/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/hi/language-info.ts | 8 ++++++++ .../i18n/locales/hi/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/hi/translation.ts | 1 + .../i18n/locales/hu/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/hu/language-info.ts | 7 +++++++ .../i18n/locales/hu/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/hu/translation.ts | 1 + .../i18n/locales/id/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/id/language-info.ts | 8 ++++++++ .../i18n/locales/id/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/id/translation.ts | 1 + .../i18n/locales/it/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/it/language-info.ts | 8 ++++++++ .../i18n/locales/it/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/it/translation.ts | 1 + .../i18n/locales/ja/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/ja/language-info.ts | 8 ++++++++ .../i18n/locales/ja/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/ja/translation.ts | 1 + .../i18n/locales/nl/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/nl/language-info.ts | 8 ++++++++ .../i18n/locales/nl/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/nl/translation.ts | 1 + .../i18n/locales/pt/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/pt/language-info.ts | 8 ++++++++ .../i18n/locales/pt/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/pt/translation.ts | 1 + .../i18n/locales/ru/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/ru/language-info.ts | 8 ++++++++ .../i18n/locales/ru/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/ru/translation.ts | 1 + .../i18n/locales/tr/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/tr/language-info.ts | 8 ++++++++ .../i18n/locales/tr/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/tr/translation.ts | 1 + .../i18n/locales/ur/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/ur/language-info.ts | 8 ++++++++ .../i18n/locales/ur/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/ur/translation.ts | 1 + .../i18n/locales/zh-CN/language-info.lokalise.json | 12 ++++++++++++ src/livecodes/i18n/locales/zh-CN/language-info.ts | 6 ++++++ .../i18n/locales/zh-CN/translation.lokalise.json | 3 +++ src/livecodes/i18n/locales/zh-CN/translation.ts | 1 + 68 files changed, 403 insertions(+) diff --git a/src/livecodes/i18n/locales/ar/language-info.lokalise.json b/src/livecodes/i18n/locales/ar/language-info.lokalise.json index 66999f5637..54be4eed48 100644 --- a/src/livecodes/i18n/locales/ar/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/ar/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "OCaml هي لغة برمجة صناعية تدعم الأنماط الوظيفية والإجرائية والكائنية." + }, + "ocamlJs.desc2": { + "translation": "يعمل مُترجم OCaml في المتصفح ويُترجم إلى JavaScript. لا يُرسَل أي شيء إلى خادم." + }, + "ocamlJs.link": { + "translation": "موقع OCaml وثائق OCaml تعلم X في Y دقائق، حيث X=OCaml تحميل القالب الأولي " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "Pascal يعمل في المتصفح باستخدام pas2js (من فريق Free Pascal) ومُجمَّع إلى WebAssembly." }, diff --git a/src/livecodes/i18n/locales/ar/language-info.ts b/src/livecodes/i18n/locales/ar/language-info.ts index ba790a63dc..902b978a49 100644 --- a/src/livecodes/i18n/locales/ar/language-info.ts +++ b/src/livecodes/i18n/locales/ar/language-info.ts @@ -352,6 +352,12 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>موقع OCaml <3> <4>وثائق OCaml <5> <6>موقع ReScript <7> <8>تعلم X في Y دقائق، حيث X=OCaml <9> <10>تحميل القالب الأولي ', name: 'OCaml', }, + ocamlJs: { + desc1: 'OCaml هي لغة برمجة صناعية تدعم الأنماط الوظيفية والإجرائية والكائنية.', + desc2: 'يعمل مُترجم OCaml في المتصفح ويُترجم إلى JavaScript. لا يُرسَل أي شيء إلى خادم.', + link: '<1><2>موقع OCaml <3> <4>وثائق OCaml <5> <6>تعلم X في Y دقائق، حيث X=OCaml <7> <8>تحميل القالب الأولي ', + name: 'OCaml (JS)', + }, pascal: { desc: 'Pascal يعمل في المتصفح باستخدام pas2js (من فريق Free Pascal) ومُجمَّع إلى WebAssembly.', link: '<1> <2>الموقع الرسمي لـ Free Pascal <3> <4>وثائق pas2js <5> <6>pas2js wiki <7> <8>وثائق LiveCodes <9> <10>تحميل القالب الأولي ', diff --git a/src/livecodes/i18n/locales/ar/translation.lokalise.json b/src/livecodes/i18n/locales/ar/translation.lokalise.json index 9c6151e3c1..bce1615867 100644 --- a/src/livecodes/i18n/locales/ar/translation.lokalise.json +++ b/src/livecodes/i18n/locales/ar/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "قالب Ocaml" }, + "templates.starter.ocaml-js": { + "translation": "قالب OCaml (JS)" + }, "templates.starter.pascal": { "translation": "قالب Pascal" }, diff --git a/src/livecodes/i18n/locales/ar/translation.ts b/src/livecodes/i18n/locales/ar/translation.ts index 310eaed198..b69c1e35e5 100644 --- a/src/livecodes/i18n/locales/ar/translation.ts +++ b/src/livecodes/i18n/locales/ar/translation.ts @@ -1037,6 +1037,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'قالب Nim (Wasm)', 'objc-wasm': 'قالب Objective-C (Wasm)', ocaml: 'قالب Ocaml', + 'ocaml-js': 'قالب OCaml (JS)', pascal: 'قالب Pascal', perl: 'قالب Perl', phaser: 'قالب Phaser', diff --git a/src/livecodes/i18n/locales/bn/language-info.lokalise.json b/src/livecodes/i18n/locales/bn/language-info.lokalise.json index 1d41fda745..d2992dd1b4 100644 --- a/src/livecodes/i18n/locales/bn/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/bn/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "OCaml একটি শিল্প-মানের প্রোগ্রামিং ভাষা যা ফাংশনাল, ইম্পেরেটিভ এবং অবজেক্ট-ওরিয়েন্টেড স্টাইল সমর্থন করে।" + }, + "ocamlJs.desc2": { + "translation": "OCaml কম্পাইলার ব্রাউজারে চলে এবং JavaScript-এ কম্পাইল করে। কোনো সার্ভারে কিছু পাঠানো হয় না।" + }, + "ocamlJs.link": { + "translation": "OCaml ওয়েবসাইট OCaml ডকুমেন্টেশন Y মিনিটে X শিখুন, যেখানে X=OCaml স্টার্টার টেমপ্লেট লোড করুন " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "Free Pascal দলের pas2js ব্যবহার করে ব্রাউজারে Pascal চলছে, যা WebAssembly-তে কম্পাইল করা।" }, diff --git a/src/livecodes/i18n/locales/bn/language-info.ts b/src/livecodes/i18n/locales/bn/language-info.ts index 5584ffced1..c286897d47 100644 --- a/src/livecodes/i18n/locales/bn/language-info.ts +++ b/src/livecodes/i18n/locales/bn/language-info.ts @@ -354,6 +354,14 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>OCaml ওয়েবসাইট <3> <4>OCaml ডকুমেন্টেশন <5> <6>ReScript ওয়েবসাইট <7> <8>Y মিনিটে X শিখুন, যেখানে X=OCaml <9> <10>স্টার্টার টেমপ্লেট লোড করুন ', name: 'OCaml', }, + ocamlJs: { + desc1: + 'OCaml একটি শিল্প-মানের প্রোগ্রামিং ভাষা যা ফাংশনাল, ইম্পেরেটিভ এবং অবজেক্ট-ওরিয়েন্টেড স্টাইল সমর্থন করে।', + desc2: + 'OCaml কম্পাইলার ব্রাউজারে চলে এবং JavaScript-এ কম্পাইল করে। কোনো সার্ভারে কিছু পাঠানো হয় না।', + link: '<1><2>OCaml ওয়েবসাইট <3> <4>OCaml ডকুমেন্টেশন <5> <6>Y মিনিটে X শিখুন, যেখানে X=OCaml <7> <8>স্টার্টার টেমপ্লেট লোড করুন ', + name: 'OCaml (JS)', + }, pascal: { desc: 'Free Pascal দলের pas2js ব্যবহার করে ব্রাউজারে Pascal চলছে, যা WebAssembly-তে কম্পাইল করা।', link: '<1> <2>Free Pascal অফিসিয়াল ওয়েবসাইট <3> <4>pas2js ডকুমেন্টেশন <5> <6>pas2js wiki <7> <8>LiveCodes ডকুমেন্টেশন <9> <10>স্টার্টার টেমপ্লেট লোড করুন ', diff --git a/src/livecodes/i18n/locales/bn/translation.lokalise.json b/src/livecodes/i18n/locales/bn/translation.lokalise.json index 0eb6f4228f..35cb6a6598 100644 --- a/src/livecodes/i18n/locales/bn/translation.lokalise.json +++ b/src/livecodes/i18n/locales/bn/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "Ocaml স্টার্টার" }, + "templates.starter.ocaml-js": { + "translation": "OCaml (JS) স্টার্টার" + }, "templates.starter.pascal": { "translation": "Pascal স্টার্টার" }, diff --git a/src/livecodes/i18n/locales/bn/translation.ts b/src/livecodes/i18n/locales/bn/translation.ts index 12d0ac84aa..261aff8d1f 100644 --- a/src/livecodes/i18n/locales/bn/translation.ts +++ b/src/livecodes/i18n/locales/bn/translation.ts @@ -1037,6 +1037,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'Nim (Wasm) স্টার্টার', 'objc-wasm': 'Objective-C (Wasm) স্টার্টার', ocaml: 'Ocaml স্টার্টার', + 'ocaml-js': 'OCaml (JS) স্টার্টার', pascal: 'Pascal স্টার্টার', perl: 'Perl স্টার্টার', phaser: 'Phaser স্টার্টার', diff --git a/src/livecodes/i18n/locales/de/language-info.lokalise.json b/src/livecodes/i18n/locales/de/language-info.lokalise.json index b2f38934bd..07ea64207b 100644 --- a/src/livecodes/i18n/locales/de/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/de/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "OCaml ist eine industrietaugliche Programmiersprache, die funktionale, imperative und objektorientierte Stile unterstützt." + }, + "ocamlJs.desc2": { + "translation": "Der OCaml-Compiler läuft im Browser und kompiliert zu JavaScript. Es wird nichts an einen Server gesendet." + }, + "ocamlJs.link": { + "translation": "OCaml Website OCaml Dokumentation Lerne X in Y Minuten, wobei X=OCaml Starter-Vorlage laden " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "Pascal läuft im Browser mit pas2js (vom Free Pascal-Team) und wird zu WebAssembly kompiliert." }, diff --git a/src/livecodes/i18n/locales/de/language-info.ts b/src/livecodes/i18n/locales/de/language-info.ts index 2fd50e8499..4eadb5a4f1 100644 --- a/src/livecodes/i18n/locales/de/language-info.ts +++ b/src/livecodes/i18n/locales/de/language-info.ts @@ -356,6 +356,14 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>OCaml Website <3> <4>OCaml Dokumentation <5> <6>ReScript Website <7> <8>Lerne X in Y Minuten, wobei X=OCaml <9> <10>Starter-Vorlage laden ', name: 'OCaml', }, + ocamlJs: { + desc1: + 'OCaml ist eine industrietaugliche Programmiersprache, die funktionale, imperative und objektorientierte Stile unterstützt.', + desc2: + 'Der OCaml-Compiler läuft im Browser und kompiliert zu JavaScript. Es wird nichts an einen Server gesendet.', + link: '<1><2>OCaml Website <3> <4>OCaml Dokumentation <5> <6>Lerne X in Y Minuten, wobei X=OCaml <7> <8>Starter-Vorlage laden ', + name: 'OCaml (JS)', + }, pascal: { desc: 'Pascal läuft im Browser mit pas2js (vom Free Pascal-Team) und wird zu WebAssembly kompiliert.', link: '<1> <2>Offizielle Free Pascal-Website <3> <4>pas2js-Dokumentation <5> <6>pas2js wiki <7> <8>LiveCodes-Dokumentationen <9> <10>Starter-Vorlage laden ', diff --git a/src/livecodes/i18n/locales/de/translation.lokalise.json b/src/livecodes/i18n/locales/de/translation.lokalise.json index ff2f1db7e4..275aad54b4 100644 --- a/src/livecodes/i18n/locales/de/translation.lokalise.json +++ b/src/livecodes/i18n/locales/de/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "OCaml-Starter" }, + "templates.starter.ocaml-js": { + "translation": "OCaml (JS)-Starter" + }, "templates.starter.pascal": { "translation": "Pascal-Starter" }, diff --git a/src/livecodes/i18n/locales/de/translation.ts b/src/livecodes/i18n/locales/de/translation.ts index 06096e119e..a53e893385 100644 --- a/src/livecodes/i18n/locales/de/translation.ts +++ b/src/livecodes/i18n/locales/de/translation.ts @@ -1039,6 +1039,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'Nim (Wasm)-Starter', 'objc-wasm': 'Objective-C (Wasm)-Starter', ocaml: 'OCaml-Starter', + 'ocaml-js': 'OCaml (JS)-Starter', pascal: 'Pascal-Starter', perl: 'Perl-Starter', phaser: 'Phaser-Starter', diff --git a/src/livecodes/i18n/locales/es/language-info.lokalise.json b/src/livecodes/i18n/locales/es/language-info.lokalise.json index 3e8ab5a1f2..519fbe2dfc 100644 --- a/src/livecodes/i18n/locales/es/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/es/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "OCaml es un lenguaje de programación de calidad industrial que admite estilos funcionales, imperativos y orientados a objetos." + }, + "ocamlJs.desc2": { + "translation": "El compilador de OCaml se ejecuta en el navegador y compila a JavaScript. No se envía nada a un servidor." + }, + "ocamlJs.link": { + "translation": "Sitio web de OCaml Documentación de OCaml Aprende X en Y minutos, donde X=OCaml Cargar plantilla inicial " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "Pascal ejecutándose en el navegador usando pas2js (por el equipo de Free Pascal), compilado a WebAssembly." }, diff --git a/src/livecodes/i18n/locales/es/language-info.ts b/src/livecodes/i18n/locales/es/language-info.ts index 0d08961637..0deceb75ac 100644 --- a/src/livecodes/i18n/locales/es/language-info.ts +++ b/src/livecodes/i18n/locales/es/language-info.ts @@ -356,6 +356,14 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>Sitio web de OCaml <3> <4>Documentación de OCaml <5> <6>Sitio web de ReScript <7> <8>Aprende X en Y minutos, donde X=OCaml <9> <10>Cargar plantilla inicial ', name: 'OCaml', }, + ocamlJs: { + desc1: + 'OCaml es un lenguaje de programación de calidad industrial que admite estilos funcionales, imperativos y orientados a objetos.', + desc2: + 'El compilador de OCaml se ejecuta en el navegador y compila a JavaScript. No se envía nada a un servidor.', + link: '<1><2>Sitio web de OCaml <3> <4>Documentación de OCaml <5> <6>Aprende X en Y minutos, donde X=OCaml <7> <8>Cargar plantilla inicial ', + name: 'OCaml (JS)', + }, pascal: { desc: 'Pascal ejecutándose en el navegador usando pas2js (por el equipo de Free Pascal), compilado a WebAssembly.', link: '<1> <2>Sitio web oficial de Free Pascal <3> <4>Documentación de pas2js <5> <6>pas2js wiki <7> <8>Documentación de LiveCodes <9> <10>Cargar plantilla inicial ', diff --git a/src/livecodes/i18n/locales/es/translation.lokalise.json b/src/livecodes/i18n/locales/es/translation.lokalise.json index f891de46a9..d283f38192 100644 --- a/src/livecodes/i18n/locales/es/translation.lokalise.json +++ b/src/livecodes/i18n/locales/es/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "Inicio Ocaml" }, + "templates.starter.ocaml-js": { + "translation": "Inicio OCaml (JS)" + }, "templates.starter.pascal": { "translation": "Inicio Pascal" }, diff --git a/src/livecodes/i18n/locales/es/translation.ts b/src/livecodes/i18n/locales/es/translation.ts index 5d28d699e6..c5f3a96fdb 100644 --- a/src/livecodes/i18n/locales/es/translation.ts +++ b/src/livecodes/i18n/locales/es/translation.ts @@ -1037,6 +1037,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'Inicio Nim (Wasm)', 'objc-wasm': 'Inicio Objective-C (Wasm)', ocaml: 'Inicio Ocaml', + 'ocaml-js': 'Inicio OCaml (JS)', pascal: 'Inicio Pascal', perl: 'Inicio Perl', phaser: 'Inicio Phaser', diff --git a/src/livecodes/i18n/locales/fa/language-info.lokalise.json b/src/livecodes/i18n/locales/fa/language-info.lokalise.json index 2f8987b4fa..b38d70c44a 100644 --- a/src/livecodes/i18n/locales/fa/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/fa/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "OCaml یک زبان برنامه‌نویسی با قدرت صنعتی است که از سبک‌های تابعی، دستوری و شی‌گرا پشتیبانی می‌کند." + }, + "ocamlJs.desc2": { + "translation": "کامپایلر OCaml در مرورگر اجرا می‌شود و به JavaScript کامپایل می‌کند. هیچ چیزی به سرور فرستاده نمی‌شود." + }, + "ocamlJs.link": { + "translation": "وب‌سایت OCaml مستندات OCaml یادگیری X در Y دقیقه، جایی که X=OCaml بارگذاری قالب شروع کننده " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "Pascal با استفاده از pas2js (توسط تیم Free Pascal) در مرورگر اجرا می‌شود و به WebAssembly کامپایل شده است." }, diff --git a/src/livecodes/i18n/locales/fa/language-info.ts b/src/livecodes/i18n/locales/fa/language-info.ts index 89b0a7e546..fd34c35141 100644 --- a/src/livecodes/i18n/locales/fa/language-info.ts +++ b/src/livecodes/i18n/locales/fa/language-info.ts @@ -355,6 +355,14 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>وب‌سایت OCaml <3> <4>مستندات OCaml <5> <6>وب‌سایت ReScript <7> <8>یادگیری X در Y دقیقه، جایی که X=OCaml <9> <10>بارگذاری قالب شروع کننده ', name: 'OCaml', }, + ocamlJs: { + desc1: + 'OCaml یک زبان برنامه‌نویسی با قدرت صنعتی است که از سبک‌های تابعی، دستوری و شی‌گرا پشتیبانی می‌کند.', + desc2: + 'کامپایلر OCaml در مرورگر اجرا می‌شود و به JavaScript کامپایل می‌کند. هیچ چیزی به سرور فرستاده نمی‌شود.', + link: '<1><2>وب‌سایت OCaml <3> <4>مستندات OCaml <5> <6>یادگیری X در Y دقیقه، جایی که X=OCaml <7> <8>بارگذاری قالب شروع کننده ', + name: 'OCaml (JS)', + }, pascal: { desc: 'Pascal با استفاده از pas2js (توسط تیم Free Pascal) در مرورگر اجرا می‌شود و به WebAssembly کامپایل شده است.', link: '<1> <2>وب‌سایت رسمی Free Pascal <3> <4>مستندات pas2js <5> <6>pas2js wiki <7> <8>مستندات LiveCodes <9> <10>بارگذاری قالب شروع کننده ', diff --git a/src/livecodes/i18n/locales/fa/translation.lokalise.json b/src/livecodes/i18n/locales/fa/translation.lokalise.json index d428fe0928..35d3b127f8 100644 --- a/src/livecodes/i18n/locales/fa/translation.lokalise.json +++ b/src/livecodes/i18n/locales/fa/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "شروع کننده Ocaml" }, + "templates.starter.ocaml-js": { + "translation": "شروع کننده OCaml (JS)" + }, "templates.starter.pascal": { "translation": "شروع کننده Pascal" }, diff --git a/src/livecodes/i18n/locales/fa/translation.ts b/src/livecodes/i18n/locales/fa/translation.ts index 1d2f6d1d67..51b6c0b6fa 100644 --- a/src/livecodes/i18n/locales/fa/translation.ts +++ b/src/livecodes/i18n/locales/fa/translation.ts @@ -1038,6 +1038,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'شروع کننده Nim (Wasm)', 'objc-wasm': 'شروع کننده Objective-C (Wasm)', ocaml: 'شروع کننده Ocaml', + 'ocaml-js': 'شروع کننده OCaml (JS)', pascal: 'شروع کننده Pascal', perl: 'شروع کننده Perl', phaser: 'شروع کننده Phaser', diff --git a/src/livecodes/i18n/locales/fr/language-info.lokalise.json b/src/livecodes/i18n/locales/fr/language-info.lokalise.json index 8aa0cbdde7..8e19867a15 100644 --- a/src/livecodes/i18n/locales/fr/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/fr/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "OCaml est un langage de programmation de qualité industrielle supportant les styles fonctionnel, impératif et orienté objet." + }, + "ocamlJs.desc2": { + "translation": "Le compilateur OCaml s'exécute dans le navigateur et compile en JavaScript. Rien n'est envoyé à un serveur." + }, + "ocamlJs.link": { + "translation": "Site web OCaml Documentation OCaml Apprenez X en Y minutes, où X=OCaml Charger le modèle de démarrage " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "Pascal s'exécutant dans le navigateur en utilisant pas2js (par l'équipe Free Pascal), compilé en WebAssembly." }, diff --git a/src/livecodes/i18n/locales/fr/language-info.ts b/src/livecodes/i18n/locales/fr/language-info.ts index 9947601f43..305e414031 100644 --- a/src/livecodes/i18n/locales/fr/language-info.ts +++ b/src/livecodes/i18n/locales/fr/language-info.ts @@ -356,6 +356,14 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>Site web OCaml <3> <4>Documentation OCaml <5> <6>Site web ReScript <7> <8>Apprenez X en Y minutes, où X=OCaml <9> <10>Charger le modèle de démarrage ', name: 'OCaml', }, + ocamlJs: { + desc1: + 'OCaml est un langage de programmation de qualité industrielle supportant les styles fonctionnel, impératif et orienté objet.', + desc2: + "Le compilateur OCaml s'exécute dans le navigateur et compile en JavaScript. Rien n'est envoyé à un serveur.", + link: '<1><2>Site web OCaml <3> <4>Documentation OCaml <5> <6>Apprenez X en Y minutes, où X=OCaml <7> <8>Charger le modèle de démarrage ', + name: 'OCaml (JS)', + }, pascal: { desc: "Pascal s'exécutant dans le navigateur en utilisant pas2js (par l'équipe Free Pascal), compilé en WebAssembly.", link: '<1> <2>Site officiel de Free Pascal <3> <4>Documentation pas2js <5> <6>pas2js wiki <7> <8>Documentations LiveCodes <9> <10>Charger le modèle de démarrage ', diff --git a/src/livecodes/i18n/locales/fr/translation.lokalise.json b/src/livecodes/i18n/locales/fr/translation.lokalise.json index 7a5274215b..8d389cfed0 100644 --- a/src/livecodes/i18n/locales/fr/translation.lokalise.json +++ b/src/livecodes/i18n/locales/fr/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "Démarrage OCaml" }, + "templates.starter.ocaml-js": { + "translation": "Démarrage OCaml (JS)" + }, "templates.starter.pascal": { "translation": "Démarrage Pascal" }, diff --git a/src/livecodes/i18n/locales/fr/translation.ts b/src/livecodes/i18n/locales/fr/translation.ts index abf00fb010..5dd8217e05 100644 --- a/src/livecodes/i18n/locales/fr/translation.ts +++ b/src/livecodes/i18n/locales/fr/translation.ts @@ -1039,6 +1039,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'Démarrage Nim (Wasm)', 'objc-wasm': 'Démarrage Objective-C (Wasm)', ocaml: 'Démarrage OCaml', + 'ocaml-js': 'Démarrage OCaml (JS)', pascal: 'Démarrage Pascal', perl: 'Démarrage Perl', phaser: 'Démarrage Phaser', diff --git a/src/livecodes/i18n/locales/hi/language-info.lokalise.json b/src/livecodes/i18n/locales/hi/language-info.lokalise.json index 02bb9b3cf1..659b0f0871 100644 --- a/src/livecodes/i18n/locales/hi/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/hi/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "OCaml एक औद्योगिक-स्तरीय प्रोग्रामिंग भाषा है जो कार्यात्मक, आदेशात्मक और ऑब्जेक्ट-उन्मुख शैलियों का समर्थन करती है।" + }, + "ocamlJs.desc2": { + "translation": "OCaml कंपाइलर ब्राउज़र में चलता है और JavaScript में कंपाइल करता है। किसी सर्वर पर कुछ नहीं भेजा जाता है।" + }, + "ocamlJs.link": { + "translation": "OCaml वेबसाइट OCaml दस्तावेज़ीकरण X को Y मिनटों में सीखें, जहां X=OCaml स्टार्टर टेम्पलेट लोड करें " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "Free Pascal टीम द्वारा pas2js का उपयोग करके ब्राउज़र में चलने वाला Pascal, जो WebAssembly में संकलित है।" }, diff --git a/src/livecodes/i18n/locales/hi/language-info.ts b/src/livecodes/i18n/locales/hi/language-info.ts index da1df6a9d4..b86018be36 100644 --- a/src/livecodes/i18n/locales/hi/language-info.ts +++ b/src/livecodes/i18n/locales/hi/language-info.ts @@ -356,6 +356,14 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>OCaml वेबसाइट <3> <4>OCaml दस्तावेज़ीकरण <5> <6>ReScript वेबसाइट <7> <8>X को Y मिनटों में सीखें, जहां X=OCaml <9> <10>स्टार्टर टेम्पलेट लोड करें ', name: 'OCaml', }, + ocamlJs: { + desc1: + 'OCaml एक औद्योगिक-स्तरीय प्रोग्रामिंग भाषा है जो कार्यात्मक, आदेशात्मक और ऑब्जेक्ट-उन्मुख शैलियों का समर्थन करती है।', + desc2: + 'OCaml कंपाइलर ब्राउज़र में चलता है और JavaScript में कंपाइल करता है। किसी सर्वर पर कुछ नहीं भेजा जाता है।', + link: '<1><2>OCaml वेबसाइट <3> <4>OCaml दस्तावेज़ीकरण <5> <6>X को Y मिनटों में सीखें, जहां X=OCaml <7> <8>स्टार्टर टेम्पलेट लोड करें ', + name: 'OCaml (JS)', + }, pascal: { desc: 'Free Pascal टीम द्वारा pas2js का उपयोग करके ब्राउज़र में चलने वाला Pascal, जो WebAssembly में संकलित है।', link: '<1> <2>Free Pascal आधिकारिक वेबसाइट <3> <4>pas2js दस्तावेज़ीकरण <5> <6>pas2js wiki <7> <8>लाइवकोड्स (LiveCodes) दस्तावेज़ <9> <10>स्टार्टर टेम्पलेट लोड करें ', diff --git a/src/livecodes/i18n/locales/hi/translation.lokalise.json b/src/livecodes/i18n/locales/hi/translation.lokalise.json index 4586943c8d..8f97d032be 100644 --- a/src/livecodes/i18n/locales/hi/translation.lokalise.json +++ b/src/livecodes/i18n/locales/hi/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "OCaml स्टार्टर" }, + "templates.starter.ocaml-js": { + "translation": "OCaml (JS) स्टार्टर" + }, "templates.starter.pascal": { "translation": "Pascal स्टार्टर" }, diff --git a/src/livecodes/i18n/locales/hi/translation.ts b/src/livecodes/i18n/locales/hi/translation.ts index bedcf6fe12..9c4acc8b72 100644 --- a/src/livecodes/i18n/locales/hi/translation.ts +++ b/src/livecodes/i18n/locales/hi/translation.ts @@ -1037,6 +1037,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'Nim (Wasm) स्टार्टर', 'objc-wasm': 'Objective-C (Wasm) स्टार्टर', ocaml: 'OCaml स्टार्टर', + 'ocaml-js': 'OCaml (JS) स्टार्टर', pascal: 'Pascal स्टार्टर', perl: 'Perl स्टार्टर', phaser: 'Phaser स्टार्टर', diff --git a/src/livecodes/i18n/locales/hu/language-info.lokalise.json b/src/livecodes/i18n/locales/hu/language-info.lokalise.json index d98cd14b15..eb61d66ee4 100644 --- a/src/livecodes/i18n/locales/hu/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/hu/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "Az OCaml egy ipari szintű programozási nyelv, amely támogatja a funkcionális, imperatív és objektumorientált stílusokat." + }, + "ocamlJs.desc2": { + "translation": "Az OCaml-fordító a böngészőben fut és JavaScript-re fordít. Semmit sem küld szerverre." + }, + "ocamlJs.link": { + "translation": "OCaml weboldal OCaml dokumentáció Tanulj X-et Y perc alatt, ahol X=OCaml Kezdő sablon betöltése " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "A Pascal a pas2js (a Free Pascal csapatától) segítségével fut a böngészőben, WebAssembly-re fordítva." }, diff --git a/src/livecodes/i18n/locales/hu/language-info.ts b/src/livecodes/i18n/locales/hu/language-info.ts index d0050b1970..bb4cedb9a9 100644 --- a/src/livecodes/i18n/locales/hu/language-info.ts +++ b/src/livecodes/i18n/locales/hu/language-info.ts @@ -356,6 +356,13 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>OCaml weboldal <3> <4>OCaml dokumentáció <5> <6>ReScript weboldal <7> <8>Tanulj X-et Y perc alatt, ahol X=OCaml <9> <10>Kezdő sablon betöltése ', name: 'OCaml', }, + ocamlJs: { + desc1: + 'Az OCaml egy ipari szintű programozási nyelv, amely támogatja a funkcionális, imperatív és objektumorientált stílusokat.', + desc2: 'Az OCaml-fordító a böngészőben fut és JavaScript-re fordít. Semmit sem küld szerverre.', + link: '<1><2>OCaml weboldal <3> <4>OCaml dokumentáció <5> <6>Tanulj X-et Y perc alatt, ahol X=OCaml <7> <8>Kezdő sablon betöltése ', + name: 'OCaml (JS)', + }, pascal: { desc: 'A Pascal a pas2js (a Free Pascal csapatától) segítségével fut a böngészőben, WebAssembly-re fordítva.', link: '<1> <2>Free Pascal hivatalos weboldal <3> <4>pas2js dokumentáció <5> <6>pas2js wiki <7> <8>LiveCodes dokumentációk <9> <10>Kezdő sablon betöltése ', diff --git a/src/livecodes/i18n/locales/hu/translation.lokalise.json b/src/livecodes/i18n/locales/hu/translation.lokalise.json index bfa3a76193..5635b2b280 100644 --- a/src/livecodes/i18n/locales/hu/translation.lokalise.json +++ b/src/livecodes/i18n/locales/hu/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "OCaml kezdő" }, + "templates.starter.ocaml-js": { + "translation": "OCaml (JS) kezdő" + }, "templates.starter.pascal": { "translation": "Pascal kezdő" }, diff --git a/src/livecodes/i18n/locales/hu/translation.ts b/src/livecodes/i18n/locales/hu/translation.ts index f6620bc854..3a0efce1a6 100644 --- a/src/livecodes/i18n/locales/hu/translation.ts +++ b/src/livecodes/i18n/locales/hu/translation.ts @@ -1038,6 +1038,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'Nim (Wasm) kezdő', 'objc-wasm': 'Objective-C (Wasm) kezdő', ocaml: 'OCaml kezdő', + 'ocaml-js': 'OCaml (JS) kezdő', pascal: 'Pascal kezdő', perl: 'Perl kezdő', phaser: 'Phaser kezdő', diff --git a/src/livecodes/i18n/locales/id/language-info.lokalise.json b/src/livecodes/i18n/locales/id/language-info.lokalise.json index 93dc5a4fe9..6b2534e828 100644 --- a/src/livecodes/i18n/locales/id/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/id/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "OCaml adalah bahasa pemrograman tingkat industri yang mendukung gaya fungsional, imperatif, dan berorientasi objek." + }, + "ocamlJs.desc2": { + "translation": "Kompiler OCaml berjalan di browser dan mengompilasi ke JavaScript. Tidak ada yang dikirim ke server." + }, + "ocamlJs.link": { + "translation": "Situs web OCaml Dokumentasi OCaml Pelajari X dalam Y menit, dengan X=OCaml Muat template pemula " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "Pascal berjalan di browser menggunakan pas2js (oleh tim Free Pascal), dikompilasi ke WebAssembly." }, diff --git a/src/livecodes/i18n/locales/id/language-info.ts b/src/livecodes/i18n/locales/id/language-info.ts index 6fa26feef7..d5501b3d8a 100644 --- a/src/livecodes/i18n/locales/id/language-info.ts +++ b/src/livecodes/i18n/locales/id/language-info.ts @@ -356,6 +356,14 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>Situs web OCaml <3> <4>Dokumentasi OCaml <5> <6>Situs web ReScript <7> <8>Pelajari X dalam Y menit, dengan X=OCaml <9> <10>Muat template pemula ', name: 'OCaml', }, + ocamlJs: { + desc1: + 'OCaml adalah bahasa pemrograman tingkat industri yang mendukung gaya fungsional, imperatif, dan berorientasi objek.', + desc2: + 'Kompiler OCaml berjalan di browser dan mengompilasi ke JavaScript. Tidak ada yang dikirim ke server.', + link: '<1><2>Situs web OCaml <3> <4>Dokumentasi OCaml <5> <6>Pelajari X dalam Y menit, dengan X=OCaml <7> <8>Muat template pemula ', + name: 'OCaml (JS)', + }, pascal: { desc: 'Pascal berjalan di browser menggunakan pas2js (oleh tim Free Pascal), dikompilasi ke WebAssembly.', link: '<1> <2>Situs web resmi Free Pascal <3> <4>Dokumentasi pas2js <5> <6>pas2js wiki <7> <8>Dokumentasi LiveCodes <9> <10>Muat template pemula ', diff --git a/src/livecodes/i18n/locales/id/translation.lokalise.json b/src/livecodes/i18n/locales/id/translation.lokalise.json index 8692aa62d4..8bd8ef1060 100644 --- a/src/livecodes/i18n/locales/id/translation.lokalise.json +++ b/src/livecodes/i18n/locales/id/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "Pemula Ocaml" }, + "templates.starter.ocaml-js": { + "translation": "Pemula OCaml (JS)" + }, "templates.starter.pascal": { "translation": "Pemula Pascal" }, diff --git a/src/livecodes/i18n/locales/id/translation.ts b/src/livecodes/i18n/locales/id/translation.ts index c025ca477b..ceca4fe3e9 100644 --- a/src/livecodes/i18n/locales/id/translation.ts +++ b/src/livecodes/i18n/locales/id/translation.ts @@ -1037,6 +1037,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'Pemula Nim (Wasm)', 'objc-wasm': 'Pemula Objective-C (Wasm)', ocaml: 'Pemula Ocaml', + 'ocaml-js': 'Pemula OCaml (JS)', pascal: 'Pemula Pascal', perl: 'Pemula Perl', phaser: 'Pemula Phaser', diff --git a/src/livecodes/i18n/locales/it/language-info.lokalise.json b/src/livecodes/i18n/locales/it/language-info.lokalise.json index 666bd9b59f..2fabcfaf9a 100644 --- a/src/livecodes/i18n/locales/it/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/it/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "OCaml è un linguaggio di programmazione di livello industriale che supporta stili funzionali, imperativi e orientati agli oggetti." + }, + "ocamlJs.desc2": { + "translation": "Il compilatore OCaml viene eseguito nel browser e compila in JavaScript. Niente viene inviato a un server." + }, + "ocamlJs.link": { + "translation": "Sito web di OCaml Documentazione di OCaml Impara X in Y minuti, dove X=OCaml Carica modello di partenza " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "Pascal in esecuzione nel browser utilizzando pas2js (del team Free Pascal), compilato in WebAssembly." }, diff --git a/src/livecodes/i18n/locales/it/language-info.ts b/src/livecodes/i18n/locales/it/language-info.ts index 2ff5f7546a..b451da494b 100644 --- a/src/livecodes/i18n/locales/it/language-info.ts +++ b/src/livecodes/i18n/locales/it/language-info.ts @@ -355,6 +355,14 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>Sito web di OCaml <3> <4>Documentazione di OCaml <5> <6>Sito web di ReScript <7> <8>Impara X in Y minuti, dove X=OCaml <9> <10>Carica modello di partenza ', name: 'OCaml', }, + ocamlJs: { + desc1: + 'OCaml è un linguaggio di programmazione di livello industriale che supporta stili funzionali, imperativi e orientati agli oggetti.', + desc2: + 'Il compilatore OCaml viene eseguito nel browser e compila in JavaScript. Niente viene inviato a un server.', + link: '<1><2>Sito web di OCaml <3> <4>Documentazione di OCaml <5> <6>Impara X in Y minuti, dove X=OCaml <7> <8>Carica modello di partenza ', + name: 'OCaml (JS)', + }, pascal: { desc: 'Pascal in esecuzione nel browser utilizzando pas2js (del team Free Pascal), compilato in WebAssembly.', link: '<1> <2>Sito ufficiale di Free Pascal <3> <4>Documentazione di pas2js <5> <6>pas2js wiki <7> <8>Documentazione LiveCodes <9> <10>Carica modello di partenza ', diff --git a/src/livecodes/i18n/locales/it/translation.lokalise.json b/src/livecodes/i18n/locales/it/translation.lokalise.json index b0fb46284a..a63c0094ba 100644 --- a/src/livecodes/i18n/locales/it/translation.lokalise.json +++ b/src/livecodes/i18n/locales/it/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "Starter OCaml" }, + "templates.starter.ocaml-js": { + "translation": "Starter OCaml (JS)" + }, "templates.starter.pascal": { "translation": "Starter Pascal" }, diff --git a/src/livecodes/i18n/locales/it/translation.ts b/src/livecodes/i18n/locales/it/translation.ts index f58d0479ce..cd499d5189 100644 --- a/src/livecodes/i18n/locales/it/translation.ts +++ b/src/livecodes/i18n/locales/it/translation.ts @@ -1038,6 +1038,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'Starter Nim (Wasm)', 'objc-wasm': 'Starter Objective-C (Wasm)', ocaml: 'Starter OCaml', + 'ocaml-js': 'Starter OCaml (JS)', pascal: 'Starter Pascal', perl: 'Starter Perl', phaser: 'Starter Phaser', diff --git a/src/livecodes/i18n/locales/ja/language-info.lokalise.json b/src/livecodes/i18n/locales/ja/language-info.lokalise.json index f53213bab5..1290fff804 100644 --- a/src/livecodes/i18n/locales/ja/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/ja/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "OCaml は、関数型、命令型、オブジェクト指向スタイルをサポートする産業用プログラミング言語です。" + }, + "ocamlJs.desc2": { + "translation": "OCaml コンパイラはブラウザ内で実行され、JavaScript にコンパイルされます。サーバーには何も送信されません。" + }, + "ocamlJs.link": { + "translation": "OCaml ウェブサイト OCaml ドキュメント X分でYを学ぶ、X=OCaml スターターテンプレートを読み込む " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "pas2js(Free Pascal チームによる)を使用してブラウザで動作する Pascal。WebAssembly にコンパイルされます。" }, diff --git a/src/livecodes/i18n/locales/ja/language-info.ts b/src/livecodes/i18n/locales/ja/language-info.ts index 7adf4071ee..d7162414a3 100644 --- a/src/livecodes/i18n/locales/ja/language-info.ts +++ b/src/livecodes/i18n/locales/ja/language-info.ts @@ -356,6 +356,14 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>OCaml ウェブサイト <3> <4>OCaml ドキュメント <5> <6>ReScript ウェブサイト <7> <8>X分でYを学ぶ、X=OCaml <9> <10>スターターテンプレートを読み込む ', name: 'OCaml', }, + ocamlJs: { + desc1: + 'OCaml は、関数型、命令型、オブジェクト指向スタイルをサポートする産業用プログラミング言語です。', + desc2: + 'OCaml コンパイラはブラウザ内で実行され、JavaScript にコンパイルされます。サーバーには何も送信されません。', + link: '<1><2>OCaml ウェブサイト <3> <4>OCaml ドキュメント <5> <6>X分でYを学ぶ、X=OCaml <7> <8>スターターテンプレートを読み込む ', + name: 'OCaml (JS)', + }, pascal: { desc: 'pas2js(Free Pascal チームによる)を使用してブラウザで動作する Pascal。WebAssembly にコンパイルされます。', link: '<1> <2>Free Pascal 公式ウェブサイト <3> <4>pas2js ドキュメント <5> <6>pas2js wiki <7> <8>LiveCodes ドキュメント <9> <10>スターターテンプレートを読み込む ', diff --git a/src/livecodes/i18n/locales/ja/translation.lokalise.json b/src/livecodes/i18n/locales/ja/translation.lokalise.json index 1f5141fe25..02cab7c9df 100644 --- a/src/livecodes/i18n/locales/ja/translation.lokalise.json +++ b/src/livecodes/i18n/locales/ja/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "OCamlスターター" }, + "templates.starter.ocaml-js": { + "translation": "OCaml(JS)スターター" + }, "templates.starter.pascal": { "translation": "Pascalスターター" }, diff --git a/src/livecodes/i18n/locales/ja/translation.ts b/src/livecodes/i18n/locales/ja/translation.ts index 494d0b5174..54c2e43544 100644 --- a/src/livecodes/i18n/locales/ja/translation.ts +++ b/src/livecodes/i18n/locales/ja/translation.ts @@ -1038,6 +1038,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'Nim(Wasm)スターター', 'objc-wasm': 'Objective-C(Wasm)スターター', ocaml: 'OCamlスターター', + 'ocaml-js': 'OCaml(JS)スターター', pascal: 'Pascalスターター', perl: 'Perlスターター', phaser: 'Phaserスターター', diff --git a/src/livecodes/i18n/locales/nl/language-info.lokalise.json b/src/livecodes/i18n/locales/nl/language-info.lokalise.json index 9e791e5f3e..23635c8f14 100644 --- a/src/livecodes/i18n/locales/nl/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/nl/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "OCaml is een industriële programmeertaal die functionele, imperatieve en objectgeoriënteerde stijlen ondersteunt." + }, + "ocamlJs.desc2": { + "translation": "De OCaml-compiler draait in de browser en compileert naar JavaScript. Er wordt niets naar een server verzonden." + }, + "ocamlJs.link": { + "translation": "OCaml website OCaml documentatie Leer X in Y minuten, waarbij X=OCaml Startsjabloon laden " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "Pascal draaiend in de browser met pas2js (van het Free Pascal-team), gecompileerd naar WebAssembly." }, diff --git a/src/livecodes/i18n/locales/nl/language-info.ts b/src/livecodes/i18n/locales/nl/language-info.ts index fe5a3b303f..07f21b04f4 100644 --- a/src/livecodes/i18n/locales/nl/language-info.ts +++ b/src/livecodes/i18n/locales/nl/language-info.ts @@ -355,6 +355,14 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>OCaml website <3> <4>OCaml documentatie <5> <6>ReScript website <7> <8>Leer X in Y minuten, waarbij X=OCaml <9> <10>Startsjabloon laden ', name: 'OCaml', }, + ocamlJs: { + desc1: + 'OCaml is een industriële programmeertaal die functionele, imperatieve en objectgeoriënteerde stijlen ondersteunt.', + desc2: + 'De OCaml-compiler draait in de browser en compileert naar JavaScript. Er wordt niets naar een server verzonden.', + link: '<1><2>OCaml website <3> <4>OCaml documentatie <5> <6>Leer X in Y minuten, waarbij X=OCaml <7> <8>Startsjabloon laden ', + name: 'OCaml (JS)', + }, pascal: { desc: 'Pascal draaiend in de browser met pas2js (van het Free Pascal-team), gecompileerd naar WebAssembly.', link: '<1> <2>Free Pascal officiële website <3> <4>pas2js-documentatie <5> <6>pas2js wiki <7> <8>LiveCodes-documentatie <9> <10>Startsjabloon laden ', diff --git a/src/livecodes/i18n/locales/nl/translation.lokalise.json b/src/livecodes/i18n/locales/nl/translation.lokalise.json index 6e1729fe00..0bb23e27cd 100644 --- a/src/livecodes/i18n/locales/nl/translation.lokalise.json +++ b/src/livecodes/i18n/locales/nl/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "Ocaml-starter" }, + "templates.starter.ocaml-js": { + "translation": "OCaml (JS)-starter" + }, "templates.starter.pascal": { "translation": "Pascal-starter" }, diff --git a/src/livecodes/i18n/locales/nl/translation.ts b/src/livecodes/i18n/locales/nl/translation.ts index fce2ffb52a..d802e88094 100644 --- a/src/livecodes/i18n/locales/nl/translation.ts +++ b/src/livecodes/i18n/locales/nl/translation.ts @@ -1038,6 +1038,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'Nim (Wasm)-starter', 'objc-wasm': 'Objective-C (Wasm)-starter', ocaml: 'Ocaml-starter', + 'ocaml-js': 'OCaml (JS)-starter', pascal: 'Pascal-starter', perl: 'Perl-starter', phaser: 'Phaser-starter', diff --git a/src/livecodes/i18n/locales/pt/language-info.lokalise.json b/src/livecodes/i18n/locales/pt/language-info.lokalise.json index 18a2fea497..229555b5c8 100644 --- a/src/livecodes/i18n/locales/pt/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/pt/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "OCaml é uma linguagem de programação de nível industrial que suporta estilos funcionais, imperativos e orientados a objetos." + }, + "ocamlJs.desc2": { + "translation": "O compilador OCaml é executado no navegador e compila para JavaScript. Nada é enviado a um servidor." + }, + "ocamlJs.link": { + "translation": "Site do OCaml Documentação do OCaml Aprenda X em Y minutos, onde X=OCaml Carregar modelo inicial " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "Pascal rodando no navegador usando pas2js (pela equipe do Free Pascal), compilado para WebAssembly." }, diff --git a/src/livecodes/i18n/locales/pt/language-info.ts b/src/livecodes/i18n/locales/pt/language-info.ts index dc7df1f9b9..88c90bdd67 100644 --- a/src/livecodes/i18n/locales/pt/language-info.ts +++ b/src/livecodes/i18n/locales/pt/language-info.ts @@ -355,6 +355,14 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>Site do OCaml <3> <4>Documentação do OCaml <5> <6>Site do ReScript <7> <8>Aprenda X em Y minutos, onde X=OCaml <9> <10>Carregar modelo inicial ', name: 'OCaml', }, + ocamlJs: { + desc1: + 'OCaml é uma linguagem de programação de nível industrial que suporta estilos funcionais, imperativos e orientados a objetos.', + desc2: + 'O compilador OCaml é executado no navegador e compila para JavaScript. Nada é enviado a um servidor.', + link: '<1><2>Site do OCaml <3> <4>Documentação do OCaml <5> <6>Aprenda X em Y minutos, onde X=OCaml <7> <8>Carregar modelo inicial ', + name: 'OCaml (JS)', + }, pascal: { desc: 'Pascal rodando no navegador usando pas2js (pela equipe do Free Pascal), compilado para WebAssembly.', link: '<1> <2>Site oficial do Free Pascal <3> <4>Documentação do pas2js <5> <6>pas2js wiki <7> <8>Documentação do LiveCodes <9> <10>Carregar modelo inicial ', diff --git a/src/livecodes/i18n/locales/pt/translation.lokalise.json b/src/livecodes/i18n/locales/pt/translation.lokalise.json index 3ec5ee1dda..2a4a6f1bd8 100644 --- a/src/livecodes/i18n/locales/pt/translation.lokalise.json +++ b/src/livecodes/i18n/locales/pt/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "Iniciante OCaml" }, + "templates.starter.ocaml-js": { + "translation": "Iniciante OCaml (JS)" + }, "templates.starter.pascal": { "translation": "Iniciante Pascal" }, diff --git a/src/livecodes/i18n/locales/pt/translation.ts b/src/livecodes/i18n/locales/pt/translation.ts index 6fbed58c5f..66bff1e295 100644 --- a/src/livecodes/i18n/locales/pt/translation.ts +++ b/src/livecodes/i18n/locales/pt/translation.ts @@ -1038,6 +1038,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'Iniciante Nim (Wasm)', 'objc-wasm': 'Iniciante Objective-C (Wasm)', ocaml: 'Iniciante OCaml', + 'ocaml-js': 'Iniciante OCaml (JS)', pascal: 'Iniciante Pascal', perl: 'Iniciante Perl', phaser: 'Iniciante Phaser', diff --git a/src/livecodes/i18n/locales/ru/language-info.lokalise.json b/src/livecodes/i18n/locales/ru/language-info.lokalise.json index a37d96b9ed..b4125d6bee 100644 --- a/src/livecodes/i18n/locales/ru/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/ru/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "OCaml - это язык программирования промышленного уровня, поддерживающий функциональный, императивный и объектно-ориентированный стили." + }, + "ocamlJs.desc2": { + "translation": "Компилятор OCaml работает в браузере и компилирует в JavaScript. Ничего не отправляется на сервер." + }, + "ocamlJs.link": { + "translation": "Сайт OCaml Документация OCaml Изучите X за Y минут, где X=OCaml Загрузить стартовый шаблон " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "Pascal, работающий в браузере с использованием pas2js (от команды Free Pascal), скомпилирован в WebAssembly." }, diff --git a/src/livecodes/i18n/locales/ru/language-info.ts b/src/livecodes/i18n/locales/ru/language-info.ts index 0ae66ae67a..d22bc60a2d 100644 --- a/src/livecodes/i18n/locales/ru/language-info.ts +++ b/src/livecodes/i18n/locales/ru/language-info.ts @@ -357,6 +357,14 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>Сайт OCaml <3> <4>Документация OCaml <5> <6>Сайт ReScript <7> <8>Изучите X за Y минут, где X=OCaml <9> <10>Загрузить стартовый шаблон ', name: 'OCaml', }, + ocamlJs: { + desc1: + 'OCaml - это язык программирования промышленного уровня, поддерживающий функциональный, императивный и объектно-ориентированный стили.', + desc2: + 'Компилятор OCaml работает в браузере и компилирует в JavaScript. Ничего не отправляется на сервер.', + link: '<1><2>Сайт OCaml <3> <4>Документация OCaml <5> <6>Изучите X за Y минут, где X=OCaml <7> <8>Загрузить стартовый шаблон ', + name: 'OCaml (JS)', + }, pascal: { desc: 'Pascal, работающий в браузере с использованием pas2js (от команды Free Pascal), скомпилирован в WebAssembly.', link: '<1> <2>Официальный сайт Free Pascal <3> <4>Документация pas2js <5> <6>pas2js wiki <7> <8>Документация LiveCodes <9> <10>Загрузить стартовый шаблон ', diff --git a/src/livecodes/i18n/locales/ru/translation.lokalise.json b/src/livecodes/i18n/locales/ru/translation.lokalise.json index 698a451697..33358355ec 100644 --- a/src/livecodes/i18n/locales/ru/translation.lokalise.json +++ b/src/livecodes/i18n/locales/ru/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "Стартер OCaml" }, + "templates.starter.ocaml-js": { + "translation": "Стартер OCaml (JS)" + }, "templates.starter.pascal": { "translation": "Стартер Pascal" }, diff --git a/src/livecodes/i18n/locales/ru/translation.ts b/src/livecodes/i18n/locales/ru/translation.ts index 12b2c9d264..b85d575c47 100644 --- a/src/livecodes/i18n/locales/ru/translation.ts +++ b/src/livecodes/i18n/locales/ru/translation.ts @@ -1037,6 +1037,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'Стартер Nim (Wasm)', 'objc-wasm': 'Стартер Objective-C (Wasm)', ocaml: 'Стартер OCaml', + 'ocaml-js': 'Стартер OCaml (JS)', pascal: 'Стартер Pascal', perl: 'Стартер Perl', phaser: 'Стартер Phaser', diff --git a/src/livecodes/i18n/locales/tr/language-info.lokalise.json b/src/livecodes/i18n/locales/tr/language-info.lokalise.json index 12a018af49..a5f57575df 100644 --- a/src/livecodes/i18n/locales/tr/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/tr/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "OCaml, fonksiyonel, zorunlu ve nesne yönelimli stilleri destekleyen endüstriyel güçte bir programlama dilidir." + }, + "ocamlJs.desc2": { + "translation": "OCaml derleyicisi tarayıcıda çalışır ve JavaScript'e derler. Sunucuya hiçbir şey gönderilmez." + }, + "ocamlJs.link": { + "translation": "OCaml web sitesi OCaml dokümantasyonu Y Dakikada X Öğrenin, X=OCaml Başlangıç şablonunu yükle " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "Pascal, Free Pascal ekibi tarafından pas2js kullanılarak tarayıcıda çalışır ve WebAssembly'ye derlenir." }, diff --git a/src/livecodes/i18n/locales/tr/language-info.ts b/src/livecodes/i18n/locales/tr/language-info.ts index c9919b01ee..732cb48712 100644 --- a/src/livecodes/i18n/locales/tr/language-info.ts +++ b/src/livecodes/i18n/locales/tr/language-info.ts @@ -356,6 +356,14 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>OCaml web sitesi <3> <4>OCaml dokümantasyonu <5> <6>ReScript web sitesi <7> <8>Y Dakikada X Öğrenin, X=OCaml <9> <10>Başlangıç şablonunu yükle ', name: 'OCaml', }, + ocamlJs: { + desc1: + 'OCaml, fonksiyonel, zorunlu ve nesne yönelimli stilleri destekleyen endüstriyel güçte bir programlama dilidir.', + desc2: + "OCaml derleyicisi tarayıcıda çalışır ve JavaScript'e derler. Sunucuya hiçbir şey gönderilmez.", + link: '<1><2>OCaml web sitesi <3> <4>OCaml dokümantasyonu <5> <6>Y Dakikada X Öğrenin, X=OCaml <7> <8>Başlangıç şablonunu yükle ', + name: 'OCaml (JS)', + }, pascal: { desc: "Pascal, Free Pascal ekibi tarafından pas2js kullanılarak tarayıcıda çalışır ve WebAssembly'ye derlenir.", link: '<1> <2>Free Pascal resmi web sitesi <3> <4>pas2js dokümantasyonu <5> <6>pas2js wiki <7> <8>LiveCodes Belgeleri <9> <10>Başlangıç şablonunu yükle ', diff --git a/src/livecodes/i18n/locales/tr/translation.lokalise.json b/src/livecodes/i18n/locales/tr/translation.lokalise.json index 21f71ca22e..f4661766e2 100644 --- a/src/livecodes/i18n/locales/tr/translation.lokalise.json +++ b/src/livecodes/i18n/locales/tr/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "Ocaml Başlangıç" }, + "templates.starter.ocaml-js": { + "translation": "OCaml (JS) Başlangıç" + }, "templates.starter.pascal": { "translation": "Pascal Başlangıç" }, diff --git a/src/livecodes/i18n/locales/tr/translation.ts b/src/livecodes/i18n/locales/tr/translation.ts index 40cbbb8a62..c33e0c0cd3 100644 --- a/src/livecodes/i18n/locales/tr/translation.ts +++ b/src/livecodes/i18n/locales/tr/translation.ts @@ -1038,6 +1038,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'Nim (Wasm) Başlangıç', 'objc-wasm': 'Objective-C (Wasm) Başlangıç', ocaml: 'Ocaml Başlangıç', + 'ocaml-js': 'OCaml (JS) Başlangıç', pascal: 'Pascal Başlangıç', perl: 'Perl Başlangıç', phaser: 'Phaser Başlangıç', diff --git a/src/livecodes/i18n/locales/ur/language-info.lokalise.json b/src/livecodes/i18n/locales/ur/language-info.lokalise.json index 3b41cfa401..11cee31c51 100644 --- a/src/livecodes/i18n/locales/ur/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/ur/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "او کیمل" }, + "ocamlJs.desc1": { + "translation": "او کیمل ایک صنعتی طاقت کی پروگرامنگ زبان ہے جو فنکشنل، امپیریٹیو اور آبجیکٹ اورینٹڈ طرزوں کی معاونت کرتی ہے۔" + }, + "ocamlJs.desc2": { + "translation": "OCaml کمپائلر براؤزر میں چلتا ہے اور JavaScript میں کمپائل کرتا ہے۔ سرور پر کچھ نہیں بھیجا جاتا۔" + }, + "ocamlJs.link": { + "translation": "او کیمل ویب سائٹ او کیمل دستاویزات X کو Y منٹ میں سیکھیں، جہاں X=او کیمل ابتدائی سانچہ لوڈ کریں " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "Free Pascal ٹیم کے pas2js کا استعمال کرتے ہوئے براؤزر میں چلنے والا Pascal، جو WebAssembly میں مرتب کیا گیا ہے۔" }, diff --git a/src/livecodes/i18n/locales/ur/language-info.ts b/src/livecodes/i18n/locales/ur/language-info.ts index 65134f09f6..8ecd10f1f3 100644 --- a/src/livecodes/i18n/locales/ur/language-info.ts +++ b/src/livecodes/i18n/locales/ur/language-info.ts @@ -357,6 +357,14 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>او کیمل ویب سائٹ <3> <4>او کیمل دستاویزات <5> <6>ری اسکرپٹ ویب سائٹ <7> <8>X کو Y منٹ میں سیکھیں، جہاں X=او کیمل <9> <10>ابتدائی سانچہ لوڈ کریں ', name: 'او کیمل', }, + ocamlJs: { + desc1: + 'او کیمل ایک صنعتی طاقت کی پروگرامنگ زبان ہے جو فنکشنل، امپیریٹیو اور آبجیکٹ اورینٹڈ طرزوں کی معاونت کرتی ہے۔', + desc2: + 'OCaml کمپائلر براؤزر میں چلتا ہے اور JavaScript میں کمپائل کرتا ہے۔ سرور پر کچھ نہیں بھیجا جاتا۔', + link: '<1><2>او کیمل ویب سائٹ <3> <4>او کیمل دستاویزات <5> <6>X کو Y منٹ میں سیکھیں، جہاں X=او کیمل <7> <8>ابتدائی سانچہ لوڈ کریں ', + name: 'OCaml (JS)', + }, pascal: { desc: 'Free Pascal ٹیم کے pas2js کا استعمال کرتے ہوئے براؤزر میں چلنے والا Pascal، جو WebAssembly میں مرتب کیا گیا ہے۔', link: '<1> <2>Free Pascal کی سرکاری ویب سائٹ <3> <4>pas2js دستاویزات <5> <6>pas2js wiki <7> <8>لائیو کوڈز دستاویزات <9> <10>ابتدائی سانچہ لوڈ کریں ', diff --git a/src/livecodes/i18n/locales/ur/translation.lokalise.json b/src/livecodes/i18n/locales/ur/translation.lokalise.json index 00ba8dd0c1..4d466e54af 100644 --- a/src/livecodes/i18n/locales/ur/translation.lokalise.json +++ b/src/livecodes/i18n/locales/ur/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "اوکامل شروعاتی" }, + "templates.starter.ocaml-js": { + "translation": "OCaml (JS) شروعاتی" + }, "templates.starter.pascal": { "translation": "پاسکل شروعاتی" }, diff --git a/src/livecodes/i18n/locales/ur/translation.ts b/src/livecodes/i18n/locales/ur/translation.ts index 5e27137393..88479ceb56 100644 --- a/src/livecodes/i18n/locales/ur/translation.ts +++ b/src/livecodes/i18n/locales/ur/translation.ts @@ -1037,6 +1037,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'Nim (واسم) شروعاتی', 'objc-wasm': 'Objective-C (واسم) شروعاتی', ocaml: 'اوکامل شروعاتی', + 'ocaml-js': 'OCaml (JS) شروعاتی', pascal: 'پاسکل شروعاتی', perl: 'پرل شروعاتی', phaser: 'فیزر شروعاتی', diff --git a/src/livecodes/i18n/locales/zh-CN/language-info.lokalise.json b/src/livecodes/i18n/locales/zh-CN/language-info.lokalise.json index 5abff12b47..d42dabcb53 100644 --- a/src/livecodes/i18n/locales/zh-CN/language-info.lokalise.json +++ b/src/livecodes/i18n/locales/zh-CN/language-info.lokalise.json @@ -636,6 +636,18 @@ "ocaml.name": { "translation": "OCaml" }, + "ocamlJs.desc1": { + "translation": "OCaml 是一种工业级编程语言,支持函数式、命令式和面向对象编程范式。" + }, + "ocamlJs.desc2": { + "translation": "OCaml 编译器在浏览器中运行并编译为 JavaScript。不会向服务器发送任何内容。" + }, + "ocamlJs.link": { + "translation": "OCaml 官方网站 OCaml 文档 在 Y 分钟内学习 X,其中 X=OCaml 加载启动模板 " + }, + "ocamlJs.name": { + "translation": "OCaml (JS)" + }, "pascal.desc": { "translation": "使用 Free Pascal 团队的 pas2js 在浏览器中运行的 Pascal,并编译为 WebAssembly。" }, diff --git a/src/livecodes/i18n/locales/zh-CN/language-info.ts b/src/livecodes/i18n/locales/zh-CN/language-info.ts index 286e371b41..ef14343087 100644 --- a/src/livecodes/i18n/locales/zh-CN/language-info.ts +++ b/src/livecodes/i18n/locales/zh-CN/language-info.ts @@ -350,6 +350,12 @@ const languageInfo: I18nLangInfoTranslation = { link: '<1><2>OCaml 官方网站 <3> <4>OCaml 文档 <5> <6>ReScript 网站 <7> <8>在 Y 分钟内学习 X,其中 X=OCaml <9> <10>加载启动模板 ', name: 'OCaml', }, + ocamlJs: { + desc1: 'OCaml 是一种工业级编程语言,支持函数式、命令式和面向对象编程范式。', + desc2: 'OCaml 编译器在浏览器中运行并编译为 JavaScript。不会向服务器发送任何内容。', + link: '<1><2>OCaml 官方网站 <3> <4>OCaml 文档 <5> <6>在 Y 分钟内学习 X,其中 X=OCaml <7> <8>加载启动模板 ', + name: 'OCaml (JS)', + }, pascal: { desc: '使用 Free Pascal 团队的 pas2js 在浏览器中运行的 Pascal,并编译为 WebAssembly。', link: '<1> <2>Free Pascal 官网 <3> <4>pas2js 文档 <5> <6>pas2js wiki <7> <8>LiveCodes 文档 <9> <10>加载启动模板 ', diff --git a/src/livecodes/i18n/locales/zh-CN/translation.lokalise.json b/src/livecodes/i18n/locales/zh-CN/translation.lokalise.json index a60b50a2f4..ed3cdfc3a6 100644 --- a/src/livecodes/i18n/locales/zh-CN/translation.lokalise.json +++ b/src/livecodes/i18n/locales/zh-CN/translation.lokalise.json @@ -2097,6 +2097,9 @@ "templates.starter.ocaml": { "translation": "Ocaml 启动模板" }, + "templates.starter.ocaml-js": { + "translation": "OCaml(JS)启动模板" + }, "templates.starter.pascal": { "translation": "Pascal 启动模板" }, diff --git a/src/livecodes/i18n/locales/zh-CN/translation.ts b/src/livecodes/i18n/locales/zh-CN/translation.ts index 11c63750d6..6566987f14 100644 --- a/src/livecodes/i18n/locales/zh-CN/translation.ts +++ b/src/livecodes/i18n/locales/zh-CN/translation.ts @@ -1035,6 +1035,7 @@ const translation: I18nTranslation = { 'nim-wasm': 'Nim(WASM)启动模板', 'objc-wasm': 'Objective-C(WASM)启动模板', ocaml: 'Ocaml 启动模板', + 'ocaml-js': 'OCaml(JS)启动模板', pascal: 'Pascal 启动模板', perl: 'Perl 启动模板', phaser: 'Phaser 启动模板', From d04ceb925da0a51d9ec0816f484f85989e5dc359 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Mon, 12 Oct 2026 22:52:49 +0300 Subject: [PATCH 4/6] update ocaml logo --- src/livecodes/assets/templates/ocaml.svg | 117 ++++++++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/src/livecodes/assets/templates/ocaml.svg b/src/livecodes/assets/templates/ocaml.svg index 7df1be4624..675eb33351 100644 --- a/src/livecodes/assets/templates/ocaml.svg +++ b/src/livecodes/assets/templates/ocaml.svg @@ -1 +1,116 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 7819304a06c760239d84459ffbd8e869ef435c04 Mon Sep 17 00:00:00 2001 From: "pullfrog[bot]" <226033991+pullfrog[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 20:07:21 +0000 Subject: [PATCH 5/6] fix(ocaml-js): keep app loading when deprecation warns in worker The compile worker is created from a data: URL, which is not a valid base for `new URL()`, so `getDocsUrl()` threw while building the deprecation warning link. Because the OCaml deprecation predicate also matches the canonical name `ocaml`, the warning now fires while the worker enumerates languages, aborting its init message and leaving the app stuck on the loading screen. Fall back to the configured relative docs path when the base URL cannot be used. The e2e test now selects the language by `data-lang`, since the dropdown shows the long title ("OCaml (compiled to JavaScript)"). --- e2e/specs/compilers.spec.ts | 2 +- src/livecodes/utils/utils.ts | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/e2e/specs/compilers.spec.ts b/e2e/specs/compilers.spec.ts index 016031f5f8..4a106409e3 100644 --- a/e2e/specs/compilers.spec.ts +++ b/e2e/specs/compilers.spec.ts @@ -1500,7 +1500,7 @@ export class App { const { app, getResult, waitForResultUpdate } = await getLoadedApp(page); await app.click(':nth-match([title="Change Language"], 3)'); - await app.click('text=OCaml (JS)'); + await (await app.$('[data-lang="ocaml-js"]'))?.click(); await waitForEditorFocus(app); await page.keyboard.insertText( [ diff --git a/src/livecodes/utils/utils.ts b/src/livecodes/utils/utils.ts index 11c3a5ac20..e95cfc688f 100644 --- a/src/livecodes/utils/utils.ts +++ b/src/livecodes/utils/utils.ts @@ -738,9 +738,15 @@ export const onLoad = /* @__PURE__ */ (fn: (...args: any[]) => any) => { export const getDocsUrl = () => { const docsBaseUrl = predefinedValues.DOCS_BASE_URL || 'docs/'; - const docsUrl = docsBaseUrl.startsWith('http') - ? docsBaseUrl - : new URL(docsBaseUrl, location.href).href; + let docsUrl = docsBaseUrl; + if (!docsBaseUrl.startsWith('http')) { + try { + docsUrl = new URL(docsBaseUrl, location.href).href; + } catch { + // `location.href` is not always usable as a base, e.g. in a worker loaded from + // a data:/blob: URL. Fall back to the configured (relative) value. + } + } return docsUrl.endsWith('/') ? docsUrl : `${docsUrl}/`; }; From 23411cd101e5d7146eb1aaabffc9289db9025ed3 Mon Sep 17 00:00:00 2001 From: "pullfrog[bot]" <226033991+pullfrog[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 20:07:23 +0000 Subject: [PATCH 6/6] fix(ocaml-js): report compiler load/run failures as errors Loading the compiler or running `compile()` can reject, and the page-side handler did not catch it, so the compile request stayed pending. Return the failure as a compilation error with empty output. --- .../ocaml-js/lang-ocaml-js-compiler-esm.ts | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/livecodes/languages/ocaml-js/lang-ocaml-js-compiler-esm.ts b/src/livecodes/languages/ocaml-js/lang-ocaml-js-compiler-esm.ts index ba6d27b3c7..13454087b5 100644 --- a/src/livecodes/languages/ocaml-js/lang-ocaml-js-compiler-esm.ts +++ b/src/livecodes/languages/ocaml-js/lang-ocaml-js-compiler-esm.ts @@ -3,6 +3,7 @@ // own workers, one per compiler program per compile, and because it is an ES module // where the compile worker is a classic one. import type { CompilerFunction } from '../../models'; +import { getErrorMessage } from '../../utils'; import { ocamlJsBaseUrl } from '../../vendors'; const ocamlJsCompilerUrl = ocamlJsBaseUrl + 'src/compiler/index.js'; @@ -32,13 +33,21 @@ const getCompiler = (): Promise => { export const ocamlCompiler: CompilerFunction = async (code: string) => { if (!code.trim()) return ''; - const compiler = await getCompiler(); - const { js, diagnostics, error } = await compiler.compile(code); + // Loading the compiler can reject (e.g. a transient CDN error), and `compile` can + // reject when the compiler worker itself fails, as opposed to the program not + // compiling. Surface both as compilation errors instead of letting the rejection + // leave the compile request pending. + try { + const compiler = await getCompiler(); + const { js, diagnostics, error } = await compiler.compile(code); - // `error` is the toolchain failing, as opposed to the program not compiling; - // `diagnostics` carries the compiler's own messages, errors and warnings alike. - if (!js) { - return { code: '', info: { errors: error ? [...diagnostics, error] : diagnostics } }; + // `error` is the toolchain failing, as opposed to the program not compiling; + // `diagnostics` carries the compiler's own messages, errors and warnings alike. + if (!js) { + return { code: '', info: { errors: error ? [...diagnostics, error] : diagnostics } }; + } + return { code: js, info: {} }; + } catch (err) { + return { code: '', info: { errors: [getErrorMessage(err)] } }; } - return { code: js, info: {} }; };