とりあえず省略記法に対応

This commit is contained in:
tai-cha 2025-03-02 09:53:53 +00:00
parent 8753c3cc37
commit ca80f4e273
6 changed files with 674 additions and 200 deletions

View File

@ -171,7 +171,7 @@ function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisR
return resolveChildrenReferences(marker); return resolveChildrenReferences(marker);
}); });
// 特殊なプロパティ変換用の関数 // 特殊なプロパティ変換用の関数 - i18n参照処理を強化
function formatSpecialProperty(key: string, value: any): string { function formatSpecialProperty(key: string, value: any): string {
// 値がundefinedの場合は空文字列を返す // 値がundefinedの場合は空文字列を返す
if (value === undefined) { if (value === undefined) {
@ -183,55 +183,82 @@ function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisR
return customStringify(value); return customStringify(value);
} }
// 文字列でない場合はJSON5で文字列化 // keywordsが配列の場合、特別に処理
if (typeof value !== 'string') { if (key === 'keywords' && Array.isArray(value)) {
return JSON5.stringify(value); return `[${formatArrayForOutput(value)}]`;
} }
// i18n.ts 参照を含む場合 // 文字列値の場合の特別処理
if (value.includes('i18n.ts.')) { if (typeof value === 'string') {
return value; // クォートなしで直接返す // i18n.ts 参照を含む場合 - クォートなしでそのまま出力
} if (value.includes('i18n.ts.')) {
logger.info(`Preserving i18n reference in output: ${value}`);
return value;
}
// keywords が配列リテラルの形式の場合 // keywords が配列リテラルの形式の場合
if (key === 'keywords' && value.startsWith('[') && value.endsWith(']')) { if (key === 'keywords' && value.startsWith('[') && value.endsWith(']')) {
return value; // クォートなしで直接返す return value;
}
} }
// 上記以外は通常の JSON5 文字列として返す // 上記以外は通常の JSON5 文字列として返す
return JSON5.stringify(value); return JSON5.stringify(value);
} }
// オブジェクトをカスタム形式に変換する関数 // オブジェクトをカスタム形式に変換する関数 - i18n参照処理を強化
function customStringify(obj: any, depth = 0): string { function customStringify(obj: any, depth = 0): string {
const INDENT_STR = '\t'; const INDENT_STR = '\t';
// 配列の処理
if (Array.isArray(obj)) { if (Array.isArray(obj)) {
if (obj.length === 0) return '[]'; if (obj.length === 0) return '[]';
const indent = INDENT_STR.repeat(depth); const indent = INDENT_STR.repeat(depth);
const childIndent = INDENT_STR.repeat(depth + 1); const childIndent = INDENT_STR.repeat(depth + 1);
const items = obj.map(item => `${childIndent}${customStringify(item, depth + 1)}`).join(',\n');
// 配列要素の処理
const items = obj.map(item => {
// オブジェクト要素
if (typeof item === 'object' && item !== null) {
return `${childIndent}${customStringify(item, depth + 1)}`;
}
// i18n参照を含む文字列要素
if (typeof item === 'string' && item.includes('i18n.ts.')) {
return `${childIndent}${item}`; // クォートなしでそのまま出力
}
// その他の要素
return `${childIndent}${JSON5.stringify(item)}`;
}).join(',\n');
return `[\n${items},\n${indent}]`; return `[\n${items},\n${indent}]`;
} }
// null または非オブジェクト
if (obj === null || typeof obj !== 'object') { if (obj === null || typeof obj !== 'object') {
return JSON5.stringify(obj); return JSON5.stringify(obj);
} }
// オブジェクトの処理
const indent = INDENT_STR.repeat(depth); const indent = INDENT_STR.repeat(depth);
const childIndent = INDENT_STR.repeat(depth + 1); const childIndent = INDENT_STR.repeat(depth + 1);
const entries = Object.entries(obj) const entries = Object.entries(obj)
// 不要なプロパティを除去
.filter(([key, value]) => { .filter(([key, value]) => {
// valueがundefinedの場合は出力しない
if (value === undefined) return false; if (value === undefined) return false;
// childrenが空配列の場合は出力しない
if (key === 'children' && Array.isArray(value) && value.length === 0) return false; if (key === 'children' && Array.isArray(value) && value.length === 0) return false;
return true; return true;
}) })
// 各プロパティを変換
.map(([key, value]) => { .map(([key, value]) => {
// childrenが配列の場合で要素がある場合のみ特別処理 // 子要素配列の特殊処理
if (key === 'children' && Array.isArray(value) && value.length > 0) { if (key === 'children' && Array.isArray(value) && value.length > 0) {
return `${childIndent}${key}: ${customStringify(value, depth + 1)}`; return `${childIndent}${key}: ${customStringify(value, depth + 1)}`;
} }
// ラベルやその他プロパティを処理
return `${childIndent}${key}: ${formatSpecialProperty(key, value)}`; return `${childIndent}${key}: ${formatSpecialProperty(key, value)}`;
}); });
@ -239,6 +266,20 @@ function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisR
return `{\n${entries.join(',\n')},\n${indent}}`; return `{\n${entries.join(',\n')},\n${indent}}`;
} }
// 配列式の文字列表現を修正 - i18n参照を適切に処理
function formatArrayForOutput(items: any[]): string {
return items.map(item => {
// i18n.ts. 参照の文字列はそのままJavaScript式として出力
if (typeof item === 'string' && item.includes('i18n.ts.')) {
logger.info(`Preserving i18n reference in array: ${item}`);
return item; // クォートなしでそのまま
}
// その他の値はJSON5形式で文字列化
return JSON5.stringify(item);
}).join(', ');
}
// 最終出力用のデバッグ情報を生成 // 最終出力用のデバッグ情報を生成
let totalMarkers = resolvedRootMarkers.length; let totalMarkers = resolvedRootMarkers.length;
let totalChildren = 0; let totalChildren = 0;
@ -266,8 +307,6 @@ function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisR
// This file was automatically generated by create-search-index. // This file was automatically generated by create-search-index.
// Do not edit this file. // Do not edit this file.
/* eslint-disable @stylistic/comma-spacing */
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
export type SearchIndexItem = { export type SearchIndexItem = {
@ -282,8 +321,6 @@ export type SearchIndexItem = {
export const searchIndexes:SearchIndexItem[] = ${customStringify(resolvedRootMarkers)} as const; export const searchIndexes:SearchIndexItem[] = ${customStringify(resolvedRootMarkers)} as const;
export type SearchIndex = typeof searchIndexes; export type SearchIndex = typeof searchIndexes;
/* eslint-enable @stylistic/comma-spacing */
`; `;
try { try {
@ -294,95 +331,350 @@ export type SearchIndex = typeof searchIndexes;
} }
} }
// 要素ノードからテキスト内容を抽出する関数 (Mustache構文のi18n参照にも対応)
function extractElementText(node: any): string | null {
if (!node) return null;
console.log(`Extracting text from node type=${node.type}, tag=${node.tag || 'unknown'}`);
// Mustache構文を検出するための正規表現パターン
const mustachePattern = /^\s*{{\s*(.*?)\s*}}\s*$/;
// childrenが配列でない場合、content直接チェック (インラインテキスト対応)
if (node.content) {
const content = node.content.trim();
console.log(`Direct node content found: ${content}`);
// Mustache構文のチェック
const mustacheMatch = content.match(mustachePattern);
if (mustacheMatch && mustacheMatch[1] && mustacheMatch[1].includes('i18n.ts.')) {
const extractedContent = mustacheMatch[1].trim();
console.log(`Extracted i18n reference from mustache: ${extractedContent}`);
return extractedContent;
}
// 直接i18n参照を含む場合
if (content.includes('i18n.ts.')) {
console.log(`Direct i18n reference found: ${content}`);
return content;
}
// その他のコンテンツ
if (content) {
return content;
}
}
// childrenがない場合は終了
if (!node.children || !Array.isArray(node.children)) {
return null;
}
// Mustacheテンプレート構文の特殊ード検出 (type=5はインターポレーション)
for (const child of node.children) {
if (child.type === 5) { // インターポレーションノード (Mustache表現)
console.log(`Found interpolation node (Mustache): `, child);
if (child.content && child.content.type === 4 && child.content.content) {
const content = child.content.content.trim();
console.log(`Interpolation content: ${content}`);
if (content.includes('i18n.ts.')) {
return content;
}
} else if (child.content && typeof child.content === 'object') {
// オブジェクト形式のcontentを再帰的に探索
console.log(`Complex interpolation node:`, JSON.stringify(child.content).substring(0, 100));
if (child.content.content) {
const content = child.content.content.trim();
if (content.includes('i18n.ts.')) {
console.log(`Found i18n reference in complex interpolation: ${content}`);
return content;
}
}
}
}
}
// 最初のパスで i18n.ts. 参照パターンを持つものを探す (最優先)
for (const child of node.children) {
if (child.type === 2 && child.content) { // 式ノード
const expr = child.content.trim();
if (expr.includes('i18n.ts.')) {
console.log(`Found i18n reference in expression node: ${expr}`);
return expr; // i18n参照を見つけたら即座に返す
}
}
}
// 2回目のパスで一般的な式を探す
for (const child of node.children) {
if (child.type === 2 && child.content) { // その他の式ノード
const expr = child.content.trim();
console.log(`Found expression: ${expr}`);
return expr;
}
}
// 3回目のパスでテキストードを探す
for (const child of node.children) {
if (child.type === 3 && child.content) { // テキストノード
const text = child.content.trim();
if (text) {
console.log(`Found text node: ${text}`);
// Mustache構文のチェック
const mustacheMatch = text.match(mustachePattern);
if (mustacheMatch && mustacheMatch[1] && mustacheMatch[1].includes('i18n.ts.')) {
console.log(`Extracted i18n ref from text mustache: ${mustacheMatch[1]}`);
return mustacheMatch[1].trim();
}
return text;
}
}
}
// 深さ優先で再帰的に探索 (子の子まで調べる)
for (const child of node.children) {
if (child.children && Array.isArray(child.children) && child.children.length > 0) {
const nestedContent = extractElementText(child);
if (nestedContent) {
console.log(`Found nested content: ${nestedContent}`);
return nestedContent;
}
} else if (child.type === 1) { // 子要素ノード - childrenがなくても内部を調査
const nestedContent = extractElementText(child);
if (nestedContent) {
console.log(`Found content in childless element: ${nestedContent}`);
return nestedContent;
}
}
}
return null;
}
// SearchLabelとSearchKeywordを探して抽出する関数 (スコープを適切に分離)
function extractLabelsAndKeywords(nodes: any[]): { label: string | null, keywords: any[] } {
let label: string | null = null;
const keywords: any[] = [];
console.log(`Extracting labels and keywords from ${nodes.length} nodes`);
// 再帰的にSearchLabelとSearchKeywordを探索ネストされたSearchMarkerは処理しない
function findComponents(nodes: any[]) {
for (const node of nodes) {
if (node.type === 1) { // Element node
console.log(`Checking element: ${node.tag}`);
// SearchMarkerの場合は、その子要素は別スコープなのでスキップ
if (node.tag === 'SearchMarker') {
console.log(`Found nested SearchMarker - skipping its content to maintain scope isolation`);
continue; // このSearchMarkerの中身は処理しない (スコープ分離)
}
// SearchLabelの処理
if (node.tag === 'SearchLabel') {
console.log(`Found SearchLabel node, structure:`, JSON.stringify(node).substring(0, 200) + '...');
// まず完全なノード内容の抽出を試みる
const content = extractElementText(node);
if (content) {
label = content;
console.log(`SearchLabel content extracted: ${content}`);
} else {
console.log(`SearchLabel found but extraction failed, trying direct children inspection`);
// バックアップ: 子直接確認 - type=5のMustacheインターポレーションを重点的に確認
if (node.children && Array.isArray(node.children)) {
for (const child of node.children) {
// Mustacheインターポレーション
if (child.type === 5 && child.content) {
// content内の式を取り出す
const expression = child.content.content ||
(child.content.type === 4 ? child.content.content : null) ||
JSON.stringify(child.content);
console.log(`Interpolation expression: ${expression}`);
if (typeof expression === 'string' && expression.includes('i18n.ts.')) {
label = expression.trim();
console.log(`Found i18n in interpolation: ${label}`);
break;
}
}
// 式ノード
else if (child.type === 2 && child.content && child.content.includes('i18n.ts.')) {
label = child.content.trim();
console.log(`Found i18n in expression: ${label}`);
break;
}
// テキストードでもMustache構文を探す
else if (child.type === 3 && child.content) {
const mustacheMatch = child.content.trim().match(/^\s*{{\s*(.*?)\s*}}\s*$/);
if (mustacheMatch && mustacheMatch[1] && mustacheMatch[1].includes('i18n.ts.')) {
label = mustacheMatch[1].trim();
console.log(`Found i18n in text mustache: ${label}`);
break;
}
}
}
}
}
}
// SearchKeywordの処理
else if (node.tag === 'SearchKeyword') {
console.log(`Found SearchKeyword node`);
// まず完全なノード内容の抽出を試みる
const content = extractElementText(node);
if (content) {
keywords.push(content);
console.log(`SearchKeyword content extracted: ${content}`);
} else {
console.log(`SearchKeyword found but extraction failed, trying direct children inspection`);
// バックアップ: 子直接確認 - type=5のMustacheインターポレーションを重点的に確認
if (node.children && Array.isArray(node.children)) {
for (const child of node.children) {
// Mustacheインターポレーション
if (child.type === 5 && child.content) {
// content内の式を取り出す
const expression = child.content.content ||
(child.content.type === 4 ? child.content.content : null) ||
JSON.stringify(child.content);
console.log(`Keyword interpolation: ${expression}`);
if (typeof expression === 'string' && expression.includes('i18n.ts.')) {
const keyword = expression.trim();
keywords.push(keyword);
console.log(`Found i18n keyword in interpolation: ${keyword}`);
break;
}
}
// 式ノード
else if (child.type === 2 && child.content && child.content.includes('i18n.ts.')) {
const keyword = child.content.trim();
keywords.push(keyword);
console.log(`Found i18n keyword in expression: ${keyword}`);
break;
}
// テキストードでもMustache構文を探す
else if (child.type === 3 && child.content) {
const mustacheMatch = child.content.trim().match(/^\s*{{\s*(.*?)\s*}}\s*$/);
if (mustacheMatch && mustacheMatch[1] && mustacheMatch[1].includes('i18n.ts.')) {
const keyword = mustacheMatch[1].trim();
keywords.push(keyword);
console.log(`Found i18n keyword in text mustache: ${keyword}`);
break;
}
}
}
}
}
}
// 子要素を再帰的に調査ただしSearchMarkerは除外
if (node.children && Array.isArray(node.children)) {
findComponents(node.children);
}
}
}
}
findComponents(nodes);
// デバッグ情報
console.log(`Extraction completed: label=${label}, keywords=[${keywords.join(', ')}]`);
return { label, keywords };
}
function extractUsageInfoFromTemplateAst( function extractUsageInfoFromTemplateAst(
templateAst: any, templateAst: any,
code: string, code: string,
): SearchIndexItem[] { ): SearchIndexItem[] {
// すべてのマーカー情報を保持するために、結果をトップレベルマーカー+すべての子マーカーを含む配列に変更
const allMarkers: SearchIndexItem[] = []; const allMarkers: SearchIndexItem[] = [];
// マーカーIDからオブジェクトへのマップ
const markerMap = new Map<string, SearchIndexItem>(); const markerMap = new Map<string, SearchIndexItem>();
// 子マーカーIDを集約するためのセット
const childrenIds = new Set<string>(); const childrenIds = new Set<string>();
if (!templateAst) { if (!templateAst) return allMarkers;
return allMarkers;
}
// デバッグ情報
logger.info('Started extracting markers from AST');
// マーカーの基本情報を収集 // マーカーの基本情報を収集
function collectMarkers(node: any, parentId: string | null = null) { function collectMarkers(node: any, parentId: string | null = null) {
// SearchMarkerコンポーネントの検出
if (node.type === 1 && node.tag === 'SearchMarker') { if (node.type === 1 && node.tag === 'SearchMarker') {
// マーカーID生成 (markerId属性またはDOM内に記録されているものを使用) // マーカーID取得
const markerIdProp = node.props?.find((p: any) => p.name === 'markerId'); const markerIdProp = node.props?.find((p: any) => p.name === 'markerId');
const markerId = markerIdProp?.value?.content || const markerId = markerIdProp?.value?.content ||
node.__markerId || node.__markerId ||
`marker-${Math.random().toString(36).substring(2, 10)}`; `marker-${Math.random().toString(36).substring(2, 10)}`;
logger.info(`Found SearchMarker with ID: ${markerId}`);
// マーカー基本情報 // マーカー基本情報
const markerInfo: SearchIndexItem = { const markerInfo: SearchIndexItem = {
id: markerId, id: markerId,
children: [], children: [],
label: '', label: '', // デフォルト値
keywords: [], keywords: [],
}; };
// 静的プロパティを抽出 // 静的プロパティを取得
if (node.props && Array.isArray(node.props)) { if (node.props && Array.isArray(node.props)) {
node.props.forEach((prop: any) => { for (const prop of node.props) {
if (prop.type === 6 && prop.name && prop.name !== 'markerId') { if (prop.type === 6 && prop.name && prop.name !== 'markerId') {
// 静的プロパティの抽出
if (prop.name === 'path') markerInfo.path = prop.value?.content || ''; if (prop.name === 'path') markerInfo.path = prop.value?.content || '';
else if (prop.name === 'icon') markerInfo.icon = prop.value?.content || ''; else if (prop.name === 'icon') markerInfo.icon = prop.value?.content || '';
else if (prop.name === 'label') markerInfo.label = prop.value?.content || ''; else if (prop.name === 'label') markerInfo.label = prop.value?.content || '';
logger.info(`Static prop ${prop.name}:`, prop.value?.content);
} }
}); }
} }
// バインドプロパティを抽出 // バインドプロパティを取得
if (node.props && Array.isArray(node.props)) { const bindings = extractNodeBindings(node);
node.props.forEach((prop: any) => { if (bindings.path) markerInfo.path = bindings.path;
if (prop.type === 7 && prop.name === 'bind' && prop.arg?.content) { if (bindings.icon) markerInfo.icon = bindings.icon;
const propName = prop.arg.content; if (bindings.label) markerInfo.label = bindings.label;
const propValue = prop.exp?.content || ''; if (bindings.children) markerInfo.children = bindings.children;
if (bindings.keywords) {
if (Array.isArray(bindings.keywords)) {
markerInfo.keywords = bindings.keywords;
} else {
markerInfo.keywords = bindings.keywords || [];
}
}
logger.info(`Bind prop ${propName}:`, propValue); // SearchLabelとSearchKeywordを抽出 (AST全体を探索)
if (node.children && Array.isArray(node.children)) {
console.log(`Processing marker ${markerId} for labels and keywords`);
const extracted = extractLabelsAndKeywords(node.children);
if (propName === 'label') { // SearchLabelからのラベル取得は最優先で適用
markerInfo.label = propValue; if (extracted.label) {
} else if (propName === 'path') { markerInfo.label = extracted.label;
markerInfo.path = propValue; console.log(`Using extracted label for ${markerId}: ${extracted.label}`);
} else if (propName === 'icon') { } else if (markerInfo.label) {
markerInfo.icon = propValue; console.log(`Using existing label for ${markerId}: ${markerInfo.label}`);
} else if (propName === 'keywords') { } else {
markerInfo.keywords = propValue || '[]'; markerInfo.label = 'Unnamed marker';
} else if (propName === 'children') { console.log(`No label found for ${markerId}, using default`);
markerInfo.children = propValue || '[]'; }
}
// SearchKeywordからのキーワード取得を追加
if (extracted.keywords.length > 0) {
const existingKeywords = Array.isArray(markerInfo.keywords) ?
[...markerInfo.keywords] :
(markerInfo.keywords ? [markerInfo.keywords] : []);
// i18n参照のキーワードは最優先で追加
const combinedKeywords = [...existingKeywords];
for (const kw of extracted.keywords) {
combinedKeywords.push(kw);
console.log(`Added extracted keyword to ${markerId}: ${kw}`);
} }
});
markerInfo.keywords = combinedKeywords;
}
} }
// ラベルがない場合はデフォルト値を設定 // マーカーを登録
if (!markerInfo.label) {
markerInfo.label = 'Unnamed marker';
}
// キーワードがない場合はデフォルト値を設定
if (!markerInfo.keywords || (Array.isArray(markerInfo.keywords) && markerInfo.keywords.length === 0)) {
markerInfo.keywords = '[]';
}
// マーカーをマップに保存し、すべてのマーカーリストにも追加
markerMap.set(markerId, markerInfo); markerMap.set(markerId, markerInfo);
allMarkers.push(markerInfo); // すべてのマーカーを保持 allMarkers.push(markerInfo);
// 親子関係を記録 // 親子関係を記録
if (parentId) { if (parentId) {
@ -395,11 +687,10 @@ function extractUsageInfoFromTemplateAst(
parent.children = [markerId]; parent.children = [markerId];
} }
childrenIds.add(markerId); childrenIds.add(markerId);
logger.info(`Added ${markerId} as child of ${parentId}`);
} }
} }
// 子ノードを処理(親は現在のノード) // 子ノードを処理
if (node.children && Array.isArray(node.children)) { if (node.children && Array.isArray(node.children)) {
node.children.forEach((child: any) => { node.children.forEach((child: any) => {
collectMarkers(child, markerId); collectMarkers(child, markerId);
@ -409,7 +700,7 @@ function extractUsageInfoFromTemplateAst(
return markerId; return markerId;
} }
// SearchMarkerでない場合は、子ノードを同じ親コンテキストで処理 // 子ノードを処理
if (node.children && Array.isArray(node.children)) { if (node.children && Array.isArray(node.children)) {
node.children.forEach((child: any) => { node.children.forEach((child: any) => {
collectMarkers(child, parentId); collectMarkers(child, parentId);
@ -419,16 +710,169 @@ function extractUsageInfoFromTemplateAst(
return null; return null;
} }
// AST解析開始 // AST解析開始
collectMarkers(templateAst); collectMarkers(templateAst);
// デバッグ情報
logger.info(`Found ${markerMap.size} markers, ${childrenIds.size} children`);
// 重要: すべてのマーカー情報を返す
return allMarkers; return allMarkers;
} }
// バインドプロパティの処理を修正する関数
function extractNodeBindings(node: any): Record<string, any> {
const bindings: Record<string, any> = {};
if (!node.props || !Array.isArray(node.props)) return bindings;
// バインド式を収集
for (const prop of node.props) {
if (prop.type === 7 && prop.name === 'bind' && prop.arg?.content) {
const propName = prop.arg.content;
const propContent = prop.exp?.content || '';
logger.info(`Processing bind prop ${propName}: ${propContent}`);
// keywordsの特殊処理
if (propName === 'keywords') {
try {
const content = propContent.trim();
// 配列式の場合
if (content.startsWith('[') && content.endsWith(']')) {
// i18n参照や特殊な式を保持するため、各要素を個別に解析
const elements = parseArrayExpression(content);
if (elements.length > 0) {
bindings.keywords = elements;
logger.info(`Parsed keywords array: ${JSON5.stringify(elements)}`);
} else {
bindings.keywords = [];
logger.info('Empty keywords array');
}
}
// その他の式(非配列)
else if (content) {
bindings.keywords = content; // 式をそのまま保持
logger.info(`Keeping keywords as expression: ${content}`);
} else {
bindings.keywords = [];
logger.info('No keywords provided');
}
} catch (e) {
logger.error(`Failed to parse keywords binding: ${propContent}`, e);
// エラーが起きても何らかの値を設定
bindings.keywords = propContent || [];
}
}
// その他のプロパティ
else if (propName === 'label') {
// ラベルの場合も式として保持
bindings[propName] = propContent;
logger.info(`Set label from bind expression: ${propContent}`);
}
else {
bindings[propName] = propContent;
}
}
}
return bindings;
}
// 配列式をパースする補助関数(文字列リテラル処理を改善)
function parseArrayExpression(expr: string): any[] {
try {
// 単純なケースはJSON5でパースを試みる
return JSON5.parse(expr.replace(/'/g, '"'));
} catch (e) {
// 複雑なケースi18n.ts.xxx などの式を含む場合)は手動パース
logger.info(`Complex array expression, trying manual parsing: ${expr}`);
// "["と"]"を取り除く
const content = expr.substring(1, expr.length - 1).trim();
if (!content) return [];
const result: any[] = [];
let currentItem = '';
let depth = 0;
let inString = false;
let stringChar = '';
// カンマで区切る(ただし文字列内や入れ子の配列内のカンマは無視)
for (let i = 0; i < content.length; i++) {
const char = content[i];
if (inString) {
if (char === stringChar && content[i - 1] !== '\\') {
inString = false;
}
currentItem += char;
} else if (char === '"' || char === "'") {
inString = true;
stringChar = char;
currentItem += char;
} else if (char === '[') {
depth++;
currentItem += char;
} else if (char === ']') {
depth--;
currentItem += char;
} else if (char === ',' && depth === 0) {
// 項目の区切りを検出
const trimmed = currentItem.trim();
// 純粋な文字列リテラルの場合、実際の値に変換
if ((trimmed.startsWith("'") && trimmed.endsWith("'")) ||
(trimmed.startsWith('"') && trimmed.endsWith('"'))) {
try {
result.push(JSON5.parse(trimmed));
} catch (err) {
result.push(trimmed);
}
} else {
// それ以外の式はそのままi18n.ts.xxx など)
result.push(trimmed);
}
currentItem = '';
} else {
currentItem += char;
}
}
// 最後の項目を処理
if (currentItem.trim()) {
const trimmed = currentItem.trim();
// 純粋な文字列リテラルの場合、実際の値に変換
if ((trimmed.startsWith("'") && trimmed.endsWith("'")) ||
(trimmed.startsWith('"') && trimmed.endsWith('"'))) {
try {
result.push(JSON5.parse(trimmed));
} catch (err) {
result.push(trimmed);
}
} else {
// それ以外の式はそのままi18n.ts.xxx など)
result.push(trimmed);
}
}
logger.info(`Parsed complex array expression: ${expr} -> ${JSON.stringify(result)}`);
return result;
}
}
// 配列式の文字列表現を修正 - i18n参照を適切に処理
function formatArrayForOutput(items: any[]): string {
return items.map(item => {
// i18n.ts. 参照の文字列はそのままJavaScript式として出力
if (typeof item === 'string' && item.includes('i18n.ts.')) {
logger.info(`Preserving i18n reference in array: ${item}`);
return item; // クォートなしでそのまま
}
// その他の値はJSON5形式で文字列化
return JSON5.stringify(item);
}).join(', ');
}
export async function analyzeVueProps(options: { export async function analyzeVueProps(options: {
targetFilePaths: string[], targetFilePaths: string[],
exportFilePath: string, exportFilePath: string,
@ -466,7 +910,7 @@ export async function analyzeVueProps(options: {
}); });
if (errors.length) { if (errors.length) {
logger.error(`Compile Error: ${filePath}`, errors); logger.error(`Compile Error: ${filePath}, ${errors}`);
continue; // エラーが発生したファイルはスキップ continue; // エラーが発生したファイルはスキップ
} }
@ -578,7 +1022,7 @@ async function processVueFile(
s.appendRight(endOfStartTag, ` markerId="${generatedMarkerId}"`); s.appendRight(endOfStartTag, ` markerId="${generatedMarkerId}"`);
logger.info(`Adding markerId="${generatedMarkerId}" to ${id}:${lineNumber}`); logger.info(`Adding markerId="${generatedMarkerId}" to ${id}:${lineNumber}`);
} else { } else {
logger.warn(`markerId already exists in ${id}:${lineNumber}`); logger.info(`markerId already exists in ${id}:${lineNumber}`);
} }
} }
} }

View File

@ -0,0 +1,14 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<slot></slot>
</template>
<script lang="ts" setup>
</script>
<style lang="scss" module>
</style>

View File

@ -0,0 +1,14 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<slot></slot>
</template>
<script lang="ts" setup>
</script>
<style lang="scss" module>
</style>

View File

@ -25,6 +25,9 @@ import MkFooterSpacer from './global/MkFooterSpacer.vue';
import MkStickyContainer from './global/MkStickyContainer.vue'; import MkStickyContainer from './global/MkStickyContainer.vue';
import MkLazy from './global/MkLazy.vue'; import MkLazy from './global/MkLazy.vue';
import SearchMarker from './global/SearchMarker.vue'; import SearchMarker from './global/SearchMarker.vue';
import SearchLabel from './global/SearchLabel.vue';
import SearchKeyword from './global/SearchKeyword.vue';
import type { App } from 'vue'; import type { App } from 'vue';
export default function(app: App) { export default function(app: App) {
@ -56,6 +59,8 @@ export const components = {
MkStickyContainer: MkStickyContainer, MkStickyContainer: MkStickyContainer,
MkLazy: MkLazy, MkLazy: MkLazy,
SearchMarker: SearchMarker, SearchMarker: SearchMarker,
SearchLabel: SearchLabel,
SearchKeyword: SearchKeyword,
}; };
declare module '@vue/runtime-core' { declare module '@vue/runtime-core' {
@ -82,5 +87,7 @@ declare module '@vue/runtime-core' {
MkStickyContainer: typeof MkStickyContainer; MkStickyContainer: typeof MkStickyContainer;
MkLazy: typeof MkLazy; MkLazy: typeof MkLazy;
SearchMarker: typeof SearchMarker; SearchMarker: typeof SearchMarker;
SearchLabel: typeof SearchLabel;
SearchKeyword: typeof SearchKeyword;
} }
} }

View File

@ -73,12 +73,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps_m"> <div class="_gaps_m">
<div class="_gaps_s"> <div class="_gaps_s">
<SearchMarker <SearchMarker
:label="i18n.ts.collapseRenotes" :keywords="['renote']"
:keywords="['renote', i18n.ts.collapseRenotesDescription]"
> >
<MkSwitch v-model="collapseRenotes"> <MkSwitch v-model="collapseRenotes">
<template #label>{{ i18n.ts.collapseRenotes }}</template> <template #label><SearchLabel>{{ i18n.ts.collapseRenotes }}</SearchLabel></template>
<template #caption>{{ i18n.ts.collapseRenotesDescription }}</template> <template #caption><SearchKeyword>{{ i18n.ts.collapseRenotesDescription }}</SearchKeyword></template>
</MkSwitch> </MkSwitch>
</SearchMarker> </SearchMarker>

View File

@ -7,8 +7,6 @@
// This file was automatically generated by create-search-index. // This file was automatically generated by create-search-index.
// Do not edit this file. // Do not edit this file.
/* eslint-disable @stylistic/comma-spacing */
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
export type SearchIndexItem = { export type SearchIndexItem = {
@ -32,22 +30,22 @@ export const searchIndexes:SearchIndexItem[] = [
{ {
id: 'gAvOWkPnm', id: 'gAvOWkPnm',
label: i18n.ts._profile.description, label: i18n.ts._profile.description,
keywords: ['description','bio'], keywords: ['description', 'bio'],
}, },
{ {
id: 'jDQ9ug9JI', id: 'jDQ9ug9JI',
label: i18n.ts.location, label: i18n.ts.location,
keywords: ['location','locale'], keywords: ['location', 'locale'],
}, },
{ {
id: '4IINpCs7w', id: '4IINpCs7w',
label: i18n.ts.birthday, label: i18n.ts.birthday,
keywords: ['birthday','birthdate','age'], keywords: ['birthday', 'birthdate', 'age'],
}, },
{ {
id: 'nrKSnXwYN', id: 'nrKSnXwYN',
label: i18n.ts.language, label: i18n.ts.language,
keywords: ['language','locale'], keywords: ['language', 'locale'],
}, },
{ {
id: 'xpFKUEupm', id: 'xpFKUEupm',
@ -98,7 +96,7 @@ export const searchIndexes:SearchIndexItem[] = [
{ {
id: 'yGVh4afrC', id: 'yGVh4afrC',
label: i18n.ts.autoAcceptFollowed, label: i18n.ts.autoAcceptFollowed,
keywords: ['follow','auto','accept'], keywords: ['follow', 'auto', 'accept'],
}, },
{ {
id: 'vomfIAjG2', id: 'vomfIAjG2',
@ -108,12 +106,12 @@ export const searchIndexes:SearchIndexItem[] = [
{ {
id: 'BakhCOlGl', id: 'BakhCOlGl',
label: i18n.ts.followingVisibility, label: i18n.ts.followingVisibility,
keywords: ['following','visibility'], keywords: ['following', 'visibility'],
}, },
{ {
id: 'nALctPZes', id: 'nALctPZes',
label: i18n.ts.followersVisibility, label: i18n.ts.followersVisibility,
keywords: ['follower','visibility'], keywords: ['follower', 'visibility'],
}, },
{ {
id: 'g39hgvANq', id: 'g39hgvANq',
@ -160,17 +158,17 @@ export const searchIndexes:SearchIndexItem[] = [
{ {
id: '6AAT3LUIL', id: '6AAT3LUIL',
label: i18n.ts.rememberNoteVisibility, label: i18n.ts.rememberNoteVisibility,
keywords: ['remember','keep','note','visibility'], keywords: ['remember', 'keep', 'note', 'visibility'],
}, },
{ {
id: '8d0FCNIgm', id: '8d0FCNIgm',
label: i18n.ts.defaultNoteVisibility, label: i18n.ts.defaultNoteVisibility,
keywords: ['default','note','visibility'], keywords: ['default', 'note', 'visibility'],
}, },
{ {
id: 'o3hisYwlV', id: 'o3hisYwlV',
label: i18n.ts.keepCw, label: i18n.ts.keepCw,
keywords: ['remember','keep','note','cw'], keywords: ['remember', 'keep', 'note', 'cw'],
}, },
], ],
label: i18n.ts.privacy, label: i18n.ts.privacy,
@ -191,36 +189,36 @@ export const searchIndexes:SearchIndexItem[] = [
}, },
], ],
label: i18n.ts.wordMute, label: i18n.ts.wordMute,
keywords: ['note','word','soft','mute','hide'], keywords: ['note', 'word', 'soft', 'mute', 'hide'],
}, },
{ {
id: 'evlmsuKtu', id: 'evlmsuKtu',
label: i18n.ts.hardWordMute, label: i18n.ts.hardWordMute,
keywords: ['note','word','hard','mute','hide'], keywords: ['note', 'word', 'hard', 'mute', 'hide'],
}, },
{ {
id: 'zLHWO9mBm', id: 'zLHWO9mBm',
label: i18n.ts.instanceMute, label: i18n.ts.instanceMute,
keywords: ['note','server','instance','host','federation','mute','hide'], keywords: ['note', 'server', 'instance', 'host', 'federation', 'mute', 'hide'],
}, },
{ {
id: 's3IxYcSKj', id: 's3IxYcSKj',
label: `${i18n.ts.mutedUsers} (${ i18n.ts.renote })`, label: `${i18n.ts.mutedUsers} (${ i18n.ts.renote })`,
keywords: ['renote','mute','hide','user'], keywords: ['renote', 'mute', 'hide', 'user'],
}, },
{ {
id: 'iBnGIbcys', id: 'iBnGIbcys',
label: i18n.ts.mutedUsers, label: i18n.ts.mutedUsers,
keywords: ['note','mute','hide','user'], keywords: ['note', 'mute', 'hide', 'user'],
}, },
{ {
id: 'g6aGcN8X5', id: 'g6aGcN8X5',
label: i18n.ts.blockedUsers, label: i18n.ts.blockedUsers,
keywords: ['block','user'], keywords: ['block', 'user'],
}, },
], ],
label: i18n.ts.muteAndBlock, label: i18n.ts.muteAndBlock,
keywords: ['mute','block'], keywords: ['mute', 'block'],
path: '/settings/mute-block', path: '/settings/mute-block',
icon: 'ti ti-ban', icon: 'ti ti-ban',
}, },
@ -235,22 +233,22 @@ export const searchIndexes:SearchIndexItem[] = [
{ {
id: '3zpvHzV5g', id: '3zpvHzV5g',
label: i18n.ts.overridedDeviceKind, label: i18n.ts.overridedDeviceKind,
keywords: ['device','type','kind','smartphone','tablet','desktop'], keywords: ['device', 'type', 'kind', 'smartphone', 'tablet', 'desktop'],
}, },
{ {
id: '1QvSeZtNe', id: '1QvSeZtNe',
label: i18n.ts.showFixedPostForm, label: i18n.ts.showFixedPostForm,
keywords: ['post','form','timeline'], keywords: ['post', 'form', 'timeline'],
}, },
{ {
id: 'oVjAZ97m1', id: 'oVjAZ97m1',
label: i18n.ts.showFixedPostFormInChannel, label: i18n.ts.showFixedPostFormInChannel,
keywords: ['post','form','timeline','channel'], keywords: ['post', 'form', 'timeline', 'channel'],
}, },
{ {
id: '6sIzeMWoB', id: '6sIzeMWoB',
label: i18n.ts.pinnedList, label: i18n.ts.pinnedList,
keywords: ['pinned','list'], keywords: ['pinned', 'list'],
}, },
{ {
id: '6HbFzMsfZ', id: '6HbFzMsfZ',
@ -261,238 +259,238 @@ export const searchIndexes:SearchIndexItem[] = [
keywords: ['renote', i18n.ts.collapseRenotesDescription], keywords: ['renote', i18n.ts.collapseRenotesDescription],
}, },
{ {
id: 'r8RoaDGyB', id: 'ge9OZWVVN',
label: i18n.ts.showNoteActionsOnlyHover, label: i18n.ts.showNoteActionsOnlyHover,
keywords: ['hover','show','footer','action'], keywords: ['hover', 'show', 'footer', 'action'],
}, },
{ {
id: 'dhe5ltCVy', id: 'qkpSLdjU0',
label: i18n.ts.showClipButtonInNoteFooter, label: i18n.ts.showClipButtonInNoteFooter,
keywords: ['footer','action','clip','show'], keywords: ['footer', 'action', 'clip', 'show'],
}, },
{ {
id: 'lJijzarvh', id: 'A3lCFvhIW',
label: i18n.ts.enableAdvancedMfm, label: i18n.ts.enableAdvancedMfm,
keywords: ['mfm','enable','show','advanced'], keywords: ['mfm', 'enable', 'show', 'advanced'],
}, },
{ {
id: 'plFY7Zr0Y', id: 'AhvTBCdWA',
label: i18n.ts.enableAnimatedMfm, label: i18n.ts.enableAnimatedMfm,
keywords: ['mfm','enable','show','animated'], keywords: ['mfm', 'enable', 'show', 'animated'],
}, },
{ {
id: 'uCWeJdWGo', id: 'hsXMJyRt9',
label: i18n.ts.enableQuickAddMfmFunction, label: i18n.ts.enableQuickAddMfmFunction,
keywords: ['mfm','enable','show','advanced','picker','form','function','fn'], keywords: ['mfm', 'enable', 'show', 'advanced', 'picker', 'form', 'function', 'fn'],
}, },
{ {
id: 'jojGm1s0T', id: 'caZ2i1vUp',
label: i18n.ts.showReactionsCount, label: i18n.ts.showReactionsCount,
keywords: ['reaction','count','show'], keywords: ['reaction', 'count', 'show'],
}, },
{ {
id: 'gob3LGyDO', id: 'zeBSHyLvX',
label: i18n.ts.showGapBetweenNotesInTimeline, label: i18n.ts.showGapBetweenNotesInTimeline,
keywords: ['note','timeline','gap'], keywords: ['note', 'timeline', 'gap'],
}, },
{ {
id: 'v5IaTjjUK', id: 'iCXH6Slng',
label: i18n.ts.loadRawImages, label: i18n.ts.loadRawImages,
keywords: ['image','photo','picture','media','thumbnail','quality','raw','attachment'], keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'quality', 'raw', 'attachment'],
}, },
{ {
id: '9rlymuz2e', id: 'dLhN3FVue',
label: i18n.ts.reactionsDisplaySize, label: i18n.ts.reactionsDisplaySize,
keywords: ['reaction','size','scale','display'], keywords: ['reaction', 'size', 'scale', 'display'],
}, },
{ {
id: 'a6JkO6iHN', id: 'vmlTGQcw9',
label: i18n.ts.limitWidthOfReaction, label: i18n.ts.limitWidthOfReaction,
keywords: ['reaction','size','scale','display','width','limit'], keywords: ['reaction', 'size', 'scale', 'display', 'width', 'limit'],
}, },
{ {
id: 'B2C8Chpn3', id: 'urTAUjuCD',
label: i18n.ts.instanceTicker, label: i18n.ts.instanceTicker,
keywords: ['ticker','information','label','instance','server','host','federation'], keywords: ['ticker', 'information', 'label', 'instance', 'server', 'host', 'federation'],
}, },
{ {
id: 'lXGQcJA0m', id: 'jEMNPc04n',
label: i18n.ts.displayOfSensitiveMedia, label: i18n.ts.displayOfSensitiveMedia,
keywords: ['attachment','image','photo','picture','media','thumbnail','nsfw','sensitive','display','show','hide','visibility'], keywords: ['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'nsfw', 'sensitive', 'display', 'show', 'hide', 'visibility'],
}, },
{ {
id: 'fI9unfBG9', id: 'dbVdQ8uQ6',
label: i18n.ts.mediaListWithOneImageAppearance, label: i18n.ts.mediaListWithOneImageAppearance,
keywords: ['attachment','image','photo','picture','media','thumbnail','list','size','height'], keywords: ['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'list', 'size', 'height'],
}, },
], ],
label: i18n.ts.displayOfNote, label: i18n.ts.displayOfNote,
keywords: ['note','display'], keywords: ['note', 'display'],
}, },
{ {
id: 'ksPnvPfsq', id: 'reaXNqM8S',
children: [ children: [
{ {
id: 'rlKh8qQSy', id: 'x5ekE7znD',
label: i18n.ts.useGroupedNotifications, label: i18n.ts.useGroupedNotifications,
keywords: ['group'], keywords: ['group'],
}, },
{ {
id: 'mZoLcRxn9', id: 'iUWlBX9ZI',
label: i18n.ts.position, label: i18n.ts.position,
keywords: ['position'], keywords: ['position'],
}, },
{ {
id: 'mu8Fghr9P', id: 'vrBikwOLp',
label: i18n.ts.stackAxis, label: i18n.ts.stackAxis,
keywords: ['stack','axis','direction'], keywords: ['stack', 'axis', 'direction'],
}, },
], ],
label: i18n.ts.notificationDisplay, label: i18n.ts.notificationDisplay,
keywords: ['notification','display'], keywords: ['notification', 'display'],
}, },
{ {
id: 'sUAe1tYeV', id: 'ufhXubmEr',
children: [ children: [
{ {
id: 'pXk2Bq5c7', id: 'fgl7X4XsD',
label: i18n.ts.reduceUiAnimation, label: i18n.ts.reduceUiAnimation,
keywords: ['animation','motion','reduce'], keywords: ['animation', 'motion', 'reduce'],
}, },
{ {
id: 'l92lxxESG', id: 'bjKigdnsy',
label: i18n.ts.useBlurEffect, label: i18n.ts.useBlurEffect,
keywords: ['blur'], keywords: ['blur'],
}, },
{ {
id: '5fw6zkK39', id: 'CGoeiZtv2',
label: i18n.ts.useBlurEffectForModal, label: i18n.ts.useBlurEffectForModal,
keywords: ['blur','modal'], keywords: ['blur', 'modal'],
}, },
{ {
id: 'm3kpvUE3f', id: 'bnzqN2Uv5',
label: i18n.ts.disableShowingAnimatedImages, label: i18n.ts.disableShowingAnimatedImages,
keywords: ['disable','animation','image','photo','picture','media','thumbnail','gif'], keywords: ['disable', 'animation', 'image', 'photo', 'picture', 'media', 'thumbnail', 'gif'],
}, },
{ {
id: 'EEHGMwhkC', id: '9LEabU98l',
label: i18n.ts.highlightSensitiveMedia, label: i18n.ts.highlightSensitiveMedia,
keywords: ['highlight','sensitive','nsfw','image','photo','picture','media','thumbnail'], keywords: ['highlight', 'sensitive', 'nsfw', 'image', 'photo', 'picture', 'media', 'thumbnail'],
}, },
{ {
id: 'hBnm0B8aI', id: 'aiKchQcTg',
label: i18n.ts.squareAvatars, label: i18n.ts.squareAvatars,
keywords: ['avatar','icon','square'], keywords: ['avatar', 'icon', 'square'],
}, },
{ {
id: 'm9Q5z11L8', id: '370ytj4BG',
label: i18n.ts.showAvatarDecorations, label: i18n.ts.showAvatarDecorations,
keywords: ['avatar','icon','decoration','show'], keywords: ['avatar', 'icon', 'decoration', 'show'],
}, },
{ {
id: 'pHvwcwF4c', id: 'sNxpyIsU0',
label: i18n.ts.useSystemFont, label: i18n.ts.useSystemFont,
keywords: ['font','system','native'], keywords: ['font', 'system', 'native'],
}, },
{ {
id: '3lcbrBHYZ', id: 'lNM8JR8Fq',
label: i18n.ts.forceShowAds, label: i18n.ts.forceShowAds,
keywords: ['ad','show'], keywords: ['ad', 'show'],
}, },
{ {
id: '523Bx87JU', id: 'rDKuKXq3L',
label: i18n.ts.seasonalScreenEffect, label: i18n.ts.seasonalScreenEffect,
keywords: ['effect','show'], keywords: ['effect', 'show'],
}, },
{ {
id: '7dFSaWz4u', id: 'eTBtusX71',
label: i18n.ts.useNativeUIForVideoAudioPlayer, label: i18n.ts.useNativeUIForVideoAudioPlayer,
keywords: ['native','system','video','audio','player','media'], keywords: ['native', 'system', 'video', 'audio', 'player', 'media'],
}, },
{ {
id: 'q3Vv5zIZu', id: 'c2IIsJe2s',
label: i18n.ts.menuStyle, label: i18n.ts.menuStyle,
keywords: ['menu','style','popup','drawer'], keywords: ['menu', 'style', 'popup', 'drawer'],
}, },
{ {
id: 'd1Gno6GaT', id: 'zeg5SUJfO',
label: i18n.ts.emojiStyle, label: i18n.ts.emojiStyle,
keywords: ['emoji','style','native','system','fluent','twemoji'], keywords: ['emoji', 'style', 'native', 'system', 'fluent', 'twemoji'],
}, },
{ {
id: '3sV67CRuN', id: 'dSCrbhyrx',
label: i18n.ts.fontSize, label: i18n.ts.fontSize,
keywords: ['font','size'], keywords: ['font', 'size'],
}, },
], ],
label: i18n.ts.appearance, label: i18n.ts.appearance,
keywords: ['appearance'], keywords: ['appearance'],
}, },
{ {
id: 'AOASYDlhv', id: 'onFBs0tYX',
children: [ children: [
{ {
id: 'rwvOv068t', id: 'gmuZO8DML',
label: i18n.ts.openImageInNewTab, label: i18n.ts.openImageInNewTab,
keywords: ['image','photo','picture','media','thumbnail','new','tab'], keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'new', 'tab'],
}, },
{ {
id: '1XB7XWwbI', id: '5pZfWlbB2',
label: i18n.ts.useReactionPickerForContextMenu, label: i18n.ts.useReactionPickerForContextMenu,
keywords: ['reaction','picker','contextmenu','open'], keywords: ['reaction', 'picker', 'contextmenu', 'open'],
}, },
{ {
id: '4fjitJYAl', id: 'pihxkFGES',
label: i18n.ts.enableInfiniteScroll, label: i18n.ts.enableInfiniteScroll,
keywords: ['load','auto','more'], keywords: ['load', 'auto', 'more'],
}, },
{ {
id: 'f2Nk4GdTa', id: '1QcQVuU3X',
label: i18n.ts.keepScreenOn, label: i18n.ts.keepScreenOn,
keywords: ['keep','screen','display','on'], keywords: ['keep', 'screen', 'display', 'on'],
}, },
{ {
id: '3D54jQsGn', id: 'DPsw4YfoC',
label: i18n.ts.disableStreamingTimeline, label: i18n.ts.disableStreamingTimeline,
keywords: ['disable','streaming','timeline'], keywords: ['disable', 'streaming', 'timeline'],
}, },
{ {
id: '6MKp7i7iH', id: 'nXcDddZr9',
label: i18n.ts.enableHorizontalSwipe, label: i18n.ts.enableHorizontalSwipe,
keywords: ['swipe','horizontal','tab'], keywords: ['swipe', 'horizontal', 'tab'],
}, },
{ {
id: 'eSvGS9DsY', id: 'sq5mQo7Th',
label: i18n.ts.alwaysConfirmFollow, label: i18n.ts.alwaysConfirmFollow,
keywords: ['follow','confirm','always'], keywords: ['follow', 'confirm', 'always'],
}, },
{ {
id: 'kGYY8LCdK', id: '9IuNcZ9Ct',
label: i18n.ts.confirmWhenRevealingSensitiveMedia, label: i18n.ts.confirmWhenRevealingSensitiveMedia,
keywords: ['sensitive','nsfw','media','image','photo','picture','attachment','confirm'], keywords: ['sensitive', 'nsfw', 'media', 'image', 'photo', 'picture', 'attachment', 'confirm'],
}, },
{ {
id: 'fdOu3BDKL', id: '4BhdUdrlf',
label: i18n.ts.confirmOnReact, label: i18n.ts.confirmOnReact,
keywords: ['reaction','confirm'], keywords: ['reaction', 'confirm'],
}, },
{ {
id: 'isbDLeTjm', id: 'qqA6jS0Fy',
label: i18n.ts.whenServerDisconnected, label: i18n.ts.whenServerDisconnected,
keywords: ['server','disconnect','reconnect','reload','streaming'], keywords: ['server', 'disconnect', 'reconnect', 'reload', 'streaming'],
}, },
{ {
id: 'F5werzQkF', id: 'EPnMDBcWn',
label: i18n.ts._contextMenu.title, label: i18n.ts._contextMenu.title,
keywords: ['contextmenu','system','native'], keywords: ['contextmenu', 'system', 'native'],
}, },
{ {
id: 'CPNGOZAoV', id: 'iHo9Udj7J',
label: i18n.ts.numberOfPageCache, label: i18n.ts.numberOfPageCache,
keywords: ['cache','page'], keywords: ['cache', 'page'],
}, },
{ {
id: '5XHiLyaol', id: '8KHaBRiOz',
label: i18n.ts.dataSaver, label: i18n.ts.dataSaver,
keywords: ['datasaver'], keywords: ['datasaver'],
}, },
@ -508,5 +506,3 @@ export const searchIndexes:SearchIndexItem[] = [
] as const; ] as const;
export type SearchIndex = typeof searchIndexes; export type SearchIndex = typeof searchIndexes;
/* eslint-enable @stylistic/comma-spacing */