Skip to content

Conversation

@snomiao
Copy link
Member

@snomiao snomiao commented Jul 26, 2025

Summary

  • Add useDynamicTranslate hook for experimental browser translation using Chrome's new Translator API
  • Implement toggle-able translation with visual indicators (🌐/🔄 emojis)
  • Apply dynamic translation to node descriptions and version changelogs in NodeDetails component
  • Convert i18n hook from TypeScript to TSX for React component support
  • Update dependencies to support new translation features

Test plan

  • Verify dynamic translation toggle works in Chrome 138+ browsers
  • Test that translation icons appear correctly in node descriptions
  • Confirm translation state persists across page reloads via localStorage
  • Validate fallback behavior in browsers without Translator API support
  • Test translation functionality with various languages

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings July 26, 2025 17:49
@vercel
Copy link

vercel bot commented Jul 26, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
registry-web Ready Ready Preview Comment Oct 26, 2025 8:06am

Copy link
Contributor

Copilot AI left a 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 useDynamicTranslate hook 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

// 3. not avaliable in china
//
const [available, availableState] = useAsyncData(async () => {
const Translator = globalThis.Translator as any
Copy link

Copilot AI Jul 26, 2025

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.

Suggested change
const Translator = globalThis.Translator as any
const Translator = globalThis.Translator as TranslatorAPI

Copilot uses AI. Check for mistakes.
Comment on lines 117 to 133
aria-label="translate"
onClick={() => {
setEnabled((e) => !e)
}}
Copy link

Copilot AI Jul 26, 2025

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.

Suggested change
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)
}
}}

Copilot uses AI. Check for mistakes.
@github-actions
Copy link

🎨 Chromatic Visual Testing Results

Resource URL
🔍 Build Results Chromatic Build
📚 Storybook View Storybook

Check the visual changes and approve or request changes as needed.

@github-actions
Copy link

🎨 Chromatic Visual Testing Results

Resource URL
🔍 Build Results Chromatic Build
📚 Storybook View Storybook

Check the visual changes and approve or request changes as needed.

snomiao and others added 5 commits October 2, 2025 09:49
- 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]>
- 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
@snomiao snomiao force-pushed the sno-node-meta-translation branch from 7ada57e to 94fc732 Compare October 2, 2025 09:52
Copy link
Contributor

Copilot AI left a 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.

role="img"
aria-label="translate"
onClick={() => {
setEnabled(!enabled) // toggle the translation statey
Copy link

Copilot AI Oct 2, 2025

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'.

Suggested change
setEnabled(!enabled) // toggle the translation statey
setEnabled(!enabled) // toggle the translation state

Copilot uses AI. Check for mistakes.
Comment on lines 57 to 65
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
Copy link

Copilot AI Oct 2, 2025

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.

Copilot uses AI. Check for mistakes.
Comment on lines 59 to 70
// 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
Copy link

Copilot AI Oct 2, 2025

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.

Suggested change
// 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;

Copilot uses AI. Check for mistakes.
// 3. not available in china
//
const [available, availableState] = useAsyncData(async () => {
const Translator = globalThis.Translator as any
Copy link

Copilot AI Oct 2, 2025

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.

Copilot uses AI. Check for mistakes.
- 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
@socket-security
Copy link

socket-security bot commented Oct 2, 2025

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.

View full report

snomiao and others added 3 commits October 17, 2025 00:17
…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]>
@socket-security
Copy link

socket-security bot commented Oct 25, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addeduse-async@​1.2.07010010078100

View full report

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
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