添加简繁切换按钮

1.9k 3 mins
... ...

  今日成果:为 blog 添加了简繁转换按钮,请看页面右下角(手机请看左下角
  尝试用 Gemini 写代码的第一个 project,成果还算喜人,虽然过程很折磨但至少跑起来了!
  之前似乎说过很多遍要写用 GPT 写代码的笔记但一直没什么动力写,加之我现在已经不用 GPT 了,所以这篇 blog 里大概也会有一些拉踩的元素……

基础切换

  使用工具:opencc-js
  如果只是想进行一次性转换的话代码非常简单,只需要几行字:

1
2
3
4
const converter = OpenCC.Converter({ from: 'cn', to: 'tw' });
let textBefore = $('body').html();
let textAfter = converter(textBefore);
$('body').html(textAfter);

  这么写完以后最基础的转换功能就做好了,但由于我的 html 代码写得并不太规范,「body」这个元素里经常会包含一些临时的 JS 或 css,导致直接在 html 元素上使用转换器的时候网页的加载速度会变得巨⸺慢⸺
  于是我加入了一些小修改,让转换器只作用与基础的文本元素:

1
2
3
4
5
6
7
8
9
10
const converter = OpenCC.Converter({ from: 'cn', to: 'tw' });
const openccELM = $('p,h2,h3,h4,h5,ul,span');
$(document).ready(function() {
openccELM.each(function() {
let $this = $(this);
let textBefore = $this.html();
let textAfter = converter(textBefore);
$this.html(textAfter);
})
})

  如此操作之后一个最基础的单向转换功能就实现了,速度也还可以,理论上性能和之前做的标点缩进差不多,实际上就要取决于 openCC 本身的代码了,总之在台前看起来还是比较丝滑的。

插入一些吐槽

  用 Gemini 写代码的第一印象:你这个人,真是满脑子只想着自己呢.jpg
  和 GPT 比起来很明显的不同是,Gemini 完全不会管我自己写了什么⸺我用 5 行代码就实现了初始的简繁转换,扔给 Gemini 让它再给我加一个切换按钮,然后它把我写的东西全删了自顾自刷刷地写了几十行,这几十行之中还额外穿插着中英双语的注释,看得我一个头两个大。
  我:「基于我的代码修改,不要重写。」
  Gemini:「好的,以下是基于您的代码修改后的结果。」
  然后他把自己自顾自写的东西原封不动地又输出了一遍。
  XQZ me?
  虽然知道对 AI 扣问号没有任何作用但我当时的唯一想法果然还是扣一个问号:)

  最后加了如下的 System instructions,配合清空历史对话跑得还算比较顺畅了:

尽可能基于用户提交的代码修改,保留用户代码中的所有变量名;
使用中文注释;
当用户提交新代码时,根据最新的内容回答

追加功能

  说是追加功能好像不太准确,因为这个切换按钮其实是最开始设想的方案,只是因为遇到了一些 bug 所以一度被我放弃了。具体遇到什么 bug 下面细讲。
  以及我发现把代码扔给 AI 让他注释比我自己写效率得多,外加目前的 blog 主题没有代码高亮颜色看起来有点费劲,所以以后的笔记大概不会再写特别详细的注释了【

添加简繁切换按钮

  一开始我的设想是把简繁切换做进同一个函数里,页面加载完后先调用一次,点击按钮的时候再调用不同的参数。但后来发现「转换文字」这个操作本来就已经由 openCC 封装好了,存储原文和转换后的文本这个动作又不能和按钮绑定,所以最后的初版代码是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$(document).ready(function() {

openccELM.each(function() {
let $this = $(this);
let txtSC = $this.html();
$this.data('SC', txtSC);
let txtTC = converter(txtSC);
$this.data('TC', txtTC);
});
// 将原文与转换后的 html 都存储在 data 中
$('#convSC').on('click', function() {
openccELM.each(function() {
let $this = $(this);
$this.html($this.data('SC'));
});
console.log("切換爲簡體");
});
$('#convTC').on('click', function() {
openccELM.each(function() {
let $this = $(this);
$this.html($this.data('TC'));
});
console.log("切换为繁体");
});

});

  代码看起来没有问题,但实际操作的时候遇到了奇怪的 bug⸺不管点击哪个按钮,都只有第一个按钮的事件会生效,后续再怎么点就都没反应了。
  折腾了很久发现是使用 html() 方法替换的同时会移除掉按钮上的 listener,需要把 listener 绑定到不进行转换的元素上以避免这个问题:

