How AnnotationWinController Displays Chinese Translations and IPA Phonetic Symbols in hallelujahim
AnnotationWinController displays Chinese translations and IPA phonetic symbols by receiving a pre-formatted annotation string from the ConversionEngine through InputController, then rendering the text in a floating NSTextField panel.
The hallelujahim input method for macOS provides an optional annotation window that appears beside candidate suggestions, showing both Chinese translations and International Phonetic Alphabet (IPA) symbols for English words. Understanding how AnnotationWinController renders this linguistic data requires examining the coordinated workflow between user selection handling, dictionary lookup, and macOS window management as implemented in the dongyuwei/hallelujahim repository.
The Three-Component Display Pipeline
The annotation display relies on a coordinated pipeline across three core Objective-C classes. When a user highlights a candidate word, the system propagates data from input handling through linguistic processing to final UI rendering.
InputController.mm: Detecting Candidate Selection
Located in src/InputController.mm at lines 86‑92, the InputController class monitors candidate selection changes through the candidateSelectionChanged: method. When the user enables the Show Translation preference, the controller immediately triggers the annotation display workflow.
The controller extracts the plain string from the selected NSAttributedString and calls the internal showAnnotation: method:
- (void)showAnnotation:(NSAttributedString *)candidateString {
NSString *annotation = [engine getAnnotation:candidateString.string];
if (annotation.length) {
[_annotationWin setAnnotation:annotation];
[_annotationWin showWindow:[self calculatePositionOfTranslationWindow]];
} else {
[_annotationWin hideWindow];
}
}
This method serves as the gateway, delegating linguistic lookup to the ConversionEngine while managing the AnnotationWinController visibility state.
ConversionEngine.mm: Composing Translations and IPA Symbols
The ConversionEngine class in src/ConversionEngine.mm (lines 23‑38) constructs the actual annotation content through its getAnnotation: method. This implementation performs dual dictionary lookups: fetching Chinese translations via getTranslations: and retrieving IPA phonetic symbols through getPhoneticSymbolOfWord:.
When a phonetic symbol exists, the engine wraps it in square brackets and prepends it to the translation list, joining all elements with newline characters:
- (NSString *)getAnnotation:(NSString *)word {
NSString *input = word.lowercaseString;
NSArray *translation = [self getTranslations:input];
NSString *phoneticSymbol = [self getPhoneticSymbolOfWord:input];
if (phoneticSymbol.length) {
NSArray *list = @[ [NSString stringWithFormat:@"[%@]", phoneticSymbol] ];
return [[list arrayByAddingObjectsFromArray:translation] componentsJoinedByString:@"\n"];
}
return [translation componentsJoinedByString:@"\n"];
}
The resulting string places the IPA symbol (e.g., [həˈloʊ]) on the first line, followed by Chinese translations on subsequent lines.
AnnotationWinController.m: Displaying the Floating Panel
The AnnotationWinController class in src/AnnotationWinController.m provides the minimal UI surface for presenting the processed text. At lines 43‑45, the setAnnotation: method assigns the received string directly to its NSTextField view:
- (void)setAnnotation:(NSString *)annotation {
(self.view).stringValue = annotation;
}
The controller manages a borderless floating panel that appears at coordinates calculated by InputController's calculatePositionOfTranslationWindow method, ensuring the annotation appears adjacent to the active candidate selection.
Step-by-Step Execution Flow
The complete display sequence follows this precise execution path:
- User highlights candidate →
InputControllerreceivescandidateSelectionChanged:with anNSAttributedString. - Preference check → The controller verifies
[preference boolForKey:@"showTranslation"]before proceeding. - Linguistic lookup →
ConversionEnginequeries both translation and IPA dictionaries, formatting results with the symbol wrapped in[]brackets. - UI update →
AnnotationWinControllerreceives the formatted string viasetAnnotation:and updates(self.view).stringValue. - Window positioning → The panel displays at calculated screen coordinates via
showWindow:or hides if no annotation exists.
Summary
- InputController.mm (lines 86‑92) triggers the annotation workflow when candidates are selected and the translation preference is enabled.
- ConversionEngine.mm (lines 23‑38) builds the display string by prepending IPA phonetic symbols in square brackets to Chinese translation lists.
- AnnotationWinController.m (lines 43‑45) renders the final text in a floating
NSTextFieldpanel positioned beside the candidate list. - The architecture separates concerns between input handling, linguistic data processing, and presentation rendering.
Frequently Asked Questions
How does AnnotationWinController receive the Chinese translation data?
AnnotationWinController does not fetch data directly. Instead, InputController calls ConversionEngine's getAnnotation: method to retrieve a pre-formatted string containing both the IPA symbol and Chinese translations, then passes this string to the controller's setAnnotation: method.
Why are IPA phonetic symbols wrapped in square brackets?
According to the implementation in ConversionEngine.mm at lines 30‑31, the code explicitly formats the phonetic symbol using [NSString stringWithFormat:@"[%@]", phoneticSymbol] to visually distinguish pronunciation guides from semantic translations in the floating panel.
Where is the annotation window positioned on screen?
The display coordinates are calculated by InputController using the private calculatePositionOfTranslationWindow method. This ensures the AnnotationWinController panel appears immediately adjacent to the active candidate list in the input method interface.
Can the annotation display be disabled by users?
Yes. The InputController checks the user preference via [preference boolForKey:@"showTranslation"] before calling showAnnotation:. When this boolean returns false, the annotation window remains hidden regardless of candidate selection changes.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →