From 2350c315b0cc3017a0fdf1468cd871d968b511b9 Mon Sep 17 00:00:00 2001
From: Hamed Rabah <26891088+hamedrabah@users.noreply.github.com>
Date: Mon, 31 Aug 2026 11:42:53 -0700
Subject: [PATCH 1/3] docs: add component translation example
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
docs/src/app/(docs)/concepts/theming/page.mdx | 34 +++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/docs/src/app/(docs)/concepts/theming/page.mdx b/docs/src/app/(docs)/concepts/theming/page.mdx
index 7537241a6c..4c85e2d171 100644
--- a/docs/src/app/(docs)/concepts/theming/page.mdx
+++ b/docs/src/app/(docs)/concepts/theming/page.mdx
@@ -528,3 +528,37 @@ type UploadDropzoneProps = {
+
+### Internationalization
+
+UploadThing does not bundle translations for its components. Instead, use the
+`content` prop to provide copy from your application's translation catalog. A
+content callback receives the component state, so translated content can still
+show loading and upload progress:
+
+```tsx
+const french = {
+ loading: "Chargement...",
+ chooseFiles: "Choisir des fichiers",
+ uploading: "Téléversement",
+ allowedContent: "Images jusqu'à 4 Mo",
+};
+
+;
+```
+
+The same approach works with `UploadDropzone`. Supply translated content for its
+`label`, `button`, and `allowedContent` fields, and keep any state-specific copy
+in callbacks.
From 2d35db143c720cf947c90ea216d69595ae51b886 Mon Sep 17 00:00:00 2001
From: Hamed Rabah <26891088+hamedrabah@users.noreply.github.com>
Date: Mon, 31 Aug 2026 16:08:01 -0700
Subject: [PATCH 2/3] docs: fix French percentage spacing
---
docs/src/app/(docs)/concepts/theming/page.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/src/app/(docs)/concepts/theming/page.mdx b/docs/src/app/(docs)/concepts/theming/page.mdx
index 4c85e2d171..b95e9ab72b 100644
--- a/docs/src/app/(docs)/concepts/theming/page.mdx
+++ b/docs/src/app/(docs)/concepts/theming/page.mdx
@@ -550,7 +550,7 @@ const french = {
button({ ready, isUploading, uploadProgress }) {
if (!ready) return french.loading;
if (isUploading) {
- return `${french.uploading} ${Math.round(uploadProgress)}%`;
+ return `${french.uploading} ${Math.round(uploadProgress)}\u00a0%`;
}
return french.chooseFiles;
},
From b39ec42d7779fac2f7ea013fb135e9acc0029c62 Mon Sep 17 00:00:00 2001
From: Hamed Rabah <26891088+hamedrabah@users.noreply.github.com>
Date: Tue, 1 Sep 2026 11:52:50 -0700
Subject: [PATCH 3/3] docs: explain ContentField callbacks
---
docs/src/app/(docs)/concepts/theming/page.mdx | 26 +++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/docs/src/app/(docs)/concepts/theming/page.mdx b/docs/src/app/(docs)/concepts/theming/page.mdx
index b95e9ab72b..bb104af00b 100644
--- a/docs/src/app/(docs)/concepts/theming/page.mdx
+++ b/docs/src/app/(docs)/concepts/theming/page.mdx
@@ -493,6 +493,32 @@ type UploadDropzoneProps = {
};
```
+Each `ContentField` can be a fixed value or a callback. Callback fields receive
+the current component state, so you can change the copy for loading, uploading,
+dragging, and selected-file states. `UploadDropzone` callbacks also receive
+`isDragActive`; both components expose `ready`, `isUploading`, `uploadProgress`,
+`fileTypes`, and `files` where applicable.
+
+For example, a dropzone can show different translated labels while it is
+preparing, while the user is dragging files over it, and after files have been
+selected:
+
+```jsx
+
+```
+
When you take over the `content` of an element, you get full responsibility to
control the different states of the component. For example, if you customize