Skip to content

Improve local setup, token handling, and Chinese localization - #1

Open
makerjackie wants to merge 4 commits into
mubashardev:mainfrom
makerjackie:makerjackie-localization-runtime-fixes
Open

Improve local setup, token handling, and Chinese localization#1
makerjackie wants to merge 4 commits into
mubashardev:mainfrom
makerjackie:makerjackie-localization-runtime-fixes

Conversation

@makerjackie

@makerjackie makerjackie commented May 25, 2026

Copy link
Copy Markdown

Summary

Hi Mubashar, thanks for building CF Studio. I have been trying it locally as a Cloudflare D1/R2 desktop workflow and found it useful, so I put together a few changes that may be helpful upstream.

This PR includes:

  • Adds a small Tauri/Rust shell environment helper so macOS GUI launches can detect node, npm, and wrangler installed through nvm, Homebrew, or npm global paths.
  • Fixes a token edge case where Wrangler works from the terminal through CLOUDFLARE_API_TOKEN, but CF Studio still reads an older Wrangler OAuth config file and can hit invalid access token.
  • Adds basic i18n support with en-US and zh-CN, plus a language selector in Settings.
  • Adds i18n coverage for the main D1, R2, and KV-facing screens with Simplified Chinese translations while keeping English as the default language.
  • Adds a public fallback implementation for the private src/pro_modules submodule so the public repository can be cloned and built without access to the private Pro repository.
  • Adds a Simplified Chinese README for users who want to run this fork locally.

Why

The main bug I hit was on macOS: when a Tauri app is opened from Finder, it does not inherit the interactive shell PATH. In that case, node and wrangler installed under ~/.nvm/versions/node/.../bin are available in Terminal but not visible to the app.

I also hit an auth mismatch: wrangler whoami worked because Wrangler was using CLOUDFLARE_API_TOKEN, while CF Studio read an older oauth_token from ~/Library/Preferences/.wrangler/config/default.toml, which produced an invalid-token API error. The change now prefers CLOUDFLARE_API_TOKEN when it is present, and otherwise falls back to Wrangler OAuth config.

The i18n changes are intentionally simple. They do not replace the existing English UI. English remains the default language, and zh-CN is added as an optional language through the Settings screen.

The public fallback for src/pro_modules is included because a fresh clone of the public repo cannot initialize the private submodule. I kept those fallback modules minimal and clearly scoped so they do not attempt to recreate the private Pro functionality.

Verification

I verified locally with:

bun run build
cargo check
git diff --check

thx for opensource !

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR improves local developer ergonomics for CF Studio by (1) making the Tauri backend more reliable at discovering Node/Wrangler in GUI-launched environments, (2) resolving a Cloudflare auth/token precedence edge case, (3) introducing a simple i18n system with English and Simplified Chinese, and (4) adding public “fallback” implementations so the repo builds without private Pro modules/submodules.

Changes:

  • Add a shell bootstrap helper for PATH discovery (nvm/Homebrew/npm-global) and reuse it for dependency probing and Wrangler refresh.
  • Prefer CLOUDFLARE_API_TOKEN (when set) over the local Wrangler OAuth config; add basic i18n with language selection persisted in the app store.
  • Remove the private src/pro_modules submodule and add public placeholder/fallback src/pro_modules modules + a Chinese README.

Reviewed changes

