-
Notifications
You must be signed in to change notification settings - Fork 8
feat: enhance browser translation with dynamic translation hook #198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
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 introduces experimental browser translation capabilities using Chrome's new Translator API, allowing dynamic translation of node descriptions and version changelogs with toggle functionality and visual indicators.
Key changes:
- Added
useDynamicTranslatehook for experimental browser translation with Chrome's Translator API - Converted i18n hook from TypeScript to TSX to support React component rendering
- Applied dynamic translation to NodeDetails component with toggle switcher and emoji indicators
Reviewed Changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 9 comments.
| File | Description |
|---|---|
| src/hooks/i18n/index.tsx | New TSX file implementing dynamic translation hook and enhanced i18n functionality |
| src/hooks/i18n/index.ts | Removed original TypeScript i18n implementation |
| package.json | Added dependencies for translation features (hot-memo, react-use, use-async) |
| components/nodes/NodeDetails.tsx | Integrated dynamic translation for node descriptions and changelogs |
src/hooks/i18n/index.tsx
Outdated
| // 3. not avaliable in china | ||
| // | ||
| const [available, availableState] = useAsyncData(async () => { | ||
| const Translator = globalThis.Translator as any |
Copilot
AI
Jul 26, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using any type defeats TypeScript's type safety. Consider defining a proper interface for the Translator API or using a more specific type assertion.
| const Translator = globalThis.Translator as any | |
| const Translator = globalThis.Translator as TranslatorAPI |
src/hooks/i18n/index.tsx
Outdated
| aria-label="translate" | ||
| onClick={() => { | ||
| setEnabled((e) => !e) | ||
| }} |
Copilot
AI
Jul 26, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Switcher component lacks proper accessibility attributes. It should include tabIndex={0} and onKeyDown handler to support keyboard navigation, and a more descriptive aria-label.
| aria-label="translate" | |
| onClick={() => { | |
| setEnabled((e) => !e) | |
| }} | |
| aria-label={enabled ? "Disable translation" : "Enable translation"} | |
| tabIndex={0} | |
| onClick={() => { | |
| setEnabled((e) => !e) | |
| }} | |
| onKeyDown={(event) => { | |
| if (event.key === "Enter" || event.key === " ") { | |
| setEnabled((e) => !e) | |
| } | |
| }} |
🎨 Chromatic Visual Testing Results
Check the visual changes and approve or request changes as needed. |
🎨 Chromatic Visual Testing Results
Check the visual changes and approve or request changes as needed. |
- Add missing key handler with experimental Translator API integration - Translate node descriptions using t() function for internationalization - Format code improvements for better readability 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
- Add useDynamicTranslate hook for experimental browser translation - Implement toggle-able translation with visual indicators (🌐/🔄) - Apply dynamic translation to node descriptions and version changelogs - Convert i18n hook from TypeScript to TSX for React component support - Update dependencies to support new translation features 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
- Remove unused imports (hot-memo, react-icons, forEach) - Fix typos in comments (broswer -> browser, avaliable -> available) - Simplify JSX return structure in dt function - Improve code readability
7ada57e to
94fc732
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 4 out of 5 changed files in this pull request and generated 4 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
src/hooks/i18n/index.tsx
Outdated
| role="img" | ||
| aria-label="translate" | ||
| onClick={() => { | ||
| setEnabled(!enabled) // toggle the translation statey |
Copilot
AI
Oct 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a typo in the comment: 'statey' should be 'state'.
| setEnabled(!enabled) // toggle the translation statey | |
| setEnabled(!enabled) // toggle the translation state |
src/hooks/i18n/index.tsx
Outdated
| if (typeof globalThis.Translator === 'undefined') return | ||
|
|
||
| // Create a translator instance | ||
| const Translator = globalThis.Translator as any | ||
| const translator = await Translator.create({ | ||
| sourceLanguage: 'en', | ||
| targetLanguage: lng, | ||
| }).catch(() => null) | ||
| if (!translator) return |
Copilot
AI
Oct 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Translator API availability check and instance creation logic is duplicated between the missingKeyHandler and useDynamicTranslate hook. Consider extracting this into a shared utility function to reduce code duplication.
src/hooks/i18n/index.tsx
Outdated
| // Create a translator instance | ||
| const Translator = globalThis.Translator as any | ||
| const translator = await Translator.create({ | ||
| sourceLanguage: 'en', | ||
| targetLanguage: lng, | ||
| }).catch(() => null) | ||
| if (!translator) return | ||
|
|
||
| // Translate the key | ||
| let tr = '' | ||
| for await (const chunk of translator.translateStreaming(key)) { | ||
| tr += chunk |
Copilot
AI
Oct 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using any type for the Translator API reduces type safety. Consider creating a proper TypeScript interface for the Translator API or using a more specific type declaration.
| // Create a translator instance | |
| const Translator = globalThis.Translator as any | |
| const translator = await Translator.create({ | |
| sourceLanguage: 'en', | |
| targetLanguage: lng, | |
| }).catch(() => null) | |
| if (!translator) return | |
| // Translate the key | |
| let tr = '' | |
| for await (const chunk of translator.translateStreaming(key)) { | |
| tr += chunk | |
| // Define the expected Translator API interface | |
| interface TranslatorInstance { | |
| translateStreaming(text: string): AsyncIterable<string>; | |
| } | |
| interface TranslatorAPI { | |
| create(options: { sourceLanguage: string; targetLanguage: string }): Promise<TranslatorInstance>; | |
| } | |
| // Create a translator instance | |
| const Translator = globalThis.Translator as TranslatorAPI; | |
| const translator = await Translator.create({ | |
| sourceLanguage: 'en', | |
| targetLanguage: lng, | |
| }).catch(() => null); | |
| if (!translator) return; | |
| // Translate the key | |
| let tr = ''; | |
| for await (const chunk of translator.translateStreaming(key)) { | |
| tr += chunk; |
src/hooks/i18n/index.tsx
Outdated
| // 3. not available in china | ||
| // | ||
| const [available, availableState] = useAsyncData(async () => { | ||
| const Translator = globalThis.Translator as any |
Copilot
AI
Oct 2, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using any type for the Translator API reduces type safety. Consider creating a proper TypeScript interface for the Translator API or using a more specific type declaration.
- Remove DynamicTranslateSwitcher component - Add dynamic translation checkbox to LanguageSwitcher dropdown - Improve UX by integrating the feature into existing language selection - Only show checkbox when browser translation API is available
- Define TranslatorAPI and TranslatorInstance interfaces - Replace 'any' types with proper type definitions - Add global type declarations for Chrome's experimental API - Improve type safety and developer experience
|
All alerts resolved. Learn more about Socket for GitHub. This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored. |
…adata This PR implements an optional dynamic translation feature using Chrome's built-in Translator API to translate node descriptions and changelogs on-demand. ## Changes - Add `useDynamicTranslate()` hook with browser Translator API integration - Add dynamic translation toggle in language dropdown - Apply `dt()` function to node descriptions and version changelogs - Add "Dynamic Translation" key to all locale files - Add comprehensive documentation in docs/node-metadata-translation.md ## Key Features - Browser-based, local translation (no server costs) - Opt-in via toggle in language dropdown - Only translates user-generated content (descriptions, changelogs) - Falls back gracefully when API unavailable - Works offline after initial model download ## Technical Details - Uses Chrome 138+ experimental Translator API - LocalStorage persistence for user preference - i18next integration with missing key handler - Automatic re-rendering on translation completion ## Limitations - Chrome 138+ only - Not available in all regions - Client-side only (no SSR support) - Requires user to enable manually 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Resolved merge conflicts in LanguageSwitcher.tsx, NodeDetails.tsx, package.json - Removed duplicate imports - Fixed TypeScript type error in LanguageSwitcher onClick handler - Regenerated bun.lock after dependency resolution - Renamed src/hooks/i18n/index.ts to index.tsx - Build succeeds without errors 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Resolve conflicts in package.json and locale files by accepting main branch versions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Fixes build error: Module not found: Can't resolve 'use-async' 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
Summary
useDynamicTranslatehook for experimental browser translation using Chrome's new Translator APITest plan
🤖 Generated with Claude Code