GreasyFork 中文

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

Per 12-06-2014. Zie de nieuwste versie.

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