# 搭建个人网站（1）如何实现中英文切换与首页基础交互的

> 这是我个人网站开发过程中的第一篇 Building Note。
> 这篇笔记主要记录：首页的中英文切换功能、语言持久化、语言菜单交互，以及 Landing 区域到主内容区的平滑滚动逻辑。
> 当前网站使用 **HTML + CSS + JavaScript** 构建，未来计划逐步迁移到 **React / Next.js**。

------

## 一、动机

在开始做这个个人网站时，我并不希望它只是一个静态的“个人介绍页”或者“作品列表页”。

我更希望它能逐步成为一个真正属于自己的技术空间：

- 可以展示项目
- 可以记录学习过程
- 可以承载未来的 Notes / Blog
- 也可以体现我作为一名计算机科学学生的成长路径

而从表达角度来说，我平时的学习、课程、技术环境很多时候以英文为主，但中文依然是我最自然的思考和输出语言之一。

所以，让网站支持：

- **English**
- **简体中文**

是一个非常自然的决定。

同时，这也是我第一次在自己的项目里认真实现一个真正有“前端交互逻辑”的功能，而不仅仅是写静态页面。

------

## 二、当前网站技术栈

目前这个网站使用的是最基础、也最适合打基础的一套前端组合：

- **HTML**
- **CSS**
- **JavaScript**

------

## 三、中英文切换的核心思路

我当前实现中英文切换的方式，不是做两套页面，也不是从服务器请求不同语言版本，而是采用了一种非常轻量、适合个人网站的方式：

> **把两种语言都直接写在 HTML 元素上，再用 JavaScript 动态切换显示内容。**

核心做法是使用 HTML 自定义属性：

```html
<h2 data-en="About Me" data-zh="关于我">About Me</h2>
```

这里：

- `data-en` 表示英文文本
- `data-zh` 表示中文文本

然后 JavaScript 统一扫描所有拥有这两个属性的元素，再根据当前语言设置去替换显示内容。

这种方式的好处是：

- 实现简单
- 易于维护
- 很适合目前这种静态个人网站
- 未来也比较容易迁移到 React 思路

------

## 四、当前 HTML 结构中的语言组织方式

我在首页里几乎把所有用户可见文本都统一做了语言标记，例如导航栏：

```html
<a href="index.html" data-en="Home" data-zh="首页">Home</a>
<a href="about.html" data-en="About" data-zh="关于">About</a>
<a href="https://project.jeremy-tan.com" data-en="Projects" data-zh="项目">Projects</a>
<a href="contact.html" data-en="Contact" data-zh="联系">Contact</a>
<a href="#" target="_blank" data-en="Notes" data-zh="笔记">Notes</a>
```

Landing 区域：

```html
<span data-en="Hi, I’m Jeremy Tan." data-zh="你好，我是 Jeremy Tan。">
    Hi, I’m Jeremy Tan.
</span>

<span data-en="A Computer Science student." data-zh="一名计算机科学学生。">
    A Computer Science student.
</span>
```

以及按钮文本：

```html
<span class="scroll-text"
      data-en="View More"
      data-zh="查看更多">
    View More
</span>
```

甚至 Hero、About、Projects、Notes、Footer 等区域，也都统一使用了这种方式。

这说明当前这套方案并不是“临时拼出来的”，而是已经具备了一个比较明确的语言组织结构。

------

## 五、`main.js` 中的核心语言切换逻辑

当前实现语言切换的核心函数是：

```js
function setLanguage(lang) {
    const elements = document.querySelectorAll("[data-en][data-zh]");

    elements.forEach((element) => {
        // 根据传入的 lang（"en" 或 "zh"）去取对应的 data-en 或 data-zh 内容
        const translatedText = element.getAttribute(`data-${lang}`);

        // 若成功取到文本，就替换页面显示内容
        if (translatedText) {
            element.textContent = translatedText;
        }
    });

    // 把用户选择的语言存到浏览器本地，下次刷新页面时，还能记住用户上次选的是哪种语言
    localStorage.setItem("language", lang);

    // 同步修改 <html lang="..."> 属性，对浏览器、搜索引擎和无障碍访问（accessibility）更规范
    document.documentElement.lang = lang;

    if (languageDropdown) {
        languageDropdown.classList.remove("show");
    }
}
```

