-
Notifications
You must be signed in to change notification settings - Fork 46
feat: add RTL language support #118
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
Conversation
Add right-to-left (RTL) language support with three modes: - LTR: Left-to-right (default) - RTL: Right-to-left for Arabic, Hebrew, etc. - Auto: Automatically detect based on content Changes: - Create direction service with auto-detection using Unicode ranges - Add direction selector in Settings (matching theme selector style) - Convert physical CSS properties to logical properties throughout (margin-inline-start/end, padding-inline-start/end, etc.) - Integrate auto-detection with editor content changes
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 adds comprehensive right-to-left (RTL) language support to the application, enabling proper display and interaction for languages like Arabic, Hebrew, Persian, and Syriac. The implementation follows the existing theme service pattern, creating a direction service with three modes: LTR (left-to-right), RTL (right-to-left), and Auto-detect. The auto-detect mode intelligently analyzes editor content using Unicode character ranges to determine the appropriate text direction.
Key changes:
- Created a DirectionService singleton following the ThemeService pattern with reactive state, localStorage persistence, and Vue watchers
- Integrated direction auto-detection into the Editor component with debounced updates during content changes
- Converted physical CSS properties (left/right, margin-left/right) to logical properties (inline-start/end, margin-inline) across all Vue components for bidirectional layout support
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| client/src/services/direction.ts | New direction service implementing state management, auto-detection algorithm for RTL languages, frontmatter stripping, and DOM manipulation |
| client/src/main.ts | Imports direction service to initialize it at application startup |
| client/src/components/Settings.vue | Adds direction selector UI matching theme selector pattern with three button options |
| client/src/components/Editor.vue | Integrates debounced direction auto-detection on content changes and initial mount |
| client/src/App.vue | Adds CSS variables for direction support (though currently unused) |
| client/src/views/Search.vue | Converts autocomplete dropdown and syntax help table positioning to logical properties |
| client/src/views/Note.vue | Converts editor split border from physical to logical property |
| client/src/views/Home.vue | Converts center-columns margin to logical property shorthand |
| client/src/views/Day.vue | Converts editor split border from physical to logical property |
| client/src/components/NestedTags.vue | Converts padding and margin properties for nested tag indentation to logical properties |
| client/src/components/MarkdownPreview.vue | Converts multiple spacing properties (margins, padding, borders) and text-align from physical to logical properties |
| client/src/components/Header.vue | Converts header spacing and dropdown positioning to logical properties, removes obsolete float property |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
client/src/services/direction.ts
Outdated
| this.state.autoDetectedDirection = detected; | ||
|
|
||
| if (this.state.preference === 'auto') { | ||
| this.state.resolved = detected; | ||
| this.applyDirection(); |
Copilot
AI
Dec 12, 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 updateAutoDirection method updates the resolved direction and applies it even when preference is 'auto', but it doesn't prevent race conditions. If multiple rapid content changes occur, the debounced calls could update autoDetectedDirection out of order. Consider checking if the detected direction has actually changed before calling applyDirection to avoid unnecessary DOM manipulations.
| this.state.autoDetectedDirection = detected; | |
| if (this.state.preference === 'auto') { | |
| this.state.resolved = detected; | |
| this.applyDirection(); | |
| if (this.state.autoDetectedDirection !== detected) { | |
| this.state.autoDetectedDirection = detected; | |
| if (this.state.preference === 'auto') { | |
| this.state.resolved = detected; | |
| this.applyDirection(); | |
| } |
client/src/services/direction.ts
Outdated
| * Strip YAML frontmatter from text | ||
| */ | ||
| private stripFrontmatter(text: string): string { | ||
| const frontmatterRegex = /^---\s*\n[\s\S]*?\n---\s*\n/; |
Copilot
AI
Dec 12, 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 frontmatter regex pattern /^---\s*\n[\s\S]*?\n---\s*\n/ requires a newline after the closing ---, but valid YAML frontmatter can end with --- at the end of the file without a trailing newline. This could cause frontmatter to not be stripped in some cases. Consider making the trailing newline optional: /^---\s*\n[\s\S]*?\n---\s*\n?/
| const frontmatterRegex = /^---\s*\n[\s\S]*?\n---\s*\n/; | |
| const frontmatterRegex = /^---\s*\n[\s\S]*?\n---\s*\n?/; |
client/src/App.vue
Outdated
| --text-direction: ltr; | ||
| } | ||
| /* RTL mode */ | ||
| .dir-rtl { | ||
| --text-direction: rtl; | ||
| } | ||
Copilot
AI
Dec 12, 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 CSS variable --text-direction is defined but never used in the codebase. Since the direction service already applies the dir attribute to the document element (which provides native browser RTL support), this CSS variable appears to be unnecessary. Consider removing it unless there are plans to use it for custom direction-aware styling.
| --text-direction: ltr; | |
| } | |
| /* RTL mode */ | |
| .dir-rtl { | |
| --text-direction: rtl; | |
| } | |
| } | |
| /* RTL mode */ | |
| .dir-rtl { | |
| } |
client/src/components/Editor.vue
Outdated
| (value: string) => { | ||
| directionService.updateAutoDirection(value); | ||
| }, | ||
| 300, |
Copilot
AI
Dec 12, 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 debounce delay of 300ms for direction updates is shorter than the 500ms throttle delay for content emission. Since direction detection involves regex matching on content, consider using a delay equal to or longer than the throttledEmit delay (500ms) to reduce unnecessary processing, especially during rapid typing.
| 300, | |
| 500, |
- Prevent race condition in direction auto-detection by only updating when the detected direction has actually changed - Make trailing newline optional in frontmatter regex to handle files ending with frontmatter - Remove unused --text-direction CSS variable (dir attribute suffices) - Align direction detection debounce to 500ms to match content throttle
Summary
Test plan