writing direction 属性
Writing Direction Attribute
このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら↗。
01 何が問題だったのか
AttributedString には、これまで段落の base writing direction(基本となる書字方向)を 単独の属性として 表現する手段がありませんでした。
UIKit や AppKit には paragraph style というプロパティがあり、その中の一要素として writing direction が含まれていますが、これは NSAttributedString 由来の仕組みで、いくつかの不都合があります。
- writing direction だけを設定したいときも、paragraph style の他のプロパティの値まで一緒に決めなければなりません。
runBoundariesやinheritedByAddedTextといったAttributedStringKeyの高度な振る舞いを活かせません。- writing direction は UI フレームワーク固有の話ではなく、双方向テキスト(左から右に書く言語と右から左に書く言語が混在しうるテキスト)を扱うあらゆる文脈で必要になる、文字列の基本的な性質です。
たとえば英語のセンテンスにアラビア語を埋め込む場合と、アラビア語のセンテンスに英語を埋め込む場合とでは、見た目を正しく整えるために必要な base writing direction が異なります。AttributedString 自体にこの情報を持たせられないと、UI フレームワークごとに別の表現で受け渡す必要があり、フレームワークに依存しない処理(双方向テキストの整形やシリアライズなど)でも writing direction を伝搬させづらくなります。
02 どのように解決されるのか
この Proposal は、AttributedString の base writing direction を表す独立した属性を追加します。新しい API は @available(FoundationPreview 6.2, *) でガードされ、FoundationPreview 6.2 以降で利用できます。
AttributedString.WritingDirection
writing direction は、leftToRight と rightToLeft の 2 ケースを持つ enum として定義されます。
extension AttributedString {
@frozen
public enum WritingDirection: Codable, Hashable, CaseIterable, Sendable {
case leftToRight
case rightToLeft
}
}
ここでの writing direction は「双方向テキストの directional run(同じ方向性を持つ連続した文字の並び)をどちら側から並べていくか」を決める、base direction の指定です。leftToRight なら最初の directional run が左端に置かれ、後続の run が右へ続きます。rightToLeft ではその逆になります。
writing direction は次のいずれとも別の概念です。
- テキストの alignment(左寄せ・中央寄せなど)
- line layout direction(行を縦に並べるか横に並べるか)
- character direction(個々の文字自体の方向性)
ただし alignment の既定値の決定には、しばしば writing direction が利用されます。
縦書きスクリプトで使われる場合、leftToRight は top-to-bottom、rightToLeft は bottom-to-top と解釈されます。これは writing direction が常に line layout direction と直交するように設計されているためです。
双方向テキストを正しく見せるには、テキストの主要言語の Locale.Language.characterDirection に対応する値を writing direction にセットします。たとえばアラビア語が混ざる英文なら .leftToRight、英語が混ざるアラビア文なら .rightToLeft です。
WritingDirectionAttribute キー
属性キー WritingDirectionAttribute が AttributeScopes.FoundationAttributes に追加され、writingDirection という名前で参照できます。
extension AttributeScopes.FoundationAttributes {
public let writingDirection: WritingDirectionAttribute
@frozen
public enum WritingDirectionAttribute: CodableAttributedStringKey {
public typealias Value = AttributedString.WritingDirection
public static let name: String = "Foundation.WritingDirection"
public static let runBoundaries: AttributedString
.AttributeRunBoundaries? = .paragraph
public static let inheritedByAddedText = false
}
}
ポイントは 2 つあります。
runBoundaries = .paragraph: writing direction は段落単位で意味を持つ性質なので、属性の run も段落境界で切られます。範囲を指定して値を読み書きしても、その範囲と交差する段落 全体 に値が反映されます。inheritedByAddedText = false: ある段落の writing direction は次の段落とは独立に決まるため、段落をまたいで追加されたテキストが既存の writing direction を継承することはありません。
使い方
通常の AttributedString の属性と同じように扱えます。値は optional で、未設定(nil)は「writing direction が指定されていない」状態を表します。
// アラビア文に英単語 "Swift" が埋め込まれているので、全体としては右から左。
var string = AttributedString(
"Swift مذهل!",
attributes: .init().writingDirection(.rightToLeft)
)
// writing direction の情報を取り除くには nil を代入する。
string.writingDirection = nil
範囲指定で値を変更しても、runBoundaries = .paragraph の効果でその段落全体に適用されます。
let range = string.range(of: "Swift")!
// "Swift" の範囲だけを指定しても、その段落全体の writing direction が
// .leftToRight に変わる。
string[range].writingDirection = .leftToRight
assert(string.runs[\.writingDirection].count == 1)
同じ段落に文字列を追加すると、既存の writing direction はそのまま新しい部分にも適用されます。一方、改行で新しい段落を始めると、新しい段落は writing direction を継承しません。
// 同じ段落への追加: 既存の writing direction (.leftToRight) が引き継がれる。
string.append(AttributedString(" It is awesome for working with strings!"))
assert(string.runs[\.writingDirection].count == 1)
assert(string.writingDirection == .leftToRight)
// 改行を含む追加: 新しい段落は writing direction を継承しない。
string.append(AttributedString("\nThe new paragraph does not inherit the writing direction."))
assert(string.runs[\.writingDirection].count == 2)
assert(string.runs.last?.writingDirection == nil)
writing direction が必要なのは段落単位の base direction だけで、natural や unknown のようなケースは導入されていません。属性が設定されていない状態(nil)が「writing direction が決まっていない」ことを表すためです。文字列分析などで writing direction を決めたい場合の戦略は、別途自前の属性を用意するか、後述の今後の見通しに従って Foundation 側の API 追加を待つことになります。
03 今後の見通し
双方向テキストを正しく表示するには、テキストの主要言語の character direction に合わせた writing direction を設定する必要があります。Foundation が文字列の strong directionality や Unicode BiDi アルゴリズムの結果をもとに、適切な writing direction を 自動で判定する API を提供することが構想として挙げられています。
なお、ここで述べたのは将来の方向性の示唆であり、その実現を約束するものではありません。文字列分析による自動判定が導入される際には、解析結果として付与した writing direction を文字列の変更に応じて自動的に無効化する仕組み(テキストが変わったときに自動で値をリセットする補助的な属性)も併せて検討される可能性があります。