language_switch.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /**
  2. * 中英文切换功能
  3. * 支持导航栏和正文内容的语言切换
  4. */
  5. (function() {
  6. 'use strict';
  7. // 语言配置
  8. const LANGUAGE_CONFIG = {
  9. chinese: {
  10. code: 'zh',
  11. name: '中文',
  12. suffix: '_zh',
  13. selector: '[data-lang="zh"]'
  14. },
  15. english: {
  16. code: 'en',
  17. name: 'English',
  18. suffix: '',
  19. selector: '[data-lang="en"]'
  20. }
  21. };
  22. // 当前语言状态
  23. let currentLanguage = 'chinese';
  24. let isInitialized = false;
  25. /**
  26. * 检测当前页面的语言
  27. */
  28. function detectCurrentLanguage() {
  29. const htmlLang = document.documentElement.getAttribute('lang');
  30. const currentPath = window.location.pathname;
  31. if ((htmlLang === 'zh-CN') && (currentPath.endsWith('_zh.html'))) return 'chinese';
  32. if ((htmlLang === 'en') && (currentPath.endsWith('.html'))) return 'english';
  33. return 'english';
  34. }
  35. /**
  36. * 初始化语言切换UI(动态创建)
  37. */
  38. function createLanguageSwitch() {
  39. // 检查是否已经存在
  40. const existingSwitch = document.querySelector('.language-switch');
  41. if (existingSwitch) {
  42. console.log('语言切换器已存在');
  43. return;
  44. }
  45. // 查找侧边栏容器
  46. const sidebar = document.querySelector('.wy-nav-side .wy-side-scroll');
  47. if (!sidebar) {
  48. console.warn('未找到侧边栏容器');
  49. return;
  50. }
  51. // 创建语言切换UI - "中文 | English" 格式
  52. const languageSwitchHTML = `
  53. <div class="language-switch-container">
  54. <div class="language-switch" id="language-switch">
  55. <div class="language-switch__container">
  56. <button class="language-switch__option" data-lang="chinese" aria-label="切换到中文">
  57. 中文
  58. </button>
  59. <span class="language-switch__separator">|</span>
  60. <button class="language-switch__option" data-lang="english" aria-label="Switch to English">
  61. English
  62. </button>
  63. </div>
  64. </div>
  65. </div>
  66. `;
  67. // 将语言切换器添加到侧边栏底部
  68. sidebar.insertAdjacentHTML('beforeend', languageSwitchHTML);
  69. console.log('语言切换器已动态创建');
  70. }
  71. /**
  72. * 设置语言切换器事件
  73. */
  74. function setupLanguageSwitchEvents() {
  75. const languageSwitch = document.getElementById('language-switch');
  76. if (!languageSwitch) return;
  77. const options = languageSwitch.querySelectorAll('.language-switch__option');
  78. const slider = languageSwitch.querySelector('.language-switch__slider');
  79. options.forEach(option => {
  80. option.addEventListener('click', function(e) {
  81. e.preventDefault();
  82. const targetLang = this.getAttribute('data-lang');
  83. if (targetLang !== currentLanguage) {
  84. switchLanguage(targetLang);
  85. }
  86. });
  87. // 键盘支持
  88. option.addEventListener('keydown', function(e) {
  89. if (e.key === 'Enter' || e.key === ' ') {
  90. e.preventDefault();
  91. this.click();
  92. }
  93. });
  94. });
  95. // 更新当前语言状态
  96. updateLanguageSwitchState();
  97. }
  98. /**
  99. * 更新语言切换器状态
  100. */
  101. function updateLanguageSwitchState() {
  102. const languageSwitch = document.getElementById('language-switch');
  103. if (!languageSwitch) return;
  104. const options = languageSwitch.querySelectorAll('.language-switch__option');
  105. options.forEach(option => {
  106. const lang = option.getAttribute('data-lang');
  107. if (lang === currentLanguage) {
  108. option.classList.add('active');
  109. option.setAttribute('aria-pressed', 'true');
  110. } else {
  111. option.classList.remove('active');
  112. option.setAttribute('aria-pressed', 'false');
  113. }
  114. });
  115. }
  116. /**
  117. * 切换语言
  118. */
  119. function switchLanguage(targetLang) {
  120. if (targetLang === currentLanguage) return;
  121. console.log(`切换语言: ${currentLanguage} -> ${targetLang}`);
  122. // 添加加载状态
  123. const languageSwitch = document.getElementById('language-switch');
  124. if (languageSwitch) {
  125. languageSwitch.classList.add('loading');
  126. }
  127. // 获取当前页面信息
  128. const currentPath = window.location.pathname;
  129. const currentUrl = window.location.href;
  130. // 构建目标URL
  131. let targetUrl = '';
  132. if (targetLang === 'chinese') {
  133. // 切换到中文版本
  134. if (currentPath.includes('_zh.html')) {
  135. // 如果已经是中文页面,不需要切换
  136. targetUrl = currentUrl;
  137. } else if (currentPath.includes('.html') && !currentPath.includes('_zh.html')) {
  138. // 如果当前是英文页面,切换到中文页面
  139. targetUrl = currentPath.replace('.html', '_zh.html');
  140. } else if (currentPath.endsWith('/') || currentPath.endsWith('/index.html')) {
  141. // 如果当前是根目录或英文版目录页面,切换到中文版目录页面
  142. targetUrl = currentPath.replace('/index.html', '/index_zh.html').replace(/\/$/, '/index_zh.html');
  143. } else {
  144. // 其他情况,尝试构建中文版本URL
  145. targetUrl = currentPath + (currentPath.endsWith('/') ? '' : '/') + 'index_zh.html';
  146. }
  147. } else {
  148. // 切换到英文版本
  149. if (currentPath.includes('_zh.html')) {
  150. // 如果当前是中文页面,切换到英文页面
  151. targetUrl = currentPath.replace('_zh.html', '.html');
  152. } else if (currentPath.includes('.html') && !currentPath.includes('_zh.html')) {
  153. // 如果当前是英文页面,保持英文版本
  154. targetUrl = currentUrl;
  155. } else if (currentPath.endsWith('/') || currentPath.endsWith('/index_zh.html')) {
  156. // 如果当前是根目录或中文版目录页面,切换到英文版目录页面
  157. targetUrl = currentPath.replace('/index_zh.html', '/index.html').replace(/\/$/, '/index.html');
  158. } else {
  159. // 其他情况,尝试构建英文版本URL
  160. targetUrl = currentPath + (currentPath.endsWith('/') ? '' : '/') + 'index.html';
  161. }
  162. }
  163. // 如果目标URL与当前URL相同,只更新UI状态
  164. if (targetUrl === currentUrl || targetUrl === window.location.href) {
  165. currentLanguage = targetLang;
  166. updateLanguageSwitchState();
  167. if (languageSwitch) {
  168. languageSwitch.classList.remove('loading');
  169. }
  170. return;
  171. }
  172. // 跳转到目标URL
  173. console.log(`跳转到: ${targetUrl}`);
  174. window.location.href = targetUrl;
  175. }
  176. /**
  177. * 更新导航栏语言显示
  178. */
  179. function updateNavigationLanguage() {
  180. const navLinks = document.querySelectorAll('.wy-menu a[href*="README"]');
  181. navLinks.forEach(link => {
  182. const href = link.getAttribute('href');
  183. const text = link.textContent.trim();
  184. if (currentLanguage === 'chinese') {
  185. // 显示中文版本,隐藏英文版本
  186. if (href.includes('_zh.html') || text.includes('(中文)')) {
  187. link.style.display = '';
  188. link.closest('li').style.display = '';
  189. } else if (href.includes('.html') && !href.includes('_zh.html') && text.includes('(English)')) {
  190. link.style.display = 'none';
  191. link.closest('li').style.display = 'none';
  192. }
  193. } else {
  194. // 显示英文版本,隐藏中文版本
  195. if (href.includes('_zh.html') || text.includes('(中文)')) {
  196. link.style.display = 'none';
  197. link.closest('li').style.display = 'none';
  198. } else if (href.includes('.html') && !href.includes('_zh.html') && text.includes('(English)')) {
  199. link.style.display = '';
  200. link.closest('li').style.display = '';
  201. }
  202. }
  203. });
  204. }
  205. /**
  206. * 初始化语言切换功能
  207. */
  208. function init() {
  209. if (isInitialized) return;
  210. console.log('初始化语言切换功能...');
  211. // 检测当前语言
  212. currentLanguage = detectCurrentLanguage();
  213. console.log('检测到的当前语言:', currentLanguage);
  214. // 等待DOM加载完成
  215. if (document.readyState === 'loading') {
  216. document.addEventListener('DOMContentLoaded', function() {
  217. setTimeout(initLanguageSwitch, 100);
  218. });
  219. } else {
  220. setTimeout(initLanguageSwitch, 100);
  221. }
  222. isInitialized = true;
  223. }
  224. /**
  225. * 初始化语言切换器
  226. */
  227. function initLanguageSwitch() {
  228. createLanguageSwitch();
  229. setupLanguageSwitchEvents();
  230. updateNavigationLanguage();
  231. // 如果侧边栏是动态加载的,等待一下再尝试
  232. setTimeout(() => {
  233. if (!document.querySelector('.language-switch')) {
  234. console.warn('语言切换器仍未找到,请检查模板配置');
  235. }
  236. }, 1000);
  237. }
  238. // 启动
  239. init();
  240. // 导出到全局作用域
  241. window.LanguageSwitch = {
  242. switchLanguage: switchLanguage,
  243. getCurrentLanguage: () => currentLanguage,
  244. updateNavigation: updateNavigationLanguage
  245. };
  246. })();