Skip to content

Commit

Permalink
docs: add chinese translation (#902)
Browse files Browse the repository at this point in the history
* config: add i18n

* docs: add chinese translation

* theming improvement for dropdown
  • Loading branch information
childrentime authored Mar 11, 2022
1 parent 607b994 commit 53c2f91
Show file tree
Hide file tree
Showing 27 changed files with 2,053 additions and 1 deletion.
10 changes: 9 additions & 1 deletion website/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ module.exports = {
onBrokenLinks: "throw",
onBrokenMarkdownLinks: "warn",
favicon: "img/favicon.ico",
i18n: {
defaultLocale: 'en',
locales: ['en', 'zh-CN'],
},
themeConfig: {
googleAnalytics: {
trackingID: "UA-65632006-3",
Expand Down Expand Up @@ -39,7 +43,11 @@ module.exports = {
docId: "support",
label: "Support Immer",
position: "right"
}
},
{
type: 'localeDropdown',
position: 'left',
},
]
},
footer: {
Expand Down
18 changes: 18 additions & 0 deletions website/i18n/zh-CN/docusaurus-plugin-content-docs/current.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"version.label": {
"message": "Next",
"description": "The label for version current"
},
"sidebar.Immer.category.Basics": {
"message": "基础",
"description": "The label for category Basics in sidebar Immer"
},
"sidebar.Immer.category.Advanced Features": {
"message": "高级",
"description": "The label for category Advanced Features in sidebar Immer"
},
"sidebar.Immer.category.Resources": {
"message": "资源",
"description": "The label for category Resources in sidebar Immer"
}
}
52 changes: 52 additions & 0 deletions website/i18n/zh-CN/docusaurus-plugin-content-docs/current/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
id: api
title: API 概览
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" class="horizontal bordered"></div>
</center>

| 导出名称 | 描述 | 章节 |
| --- | --- | --- |
| `(default)` | Immer 核心 API,通常命名为 `produce`: `import produce from "immer"` | [Produce](./produce.mdx) |
| `applyPatches` | 给定一个基本 state 或 draft,以及一组 patches ,应用 patches | [Patches](./patches.mdx) |
| `castDraft` | 将任何不可变类型转换为其可变对应物。这只是一个转换,实际上并没有做任何事情。 | [TypeScript](./typescript.mdx) |
| `castImmutable` | 将任何可变类型转换为其不可变对应物。这只是一个转换,实际上并没有做任何事情。 | [TypeScript](./typescript.mdx) |
| `createDraft` | 给定一个基本 state,创建一个可变 draft,任何修改都将被记录下来 | [Async](./async.mdx) |
| `current` | 给定一个 draft 对象(不必是对象的根结点),对 draft 的当前状态进行快照 | [Current](./current.md) |
| `Draft<T>` | 暴露的 TypeScript 类型以将不可变类型转换为可变类型 | [TypeScript](./typescript.mdx) |
| `enableAllPlugins()` | 启用下面提到的所有插件 | [Installation](./installation.mdx#pick-your-immer-version) |
| `enableES5()` | 启用对旧 JavaScript 引擎的支持,例如 Internet Explorer 和 React Native | [Installation](./installation.mdx#pick-your-immer-version) |
| `enableMapSet()` | 启用对 `Map``Set` 集合的支持。 | [Installation](./installation.mdx#pick-your-immer-version) |
| `enablePatches()` | 启用对 JSON patches 的支持 | [Installation](./installation#pick-your-immer-version) |
| `finishDraft` | 给定使用 `createDraft` 创建的 draft,冻结 draft 并生成并返回下一个不可变状态,该状态捕获所有更改 | [Async](./async.mdx) |
| `freeze(obj, deep?)` | 冻结可 draft 对象。返回原始对象。默认情况下浅冻结,但如果第二个参数为真,它将递归冻结。|
| `Immer` | 可用于创建第二个“immer”实例(暴露此实例中列出的所有 API)的构造函数,它不与全局实例共享其设置 |
| `immerable` | 可以添加到构造函数或原型的符号,表示 Immer 应该将类视为可以安全 draft的东西 | [Classes](./complex-objects.md) |
| `Immutable<T>` | 暴露的 TypeScript 类型以将可变类型转换为不可变类型 | |
| `isDraft` | 如果给定对象是 draft 对象,则返回 true | |
| `isDraftable` | 如果 Immer 能够将此对象变成 draft,则返回 true。这适用于:数组、没有原型的对象、以 `Object` 为原型的对象、在其构造函数或原型上具有 `immerable` 符号的对象 | |
| `nothing` | 可以从 recipe 返回的值,以指示应生成 `undefined` | [Return](./return.mdx) |
| `original` | 给定一个 draft 对象(不必是对象的根结点),返回原始状态树中相同路径的原始对象(如果存在) | [Original](./original.md) |
| `Patch` | 暴露的 TypeScript 类型,描述(反向)patches 对象的形状 | [Patches](./patches.mdx) |
| `produce` | Immer 的核心 API,也暴露为 `default` 导出 | [Produce](./produce.mdx) |
| `produceWithPatches` |`produce` 相同,但它不仅返回生成的对象,还返回一个由 `[result, patch, inversePatches]` 组成的元组 | [Patches](./patches.mdx) |
| `setAutoFreeze` | 启用/禁用递归的自动冻结。默认启用 | [Freezing](./freezing.mdx) |
| `setUseProxies` | 可用于禁用或强制使用 `Proxy` 对象。在提交错误报告时很有用。 | |

## 导入 immer

`produce` 作为默认导出,但也可以选择将其用作名称导入,因为这有利于一些较旧的项目设置。所以下面的导入都是正确的,这里推荐第一个:

```javascript
import produce from "immer"
import {produce} from "immer"

const {produce} = require("immer")
const produce = require("immer").produce
const produce = require("immer").default

import unleashTheMagic from "immer"
import {produce as unleashTheMagic} from "immer"
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
id: async
title: 异步 producers & createDraft / finishDraft
sidebar_label: 异步 produce / createDraft
---

<center>
<div
data-ea-publisher="immerjs"
data-ea-type="image"
className="horizontal bordered"
></div>
</center> <details>
<summary className="egghead-summary">
egghead.io 第11课: 创建<b>异步</b> producers(以及为什么不应该这样做)
</summary>
<br />
<div>
<iframe
width="760"
height="427"
scrolling="no"
src="https://egghead.io/lessons/react-write-asynchronous-producers-in-immer-and-why-you-shouldn-t/embed"
></iframe>
</div>
<a
className="egghead-link"
href="https://egghead.io/lessons/react-write-asynchronous-producers-in-immer-and-why-you-shouldn-t"
>
Hosted on egghead.io
</a>
</details>

允许从 recipe 返回 Promise 对象。或者,换句话说,使用 `async / await`。这对于长时间运行的进程非常有用,只有在 Promise 链解析后才生成新对象。请注意,如果 producer 是异步的,`produce` 本身(即使是柯里化形式)也会返回一个 promise。例子:

```javascript
import produce from "immer"

const user = {
name: "michel",
todos: []
}

const loadedUser = await produce(user, async function(draft) {
draft.todos = await (await window.fetch("http://host/" + draft.name)).json()
})
```

_警告:请注意,draft 不应从异步程序中“泄露”并存储在其他地方。异步过程完成后,draft 仍将被释放_

## `createDraft` and `finishDraft`

`createDraft``finishDraft` 是两个底层函数,它们对于在 immer 之上构建抽象的库非常有用。它避免了为了使用 draft 始终创建函数。相反,人们可以创建一个 draft,对其进行修改,并在未来的某个时间完成该 draft,在这种情况下,将产生下一个不可变状态。例如,我们可以将上面的示例重写为:


```javascript
import {createDraft, finishDraft} from "immer"

const user = {
name: "michel",
todos: []
}

const draft = createDraft(user)
draft.todos = await (await window.fetch("http://host/" + draft.name)).json()
const loadedUser = finishDraft(draft)
```

注意:`finishDraft` 以一个 `patchListener` 作为第二个参数,可以用来记录 patches,类似于 `produce`

_警告:一般情况下,我们建议使用 `producer` 而不是 `createDraft / finishDraft` 组合,`produce` 在使用中不易出错,并且在代码中更清楚地区分了可变性和不变性的概念。_
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
id: built-with
title: 基于 Immer
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" class="horizontal bordered"></div>
</center>

- [react-copy-write](https://github.com/aweary/react-copy-write) _具有可变 API 的不可变状态_
- [redux-toolkit](https://github.com/reduxjs/redux-toolkit) _官方的,opinionated,自带全套工具的效率 Redux 开发_
- [immer based handleActions](https://gist.github.com/kitze/fb65f527803a93fb2803ce79a792fff8) _Redux 自由动作脚手架_
- [redux-box](https://github.com/anish000kumar/redux-box) _模块化且易于掌握的基于 redux 的状态管理,样板代码最少_
- [quick-redux](https://github.com/jeffreyyoung/quick-redux) _使 redux 开发更快更容易的工具_
- [bey](https://github.com/jamiebuilds/bey) _使用 Immer 实现 React 的简单不可变状态_
- [cool-store](https://github.com/Maxvien/cool-store) _CoolStore 是建立在 ImmerJS 和 RxJS 之上的不可变状态存储_
- [immer-wieder](https://github.com/drcmda/immer-wieder#readme) _结合 React 16 Context 和 immer 用于 Redux 语义的状态管理库_
- [robodux](https://github.com/neurosnap/robodux) _减少 redux 样板的灵活脚手架_
- [immer-reducer](https://github.com/epeli/immer-reducer) _用于 React Hooks 和 Redux 的 Typescript 类型安全和简洁的 reducer_
- [redux-ts-utils](https://github.com/knpwrs/redux-ts-utils) _使用 Redux 创建类型安全的应用程序所需的一切,强调简单性_
- [react-state-tree](https://github.com/suchipi/react-state-tree) _将您的状态持久化到类似 redux 的状态树,useState 的替代品_
- [redux-immer](https://github.com/salvoravida/redux-immer) _用于创建与 immer 状态一起使用的 Redux combineReducers 的等效函数。像 redux-immutable 但是 immer的_
- [ngrx-wieder](https://github.com/nilsmehlhorn/ngrx-wieder) _轻量级但可配置的解决方案,用于在 NgRx 和 Immer 之上的 Angular 应用程序中实现撤消重做_
- ... 还有 [很多](https://www.npmjs.com/browse/depended/immer)
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
id: complex-objects
title:
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" class="horizontal bordered"></div>
</center>

普通对象(没有原型的对象)、数组、`Map``Set` 总是可以用 Immer 更新。所有其他对象都必须使用 `immerable` 符号将自己标记为与 Immer 兼容。当这些对象之一在 `produce` 中进行更改时,它的原型将保留在副本之间


```js
import {immerable} from "immer"

class Foo {
[immerable] = true // 方式一

constructor() {
this[immerable] = true // 方式二
}
}

Foo[immerable] = true // 方式三
```

### 例子

```js
import {immerable, produce} from "immer"

class Clock {
[immerable] = true

constructor(hour, minute) {
this.hour = hour
this.minute = minute
}

get time() {
return `${this.hour}:${this.minute}`
}

tick() {
return produce(this, draft => {
draft.minute++
})
}
}

const clock1 = new Clock(12, 10)
const clock2 = clock1.tick()
console.log(clock1.time) // 12:10
console.log(clock2.time) // 12:11
console.log(clock2 instanceof Clock) // true
```

### 语义细节

关于类的 `draft` 对象语义如下:

1. 类的 `draft` 是一个新对象,但与原始对象具有相同的原型。
2. 创建 `draft` 时,Immer 会将所有拥有的的属性从源对象复制到 `draft`。这包括不可枚举和符号属性。
3. 源对象拥有的 getter 将在复制过程中被调用,就像 `Object.assign` 方法一样
4. 继承的 getter 和方法将保持原样并被 `draft` 继承
5. Immer 不会调用构造函数
6. 最终实例将使用与创建 `draft` 相同的机制构建。
7. 只有具有 setter 的 getter 才能在 `draft` 中写入,否则无法将值复制回来。

因为 Immer 会将对象拥有的 getter 解引用到普通属性中,所以可以使用在其字段上使用 getter/setter 获得的对象,就像MobX 和 Vue。

Immer 不支持外来/引擎原生对象,例如 DOM 节点或 Buffers,也不支持继承的 Map、Set 或数组,并且不能在它们上使用 immerable 符号。

因此,例如在使用 `Date` 对象时,您应该始终创建一个新的 `Date` 实例,而不是改变现有的 `Date` 对象。
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
id: current
title: 从 draft 中提取当前 state
sidebar_label: Current
---

<center>
<div data-ea-publisher="immerjs" data-ea-type="image" class="horizontal bordered"></div>
</center>

Immer 暴露了一个命名导出的 `current`函数,可以创建 draft 对象当前状态的一个副本。
这对于调试非常有用(因为这些对象不会是代理对象,也不会被记录下来)。
此外,对 `current` 的引用可以安全地从 `produce` 函数中释放。换句话说,`current` 提供 draft 当前状态的快照。

`current` 工作生成的对象类似于 `produced` 本身创建的对象。


1. 未修改的对象将在结构上与原始对象共享。
2. 如果未对 draft 进行任何更改,通常它会保留 original(draft) === current(draft),但这并不能保证。
3. 未来对 draft 的更改不会反映在 `current` 生成的对象中(不可被 draft 对象的引用除外)
4.`produce` 创建的对象不同,`current` 创建的对象不会被冻结。

谨慎使用 `current`,这可能是一项潜在的昂贵操作,尤其是在使用 ES5 时。

请注意,不能在不是 draft 的对象上调用 `current`

### 例子

以下示例显示了 `current`(和 `original` )的效果:


```js
const base = {
x: 0
}

const next = produce(base, draft => {
draft.x++
const orig = original(draft)
const copy = current(draft)
console.log(orig.x)
console.log(copy.x)

setTimeout(() => {
// 将在 produce 完成后执行
console.log(orig.x)
console.log(copy.x)
}, 100)

draft.x++
console.log(draft.x)
})
console.log(next.x)

// 将会打印
// 0 (orig.x)
// 1 (copy.x)
// 2 (draft.x)
// 2 (next.x)
// 0 (after timeout, orig.x)
// 1 (after timeout, copy.x)
```
Loading

0 comments on commit 53c2f91

Please sign in to comment.