diff --git a/Makefile b/Makefile
index 1feb0a44e36..7997ac53d45 100644
--- a/Makefile
+++ b/Makefile
@@ -58,7 +58,13 @@ dev:
@echo "Starting development servers..."
@# Start both processes, with marimo in background
@(trap 'kill %1; exit' INT; \
- marimo edit --no-token --headless /tmp & \
+ uv run marimo edit --no-token --headless /tmp & \
+ pnpm dev)
+dev-sandbox:
+ @echo "Starting development servers..."
+ @# Start both processes, with marimo in background
+ @(trap 'kill %1; exit' INT; \
+ uv run marimo edit /tmp/notebook.py --no-token --headless --sandbox & \
pnpm dev)
#############
diff --git a/frontend/src/components/app-config/user-config-form.tsx b/frontend/src/components/app-config/user-config-form.tsx
index f344fbe1559..5a3c6496900 100644
--- a/frontend/src/components/app-config/user-config-form.tsx
+++ b/frontend/src/components/app-config/user-config-form.tsx
@@ -13,6 +13,7 @@ import {
PackageIcon,
} from "lucide-react";
import React, { useId, useRef } from "react";
+import { useLocale } from "react-aria";
import { useForm } from "react-hook-form";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
@@ -118,6 +119,7 @@ export const UserConfigForm: React.FC = () => {
);
const capabilities = useAtomValue(capabilitiesAtom);
const marimoVersion = useAtomValue(marimoVersionAtom);
+ const { locale } = useLocale();
const { saveUserConfig } = useRequestClient();
// Create form
@@ -1333,8 +1335,9 @@ export const UserConfigForm: React.FC = () => {
))}
-
+
Version: {marimoVersion}
+ Locale: {locale}
diff --git a/frontend/src/core/i18n/local-provider.tsx b/frontend/src/core/i18n/local-provider.tsx
new file mode 100644
index 00000000000..f77162dc433
--- /dev/null
+++ b/frontend/src/core/i18n/local-provider.tsx
@@ -0,0 +1,12 @@
+/* Copyright 2024 Marimo. All rights reserved. */
+
+import type { ReactNode } from "react";
+import { I18nProvider } from "react-aria-components";
+
+interface LocaleProviderProps {
+ children: ReactNode;
+}
+
+export const LocaleProvider = ({ children }: LocaleProviderProps) => {
+ return
{children};
+};
diff --git a/frontend/src/core/islands/components/web-components.tsx b/frontend/src/core/islands/components/web-components.tsx
index ef0ae98e92e..db5075b227a 100644
--- a/frontend/src/core/islands/components/web-components.tsx
+++ b/frontend/src/core/islands/components/web-components.tsx
@@ -7,6 +7,7 @@ import { ErrorBoundary } from "@/components/editor/boundary/ErrorBoundary";
import { TooltipProvider } from "@/components/ui/tooltip";
import { notebookAtom } from "@/core/cells/cells";
import { UI_ELEMENT_REGISTRY } from "@/core/dom/uiregistry";
+import { LocaleProvider } from "@/core/i18n/local-provider";
import { renderHTML } from "@/plugins/core/RenderHTML";
import { invariant } from "@/utils/invariant";
import type { CellId } from "../../cells/ids";
@@ -80,16 +81,18 @@ export class MarimoIslandElement extends HTMLElement {
this.root?.render(
-
-
- {initialHtml}
-
- {editor}
-
+
+
+
+ {initialHtml}
+
+ {editor}
+
+
,
);
diff --git a/frontend/src/mount.tsx b/frontend/src/mount.tsx
index 59fe1db2b9e..8a0f2964e9a 100644
--- a/frontend/src/mount.tsx
+++ b/frontend/src/mount.tsx
@@ -26,6 +26,7 @@ import {
parseConfigOverrides,
parseUserConfig,
} from "./core/config/config-schema";
+import { LocaleProvider } from "./core/i18n/local-provider";
import { MarimoApp, preloadPage } from "./core/MarimoApp";
import { type AppMode, initialModeAtom, viewStateAtom } from "./core/mode";
import { cleanupAuthQueryParams } from "./core/network/auth";
@@ -82,9 +83,11 @@ export function mount(options: unknown, el: Element): Error | undefined {
root.render(
-
-
-
+
+
+
+
+
,
);
} catch (error) {
diff --git a/frontend/src/plugins/core/registerReactComponent.tsx b/frontend/src/plugins/core/registerReactComponent.tsx
index cb1f4d2f353..868a9671c57 100644
--- a/frontend/src/plugins/core/registerReactComponent.tsx
+++ b/frontend/src/plugins/core/registerReactComponent.tsx
@@ -29,6 +29,7 @@ import { createInputEvent, MarimoValueUpdateEvent } from "@/core/dom/events";
import { getUIElementObjectId } from "@/core/dom/ui-element";
import { UIElementRegistry } from "@/core/dom/uiregistry";
import { FUNCTIONS_REGISTRY } from "@/core/functions/FunctionRegistry";
+import { LocaleProvider } from "@/core/i18n/local-provider";
import { store } from "@/core/state/jotai";
import {
type HTMLElementNotDerivedFromRef,
@@ -363,16 +364,18 @@ export function registerReactComponent
(plugin: IPlugin): void {
invariant(this.root, "Root must be defined");
this.root.render(
- {
- return parseInitialValue(this, UIElementRegistry.INSTANCE);
- }}
- >
- {this.getChildren()}
- ,
+
+ {
+ return parseInitialValue(this, UIElementRegistry.INSTANCE);
+ }}
+ >
+ {this.getChildren()}
+
+ ,
);
}
diff --git a/marimo/_cli/envinfo.py b/marimo/_cli/envinfo.py
index 15f06d98a6c..210e8873326 100644
--- a/marimo/_cli/envinfo.py
+++ b/marimo/_cli/envinfo.py
@@ -46,6 +46,16 @@ def get_experimental_flags() -> dict[str, Union[str, bool, dict[str, Any]]]:
return {}
+def get_default_locale() -> str:
+ try:
+ import locale
+
+ default_locale, _ = locale.getdefaultlocale()
+ return default_locale or "--"
+ except Exception:
+ return "--"
+
+
def get_system_info() -> dict[str, Union[str, bool, dict[str, Any]]]:
os_version = platform.release()
if platform.system() == "Windows" and is_win11():
@@ -61,6 +71,7 @@ def get_system_info() -> dict[str, Union[str, bool, dict[str, Any]]]:
# e.g., x86 or arm
"Processor": platform.processor(),
"Python Version": platform.python_version(),
+ "Locale": get_default_locale(),
}
binaries = {