维基百科:HanAssist

HanAssist
描述处理中文变体消息的实用程序
作者Diskdance
版本4.0.2
原始码Gadget-HanAssist.js
GitHub仓库GitHub上的HanAssist页面

HanAssist是帮助中文维基百科上的用户脚本和小工具更优雅地处理中文变体消息的实用程序。本程序是wgULSwgUVS的替代品。

迁移指南

以下为迁移方式:

小工具迁移方式
旧版用法 新版用法
wgULS( '简体', '繁体' );
先添加对ext.gadget.HanAssist的依赖,然后:
const { conv } = require( 'ext.gadget.HanAssist' );
conv( { hans: '简体', hant: '繁体' } );
wgUVS( '简体', '繁体' );
先添加对ext.gadget.HanAssist的依赖,然后:
const { convByVar } = require( 'ext.gadget.HanAssist' );
convByVar( { hans: '简体', hant: '繁体' } );
用户脚本迁移方式
旧版用法 新版用法
wgULS( '简体', '繁体' );
mw.loader.using( 'ext.gadget.HanAssist' ).then( ( require ) => {
	const { conv } = require( 'ext.gadget.HanAssist' );
    conv( { hans: '简体', hant: '繁体' } );
    
    // 建议将小工具代码置于此块中
} );
wgUVS( '简体', '繁体' );
mw.loader.using( 'ext.gadget.HanAssist' ).then( ( require ) => {
	const { convByVar } = require( 'ext.gadget.HanAssist' );
    convByVar( { hans: '简体', hant: '繁体' } );
    
    // 建议将小工具代码置于此块中
} );

为什么使用HanAssist?

wgULS()wgUVS()自其部署十多年来,极大方便了中文变体消息的处理。但随着JavaScript的发展,它们的问题也逐渐显现:

  1. 仍然使用旧式的wgXXX类名称,污染全局空间。现今MediaWiki中的此类变量全部通过mw.config.get()获取,但这两个函数并未也无法跟进。
  2. 使用意义不明的缩写,影响代码可读性。
  3. 参数列表过长,影响阅读。设计良好的JavaScript函数最多仅应包含两个参数。设想一下,如果像这样调用wgULS()
    wgULS( undefined, undefined, '显示%s的用户日志', '顯示%s的使用者日誌', '顯示%s的用戶日誌' );
    
    难道不会使代码非常难以阅读及维护?
  4. 并非类型安全。wgULS()wgUVS()允许任何类型的参数传入,这可能会导致非预期的行为发生,并且使得代码难以维护。
  5. 没有代码文档。这使得不了解这些函数的人必须通过直接阅读代码来确定它们的用法。

为了解决这些问题,我们制作了HanAssist。它具有如下优点:

  1. 不占用全局空间,利用ResourceLoader模块系统实现按需导入;
  2. 采用命名参数语法,显著提升代码可读性;
  3. 完善的代码文档及类型定义;
  4. 支持批量转译消息,在代码大量依赖中文变体消息时可极大减少代码复杂程度。

用法

在中文维基百科,HanAssist部署在小工具MediaWiki:Gadget-HanAssist.js中。

若要使用小工具,请在您的小工具定义中添加对HanAssist的依赖,亦或使用代码手动加载HanAssist:

// 小工具需要先添加对 ext.gadget.HanAssist 的依赖
const { conv, convByVar } = require( 'ext.gadget.HanAssist' );

// 也可动态加载
mw.loader.using( 'ext.gadget.HanAssist' ).then( ( require ) => {
	const { conv, convByVar } = require( 'ext.gadget.HanAssist' );
	// ...
} );

conv( { hans: '一天一苹果,医生远离我。', hant: '一天一蘋果,醫生遠離我。' } );
// => 界面语言为简中:“一天一苹果,医生远离我。”;繁中:“一天一蘋果,醫生遠離我。”

convByVar( { hans: '一天一苹果,医生远离我。', hant: '一天一蘋果,醫生遠離我。' } );
// => 页面变体为简中:“一天一苹果,医生远离我。”;繁中:“一天一蘋果,醫生遠離我。”

// 由于技术限制,如果 HanAssist 位于其他 wiki 上,那么函数将会导出到 mw.libs.HanAssist 全局空间
mw.loader.load( 'https://another.wiki/w/index.php?title=MediaWiki:Gadget-HanAssist.js&action=raw&ctype=text/javascript' );
// 按照如下方式使用:
// mw.libs.HanAssist.conv( ... );
// mw.libs.HanAssist.convByVar( ... );

conv()convByVar()

这两个函数分别替代wgULS()wgUVS()。它们的第一个参数为一个原型大致如下所示的对象:

