GitHub Russian Translation

Translates the github.com website into Russian.

目前为 2025-01-16 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name GitHub Russian Translation
  3. // @name:ru Русификатор GitHub
  4. // @author Deflecta
  5. // @contributionURL https://boosty.to/rushanm
  6. // @description Translates the github.com website into Russian.
  7. // @description:ru Переводит сайт github.com на русский язык.
  8. // @grant none
  9. // @homepageURL https://github.com/RushanM/GitHub-Russian-Translation
  10. // @icon https://github.githubassets.com/favicons/favicon.png
  11. // @license MIT
  12. // @match https://github.com/*
  13. // @run-at document-end
  14. // @namespace githubrutraslation
  15. // @supportURL https://github.com/RushanM/GitHub-Russian-Translation/issues
  16. // @version 1-B8
  17. // ==/UserScript==
  18.  
  19. (function() {
  20. 'use strict';
  21.  
  22. const translations = {
  23. "Public profile": "Публичный профиль",
  24. "Account": "Учётная запись",
  25. "Appearance": "Внешний вид",
  26. "Accessibility": "Доступность",
  27. "Notifications": "Уведомления",
  28. "Billing and plans": "Выставление счетов и планы",
  29. "Plans and usage": "Планы и использование",
  30. "Spending limits": "Лимиты расходов",
  31. "Payment information": "Платёжная информация",
  32. "Emails": "Электронные почты",
  33. "Password and authentication": "Пароль и аутентификация",
  34. "Sessions": "Сессии",
  35. "SSH and GPG keys": "Ключи SSH и GPG",
  36. "Organizations": "Организации",
  37. "Enterprises": "Предприятия",
  38. "Blocked users": "Заблокированные пользователи",
  39. "Interaction limits": "Ограничения взаимодействия",
  40. "Code review limits": "Ограничения код-ревью",
  41. "Repositories": "Репозитории",
  42. "Codespaces": "Кодовые пространства",
  43. "Packages": "Пакеты",
  44. "Copilot": "Копайлот",
  45. "Pages": "Страницы",
  46. "Saved replies": "Сохранённые ответы",
  47. "Applications": "Приложения",
  48. "Scheduled reminders": "Запланированные напоминания",
  49. "Security log": "Журнал безопасности",
  50. "Sponsorship log": "Журнал спонсорства",
  51. "Developer settings": "Настройки разработчика",
  52. "Code security": "Безопасность кода",
  53. "Moderation": "Модерация",
  54. // Заголовки настроек
  55. "Access": "Доступ",
  56. "Code, planning, and automation": "Код, планирование и автоматизация",
  57. "Security": "Безопасность",
  58. "Integrations": "Интеграции",
  59. "Archives": "Архивы",
  60. // Вкладки
  61. "Code": "Код",
  62. "Issues": "Темы",
  63. "Bugs": "Ошибки",
  64. "Pull requests": "Запросы на слияние",
  65. "Discussions": "Обсуждения",
  66. "Actions": "Экшены",
  67. "Projects": "Проекты",
  68. "Wiki": "Вики",
  69. "Security": "Безопасность",
  70. "Insights": "Аналитика",
  71. "Settings": "Настройки",
  72. "Releases": "Выпуски",
  73. // Бутербродное меню репозитория
  74. "Compare": "Сравнение",
  75. "Dependencies": "Зависимости",
  76. "Commits": "Правки",
  77. "Branches": "Ветки",
  78. // Настройки репозитория
  79. "General": "Основное",
  80. "Collaborators": "Коллабораторы",
  81. "Moderation options": "Настройки модерации",
  82. "Tags": "Теги",
  83. "Rules": "Правила",
  84. "Rulesets": "Наборы правил",
  85. "Runners": "Исполнители",
  86. "Webhooks": "Вебхуки",
  87. "Environments": "Среды",
  88. "Deploy keys": "Ключи развёртывания",
  89. "Secrets and variables": "Секреты и переменные",
  90. "GitHub Apps": "Приложения GitHub",
  91. "Email notifications": "Уведомления по почте",
  92. "Autolink references": "Автоссылки",
  93. // Заголовки настроек репозитория
  94. "Code and automation": "Код и автоматизация",
  95. // Разделы экшенов
  96. "All workflows": "Все рабочие процессы",
  97. "Caches": "Кэши",
  98. "Attestations": "Утверждения",
  99. // Разделы экшена
  100. "Summary": "Сводка",
  101. "Usage": "Использование",
  102. "Workflow file": "Файл рабочего процесса",
  103. // Заголовки разделов экшена
  104. "Jobs": "Задания",
  105. "Run details": "Подробности запуска",
  106. // Заголовки разделов экшенов
  107. "Management": "Управление",
  108. // Заголовки страниц
  109. "Dashboard": "Главная страница",
  110. "Copilot": "Копайлот",
  111. // Поиск
  112. "Type / to search": "Нажмите <kbd class=\"AppHeader-search-kbd\">/</kbd> для поиска",
  113. "Find a repository…": "Найти репозиторий…",
  114. // Разделы главной
  115. "Home": "Главная",
  116. "Explore": "Обзор",
  117. "Marketplace": "Торговая площадка",
  118. // Главная
  119. "Top repositories": "Лучшие репозитории",
  120. "Recent activity": "Недавняя активность",
  121. // Подзагаловки главной
  122. "Show more": "Показать больше",
  123. "Filter": "Фильтр",
  124. "Events": "События",
  125. "Activity you want to see on your feed": "Деятельность, которую вы хотите видеть в своей ленте",
  126. "Announcements": "Объявления",
  127. "Special discussion posts from repositories": "Особые обсуждения из репозиториев",
  128. "Releases": "Выпуски",
  129. "Update posts from repositories": "Обновления из репозиториев",
  130. "Sponsors": "Спонсоры",
  131. "Relevant projects or people that are being sponsored": "Соответствующие проекты или люди, которых спонсируют",
  132. "Stars": "Звёзды",
  133. "Repositories being starred by people": "Репозитории, которые получают звёзды от пользователей",
  134. "Repositories": "Репозитории",
  135. "Repositories that are created or forked by people": "Репозитории, созданные или разветвлённые пользователями",
  136. "Repository activity": "Деятельность репозиториев",
  137. "Issues and pull requests from repositories": "Проблемы и запросы на слияние из репозиториев",
  138. "Follows": "Подписки",
  139. "Who people are following": "На кого подписываются пользователи",
  140. "Recommendations": "Рекомендации",
  141. "Repositories and people you may like": "Репозитории и пользователи, которые могут вам понравиться",
  142. "Include events from starred repositories": "Включать события из репозиториев, на которые вы поставили звезду",
  143. "By default, the feed shows events from repositories you sponsor or watch, and people you follow.": "По умолчанию лента отображает события из репозиториев, которые вы спонсируете или за которыми следите, а также от людей, на которых подписаны.",
  144. "Reset to default": "Сбросить до настроек по умолчанию",
  145. "Save": "Сохранить"
  146. };
  147.  
  148. function translateTextContent() {
  149. const elements = document.querySelectorAll('.ActionList-sectionDivider-title, .ActionListItem-label, span[data-content], .AppHeader-context-item-label, #qb-input-query, .Truncate-text, h2, button');
  150.  
  151. elements.forEach(el => {
  152. // Проверка, содержит ли элемент дочерние элементы (<kbd>)
  153. if (el.childElementCount > 0) {
  154. // Сборка текстового содержания с учётом дочерних элементов
  155. let text = '';
  156. el.childNodes.forEach(node => {
  157. if (node.nodeType === Node.TEXT_NODE) {
  158. text += node.textContent;
  159. } else if (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'KBD') {
  160. text += '/'; // Добавление символа «/», который содержится внутри <kbd>
  161. }
  162. });
  163. text = text.trim();
  164. if (translations[text]) {
  165. // Создание нового фрагмента с переводом и сохранение тега <kbd>
  166. const newFragment = document.createDocumentFragment();
  167. const parts = translations[text].split('<kbd class="AppHeader-search-kbd">/</kbd>');
  168. newFragment.append(document.createTextNode(parts[0]));
  169. const kbd = document.createElement('kbd');
  170. kbd.className = 'AppHeader-search-kbd';
  171. kbd.textContent = '/';
  172. newFragment.append(kbd);
  173. newFragment.append(document.createTextNode(parts[1]));
  174. // Очистка элемента и вставка нового контента
  175. el.innerHTML = '';
  176. el.appendChild(newFragment);
  177. }
  178. } else {
  179. const text = el.textContent.trim();
  180. if (translations[text]) {
  181. el.textContent = translations[text];
  182. }
  183. }
  184. });
  185. }
  186.  
  187. function translateAttributes() {
  188. // Перевод placeholder
  189. document.querySelectorAll('input[placeholder]').forEach(el => {
  190. const text = el.getAttribute('placeholder');
  191. if (translations[text]) {
  192. el.setAttribute('placeholder', translations[text]);
  193. }
  194. });
  195. // Перевод aria-label
  196. document.querySelectorAll('[aria-label]').forEach(el => {
  197. const text = el.getAttribute('aria-label');
  198. if (translations[text]) {
  199. el.setAttribute('aria-label', translations[text]);
  200. }
  201. });
  202. }
  203.  
  204. function translateCopilotPreview() {
  205. // Замена «Ask Copilot»
  206. const askCopilotPlaceholder = document.querySelector('.copilotPreview__input[placeholder="Ask Copilot"]');
  207. if (askCopilotPlaceholder) {
  208. askCopilotPlaceholder.setAttribute('placeholder', 'Спросить Копайлота');
  209. }
  210.  
  211. // Предложения Копайлота
  212. document.querySelectorAll('.copilotPreview__suggestionButton div').forEach(div => {
  213. const text = div.textContent.trim();
  214. if (text === 'What is a hash table in JS?') {
  215. div.innerHTML = 'Что такое хэш-таблица в JS?';
  216. } else if (text === 'Email validation regex in JS') {
  217. div.innerHTML = 'Регулярное выражение для валидации адреса электронной почты в JS';
  218. } else if (text === 'Generate an HTML/JS calculator') {
  219. div.innerHTML = 'Напиши калькулятор на HTML/JS';
  220. } else if (text === 'How can you help?') {
  221. div.innerHTML = 'Как ты можешь помочь?';
  222. } else if (text === 'What are Python decorators?') {
  223. div.innerHTML = 'Что такое декораторы в Python?';
  224. } else if (text === 'Latest nodejs/node release') {
  225. div.innerHTML = 'Последний выпуск <span class="fgColor-muted">nodejs/node</span>';
  226. } else if (text === 'Rails authentication endpoint') {
  227. div.innerHTML = 'Точка аутентификации Rails';
  228. } else if (text === 'Pull requests in microsoft/vscode') {
  229. div.innerHTML = 'Запросы на слияние в <span class="fgColor-muted">microsoft/vscode</span>';
  230. } else if (text === 'Find issues assigned to me') {
  231. div.innerHTML = 'Найди назначенные на меня issues';
  232. } else if (text === 'Create a profile README for me') {
  233. div.innerHTML = 'Напиши README мне для профиля';
  234. } else if (text === 'Python Panda data analysis') {
  235. div.innerHTML = 'Анализ данных с помощью Python и Panda';
  236. } else if (text === 'Open issues in facebook/react') {
  237. div.innerHTML = 'Открытые issues в <span class="fgColor-muted">facebook/react</span>';
  238. } else if (text === 'Recent bugs in primer/react') {
  239. div.innerHTML = 'Последние баги в <span class="fgColor-muted">primer/react</span>';
  240. } else if (text === 'My open pull requests') {
  241. div.innerHTML = 'Открытые мной запросы на слияние';
  242. } else if (text === 'Python password endpoint') {
  243. div.innerHTML = 'Точка пароля Python';
  244. } else if (text === 'Recent commits in <span class="fgColor-muted">torvalds/linux</span>') {
  245. div.innerHTML = 'Последние правки в <span class="fgColor-muted">torvalds/linux</span>';
  246. } else if (text === 'What can I do here?') {
  247. div.innerHTML = 'Чем заняться?';
  248. }
  249. });
  250. }
  251.  
  252. function translateTooltips() {
  253. const commandPaletteTooltip = document.querySelector('tool-tip[for="AppHeader-commandPalette-button"]');
  254. if (commandPaletteTooltip && commandPaletteTooltip.textContent.trim() === 'Command palette') {
  255. commandPaletteTooltip.textContent = 'Палитра команд';
  256. }
  257.  
  258. const copilotChatTooltip = document.querySelector('tool-tip[for="copilot-chat-header-button"]');
  259. if (copilotChatTooltip && copilotChatTooltip.textContent.trim() === 'Chat with Copilot') {
  260. copilotChatTooltip.textContent = 'Поговорить с Копайлотом';
  261. }
  262.  
  263. const copilotOpenTooltip = document.querySelector('tool-tip[for="global-copilot-menu-button"]');
  264. if (copilotOpenTooltip && copilotOpenTooltip.textContent.trim() === 'Open Copilot…') {
  265. copilotOpenTooltip.textContent = 'Открыть Копайлот';
  266. }
  267.  
  268. const createNewTooltip = document.querySelector('tool-tip[for="global-create-menu-anchor"]');
  269. if (createNewTooltip && createNewTooltip.textContent.trim() === 'Create new...') {
  270. createNewTooltip.textContent = 'Создать новый…';
  271. }
  272.  
  273. document.querySelectorAll('tool-tip[role="tooltip"]').forEach(tooltip => {
  274. if (tooltip.textContent.trim() === 'Issues') {
  275. tooltip.textContent = 'Темы';
  276. }
  277. });
  278.  
  279. document.querySelectorAll('tool-tip[role="tooltip"]').forEach(tooltip => {
  280. if (tooltip.textContent.trim() === 'Pull requests') {
  281. tooltip.textContent = 'Запросы на слияние';
  282. }
  283. });
  284.  
  285. const unreadTooltip = document.querySelector('tool-tip[for="AppHeader-notifications-button"]');
  286. if (unreadTooltip && unreadTooltip.textContent.trim() === 'You have unread notifications') {
  287. unreadTooltip.textContent = 'У вас есть непрочитанные уведомления';
  288. }
  289.  
  290. document.querySelectorAll('tool-tip[role="tooltip"]').forEach(tooltip => {
  291. if (tooltip.textContent.trim() === 'Send') {
  292. tooltip.textContent = 'Отправить';
  293. }
  294. });
  295. }
  296.  
  297. function translateGitHubEducation() {
  298. const noticeForms = document.querySelectorAll('div.js-notice form.js-notice-dismiss');
  299.  
  300. noticeForms.forEach(form => {
  301. const heading = form.querySelector('h3.h4');
  302. if (heading && heading.textContent.trim() === 'Learn. Collaborate. Grow.') {
  303. heading.textContent = 'Учитесь. Кооперируйтесь. Развивайтесь.';
  304. }
  305.  
  306. const desc = form.querySelector('p.my-3.text-small');
  307. if (desc && desc.textContent.includes('GitHub Education gives you the tools')) {
  308. desc.textContent = 'GitHub Education предоставляет инструменты и поддержку сообщества, чтобы вы могли принимать технологические вызовы и превращать их в возможности. Ваше технологическое будущее начинается здесь!';
  309. }
  310.  
  311. const link = form.querySelector('.Button-label');
  312. if (link && link.textContent.trim() === 'Go to GitHub Education') {
  313. link.textContent = 'Перейти в GitHub Education';
  314. }
  315. });
  316. }
  317.  
  318. function translateFilterMenu() {
  319. const filterTranslations = {
  320. "Filter": "Фильтр",
  321. "Events": "События",
  322. "Activity you want to see on your feed": "Деятельность, которую вы хотите видеть в своей ленте",
  323. "Announcements": "Объявления",
  324. "Special discussion posts from repositories": "Особые обсуждения из репозиториев",
  325. "Releases": "Выпуски",
  326. "Update posts from repositories": "Новые обновления в репозиториях",
  327. "Sponsors": "Спонсоры",
  328. "Relevant projects or people that are being sponsored": "Проекты или люди, которых кто-то начинает спонсировать",
  329. "Stars": "Звёзды",
  330. "Repositories being starred by people": "Репозитории, которые получают звёзды от людей",
  331. "Repositories": "Репозитории",
  332. "Repositories that are created or forked by people": "Репозитории, созданные или разветвлённые пользователями",
  333. "Repository activity": "Деятельность в репозиториях",
  334. "Issues and pull requests from repositories": "Новые темы и запросы на слияние в репозиториях",
  335. "Follows": "Подписки",
  336. "Who people are following": "На кого подписываются пользователи",
  337. "Recommendations": "Рекомендации",
  338. "Repositories and people you may like": "Репозитории и пользователи, которые могут вам понравиться",
  339. "Include events from starred repositories": "Включать события из репозиториев, на которые вы поставили звезду",
  340. "By default, the feed shows events from repositories you sponsor or watch, and people you follow.": "По умолчанию лента отображает события из репозиториев, которые вы спонсируете или за которыми следите, а также от людей, на которых подписаны.",
  341. "Reset to default": "Сбросить до настроек по умолчанию",
  342. "Save": "Сохранить"
  343. };
  344.  
  345. const elements = document.querySelectorAll(
  346. '.SelectMenu-title, .SelectMenu-item h5, .SelectMenu-item span, .px-3.mt-2 h5, .px-3.mt-2 p'
  347. );
  348.  
  349. elements.forEach(el => {
  350. const text = el.textContent.trim();
  351. if (filterTranslations[text]) {
  352. el.textContent = filterTranslations[text];
  353. }
  354. });
  355. }
  356.  
  357. const observer = new MutationObserver(() => {
  358. translateTextContent();
  359. translateAttributes();
  360. translateCopilotPreview();
  361. translateTooltips();
  362. translateGitHubEducation();
  363. translateFilterMenu();
  364. });
  365.  
  366. // Наблюдение за всем документом, включая изменения атрибутов
  367. observer.observe(document, {
  368. childList: true,
  369. subtree: true,
  370. attributes: true
  371. });
  372.  
  373. translateTextContent();
  374. translateAttributes();
  375. translateCopilotPreview();
  376. translateTooltips();
  377. translateGitHubEducation();
  378. translateFilterMenu();
  379.  
  380. // Замена «Filter»
  381. document.querySelectorAll('summary .octicon-filter').forEach(icon => {
  382. const summary = icon.parentElement;
  383. if (summary) {
  384. summary.childNodes.forEach(node => {
  385. if (node.nodeType === Node.TEXT_NODE && node.textContent.trim() === 'Filter') {
  386. node.textContent = translations["Filter"];
  387. }
  388. });
  389. }
  390. });
  391. translateFilterMenu();
  392. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址