// ==UserScript==
// @name GreasyFork 中文
// @namespace http://jixun.org/
// @description 实验性脚本, 尚有内容未翻译完毕。
// @include https://greasyfork.org/*
// @version 1.1.1
// @run-at document-start
// @grant none
// ==/UserScript==
var translation = {
// Links
'a': {
'Back': '返回',
'Post a new script': '提交新脚本',
'Attach a file': '上传附件'
},
'h1,h2,h3': {
'Scripts': '脚本',
'Recent Discussions': '近期讨论',
'Comparing versions': '脚本更新内容查询',
// 论坛
'Comments': '吐槽',
'Leave a Comment': '发表回复'
},
// 右上角 - 搜索框
'#script-search': {
'Search': '搜索脚本'
},
// 右上角导航条
'#main-header>nav': {
'Scripts': '脚本列表',
'Forum': '论坛',
'Help': '帮助',
'Search': '搜索脚本'
},
// 用户页面 - 控制面板
'#control-panel': {
'Control panel': '控制台',
'Post a script': '提交脚本',
'Import scripts': '批量导入脚本',
'Set up a GitHub webhook': '设定 GitHub WebHook (自动更新)',
'Edit account': '更改账户信息',
'Sign out': '登出系统'
},
// 用户页面 - 讨论组
'#user-discussions-on-scripts-written': {
__regex: [
[/(\d+) minutes? ago/, '发表于 $1 分钟前'],
[/(\d+) hours? ago/, '发表于 $1 小时前'],
[/(\d+) days? ago/, '发表于 $1 天前']
],
'Discussions on your scripts': '您的脚本讨论帖 ',
'More discussions': '> 点我查看更多讨论贴',
', last comment by': ',最后评论由 ',
'by': ' 由 ',
},
// 用户页面 & 检索页面 的脚本列表
'.script-list': {
__regex: [
[/(\d+) minutes? ago/, '$1 分钟前'],
[/(\d+) hours? ago/, '$1 小时前'],
[/(\d+) days? ago/, '$1 天前']
],
'Author': '脚本作者',
'Daily installs': '今日安装',
'Total installs': '安装总数',
'Created': '创建日期',
'Updated': '更新日期',
'(Deleted)': '(已删)',
'(Locked)': '(锁定)'
},
// 脚本检索页 - 排序
'#script-list-sort': {
'Daily installs': '今日安装',
'Total installs': '安装总数',
'Sort by:': '排序方式: ',
'Created date': '创建日期',
'Updated date': '更新日期',
},
// 脚本检索页 - 过滤
'#script-list-filter': {
'Showing:': '显示: ',
'All': '所有脚本',
'(All sites)': '(全部网站)',
'More...': '更多…',
'Search': '搜索',
'Applies to': '应用于',
'All sites': '所有站点'
},
// 翻页
'.pagination': {
'← Previous': '← 上一页',
'Next →': '下一页 →'
},
// 脚本信息页 - 导航标签
'#script-links': {
__regex: [
[/Feedback \((\d+)\)/, '反馈与吐槽 ($1)'],
],
'Info': '脚本信息',
'Code': '参阅源码',
'History': '更新历史',
'Update': '更新脚本',
'Sync': '同步',
'Delete': '删除脚本',
'Undelete': '取消删除',
},
// 脚本信息页 - 脚本简介
'#script-content': {
'Install this script': '安装该脚本',
'Version': '版本',
'Author': '作者',
'Daily installs': '今日安装',
'Total installs': '安装总数',
'Created': '创建日期',
'Updated': '更新日期',
'License': '脚本授权',
'N/A': '未知',
'Applies to': '脚本运行于下述站点',
'Author\'s Description': '脚本详细描述',
'Diff': '查询更改',
'Old:': '旧版:',
'New:': '新版:',
'Lines of context:': '对比差异行数:',
'Refresh': '重新对比'
},
// 脚本更新页 - 代码规则
'#script-content>p': {
'Scripts must be': '请注意: 您所上传的脚本应',
'properly described': '代码、思路清晰',
', cannot be': ',不得',
'obfuscated': '加密',
'or': '或',
'minified': '压缩',
', must respect': ',必须尊重第三方',
'copyright': '版权',
', and are limited in the': ',以及确保引用的',
'external code': '外部代码',
'used.': '不在白名单之外。',
'Read the full rules.': '查阅完整脚本发布规则 (英文)'
},
// 脚本更新页 - 代码发布框
'#script-content>#new_script_version': {
'Code': '提交代码',
'Or upload:': '或直接上传:',
'Script type': '脚本类型',
'Changelog': '更新日志',
'What\'s changed in this version?': '新版本更新了什么?',
// 脚本类型
'Public user script - A user script for all to see and use.': '公开用户脚本 - 所有用户均可视及安装、更新',
'Unlisted user script - A user script for (semi-)private use. Available by direct access, but not linked to from anywhere on Greasy Fork.': '私用脚本 - 私用脚本,仅限拥有链接的用户可以访问 (不需要登录)。',
'Library - A script intended to be @require-d from other scripts and not installed directly.': '脚本库 - 用于第三方 @require 引用',
'Additional info': '脚本详细描述',
'Ramble on about your script.': '脚本的那点事',
'Preview': '预览',
'Post new version': '发布新版'
},
// Feedback 标签页
'#no-discussions': {
'No discussions posted yet.': '尚无该脚本相关评论,',
'Be the first to discuss this script.': '戳我抢下第一贴!',
'Start a new discussion on this script.': '想吐槽?点我发布到论坛~'
},
// 用户信息 - 更改页
'#edit_user': {
'Name': '用户名',
'Email': '邮件',
'Profile': '个人信息',
'Preview': '预览',
'Password': '密码',
'(Leave blank if you don\'t want to change it)': '(如果不想更改请留空)',
'Password confirmation': '密码确认',
'Current password': '当前密码',
'(We need your current password to confirm your changes)': '(请输入当前密码确认信息更新)',
'Update': '更新'
},
// 论坛 - 右上角搜索框
'.SiteSearch': {
'Search': '搜索论坛'
},
// 论坛 - 上方导航
'.SiteMenu': {
'Discussions': '讨论区',
'Activity': '论坛动态',
'Mark All Viewed': '全部标为已阅'
},
// 论坛 - 发帖按钮
'.Button': {
'New Discussion': '发表新帖',
'Preview': '预览',
'Save Draft': '储存草稿',
'Post Comment': '发表回复'
},
// 论坛 - 左边过滤
'.BoxFilter': {
'Categories': '论坛板块',
'Recent Discussions': '近期讨论',
'Activity': '论坛活动',
'My Discussions': '我的帖子',
'My Drafts': '我的草稿',
'Discussions': '帖子',
'Comments': '帖子回应'
},
// 论坛 - 板块名称
'.BoxCategories,.Meta>.Category': {
'Categories': '论坛板块',
'All Categories': '所有板块',
'Greasy Fork Meta': '站点相关',
'Script Development': '脚本开发',
'Script Requests': '脚本请求',
'Script Discussions': '脚本讨论'
},
// 论坛 - 帖子操作
'.OptionsMenu': {
'Edit': '编辑',
'Delete': '删除'
},
// 论坛 - 其他
'.Meta': {
__regex: [
[/edited(.+)/, '最后编辑于$1']
],
'Announcement': '公告',
'views': ' 次围观',
'comments': ' 个吐槽',
'comment': ' 个吐槽',
'Most recent by': '最新吐槽 by '
},
// 论坛 - 帖子链接
'.MItem': {
'in': '发布于 ',
'Flag': '举报',
'Quote': '引用'
},
// 论坛 - 菜单
'.MenuItems': {
'Preferences': '首选项',
'Mark All Viewed': '全部标为已阅',
'Sign Out': '登出论坛'
},
// 论坛 - 私信按钮
'.ProfileOptions': {
'Message': '私信'
},
// 论坛 - 各类窗口
'.PopList': {
__regex: [
[/(\d+) messages?/, '$1 条内容']
],
'Notifications': '通知',
'Notification Preferences': '设定',
'mentioned you in': ' 提到你:',
'All Notifications': '所有通知',
'Inbox': '私信',
'New Message': '撰写私信',
'All Messages': '所有私信'
}
};
var _each = function (arr, eachCb, defValue) {
if (!arr || !arr.length) return ;
for (var i = arr.length, ret; i-- ; )
// If there's something to return, then return it.
if (ret = eachCb (arr[i], i))
return ret;
return defValue ;
};
var doesNodeMatch = (function (doc) {
var matches = doc.matches || doc.mozMatchesSelector || doc.oMatchesSelector || doc.webkitMatchesSelector;
return matches ? function (what, selector) {
return matches.call (what, selector);
} : function () {
// No matche selector :<
return false;
};
}) (document.documentElement);
// 寻找翻译
var findTranslation = function (domSelector, origionalContent) {
// Not string or undefined etc.
if (!origionalContent) return null;
var tmpNodeContent = origionalContent.trim(),
translatedContent = translation[domSelector][tmpNodeContent];
// Empty string.
if (!tmpNodeContent) return origionalContent;
// Language string match!
if (translatedContent) return translatedContent;
// Check weather it has regex matches.
if (!translation[domSelector].hasOwnProperty('__regex')) return null;
// Check regex match.
return _each (translation[domSelector].__regex, function (regex) {
if (regex[0].test (tmpNodeContent))
return String.prototype.replace.apply (tmpNodeContent, regex);
});
};
var fixInput = function (domSelector, inputDom) {
// 搜索框
if (translatedContent = findTranslation(domSelector, inputDom.getAttribute ('placeholder') || ''))
inputDom.setAttribute ('placeholder', translatedContent);
// 提交按钮
if (translatedContent = findTranslation(domSelector, inputDom.value || ''))
inputDom.value = translatedContent;
};
var translateNode = function (domSelector, domNode) {
// Fix input element
if (domNode.nodeName == 'INPUT') {
fixInput (domSelector, domNode);
return ;
}
// Loop through all text nodes:
// http://stackoverflow.com/a/2579869/3416493
var walker = document.createTreeWalker(domNode, NodeFilter.SHOW_TEXT, null, false),
node, translatedContent;
// Loop through text nodes.
while (node = walker.nextNode())
if (translatedContent = findTranslation (domSelector, node.nodeValue))
node.nodeValue = translatedContent;
// Loop through inputs.
_each (domNode.getElementsByTagName ('input'), fixInput.bind({}, domSelector));
};
var translateContent = function (domSelector, base) {
_each (base.querySelectorAll (domSelector), translateNode.bind({}, domSelector));
};
var cbTranslate = function (base) {
for (var x in translation) {
if (translation.hasOwnProperty (x)) {
if (doesNodeMatch (base, x)) {
translateNode (x, base);
} else {
translateContent (x, base);
}
}
}
};
var mo = new MutationObserver (function (m) {
_each (m, function (q) {
_each (q.addedNodes, function (e) {
// Ignore firebug
if (e.className.indexOf ('firebug') != -1) return ;
cbTranslate (e);
});
});
});
mo.observe (document, {
childList: true,
subtree: true
});
addEventListener ('DOMContentLoaded', function () {
cbTranslate (document.body);
}, false);