这个函数其实做了四件非常重要的事。

------

### 1. 选中所有可翻译元素

```js
const elements = document.querySelectorAll("[data-en][data-zh]");
```

这句的意思是：

> 找出页面中所有同时拥有 `data-en` 和 `data-zh` 的元素。

这是一种非常干净的选择方式，因为它不依赖某个 class 名称，而是直接用“有没有语言数据”来决定是否属于翻译系统。

这比手动一个个写：

```js
document.querySelector(".title")
document.querySelector(".subtitle")
document.querySelector(".nav-link")
```

要更统一，也更可扩展。

------

### 2. 根据语言动态读取属性内容

```js
const translatedText = element.getAttribute(`data-${lang}`);
```

如果传入的是：

```js
setLanguage("en")
```

那它读取的就是：

```html
data-en="..."
```

如果传入的是：

```js
setLanguage("zh")
```

那它读取的就是：

```html
data-zh="..."
```

这其实就是一种非常轻量的“本地翻译字典系统”。

虽然不是 React/Vue 那种正式 i18n 方案，但对于当前阶段来说已经足够清晰。

------

### 3. 动态更新页面文本

```js
element.textContent = translatedText;
```

这一步就是直接修改 DOM 中该元素显示的文本内容。

也就是说，中英文切换的本质不是“重新加载页面”，而是：

> **在同一个页面里，动态替换当前显示的文本。**

这就是典型的前端动态交互逻辑。

------

### 4. 保存语言偏好

```js
localStorage.setItem("language", lang);
```

这一句非常关键。

因为如果没有它，用户每次刷新页面，语言都会回到默认值。

有了它之后，浏览器就会记住用户上一次选择的是：

- 英文
- 还是中文

这会让整个网站显得更像一个“完整产品”，而不是一个只有表层视觉的静态练习页。

------

## 六、页面加载时的语言初始化

除了切换逻辑本身，我还实现了“页面打开时自动恢复语言设置”的初始化逻辑：

```js
document.addEventListener("DOMContentLoaded", () => {
    // 从 localStorage 中读取之前保存的语言设置
    const savedLanguage = localStorage.getItem("language");

    // 如果之前有保存过语言，就用保存的语言，否则默认使用英语 "en"
    const defaultLanguage = savedLanguage || "en";

    setLanguage(defaultLanguage);
});
```

这段代码的作用是：

1. 等页面 HTML 加载完成后再执行
2. 检查浏览器本地是否已经保存过语言设置
3. 如果保存过，就恢复之前的语言
4. 如果没有，就默认使用英文

这一步的意义在于：

> 网站的语言切换不只是“当下有效”，而是具有“记忆性”。

这是一个小细节，但非常影响体验。

------

## 七、语言切换按钮与下拉菜单交互

当前语言切换器不是直接放两个按钮平铺，而是做成了一个右上角的 🌐 下拉菜单。

对应代码：

```js
const languageBtn = document.getElementById("languageBtn");
const languageDropdown = document.getElementById("languageDropdown");
```

### 1. 点击按钮时展开 / 收起菜单

```js
if (languageBtn) {
    languageBtn.addEventListener("click", () => {
        languageDropdown.classList.toggle("show");
    });
}
```

这里用到了：

```js
classList.toggle("show")
```

意思是：

- 如果当前没有 `show` 类，就加上
- 如果当前已经有 `show` 类，就移除

这是一种很经典的前端 UI 状态切换写法。

------

### 2. 点击页面其他区域时自动关闭菜单

```js
document.addEventListener("click", (event) => {
    if (
        languageBtn &&
        languageDropdown &&
        !languageBtn.contains(event.target) &&
        !languageDropdown.contains(event.target)
    ) {
        languageDropdown.classList.remove("show");
    }
});
```

