# 语言无关的 key 契约 (/zh/docs/guide/guides/keys)

为什么星名不能拿来做判断，key 字段是什么，三种编程语言各自怎么用。



*适合：开发者*

## 问题 [#问题]

排盘结果的文本会跟着盘面语言变。同一颗星，中文盘上是「紫微」，英文盘上是 `emperor`，
韩文盘上是 `자미`。如果判断逻辑写成：

```python
# 反面例子
if any(s.name == "紫微" for s in soul.major_stars):
    ...
```

那么这段代码只在 `language="zh-CN"` 时正确。换成任何其他盘面语言就静默失效 ——
不会报错，只是永远返回 `False`。这类 bug 很难发现。

## 解法 [#解法]

每个会被翻译的字段，x-iztro 都额外提供一个**语言无关标识**（key）。
key 的取值是 iztro 的 i18n 键名，与盘面语言无关，永远不变。

```json
{
  "name": "紫微",
  "key": "ziweiMaj",
  "brightness": "庙",
  "brightnessKey": "miao",
  "mutagen": "禄",
  "mutagenKey": "sihuaLu"
}
```

`name` 给人看，`key` 给代码用。

## 有哪些 key 字段 [#有哪些-key-字段]

| 数据      | 翻译字段                  | 标识字段                   | 取值示例                |
| ------- | --------------------- | ---------------------- | ------------------- |
| 星耀      | `name`                | `key`                  | `ziweiMaj`          |
| 亮度      | `brightness`          | `brightnessKey`        | `miao`              |
| 四化      | `mutagen`             | `mutagenKey`           | `sihuaLu`           |
| 宫位名     | `name`                | `nameKey`              | `soulPalace`        |
| 天干      | `heavenly_stem`       | `heavenlyStemKey`      | `jiaHeavenly`       |
| 地支      | `earthly_branch`      | `earthlyBranchKey`     | `ziEarthly`         |
| 五行局     | `five_elements_class` | `fiveElementsClassKey` | `water2nd`          |
| 命主 / 身主 | `soul` / `body`       | `soulKey` / `bodyKey`  | `ziweiMaj`          |
| 性别      | `gender`              | `genderKey`            | `male`              |
| 长生十二神   | `changsheng12`        | `changsheng12Key`      | `changsheng`        |
| 博士十二神   | `boshi12`             | `boshi12Key`           | `boshi`             |
| 将前十二神   | `jiangqian12`         | `jiangqian12Key`       | `jiangxing`         |
| 岁前十二神   | `suiqian12`           | `suiqian12Key`         | `suijian`           |
| 宫干四化星   | —                     | `mutagenStarKeys`      | `["taiyangMaj", …]` |

## 三种编程语言的用法 [#三种编程语言的用法]

### Python：枚举 [#python枚举]

`x_iztro.enums` 里所有枚举都是 `StrEnum`，**成员的值就是 key**。

```python
from x_iztro.enums import MajorStar, Mutagen, PalaceName, Brightness

MajorStar.ZIWEI      # "ziweiMaj"
Mutagen.LU           # "sihuaLu"
PalaceName.SOUL      # "soulPalace"
Brightness.MIAO      # "miao"
```

判断方法接受枚举：

```python
soul = chart.palace(PalaceName.SOUL)
soul.has([MajorStar.ZIWEI])
soul.has_mutagen(Mutagen.LU)
```

因为是 `StrEnum`，它同时也是字符串，可以直接和 key 字段比较：

```python
star.key == MajorStar.ZIWEI   # True
```

### Go：常量 [#go常量]

`keys.go` 里的常量值就是 key：

```go
iztro.PalaceSoul      // "soulPalace"
iztro.StarZiweiMaj    // "ziweiMaj"
iztro.MutagenLu       // "sihuaLu"
iztro.BrightnessMiao  // "miao"

soul := chart.Palace(iztro.PalaceSoul)
soul.Has(iztro.StarZiweiMaj)
star.WithMutagen(iztro.MutagenQuan)
star.WithBrightness(iztro.BrightnessMiao)
```

### Rust：枚举本身 [#rust枚举本身]

Rust 侧不需要 key 字段 —— 结构体里存的本来就是枚举，翻译是显示时才做的事。

```rust
if soul.has(&[StarKey::ZiweiMaj]) { }
```

需要 key 字符串时（例如自己做序列化）调 `as_key()`：

```rust
Palace::Soul.as_key();        // "soulPalace"
Mutagen::Lu.as_key();         // "sihuaLu"
Brightness::Miao.as_key();    // "miao"
```

## 验证方式 [#验证方式]

同一个生日分别用六种盘面语言排盘，所有 key 字段必须逐一相等 ——
这条由绑定契约测试（`golden_contract`）与 Go / Python 的端到端金标测试守着。

所以下面这段代码在任何盘面语言下结果都相同：

```python
for lang in ["zh-CN", "zh-TW", "en-US", "ja-JP", "ko-KR", "vi-VN"]:
    chart = astro.by_solar("2000-8-16", 2, "female", language=lang)
    soul = chart.palace(PalaceName.SOUL)
    assert soul.has_mutagen(Mutagen.LU) == expected
```

## 什么时候可以用文本 [#什么时候可以用文本]

展示。只有展示。任何进入 `if` 的比较都应该用 key。
