User:SunAfterRain/js/HanAssist.js

From Meta, a Wikimedia project coordination wiki

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/* jshint esversion: 11 */
/**!
 * For license information, see [https://github.com/diskdance/HanAssist/blob/main/LICENSE].
 */
/*!
 * HanAssist v4.2.1-git-5f4e092-sunafterrainwm
 * Utilities to ease Chinese variant handling in user scripts and gadgets.
 * https://github.com/diskdance/HanAssist
 * 
 * Date: 2024-05-09T03:17:42.616Z
 *
 * @author diskdance <psnbaotg@protonmail.com>
 * @author sunafterrainwm <sunafterrainwm@gmail.com>
 * @license BSD 3-Clause
 */
// <nowiki>

(function (factory) {
	if (typeof module === 'object') {
		factory(module.exports);
	} else if (define === 'function' && define.amd) {
		define('HanAssist', ['exports'], factory);
	} else {
		const HanAssist = {};
		// mw.libs.HanAssist = HanAssist;
		factory(factory);
	}
})(function (exports) {
	'use strict';

	/**
	 * Safely convert an object to string.
	 * @param val value to convert
	 * @return string
	 */
	function safelyToString(val) {
		try {
			if (typeof val === 'undefined' || val === null) {
				return '';
			}
			return String(val);
		} catch {
			return Object.prototype.toString.call(val);
		}
	}
	function isPlainObject(val) {
		return $.isPlainObject(val);
	}

	const FALLBACK_LIST = {
		zh: ['zh', 'hans', 'hant', 'cn', 'tw', 'hk', 'sg', 'mo', 'my', 'other'],
		'zh-hans': ['hans', 'cn', 'sg', 'my', 'zh', 'hant', 'tw', 'hk', 'mo', 'other'],
		'zh-hant': ['hant', 'tw', 'hk', 'mo', 'zh', 'hans', 'cn', 'sg', 'my', 'other'],
		'zh-cn': ['cn', 'hans', 'sg', 'my', 'zh', 'hant', 'tw', 'hk', 'mo', 'other'],
		'zh-sg': ['sg', 'hans', 'cn', 'my', 'zh', 'hant', 'tw', 'hk', 'mo', 'other'],
		'zh-my': ['my', 'hans', 'cn', 'sg', 'zh', 'hant', 'tw', 'hk', 'mo', 'other'],
		'zh-tw': ['tw', 'hant', 'hk', 'mo', 'zh', 'hans', 'cn', 'sg', 'my', 'other'],
		'zh-hk': ['hk', 'hant', 'mo', 'tw', 'zh', 'hans', 'cn', 'sg', 'my', 'other'],
		'zh-mo': ['mo', 'hant', 'hk', 'tw', 'zh', 'hans', 'cn', 'sg', 'my', 'other'],
	};
	const DEFAULT_FALLBACK = ['other', 'zh', 'hans', 'hant', 'cn', 'tw', 'hk', 'sg', 'mo', 'my'];
	function elect(candidates, locale) {
		const fallback = FALLBACK_LIST[locale] ?? DEFAULT_FALLBACK;
		// Try every locale sequently
		for (const key of fallback) {
			const value = candidates[key];
			// Return if the value is neither null nor undefined
			if (value != null) {
				return value;
			}
		}
		return null;
	}
	/**
	 * A wrapper around `elect()` to ensure no non-string results are returned.
	 */
	function safeElect(candidates, locale) {
		// Guards to ensure types at runtime
		if (!isPlainObject(candidates)) {
			throw new TypeError('[HanAssist] Invalid parameter. Must be an object.');
		}
		if (typeof locale !== 'string') {
			mw.log.warn('[HanAssist] locale parameter must be a string. Please check your code.');
			locale = safelyToString(locale);
		}
		const result = elect(candidates, locale);
		if (typeof result !== 'string') {
			mw.log.warn('[HanAssist] Non-string conversion result detected. Please check your code.');
		}
		if (result === null) {
			return '';
		}
		// Wrap in another guard to ensure result is really string at runtime
		return safelyToString(result);
	}
	/**
	 * Select between candidates based on user language.
	 * @param candidates an object of candidates
	 * @param locale locale, defaults to `wgUserLanguage`
	 * @returns selected value
	 */
	function conv(candidates, locale = mw.config.get('wgUserLanguage')) {
		return safeElect(candidates, locale);
	}
	/**
	 * Select between candidates based on user variant.
	 * @param candidates an object of candidates
	 * @returns selected value
	 */
	function convByVar(candidates) {
		return safeElect(candidates, mw.config.get('wgUserVariant') ?? new URL(location.href).searchParams.get('variant') ?? mw.user.options.get('variant'));
	}
	/**
	 * Perform selection for each item in a candidates dictionary.
	 * @param candidatesDict the dictionary of candidates
	 * @param locale locale, defaults to `wgUserLanguage`
	 * @returns converted candidates dictionary
	 */
	function batchConv(candidatesDict, locale = mw.config.get('wgUserLanguage')) {
		if (!isPlainObject(candidatesDict)) {
			throw new TypeError('[HanAssist] Invalid parameter. Must be an object.');
		}
		const result = {};
		for (const key in candidatesDict) {
			const candidates = candidatesDict[key];
			const electionResult = isPlainObject(candidates)
				? safeElect(candidates, locale)
				: safelyToString(candidates);
			result[key] = electionResult;
		}
		return result;
	}

	function uxsShim(locale, hans, hant, cn, tw, hk, sg, zh, mo, my) {
		try {
			return elect({
				hans, hant, cn, tw, hk, sg, zh, mo, my,
			}, locale);
		} catch {
			return undefined;
		}
	}
	function generateUxsShim(configName) {
		return (hans, hant, cn, tw, hk, sg, zh, mo, my) => uxsShim(mw.config.get(configName), hans, hant, cn, tw, hk, sg, zh, mo, my);
	}

	function safeDeprecate(root, name, func, replacement) {
		try {
			mw.log.deprecate(root, name, func, `Use ${replacement} instead.`);
		} catch {
			// ignore duplicate definition
		}
	}

	exports.batchConv = batchConv;
	exports.conv = conv;
	exports.convByVar = convByVar;
	
	let isShimmed = false;
	function shimUXS() {
		if (isShimmed) {
			return;
		}
		isShimmed = true;

		// Compatibility: redirect wgULS, wgUVS and wgUXS calls to HanAssist implementation
		safeDeprecate(self, 'wgULS', generateUxsShim('wgUserLanguage'), 'HanAssist.conv');
		safeDeprecate(self, 'wgUVS', generateUxsShim('wgUserVariant'), 'HanAssist.convByVar');
		safeDeprecate(self, 'wgUXS', uxsShim, 'HanAssist.conv');
	}

	// Compatibility: redirect HanAssist <= v3 calls to v4
	const globalMountPoint = (mw.libs.HanAssist = mw.libs.HanAssist || {});
	safeDeprecate(globalMountPoint, 'localize', conv, 'conv');
	safeDeprecate(globalMountPoint, 'vary', convByVar, 'convByVar');
	safeDeprecate(globalMountPoint, 'parse', batchConv, 'batchConv');

	exports.batchConv = batchConv;
	exports.conv = conv;
	exports.convByVar = convByVar;
	exports.shimUXS = shimUXS;

	mw.hook('userscript.SunAfterRain.HanAssist.ready').fire(exports);
});
// </nowiki>