这一段的逻辑是：

> 如果点击的位置既不在按钮上，也不在菜单内部，就自动关闭下拉菜单。

这是非常标准的“点击外部关闭（click outside to close）”交互模式。

这个功能虽然不复杂，但很有意义，因为它让我第一次比较明确地意识到：

> 前端开发不仅是“让页面显示出来”，还包括如何让页面行为符合用户预期。

------

## 八、Landing 区域与首页主体内容的交互

除了语言切换，我首页还有一个很重要的小交互：

> Landing 区域的 “View More / 查看更多” 按钮，会平滑滚动到主页主体内容区。

对应代码如下：

```js
function scrollToContent() {
    const section = document.getElementById("main-content");

    if (section) {
        section.scrollIntoView({
            behavior: "smooth"
        });
    }
}
```

HTML 中对应按钮：

```html
<button class="scroll-down" onclick="scrollToContent()">
    <span class="scroll-text"
          data-en="View More"
          data-zh="查看更多">
        View More
    </span>
    <span class="scroll-icon">⬇️</span>
</button>
```

这个设计背后的目的不是“单纯为了酷”，而是为了让首页结构更有层次：

### Landing 区域的作用

- 制造第一印象
- 展示个人定位
- 提供视觉吸引力

### Main Content 的作用

- 承载真正的信息内容
- 展示 About / Projects / Notes 等模块

通过平滑滚动，这两个区域被自然连接起来，首页就不会显得像一个普通的“信息堆叠页”。

------

## 九、当前这套写法为什么对未来迁移 React 很友好？

这是我在开发时非常在意的一点。

我并不希望现在写的这套代码未来全部推翻重来。
我更希望它能成为一个**过渡阶段的基础版本**。

而目前来看，这套结构其实是比较适合未来迁移到 React 的。

原因在于：

> 我当前的页面文本，本质上已经是“数据驱动”的，而不是完全写死在页面里的。

例如现在的写法：

```html
<span data-en="View More" data-zh="查看更多">View More</span>
```

未来在 React 中，很可能会变成：

```jsx
<span>{translations[lang].viewMore}</span>
```

它们的核心思想其实是一样的：

### 当前版本

- JavaScript 手动更新 DOM

### React 版本

- React 根据状态自动重新渲染 DOM

所以说，我现在这套网站并不是一个“做完就废掉的初学者页面”，而更像是：

> **一个从原生前端逐步过渡到现代前端框架的中间阶段项目。**

------

## 十、当前实现的优点

从现在回头看，这套方案有几个我认为比较值得保留的优点。

### 1. 简单、直接、低依赖

不需要：

- 第三方 i18n 库
- 复杂构建工具
- 前端框架

非常适合个人网站的第一版。

------

### 2. 语言逻辑统一

只要一个元素拥有：

```html
data-en="..."
data-zh="..."
```

它就自动进入语言切换系统。

这意味着后续继续扩展新页面时，思路非常统一。

------

### 3. 已经具备一定的“产品思维”

虽然只是一个小网站，但目前已经有了：

- 语言偏好持久化
- UI 下拉菜单交互
- 平滑滚动过渡
- 页面结构分层

这些东西说明它已经不是“只会摆内容”的静态页面，而是开始有一点产品化体验了。

------

## 十一、当前实现的局限与未来可优化点

当然，这套方案也有一些明显的局限。

------

### 1. `textContent` 会覆盖内部结构

当前切换语言时使用的是：

```js
element.textContent = translatedText;
```

这意味着如果未来某些文本变复杂，比如：

```html
<p>
  Hello <strong>Jeremy</strong>
</p>
```

那直接替换 `textContent` 可能会把内部结构一起抹掉。

这说明未来如果页面越来越复杂，可能需要升级成：

- `innerHTML`
- 或更正式的组件化渲染方案

不过在当前阶段，这个问题还不算严重。

------

