mcpField
R
rtl-internationalization

rtl-internationalization

github.com/mindrallyデザイン・UI28788 回インストール3 週間前に更新
リポジトリ

rtl-internationalization について

WebやReact Nativeのインターフェースを、右から左へ書く言語に対応させるためのワークフロースキルです。方向対応レイアウト、双方向テキスト、ローカライズ、RTLテストを扱います。

主な機能

  1. 01物理方向指定スタイルの監査
  2. 02論理CSSとTailwindプロパティの利用
  3. 03実行時の文字方向設定
  4. 04双方向ユーザーテキストへの対応
  5. 05方向性アイコンやコントロールの調整
  6. 06RTLインターフェースのローカライズとテスト

活用シーン

  1. 01Web UIのRTL問題の監査
  2. 02アラビア語やヘブライ語への対応
  3. 03UI内の混在スクリプトテキストの確認
  4. 04RTLビジュアル回帰チェックの追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mindrally/skills --skill rtl-internationalization

インストール後、Claude Code で/rtl-internationalizationを入力して読み込まれたか確認します。

詳細

RTL(右から左)対応の国際化

ヘブライ語、アラビア語、ペルシア語、ウルドゥー語などの RTL 言語に対応するには、方向に依存しない CSS でレイアウトを構築し、テキストの方向を、左右のスタイルに固定の前提として組み込むのではなく、実行時に切り替え可能な第一級のプロパティとして扱う必要があります。

UI を RTL セーフにする手順

  1. 物理プロパティを監査する — コードベースで margin-left/right、padding-left/right、left/right による位置指定、text-align: left/right、および ml-*、mr-*、pl-*、pr-*、left-*、right-* のような Tailwind クラスを検索します。
  2. 論理プロパティに変換する — 各物理プロパティ/クラスを論理的な同等のもの(margin-inline-start、ms-* など)に置き換え、dir に基づいてブラウザーが自動的に反転するようにします。
  3. ルートで方向を設定する — アクティブなロケールに応じて <html> または最上位のコンテナーに dir="rtl"(または dir="auto")を設定します。コンポーネントごとにハードコードしないでください。
  4. 混在する文字体系のテキストを扱う — 周囲のテキストと方向が異なる可能性がある、ユーザー生成文字列や補間文字列を <bdi> で囲みます。
  5. アイコンと方向性のあるコンポーネントを監査する — 矢印、シェブロン、戻る/進むボタンは反転します。検索、設定、ホームなど方向性のないアイコンは反転せず、カルーセル、スライダー、プログレスバーは逆向きにします。
  6. すべての文字列を外部化する — ユーザーに表示する文字列はすべて翻訳関数を介して扱い、数値、通貨、日付には手動の書式設定ではなく Intl API を使用します。
  7. RTL でテストする — dir="rtl" と実際の RTL コンテンツ(LTR のプレースホルダーテキストを反転しただけのものではなく)を使ってアプリを表示し、すべての画面を目視で確認します。

論理 CSS プロパティ

物理プロパティではなく、常に CSS 論理プロパティを使用してください。論理プロパティは要素の direction と writing-mode に基づいて適切な物理的な側に自動的に対応するため、同じスタイルシートを重複させずに LTR と RTL の両方で使用できます。

物理プロパティ(使用しない)論理プロパティ(使用する)
margin-leftmargin-inline-start
margin-rightmargin-inline-end
padding-leftpadding-inline-start
padding-rightpadding-inline-end
leftinset-inline-start
rightinset-inline-end
border-leftborder-inline-start
border-rightborder-inline-end
text-align: lefttext-align: start
text-align: righttext-align: end
/* Before: breaks in RTL */
.card {
  margin-left: 1rem;
  padding-right: 1.5rem;
  border-left: 2px solid var(--border);
  text-align: left;
}

/* After: direction-agnostic */
.card {
  margin-inline-start: 1rem;
  padding-inline-end: 1.5rem;
  border-inline-start: 2px solid var(--border);
  text-align: start;
}

Tailwind CSS の論理クラス

方向を示す(l/r)ユーティリティではなく、Tailwind の論理ユーティリティを使用します。

  • ml-4 ではなく ms-4(margin-inline-start)
  • mr-4 ではなく me-4(margin-inline-end)
  • pl-4 ではなく ps-4(padding-inline-start)
  • pr-4 ではなく pe-4(padding-inline-end)
  • left-0 ではなく start-0(inset-inline-start)
  • right-0 ではなく end-0(inset-inline-end)
  • text-left ではなく text-start
  • text-right ではなく text-end

<div class="ml-4 pr-6 text-left">...</div>


<div class="ms-4 pe-6 text-start">...</div>

React Native の論理プロパティ

React Native の Yoga レイアウトエンジンも論理プロパティをサポートしています。Left/Right のバリアントではなく、論理プロパティを使用します。

  • paddingLeft/paddingRight ではなく paddingStart/paddingEnd
  • marginLeft/marginRight ではなく marginStart/marginEnd
  • borderLeftWidth/borderRightWidth ではなく borderStartWidth/borderEndWidth
  • 絶対位置指定では left/right ではなく start/end
