維基百科: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授權協定。