ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Get it right (to left)(右から左方向への文字体)
アラビア語やヘブライ語などの右横書き言語にローカライズされたAppを開発する方法をご覧ください。これらの言語に関する重要な考慮事項、問題に対するソリューション、Appで右横書き言語のエクスペリエンスを向上させるベストプラクティスを紹介します。
リソース
関連ビデオ
WWDC22
WWDC21
-
ダウンロード
こんにちは リッチです 分かりやすく ご説明させていただきます 一般的なヨーロッパの言語 一般的なアジアの言語など 多くの言語向けに Appをローカライズ してきたかと思います 今度はアラビア語とヘブライ語に ローカライズしたいとしたら それはいい選択です アラビア語は私たちのプラット- フォームで最も使われている 10言語のうちの1つですが 他の言語向けの開発では 直面しないような 課題もあります このトークではアラビア語や ヘブライ語などの言語に ローカライズできるようApp開発 する方法について説明します アラビア語とヘブライ語は いわゆる「右から左へ読む言語」の中 最もよく使われている 言語です なぜそう呼ばれるのか? 英語 フランス語 中国語 タイ語など多くの言語は このように左から右へ 文字が書かれています ヘブライ語ではこのように 右から左へ文字が走ります アラビア語でも同じで 文字も筆記体で 結合しています ”salaam"の4文字を別々に 書くとこのようになります
ちなみにアラビア語や ヘブライ語だけではありません Appleは既に右から 左へ進む15の言語の フォントとキーボードを サポートしています 以下ヘブライ語の 文章を一段落 こちらはヘブライ語版の 「数式・関数ヘルプ」で Numbersのページです テキストが右側に揃えられ 左側がバラバラな所 最後の行を含め多くの行で 左側に句読点が あることに注目してください この段落には 数字も入っています 数字もやはり左から右へ こちらはNumbersの 対応機能が 250以上であることを 伝えています これはiWorkとそれを構成する Pages Numbers Keynoteという Appの名前であり いくつかの英単語が 含まれていることが わかります これらはヘブライ語の段落でも 左から右に書かれている そのため多くの段落で テキストは双方向になります これはアラビア語や ヘブライ語に固有の性質で よく「bi-di」言語とも 呼ばれる所以です
さらに視野を広げると ページ全体が右から左へと レイアウトされている ことがわかります ここには表がありますが テキストは 画像の左側ではなく 右側にあります
さらにSafariの ウインドウ枠を広げても コンテンツで終わらないことが わかります アラビア語やヘブライ語の テキストは右から左へ進んでいく事から 他のUI要素も同じように 考えるのが自然でしょう ユーザーが左から始まって 右へ進むことを期待するように アラビア語やヘブライ語の 話者はその逆を期待するのです ここではSafariのツールバーを 右から左へ動かし 右上に信号機のボタン 左側にボタンが 続きます そして画面全体に フォーカスを広げてみると どこまでも広がっている ことがわかります これはNumbersの ヘルプ画面ですが Numbersの要素もすべて 反転していることがわかります 左側がサイドバーです タブバーが右から左へ流れ ドキュメントも反転しています MacのメニューバーとDockも 同様に右から左へ流れています しかしこのような 複雑な作業のほとんどを 私たちは皆さんに代わって行います サポートのほとんどは 無料で提供されます しかし気をつけなければ ならないことがあります そこでこのシステムが何を してくれるのかお話します オプトイン オプトアウトが必要な場合 また独自サポートを実施する 際に考えるべきことなどです テキスト 画像 コントロールの向き UIレイアウトについて説明します またアラビア語の数字 表示についても説明します 最後にAppが右から 左に正しく処理されているか どうかをテストする方法に ついて少し説明します では始めましょう まずテキストの仕組みに ついてもう少し詳しく話し 用語も紹介します まずは書く方向の考え方から すでに見てきたように 英語は左から右へ ヘブライ語は右から 左へ書くものです では混ぜたら どうなるでしょう
このような多言語文の場合 個々の構成要素の 書き方はそのままで それぞれの文が3つの 構成要素から なることを意味します: ネイティブ言語で書かれた 2つの文章が 異なる言語で書かれた 1つの文章を挟んでいます パラグラフの 方向性というのは このような個々の スニペットの順序のことです 英語の文章が左から右へ 書かれていると言うのは この3つのボックスが 左から右へ走っているからで ヘブライ語の文章が右から左へ 書かれていると言うのは この3つのボックスが右から 左へ走っているからです
少し異なるが関連する概念として テキストアライメントがあります 左から右への言語を 読む場合 視線は ページの左側に行き 右側に進んでいく 右から左の言語を読むと その逆になってしまうのです そのため右から左への言語の場合 テキストは右側に配置されます しかしほとんどの場合 これらの心配は無用です CoreTextは1行や1段落に 異なる方向の 文字が混在している 場合にも すべての文字を適切に 配置するだけでなく すべてのUIフレームワークが 自動的に文字の向きや 配置を設定します すべてのUIウィジェットの デフォルトは 「自然な筆記方向」と「自然な配置 」と 呼ばれるものです テキストウィジェットの 書込み方向はユーザーのUI言語の 通常の書込み方向と一致するよう デフォルト設定されています つまりUIがヘブライ語や アラビア語の場合 テキストウィジェットの筆記方向は デフォルトで右から左となります 自然な配置は ライティングの方向性に沿っています つまりテキストウィジェットの 書込み方向が 右から左の場合 右寄せになります 大抵の場合これで十分ですが デフォルトの上書きもできます これについては制御方向性の セクションで詳しく説明します この機会に用語集を 作ると良いと思います ここで言っているのは 自然な配置とは 左から右への言語では 左配置に 右から左への言語では 右配置に対応する事です この表は 順次追加していきます もちろん心配材料は 文字だけではありません 文字が反対方向に 読まれることは 文字以外のAppの要素に 大きな影響を及ぼします アイコン等の絵柄にどんな 影響を与えるか説明します 英語版とアラビア語版の ページツールバーです ツールバーのアイコンの いくつか詳しく見てみましょう 「ページを追加」 「メディア」ボタンなど 多くのボタンが両言語で 同じように見えます これは左右対称であるためか 方向性が言語に縛られていないためか どちらの言語でも 問題なく見えるのです その他「表示」「文書」ボタンなどは アラビア語の反転表示に 切り替わります 「表示」ボタンを押すと アラビア語でウインドウの 反対側に表示される「ページ」 サイドバーが表示されるので それを反映させるためアイコンを 変更する必要があります 「文書」ボタンはユーザーが アラビア語で書いている場合 ページが逆方向に 回転するように変化します さらにアイコンが完全に 変わってしまう状況もありえます 「テキストボックスの挿入」 ボタンの文字が ユーザーの言語に合わせて 別の文字に変化します
繰返しですが嬉しいニュースは この多くがシステムによって処理されます 画像の向きは一般的な テキストの書き方よりも 少し考えなければなりませんが 正しく設定するのはとても簡単です MacのPagesの表示メニュー 英語版とアラビア語版です 「ルーラーを表示」アイコンが 反転してる事に注意ください 右から左への言語では 垂直方向の罫線は 右側にあります ルーラーアイコンのような カスタム画像の場合 右から左への動作はXcodeの イメージセットエディタで制御されます 左右の画像が同じであれば 特に何もする 必要はありません また開発言語と記述方向が 逆の言語でAppが 動作している場合 システムがアルゴリズムで 画像をミラーリング することも可能です Xcodeのイメージセットエディターで この機能を要求できます サイドバーの中に「Direction」と 書かれたコントロールがあります これをクリックすると選択肢4つから なるメニューが表示されます UI言語に関係なくイメージが 同じなら「Fixed」を選びます アルゴリズムによる ミラーリングを希望する場合は 「Mirrors」オプションの いずれかで選択します どちらを選ぶかは開発言語の 方向によります UIの向きを変えたときに 挙動が異なる複数の要素が あったり 動かしたくない シェーディングがあったりと アルゴリズムで ミラーリングできない 画像がある 場合は「Both」を選ぶと 左から右 右から左の文脈で 使う画像を別々に 作成することが可能です しかしPagesのツールバーが そうであったように 「SF Symbols」の画像を使えば 事態はさらに簡単になります ほとんどすべての作業を 代行しています 右から左への言語用に 変更する必要がある記号は 自動的に変更されます 例えばこの箇条書きリストの アイコンを考えてみてください 多くの画像について 「SF Symbols」のサイドバーには 「Localization」という 項目があり 選択した画像の ローカライズ版を表示できます この場合 箇条書きのアイコンは 左から右と右から左の バージョンがあります 自動でミラーリング してくれます
ローカライズ機能は 単に右から左への 言語のミラーリングに とどまりません 「テキストボックスの挿入」アイコンの ローカライズ版がこちら ラテン文字や アラビア文字だけでなく さまざまな文字に対応した ローカライズ版も用意されています
アラビア語のサポートで 特に重要なのは 「ヘルプ」アイコンとして よく使われるクエスチョンマークです アラビア語では クエスチョンマークは ラテン語のクエスチョンマークを 逆にしたものです ヘルプアイコンにSFシンボルの アイコンを使用することで 余分な作業をすることなく このバージョンを手に入れられます 矢印などの方向性を 示す画像は よく考える必要があります ここで4つの矢印を円形にした アイコンを用意しました 2組になっているのが わかります 左向きが2つ 右向きが2つありますね 左を向いている 2つだけを見ると1つは "arrow.backward.circle "と 呼ばれているのがわかります これは右から左で右を 指すようにフリップします もう1つは「arrow.left..circle」 という名前で 右から左への 反転は行いません SFシンボルではこの命名規則に従い 右から左へ反転させたい アイコンさせたくない アイコンを随所に配置します 「前方」「後方」は反転し 「Left」「Right」は反転しない 矢印などの図形を使って「前へ」 「後ろへ」ということを 伝えるなら 反転タイプを 絶対的な方向を伝えるなら 非反転タイプを 使いたいところです
そして用語のチャートに 行を追加してみましょう SFシンボルで画像を 選ぶ際には「Left」「Right」は 必ずその方向を指し 「前」「後」は UI言語によって異なる方向を 指すことを覚えておきましょう 次にコントロールなどの UIウィジェットが右から左へ 移動する際の処理に ついて説明します MacのKeynoteのサイドバーが 英語とアラビア語に表示される シェイプのフォーマット インスペクタです 右から左へすべてが反転して いることに注目ください メニューのインジケータが 右から左へ移動する ポップアップメニューボタンが たくさんありますね チェックボックスが いくつかありますが アラビア語ではラベルの右側に チェックボックスがあります アラビア語では不透明度 スライダーが変更され 右が最小左が最大と なりました そしてこのインスペクタの 他のコントロールも同様です この動作が無料なのは 大きな魅力です すべてのUIフレームワークの 標準的なUIコントロールは 右横書き言語のために 自動的にその外観を反転させます しかしこれを望まない場合や どのように起こるかをある程度 コントロールする必要が ある場合もあります 興味深い事例を いくつか紹介しよう ここでテキストラベルとアイコンの 両方が表示されるボタンを説明します Keynoteのアニメーション インスペクタで 「Move In」アニメーションの コントロールを表示しました このインスペクタには2つのボタンがあり ラベルとアイコンの両方が表示されます UI の方向が変わると プレビューボタンの矢印は 反転しますがアニメーションの 方向メニューの矢印は 反転しないことに 注意してください どちらもUIの方向で 反転しますがもし方向制御が メニューではなく ボタン群であったなら 左右を変えてほしくない というイメージはありますね
これを制御する方法を示すため この2つの例を小さな おもちゃのAppに 分離してみました
そのUIをSwiftUIで 構築するコードはこちらです ここでいくつか 興味深いことがあります 1つずつ見ていきます まずは画像名から 先ほど見たように SFシンボルの画像は 反転するアイコンとしないもの どちらか選ぶことになります ここではプレビューボタンに 「arrowtriangle.forward.fill」を 使用しています 名前にある「forward」が 右から左への反転を伝えています 方向ボタンには「arrow.left」 「arrow.right」を使用しました 名前にある「left」と 「right」は 右から左への反転ではない ことを物語っています
AppKitやUIKitで作業している場合も 同じように動作します Xcodeのストーリーボードエディタで 「Preview 」ボタンを選択した状態のAppです ボタンのアイコンは 属性インスペクタの 「Image」コントロールで 制御します コードではこれをボタンの 「Image」プロパティで設定します これはAppKitでもUIKitでも 基本的に同じように動作します SwiftUIの例に戻ると 次の問題はアイコンが ラベルのどの側に置かれるかを どのように制御するかです これはラベルのスタイルを 設定することで行います 組み込みの TitleAndIconLabelStyleは ユーザーの読む方向でラベル前に アイコンを配置します これを「Left」ボタンに 使うことができます 他の2つのボタンについては ユーザーの読む方向に対して ラベルの後にアイコンを 表示させたいですね これを行うにはカスタムラベルの スタイルが必要ですがとても簡単です ラベルスタイルのmakeBody()メソッドで HStackを作成し そこにタイトルとアイコンを 追加するだけです 他のHStackと同様に 追加した順番で表示順が決まり UI方向が適切な場合は 自動的に順序が逆転します このテクニックはボタンだけでなく ラベルを受取る全ビューで有効です もちろん「Right」ボタンでアイコンの 向きが変わるようでは困ります UIの向きに関係なく 常に右側に表示させたい そこでこのコードスニペットで 最後に興味深い事があります SwiftUIのビューはSwiftUI環境 から方向性を取得し 変更することができます これを行うにはビューに 「環境」修飾子を追加し 変更したいプロパティの キーと新しい値を指定します ここでは環境の「レイアウト方向」 プロパティをオーバーライドして 親から継承した値に関係なく 常に左から右に なるようにしています この方法で環境を変更すると ユーザーのUI方向に 反応するすべての SwiftUIビューで動作します 「Left」ボタンと「Right」 ボタンを含むHStackに モディファイアを適用している ことに注意ください ビューの環境に加えた変更は その子ビューに継承されるので ここに置くことでHStackがボタンの 順番を逆にしないだけでなく 両方のボタンがラベルの レイアウトを 逆にしないように することができます もちろん「Preview」 ボタンの親チェーンには 環境修飾モディファイアを 適用していませんので 私たちが望むように 適切なときに反転します
つまり「Left」ボタンのアイコンは 組み込みの TitleAndIconLabelStyle を 使用したため左側にあり 「Preview」と「Right」ボタンのアイコンは IconOnRightLabelStyle という カスタムラベルスタイルを使用したため 右側にあるということに なります 「Left」「Right」ボタンの順番やラベルの 内部配置が変わらないのは それらを含むHStackに 環境モディファイアを 追加して レイアウト方向を左から右に 設定したためです 「Preview」ボタンは その修飾子を持たないため ラベルの内部配置を 反転させます これはAppKitとUIKitで 動作が異なります どちらのフレームワークでも ラベルに対するアイコンの位置は Xcodeの属性 インスペクタにある 「Position」コントロールで 制御します このコントロールを クリックすると メニューの中にラベルと アイコンを水平に揃える オプションが 2組あることがわかる 「Leading」と 「Left」 「Trailing 」と 「Right」がありますね 「Leading」「Trailing」は UIの方向によって意味が変わり 「Left」「Right」は意味が 変わりません AppKitではボタンのイメージポジションの プロパティでこれを制御します UIKitではボタンの設定の 「imagePlacement」プロパティなので 先にボタンの設定をする必要が あるという事かもしれません 「Preview」ボタンの アイコンは位置を 「Trailing」に設定したため 左右に変化し 「Right」ボタンのアイコンは 位置を「Right」に設定したため 左右に変化しないのです また用語集の最後の行を 埋めることができます UIレイアウトを語る上で 「Leading」「Trailing」 という言葉は よく出てきます 「Forward」 「Backword」と同様に 「Left」「Right」と対比して 使われることが多いです リーディングエッジとは 左から右へ 右から左へ読む場合 行頭または画面や ウインドウの読み始めに 最も近いエッジのことです トレーリングエッジは 反対側のエッジに近い側で 左から右の場合は右 右から左の場合は 左となります ほとんどの場合「Left」「Right」の 代わりにこれらを使い 「Left」「Right」は絶対的な方向と 結びつくものだけにすると良いです
もうひとつ興味深い ケースを見てみよう iPhoneのKeynoteのテキストフォーマット- インスペクタの一部で 英語とアラビア語です このスクリーンショットでは 4分割されたコントロールがあります 上の2つインスペクタの ページセレクタと 標準的な「太字/イタリック/下線」 スタイルのボタンは UI言語によりセグメントの 順番が逆になります アラビア語が読めない人は ページセレクタで私を信じてください これまで見てきた 他のコントロールと同様 この動作はデフォルトで 無料で手に入ります 他の2つのセグメント- コントロールである アライメントコントロールは セグメントの順序を逆にしません 絶対的な方向で 動かすからです 左揃えはそれが 行頭であろうと 行末であろうと 左揃えになります 制御が逆転しないためには どうすべきか考えましょう 私たちはすでにSwiftUIで これを行う方法を知っています 「環境」モディファイアを適用して 環境の「レイアウト方向」プロパティを 左から右へ変更するだけです ここでは このテクニックを使って アライメントコントロールは 反転させずに スタイルコントロールは 通常通り反転させています UIKitではこれは 異なる動作をします そのセグメント制御の動作を シミュレートするために作られた Xcodeのおもちゃの Appを紹介します 太字/斜体/下線の動作を模倣した セグメントコントロールと アライメントコントロールを 模倣した セグメントコントロールの 2つがあります アライメントコントロールが 選択されています 属性インスペクタの中に「Semantic」と 書かれたメニューがあります そのメニューをクリックすると 5つの選択肢が出てきます このメニューはセマンティック- コンテンツ属性を制御します これを用いてこれがどのような コントロールであるかを言い システムはそれを用いて UIの方向に基づいて その外観を反転させるか どうかを決定します デフォルトは「Unspecified」です これがコントロールの 表示を反転させます 「Playback」はそのコントロールが メディア再生コントロール または再生コントロールの グループの一部であることを示します 「Spatial」とは空間的なコントロールで ある事またはそのグループの一部を示す 空間制御は空間内の物を絶対的な 方向に移動させます さらにコントロールの レイアウトを常に左から右 または右から左に することができます つまり太字/イタリック/下線 コントロールは意味内容属性が 「Unspecified」 に設定されているため セグメントを右から左に反転させ アライメントコントロールは セマンティックコンテンツの属性が 「Spacial」に設定されているためセグメントを 反転させないということです これの素晴らしいところは UISegmentedControlだけで 動作するわけでは ないことです 全UIViewsはセマンティック- コンテンツ属性を持っており コントロールの右から左への 動作をすべて制御します サブコンポーネントを持つ 標準的なUIKitビューの場合 セマンティックコンテンツ属性は そのビューのサブコンポーネントの位置が UI言語に基づいて 反転するか否かを決定します
AppKitではこのようなことは 別の方法で行います すべてのNSControlsについて Xcodeの属性インスペクタには 「Layout」と「Mirror」と 書かれた2つのメニューがあります 「Layout」メニューは コントロールの userInterfaceLayoutDirection プロパティに対応し コントロールが左から右 または右から左のどちらの レイアウトを使用すべきかを示します インターフェースビルダーで作業中は これを変更することはありません その代わり「Mirror」 メニューを使用します 「Always」に設定すると ユーザーのUI言語が 右から左のときに ニブを読み込むと userInterfaceLayoutDirection ひいてはコントロールの レイアウトが反転し「Never」に 設定するとこの動作が無効になり レイアウトは 同じままとなります この値を「Never」に 設定することで アライメントコントロールのレイアウトを 同じに保つことができます インターフェースビルダーを 使用していない場合は コントロールの userInterfaceLayoutDirectionを 直接左から右に戻すことで 同じことをコードで 実現します userInterfaceLayoutDirectionは NSViewのプロパティですが インターフェースビルダーでは NSコントロールのインスタンスにのみ 表示されNSコントロールでは ないものをリバースしたい場合は ここで紹介するような コードが必要です
その前にもう少しテキストの 話をしたいと思います iWork for Macの「文書のパスワードを 設定する」ダイアログです アラビア語版では すべてが逆転したことがわかります ラベルに何が起こったのか 注目してください 英語版では編集テキスト フィールドに近づけるため 右寄せにしたのです アラビア語では 左寄せになります つまりナチュラル- アライメントとは逆の トレーリングエッジ- アライメントになっています MacのSwiftUIでこの レイアウトを得るのは簡単です フォームを使いテキスト- フィールドを集めるだけです しかしこの例のように ラベルの1つが複数行である場合 これは興味深い ことになります 最後のラベルを2行に 展開するとこうなります 2つの1行ラベルは 正しく右寄せになりますが 2行ラベルは そうではありません 下のラベルが右寄せに なっていることです そのバウンディングボックスが 右寄せなだけで 個々の行のテキストは 右寄せになっていません 最後のラベルにmultiline- TextAlignmentモディファイアを 追加することで これを修正します SwiftUIのテキストアライメントは 1行以上の長さの テキストオブジェクトに のみ適用されます 単一行のテキスト- オブジェクトの場合 そのバウンディングボックスは テキスト自身を囲んで テキストを アライメントします またテキストのバウンディング- ボックスを揃えるか バウンディングボックス内の 複数行のテキストを揃えるかは ユーザーのUI方向に基づいて 意味を変えるリーディングと トレーリングを選択できる ことに注意してください UIの向きに関係なく 同じ配置にするためには 先に見たように環境 モディファイアを使って 環境のレイアウト方向を 変更します UIKitではテキストはデフォルトで 自然に整列されますが 必要に応じて絶対方向の いずれかに変更できます インターフェースビルダーでは このようなコントロールで UILabelとUITextViewの textAlignmentプロパティに 対応しています 右端の点線のボタンを押すと ナチュラル(先端) アライメントになります ラベルのアライメントは ラベルのセマンティック- コンテンツ属性に従います その他のボタンはUIの方向やラベルの セマンティックコンテンツ属性に 関係なく 左 右 または中央の 固定配置を与えます トレーリングエッジのアライメントの 設定は内蔵されていません コードを記述する必要があります AppKitでは少し違います アライメントコントロールは UIKitと基本的に 同じように動作しますが userInterfaceLayoutDirectionとの 相互作用の仕方が異なります ミラーリングを「Automatically」に設定し システムが userInterfaceLayoutDirectionを 右から左に設定した場合 すべてのアライメント設定の 意味が逆になります そのため「Automatically」に設定すると 左寄せはまさに リーディングエッジ 右寄せはまさにトレーリングエッジの 位置となります 標準的なUIウィジェットでは ユーザーの筆記方向に合わせて 自動的にレイアウトが 反転することを説明しましたが 必要に応じてそれを 防ぐことは非常に簡単です これは画面上の個々のUI ウィジェットの配置にも及びます 標準的なビューや サブビューの位置決めを行う ビューコントローラを 使用している場合 これらのビューはすべて必要に 応じて自動的にレイアウトを 反転させるため 何もする必要がありません テーブルビューと コレクションビューは 右から左への言語でも 正しくスクロールを処理します UINavigationControllerは ユーザーの筆記方向に合わせて セグエアニメーションの方向を 自動的に変更し 「Back」ボタンも それに合わせて変更されます またUIPageViewControllerは ページング方向と スワイプジェスチャーの意味を 自動的に反転させます 子ビューを配置するために スタックビューを 使用しているときを除いて 一般的にこれらのものを オーバーライドしたいと 思わないでしょう AppKit標準のビューも同様で テーブルビューとコレクションビューは 右から左への スクロールも扱えます インターフェースビルダーでは 設定できませんが ビューはすべて userInterfaceLayoutDirection プロパティを尊重しサブビューの レイアウトを決定します これはコードで記述する 必要があります SwiftUIの標準的な ビューは環境の レイアウトダイレクション- プロパティも反映します
スタックビューや グリッドビューの代わりに 自動レイアウトを 使用している場合 自動レイアウトは UIの向きを考慮して 自動的に反転させる こともできます 水平方向の制約がある場合 自動的にリーディングエッジと トレーリングエッジに接続する ことがわかりますが これまで見てきたように 「Leading」と「Trailing」は UIの方向によって異なる 意味を持ちます 必要であれば オートレイアウトの制約を左右の 絶対的な方向に 設定することも可能です これは制約の片側の 方向をクリックし ポップアップするメニューで 「Respect language direction」を オフにすることで行います これで制約の 両端の方向が「Leading」と 「Trailing」から「Left」と 「Right」に変わりますね コードでオートレイアウトの制約を 設定するには様々な方法があります その中でも一つだけ 再度紹介します UI言語の 記述方向に関係なく 同じレイアウトにしたい場合を 除き 「Left」「Right」の代わりに「Leading」 「Trailing」を使用することを 覚えておくとよいでしょう さていろいろありましたが 一息つきましょう 主なポイントは 右から左への言語を処理する 作業のほとんどを 私たちが代行し 上書きする必要がある時は 方法があるという事です 用語のスライドを もう1度見てみましょう 「Left」「Right」は 常に左と右であり その他の用語はUI全体の 方向によって意味が 逆転することを 忘れないでください
最後に もう一つ重要な問題 それは数値の 表示方法についてです 厳密には筆記方向の 問題ではないですが 多くの開発者にとってアラビア語は 英語と異なる数字文字を使う 最初のローカライズ言語でしょう その数字はこんな感じです 桁の命名規則はいろいろありますが ここでは ヨーロッパの多くの言語で 使われているものを「ラテン語桁」 アラビア語で使われているものを 「アラビア語-インド語桁」と呼びます 他の言語でも独自の 数字を持つものがあります これはヒンディー語と一緒に使われる デーヴァナーガリー文字で ヒンディー語も別の数字を使う 一般的な言語です ここで注意が必要なのは アラビア語もヒンディー語も 常にその言語の数字を使う わけではないということです アラビア語は国によって異なり サウジアラビアのように 母国語の数字を使うところと アラブ首長国連邦のように ラテン語の数字を 使うところとがあります ユーザーごとに好みの数字を 選択することも可能です ヒンディー語の場合デフォルトでは ラテン語の数字を使用しているが ユーザーがネイティブの数字を 選択することもできます
このようなUI文字列の構成が崩れる ことはご存知の通りです 文字列がハードコード されていて翻訳できない 複数形を扱うために メッセージが変化しない等です しかしこれが良くない理由は 「peopleInChat」の値が 常にラテン数字でレンダリング されてしまうからです これを解決するメソッドはAppの バンドルにある 実際の文字列を検索し stringsdictファイルが ある場合は 適切に複数形を処理します 数字も正しく扱えるのが 大きな特徴です ここでの "peopleInChat "補間の値は ユーザーのロケールや好みに合わせ 正しくローカライズされた 数字でレンダリングされます これはSwiftUIのテキスト- ビューでも正しく動作します テキストビューの イニシャライザーは文字列の補間も 適切にローカライズされた 数字でレンダリングします ユーザーが見える文字列を作成する時は 常にString(localized:)を使用します StringWithFormat:や数字を 受け取るString init関数など 数字をフォーマットできる Stringの他の多くのAPIは 常にラテン語の 数字を使用します 注意しなければならないのは このような数字を含む 静的な文字列である 何が大変なんでしょう 翻訳者に送り翻訳して もらうとこうなります これは多くの地域で 正しいのですが サウジアラビアや他の いくつかの国では異なります こちらをご覧ください テキストは3に使用される 文字以外は同じです もちろんアラビア語圏で アラビア数字を使っている地域と ラテン数字を使っている ところを分けて ローカライズすることも できますが そんな人は少ないでしょうし 無駄が多くなります さらに言えばアラビア語も ヒンディー語も ユーザーが使いたい 数字を選べるので ロケールだけでなく ユーザーの好みに合わせて ローカライズを選ぶ 必要がありますね 解決策としては アラビア語やヒンディー語の ローカライズを1つだけにして コンパイル時に値が分かっていても 実行時に数字を 代入することです Swiftではこれを文字列補間で 済ませることができます
数字と一緒に移動する 他の要素がある場合 数字との相対的な 配置も難しくなります 右から左への言語すべてに おいて同じというわけでもない アラビア語とヘブライ語では マイナス記号とパーセント記号が 数字の異なる側に あることに注意ください 実は右横書き言語である 必要はまったくないのです トルコ語は 左から右への言語にもかかわらず パーセント記号も 左側にある事に注意ください もちろんネイティブの アラビア数字を使う場合は 全く別のパーセント記号を 使うことに留意ください つまりパーセント記号や 通貨記号単位略語など 自分で付加する ようなことは 本当はやりたくないのです 代わりに 数値フォーマッタを使って パーセント記号や通貨記号など 追加してください Swiftではこれは すべての数値型にある formatted()メソッドで 簡単に行えます この例のようにより 大きな文字列の一部である場合 String(localized:) は フォーマットされた数字 あるいは他の文字列も 含めて実行時に 実行時に文字列に 代入されるものが フォーマットされた数字の記述方向と 周囲のメッセージが互いに 混乱しないように マークアップで 囲まれることも 確認しています 最後にAppをテストして右から 左へ正しい動作をしているか 確認するためのヒントを 1つ紹介します 実行ファイルにアラビア語やヘブライ語の ローカリゼーションがなくても Appを右から左へ テストできます 実際に開発言語で 右から左への 動作をテストできます そのためにXcodeの スキームエディタを起動します 次に「Options」タブで 「App Language」メニューを探します このメニューの一番下に「pseudolanguage」 オプションが多くあります これらは実際に ローカライズすることなく ローカライズの問題を チェックできるように UIを様々な方法で 変形させる偽の言語です 「Right-to-Left Pseudolanguage」 を選んで「Run」をクリックすると Appは英語または 開発言語のままですが UIはすべて右から左に 反転された状態になります 以上でおしまいです 右から左への言語の ローカライズは 筆記方向の変更に関連する問題に 注意を払う必要がありますが システムによってその ほとんどを自動化できます 通常絶対的な 方向性の周辺では この動作を オプトアウトしたい場合があり それは常に可能です またラテン語で数字を表記しない言語が あることも覚えておきましょう 以上に注意すれば 右横書き言語も 難しくないでしょう
-
-
12:55 - Control orientation example
struct ContentView: View { var body: some View { VStack(alignment: .leading) { Button(action: {}) { Label("Preview", systemImage: "arrowtriangle.forward.fill") }.labelStyle(IconOnRightLabelStyle()) HStack() { Button(action: {}) { Label("Left", systemImage: "arrow.left") }.labelStyle(TitleAndIconLabelStyle()) Button(action: {}) { Label("Right", systemImage: "arrow.right") }.labelStyle(IconOnRightLabelStyle()) }.environment(\.layoutDirection, .leftToRight) }.padding() } }
-
14:22 - Control orientation custom label style example
struct IconOnRightLabelStyle : LabelStyle { func makeBody(configuration: Configuration) -> some View { HStack { configuration.title configuration.icon } } }
-
14:43 - Control orientation example
struct ContentView: View { var body: some View { VStack(alignment: .leading) { Button(action: {}) { Label("Preview", systemImage: "arrowtriangle.forward.fill") }.labelStyle(IconOnRightLabelStyle()) HStack() { Button(action: {}) { Label("Left", systemImage: "arrow.left") }.labelStyle(TitleAndIconLabelStyle()) Button(action: {}) { Label("Right", systemImage: "arrow.right") }.labelStyle(IconOnRightLabelStyle()) }.environment(\.layoutDirection, .leftToRight) }.padding() } }
-
18:58 - Control orientation example—keeping controls from reversing
struct ContentView: View { var body: some View { VStack(alignment: .leading) { Picker(selection: $textStyle, label: Text("Text Style")) { Text("B").tag(TextStyle.bold) Text("I").tag(TextStyle.italic) Text("U").tag(TextStyle.underline) Text("S").tag(TextStyle.strikethrough) }.pickerStyle(.segmented) Picker(selection: $alignment, label: Text("Alignment")) { Image(systemName: "text.alignleft").tag(TextAlignment.left) Image(systemName: "text.aligncenter").tag(TextAlignment.center) Image(systemName: "text.alignright").tag(TextAlignment.right) }.pickerStyle(.segmented) .environment(\.layoutDirection, .leftToRight) } } }
-
22:38 - Control orientation example—form with multiline text alignment modifier
var body: some View { Form { TextField("Password:", text: $password) TextField("Verify:", text: $verifyPassword) TextField("Password Hint:\n(Recommended)", text: $passwordHint) .multilineTextAlignment(.trailing) }.padding() }
-
27:14 - Set up Auto Layout in code
myView.leadingAnchor.constraint(equalTo: mySuperView.leadingAnchor, constant:16)
-
29:05 - Digits in Arabic
myLabel.string = String(localized: "There are \(peopleInChat) people in this chat.", comment: "Label indicating number of chat participants") Text("There are \(peopleInChat) people in this chat.", comment: "Label indicating number of chat participants")
-
30:12 - Digits in Arabic
myLabel.string = String(localized: "This application supports \(3) file formats.", comment: "Label showing number of supported file formats (number is always 3)")
-
31:41 - Numbers in RTL text
myLabel.stringValue = String(localized: "\(percentComplete.formatted(.percent)) complete")
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。