### 2. 文案仍然分散在 HTML 中

虽然当前方案已经很整齐，但本质上文案还是分散在各个 HTML 元素里：

```html
data-en="..."
data-zh="..."
```

未来如果页面越来越多，这种方式维护起来会慢慢变累。

更高级一点的做法会是：

```js
const translations = {
  en: { ... },
  zh: { ... }
}
```

再由页面统一读取。

这其实也正是未来迁移到 React 时更自然的方向。

------

### 3. 当前还没有形成真正的 Notes / Blog 内容系统

现在首页里已经预留了：

- `Notes`
- `Notes / Blog`
- `Visit Notes`

这些入口，但内容系统本身还没有真正建起来。

也就是说：

> 页面结构已经在等内容，但内容生态还需要慢慢补齐。

而这篇 Building Note，正好就是第一步。

------

## 十二、这次开发让我真正学到的东西

这次实现虽然看起来只是一个“小功能”，但它让我第一次比较真实地体会到前端开发的几个关键点：

### 1. 前端不是“写页面”，而是“组织交互”

真正重要的不只是页面长什么样，而是：

- 用户点了会发生什么
- 状态如何变化
- 页面是否有一致性
- 行为是否符合直觉

------

### 2. 页面结构和行为逻辑应该分离

我开始更清楚地理解：

- **HTML** 负责结构
- **CSS** 负责样式
- **JavaScript** 负责行为

虽然这句话看起来很基础，但只有真正自己写过一个小系统后，才会更有感觉。

------

### 3. 小功能也可以成为未来架构的一部分

语言切换器看起来只是一个小按钮，但它背后其实已经包含了：

- 状态
- 事件
- DOM 更新
- 本地持久化
- 页面初始化
- 可扩展性

也就是说，哪怕只是一个小功能，只要你认真做，它也会自然带出很多真正有价值的前端知识。

------

## 十三、接下来我想继续做的事

这个网站现在只是第一阶段，后面我还想继续把它慢慢打磨成一个更完整的个人技术空间。

接下来比较明确想做的方向有：

-  增加 **Dark Mode（深色模式）**
-  优化 **移动端导航**
-  给语言切换器增加当前语言状态提示
-  开始真正搭建 **Notes / Blog 内容区**
-  继续整理更多 **Building Notes**
-  未来逐步迁移到 **React / Next.js**
-  把网站逐步发展成自己的技术档案库（personal knowledge archive）

我希望这个网站最终不仅仅是一个“展示结果”的地方，而是：

> **一个能够持续记录我如何学习、如何构建、如何成长的地方。**

------

## 结语

如果说这个网站是我个人技术空间的起点，那么这个中英文切换系统和首页交互逻辑，大概就是我第一次真正认真写下来的“前端功能”。

它不复杂，但它是一个很好的开始。

而我也希望未来回头看这篇笔记时，能看到的不只是一个小功能，而是一条很具体的成长路径：

> 从原生 HTML / CSS / JavaScript 开始，逐步走向更成熟的前端开发能力。

------

## 附：当前相关核心代码片段

### 语言切换核心函数

```js
function setLanguage(lang) {
    const elements = document.querySelectorAll("[data-en][data-zh]");

    elements.forEach((element) => {
        const translatedText = element.getAttribute(`data-${lang}`);

        if (translatedText) {
            element.textContent = translatedText;
        }
    });

    localStorage.setItem("language", lang);
    document.documentElement.lang = lang;

    if (languageDropdown) {
        languageDropdown.classList.remove("show");
    }
}
```

### 页面加载时恢复语言

```js
document.addEventListener("DOMContentLoaded", () => {
    const savedLanguage = localStorage.getItem("language");
    const defaultLanguage = savedLanguage || "en";
    setLanguage(defaultLanguage);
});
```

### Landing 按钮平滑滚动

```js
function scrollToContent() {
    const section = document.getElementById("main-content");

    if (section) {
        section.scrollIntoView({
            behavior: "smooth"
        });
    }
}
```
