为啥 NSPredicateEditor 会自动本地化一些表达式字符串?如何禁用?

Posted

技术标签:

【中文标题】为啥 NSPredicateEditor 会自动本地化一些表达式字符串?如何禁用?【英文标题】:Why is NSPredicateEditor automatically localizing some Expression strings? How to disable?为什么 NSPredicateEditor 会自动本地化一些表达式字符串?如何禁用? 【发布时间】:2017-02-06 08:49:08 【问题描述】:

我发现 一些 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 会以这种方式映射。我不知道除了 Operators 和 UTIs 之外的其他格式是否有自动本地化字符串。

这是一个问题,因为我想localize my NSPredicateEditor and Row Templates。

本地化谓词的过程涉及将键与本地化值匹配。

KEY: "%[left]@ %[is]@ %[right]@"
VAL: "%1$[left_display_string]@ %2$[is]@ %3$[right_display_string]@"

问题在于键中的值必须与用户界面中显示的字符串匹配。不是最初设置为行模板的左右表达式的字符串。

所以,我无法在密钥中使用 "public.image" 进行本地化。 UI 出于某种原因已经将其本地化为"image"。如果我想本地化行模板,我必须改用字符串"image"。而且我不知道这个"image" 字符串是如何或为什么被选中的。

我可以通过测试确定这些字符串,然后编写一个将表达式映射到本地化字符串的表。但我更希望有一个禁用这种自动本地化的解决方案,这样我就不必担心我没有测试过的字符串。

为什么 UTI 会自动本地化?其他值是否受到相同的处理?

有没有办法禁用 UTI 字符串和/或整个谓词编辑器的自动本地化?

【问题讨论】:

我已经为 Apple 打开了 rdar://30468110 以将这些私有翻译词典添加到公共 API。 【参考方案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;

bt:

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 中可能会有所不同。

【讨论】:

哇,这太棒了。谢谢你。这个来源在某处可用吗?那些 all 条目是否在显示值字典中?知道.equalTo-to-"is" 翻译发生在哪里吗? 看起来它们将是方法_displayValueForPredicateOperator:_displayValueForCompoundPredicateType:_displayValueForConstantValue:_displayValueForKeyPath:...关于在哪里找到实现或键/值的任何提示? 我遇到了为_displayValueForConstantValue: 添加的断点。但是你能解释一下你是如何找到正在使用的完整字典的吗?我不明白这将如何出现在调试器中。谢谢! objc_msgSend 和选择器 initWithObjectsAndKeys: 之后,返回的结果在 rax 中。 po $rax 打印字典。【参考方案2】:

您可以直接调用私有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 崩溃或返回错误的字符串翻译的问题。

【讨论】:

【参考方案3】:

扩展 Willeke 的最佳答案:

将符号断点添加到以下私有方法以查看映射。

_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)"

【讨论】:

以上是关于为啥 NSPredicateEditor 会自动本地化一些表达式字符串?如何禁用?的主要内容,如果未能解决你的问题,请参考以下文章

iOS 上是不是存在类似 NSPredicateEditor 的东西?

将 NSPredicateEditor 添加到 NSScrollView 时出现 UI 故障

关闭 NSPredicateEditor 动画

NSPredicateEditor 只是不会出现

NSPredicateEditor 的 UI 约定

NSPredicateEditor,忽略没有搜索词的行?