interface Candidates {
	zh?: string, // 中文(不转换)消息
	hans?: string, // 简体中文消息
	hant?: string, // 繁體中文消息
	cn?: string, // 大陆简体消息
	tw?: string, // 台灣正體消息
	hk?: string, // 香港繁體消息
	mo?: string, // 澳門繁體消息
	my?: string, // 大马简体消息
	sg?: string, // 新加坡简体消息
	other?: string // 非中文语言(如英语)消息
}

两者的用法则如下所示:

const { conv, convByVar } = require( 'ext.gadget.HanAssist' );

// 等同于 wgULS( '一天一苹果,医生远离我。', '一天一蘋果,醫生遠離我。' );
conv( { hans: '一天一苹果,医生远离我。', hant: '一天一蘋果,醫生遠離我。' } );
// => 界面语言为简中:“一天一苹果,医生远离我。”;繁中:“一天一蘋果,醫生遠離我。”

// 等同于 wgULS( undefined, undefined, 'IP用户', 'IP使用者', 'IP用戶' );
conv( { cn: 'IP用户', tw: 'IP使用者', hk: 'IP用戶' } );
// => 界面语言为大陆简体:“一天一苹果,医生远离我。”;台灣正體:“一天一蘋果,醫生遠離我。”;香港繁體:“一天一蘋果,醫生遠離我。”

// 其他变体下则根据 fallback 链选择相应的消息
// 等同于 wgUVS( '一天一苹果,医生远离我。', '一天一蘋果,醫生遠離我。' );
convByVar( { hans: '一天一苹果,医生远离我。', hant: '一天一蘋果,醫生遠離我。' } );
// => 页面变体为简中:“一天一苹果,医生远离我。”;繁中:“一天一蘋果,醫生遠離我。”

// 配合占位符号使用。有关 mw.format 的用法详见 MediaWiki 文档
mw.format(
	conv( { hans: '页面$2的修订版本$1', hant: '頁面$2的修訂版本$1' } ),
	'123456',
	'Apple'
); // => 界面语言为简中:“页面Apple的修订版本123456”;繁中:“頁面Apple的修訂版本123456”

batchConv()

这是一个提供批量转译消息功能的函数。

const { batchConv } = require( 'ext.gadget.HanAssist' );

batchConv( {
	'article': { hans: '条目', hant: '條目' },
	'category': { hans: '分类', hant: '分類' },
	'categories': { hans: '分类', hant: '分類' },
	'image': { hans: '文件', hant: '檔案' },
	'images': { hans: '文件', hant: '檔案' },
	'minute': '分',
	'minutes': '分',
	'second': '秒',
	'seconds': '秒',
	'week': '周',
	'weeks': '周',
	'search': { hans: '搜索', hant: '搜尋' },
	'SearchHint': { hans: '搜索包含$1的页面', hant: '搜尋包含$1的頁面' },
	'web': { hans: '站点', hant: '站點' },
} ); // => { 'article': '条目', 'category': '分类', 'categories': '分类', ... }

大多数情况下,推荐配合mw.messages使用。

mw.messages.set( batchConv( {
	'article': { hans: '条目', hant: '條目' },
	'category': { hans: '分类', hant: '分類' },
	'categories': { hans: '分类', hant: '分類' },
	'image': { hans: '文件', hant: '檔案' },
	'images': { hans: '文件', hant: '檔案' },
	'minute': '分',
	'minutes': '分',
	'second': '秒',
	'seconds': '秒',
	'week': '周',
	'weeks': '周',
	'search': { hans: '搜索', hant: '搜尋' },
	'SearchHint': { hans: '搜索包含$1的页面', hant: '搜尋包含$1的頁面' },
	'web': { hans: '站点', hant: '站點' },
} ) );

mw.msg( 'categories' ); // => 界面语言为简中:“分类”;繁中:“分類”
mw.msg( 'SearchHint', 'Apple' ); // => 界面语言为简中:“搜索包含Apple的页面”;繁中:“搜尋包含Apple的頁面”

使用类型定义(.d.ts)文件

如果您的小工具使用TypeScript编写,那么,您可以将GitHub仓库根目录中的typings.d.ts文件复制至您的项目目录中。这样,您就可以获得完整的编译时类型检查。

局限

在软件领域,没有银弹,因此HanAssist也并非完美。在一些使用场景下,您应该使用其他更合适的工具而非HanAssist。

如果您的小工具或用户脚本需要多国语言支持,而非仅限于中文(汉语)一种,请考虑使用其他支持多语言处理的库,如jQuery.i18n

授权

本程序由Diskdance等制作,原始码采用3-Clause BSD License授权协议。