index_generator.py 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. 索引生成器模块
  5. 负责生成各种索引文件,支持中英双语
  6. """
  7. from pathlib import Path
  8. import re
  9. from typing import Dict, List, Tuple
  10. class IndexGenerator:
  11. def __init__(self, output_dir: str, file_processor):
  12. self.output_dir = Path(output_dir)
  13. self.file_processor = file_processor
  14. def check_available_languages(self, project: str, category: str) -> Tuple[bool, bool]:
  15. """检查项目支持的语言
  16. Returns:
  17. (has_chinese, has_english): 是否有中文和英文文档
  18. """
  19. try:
  20. # 获取项目在 projects 目录中的实际路径
  21. project_path = None
  22. projects_dir = getattr(self.file_processor, 'projects_dir', 'projects')
  23. # 尝试不同的路径组合
  24. possible_paths = [
  25. Path(projects_dir) / project,
  26. Path(projects_dir) / category / project,
  27. ]
  28. for path in possible_paths:
  29. if path.exists():
  30. project_path = path
  31. break
  32. if not project_path:
  33. # 回退:检查输出目录中的文件
  34. output_project_path = self.output_dir / category / project
  35. has_chinese = (output_project_path / "README_zh.md").exists()
  36. has_english = (output_project_path / "README.md").exists()
  37. return has_chinese, has_english
  38. has_chinese = (project_path / "README_zh.md").exists()
  39. has_english = (project_path / "README.md").exists()
  40. return has_chinese, has_english
  41. except Exception as e:
  42. print(f"检查语言支持时出错 {project}: {e}")
  43. # 回退到默认:假设只有中文
  44. return True, False
  45. def generate_category_index(self, category: str, category_name: str, projects: List[str], language: str = 'zh') -> str:
  46. """生成分类索引页面,支持双语"""
  47. title_length = len(category_name.encode('utf-8'))
  48. underline = '=' * title_length
  49. if language == 'en':
  50. description = f"This section contains SDK {category_name.lower()}."
  51. else:
  52. description = f"这里包含了 SDK 的 {category_name}。"
  53. content = f"""{category_name}
  54. {underline}
  55. {description}
  56. .. toctree::
  57. :maxdepth: 4
  58. :caption: {category_name}
  59. """
  60. # 读取各项目的显示标题,用于自然排序(数字感知、大小写不敏感)
  61. items = [] # (display_title, project_path, project_name, has_chinese, has_english)
  62. for project in projects:
  63. has_chinese, has_english = self.check_available_languages(project, category)
  64. # 根据语言选择标题
  65. display_title = None
  66. if language == 'en' and has_english:
  67. display_title = self.file_processor.get_readme_title(project, category, 'en') or project
  68. elif language == 'zh' and has_chinese:
  69. display_title = self.file_processor.get_readme_title(project, category, 'zh') or project
  70. elif has_chinese:
  71. display_title = self.file_processor.get_readme_title(project, category, 'zh') or project
  72. elif has_english:
  73. display_title = self.file_processor.get_readme_title(project, category, 'en') or project
  74. else:
  75. display_title = project
  76. items.append((display_title, project, has_chinese, has_english))
  77. # 自然排序函数
  78. def natural_key(s: str):
  79. return [int(part) if part.isdigit() else part.casefold() for part in re.split(r'(\d+)', s)]
  80. items.sort(key=lambda x: natural_key(x[0]))
  81. # 在 toctree 中生成条目
  82. for display_title, project, has_chinese, has_english in items:
  83. if language == 'en':
  84. # 英文版:只显示英文链接
  85. if has_english:
  86. content += f" {display_title} <{project}/README>\n"
  87. elif has_chinese:
  88. # 如果没有英文版,回退到中文版
  89. content += f" {display_title} <{project}/README_zh>\n"
  90. else:
  91. # 中文版:只显示中文链接
  92. if has_chinese:
  93. content += f" {display_title} <{project}/README_zh>\n"
  94. elif has_english:
  95. # 如果没有中文版,回退到英文版
  96. content += f" {display_title} <{project}/README>\n"
  97. if language == 'en':
  98. content += f"\nThese examples demonstrate SDK {category_name.lower()}.\n"
  99. else:
  100. content += f"\n这些示例展示了 SDK 的 {category_name}。\n"
  101. return content
  102. def generate_main_index(self, project_info: Dict, language: str = 'zh') -> str:
  103. """生成主索引页面"""
  104. if language == 'en':
  105. title = f"Welcome to {project_info.get('name', 'SDK')} Documentation!"
  106. else:
  107. title = f"欢迎来到 {project_info.get('name', 'SDK')} 文档!"
  108. title_length = len(title.encode('utf-8'))
  109. underline = '=' * title_length
  110. # 读取 output_structure 以动态生成章节顺序
  111. output_structure = []
  112. # 从 FileProcessor 的配置读取 output_structure
  113. try:
  114. output_structure = ((self.file_processor.config.get('output_structure', [])) or [])
  115. except Exception:
  116. output_structure = []
  117. if not output_structure:
  118. # 回退到已有分类顺序
  119. output_structure = ['start', 'basic', 'driver', 'component', 'multimedia', 'multcore']
  120. try:
  121. self.structure_mode = 'hardcoded'
  122. except Exception:
  123. pass
  124. else:
  125. try:
  126. self.structure_mode = 'dynamic'
  127. except Exception:
  128. pass
  129. toc_lines = []
  130. for cat in output_structure:
  131. if language == 'en':
  132. # 英文版:引用无后缀的index文件
  133. toc_lines.append(f" {cat}/index")
  134. else:
  135. # 中文版:引用带_zh后缀的index文件
  136. toc_lines.append(f" {cat}/index_zh")
  137. toc_block = "\n".join(toc_lines)
  138. # 根据语言选择正确的描述
  139. if language == 'en':
  140. description = project_info.get('description_en') or project_info.get('description', 'This is a brief introduction to the SDK.')
  141. else:
  142. description = project_info.get('description', '这里是 SDK 的简要介绍。')
  143. content = f""".. {project_info.get('name', 'SDK')} documentation master file, created by sphinx-quickstart
  144. {title}
  145. {underline}
  146. .. toctree::
  147. :maxdepth: 4
  148. :caption: {'Contents' if language == 'en' else '目录'}
  149. {toc_block}
  150. {'Project Overview' if language == 'en' else '项目简介'}
  151. --------
  152. {description}
  153. """
  154. return content
  155. def write_index_file(self, content: str, file_path: str):
  156. """写入索引文件"""
  157. file_path = Path(file_path)
  158. file_path.parent.mkdir(parents=True, exist_ok=True)
  159. with open(file_path, 'w', encoding='utf-8') as f:
  160. f.write(content)
  161. print(f"已生成索引文件: {file_path}")
  162. def generate_all_indexes(self, categories: Dict, category_mapping: Dict, project_info: Dict):
  163. """生成所有索引文件"""
  164. # 生成主索引(中文版)- 使用 _zh 后缀
  165. main_index_content = self.generate_main_index(project_info, 'zh')
  166. self.write_index_file(main_index_content, self.output_dir / "index_zh.rst")
  167. # 生成主索引(英文版)- 无后缀表示英文
  168. main_index_content_en = self.generate_main_index(project_info, 'en')
  169. self.write_index_file(main_index_content_en, self.output_dir / "index.rst")
  170. # 生成分类索引
  171. total_chinese = 0
  172. total_english = 0
  173. total_bilingual = 0
  174. for category, config in categories.items():
  175. projects = category_mapping.get(category, [])
  176. if projects:
  177. # 生成中文版索引 - 使用 _zh 后缀
  178. category_name_zh = config.get('name', category)
  179. index_content_zh = self.generate_category_index(category, category_name_zh, projects, 'zh')
  180. index_path_zh = self.output_dir / category / "index_zh.rst"
  181. self.write_index_file(index_content_zh, index_path_zh)
  182. # 生成英文版索引 - 无后缀表示英文
  183. category_name_en = config.get('name_en', category)
  184. index_content_en = self.generate_category_index(category, category_name_en, projects, 'en')
  185. index_path_en = self.output_dir / category / "index.rst"
  186. self.write_index_file(index_content_en, index_path_en)
  187. # 统计语言支持情况
  188. for project in projects:
  189. has_chinese, has_english = self.check_available_languages(project, category)
  190. if has_chinese and has_english:
  191. total_bilingual += 1
  192. elif has_chinese:
  193. total_chinese += 1
  194. elif has_english:
  195. total_english += 1
  196. # 末尾总结日志
  197. mode = getattr(self, 'structure_mode', 'hardcoded')
  198. if mode == 'dynamic':
  199. print("索引结构生成模式: 动态 (来自 config.yaml:generation.output_structure)")
  200. else:
  201. print("索引结构生成模式: 硬编码回退 (未在 config.yaml 中找到 output_structure)")
  202. print(f"语言支持统计: 双语文档 {total_bilingual} 个, 仅中文 {total_chinese} 个, 仅英文 {total_english} 个")