为啥 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 的东西?