GreasyFork 中文

实验性脚本, 尚有内容未翻译完毕。

اعتبارا من 13-06-2014. شاهد أحدث إصدار.

// ==UserScript==
// @name        GreasyFork 中文
// @namespace   http://jixun.org/
// @description 实验性脚本, 尚有内容未翻译完毕。
// @include     https://greasyfork.org/*
// @version     1.1.3
// @run-at      document-start
// @grant       none
// ==/UserScript==

var translation = {
	// Links
	'a': {
		'Back': '返回',
		'Post a new script': '提交新脚本',
		'Attach a file': '上传附件',
		'Rules for code posted on Greasy Fork': 'GF 站代码提交规则',
		'Rules for code including external scripts': 'GF 站外部脚本引用规则',
		'Baidu CDN': '百度 CDN (国内)',
		'开放静态文件 CDN': '七牛 CDN (国内)',
		'Next': '下一页',
		'Previous': '上一页',
		'More...': '更多…'
	},
	
	// Rules, from list or paragraph.
	'ul,ol,p': {
		'Scripts must include a description of what they do and may not do things unreasonably outside of this description. Users must know what a script will do before installing it.': '脚本必须包含一个脚本描述用于解释脚本的功能,并不得实现超出描述外的内容。用户必须在安装脚本之前明白脚本的用途。',
		'Code posted to this site may not be obfuscated or minified. Users be given the opportunity to inspect and understand a script before installing it.': '复制粘贴到该站的脚本不得为压缩或加密后的。用户拥有安装脚本前的代码的审查权。',
		'Your script must respect others\' copyrights. This includes the script itself and any resources (for example images) it uses. If you intend on using someone else\'s content, abide by their licensing terms or get their permission before doing so.': '您上传的脚本必须尊重他人的版权声明。这包括脚本本身以及其它第三方引用的数据 (如图片)。如果您使用了任何第三方内容,请务必按照其所属授权执行,或事先取得原作者授权。',
		'Use of external JavaScript is limited.': '您只能使用白名单内的脚本。'
	},

	'h1,h2,h3': {
		'Scripts': '脚本',
		'Recent Discussions': '近期讨论',
		'Comparing versions': '脚本更新内容对比',
		'A sample of our scripts': '脚本展览柜',
		'Daily installs': '每日安装统计',


		// 论坛
		'Comments': '评论',
		'Leave a Comment': '发表回复',
		'New Discussion about': '发表新贴,关于 ',
		'Recent Activity': '近期动态'
	},

	// 右上角 - 搜索框
	'#script-search': {
		'Search': '搜索脚本'
	},

	// 右上角导航条
	'#main-header>nav': {
		'Scripts': '脚本列表',
		'Forum': '论坛',
		'Help': '帮助',
		'Sign in': '登陆',
		'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)': '(锁定)',
		'(Library)': '(脚本库)'
	},

	// 脚本检索页 - 排序
	'#script-list-sort': {
		'Daily installs': '今日安装',
		'Total installs': '安装总数',
		'Sort by:': '排序方式: ',
		'Created date': '创建日期',
		'Updated date': '更新日期',
	},

	// 脚本检索页 - 过滤
	'#script-list-filter': {
		'Showing:': '显示: ',
		'All': '所有脚本',
		'(All sites)': '(全部网站)',
		'Search': '搜索',
		'Applies to': '应用于',
		'All sites': '所有站点'
	},

	// 翻页
	'.pagination': {
		'← Previous': '← 上一页',
		'Next →': '下一页 →'
	},

	// 脚本信息页 - 导航标签
	'#script-links': {
		__regex: [
			[/Feedback \((\d+)\)/, '反馈与吐槽 ($1)'],
		],
		'Info': '脚本信息',
		'Code': '参阅源码',
		'History': '更新历史',
		'Stats': '数据统计',
		'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': '脚本详细描述',
		
		// 数据统计
		'Date': '日期',
		'Installs': '安装计数',

		// 更新历史
		'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': '发表回复',
		'Post Discussion': '发帖',
		'Cancel': '取消',
		'Share': '分享'
	},

	// 论坛 - 项目标签
	'label.Form_Name': {
		'Discussion Title': '帖子名称'
	},

	// 论坛 - 左边过滤
	'.BoxFilter': {
		'Categories': '论坛板块',
		'Recent Discussions': '近期讨论',
		'Activity': '论坛活动',
		'Recent Activity': '近期动态',
		'Moderator 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': '公告',
		'Closed': '锁帖',
		'views': ' 次围观',
		'comments': ' 个吐槽',
		'comment': ' 个吐槽',
		'Most recent by': '最新吐槽 by '
	},

	// 论坛 - 帖子链接
	'.MItem': {
		'in': '发布于 ',
		'Flag': '举报',
		'Quote': '引用',
		'Comment': '吐槽'
	},

	// 论坛 - 近期动态
	'.Activity': {
		__regex: [
			[/and (\d+) others? joined./, ' 以及其它 $1 位加入论坛']
		],
		'and': ' 以及 ',
		'joined.': ' 加入论坛',
		'Write a comment': '写点什么吧,回车就能发送了哦',
		'changed his profile picture.': ' 更换了他的头像',
		'changed her profile picture.': ' 更换了她的头像'
	},

	// 论坛 - 菜单
	'.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': '所有私信'
	},
	
	// 论坛 - 发帖选项
	'.PostOptions': {
		'Item ID:': '脚本 ID: ',
		'No rating (just a question or comment)': ' 无评分 (询问问题或评论)',
		'Report script (malware, stolen code, or other bad things requiring moderator review)': ' 举报脚本 (恶意代码、抄袭代码或其它需要管理员审核的脚本 [有需要可 @JixunMoe])',
		'Bad (doesn\'t work)': ' 有问题 (网站改版? 脚本坏掉了?)',
		'OK (works, but could use improvement)': ' 能用 (但是可以做出一些改进)',
		'Good (works well)': ' 完美 (多称赞几句作者吧~)'
	}
};

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);