Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Source/Base.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,21 @@
"Roman Numbers (Full-Width Upper Case)" = "Roman Numbers (Full-Width Upper Case)";

"Roman Numbers (Full-Width Lower Case)" = "Roman Numbers (Full-Width Lower Case)";

"Show Issues in User Files ⚠️" = "Show Issues in User Files ⚠️";
Comment thread
lukhnos marked this conversation as resolved.

"Issues were found in the following user phrase files:" = "Issues were found in the following user phrase files:";

"Check McBopomofo menu for user file issues" = "Check McBopomofo menu for user file issues";

"User phrase file" = "User phrase file";

"Excluded phrase file" = "Excluded phrase file";

"Phrase replacement file" = "Phrase replacement file";

"line %lu: " = "line %lu: ";

"Only one column was found." = "Only one column was found.";

"Illegal NULL character was found." = "Illegal NULL character was found.";
60 changes: 60 additions & 0 deletions Source/InputMethodController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ class McBopomofoInputMethodController: IMKInputController {
var state: InputState = InputState.Empty()
lazy var charInfo: SystemCharacterInfo? = try? SystemCharacterInfo()

// Share the stored issues, so a set of issues is shown as notification only once.
static var latestUserFileIssues: [String] = []
Comment thread
lukhnos marked this conversation as resolved.

// MARK: - IMKInputController methods

override init!(server: IMKServer!, delegate: Any!, client inputClient: Any!) {
Expand Down Expand Up @@ -122,6 +125,16 @@ class McBopomofoInputMethodController: IMKInputController {
menu.addItem(
withTitle: NSLocalizedString("Reload User Phrases", comment: ""),
action: #selector(reloadUserPhrases(_:)), keyEquivalent: "")

if !McBopomofoInputMethodController.latestUserFileIssues.isEmpty {
// Setting menuItem.image does not work in input method menus even on macOS 26,
// so we just use the alert emoji in the menu item title.
Comment thread
lukhnos marked this conversation as resolved.
let menuItem = NSMenuItem(
title: NSLocalizedString("Show Issues in User Files ⚠️", comment: ""),
action: #selector(showUserFileIssues(_:)), keyEquivalent: "")
menu.addItem(menuItem)
}

menu.addItem(NSMenuItem.separator())

menu.addItem(
Expand Down Expand Up @@ -171,6 +184,9 @@ class McBopomofoInputMethodController: IMKInputController {
keyHandler.inputMode = newInputMode
self.handle(state: .Empty(), client: client)
}

// Since setValue is called after activateServer, show user file issues here, if any.
checkUserFileIssues()
}

// MARK: - IMKServerInput protocol methods
Expand Down Expand Up @@ -311,6 +327,34 @@ class McBopomofoInputMethodController: IMKInputController {
LanguageModelManager.loadUserPhrases(
enableForPlainBopomofo: Preferences.enableUserPhrasesInPlainBopomofo)
LanguageModelManager.loadUserPhraseReplacement()

// Empty the issues so that if there are still the same issues, a
// notification will be shown.
McBopomofoInputMethodController.latestUserFileIssues = []
checkUserFileIssues()
}

@objc func showUserFileIssues(_ sender: Any?) {
let header = NSLocalizedString(
"Issues were found in the following user phrase files:", comment: "")
let report =
header + "\n\n"
+ McBopomofoInputMethodController.latestUserFileIssues.joined(separator: "\n")
Comment thread
lukhnos marked this conversation as resolved.
let tempDir = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let now = Date()
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyyMMdd-HHmmss.SSS"
let dateString = formatter.string(from: now)
let fileName = "UserFileIssues-\(dateString).txt"
let fileURL = tempDir.appendingPathComponent(fileName)
do {
try report.write(to: fileURL, atomically: true, encoding: .utf8)
NSWorkspace.shared.open(fileURL)
} catch {
NSLog("Failed to write report to temporary file: \(error)")
return
}
}

@objc func showAbout(_ sender: Any?) {
Expand Down Expand Up @@ -849,4 +893,20 @@ extension McBopomofoInputMethodController {
private func hideTooltip() {
McBopomofoInputMethodController.tooltipController.hide()
}

private func checkUserFileIssues() {
let issues: [String] = keyHandler.collectUserFileIssues()

// McBopomofoLM caps the maximum number of issues collected, and so
// we'll just do this O(n) comparison since n is small.
if McBopomofoInputMethodController.latestUserFileIssues != issues {
McBopomofoInputMethodController.latestUserFileIssues = issues

if !McBopomofoInputMethodController.latestUserFileIssues.isEmpty {
NotifierController.notify(
message: NSLocalizedString(
"Check McBopomofo menu for user file issues", comment: ""), stay: true)
}
}
}
Comment thread
lukhnos marked this conversation as resolved.
}
2 changes: 2 additions & 0 deletions Source/KeyHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ extern InputMode InputModePlainBopomofo;

- (size_t)computeActualCursorIndex:(size_t)cursor;

- (NSArray<NSString *> *)collectUserFileIssues;

@property (strong, nonatomic) InputMode inputMode;
@property (weak, nonatomic) id<KeyHandlerDelegate> delegate;
@property (assign, nonatomic, readonly) NSInteger actualCandidateCursorIndex;
Expand Down
47 changes: 47 additions & 0 deletions Source/KeyHandler.mm
Original file line number Diff line number Diff line change
Expand Up @@ -2502,4 +2502,51 @@ - (nullable InputState *)buildAssociatedPhraseStateWithPreviousState:(id)state
return [self buildAssociatedPhraseStateWithPreviousState:state prefixCursorAt:[self computeActualCursorIndex:candidtaeStateOriginalCursorIndex] reading:prefixReading value:prefixValue selectedCandidateIndex:candidateIndex useVerticalMode:useVerticalMode useShiftKey:useShiftKey];
}

- (NSArray<NSString *> *)collectUserFileIssues
{
NSMutableArray<NSString *> *array = [NSMutableArray array];

std::vector<McBopomofo::McBopomofoLM::UserFileIssue> issues = _languageModel->getUserFileIssues();
for (const auto& issue : issues) {
NSMutableString *msg = [NSMutableString string];

switch (issue.fileType) {
case McBopomofo::McBopomofoLM::UserFileType::USER_PHRASES:
[msg appendString:NSLocalizedString(@"User phrase file", "")];
break;
case McBopomofo::McBopomofoLM::UserFileType::EXCLUDED_PHRASES:
[msg appendString:NSLocalizedString(@"Excluded phrase file", "")];
break;
case McBopomofo::McBopomofoLM::UserFileType::PHRASE_REPLACEMENT_MAP:
[msg appendString:NSLocalizedString(@"Phrase replacement file", "")];
break;
default:
// Shouldn't happen, and so the string is not localized.
[msg appendString:@"Unknown user file"];
break;
}

[msg appendFormat:@" (%@) ", [NSString stringWithUTF8String:issue.path.filename().c_str()]];
[msg appendFormat:NSLocalizedString(@"line %lu: ", ""), issue.lineNumber];

switch (issue.issueType) {
case McBopomofo::McBopomofoLM::IssueType::MISSING_SECOND_COLUMN:
[msg appendString:NSLocalizedString(@"Only one column was found.", "")];
break;
case McBopomofo::McBopomofoLM::IssueType::NULL_CHARACTER_IN_TEXT:
[msg appendString:NSLocalizedString(@"Illegal NULL character was found.", "")];
break;
case McBopomofo::McBopomofoLM::IssueType::NO_ISSUE:
default:
// Shouldn't happen, and so the string is not localized.
[msg appendString:@"Unknown issue."];
break;
}
Comment thread
lukhnos marked this conversation as resolved.

[array addObject:msg];
}

return array;
}
Comment thread
lukhnos marked this conversation as resolved.

@end
18 changes: 18 additions & 0 deletions Source/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,21 @@
"Roman Numbers (Full-Width Upper Case)" = "Roman Numbers (Full-Width Upper Case)";

"Roman Numbers (Full-Width Lower Case)" = "Roman Numbers (Full-Width Lower Case)";

"Show Issues in User Files ⚠️" = "Show Issues in User Files ⚠️";
Comment thread
lukhnos marked this conversation as resolved.

"Issues were found in the following user phrase files:" = "Issues were found in the following user phrase files:";

"Check McBopomofo menu for user file issues" = "Check McBopomofo menu for user file issues";

"User phrase file" = "User phrase file";

"Excluded phrase file" = "Excluded phrase file";

"Phrase replacement file" = "Phrase replacement file";

"line %lu: " = "line %lu: ";

"Only one column was found." = "Only one column was found.";

"Illegal NULL character was found." = "Illegal NULL character was found.";
18 changes: 18 additions & 0 deletions Source/zh-Hant.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,21 @@
"Roman Numbers (Full-Width Upper Case)" = "羅馬數字 (大寫全形)";

"Roman Numbers (Full-Width Lower Case)" = "羅馬數字 (小寫全形)";

"Show Issues in User Files ⚠️" = "列出自訂詞庫中的問題 ⚠️";
Comment thread
lukhnos marked this conversation as resolved.

"Issues were found in the following user phrase files:" = "以下是用戶自訂詞庫檔案中發現的問題:";

"Check McBopomofo menu for user file issues" = "自訂詞庫有誤,請從小麥注音選單點選「列出自訂詞庫中的問題」";

"User phrase file" = "使用者自訂詞彙檔";

"Excluded phrase file" = "排除詞彙檔";

"Phrase replacement file" = "詞彙替換表格檔";

"line %lu: " = "第 %lu 行:";

"Only one column was found." = "一行應該有兩欄文字,這行只有一欄。";

"Illegal NULL character was found." = "這一行包含了不合規則的 NULL 字元 (0x00)。";