const styles = StyleSheet.create({
  row: {
    flexDirection: 'row',
    paddingStart: 16,
    paddingEnd: 16,
  },
  badge: {
    position: 'absolute',
    end: 8, // flips automatically with I18nManager.isRTL
    top: 8,
  },
})

双方向テキストの安全性

ユーザー名、製品コード、ファイルパス、または翻訳文に補間されるユーザー生成コンテンツなど、方向が周囲のコンテキストと異なる可能性のあるテキストは <bdi> で囲み、ブラウザーの双方向アルゴリズムが正しく分離できるようにします。

<p>User <bdi>{userName}</bdi> posted a comment</p>
<p>Order number: <bdi>{orderCode}</bdi> has shipped</p>

<bdi> を使わないと、アラビア語の文に埋め込まれたラテン文字のユーザー名(またはその逆)によって、周囲の句読点や隣接する単語の表示順序が入れ替わることがあります。

方向を示すアイコンとコンポーネント

  • RTL モードでは、矢印、山かっこ、戻る/進む/次へ/前へボタン、メールやチャットの UI にある「返信」アイコンなど、方向を示すアイコンを反転します。
  • ホーム、設定、検索、印刷、ゴミ箱、チェックマーク、実物を表すアイコン(時計の文字盤や電話など)といった、方向を示さないアイコンは反転しないでください。
  • RTL では、カルーセル、スライダー、進行状況バーの方向を反転し、「次へ」が引き続き読字方向に対応するようにします。
  • RTL では、スワイプジェスチャーの方向を反転します(例:スワイプして閉じるカードは、常に左ではなく末尾側へスワイプするようにします)。
  • 方向軸を持つグラフや図(左から右へ進むタイムラインなど)は反転し、時間の流れが引き続き読字方向に沿うようにします。
/* Mirror an icon only when the document is RTL */
[dir="rtl"] .icon-chevron-forward {
  transform: scaleX(-1);
}
// React: pick the mirrored icon variant based on direction
function BackButton({ dir }: { dir: 'ltr' | 'rtl' }) {
  const Icon = dir === 'rtl' ? ChevronRightIcon : ChevronLeftIcon
  return (
    <button aria-label="Back">
      <Icon aria-hidden="true" />
    </button>
  )
}

国際化の基本

  • ユーザーに表示する文字列をハードコードしないでください。すべての文字列を翻訳関数(t()、intl.formatMessage() など)経由で処理し、ローカライズできるようにするとともに、RTL ロケールで句読点や語順が正しく表示されるようにします。
  • 数値や通貨の手動での文字列整形には、Intl.NumberFormat を使ってください。ロケールによって数字の表示形式や桁区切り記号は異なります。
  • 日付や時刻の手動での連結には、Intl.DateTimeFormat を使ってください。
  • ユーザー生成コンテンツのフィールド(コメント、チャットメッセージ)には dir="auto" を設定し、ブラウザーがコンテンツから方向を判定できるようにします。また、アクティブなロケールに応じて、ドキュメントのルートに明示的な dir="rtl" または dir="ltr" を設定します。
const currency = new Intl.NumberFormat('ar-EG', {
  style: 'currency',
  currency: 'EGP',
}).format(1234.5)
// "١٬٢٣٤٫٥٠ ج.م.‏"

document.documentElement.dir = locale.startsWith('ar') || locale.startsWith('he') ? 'rtl' : 'ltr'
document.documentElement.lang = locale

テスト

  • LTR レイアウトのスクリーンショットを反転するだけでなく、ルート要素に dir="rtl" を適用して必ずテストしてください。
  • 反転した LTR のプレースホルダーテキストではなく、実際の RTL コンテンツ(通常は英語の同等表現より短い、または長いアラビア語やヘブライ語の文字列)を使って検証してください。文字列の長さの違いによって、反転だけでは見つからない切り詰めやはみ出しの不具合が明らかになります。
  • LTR 版と合わせて、主要な画面(ナビゲーション、フォーム、データテーブル、モーダル)の RTL スナップショットやビジュアルリグレッションテストを用意してください。
  • 一部のフレームワークでは DOM 順序や Tab 順序が自動的に反転されないため、RTL でフォーカス順序やキーボード操作(Tab 順序)が視覚的な読字方向に沿っていることを確認してください。
  • サードパーティ製コンポーネント(日付ピッカー、グラフ、リッチテキストエディター)が dir に対応していることを確認してください。多くの一般的なライブラリはデフォルトで LTR のみに対応しており、明示的な RTL モードや CSS の上書きが必要です。

よくある間違い

  • 物理的な CSS/Tailwind プロパティ(ml-*、left、text-align: left)を使い、ロケールが RTL に切り替わると気づかないうちに表示が崩れること。
  • 反転すべきでないアイコン(時計や「再生」三角形など)を反転し、RTL を母語とするユーザーに視覚的な違和感を与えること。
  • ICU メッセージフォーマットを使わず、翻訳済み文字列にハードコードした句読点や語順(例:name + ": " + value)を連結し、RTL ロケールで語順を崩すこと。
  • dir="rtl" だけですべて解決すると考えること。インラインスタイル、キャンバスに描画する UI、left/right を使う絶対配置の要素は、引き続き論理プロパティへ手動で変換する必要があります。

コメント