Copilot reviewed 41 out of 42 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/store/useAppStore.ts Adds persisted language setting and setter.
src/lib/i18n.ts Introduces translation tables and useI18n() helper.
src/components/SetupWizard.tsx Replaces setup wizard strings with i18n keys.
src/components/SettingsView.tsx Localizes settings UI and adds language selector.
src/components/SchemaVisualizer.tsx Localizes schema empty-state strings.
src/components/R2ProGate.tsx Localizes Pro gating labels/toasts and PRO badge text.
src/components/QueryEditor.tsx Localizes editor strings, templates, tooltips, and pagination labels.
src/components/Layout.tsx Localizes sidebar/titlebar; adds KV placeholder route/view.
src/components/IntelligencePanel.tsx Localizes query intelligence messaging and actions.
src/components/FreeExportDialog.tsx Localizes export upsell dialog strings.
src/components/ExportWrapper.tsx Localizes lazy-load fallback text.
src/components/EditColumnDialog.tsx Localizes column editor UI, diffs, and toasts.
src/components/DatabasesView.tsx Localizes D1 empty states, headings, and history labels.
src/components/DatabaseExplorer.tsx Localizes explorer UI (tabs, tooltips, pagination, dialogs).
src-tauri/src/shell_env.rs Adds reusable shell/PATH bootstrap for GUI launch environments.
src-tauri/src/setup.rs Reuses shell bootstrap for dependency checks and shell execution.
src-tauri/src/lib.rs Wires public src/pro_modules/rust/* via #[path] modules.
src-tauri/src/cloudflare_auth.rs Prefers CLOUDFLARE_API_TOKEN; uses login-shell PATH bootstrap for refresh.
src/pro_modules/ui/audits/SecurityPosture.tsx Public placeholder UI for Pro audit screen.
src/pro_modules/ui/audits/PerformancePosture.tsx Public placeholder UI for Pro audit screen.
src/pro_modules/ui/audits/Overview.tsx Public placeholder UI for Pro audit screen.
src/pro_modules/ui/audits/DomainScanner.tsx Public placeholder UI for Pro audit screen.
src/pro_modules/ui/audits/DnsEmailPosture.tsx Public placeholder UI for Pro audit screen.
src/pro_modules/ui/audits/AuditPreferences.tsx Public placeholder UI for Pro audit screen.
src/pro_modules/ui/ActivityDashboard.tsx Public placeholder UI for Pro history/dashboard screen.
src/pro_modules/rust/r2_worker_proxy.rs Stub Rust file to keep public build self-contained.
src/pro_modules/rust/r2_pro.rs Public stub implementations for Pro R2 commands.
src/pro_modules/rust/history.rs Public stub implementations for Pro history commands.
src/pro_modules/rust/domain_audit.rs Public stub implementations for Pro audit commands.
src/pro_modules/hooks/useD1TrackerLogic.ts Public stub for tracked-query hook logic.
src/pro_modules/frontend/useRemoteConfig.ts Public fallback remote config with Pro features disabled.
src/pro_modules/frontend/R2BucketsView.tsx Public fallback R2 bucket/object listing UI.
src/pro_modules/frontend/PurchaseScreen.tsx Public placeholder purchase/unavailable dialog.
src/pro_modules/frontend/ProFeatureGate.tsx Public placeholder feature-gate dialog.
src/pro_modules/frontend/IndexManagerDialog.tsx Public placeholder dialog (auto-closes).
src/pro_modules/frontend/AuditZoneContext.tsx Public placeholder provider wrapper.
README.zh-CN.md Adds Simplified Chinese README for local fork usage.
README.md Links to the Chinese README.
docs/makerjackie-fork-requirements.md Adds fork requirements/spec documentation.
.gitmodules Removes private src/pro_modules submodule entry.
.gitignore Adds LOCAL_DEV.md ignore entry.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/lib/i18n.ts
Comment on lines +596 to +613
export type TranslationKey = keyof typeof translations["en-US"];

export function useI18n() {
const language = useAppStore((state) => state.language);
const setLanguage = useAppStore((state) => state.setLanguage);

const interpolate = (value: string, vars?: Record<string, string | number>) => {
if (!vars) return value;
return value.replace(/\{(\w+)\}/g, (_, key) => String(vars[key] ?? `{${key}}`));
};

return {
language,
setLanguage,
t: (key: TranslationKey, vars?: Record<string, string | number>) =>
interpolate(translations[language][key] ?? translations["en-US"][key] ?? key, vars),
};
}
Comment on lines +9 to +16
pub fn user_path_prefix() -> &'static str {
r#"export NVM_DIR="${NVM_DIR:-$HOME/.nvm}";
if [ -s "$NVM_DIR/nvm.sh" ]; then . "$NVM_DIR/nvm.sh" >/dev/null 2>&1; fi;
for d in "$HOME"/.nvm/versions/node/*/bin "$HOME"/.npm-global/bin /opt/homebrew/bin /usr/local/bin; do
if [ -d "$d" ]; then PATH="$d:$PATH"; fi;
done;
export PATH"#
}
Comment on lines +1 to +16
import type { D1TableSchema } from "@/hooks/useCloudflare";

export function IndexManagerDialog({
open,
onOpenChange,
}: {
databaseId: string;
open: boolean;
onOpenChange: (open: boolean) => void;
allTables: D1TableSchema[];
}) {
if (open) {
queueMicrotask(() => onOpenChange(false));
}
return null;
}
Comment on lines +7 to +25
#[tauri::command]
pub async fn fetch_cloudflare_zones() -> Result<Vec<Value>, String> {
Ok(Vec::new())
}

#[tauri::command]
pub async fn create_r2_bucket(_bucket_name: String) -> Result<(), String> {
Err(unavailable())
}

#[tauri::command]
pub async fn delete_r2_bucket(_bucket_name: String) -> Result<(), String> {
Err(unavailable())
}

#[tauri::command]
pub async fn empty_r2_bucket(_bucket_name: String) -> Result<(), String> {
Err(unavailable())
}
Comment on lines +27 to +53
#[tauri::command]
pub async fn upload_r2_object(
_bucket_name: String,
_key: String,
_local_path: String,
_upload_id: String,
) -> Result<(), String> {
Err(unavailable())
}

#[tauri::command]
pub async fn cancel_upload_r2_object(
_upload_id: String,
_bucket_name: String,
_key: String,
) -> Result<(), String> {
Ok(())
}

#[tauri::command]
pub async fn download_r2_object(
_bucket_name: String,
_key: String,
_destination_path: String,
) -> Result<(), String> {
Err(unavailable())
}
Comment on lines +55 to +84
#[tauri::command]
pub async fn update_r2_bucket_managed_domain(
_bucket_name: String,
_enabled: bool,
) -> Result<(), String> {
Err(unavailable())
}

#[tauri::command]
pub async fn add_r2_bucket_custom_domain(
_bucket_name: String,
_domain: String,
_zone_id: String,
_zone_name: String,
) -> Result<(), String> {
Err(unavailable())
}

#[tauri::command]
pub async fn remove_r2_bucket_custom_domain(
_bucket_name: String,
_domain: String,
) -> Result<(), String> {
Err(unavailable())
}

#[tauri::command]
pub async fn get_r2_bucket_domains_list(_bucket_name: String) -> Result<Value, String> {
Ok(json!({ "managed": null, "custom": [] }))
}
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.

2 participants