国際化アーキテクチャの設計
xyflowにおける多言語対応は、動的テキストマッピングシステムによる3層構造で実現します:
- 静的コンテンツ層:ノード表示テキストやボタンラベル
- インタラクティブメッセージ層:ドラッグ操作時のヒントや接続状態通知
- システム通知層:エラーメッセージや操作ガイドのグローバル表示
既存コードへの侵入を最小限にしつつ、型システム拡張と専用フックを活用した実装手法を解説します。
型定義の拡張
nodes.tsでノードデータに多言語対応を追加します:
interface Node<Data = Record<string, unknown>> {
id: string;
position: { x: number; y: number };
data: Data & {
langData?: {
displayText?: { [locale: string]: string };
tooltipText?: { [locale: string]: string };
};
};
// 既存プロパティ保持
}言語処理フック
useTranslatedData.tsで言語依存データを処理します:
import { useNodeList } from './useNodeList';
import { useActiveLanguage } from './useActiveLanguage';
export function useTranslatedNodes() {
const nodes = useNodeList();
const { activeLang } = useActiveLanguage();
return nodes.map(node => ({
...node,
data: {
...node.data,
displayText: node.data.langData?.displayText?.[activeLang] ?? node.data.displayText,
tooltipText: node.data.langData?.tooltipText?.[activeLang] ?? node.data.tooltipText
}
}));
}利用例:
function FlowContainer() {
const processedNodes = useTranslatedNodes();
return (
<ReactFlow nodes={processedNodes}>
<!-- フローデータ処理 -->
</ReactFlow>
);
}言語コンテキスト管理
LanguageContext.tsxでグローバル言語状態を管理します:
import { createContext, useContext, useState } from 'react';
const LanguageState = createContext<{
activeLang: string;
changeLanguage: (lang: string) => void;
}>({ activeLang: 'en', changeLanguage: () => {} });
export function LanguageProvider({ children }) {
const [activeLang, changeLanguage] = useState('en');
return (
<LanguageState.Provider value={{ activeLang, changeLanguage }}>
{children}
</LanguageState.Provider>
);
}
export const useLanguageContext = () => useContext(LanguageState);ノードコンポーネントの実装
DefaultNode.tsxで言語依存表示を処理します:
import { useLanguageContext } from '../contexts/LanguageContext';
export default function NodeComponent({ data }) {
const { activeLang } = useLanguageContext();
const displayText = data.langData?.displayText?.[activeLang] ?? data.displayText;
return (
<div className="flow-node">
<span className="node-title">{displayText}</span>
<!-- その他のUI要素 -->
</div>
);
}実際の使用シナリオ
Reactプロジェクトでの実装例:
const initialNodes = [
{
id: 'start',
position: { x: 100, y: 50 },
data: {
langData: {
displayText: {
'en': 'Start',
'zh': '开始',
'ja': '開始'
}
}
}
}
];
function App() {
return (
<LanguageProvider>
<ReactFlow nodes={initialNodes} edges={connectionList} />
<LanguageSelector />
</LanguageProvider>
);
}Svelte実装のポイント
Svelte版ではtypes/nodes.tsで同様の型定義を行い、storeを活用した言語状態管理を実装します。コンポーネント内では$store構文で言語状態を参照します。
パフォーマンス最適化戦略
- オブジェクトのシャローコンパリソンで不要な再描画を防止
- 大規模フローの言語切替時にデバウンス処理を適用
- 言語パッケージを分割して非同期ロード