对JavaScript繁简字切换的小改进

简介: 繁简即时切换脚本属于比较普遍常见的脚本,多应用于港澳台的公司企业网站上,一些面向大陆服务的站点也提供正体、简体的页面切换(“正体”一词乃台湾方面的新说法)。在前人梳理的经验上,推荐这个 StranBody 方案。

繁简即时切换脚本属于比较普遍常见的脚本,多应用于港澳台的公司企业网站上,一些面向大陆服务的站点也提供正体、简体的页面切换(“正体”一词乃台湾方面的新说法)。在前人梳理的经验上,推荐这个 StranBody 方案。此方案是从客户端出发而考虑,是直接基于 JavaScript 对浏览器 DOM 内容修改的纯客户端方案,因此具有不依赖服务端转换,减轻服务端运算符合等的好处。当然,如果用户关闭掉 JavaScript 脚本,就无法使用正体、简体切换的功能了。直接使用该脚本毫无问题,亦兼容 IE & FireFox 浏览器,但美中不足的是,笔者个人感觉代码写得比较乱,当然这乃是较早期的实现,对JS认识不如今天的应用是可以理解的。现在恰好客户需求,笔者正好可将此代码派上项目用场,加上笔者自身亦一时技痒,就打算重构一番这个早期的繁简切换脚本,多练练手。

观察 在线演示地址代码IE6 & FF 3.0/Ext Core 3.2下通过,。 edit:2012.12.27 该文链接已失效

代码约定,true 的话表示正体中文(繁体中文),反之 false 就是简体中文。并且需要说明的是,当然脚本以默认“简体中文”的网站为假设,如果本来是正体中文的,就需要按如下修改脚本的原始值:

$$.big5.language = true; // true表示正体中文,反之false就是简体中文

经过重构,该模块的命名空间是 $$.big5.*(请注意命名空间的设置:if(typeof $$ == 'undefined')$$={};)。使用方法很简单,执行 init() 对其送入元素 id 或元素对象即可。该元素就是用来切换的按钮。

$$.big5.init('StranLink'); // 修改StranLink为你的元素标识

繁、简切换的原理在是,先准备一“繁、简”对照表,如私有成员“ var 简化中文 = '啊阿埃挨哎唉哀皑癌蔼矮艾碍爱隘鞍氨安俺……”和“var 正体中文 = '啊阿埃挨哎唉哀皚癌藹矮艾礙愛隘鞍氨安……”,他们之间是一一对应的,知道任意一种字符的索引即可查得另一种字符的编码;然后,字符串的索引如何怎么查得呢?可通过字符串的indeOf()。charAt()方法返回指定索引位置处的字符。这样,凭借此对照表,按照顺序逐一替换为他种语言。以上的实现编码在 $$.big5.traditionalized() 及 $$.big5.simplized()方法中。

如何得到那些要的翻译文本?遍历 DOM 是前台开发中经常使用的一点,一般而言通过递归遍历 DOM。这一次,我们又是从 document.body 收集需要转换的内容。虽然说的比较简单,但是实际还有不少需要考虑的细节问题。先看看这个递归函数。

/** * 转换对象,使用递归,逐层剥到文本 * @param {HTMLElement} obj 从document.body开始, */ function StranBody(obj){ var obj = obj.childNodes ,node; for (var i = 0, j = obj.length; i < j; i++) { node = obj.item(i); if (("||BR|HR|TEXTAREA|".indexOf("|" + node.tagName + "|")) > 0 || (node == $$.big5.el.dom)){ continue; } if(node.title){ node.title = $$.big5.fn(node.title); }else if(node.alt){ node.alt = $$.big5.fn(node.alt); }else if(node.tagName == "INPUT" && node.value != "" && node.type != "text" && node.type != "hidden"){ node.value = $$.big5.fn(node.value); }else if(node.nodeType == 3){ node.data = $$.big5.fn(node.data); } else{ arguments.callee(node); } } }

不知看官有没有稍加注意,我们采用 arguments.callee(node);的技巧实现匿名递归。

控制切换的UI是$$.big5.el,类型是 Ext.Element。我是为了避免烦恼的跨浏览器问题,使用上了 Ext Core 库。如果需要通用,用户可以很快的修改通过的 w3c 方案,不算太困难。Ext Core 方案如下:

