The ICU Project offers methods for what you are trying to achieve and on Xcode 11 it is possible to link the ICU library into an iOS application or iOS framework target. To do so, open your target and on the "General" tab under "Frameworks and Libraries" add libicucore.tbd
.
It might happen that Xcode chooses the macOS variant of the library if you do that in which case you'll see something like this in your project file.
ABCDEFGHIJKLMNOPQRSTUVWX /* libicucore.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libicucore.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/usr/lib/libicucore.tbd; sourceTree = DEVELOPER_DIR; };
To force the iOS variant, simply edit the project file with a text editor to make the line look something like this
ABCDEFGHIJKLMNOPQRSTUVWX /* libicucore.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libicucore.tbd; path = usr/lib/libicucore.tbd; sourceTree = SDKROOT; };
Unfortunately, the version of the library that ships with iOS is a bit older and doesn't include ubidi_getBaseDirection
. There is, however, a method u_charDirection
that you can use to rebuilt ubidi_getBaseDirection
. Simply walk the characters in the string and return the direction of the first character with strong directionality. Below is an example of how to do this in Swift (Objective-C port should be straightforward).
enum Direction {
case leftToRight
case rightToLeft
case neutral
}
func ubidi_getBaseDirection(of string: String) -> Direction {
guard let data = string.data(using: .utf32) else {
return .leftToRight
}
let chars = data.withUnsafeBytes { $0.bindMemory(to: UChar32.self) }
for c in chars {
let direction = u_charDirection(c)
if direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC {
return .rightToLeft
} else if direction == U_LEFT_TO_RIGHT {
return .leftToRight
}
}
return .neutral
}
Note that since libicucore
is a pure C library, you'll need to add it to your bridging header / umbrella header if you're working in Swift. I've found the following to be enough.
#include "unicode/utypes.h"
return ... (c >= 0x10800 && c <= 0x10805)...
. This is becauseunichar
isunsigned short
which has a maximum value of 0xFFFF and these constants are larger than that. Where do these constants come from? Maybe I should create a new question? – Wits