1
2
3
4
5
6
7
8
$(document).on('click', '#convSC', function() {
// 监听整个 document,当其中 ID 为「#convSC」被点击时执行函数
openccELM.each(function() {
let $this = $(this);
$this.html($this.data('SC'));
});
console.log("切換爲簡體");
});

  繁体按钮以此类推,这么修改完之后便大功告成!

记忆全局简繁选项

  完成最初计划的功能之后感觉每刷新一个页面就要重新切换简繁体很蠢(说的就是你 wikipedia),于是我问 Gemini:「如何在刷新页面后继续保持当前的简繁设置?」
  以下是它给的代码,真的开箱即用,比 GPT 强多了真的……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$(document).ready(function() {

const STORAGE_KEY = 'languagePreference';
// 创建变量用于存储简繁设置
let currentState = 'TC';
// 设置默认状态
const savedState = localStorage.getItem(STORAGE_KEY);
if (savedState === 'SC' || savedState === 'TC') {
currentState = savedState;
}

openccELM.each(function() {
let $this = $(this);
let txtSC = $this.html();
$this.data('SC', txtSC);
let txtTC = converter(txtSC);
$this.data('TC', txtTC);
if (currentState === 'SC') {
$this.html(txtSC);
} else {
$this.html(txtTC);
}
});
$(document).on('click', '#convSC', function() {
openccELM.each(function() {
let $this = $(this);
$this.html($this.data('SC'));
});
localStorage.setItem(STORAGE_KEY, 'SC');
console.log("切換爲簡體");
});
// 繁体以此类推

依然存在的 bug

  切换简繁后右侧的目录激活似乎出了一点问题,一开始我以为和监听器是一样的问题,但每一篇的目录激活状态似乎都不一样,看起来需要加控制台输出慢慢研究……

  • 后续|看了下 dom 发现是简繁转换的时候把标题链接的 href 属性也一起转换了,哎这个要修复起来就很麻烦……我先开摆了……
  • 后续的后续|更新 blog 之前又看了一眼,发现标题的 id 是没有转换的,用标题 id 重新生成一遍链接就可以正常激活了,不愧是我!
  • 后续的后续的后续|救命这玩意怎么和 waline 的数据更新互相冲突,我不活了!
  • 堂堂完结!|修好了,不愧是我

总结

  和 Gemini 相处【?一段时间之后感觉它和 GPT 最大的不同就是它会频繁地否认用户提出的先决条件⸺它是有判断能力的擅自重写我的代码也是判断力的一环
  应该说不愧是依托搜索引擎起家的 AI,这份判断力大概会让他在处理客观问题的时候比 GPT 可靠不少,但相应地也需要做更多的提示词限定才能让它按照用户的节奏慢慢调整输出。
  但这个判断力感觉也不是什么技术上的革新,而是「先验」的依据不同。GPT 是根据用户提交的内容做验证的,而 Gemini 会更优先在自己的数据库里进行查询(比 GPT 更加耗费算力的做法)。感觉谷歌至少现阶段是想做一个生产力工具的,而不是像 GPT 一样停留在情感支持阶段做一个陪聊机器人?
  不过某天他觉得自己的模型发展到一定程度或许也会阉割免费用户的使用体验……那就能白嫖一天是一天吧【