$$.big5.el = Ext.get(el).on('click', function(e, el){ $$.big5.language = !$$.big5.language;// 反相器 toggle($$.big5.language); StranBody(document.body); });

cookie 是记录在客户端的可控对象,可以透过 JavaScript 编程来创建和取回 cookie 的值。每当同一台计算机通过浏览器请求某个页面时,就会发送这个 cookie。在本脚本中我们使用 Cookie 来记录用户选择了那一种语言,那么下一次客户离开页面再访问的时候,仍然可以转换到上一次选择的结果,无须用户手动设置。

设置Cookie,当按钮选择后发生。

// Sys.Big5.js 第53行 setCookie("ft" + window.location.hostname.replace(//./g, ""), b, 7);

每一次运行该脚本时都会执行下一行语句。如果用户从未选择过“繁体/简体”,那么这个方法总是返回 null 值。

// Sys.Big5.js 第96行 var c = getCookie("ft" + window.location.hostname.replace(//./g, ""));

至此,我们就对 StranBody 基本问题介绍了一遍。如果是原本的 StranBody 方案,那么到这儿就算结束了,——可如果马上结束就失去了本文的意义,尚有后面改进内容的介绍——

首先是重构后焕然一新的代码,从原来的全局变量重构为 JS 单例模式。表面上是这样,但其中最大变化的一点,可以说集中在 toggle() 函数中,从而避免源码混乱的状态管理。

/** * @param {Boolean} b True正体中文,false,简化中文 */ function toggle(b){ $$.big5.fn = b === true ? $$.big5.traditionalized : $$.big5.simplized; $$.big5.el.update(b === true ? "-》简体中文" : "-》繁体中文"); setCookie("ft" + window.location.hostname.replace(//./g, ""), b, 7); // 触发事件 if(b === true){ $$.big5.onBig5(); }else{ $$.big5.onSimpleChinese(); } }

JS的函数是第一要员,可灵活控制之。我们的$$.big5.fn正是这一种体现,无论是繁转简抑或是简转繁,反正调用$$.big5.fn即可!

其次,加入了事件$$.big5.onBig5、$$.big5.onSimpleChinese,那么等于增加了对图片和动画处理的手段了。我们重写这个两个方法就可以加入自定义的事件;还有依据浏览器的userLanguage自动选择繁体:

/** * 默认是否正体中文:true为正体;false简体。 * ASP版本:Request.ServerVariables("http_accept_language") * @return {Boolean} */ function getClientLanguage(){ var s = navigator.userLanguage||navigator.language; switch(s.toLowerCase()){ case 'zh-cn': return false; case 'zh-tw': return true; default: return null; } }

 

有人不免要问,为什么不写成属性而是方法。因为方法的写法可避免在服务端下JS的报错。

最后,就是一个对 StranBody 的小 Patch 修正了,虽然属于别人的劳动成果,但既然公开了,应该不碍事吧!?还是可以借用一下的^_^,原文如下:

对上面的程序进行测试,可以发现,对于有行内框架(IFRMIE)内的内容没有转换,对脚本输出文本即alert. confirrmn和prompt函数输出的内容也末作转换,还有网页标题也末作转换,这显然是很不完美的事。于是,经过一番探索,终于找到很好的办法解决了这两个问题。

在此基础我修改了一下,就是函数hijackFn():

function hackjackFn(){ var _alert = window.alert; window.alert = function(s){ _alert($$.big5.fn(s)); } var _confirm = window.confirm; window.confirm = function(s){ _confirm($$.big5.fn(s)); } var _prompt = window.prompt; window.prompt = function(s){ _prompt($$.big5.fn(s)); } }

总结今次学习过程,可以明白繁简翻译、Cookie 控制、RegExp.exec()等等的细节问题,从中收获不少。

 

在线例子:http://playen.ajaxjs.com/playen/blog/big5/

edit:2011-05-29 14:35:32重新上传,修正了例子的链接。

 

参见:  唐乾林,牟向宇,《JavaScript在网站中繁简字体转换的应用》。

目录
相关文章
|
2月前
|
JavaScript
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)
Node.js【GET/POST请求、http模块、路由、创建客户端、作为中间层、文件系统模块】(二)-全面详解(学习总结---从入门到深化)
27 0
|
2月前
|
消息中间件 Web App开发 JavaScript
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
Node.js【简介、安装、运行 Node.js 脚本、事件循环、ES6 作业队列、Buffer(缓冲区)、Stream(流)】(一)-全面详解(学习总结---从入门到深化)
74 0
|
8天前
|
JavaScript 前端开发 应用服务中间件
node.js之第一天学习
node.js之第一天学习
|
1月前
|
运维 JavaScript 前端开发
发现了一款宝藏学习项目,包含了Web全栈的知识体系,JS、Vue、React知识就靠它了!
发现了一款宝藏学习项目,包含了Web全栈的知识体系,JS、Vue、React知识就靠它了!
|
1月前
|
JavaScript
Vue.js学习详细课程系列--共32节(4 / 6)
Vue.js学习详细课程系列--共32节(4 / 6)
33 0
|
1月前
|
前端开发 搜索推荐 JavaScript
编程笔记 html5&css&js 001 学习编程从网页开始
编程笔记 html5&css&js 001 学习编程从网页开始
|
2月前
|
前端开发 JavaScript
从零开始学习前端开发:HTML、CSS、JavaScript入门指南
【2月更文挑战第1天】本文将带领读者从零开始学习前端开发,介绍HTML、CSS和JavaScript的基础知识与应用,帮助读者快速入门前端开发领域。
64 1
|
2月前
|
数据采集 机器学习/深度学习 JavaScript
画【Python折线图】的一百个学习报告(二、pyecharts引入js文件)
画【Python折线图】的一百个学习报告(二、pyecharts引入js文件)
51 0
|
2月前
|
JSON 前端开发 JavaScript
Webpack【Webpack图片处理、Webpack中proxy代理 、自动清理dist、Webpack优化、JavaScript中的代码检查】(三)-全面详解(学习总结---从入门到深化)
Webpack【Webpack图片处理、Webpack中proxy代理 、自动清理dist、Webpack优化、JavaScript中的代码检查】(三)-全面详解(学习总结---从入门到深化)
35 0
Webpack【Webpack图片处理、Webpack中proxy代理 、自动清理dist、Webpack优化、JavaScript中的代码检查】(三)-全面详解(学习总结---从入门到深化)
|
2月前
|
资源调度 JavaScript 关系型数据库
Node.js【文件系统模块、路径模块 、连接 MySQL、nodemon、操作 MySQL】(三)-全面详解(学习总结---从入门到深化)
Node.js【文件系统模块、路径模块 、连接 MySQL、nodemon、操作 MySQL】(三)-全面详解(学习总结---从入门到深化)
33 0