Почему NSPredicateEditor автоматически локализует некоторые строки выражений? Как отключить?
Я обнаружил, что некоторые NSPredicateEditor
/ NSPredicateEditorRowTemplate
значения локализуются автоматически OS X.
Это легко заметить при отображении операторов: .equalTo
в строку is
,
Но я только что заметил, что строки UTI отображаются в читаемую человеком версию этого UTI.
Ниже я установил "public.image"
но затем отображается как "image"
,
func setupPredicateEditor() {
let left = [NSExpression(forKeyPath: "Type")]
let operators = [NSComparisonPredicate.Operator.equalTo.rawValue as NSNumber]
let right = [
NSExpression(forConstantValue: "public.image"),
NSExpression(forConstantValue: "public.text"),
NSExpression(forConstantValue: "public.fakeUTI"),
];
let rowTemplate = NSPredicateEditorRowTemplate.init(leftExpressions: left, rightExpressions: right, modifier: .all, operators: operators, options: 0)
predicateEditor.rowTemplates = [rowTemplate]
predicateEditor.addRow(self)
}
Только определенные действительные UTI отображаются таким образом. Я не знаю, имеют ли другие форматы, кроме операторов и UTI, автоматические локализованные строки.
Это проблема, потому что я хочу локализовать свои шаблоны NSPredicateEditor и Row.
Процесс локализации предиката включает сопоставление ключа с локализованным значением.
KEY: "%[left]@ %[is]@ %[right]@"
VAL: "%1$[left_display_string]@ %2$[is]@ %3$[right_display_string]@"
Проблема в том, что значения в ключе должны соответствовать строкам, отображаемым в пользовательском интерфейсе. Не те строки, которые изначально установлены для левого и правого выражений шаблона строки.
Итак, я не могу локализовать с помощью "public.image"
в ключе. Пользовательский интерфейс по какой-то причине уже локализует это "image"
, Если я хочу локализовать шаблон строки, я должен использовать строку "image"
вместо. И я не знаю, как и почему это "image"
Строка выбирается.
Я мог бы определить эти строки с помощью тестирования, а затем написать таблицу, которая отображает выражение в локализованную строку. Но я бы предпочел иметь решение, которое отключает эту автоматическую локализацию, чтобы мне не приходилось беспокоиться о строках, которые я не тестировал.
Почему ИМП локализуются автоматически? Другие ценности получают то же самое лечение?
Есть ли способ отключить автоматическую локализацию строк UTI и / или всего редактора предикатов?
1 ответ
Не ответ, а некоторая информация: NSPredicateEditorRowTemplate
переводит строки в _displayValueForConstantValue:
, Он использует словарь:
{
"com.apple.application" = application;
"com.apple.pict" = PICT;
"com.apple.protected-mpeg-4-audio" = "purchased music";
"com.apple.rtfd" = RTFD;
"com.compuserve.gif" = GIF;
"com.microsoft.bmp" = BMP;
"public.audio" = music;
"public.folder" = folder;
"public.html" = HTML;
"public.image" = image;
"public.jpeg" = JPEG;
"public.jpeg-2000" = "JPEG 2000";
"public.mp3" = MP3;
"public.mpeg-4-audio" = "MPEG4 audio";
"public.png" = PNG;
"public.rtf" = RTF;
"public.source-code" = "source code";
"public.text" = text;
"public.tiff" = TIFF;
"public.xml" = XML;
}
Ы:
AppKit`-[NSPredicateEditorRowTemplate _displayValueForConstantValue:] + 913
AppKit`-[NSPredicateEditorRowTemplate _viewFromExpressions:] + 589
AppKit`-[NSPredicateEditorRowTemplate initWithLeftExpressions:rightExpressions:modifier:operators:options:] + 205
Редактировать:
_displayValueForKeyPath:
использует этот словарь:
{
kMDItemContentCreationDate = Created;
kMDItemContentModificationDate = "Last modified";
kMDItemContentTypeTree = "File type";
kMDItemDisplayName = "File display name";
kMDItemFSContentChangeDate = "Change date";
kMDItemFSCreationDate = "Creation date";
kMDItemFSName = "File name";
kMDItemFSOwnerGroupID = "Owner group id";
kMDItemFSOwnerUserID = "Owner user ID";
kMDItemFSSize = "File size";
kMDItemLastUsedDate = "Last opened";
kMDItemPath = "File path";
}
_displayValueForPredicateOperator:
а также _displayValueForCompoundPredicateType:
перевести перечисления в строки.
Это должно быть задокументировано, но это не так. Я ставлю точку останова на _displayValueForConstantValue:
и я смотрел что случилось. Словари жестко запрограммированы и могут отличаться в других версиях macOS.
Вы можете вызвать частные методы API напрямую, чтобы использовать отображение системы.
В Swift для этого требуется заголовок моста:
#import <AppKit/AppKit.h>
@interface NSPredicateEditorRowTemplate ()
- (NSString *)_displayValueForKeyPath:(CFStringRef)keyPath;
- (NSString *)_displayValueForConstantValue:(CFStringRef)constantValue;
- (NSString *)_displayValueForCompoundPredicateType:(NSCompoundPredicateType)compoundPredicateType;
- (NSString *)_displayValueForPredicateOperator:(NSPredicateOperatorType)predicateOperator;
@end
Эти частные методы затем можно вызывать так:
let keyPath = rowTemplate._displayValue(forKeyPath: kMDItemFSSize) // "File size"
let constantValue = rowTemplate._displayValue(forConstantValue: "com.apple.application" as CFString) // "application"
let compoundPredicateType = rowTemplate._displayValue(for: .or) // "Any"
Три перечисленных выше работают, но в настоящее время у меня проблемы с _displayValueForPredicateOperator:
сбой с EXC_BAD_ACCESS
или возврат неправильного перевода строки.
Расширяя отличный ответ Виллеке:
Добавьте символические точки останова к следующим частным методам, чтобы увидеть сопоставления.
_displayValueForKeyPath:
_displayValueForConstantValue:
_displayValueForCompoundPredicateType:
_displayValueForPredicateOperator:
Когда вы прерываете, ставьте точку останова на строку, содержащую objc_msgSend
и снова сломайся там.
Затем введите po $rax
для печати таблицы сопоставления.
В двух нижних случаях он не использует словарь, но строки можно увидеть при достижении точек останова.
_displayValueForKeyPath:
{
kMDItemContentCreationDate = Created;
kMDItemContentModificationDate = "Last modified";
kMDItemContentTypeTree = "File type";
kMDItemDisplayName = "File display name";
kMDItemFSContentChangeDate = "Change date";
kMDItemFSCreationDate = "Creation date";
kMDItemFSName = "File name";
kMDItemFSOwnerGroupID = "Owner group id";
kMDItemFSOwnerUserID = "Owner user ID";
kMDItemFSSize = "File size";
kMDItemLastUsedDate = "Last opened";
kMDItemPath = "File path";
}
_displayValueForConstantValue:
{
"com.apple.application" = application;
"com.apple.pict" = PICT;
"com.apple.protected-mpeg-4-audio" = "purchased music";
"com.apple.rtfd" = RTFD;
"com.compuserve.gif" = GIF;
"com.microsoft.bmp" = BMP;
"public.audio" = music;
"public.folder" = folder;
"public.html" = HTML;
"public.image" = image;
"public.jpeg" = JPEG;
"public.jpeg-2000" = "JPEG 2000";
"public.mp3" = MP3;
"public.mpeg-4-audio" = "MPEG4 audio";
"public.png" = PNG;
"public.rtf" = RTF;
"public.source-code" = "source code";
"public.text" = text;
"public.tiff" = TIFF;
"public.xml" = XML;
}
_displayValueForCompoundPredicateType:
0x7fff32a7342c <+20>: leaq 0x5ca25255(%rip), %rax ; @"Any"
0x7fff32a73434 <+28>: leaq 0x5c9c8dad(%rip), %rax ; @"None"
0x7fff32a7343c <+36>: leaq 0x5ca00ac5(%rip), %rax ; @"All"
0x7fff32a73456 <+62>: leaq 0x5ca2524b(%rip), %rdx ; @"(unknown compound type %ld)"
_displayValueForPredicateOperator:
0x7fff32a7331b <+42>: leaq 0x5ca251c6(%rip), %rax ; @"is less than"
0x7fff32a73332 <+65>: leaq 0x5ca251cf(%rip), %rax ; @"is less than or equal to"
0x7fff32a7334a <+89>: leaq 0x5ca252f7(%rip), %rax ; @"between"
0x7fff32a73356 <+101>: leaq 0x5ca251cb(%rip), %rax ; @"is greater than"
0x7fff32a73362 <+113>: leaq 0x5ca251df(%rip), %rax ; @"is greater than or equal to"
0x7fff32a7336b <+122>: leaq 0x5ca251f6(%rip), %rax ; @"is"
0x7fff32a73374 <+131>: leaq 0x5ca2520d(%rip), %rax ; @"is not"
0x7fff32a7337d <+140>: leaq 0x5ca25224(%rip), %rax ; @"matches"
0x7fff32a73386 <+149>: leaq 0x5ca2523b(%rip), %rax ; @"is like"
0x7fff32a7338f <+158>: leaq 0x5ca25252(%rip), %rax ; @"begins with"
0x7fff32a73398 <+167>: leaq 0x5ca25269(%rip), %rax ; @"ends with"
0x7fff32a733a1 <+176>: leaq 0x5ca01300(%rip), %rax ; @"in"
0x7fff32a733aa <+185>: leaq 0x5ca25277(%rip), %rax ; @"contains"
0x7fff32a733d4 <+227>: leaq 0x5ca2528d(%rip), %rdx ; @"(unknown predicate operator %ld)"