Skip to content

Comments

fix(v2): set LANG for pbpaste/pbcopy to prevent clipboard mojibake on macOS#5012

Open
veeceey wants to merge 2 commits intowailsapp:masterfrom
veeceey:fix/issue-4132-clipboard-encoding
Open

fix(v2): set LANG for pbpaste/pbcopy to prevent clipboard mojibake on macOS#5012
veeceey wants to merge 2 commits intowailsapp:masterfrom
veeceey:fix/issue-4132-clipboard-encoding

Conversation

@veeceey
Copy link

@veeceey veeceey commented Feb 23, 2026

Fixes #4132

When a Wails app runs as a standalone macOS app (not launched from a terminal), the LANG environment variable is unset. pbpaste then defaults to an ASCII-compatible encoding, which turns non-ASCII clipboard content into garbage.

The fix ensures LANG=en_US.UTF-8 is set in the command's environment before invoking pbpaste/pbcopy, but only when LANG isn't already present — so it won't override anything the user has explicitly set.

Quick terminal demo showing the difference:

$ echo "你好世界 こんにちは" | pbcopy

$ LANG= pbpaste
Test: ???? ?????

$ LANG=en_US.UTF-8 pbpaste
Test: 你好世界 こんにちは

Summary by CodeRabbit

  • Bug Fixes
    • Improved clipboard handling on macOS so copied text and pasted content preserve UTF-8 characters correctly.
    • Ensures a UTF-8 environment for clipboard operations in packaged macOS apps to prevent garbled or misencoded characters when copying/pasting.

When macOS apps are launched as standalone (not from terminal), the LANG
environment variable is unset. This causes pbpaste to default to an
ASCII-compatible encoding, resulting in mojibake for non-ASCII clipboard
content.

Fix by ensuring LANG=en_US.UTF-8 is set in the command environment when
it's not already present.

Fixes wailsapp#4132
@veeceey
Copy link
Author

veeceey commented Feb 23, 2026

Manual test results (macOS 15, M4)

Verified the fix works by testing pbpaste behavior with and without LANG:

$ echo "你好世界 こんにちは" | pbcopy

# Without LANG (simulates standalone app launch):
$ LANG= pbpaste
Test: ???? ?????

# With LANG=en_US.UTF-8 (what this PR does):
$ LANG=en_US.UTF-8 pbpaste
Test: 你好世界 こんにちは

Also confirmed that go build ./v2/internal/frontend/desktop/darwin/ compiles cleanly.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 23, 2026

📝 Walkthrough

Walkthrough

Adds an ensureUTF8Env helper and applies it to the pbpaste and pbcopy command environments so macOS clipboard reads/writes run with LANG set to en_US.UTF-8 when LANG is unset.

Changes

Cohort / File(s) Summary
Clipboard UTF-8 Environment Fix
v2/internal/frontend/desktop/darwin/clipboard.go
Adds ensureUTF8Env() helper, imports os, and sets Cmd.Env = ensureUTF8Env(os.Environ()) for both ClipboardGetText (pbpaste) and ClipboardSetText (pbcopy). Adds explanatory comment about packaged macOS apps and LANG.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related issues

Poem

🐇 I nibble at bugs and hop through the night,
LANG set to UTF-8, everything’s right.
Copies and pastes now sing clear and bright,
A rabbit’s small hop fixed text’s flight. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description references issue #4132, explains the problem and solution clearly, and provides a practical demo. However, the required template sections (Type of change checklist, How Has This Been Tested with platform checkboxes, and Test Configuration) are not filled out. Complete the required checklist sections: mark the appropriate 'Type of change' option, specify which platforms were tested, and provide 'wails doctor' output or environment details.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: fixing clipboard encoding issues by setting LANG for pbpaste/pbcopy on macOS, addressing the specific problem of mojibake.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 OpenGrep (1.16.0)
v2/internal/frontend/desktop/darwin/clipboard.go

┌──────────────┐
│ Opengrep CLI │
└──────────────┘

�[32m✔�[39m �[1mOpengrep OSS�[0m
�[32m✔�[39m Basic security coverage for first-party code vulnerabilities.

�[1m Loading rules from local config...�[0m


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
v2/internal/frontend/desktop/darwin/clipboard.go (1)

14-22: Consider os.LookupEnv for a cleaner, more idiomatic implementation.

os.LookupEnv explicitly distinguishes "not set" from "set to empty" without manual string slicing, and is the standard Go idiom for this pattern:

♻️ Proposed refactor
 func ensureUTF8Env() []string {
 	env := os.Environ()
-	for _, e := range env {
-		if len(e) > 5 && e[:5] == "LANG=" {
-			return env
-		}
+	if _, ok := os.LookupEnv("LANG"); !ok {
+		env = append(env, "LANG=en_US.UTF-8")
 	}
-	return append(env, "LANG=en_US.UTF-8")
+	return env
 }

This also correctly handles the case where LANG is set but empty (keeping the existing empty value rather than creating a duplicate entry), which the current loop misses due to the > 5 boundary.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@v2/internal/frontend/desktop/darwin/clipboard.go` around lines 14 - 22,
Replace the manual loop in ensureUTF8Env with os.LookupEnv: use
os.LookupEnv("LANG") to detect whether LANG is present (allowing an existing
empty value to be preserved) and, if not present, append "LANG=en_US.UTF-8" to
os.Environ(); ensure you return the original env unchanged when LANG is set
(including empty string) to avoid duplicating entries and to follow Go idioms.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@v2/internal/frontend/desktop/darwin/clipboard.go`:
- Line 17: The guard that checks environment entries uses len(e) > 5 && e[:5] ==
"LANG=" which misses the exact "LANG=" entry; update the check in the loop over
environment entries (the variable e) to use a correct boundary such as len(e) >=
5 && e[:5] == "LANG=" or, better, strings.HasPrefix(e, "LANG=") so entries equal
to "LANG=" are treated as matches and the function will early-return instead of
appending a second LANG variable.

---

Nitpick comments:
In `@v2/internal/frontend/desktop/darwin/clipboard.go`:
- Around line 14-22: Replace the manual loop in ensureUTF8Env with os.LookupEnv:
use os.LookupEnv("LANG") to detect whether LANG is present (allowing an existing
empty value to be preserved) and, if not present, append "LANG=en_US.UTF-8" to
os.Environ(); ensure you return the original env unchanged when LANG is set
(including empty string) to avoid duplicating entries and to follow Go idioms.

Replace manual string slicing with os.LookupEnv which is more idiomatic
and correctly handles the edge case where LANG is set to an empty string.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@v2/internal/frontend/desktop/darwin/clipboard.go`:
- Around line 14-20: The function ensureUTF8Env correctly uses
os.LookupEnv("LANG") to detect presence (including an empty LANG=) and only
appends "LANG=en_US.UTF-8" when absent, so no code change is required; keep the
current implementation (ensureUTF8Env) as-is and approve the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Incorrect Clipboard Text Encoding when LANG Environment Variable is Empty on macOS

1 participant