You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fory.apache.org by ch...@apache.org on 2026/02/10 06:00:59 UTC

(fory-site) 01/02: docs(zh-cn): add missing compiler and guide translations

This is an automated email from the ASF dual-hosted git repository.

chaokunyang pushed a commit to branch translate_0.15_docs
in repository https://gitbox.apache.org/repos/asf/fory-site.git

commit 09556b5d3583796f23d2b13bca4091cb9992db56
Author: chaokunyang <sh...@gmail.com>
AuthorDate: Tue Feb 10 13:20:46 2026 +0800

    docs(zh-cn): add missing compiler and guide translations
---
 .../current/compiler/compiler-guide.md             |  657 +++++++++
 .../current/compiler/flatbuffers-idl.md            |  199 +++
 .../current/compiler/generated-code.md             |  714 ++++++++++
 .../current/compiler/grpc-service-design.md        |  219 +++
 .../current/compiler/index.md                      |  213 +++
 .../current/compiler/protobuf-idl.md               |  335 +++++
 .../current/compiler/schema-idl.md                 | 1398 ++++++++++++++++++++
 .../current/guide/cpp/custom-serializers.md        |  371 ++++++
 .../current/guide/cpp/polymorphism.md              |  480 +++++++
 .../current/guide/java/field-configuration.md      |  605 +++++++++
 .../current/guide/python/field-configuration.md    |  492 +++++++
 .../current/guide/rust/field-configuration.md      |  460 +++++++
 .../current/guide/xlang/field-type-meta.md         |  301 +++++
 .../version-0.15/compiler/compiler-guide.md        |  657 +++++++++
 .../version-0.15/compiler/flatbuffers-idl.md       |  199 +++
 .../version-0.15/compiler/generated-code.md        |  714 ++++++++++
 .../version-0.15/compiler/grpc-service-design.md   |  219 +++
 .../version-0.15/compiler/index.md                 |  213 +++
 .../version-0.15/compiler/protobuf-idl.md          |  335 +++++
 .../version-0.15/compiler/schema-idl.md            | 1398 ++++++++++++++++++++
 .../version-0.15/guide/cpp/custom-serializers.md   |  371 ++++++
 .../version-0.15/guide/cpp/polymorphism.md         |  480 +++++++
 .../version-0.15/guide/java/field-configuration.md |  605 +++++++++
 .../guide/python/field-configuration.md            |  492 +++++++
 .../version-0.15/guide/rust/field-configuration.md |  460 +++++++
 .../version-0.15/guide/xlang/field-type-meta.md    |  301 +++++
 26 files changed, 12888 insertions(+)

diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/compiler-guide.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/compiler-guide.md
new file mode 100644
index 0000000000..833ea0d3ff
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/compiler-guide.md
@@ -0,0 +1,657 @@
+---
+title: Compiler Guide
+sidebar_position: 3
+id: compiler_guide
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+This guide covers installation, usage, and integration of the Fory IDL compiler.
+
+## Installation
+
+### From Source
+
+```bash
+cd compiler
+pip install -e .
+```
+
+### Verify Installation
+
+```bash
+foryc --help
+```
+
+## Command Line Interface
+
+### Basic Usage
+
+```bash
+foryc [OPTIONS] FILES...
+```
+
+```bash
+foryc --scan-generated [OPTIONS]
+```
+
+### Options
+
+Compile options:
+
+| Option                                | Description                                           | Default             |
+| ------------------------------------- | ----------------------------------------------------- | ------------------- |
+| `--lang`                              | Comma-separated target languages                      | `all`               |
+| `--output`, `-o`                      | Output directory                                      | `./generated`       |
+| `--package`                           | Override package name from Fory IDL file              | (from file)         |
+| `-I`, `--proto_path`, `--import_path` | Add directory to import search path (can be repeated) | (none)              |
+| `--java_out=DST_DIR`                  | Generate Java code in DST_DIR                         | (none)              |
+| `--python_out=DST_DIR`                | Generate Python code in DST_DIR                       | (none)              |
+| `--cpp_out=DST_DIR`                   | Generate C++ code in DST_DIR                          | (none)              |
+| `--go_out=DST_DIR`                    | Generate Go code in DST_DIR                           | (none)              |
+| `--rust_out=DST_DIR`                  | Generate Rust code in DST_DIR                         | (none)              |
+| `--go_nested_type_style`              | Go nested type naming: `camelcase` or `underscore`    | from schema/default |
+| `--emit-fdl`                          | Print translated Fory IDL for non-`.fdl` inputs       | `false`             |
+| `--emit-fdl-path`                     | Write translated Fory IDL to a file or directory      | (stdout)            |
+
+Scan options (with `--scan-generated`):
+
+| Option       | Description                    | Default |
+| ------------ | ------------------------------ | ------- |
+| `--root`     | Root directory to scan         | `.`     |
+| `--relative` | Print paths relative to root   | `false` |
+| `--delete`   | Delete matched generated files | `false` |
+| `--dry-run`  | Scan/print only, do not delete | `false` |
+
+### Scan Generated Files
+
+Use `--scan-generated` to find files produced by `foryc`. The scanner walks
+the tree recursively, skips `build/`, `target/`, and hidden directories, and prints
+each generated file as it is found.
+
+```bash
+# Scan current directory
+foryc --scan-generated
+
+# Scan a specific root
+foryc --scan-generated --root ./src
+
+# Print paths relative to the scan root
+foryc --scan-generated --root ./src --relative
+
+# Delete scanned generated files
+foryc --scan-generated --root ./src --delete
+
+# Dry-run (scan and print only)
+foryc --scan-generated --root ./src --dry-run
+```
+
+### Examples
+
+**Compile for all languages:**
+
+```bash
+foryc schema.fdl
+```
+
+**Compile for specific languages:**
+
+```bash
+foryc schema.fdl --lang java,python
+```
+
+**Specify output directory:**
+
+```bash
+foryc schema.fdl --output ./src/generated
+```
+
+**Override package name:**
+
+```bash
+foryc schema.fdl --package com.myapp.models
+```
+
+**Compile multiple files:**
+
+```bash
+foryc user.fdl order.fdl product.fdl --output ./generated
+```
+
+**Use import search paths:**
+
+```bash
+# Add a single import path
+foryc src/main.fdl -I libs/common
+
+# Add multiple import paths (repeated option)
+foryc src/main.fdl -I libs/common -I libs/types
+
+# Add multiple import paths (comma-separated)
+foryc src/main.fdl -I libs/common,libs/types,third_party/
+
+# Using --proto_path (protoc-compatible alias)
+foryc src/main.fdl --proto_path=libs/common
+
+# Mix all styles
+foryc src/main.fdl -I libs/common,libs/types --proto_path third_party/
+```
+
+**Language-specific output directories (protoc-style):**
+
+```bash
+# Generate only Java code to a specific directory
+foryc schema.fdl --java_out=./src/main/java
+
+# Generate multiple languages to different directories
+foryc schema.fdl --java_out=./java/gen --python_out=./python/src --go_out=./go/gen
+
+# Combine with import paths
+foryc schema.fdl --java_out=./gen/java -I proto/ -I common/
+```
+
+When using `--{lang}_out` options:
+
+- Only the specified languages are generated (not all languages)
+- The compiler writes under the specified directory (language-specific generators may still create package/module subdirectories)
+- This is compatible with protoc-style workflows
+
+**Inspect translated Fory IDL from proto/fbs input:**
+
+```bash
+# Print translated Fory IDL to stdout
+foryc schema.proto --emit-fdl
+
+# Write translated Fory IDL to a directory
+foryc schema.fbs --emit-fdl --emit-fdl-path ./translated
+```
+
+## Import Path Resolution
+
+When compiling Fory IDL files with imports, the compiler searches for imported files in this order:
+
+1. **Relative to the importing file (default)** - The directory containing the file with the import statement is always searched first, automatically. No `-I` flag needed for same-directory imports.
+2. **Each `-I` path in order** - Additional search paths specified on the command line
+
+**Same-directory imports work automatically:**
+
+```protobuf
+// main.fdl
+import "common.fdl";  // Found if common.fdl is in the same directory
+```
+
+```bash
+# No -I needed for same-directory imports
+foryc main.fdl
+```
+
+**Example project structure:**
+
+```
+project/
+├── src/
+│   └── main.fdl          # import "common.fdl";
+└── libs/
+    └── common.fdl
+```
+
+**Without `-I` (fails):**
+
+```bash
+$ foryc src/main.fdl
+Import error: Import not found: common.fdl
+  Searched in: /project/src
+```
+
+**With `-I` (succeeds):**
+
+```bash
+$ foryc src/main.fdl -I libs/
+Compiling src/main.fdl...
+  Resolved 1 import(s)
+```
+
+## Supported Languages
+
+| Language | Flag     | Output Extension | Description                 |
+| -------- | -------- | ---------------- | --------------------------- |
+| Java     | `java`   | `.java`          | POJOs with Fory annotations |
+| Python   | `python` | `.py`            | Dataclasses with type hints |
+| Go       | `go`     | `.go`            | Structs with struct tags    |
+| Rust     | `rust`   | `.rs`            | Structs with derive macros  |
+| C++      | `cpp`    | `.h`             | Structs with FORY macros    |
+
+## Output Structure
+
+### Java
+
+```
+generated/
+└── java/
+    └── com/
+        └── example/
+            ├── User.java
+            ├── Order.java
+            ├── Status.java
+            └── ExampleForyRegistration.java
+```
+
+- One file per type (enum or message)
+- Package structure matches Fory IDL package
+- Registration helper class generated
+
+### Python
+
+```
+generated/
+└── python/
+    └── example.py
+```
+
+- Single module with all types
+- Module name derived from package
+- Registration function included
+
+### Go
+
+```
+generated/
+└── go/
+    └── example/
+        └── example.go
+```
+
+- Single file with all types
+- Directory and package name are derived from `go_package` or the Fory IDL package
+- Registration function included
+
+### Rust
+
+```
+generated/
+└── rust/
+    └── example.rs
+```
+
+- Single module with all types
+- Module name derived from package
+- Registration function included
+
+### C++
+
+```
+generated/
+└── cpp/
+    └── example.h
+```
+
+- Single header file
+- Namespace matches package (dots to `::`)
+- Header guards and forward declarations
+
+## Build Integration
+
+### Maven (Java)
+
+Add to your `pom.xml`:
+
+```xml
+<build>
+  <plugins>
+    <plugin>
+      <groupId>org.codehaus.mojo</groupId>
+      <artifactId>exec-maven-plugin</artifactId>
+      <version>3.1.0</version>
+      <executions>
+        <execution>
+          <id>generate-fory-types</id>
+          <phase>generate-sources</phase>
+          <goals>
+            <goal>exec</goal>
+          </goals>
+          <configuration>
+            <executable>foryc</executable>
+            <arguments>
+              <argument>${project.basedir}/src/main/fdl/schema.fdl</argument>
+              <argument>--java_out</argument>
+              <argument>${project.build.directory}/generated-sources/fory</argument>
+            </arguments>
+          </configuration>
+        </execution>
+      </executions>
+    </plugin>
+  </plugins>
+</build>
+```
+
+Add generated sources:
+
+```xml
+<build>
+  <plugins>
+    <plugin>
+      <groupId>org.codehaus.mojo</groupId>
+      <artifactId>build-helper-maven-plugin</artifactId>
+      <version>3.4.0</version>
+      <executions>
+        <execution>
+          <phase>generate-sources</phase>
+          <goals>
+            <goal>add-source</goal>
+          </goals>
+          <configuration>
+            <sources>
+              <source>${project.build.directory}/generated-sources/fory</source>
+            </sources>
+          </configuration>
+        </execution>
+      </executions>
+    </plugin>
+  </plugins>
+</build>
+```
+
+### Gradle (Java/Kotlin)
+
+Add to `build.gradle`:
+
+```groovy
+task generateForyTypes(type: Exec) {
+    commandLine 'foryc',
+        "${projectDir}/src/main/fdl/schema.fdl",
+        '--java_out', "${buildDir}/generated/sources/fory"
+}
+
+compileJava.dependsOn generateForyTypes
+
+sourceSets {
+    main {
+        java {
+            srcDir "${buildDir}/generated/sources/fory"
+        }
+    }
+}
+```
+
+### Python (setuptools)
+
+Add to `setup.py` or `pyproject.toml`:
+
+```python
+# setup.py
+from setuptools import setup
+from setuptools.command.build_py import build_py
+import subprocess
+
+class BuildWithForyIdl(build_py):
+    def run(self):
+        subprocess.run([
+            'foryc',
+            'schema.fdl',
+            '--python_out', 'src/generated'
+        ], check=True)
+        super().run()
+
+setup(
+    cmdclass={'build_py': BuildWithForyIdl},
+    # ...
+)
+```
+
+### Go (go generate)
+
+Add to your Go file:
+
+```go
+//go:generate foryc ../schema.fdl --lang go --output .
+package models
+```
+
+Run:
+
+```bash
+go generate ./...
+```
+
+### Rust (build.rs)
+
+Add to `build.rs`:
+
+```rust
+use std::process::Command;
+
+fn main() {
+    println!("cargo:rerun-if-changed=schema.fdl");
+
+    let status = Command::new("foryc")
+        .args(&["schema.fdl", "--rust_out", "src/generated"])
+        .status()
+        .expect("Failed to run foryc");
+
+    if !status.success() {
+        panic!("Fory IDL compilation failed");
+    }
+}
+```
+
+### CMake (C++)
+
+Add to `CMakeLists.txt`:
+
+```cmake
+find_program(FORY_COMPILER foryc)
+
+add_custom_command(
+    OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/generated/example.h
+    COMMAND ${FORY_COMPILER}
+        ${CMAKE_CURRENT_SOURCE_DIR}/schema.fdl
+        --cpp_out ${CMAKE_CURRENT_SOURCE_DIR}/generated
+    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/schema.fdl
+    COMMENT "Generating Fory IDL types"
+)
+
+add_custom_target(generate_fory_idl DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/generated/example.h)
+
+add_library(mylib ...)
+add_dependencies(mylib generate_fory_idl)
+target_include_directories(mylib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/generated)
+```
+
+### Bazel
+
+Create a rule in `BUILD`:
+
+```python
+genrule(
+    name = "generate_fdl",
+    srcs = ["schema.fdl"],
+    outs = ["generated/example.h"],
+    cmd = "$(location //:fory_compiler) $(SRCS) --cpp_out $(RULEDIR)/generated",
+    tools = ["//:fory_compiler"],
+)
+
+cc_library(
+    name = "models",
+    hdrs = [":generate_fdl"],
+    # ...
+)
+```
+
+## Error Handling
+
+### Syntax Errors
+
+```
+Error: Line 5, Column 12: Expected ';' after field declaration
+```
+
+Fix: Check the indicated line for missing semicolons or syntax issues.
+
+### Duplicate Type Names
+
+```
+Error: Duplicate type name: User
+```
+
+Fix: Ensure each enum and message has a unique name within the file.
+
+### Duplicate Type IDs
+
+```
+Error: Duplicate type ID 100: User and Order
+```
+
+Fix: Assign unique type IDs to each type.
+
+### Unknown Type References
+
+```
+Error: Unknown type 'Address' in Customer.address
+```
+
+Fix: Define the referenced type before using it, or check for typos.
+
+### Duplicate Field Numbers
+
+```
+Error: Duplicate field number 1 in User: name and id
+```
+
+Fix: Assign unique field numbers within each message.
+
+## Best Practices
+
+### Project Structure
+
+```
+project/
+├── fdl/
+│   ├── common.fdl       # Shared types
+│   ├── user.fdl         # User domain
+│   └── order.fdl        # Order domain
+├── src/
+│   └── generated/       # Generated code (git-ignored)
+└── build.gradle
+```
+
+### Version Control
+
+- **Track**: Fory IDL schema files
+- **Ignore**: Generated code (can be regenerated)
+
+Add to `.gitignore`:
+
+```
+# Generated Fory IDL code
+src/generated/
+generated/
+```
+
+### CI/CD Integration
+
+Always regenerate during builds:
+
+```yaml
+# GitHub Actions example
+steps:
+  - name: Install Fory IDL Compiler
+    run: pip install ./compiler
+
+  - name: Generate Types
+    run: foryc fdl/*.fdl --output src/generated
+
+  - name: Build
+    run: ./gradlew build
+```
+
+### Schema Evolution
+
+When modifying schemas:
+
+1. **Never reuse field numbers** - Mark as reserved instead
+2. **Never change type IDs** - They're part of the binary format
+3. **Add new fields** - Use new field numbers
+4. **Use `optional`** - For backward compatibility
+
+```protobuf
+message User [id=100] {
+    string id = 1;
+    string name = 2;
+    // Field 3 was removed, don't reuse
+    optional string email = 4;  // New field
+}
+```
+
+## Troubleshooting
+
+### Command Not Found
+
+```
+foryc: command not found
+```
+
+**Solution:** Ensure the compiler is installed and in your PATH:
+
+```bash
+pip install -e ./compiler
+# Or add to PATH
+export PATH=$PATH:~/.local/bin
+```
+
+### Permission Denied
+
+```
+Permission denied: ./generated
+```
+
+**Solution:** Ensure write permissions on the output directory:
+
+```bash
+chmod -R u+w ./generated
+```
+
+### Import Errors in Generated Code
+
+**Java:** Ensure Fory dependency is in your project:
+
+```xml
+<dependency>
+  <groupId>org.apache.fory</groupId>
+  <artifactId>fory-core</artifactId>
+  <version>${fory.version}</version>
+</dependency>
+```
+
+**Python:** Ensure pyfory is installed:
+
+```bash
+pip install pyfory
+```
+
+**Go:** Ensure fory module is available:
+
+```bash
+go get github.com/apache/fory/go/fory
+```
+
+**Rust:** Ensure fory crate is in `Cargo.toml`:
+
+```toml
+[dependencies]
+fory = "x.y.z"
+```
+
+**C++:** Ensure Fory headers are in include path.
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/flatbuffers-idl.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/flatbuffers-idl.md
new file mode 100644
index 0000000000..7362a1028c
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/flatbuffers-idl.md
@@ -0,0 +1,199 @@
+---
+title: FlatBuffers IDL Support
+sidebar_position: 7
+id: flatbuffers_idl
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+This page explains how Apache Fory consumes FlatBuffers schemas (`.fbs`) and
+translates them into Fory IR for code generation.
+
+## What This Page Covers
+
+- When to use FlatBuffers input with Fory
+- Exact FlatBuffers to Fory mapping behavior
+- Supported Fory-specific attributes in `.fbs`
+- Migration notes and generated-code differences
+
+## Why Use Apache Fory
+
+- Idiomatic generated code: Fory generates language-idiomatic classes/structs
+  that can be used directly as domain objects.
+- Java performance: In Java object-serialization workloads, Fory is faster than
+  FlatBuffers in Fory benchmarks.
+- Other languages: serialization performance is generally in a similar range.
+- Deserialization in practice: FlatBuffers does not perform native-object deserialization and is
+  faster by default, but if your application needs native objects, it requires
+  conversion and that conversion step can dominate read cost. In those cases,
+  Fory deserialization is often faster end-to-end.
+- Easier APIs: Fory uses direct native objects, so you do not need to
+  reverse-build tables or manually manage offsets.
+- Better graph modeling: Shared and circular references are first-class features
+  in Fory.
+
+## Quick Decision Guide
+
+| Situation                                                          | Recommended Path       |
+| ------------------------------------------------------------------ | ---------------------- |
+| You already have `.fbs` schemas and want Fory runtime/codegen      | Use FlatBuffers input  |
+| You are starting new schema work and want full Fory syntax control | Use native Fory IDL    |
+| You need FlatBuffers wire compatibility at runtime                 | Keep FlatBuffers stack |
+| You need Fory object-graph semantics (`ref`, weak refs, etc.)      | Use Fory               |
+
+## FlatBuffers to Fory Mapping
+
+### Schema-Level Rules
+
+- `namespace` maps to Fory package namespace.
+- `include` entries map to Fory imports.
+- `table` is translated as `evolving=true`.
+- `struct` is translated as `evolving=false`.
+- `root_type` is parsed but ignored by Fory runtime/codegen.
+- `file_identifier` and `file_extension` are parsed but not used by Fory codegen.
+
+### Field Numbering
+
+FlatBuffers fields do not have explicit field IDs. Fory assigns field numbers by
+source declaration order, starting at `1`.
+
+### Scalar Type Mapping
+
+| FlatBuffers | Fory Type |
+| ----------- | --------- |
+| `byte`      | `int8`    |
+| `ubyte`     | `uint8`   |
+| `short`     | `int16`   |
+| `ushort`    | `uint16`  |
+| `int`       | `int32`   |
+| `uint`      | `uint32`  |
+| `long`      | `int64`   |
+| `ulong`     | `uint64`  |
+| `float`     | `float32` |
+| `double`    | `float64` |
+| `bool`      | `bool`    |
+| `string`    | `string`  |
+
+Vectors (`[T]`) map to Fory lists.
+
+### Unions
+
+FlatBuffers unions map to Fory unions.
+
+- Case IDs are assigned by declaration order, starting at `1`.
+- Case names are derived from type names using snake_case field naming.
+
+**FlatBuffers**
+
+```fbs
+union Payload {
+  Note,
+  Metric
+}
+
+table Container {
+  payload: Payload;
+}
+```
+
+**Fory shape after translation**
+
+```protobuf
+union Payload {
+    Note note = 1;
+    Metric metric = 2;
+}
+
+message Container {
+    Payload payload = 1;
+}
+```
+
+### Defaults and Metadata
+
+- FlatBuffers default values are parsed but not applied as Fory runtime defaults.
+- Non-Fory metadata attributes are preserved as generic options in IR and may be
+  consumed by downstream tooling.
+
+## Fory-Specific Attributes in FlatBuffers
+
+FlatBuffers metadata attributes use `key:value`. For Fory-specific options, use
+`fory_` (or `fory.`) prefix in `.fbs`; the prefix is removed during parsing.
+
+### Supported Field Attributes
+
+| FlatBuffers Attribute            | Effect in Fory                                        |
+| -------------------------------- | ----------------------------------------------------- |
+| `fory_ref:true`                  | Enable reference tracking for the field               |
+| `fory_nullable:true`             | Mark field optional/nullable                          |
+| `fory_weak_ref:true`             | Enable weak reference semantics and implies `ref`     |
+| `fory_thread_safe_pointer:false` | For ref fields, select non-thread-safe pointer flavor |
+
+Semantics:
+
+- `fory_weak_ref:true` implies `ref`.
+- `fory_thread_safe_pointer` only takes effect when the field is ref-tracked.
+- For list fields, `fory_ref:true` applies to list elements.
+
+Example:
+
+```fbs
+table Node {
+  parent: Node (fory_weak_ref: true);
+  children: [Node] (fory_ref: true);
+  cached: Node (fory_ref: true, fory_thread_safe_pointer: false);
+}
+```
+
+## Generated Code Differences
+
+Using `.fbs` as input to Fory still produces normal Fory-generated code, not
+FlatBuffers `ByteBuffer`-style APIs.
+
+- Java: POJOs/records with Fory metadata
+- Python: dataclasses plus registration helpers
+- Go/Rust/C++: native structs and Fory metadata
+
+The serialization format is Fory binary protocol, not FlatBuffers wire format.
+
+## Usage
+
+Compile a FlatBuffers schema directly:
+
+```bash
+foryc schema.fbs --lang java,python --output ./generated
+```
+
+Inspect translated schema syntax for debugging:
+
+```bash
+foryc schema.fbs --emit-fdl --emit-fdl-path ./translated
+```
+
+## Migration Notes
+
+1. Keep existing `namespace` values stable to keep type registration stable.
+2. Review fields that relied on FlatBuffers default literals and set explicit
+   defaults in application code if needed.
+3. Add `fory_ref`/`fory_weak_ref` where object-graph semantics are required.
+4. Validate generated model behavior with roundtrip tests before replacing
+   existing serialization paths.
+
+## Summary
+
+FlatBuffers input lets you reuse existing `.fbs` schemas while moving to Fory's
+runtime and code generation model. This is useful for incremental migration,
+while preserving schema investment and adopting Fory-native object APIs.
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/generated-code.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/generated-code.md
new file mode 100644
index 0000000000..b433374af1
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/generated-code.md
@@ -0,0 +1,714 @@
+---
+title: Generated Code
+sidebar_position: 5
+id: generated_code
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+This document explains generated code for each target language.
+
+Fory IDL generated types are idiomatic in host languages and can be used directly as domain objects. Generated types also include `to/from bytes` helpers and registration helpers.
+
+## Reference Schemas
+
+The examples below use two real schemas:
+
+1. `addressbook.fdl` (explicit type IDs)
+2. `auto_id.fdl` (no explicit type IDs)
+
+### `addressbook.fdl` (excerpt)
+
+```protobuf
+package addressbook;
+
+option go_package = "github.com/myorg/myrepo/gen/addressbook;addressbook";
+
+message Person [id=100] {
+    string name = 1;
+    int32 id = 2;
+
+    enum PhoneType [id=101] {
+        PHONE_TYPE_MOBILE = 0;
+        PHONE_TYPE_HOME = 1;
+        PHONE_TYPE_WORK = 2;
+    }
+
+    message PhoneNumber [id=102] {
+        string number = 1;
+        PhoneType phone_type = 2;
+    }
+
+    list<PhoneNumber> phones = 7;
+    Animal pet = 8;
+}
+
+message Dog [id=104] {
+    string name = 1;
+    int32 bark_volume = 2;
+}
+
+message Cat [id=105] {
+    string name = 1;
+    int32 lives = 2;
+}
+
+union Animal [id=106] {
+    Dog dog = 1;
+    Cat cat = 2;
+}
+
+message AddressBook [id=103] {
+    list<Person> people = 1;
+    map<string, Person> people_by_name = 2;
+}
+```
+
+### `auto_id.fdl` (excerpt)
+
+```protobuf
+package auto_id;
+
+enum Status {
+    UNKNOWN = 0;
+    OK = 1;
+}
+
+message Envelope {
+    string id = 1;
+
+    message Payload {
+        int32 value = 1;
+    }
+
+    union Detail {
+        Payload payload = 1;
+        string note = 2;
+    }
+
+    Payload payload = 2;
+    Detail detail = 3;
+    Status status = 4;
+}
+
+union Wrapper {
+    Envelope envelope = 1;
+    string raw = 2;
+}
+```
+
+## Java
+
+### Output Layout
+
+For `package addressbook`, Java output is generated under:
+
+- `<java_out>/addressbook/`
+- Type files: `AddressBook.java`, `Person.java`, `Dog.java`, `Cat.java`, `Animal.java`
+- Registration helper: `AddressbookForyRegistration.java`
+
+### Type Generation
+
+Messages generate Java classes with `@ForyField`, default constructors, getters/setters, and byte helpers:
+
+```java
+public class Person {
+    public static enum PhoneType {
+        MOBILE,
+        HOME,
+        WORK;
+    }
+
+    public static class PhoneNumber {
+        @ForyField(id = 1)
+        private String number;
+
+        @ForyField(id = 2)
+        private PhoneType phoneType;
+
+        public byte[] toBytes() { ... }
+        public static PhoneNumber fromBytes(byte[] bytes) { ... }
+    }
+
+    @ForyField(id = 1)
+    private String name;
+
+    @ForyField(id = 8)
+    private Animal pet;
+
+    public byte[] toBytes() { ... }
+    public static Person fromBytes(byte[] bytes) { ... }
+}
+```
+
+Unions generate classes extending `org.apache.fory.type.union.Union`:
+
+```java
+public final class Animal extends Union {
+    public enum AnimalCase {
+        DOG(1),
+        CAT(2);
+        public final int id;
+        AnimalCase(int id) { this.id = id; }
+    }
+
+    public static Animal ofDog(Dog v) { ... }
+    public AnimalCase getAnimalCase() { ... }
+    public int getAnimalCaseId() { ... }
+
+    public boolean hasDog() { ... }
+    public Dog getDog() { ... }
+    public void setDog(Dog v) { ... }
+}
+```
+
+### Registration
+
+Generated registration helper:
+
+```java
+public static void register(Fory fory) {
+    org.apache.fory.resolver.TypeResolver resolver = fory.getTypeResolver();
+    resolver.registerUnion(Animal.class, 106L, new org.apache.fory.serializer.UnionSerializer(fory, Animal.class));
+    resolver.register(Person.class, 100L);
+    resolver.register(Person.PhoneType.class, 101L);
+    resolver.register(Person.PhoneNumber.class, 102L);
+    resolver.register(Dog.class, 104L);
+    resolver.register(Cat.class, 105L);
+    resolver.register(AddressBook.class, 103L);
+}
+```
+
+For schemas without explicit `[id=...]`, generated registration uses computed numeric IDs (for example from `auto_id.fdl`):
+
+```java
+resolver.register(Status.class, 1124725126L);
+resolver.registerUnion(Wrapper.class, 1471345060L, new org.apache.fory.serializer.UnionSerializer(fory, Wrapper.class));
+resolver.register(Envelope.class, 3022445236L);
+resolver.registerUnion(Envelope.Detail.class, 1609214087L, new org.apache.fory.serializer.UnionSerializer(fory, Envelope.Detail.class));
+resolver.register(Envelope.Payload.class, 2862577837L);
+```
+
+If `option enable_auto_type_id = false;` is set, registration uses namespace and type name:
+
+```java
+resolver.register(Config.class, "myapp.models", "Config");
+resolver.registerUnion(
+    Holder.class,
+    "myapp.models",
+    "Holder",
+    new org.apache.fory.serializer.UnionSerializer(fory, Holder.class));
+```
+
+### Usage
+
+```java
+Person person = new Person();
+person.setName("Alice");
+person.setPet(Animal.ofDog(new Dog()));
+
+byte[] data = person.toBytes();
+Person restored = Person.fromBytes(data);
+```
+
+## Python
+
+### Output Layout
+
+Python output is one module per schema file, for example:
+
+- `<python_out>/addressbook.py`
+
+### Type Generation
+
+Unions generate a case enum plus a `Union` subclass with typed helpers:
+
+```python
+class AnimalCase(Enum):
+    DOG = 1
+    CAT = 2
+
+class Animal(Union):
+    @classmethod
+    def dog(cls, v: Dog) -> "Animal": ...
+
+    def case(self) -> AnimalCase: ...
+    def case_id(self) -> int: ...
+
+    def is_dog(self) -> bool: ...
+    def dog_value(self) -> Dog: ...
+    def set_dog(self, v: Dog) -> None: ...
+```
+
+Messages generate `@pyfory.dataclass` types, and nested types stay nested:
+
+```python
+@pyfory.dataclass
+class Person:
+    class PhoneType(IntEnum):
+        MOBILE = 0
+        HOME = 1
+        WORK = 2
+
+    @pyfory.dataclass
+    class PhoneNumber:
+        number: str = pyfory.field(id=1, default="")
+        phone_type: Person.PhoneType = pyfory.field(id=2, default=None)
+
+    name: str = pyfory.field(id=1, default="")
+    phones: List[Person.PhoneNumber] = pyfory.field(id=7, default_factory=list)
+    pet: Animal = pyfory.field(id=8, default=None)
+
+    def to_bytes(self) -> bytes: ...
+    @classmethod
+    def from_bytes(cls, data: bytes) -> "Person": ...
+```
+
+### Registration
+
+Generated registration function:
+
+```python
+def register_addressbook_types(fory: pyfory.Fory):
+    fory.register_union(Animal, type_id=106, serializer=AnimalSerializer(fory))
+    fory.register_type(Person, type_id=100)
+    fory.register_type(Person.PhoneType, type_id=101)
+    fory.register_type(Person.PhoneNumber, type_id=102)
+    fory.register_type(Dog, type_id=104)
+    fory.register_type(Cat, type_id=105)
+    fory.register_type(AddressBook, type_id=103)
+```
+
+For schemas without explicit `[id=...]`, generated registration uses computed numeric IDs:
+
+```python
+fory.register_type(Status, type_id=1124725126)
+fory.register_union(Wrapper, type_id=1471345060, serializer=WrapperSerializer(fory))
+fory.register_type(Envelope, type_id=3022445236)
+fory.register_union(Envelope.Detail, type_id=1609214087, serializer=Envelope.DetailSerializer(fory))
+fory.register_type(Envelope.Payload, type_id=2862577837)
+```
+
+If `option enable_auto_type_id = false;` is set:
+
+```python
+fory.register_type(Config, namespace="myapp.models", typename="Config")
+fory.register_union(
+    Holder,
+    namespace="myapp.models",
+    typename="Holder",
+    serializer=HolderSerializer(fory),
+)
+```
+
+### Usage
+
+```python
+person = Person(name="Alice", pet=Animal.dog(Dog(name="Rex", bark_volume=10)))
+
+data = person.to_bytes()
+restored = Person.from_bytes(data)
+```
+
+## Rust
+
+### Output Layout
+
+Rust output is one module file per schema, for example:
+
+- `<rust_out>/addressbook.rs`
+
+### Type Generation
+
+Unions map to Rust enums with `#[fory(id = ...)]` case attributes:
+
+```rust
+#[derive(ForyObject, Debug, Clone, PartialEq)]
+pub enum Animal {
+    #[fory(id = 1)]
+    Dog(Dog),
+    #[fory(id = 2)]
+    Cat(Cat),
+}
+```
+
+Nested types generate nested modules:
+
+```rust
+pub mod person {
+    #[derive(ForyObject, Debug, Clone, PartialEq, Default)]
+    #[repr(i32)]
+    pub enum PhoneType {
+        #[default]
+        Mobile = 0,
+        Home = 1,
+        Work = 2,
+    }
+
+    #[derive(ForyObject, Debug, Clone, PartialEq, Default)]
+    pub struct PhoneNumber {
+        #[fory(id = 1)]
+        pub number: String,
+        #[fory(id = 2)]
+        pub phone_type: PhoneType,
+    }
+}
+```
+
+Messages derive `ForyObject` and include `to_bytes`/`from_bytes` helpers:
+
+```rust
+#[derive(ForyObject, Debug, Clone, PartialEq, Default)]
+pub struct Person {
+    #[fory(id = 1)]
+    pub name: String,
+    #[fory(id = 7)]
+    pub phones: Vec<person::PhoneNumber>,
+    #[fory(id = 8, type_id = "union")]
+    pub pet: Animal,
+}
+```
+
+### Registration
+
+Generated registration function:
+
+```rust
+pub fn register_types(fory: &mut Fory) -> Result<(), fory::Error> {
+    fory.register_union::<Animal>(106)?;
+    fory.register::<person::PhoneType>(101)?;
+    fory.register::<person::PhoneNumber>(102)?;
+    fory.register::<Person>(100)?;
+    fory.register::<Dog>(104)?;
+    fory.register::<Cat>(105)?;
+    fory.register::<AddressBook>(103)?;
+    Ok(())
+}
+```
+
+For schemas without explicit `[id=...]`, generated registration uses computed numeric IDs:
+
+```rust
+fory.register::<Status>(1124725126)?;
+fory.register_union::<Wrapper>(1471345060)?;
+fory.register::<Envelope>(3022445236)?;
+fory.register_union::<envelope::Detail>(1609214087)?;
+fory.register::<envelope::Payload>(2862577837)?;
+```
+
+If `option enable_auto_type_id = false;` is set:
+
+```rust
+fory.register_by_namespace::<Config>("myapp.models", "Config")?;
+fory.register_union_by_namespace::<Holder>("myapp.models", "Holder")?;
+```
+
+### Usage
+
+```rust
+let person = Person {
+    name: "Alice".into(),
+    pet: Animal::Dog(Dog::default()),
+    ..Default::default()
+};
+
+let bytes = person.to_bytes()?;
+let restored = Person::from_bytes(&bytes)?;
+```
+
+## C++
+
+### Output Layout
+
+C++ output is one header per schema file, for example:
+
+- `<cpp_out>/addressbook.h`
+
+### Type Generation
+
+Messages generate `final` classes with typed accessors and byte helpers:
+
+```cpp
+class Person final {
+ public:
+  class PhoneNumber final {
+   public:
+    const std::string& number() const;
+    std::string* mutable_number();
+    template <class Arg, class... Args>
+    void set_number(Arg&& arg, Args&&... args);
+
+    fory::Result<std::vector<uint8_t>, fory::Error> to_bytes() const;
+    static fory::Result<PhoneNumber, fory::Error> from_bytes(const std::vector<uint8_t>& data);
+  };
+
+  const std::string& name() const;
+  std::string* mutable_name();
+  template <class Arg, class... Args>
+  void set_name(Arg&& arg, Args&&... args);
+
+  const Animal& pet() const;
+  Animal* mutable_pet();
+};
+```
+
+Optional message fields generate `has_xxx`, `mutable_xxx`, and `clear_xxx` APIs:
+
+```cpp
+class Envelope final {
+ public:
+  bool has_payload() const { return payload_ != nullptr; }
+  const Envelope::Payload& payload() const { return *payload_; }
+  Envelope::Payload* mutable_payload() {
+    if (!payload_) {
+      payload_ = std::make_unique<Envelope::Payload>();
+    }
+    return payload_.get();
+  }
+  void clear_payload() { payload_.reset(); }
+
+ private:
+  std::unique_ptr<Envelope::Payload> payload_;
+};
+```
+
+Unions generate `std::variant` wrappers:
+
+```cpp
+class Animal final {
+ public:
+  enum class AnimalCase : uint32_t {
+    DOG = 1,
+    CAT = 2,
+  };
+
+  static Animal dog(Dog v);
+  static Animal cat(Cat v);
+
+  AnimalCase animal_case() const noexcept;
+  uint32_t animal_case_id() const noexcept;
+
+  bool is_dog() const noexcept;
+  const Dog* as_dog() const noexcept;
+  Dog* as_dog() noexcept;
+  const Dog& dog() const;
+  Dog& dog();
+
+  template <class Visitor>
+  decltype(auto) visit(Visitor&& vis) const;
+
+ private:
+  std::variant<Dog, Cat> value_;
+};
+```
+
+Generated headers also include `FORY_UNION`, `FORY_FIELD_CONFIG`, `FORY_ENUM`, and `FORY_STRUCT` macros for serialization metadata.
+
+### Registration
+
+Generated registration function:
+
+```cpp
+inline void register_types(fory::serialization::BaseFory& fory) {
+    fory.register_union<Animal>(106);
+    fory.register_enum<Person::PhoneType>(101);
+    fory.register_struct<Person::PhoneNumber>(102);
+    fory.register_struct<Person>(100);
+    fory.register_struct<Dog>(104);
+    fory.register_struct<Cat>(105);
+    fory.register_struct<AddressBook>(103);
+}
+```
+
+For schemas without explicit `[id=...]`, generated registration uses computed numeric IDs:
+
+```cpp
+fory.register_enum<Status>(1124725126);
+fory.register_union<Wrapper>(1471345060);
+fory.register_struct<Envelope>(3022445236);
+fory.register_union<Envelope::Detail>(1609214087);
+fory.register_struct<Envelope::Payload>(2862577837);
+```
+
+If `option enable_auto_type_id = false;` is set:
+
+```cpp
+fory.register_struct<Config>("myapp.models", "Config");
+fory.register_union<Holder>("myapp.models", "Holder");
+```
+
+### Usage
+
+```cpp
+addressbook::Person person;
+person.set_name("Alice");
+*person.mutable_pet() = addressbook::Animal::dog(addressbook::Dog{});
+
+auto bytes = person.to_bytes();
+auto restored = addressbook::Person::from_bytes(bytes.value());
+```
+
+## Go
+
+### Output Layout
+
+Go output path depends on schema options and `--go_out`.
+
+For `addressbook.fdl`, `go_package` is configured and generated output follows the configured import path/package (for example under your `--go_out` root).
+
+Without `go_package`, output uses the requested `--go_out` directory and package-derived file naming.
+
+### Type Generation
+
+Nested types use underscore naming by default (`Person_PhoneType`, `Person_PhoneNumber`):
+
+```go
+type Person_PhoneType int32
+
+const (
+    Person_PhoneTypeMobile Person_PhoneType = 0
+    Person_PhoneTypeHome   Person_PhoneType = 1
+    Person_PhoneTypeWork   Person_PhoneType = 2
+)
+
+type Person_PhoneNumber struct {
+    Number    string           `fory:"id=1"`
+    PhoneType Person_PhoneType `fory:"id=2"`
+}
+```
+
+Messages generate structs with `fory` tags and byte helpers:
+
+```go
+type Person struct {
+    Name   string               `fory:"id=1"`
+    Id     int32                `fory:"id=2,compress=true"`
+    Phones []Person_PhoneNumber `fory:"id=7"`
+    Pet    Animal               `fory:"id=8"`
+}
+
+func (m *Person) ToBytes() ([]byte, error) { ... }
+func (m *Person) FromBytes(data []byte) error { ... }
+```
+
+Unions generate typed case structs with constructors/accessors/visitor APIs:
+
+```go
+type AnimalCase uint32
+
+type Animal struct {
+    case_ AnimalCase
+    value any
+}
+
+func DogAnimal(v *Dog) Animal { ... }
+func CatAnimal(v *Cat) Animal { ... }
+
+func (u Animal) Case() AnimalCase { ... }
+func (u Animal) AsDog() (*Dog, bool) { ... }
+func (u Animal) Visit(visitor AnimalVisitor) error { ... }
+```
+
+### Registration
+
+Generated registration function:
+
+```go
+func RegisterTypes(f *fory.Fory) error {
+    if err := f.RegisterUnion(Animal{}, 106, fory.NewUnionSerializer(...)); err != nil {
+        return err
+    }
+    if err := f.RegisterEnum(Person_PhoneType(0), 101); err != nil {
+        return err
+    }
+    if err := f.RegisterStruct(Person_PhoneNumber{}, 102); err != nil {
+        return err
+    }
+    if err := f.RegisterStruct(Person{}, 100); err != nil {
+        return err
+    }
+    return nil
+}
+```
+
+For schemas without explicit `[id=...]`, generated registration uses computed numeric IDs:
+
+```go
+if err := f.RegisterEnum(Status(0), 1124725126); err != nil { ... }
+if err := f.RegisterUnion(Wrapper{}, 1471345060, fory.NewUnionSerializer(...)); err != nil { ... }
+if err := f.RegisterStruct(Envelope{}, 3022445236); err != nil { ... }
+if err := f.RegisterUnion(Envelope_Detail{}, 1609214087, fory.NewUnionSerializer(...)); err != nil { ... }
+if err := f.RegisterStruct(Envelope_Payload{}, 2862577837); err != nil { ... }
+```
+
+If `option enable_auto_type_id = false;` is set:
+
+```go
+if err := f.RegisterNamedStruct(Config{}, "myapp.models.Config"); err != nil { ... }
+if err := f.RegisterNamedUnion(Holder{}, "myapp.models.Holder", fory.NewUnionSerializer(...)); err != nil { ... }
+```
+
+`go_nested_type_style` controls nested type naming:
+
+```protobuf
+option go_nested_type_style = "camelcase";
+```
+
+### Usage
+
+```go
+person := &Person{
+    Name: "Alice",
+    Pet:  DogAnimal(&Dog{Name: "Rex"}),
+}
+
+data, err := person.ToBytes()
+if err != nil {
+    panic(err)
+}
+var restored Person
+if err := restored.FromBytes(data); err != nil {
+    panic(err)
+}
+```
+
+## Cross-Language Notes
+
+### Type ID Behavior
+
+- Explicit `[id=...]` values are used directly in generated registration.
+- When type IDs are omitted, generated code uses computed numeric IDs (see `auto_id.*` outputs).
+- If `option enable_auto_type_id = false;` is set, generated registration uses namespace/type-name APIs instead of numeric IDs.
+
+### Nested Type Shape
+
+| Language | Nested type form               |
+| -------- | ------------------------------ |
+| Java     | `Person.PhoneNumber`           |
+| Python   | `Person.PhoneNumber`           |
+| Rust     | `person::PhoneNumber`          |
+| C++      | `Person::PhoneNumber`          |
+| Go       | `Person_PhoneNumber` (default) |
+
+### Byte Helper Naming
+
+| Language | Helpers                   |
+| -------- | ------------------------- |
+| Java     | `toBytes` / `fromBytes`   |
+| Python   | `to_bytes` / `from_bytes` |
+| Rust     | `to_bytes` / `from_bytes` |
+| C++      | `to_bytes` / `from_bytes` |
+| Go       | `ToBytes` / `FromBytes`   |
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/grpc-service-design.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/grpc-service-design.md
new file mode 100644
index 0000000000..b1f1883d64
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/grpc-service-design.md
@@ -0,0 +1,219 @@
+---
+title: gRPC Service IDL Design
+sidebar_position: 8
+id: grpc_service_design
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+# gRPC Service IDL Design
+
+## Thoughts and Constraints
+
+- Fory generates native language types for Fory IDL/proto/fbs, not protobuf/flatbuffers runtime types.
+  This makes standard gRPC stubs (which expect protobuf or flatbuffers runtime classes) incompatible
+  with Fory-generated types by default.
+- We should keep the Fory runtime dependency-free from gRPC. Any gRPC integration must be
+  generated code or optional helper files emitted by the compiler.
+- We need to support service definitions in Fory IDL, protobuf, and FlatBuffers, and generate gRPC
+  stubs for Java/Python/Rust/Go/C++.
+
+The design below uses a "service IR" that can be rendered into gRPC stubs in each language,
+with a single serialization strategy (Fory) to keep the system simple and dependency-light.
+
+## Goals
+
+- Add `service` definitions to Fory IDL with protobuf-like syntax.
+- Parse protobuf `service` and FlatBuffers `rpc_service` blocks.
+- Extend the compiler IR with service/method definitions.
+- Generate gRPC stubs for Java/Python/Rust/Go/C++ without adding gRPC runtime deps to Fory.
+- Preserve performance: avoid per-call reflection and minimize allocations in codecs.
+
+## Non-Goals
+
+- Implement a gRPC runtime inside Fory.
+- Provide full interoperability with standard protobuf/flatbuffers gRPC without explicit opt-in.
+- Change core Fory serialization formats or protocol specs.
+
+## IDL Additions
+
+### Fory IDL Service Syntax
+
+Fory IDL service syntax mirrors protobuf:
+
+```protobuf
+service Greeter {
+  rpc SayHello (HelloRequest) returns (HelloReply);
+  rpc LotsOfReplies (HelloRequest) returns (stream HelloReply);
+  rpc LotsOfGreetings (stream HelloRequest) returns (HelloReply);
+  rpc BidiHello (stream HelloRequest) returns (stream HelloReply);
+}
+```
+
+Notes:
+
+- `stream` is supported on request/response for gRPC streaming.
+- Service and method-level `option` blocks are allowed and stored as raw key/value pairs.
+- Service methods must reference message types (not enums or unions).
+
+### Protobuf Service Support
+
+Parse `service` and `rpc` definitions (including `stream`) into proto AST nodes, then
+translate into the shared service IR. Preserve options for round-tripping and future use.
+
+### FlatBuffers `rpc_service` Support
+
+Parse `rpc_service` blocks into the service IR. FlatBuffers methods are mapped to
+unary RPC by default; streaming is a follow-up if FlatBuffers gRPC spec supports it.
+
+## IR Changes
+
+Add new nodes in `compiler/fory_compiler/ir/ast.py`:
+
+```python
+@dataclass
+class RpcMethod:
+    name: str
+    request_type: NamedType
+    response_type: NamedType
+    client_streaming: bool = False
+    server_streaming: bool = False
+    options: dict = field(default_factory=dict)
+    line: int = 0
+    column: int = 0
+    location: Optional[SourceLocation] = None
+
+@dataclass
+class Service:
+    name: str
+    methods: List[RpcMethod] = field(default_factory=list)
+    options: dict = field(default_factory=dict)
+    line: int = 0
+    column: int = 0
+    location: Optional[SourceLocation] = None
+```
+
+Extend `Schema` with `services: List[Service]`.
+
+## Frontend Updates
+
+- Fory IDL lexer/parser: add keywords `service`, `rpc`, `returns`, `stream`.
+- Proto parser: replace the current "skip service block" logic with full parsing.
+- FlatBuffers parser: add `rpc_service` parsing and AST nodes.
+- Translators: map format-specific AST into the shared IR.
+
+## Validation Rules
+
+- Service names must be unique per schema.
+- Method names must be unique per service.
+- Request/response types must resolve to message types (not enums/unions).
+- Streaming flags are only allowed on request/response types.
+- FlatBuffers: enforce request/response are tables (or document the accepted type set).
+
+## Serialization Strategy (Only Fory)
+
+- gRPC always uses a custom codec that serializes request/response with Fory.
+- Works with Fory-generated native types across languages.
+- Not wire-compatible with standard protobuf-based gRPC clients.
+- No external protoc/flatc invocation and no extra runtime dependencies in Fory.
+
+## Codegen Architecture
+
+### Compiler Options
+
+New CLI options:
+
+- `--grpc`: enable gRPC stub generation.
+- `--grpc-backend=<lang-specific>`:
+  - Rust: `tonic` (default), future `grpcio`.
+  - C++: `grpc++`.
+  - Java: `grpc-java`.
+  - Go: `grpc-go`.
+  - Python: `grpcio`.
+
+### Generator Integration
+
+- Add a `generate_services()` hook to each language generator.
+- Emit service stubs into a separate file group (for easy optional compilation).
+- If `--grpc` is not set, only emit pure service interfaces (no gRPC deps).
+
+### File Layout (Proposed)
+
+- Java: `*Service.java` for pure interface, `*Grpc.java` for gRPC bindings.
+- Python: `*_service.py` for interface, `*_grpc.py` for gRPC bindings.
+- Go: `*_service.go` for interface, `*_grpc.go` for gRPC bindings.
+- Rust: `service.rs` module and `service_grpc.rs` with gRPC bindings (feature-gated).
+- C++: `service.h` and `service.grpc.h/.cc`.
+
+## Language-Specific gRPC Generation (High Level)
+
+- Java: generate `Grpc` class with `MethodDescriptor`s, server binder, and client stubs.
+  For `fory` serialization, emit a `Marshaller` using Fory encoders/decoders.
+- Python: generate `Servicer` base class and `Stub` class using `grpc` unary/stream APIs.
+  For `fory` serialization, pass serializer/deserializer callables.
+- Go: generate `ServiceDesc`, server interface, and client wrapper. For `fory`, register
+  a custom codec and use it in `grpc.CallOption`.
+- Rust: use `tonic` with a custom codec for `fory`. For protobuf mode, emit standard
+  `tonic` service traits and clients.
+- C++: generate abstract service and stub classes. For `fory`, use gRPC custom
+  serialization hooks to map between Fory types and byte streams.
+
+## Compatibility and Interop
+
+- Fory gRPC is cross-language compatible within Fory, but not compatible with
+  standard protobuf-based gRPC clients.
+
+## Testing Plan
+
+- Parser tests for Fory IDL/proto/fbs service syntax.
+- IR validation tests for method/type resolution and streaming rules.
+- Golden codegen tests that verify gRPC output file names and key signatures.
+- Cross-language smoke tests (optional): gRPC request/response with `fory` codec.
+
+## Decisions
+
+1. FlatBuffers `rpc_service` supports both table and struct types.
+2. gRPC codegen runs only when `--grpc` is enabled.
+3. Rust backend uses `tonic`.
+4. Ship small, generated helper files instead of a separate `fory-grpc` module.
+
+## Expected Codegen Footprint
+
+The compiler will generate a small, predictable set of service files. The exact line
+count scales with the number of RPC methods and whether streaming is used.
+
+### Files per service (per language)
+
+- Java: 2 files (`*Service.java`, `*Grpc.java`)
+- Python: 2 files (`*_service.py`, `*_grpc.py`)
+- Go: 2 files (`*_service.go`, `*_grpc.go`)
+- Rust: 2 files (`service.rs`, `service_grpc.rs`)
+- C++: 3 files (`service.h`, `service.grpc.h`, `service.grpc.cc`)
+
+### Rough size estimate
+
+Each service generates:
+
+- One interface/trait file: roughly 10-20 lines per method.
+- One gRPC binding file: roughly 25-50 lines per method plus a fixed header (about 80-200 lines).
+
+So a service with `M` methods typically adds:
+
+- Java/Python/Go/Rust: about `~(100-200) + (35-70)*M` lines across 2 files.
+- C++: about `~(150-250) + (45-90)*M` lines across 3 files.
+
+These numbers are intentionally conservative; the final output depends on the exact
+backend template we implement.
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/index.md
new file mode 100644
index 0000000000..0038018790
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/index.md
@@ -0,0 +1,213 @@
+---
+title: Overview
+sidebar_position: 1
+id: index
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+Fory IDL is a schema definition language for Apache Fory that enables type-safe
+cross-language serialization. Define your data structures once and generate
+native data structure code for Java, Python, Go, Rust, and C++.
+
+## Example Schema
+
+Fory IDL provides a simple, intuitive syntax for defining cross-language data structures:
+
+```protobuf
+package example;
+
+enum Status {
+    PENDING = 0;
+    ACTIVE = 1;
+    COMPLETED = 2;
+}
+
+message User {
+    string name = 1;
+    int32 age = 2;
+    optional string email = 3;
+    list<string> tags = 4;
+}
+
+message Item {
+    string sku = 1;
+    int32 quantity = 2;
+}
+
+message Order {
+    ref User customer = 1;
+    list<Item> items = 2;
+    Status status = 3;
+    map<string, int32> metadata = 4;
+}
+
+message Dog [id=104] {
+    string name = 1;
+    int32 bark_volume = 2;
+}
+
+message Cat [id=105] {
+    string name = 1;
+    int32 lives = 2;
+}
+
+union Animal [id=106] {
+    Dog dog = 1;
+    Cat cat = 2;
+}
+```
+
+## Why Fory IDL?
+
+### Schema-First Development
+
+Define your data model once in Fory IDL and generate consistent, type-safe code across all languages. This ensures:
+
+- **Type Safety**: Catch type errors at compile time, not runtime
+- **Consistency**: All languages use the same field names, types, and structures
+- **Documentation**: Schema serves as living documentation
+- **Evolution**: Managed schema changes across all implementations
+
+### Fory-Native Features
+
+Unlike generic IDLs, Fory IDL is designed specifically for Fory serialization:
+
+- **Reference Tracking**: First-class support for shared and circular references via `ref`
+- **Nullable Fields**: Explicit `optional` modifier for nullable types
+- **Type Registration**: Built-in support for both numeric IDs and namespace-based registration
+- **Native Code Generation**: Generates idiomatic code with Fory annotations/macros
+
+### Low Integration Overhead
+
+Generated code uses native language constructs:
+
+- Java: Plain POJOs with `@ForyField` annotations
+- Python: Dataclasses with type hints
+- Go: Structs with struct tags
+- Rust: Structs with `#[derive(ForyObject)]`
+- C++: Structs with `FORY_STRUCT` macros
+
+## Quick Start
+
+### 1. Install the Compiler
+
+```bash
+pip install fory-compiler
+```
+
+Or install from source:
+
+```bash
+cd compiler
+pip install -e .
+```
+
+### 2. Write Your Schema
+
+Create `example.fdl`:
+
+```protobuf
+package example;
+
+message Person {
+    string name = 1;
+    int32 age = 2;
+    optional string email = 3;
+}
+```
+
+### 3. Generate Code
+
+```bash
+# Generate for all languages
+foryc example.fdl --output ./generated
+
+# Generate for specific languages
+foryc example.fdl --lang java,python --output ./generated
+```
+
+### 4. Use Generated Code
+
+**Java:**
+
+```java
+Person person = new Person();
+person.setName("Alice");
+person.setAge(30);
+byte[] data = person.toBytes();
+```
+
+**Python:**
+
+```python
+import pyfory
+from example import Person
+
+person = Person(name="Alice", age=30)
+data = bytes(person) # or `person.to_bytes()`
+```
+
+## Documentation
+
+| Document                                        | Description                                       |
+| ----------------------------------------------- | ------------------------------------------------- |
+| [Fory IDL Syntax](schema-idl.md)                | Complete language syntax and grammar              |
+| [Type System](schema-idl.md#type-system)        | Primitive types, collections, and type rules      |
+| [Compiler Guide](compiler-guide.md)             | CLI options and build integration                 |
+| [Generated Code](generated-code.md)             | Output format for each target language            |
+| [Protocol Buffers IDL Support](protobuf-idl.md) | Comparison with protobuf and migration guide      |
+| [FlatBuffers IDL Support](flatbuffers-idl.md)   | FlatBuffers mapping rules and codegen differences |
+
+## Key Concepts
+
+### Field Modifiers
+
+- **`optional`**: Field can be null/None
+- **`ref`**: Enable reference tracking for shared/circular references
+- **`list`**: Field is a list/array (alias: `repeated`)
+
+```protobuf
+message Example {
+    optional string nullable = 1;
+    ref Node parent = 2;
+    list<int32> numbers = 3;
+}
+```
+
+### Cross-Language Compatibility
+
+Fory IDL types map to native types in each language:
+
+| Fory IDL Type | Java      | Python         | Go       | Rust     | C++           |
+| ------------- | --------- | -------------- | -------- | -------- | ------------- |
+| `int32`       | `int`     | `pyfory.int32` | `int32`  | `i32`    | `int32_t`     |
+| `string`      | `String`  | `str`          | `string` | `String` | `std::string` |
+| `bool`        | `boolean` | `bool`         | `bool`   | `bool`   | `bool`        |
+
+See [Type System](schema-idl.md#type-system) for complete mappings.
+
+## Best Practices
+
+1. **Use meaningful package names**: Group related types together
+2. **Assign type IDs for performance**: Numeric IDs are faster than name-based registration
+3. **Reserve ID ranges**: Leave gaps for future additions (e.g., 100-199 for users, 200-299 for orders)
+4. **Use `optional` explicitly**: Make nullability clear in the schema
+5. **Use `ref` for shared objects**: Enable reference tracking when objects are shared
+
+## Examples
+
+See the [examples](https://github.com/apache/fory/tree/main/compiler/examples) directory for complete working examples.
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/protobuf-idl.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/protobuf-idl.md
new file mode 100644
index 0000000000..8292a00f5e
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/protobuf-idl.md
@@ -0,0 +1,335 @@
+---
+title: Protobuf IDL Support
+sidebar_position: 10
+id: protobuf_idl_support
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+This page explains how Apache Fory works with Protocol Buffers (`.proto`) schemas,
+how protobuf concepts map to Fory, and how to use protobuf-only Fory extension options.
+
+## What This Page Covers
+
+- Choosing protobuf vs Fory for your use case
+- Syntax and semantic differences that matter during migration
+- Supported Fory extension options in protobuf files
+- Practical migration patterns from protobuf to Fory
+
+## Quick Decision Guide
+
+| Situation                                                     | Recommended Format |
+| ------------------------------------------------------------- | ------------------ |
+| You are building gRPC APIs and rely on protobuf tooling       | Protocol Buffers   |
+| You need maximum object-graph performance and ref tracking    | Fory               |
+| You need circular/shared references in serialized data        | Fory               |
+| You need strong unknown-field behavior for wire compatibility | Protocol Buffers   |
+| You need native structs/classes instead of protobuf wrappers  | Fory               |
+
+## Protobuf vs Fory at a Glance
+
+| Aspect             | Protocol Buffers              | Fory                                  |
+| ------------------ | ----------------------------- | ------------------------------------- |
+| Primary purpose    | RPC/message contracts         | High-performance object serialization |
+| Encoding model     | Tag-length-value              | Fory binary protocol                  |
+| Reference tracking | Not built-in                  | First-class (`ref`)                   |
+| Circular refs      | Not supported                 | Supported                             |
+| Unknown fields     | Preserved                     | Not preserved                         |
+| Generated types    | Protobuf-specific model types | Native language constructs            |
+| gRPC ecosystem     | Native                        | In progress (active development)      |
+
+Fory gRPC support is under active development. For production gRPC
+workflows today, protobuf remains the mature/default choice.
+
+## Why Use Apache Fory
+
+- Idiomatic generated code: Fory IDL generates language-idiomatic classes and
+  structs that can be used directly as domain objects.
+- Faster serialization: In Fory benchmarks, Fory can be around 10x faster than
+  protobuf for object serialization workloads.
+- Better graph modeling: Shared and circular references are first-class features
+  instead of application-level ID-link workarounds.
+
+See benchmark details under [Performance References](#performance-references).
+
+## Syntax and Semantic Mapping
+
+### Package and File Options
+
+**Protocol Buffers**
+
+```protobuf
+syntax = "proto3";
+package example.models;
+option java_package = "com.example.models";
+option go_package = "example.com/models";
+```
+
+**Fory**
+
+```protobuf
+package example.models;
+```
+
+Fory uses one package namespace for cross-language registration. Language-specific
+package placement is still configurable in code generation.
+
+### Message and Enum Definitions
+
+**Protocol Buffers**
+
+```protobuf
+message User {
+  string id = 1;
+  string name = 2;
+  optional string email = 3;
+  int32 age = 4;
+  repeated string tags = 5;
+  map<string, string> metadata = 6;
+}
+
+enum Status {
+  STATUS_UNSPECIFIED = 0;
+  STATUS_ACTIVE = 1;
+}
+```
+
+**Fory**
+
+```protobuf
+message User [id=101] {
+    string id = 1;
+    string name = 2;
+    optional string email = 3;
+    int32 age = 4;
+    list<string> tags = 5;
+    map<string, string> metadata = 6;
+}
+
+enum Status [id=102] {
+    UNKNOWN = 0;
+    ACTIVE = 1;
+}
+```
+
+Key differences:
+
+- Fory can assign stable type IDs directly (`[id=...]`).
+- Fory uses `list<T>` (with `repeated T` as alias).
+- Enum naming conventions are language-driven instead of protobuf prefix style.
+
+### `oneof` to `union`
+
+Protobuf `oneof` is translated to a nested Fory `union` plus an optional field
+referencing that union.
+
+**Protocol Buffers**
+
+```protobuf
+message Event {
+  oneof payload {
+    string text = 1;
+    int32 number = 2;
+  }
+}
+```
+
+**Fory-style shape after translation**
+
+```protobuf
+message Event {
+    union payload {
+        string text = 1;
+        int32 number = 2;
+    }
+    optional payload payload = 1;
+}
+```
+
+Notes:
+
+- Union case IDs are derived from the original `oneof` field numbers.
+- The synthetic union field uses the smallest `oneof` case number.
+
+### Imports and Well-Known Types
+
+Protobuf imports are supported. Common well-known types map directly:
+
+- `google.protobuf.Timestamp` -> `timestamp`
+- `google.protobuf.Duration` -> `duration`
+- `google.protobuf.Any` -> `any`
+
+## Type Mapping Highlights
+
+| Protobuf Type                            | Fory Mapping                             |
+| ---------------------------------------- | ---------------------------------------- |
+| `bool`                                   | `bool`                                   |
+| `int32`, `uint32`                        | variable-length 32-bit integer kinds     |
+| `sint32`                                 | zigzag 32-bit integer                    |
+| `int64`, `uint64`                        | variable-length 64-bit integer kinds     |
+| `sint64`                                 | zigzag 64-bit integer                    |
+| `fixed32`, `fixed64`                     | fixed-width unsigned integer kinds       |
+| `sfixed32`, `sfixed64`                   | fixed-width signed integer kinds         |
+| `float`, `double`                        | `float32`, `float64`                     |
+| `string`, `bytes`                        | `string`, `bytes`                        |
+| `repeated T`                             | `list<T>`                                |
+| `map<K, V>`                              | `map<K, V>`                              |
+| `optional T`                             | `optional T`                             |
+| `oneof`                                  | `union` + optional union reference field |
+| `int64 [(fory).type = "tagged_int64"]`   | `tagged_int64` encoding                  |
+| `uint64 [(fory).type = "tagged_uint64"]` | `tagged_uint64` encoding                 |
+
+## Fory Extension Options (Protobuf)
+
+Fory-specific options in `.proto` use the `(fory).` prefix.
+
+```protobuf
+option (fory).enable_auto_type_id = true;
+
+message TreeNode {
+  TreeNode parent = 1 [(fory).weak_ref = true];
+  repeated TreeNode children = 2 [(fory).ref = true];
+}
+```
+
+### File-Level Options
+
+| Option                               | Type   | Description                                                    |
+| ------------------------------------ | ------ | -------------------------------------------------------------- |
+| `(fory).use_record_for_java_message` | bool   | Generate Java records for all messages in this file            |
+| `(fory).polymorphism`                | bool   | Enable polymorphic serialization metadata by default           |
+| `(fory).enable_auto_type_id`         | bool   | Auto-generate type IDs when omitted (compiler default is true) |
+| `(fory).evolving`                    | bool   | Default schema-evolution behavior for messages                 |
+| `(fory).go_nested_type_style`        | string | Go nested naming style: `underscore` (default) or `camelcase`  |
+
+### Message and Enum Options
+
+| Option                       | Applies To    | Type   | Description                              |
+| ---------------------------- | ------------- | ------ | ---------------------------------------- |
+| `(fory).id`                  | message, enum | int    | Explicit type ID for registration        |
+| `(fory).alias`               | message, enum | string | Alternate name used for auto-ID hashing  |
+| `(fory).evolving`            | message       | bool   | Override file-level evolution setting    |
+| `(fory).use_record_for_java` | message       | bool   | Generate Java record for this message    |
+| `(fory).deprecated`          | message, enum | bool   | Mark type as deprecated                  |
+| `(fory).namespace`           | message       | string | Override default package-based namespace |
+
+### Field-Level Options
+
+| Option                       | Type   | Description                                                  |
+| ---------------------------- | ------ | ------------------------------------------------------------ |
+| `(fory).ref`                 | bool   | Enable reference tracking for this field                     |
+| `(fory).nullable`            | bool   | Treat field as nullable (`optional`)                         |
+| `(fory).weak_ref`            | bool   | Generate weak pointer semantics (C++/Rust codegen)           |
+| `(fory).thread_safe_pointer` | bool   | Rust pointer flavor for ref fields (`Arc` vs `Rc`)           |
+| `(fory).deprecated`          | bool   | Mark field as deprecated                                     |
+| `(fory).type`                | string | Primitive override, currently `tagged_int64`/`tagged_uint64` |
+
+Reference option behavior:
+
+- `weak_ref = true` implies ref tracking.
+- For `repeated` fields, `(fory).ref = true` applies to list elements.
+- For `map<K, V>` fields, `(fory).ref = true` applies to map values.
+- `weak_ref` and `thread_safe_pointer` are codegen hints for C++/Rust.
+
+### Option Examples by Shape
+
+```protobuf
+message Graph {
+  Node root = 1 [(fory).ref = true, (fory).thread_safe_pointer = false];
+  repeated Node nodes = 2 [(fory).ref = true];
+  map<string, Node> cache = 3 [(fory).ref = true];
+  Node parent = 4 [(fory).weak_ref = true];
+}
+```
+
+## Reference Tracking vs Protobuf IDs
+
+Protobuf itself does not preserve shared/cyclic object graphs. With Fory
+protobuf extensions, you can opt into graph semantics.
+
+**Without Fory ref options (protobuf-style IDs):**
+
+```protobuf
+message TreeNode {
+  string id = 1;
+  string parent_id = 2;
+  repeated string child_ids = 3;
+}
+```
+
+**With Fory ref options (object graph):**
+
+```protobuf
+message TreeNode {
+  TreeNode parent = 1 [(fory).weak_ref = true];
+  repeated TreeNode children = 2 [(fory).ref = true];
+}
+```
+
+## Migration Guide: Protobuf to Fory
+
+### Step 1: Translate Schema Syntax
+
+- Keep package names stable.
+- Replace `repeated T` with `list<T>` (or keep `repeated` alias).
+- Add explicit `[id=...]` where you need stable numeric registration.
+
+### Step 2: Convert `oneof` and Special Types
+
+- `oneof` -> `union` + optional union field.
+- Map protobuf well-known types to Fory primitives (`timestamp`, `duration`, `any`).
+
+### Step 3: Replace Protobuf Workarounds with `ref`
+
+Where protobuf used manual ID links for object graphs, switch to Fory `ref`
+modifiers (and optional `ref(weak=true)` where needed).
+
+### Step 4: Update Build/Codegen
+
+Replace protobuf generation steps with the Fory compiler invocation for target
+languages.
+
+### Step 5: Run Compatibility Checks
+
+For staged migrations, keep both formats in parallel and verify payload-level
+parity with integration tests.
+
+## Coexistence Strategy
+
+You can run protobuf and Fory in parallel during migration:
+
+```java
+public byte[] serialize(Object obj, Format format) {
+    if (format == Format.PROTOBUF) {
+        return ((MessageLite) obj).toByteArray();
+    }
+    return fory.serialize(obj);
+}
+```
+
+Use translators at service boundaries while internal object-graph heavy paths
+migrate first.
+
+## Performance References
+
+- Benchmarks: https://fory.apache.org/docs/introduction/benchmark
+- Benchmark code: https://github.com/apache/fory/tree/main/benchmarks
+
+## Summary
+
+Use protobuf when your primary concern is API contracts and gRPC ecosystem
+integration. Use Fory when object-graph performance, native models, and
+reference semantics are the primary concern.
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/schema-idl.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/schema-idl.md
new file mode 100644
index 0000000000..4e297aa770
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/compiler/schema-idl.md
@@ -0,0 +1,1398 @@
+---
+title: Schema IDL
+sidebar_position: 2
+id: syntax
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+This document provides the syntax and semantic reference for Fory IDL.
+
+For compiler usage and build integration, see
+[Compiler Guide](compiler-guide.md). For protobuf/FlatBuffers frontend mapping
+rules, see [Protocol Buffers IDL Support](protobuf-idl.md) and
+[FlatBuffers IDL Support](flatbuffers-idl.md).
+
+## File Structure
+
+An Fory IDL file typically consists of:
+
+1. Optional package declaration
+2. Optional file-level options
+3. Optional import statements
+4. Type definitions (enums, messages, and unions)
+
+```protobuf
+// Optional package declaration
+package com.example.models;
+
+// Optional file-level options
+option java_package = "com.example.models";
+
+// Import statements
+import "common/types.fdl";
+
+// Type definitions
+enum Color [id=100] { ... }
+message User [id=101] { ... }
+message Order [id=102] { ... }
+union Event [id=103] { ... }
+```
+
+## Comments
+
+Fory IDL supports both single-line and block comments:
+
+```protobuf
+// This is a single-line comment
+
+/*
+ * This is a block comment
+ * that spans multiple lines
+ */
+
+message Example {
+    string name = 1;  // Inline comment
+}
+```
+
+## Package Declaration
+
+The package declaration defines the namespace for all types in the file.
+
+```protobuf
+package com.example.models;
+```
+
+You can optionally specify a package alias used for auto-generated type IDs:
+
+```protobuf
+package com.example.models alias models_v1;
+```
+
+**Rules:**
+
+- Optional but recommended
+- Must appear before any type definitions
+- Only one package declaration per file
+- Used for namespace-based type registration
+- Package alias is used for auto-ID hashing
+
+**Language Mapping:**
+
+| Language | Package Usage                     |
+| -------- | --------------------------------- |
+| Java     | Java package                      |
+| Python   | Module name (dots to underscores) |
+| Go       | Package name (last component)     |
+| Rust     | Module name (dots to underscores) |
+| C++      | Namespace (dots to `::`)          |
+
+## File-Level Options
+
+Options can be specified at file level to control language-specific code generation.
+
+### Syntax
+
+```protobuf
+option option_name = value;
+```
+
+### Java Package Option
+
+Override the Java package for generated code:
+
+```protobuf
+package payment;
+option java_package = "com.mycorp.payment.v1";
+
+message Payment {
+    string id = 1;
+}
+```
+
+**Effect:**
+
+- Generated Java files will be in `com/mycorp/payment/v1/` directory
+- Java package declaration will be `package com.mycorp.payment.v1;`
+- Type registration still uses the Fory IDL package (`payment`) for cross-language compatibility
+
+### Go Package Option
+
+Specify the Go import path and package name:
+
+```protobuf
+package payment;
+option go_package = "github.com/mycorp/apis/gen/payment/v1;paymentv1";
+
+message Payment {
+    string id = 1;
+}
+```
+
+**Format:** `"import/path;package_name"` or just `"import/path"` (last segment used as package name)
+
+**Effect:**
+
+- Generated Go files will have `package paymentv1`
+- The import path can be used in other Go code
+- Type registration still uses the Fory IDL package (`payment`) for cross-language compatibility
+
+### Java Outer Classname Option
+
+Generate all types as inner classes of a single outer wrapper class:
+
+```protobuf
+package payment;
+option java_outer_classname = "DescriptorProtos";
+
+enum Status {
+    UNKNOWN = 0;
+    ACTIVE = 1;
+}
+
+message Payment {
+    string id = 1;
+    Status status = 2;
+}
+```
+
+**Effect:**
+
+- Generates a single file `DescriptorProtos.java` instead of separate files
+- All enums and messages become `public static` inner classes
+- The outer class is `public final` with a private constructor
+- Useful for grouping related types together
+
+**Generated structure:**
+
+```java
+public final class DescriptorProtos {
+    private DescriptorProtos() {}
+
+    public static enum Status {
+        UNKNOWN,
+        ACTIVE;
+    }
+
+    public static class Payment {
+        private String id;
+        private Status status;
+        // ...
+    }
+}
+```
+
+**Combined with java_package:**
+
+```protobuf
+package payment;
+option java_package = "com.example.proto";
+option java_outer_classname = "PaymentProtos";
+
+message Payment {
+    string id = 1;
+}
+```
+
+This generates `com/example/proto/PaymentProtos.java` with all types as inner classes.
+
+### Java Multiple Files Option
+
+Control whether types are generated in separate files or as inner classes:
+
+```protobuf
+package payment;
+option java_outer_classname = "PaymentProtos";
+option java_multiple_files = true;
+
+message Payment {
+    string id = 1;
+}
+
+message Receipt {
+    string id = 1;
+}
+```
+
+**Behavior:**
+
+| `java_outer_classname` | `java_multiple_files` | Result                                      |
+| ---------------------- | --------------------- | ------------------------------------------- |
+| Not set                | Any                   | Separate files (one per type)               |
+| Set                    | `false` (default)     | Single file with all types as inner classes |
+| Set                    | `true`                | Separate files (overrides outer class)      |
+
+**Effect of `java_multiple_files = true`:**
+
+- Each top-level enum and message gets its own `.java` file
+- Overrides `java_outer_classname` behavior
+- Useful when you want separate files but still specify an outer class name for other purposes
+
+**Example without java_multiple_files (default):**
+
+```protobuf
+option java_outer_classname = "PaymentProtos";
+// Generates: PaymentProtos.java containing Payment and Receipt as inner classes
+```
+
+**Example with java_multiple_files = true:**
+
+```protobuf
+option java_outer_classname = "PaymentProtos";
+option java_multiple_files = true;
+// Generates: Payment.java, Receipt.java (separate files)
+```
+
+### Multiple Options
+
+Multiple options can be specified:
+
+```protobuf
+package payment;
+option java_package = "com.mycorp.payment.v1";
+option go_package = "github.com/mycorp/apis/gen/payment/v1;paymentv1";
+option deprecated = true;
+
+message Payment {
+    string id = 1;
+}
+```
+
+### Protobuf Extension Syntax
+
+In `.fdl` files, use native Fory IDL syntax only (for example, `[id=100]`, `ref`,
+`optional`, `nullable=true`).
+
+Protobuf extension syntax with `(fory).` is for `.proto` files and the protobuf
+frontend only.
+
+For protobuf extension options, see
+[Protocol Buffers IDL Support](protobuf-idl.md#fory-extension-options-protobuf).
+
+### Option Priority
+
+For language-specific packages:
+
+1. Command-line package override (highest priority)
+2. Language-specific option (`java_package`, `go_package`)
+3. Fory IDL package declaration (fallback)
+
+**Example:**
+
+```protobuf
+package myapp.models;
+option java_package = "com.example.generated";
+```
+
+| Scenario                  | Java Package Used         |
+| ------------------------- | ------------------------- |
+| No override               | `com.example.generated`   |
+| CLI: `--package=override` | `override`                |
+| No java_package option    | `myapp.models` (fallback) |
+
+### Cross-Language Type Registration
+
+Language-specific options only affect where code is generated, not the type namespace used for serialization. This ensures cross-language compatibility:
+
+```protobuf
+package myapp.models;
+option java_package = "com.mycorp.generated";
+option go_package = "github.com/mycorp/gen;genmodels";
+
+message User {
+    string name = 1;
+}
+```
+
+All languages will register `User` with namespace `myapp.models`, enabling:
+
+- Java serialized data → Go deserialization
+- Go serialized data → Java deserialization
+- Any language combination works seamlessly
+
+## Import Statement
+
+Import statements allow you to use types defined in other Fory IDL files.
+
+### Basic Syntax
+
+```protobuf
+import "path/to/file.fdl";
+```
+
+### Multiple Imports
+
+```protobuf
+import "common/types.fdl";
+import "common/enums.fdl";
+import "models/address.fdl";
+```
+
+### Path Resolution
+
+Import paths are resolved relative to the importing file:
+
+```
+project/
+├── common/
+│   └── types.fdl
+├── models/
+│   ├── user.fdl      # import "../common/types.fdl"
+│   └── order.fdl     # import "../common/types.fdl"
+└── main.fdl          # import "common/types.fdl"
+```
+
+**Rules:**
+
+- Import paths are quoted strings (double or single quotes)
+- Paths are resolved relative to the importing file's directory
+- Imported types become available as if defined in the current file
+- Circular imports are detected and reported as errors
+- Transitive imports work (if A imports B and B imports C, A has access to C's types)
+
+### Complete Example
+
+**common/types.fdl:**
+
+```protobuf
+package common;
+
+enum Status [id=100] {
+    PENDING = 0;
+    ACTIVE = 1;
+    COMPLETED = 2;
+}
+
+message Address [id=101] {
+    string street = 1;
+    string city = 2;
+    string country = 3;
+}
+```
+
+**models/user.fdl:**
+
+```protobuf
+package models;
+import "../common/types.fdl";
+
+message User [id=200] {
+    string id = 1;
+    string name = 2;
+    Address home_address = 3;  // Uses imported type
+    Status status = 4;          // Uses imported enum
+}
+```
+
+### Unsupported Import Syntax
+
+The following protobuf import modifiers are **not supported**:
+
+```protobuf
+// NOT SUPPORTED - will produce an error
+import public "other.fdl";
+import weak "other.fdl";
+```
+
+**`import public`**: Fory IDL uses a simpler import model. All imported types are available to the importing file only. Re-exporting is not supported. Import each file directly where needed.
+
+**`import weak`**: Fory IDL requires all imports to be present at compile time. Optional dependencies are not supported.
+
+### Import Errors
+
+The compiler reports errors for:
+
+- **File not found**: The imported file doesn't exist
+- **Circular import**: A imports B which imports A (directly or indirectly)
+- **Parse errors**: Syntax errors in imported files
+- **Unsupported syntax**: `import public` or `import weak`
+
+## Enum Definition
+
+Enums define a set of named integer constants.
+
+### Basic Syntax
+
+```protobuf
+enum Status {
+    PENDING = 0;
+    ACTIVE = 1;
+    COMPLETED = 2;
+}
+```
+
+### With Explicit Type ID
+
+```protobuf
+enum Status [id=100] {
+    PENDING = 0;
+    ACTIVE = 1;
+    COMPLETED = 2;
+}
+```
+
+### Reserved Values
+
+Reserve field numbers or names to prevent reuse:
+
+```protobuf
+enum Status {
+    reserved 2, 15, 9 to 11, 40 to max;  // Reserved numbers
+    reserved "OLD_STATUS", "DEPRECATED"; // Reserved names
+    PENDING = 0;
+    ACTIVE = 1;
+    COMPLETED = 3;
+}
+```
+
+### Enum Type Options
+
+Enum-level options are declared inline in `[]` after the enum name:
+
+```protobuf
+enum Status [deprecated=true] {
+    PENDING = 0;
+    ACTIVE = 1;
+}
+```
+
+FDL does not support `option ...;` statements inside enum bodies.
+
+**Unsupported:**
+
+- `allow_alias` is **not supported**. Each enum value must have a unique integer.
+
+### Language Mapping
+
+| Language | Implementation                         |
+| -------- | -------------------------------------- |
+| Java     | `enum Status { UNKNOWN, ACTIVE, ... }` |
+| Python   | `class Status(IntEnum): UNKNOWN = 0`   |
+| Go       | `type Status int32` with constants     |
+| Rust     | `#[repr(i32)] enum Status { Unknown }` |
+| C++      | `enum class Status : int32_t { ... }`  |
+
+### Enum Prefix Stripping
+
+When enum values use a protobuf-style prefix (enum name in UPPER_SNAKE_CASE), the compiler automatically strips the prefix for languages with scoped enums:
+
+```protobuf
+// Input with prefix
+enum DeviceTier {
+    DEVICE_TIER_UNKNOWN = 0;
+    DEVICE_TIER_TIER1 = 1;
+    DEVICE_TIER_TIER2 = 2;
+}
+```
+
+**Generated code:**
+
+| Language | Output                                    | Style          |
+| -------- | ----------------------------------------- | -------------- |
+| Java     | `UNKNOWN, TIER1, TIER2`                   | Scoped enum    |
+| Rust     | `Unknown, Tier1, Tier2`                   | Scoped enum    |
+| C++      | `UNKNOWN, TIER1, TIER2`                   | Scoped enum    |
+| Python   | `UNKNOWN, TIER1, TIER2`                   | Scoped IntEnum |
+| Go       | `DeviceTierUnknown, DeviceTierTier1, ...` | Unscoped const |
+
+**Note:** The prefix is only stripped if the remainder is a valid identifier. For example, `DEVICE_TIER_1` is kept unchanged because `1` is not a valid identifier name.
+
+**Grammar:**
+
+```
+enum_def     := 'enum' IDENTIFIER [type_options] '{' enum_body '}'
+type_options := '[' type_option (',' type_option)* ']'
+type_option  := IDENTIFIER '=' option_value
+enum_body    := (reserved_stmt | enum_value)*
+reserved_stmt := 'reserved' reserved_items ';'
+enum_value   := IDENTIFIER '=' INTEGER ';'
+```
+
+**Rules:**
+
+- Enum names must be unique within the file
+- Enum values must have explicit integer assignments
+- Value integers must be unique within the enum (no aliases)
+- Type ID (`[id=100]`) is optional for enums but recommended for cross-language use
+
+**Example with All Features:**
+
+```protobuf
+// HTTP status code categories
+enum HttpCategory [id=200] {
+    reserved 10 to 20;           // Reserved for future use
+    reserved "UNKNOWN";          // Reserved name
+    INFORMATIONAL = 1;
+    SUCCESS = 2;
+    REDIRECTION = 3;
+    CLIENT_ERROR = 4;
+    SERVER_ERROR = 5;
+}
+```
+
+## Message Definition
+
+Messages define structured data types with typed fields.
+
+### Basic Syntax
+
+```protobuf
+message Person {
+    string name = 1;
+    int32 age = 2;
+}
+```
+
+### With Explicit Type ID
+
+```protobuf
+message Person [id=101] {
+    string name = 1;
+    int32 age = 2;
+}
+```
+
+### Without Explicit Type ID
+
+```protobuf
+message Person {  // Auto-generated when enable_auto_type_id = true
+    string name = 1;
+    int32 age = 2;
+}
+```
+
+### Language Mapping
+
+| Language | Implementation                      |
+| -------- | ----------------------------------- |
+| Java     | POJO class with getters/setters     |
+| Python   | `@dataclass` class                  |
+| Go       | Struct with exported fields         |
+| Rust     | Struct with `#[derive(ForyObject)]` |
+| C++      | Struct with `FORY_STRUCT` macro     |
+
+Type IDs control cross-language registration for messages, unions, and enums. See
+[Type IDs](#type-ids) for auto-generation, aliases, and collision handling.
+
+### Reserved Fields
+
+Reserve field numbers or names to prevent reuse after removing fields:
+
+```protobuf
+message User {
+    reserved 2, 15, 9 to 11;       // Reserved field numbers
+    reserved "old_field", "temp";  // Reserved field names
+    string id = 1;
+    string name = 3;
+}
+```
+
+### Message Type Options
+
+Message-level options are declared inline in `[]` after the message name:
+
+```protobuf
+message User [deprecated=true] {
+    string id = 1;
+    string name = 2;
+}
+```
+
+FDL does not support `option ...;` statements inside message or enum bodies.
+
+**Grammar:**
+
+```
+message_def  := 'message' IDENTIFIER [type_options] '{' message_body '}'
+type_options := '[' type_option (',' type_option)* ']'
+type_option  := IDENTIFIER '=' option_value
+message_body := (reserved_stmt | nested_type | field_def)*
+nested_type  := enum_def | message_def | union_def
+```
+
+**Rules:**
+
+- Type IDs follow the rules in [Type IDs](#type-ids).
+
+## Nested Types
+
+Messages can contain nested message, enum, and union definitions. This is useful for defining types that are closely related to their parent message.
+
+### Nested Messages
+
+```protobuf
+message SearchResponse {
+    message Result {
+        string url = 1;
+        string title = 2;
+        list<string> snippets = 3;
+    }
+    list<Result> results = 1;
+}
+```
+
+### Nested Enums
+
+```protobuf
+message Container {
+    enum Status {
+        STATUS_UNKNOWN = 0;
+        STATUS_ACTIVE = 1;
+        STATUS_INACTIVE = 2;
+    }
+    Status status = 1;
+}
+```
+
+### Qualified Type Names
+
+Nested types can be referenced from other messages using qualified names (Parent.Child):
+
+```protobuf
+message SearchResponse {
+    message Result {
+        string url = 1;
+        string title = 2;
+    }
+}
+
+message SearchResultCache {
+    // Reference nested type with qualified name
+    SearchResponse.Result cached_result = 1;
+    list<SearchResponse.Result> all_results = 2;
+}
+```
+
+### Deeply Nested Types
+
+Nesting can be multiple levels deep:
+
+```protobuf
+message Outer {
+    message Middle {
+        message Inner {
+            string value = 1;
+        }
+        Inner inner = 1;
+    }
+    Middle middle = 1;
+}
+
+message OtherMessage {
+    // Reference deeply nested type
+    Outer.Middle.Inner deep_ref = 1;
+}
+```
+
+### Language-Specific Generation
+
+| Language | Nested Type Generation                                                            |
+| -------- | --------------------------------------------------------------------------------- |
+| Java     | Static inner classes (`SearchResponse.Result`)                                    |
+| Python   | Nested classes within dataclass                                                   |
+| Go       | Flat structs with underscore (`SearchResponse_Result`, configurable to camelcase) |
+| Rust     | Nested modules (`search_response::Result`)                                        |
+| C++      | Nested classes (`SearchResponse::Result`)                                         |
+
+**Note:** Go defaults to underscore-separated nested names; set `option go_nested_type_style = "camelcase";` to use concatenated names. Rust emits nested modules for nested types.
+
+### Nested Type Rules
+
+- Nested type names must be unique within their parent message
+- Nested types can have their own type IDs
+- Numeric type IDs must be globally unique (including nested types); see [Type IDs](#type-ids)
+  for auto-generation and collision handling
+- Within a message, you can reference nested types by simple name
+- From outside, use the qualified name (Parent.Child)
+
+## Union Definition
+
+Unions define a value that can hold exactly one of several case types.
+
+### Basic Syntax
+
+```protobuf
+union Animal [id=106] {
+    Dog dog = 1;
+    Cat cat = 2;
+}
+```
+
+### Using a Union in a Message
+
+```protobuf
+message Person [id=100] {
+    Animal pet = 1;
+    optional Animal favorite_pet = 2;
+}
+```
+
+### Rules
+
+- Case IDs must be unique within the union
+- Cases cannot be `optional` or `ref`
+- Union cases do not support field options
+- Case types can be primitives, enums, messages, or other named types
+- Union type IDs follow the rules in [Type IDs](#type-ids).
+
+**Grammar:**
+
+```
+union_def  := 'union' IDENTIFIER [type_options] '{' union_field* '}'
+union_field := field_type IDENTIFIER '=' INTEGER ';'
+```
+
+## Field Definition
+
+Fields define the properties of a message.
+
+### Basic Syntax
+
+```protobuf
+field_type field_name = field_number;
+```
+
+### With Modifiers
+
+```protobuf
+optional list<string> tags = 1;  // Nullable list
+list<optional string> tags = 2;  // Elements may be null
+ref list<Node> nodes = 3;        // Collection tracked as a reference
+list<ref Node> nodes = 4;        // Elements tracked as references
+```
+
+**Grammar:**
+
+```
+field_def    := [modifiers] field_type IDENTIFIER '=' INTEGER ';'
+modifiers    := { 'optional' | 'ref' }
+field_type   := primitive_type | named_type | list_type | map_type
+list_type    := 'list' '<' { 'optional' | 'ref' } field_type '>'
+```
+
+Modifiers apply to the field/collection. Use `list<...>` to describe element
+modifiers. `repeated` is accepted as an alias for `list`.
+
+### Field Modifiers
+
+#### `optional`
+
+Marks the field as nullable:
+
+```protobuf
+message User {
+    string name = 1;           // Required, non-null
+    optional string email = 2; // Nullable
+}
+```
+
+**Generated Code:**
+
+| Language | Non-optional       | Optional                                        |
+| -------- | ------------------ | ----------------------------------------------- |
+| Java     | `String name`      | `String email` with `@ForyField(nullable=true)` |
+| Python   | `name: str`        | `name: Optional[str]`                           |
+| Go       | `Name string`      | `Name *string`                                  |
+| Rust     | `name: String`     | `name: Option<String>`                          |
+| C++      | `std::string name` | `std::optional<std::string> name`               |
+
+**Default Values:**
+
+| Type               | Default Value       |
+| ------------------ | ------------------- |
+| Non-optional types | Language default    |
+| Optional types     | `null`/`None`/`nil` |
+
+#### `ref`
+
+Enables reference tracking for shared/circular references:
+
+```protobuf
+message Node {
+    string value = 1;
+    ref Node parent = 2;     // Can point to shared object
+    list<ref Node> children = 3;
+}
+```
+
+**Use Cases:**
+
+- Shared objects (same object referenced multiple times)
+- Circular references (object graphs with cycles)
+- Tree structures with parent pointers
+
+**Generated Code:**
+
+| Language | Without `ref`  | With `ref`                                |
+| -------- | -------------- | ----------------------------------------- |
+| Java     | `Node parent`  | `Node parent` with `@ForyField(ref=true)` |
+| Python   | `parent: Node` | `parent: Node = pyfory.field(ref=True)`   |
+| Go       | `Parent Node`  | `Parent *Node` with `fory:"ref"`          |
+| Rust     | `parent: Node` | `parent: Arc<Node>`                       |
+| C++      | `Node parent`  | `std::shared_ptr<Node> parent`            |
+
+Rust uses `Arc` by default; use `ref(thread_safe=false)` or `ref(weak=true)`
+to customize pointer types. For protobuf option syntax, see
+[Protocol Buffers IDL Support](protobuf-idl.md#field-level-options).
+
+#### `list`
+
+Marks the field as a list/array:
+
+```protobuf
+message Document {
+    list<string> tags = 1;
+    list<User> authors = 2;
+}
+```
+
+**Generated Code:**
+
+| Language | Type                       |
+| -------- | -------------------------- |
+| Java     | `List<String>`             |
+| Python   | `List[str]`                |
+| Go       | `[]string`                 |
+| Rust     | `Vec<String>`              |
+| C++      | `std::vector<std::string>` |
+
+### Combining Modifiers
+
+Modifiers can be combined:
+
+```fdl
+message Example {
+    optional list<string> tags = 1;  // Nullable list
+    list<optional string> aliases = 2; // Elements may be null
+    ref list<Node> nodes = 3;          // Collection tracked as a reference
+    list<ref Node> children = 4;       // Elements tracked as references
+    optional ref User owner = 5;          // Nullable tracked reference
+}
+```
+
+Modifiers before `list` apply to the field/collection. Modifiers after `list`
+apply to elements. `repeated` is accepted as an alias for `list`.
+
+**List modifier mapping:**
+
+| Fory IDL                | Java                                           | Python                                  | Go                      | Rust                  | C++                                       |
+| ----------------------- | ---------------------------------------------- | --------------------------------------- | ----------------------- | --------------------- | ----------------------------------------- |
+| `optional list<string>` | `List<String>` + `@ForyField(nullable = true)` | `Optional[List[str]]`                   | `[]string` + `nullable` | `Option<Vec<String>>` | `std::optional<std::vector<std::string>>` |
+| `list<optional string>` | `List<String>` (nullable elements)             | `List[Optional[str]]`                   | `[]*string`             | `Vec<Option<String>>` | `std::vector<std::optional<std::string>>` |
+| `ref list<User>`        | `List<User>` + `@ForyField(ref = true)`        | `List[User]` + `pyfory.field(ref=True)` | `[]User` + `ref`        | `Arc<Vec<User>>`      | `std::shared_ptr<std::vector<User>>`      |
+| `list<ref User>`        | `List<User>`                                   | `List[User]`                            | `[]*User` + `ref=false` | `Vec<Arc<User>>`      | `std::vector<std::shared_ptr<User>>`      |
+
+Use `ref(thread_safe=false)` in Fory IDL (or `[(fory).thread_safe_pointer = false]` in protobuf)
+to generate `Rc` instead of `Arc` in Rust.
+
+## Field Numbers
+
+Each field must have a unique positive integer identifier:
+
+```protobuf
+message Example {
+    string first = 1;
+    string second = 2;
+    string third = 3;
+}
+```
+
+**Rules and best practices:**
+
+- Numbers must be unique within a message.
+- Numbers must be positive integers.
+- Gaps are allowed and are useful when fields are removed.
+- Prefer sequential numbering from `1`.
+- Never reuse a removed field number for a different field.
+
+## Type System
+
+Fory IDL provides a cross-language type system for primitives, named types, and
+collections. Field modifiers (`optional`, `list`, `ref`) control nullability,
+collection behavior, and reference tracking (see
+[Field Modifiers](#field-modifiers)).
+
+### Primitive Types
+
+| Type            | Description                               | Size     |
+| --------------- | ----------------------------------------- | -------- |
+| `bool`          | Boolean value                             | 1 byte   |
+| `int8`          | Signed 8-bit integer                      | 1 byte   |
+| `int16`         | Signed 16-bit integer                     | 2 bytes  |
+| `int32`         | Signed 32-bit integer (varint encoding)   | 4 bytes  |
+| `int64`         | Signed 64-bit integer (varint encoding)   | 8 bytes  |
+| `uint8`         | Unsigned 8-bit integer                    | 1 byte   |
+| `uint16`        | Unsigned 16-bit integer                   | 2 bytes  |
+| `uint32`        | Unsigned 32-bit integer (varint encoding) | 4 bytes  |
+| `uint64`        | Unsigned 64-bit integer (varint encoding) | 8 bytes  |
+| `fixed_int32`   | Signed 32-bit integer (fixed encoding)    | 4 bytes  |
+| `fixed_int64`   | Signed 64-bit integer (fixed encoding)    | 8 bytes  |
+| `fixed_uint32`  | Unsigned 32-bit integer (fixed encoding)  | 4 bytes  |
+| `fixed_uint64`  | Unsigned 64-bit integer (fixed encoding)  | 8 bytes  |
+| `tagged_int64`  | Signed 64-bit integer (tagged encoding)   | 8 bytes  |
+| `tagged_uint64` | Unsigned 64-bit integer (tagged encoding) | 8 bytes  |
+| `float32`       | 32-bit floating point                     | 4 bytes  |
+| `float64`       | 64-bit floating point                     | 8 bytes  |
+| `string`        | UTF-8 string                              | Variable |
+| `bytes`         | Binary data                               | Variable |
+| `date`          | Calendar date                             | Variable |
+| `timestamp`     | Date and time with timezone               | Variable |
+| `duration`      | Duration                                  | Variable |
+| `decimal`       | Decimal value                             | Variable |
+| `any`           | Dynamic value (runtime type)              | Variable |
+
+#### Boolean
+
+| Language | Type                  | Notes              |
+| -------- | --------------------- | ------------------ |
+| Java     | `boolean` / `Boolean` | Primitive or boxed |
+| Python   | `bool`                |                    |
+| Go       | `bool`                |                    |
+| Rust     | `bool`                |                    |
+| C++      | `bool`                |                    |
+
+#### Integer Types
+
+Fory IDL provides fixed-width signed integers (varint encoding for 32/64-bit by default):
+
+| Fory IDL Type | Size   | Range             |
+| ------------- | ------ | ----------------- |
+| `int8`        | 8-bit  | -128 to 127       |
+| `int16`       | 16-bit | -32,768 to 32,767 |
+| `int32`       | 32-bit | -2^31 to 2^31 - 1 |
+| `int64`       | 64-bit | -2^63 to 2^63 - 1 |
+
+**Language Mapping (Signed):**
+
+| Fory IDL | Java    | Python         | Go      | Rust  | C++       |
+| -------- | ------- | -------------- | ------- | ----- | --------- |
+| `int8`   | `byte`  | `pyfory.int8`  | `int8`  | `i8`  | `int8_t`  |
+| `int16`  | `short` | `pyfory.int16` | `int16` | `i16` | `int16_t` |
+| `int32`  | `int`   | `pyfory.int32` | `int32` | `i32` | `int32_t` |
+| `int64`  | `long`  | `pyfory.int64` | `int64` | `i64` | `int64_t` |
+
+Fory IDL provides fixed-width unsigned integers (varint encoding for 32/64-bit by default):
+
+| Fory IDL | Size   | Range         |
+| -------- | ------ | ------------- |
+| `uint8`  | 8-bit  | 0 to 255      |
+| `uint16` | 16-bit | 0 to 65,535   |
+| `uint32` | 32-bit | 0 to 2^32 - 1 |
+| `uint64` | 64-bit | 0 to 2^64 - 1 |
+
+**Language Mapping (Unsigned):**
+
+| Fory IDL | Java    | Python          | Go       | Rust  | C++        |
+| -------- | ------- | --------------- | -------- | ----- | ---------- |
+| `uint8`  | `short` | `pyfory.uint8`  | `uint8`  | `u8`  | `uint8_t`  |
+| `uint16` | `int`   | `pyfory.uint16` | `uint16` | `u16` | `uint16_t` |
+| `uint32` | `long`  | `pyfory.uint32` | `uint32` | `u32` | `uint32_t` |
+| `uint64` | `long`  | `pyfory.uint64` | `uint64` | `u64` | `uint64_t` |
+
+#### Integer Encoding Variants
+
+For 32/64-bit integers, Fory IDL uses varint encoding by default. Use explicit types when
+you need fixed-width or tagged encoding:
+
+| Fory IDL Type   | Encoding | Notes                    |
+| --------------- | -------- | ------------------------ |
+| `fixed_int32`   | fixed    | Signed 32-bit            |
+| `fixed_int64`   | fixed    | Signed 64-bit            |
+| `fixed_uint32`  | fixed    | Unsigned 32-bit          |
+| `fixed_uint64`  | fixed    | Unsigned 64-bit          |
+| `tagged_int64`  | tagged   | Signed 64-bit (hybrid)   |
+| `tagged_uint64` | tagged   | Unsigned 64-bit (hybrid) |
+
+#### Floating-Point Types
+
+| Fory IDL Type | Size   | Precision     |
+| ------------- | ------ | ------------- |
+| `float32`     | 32-bit | ~7 digits     |
+| `float64`     | 64-bit | ~15-16 digits |
+
+**Language Mapping:**
+
+| Fory IDL  | Java     | Python           | Go        | Rust  | C++      |
+| --------- | -------- | ---------------- | --------- | ----- | -------- |
+| `float32` | `float`  | `pyfory.float32` | `float32` | `f32` | `float`  |
+| `float64` | `double` | `pyfory.float64` | `float64` | `f64` | `double` |
+
+#### String Type
+
+| Language | Type          | Notes                 |
+| -------- | ------------- | --------------------- |
+| Java     | `String`      | Immutable             |
+| Python   | `str`         |                       |
+| Go       | `string`      | Immutable             |
+| Rust     | `String`      | Owned, heap-allocated |
+| C++      | `std::string` |                       |
+
+#### Bytes Type
+
+| Language | Type                   | Notes     |
+| -------- | ---------------------- | --------- |
+| Java     | `byte[]`               |           |
+| Python   | `bytes`                | Immutable |
+| Go       | `[]byte`               |           |
+| Rust     | `Vec<u8>`              |           |
+| C++      | `std::vector<uint8_t>` |           |
+
+#### Temporal Types
+
+##### Date
+
+| Language | Type                        | Notes                   |
+| -------- | --------------------------- | ----------------------- |
+| Java     | `java.time.LocalDate`       |                         |
+| Python   | `datetime.date`             |                         |
+| Go       | `time.Time`                 | Time portion ignored    |
+| Rust     | `chrono::NaiveDate`         | Requires `chrono` crate |
+| C++      | `fory::serialization::Date` |                         |
+
+##### Timestamp
+
+| Language | Type                             | Notes                   |
+| -------- | -------------------------------- | ----------------------- |
+| Java     | `java.time.Instant`              | UTC-based               |
+| Python   | `datetime.datetime`              |                         |
+| Go       | `time.Time`                      |                         |
+| Rust     | `chrono::NaiveDateTime`          | Requires `chrono` crate |
+| C++      | `fory::serialization::Timestamp` |                         |
+
+#### Any
+
+| Language | Type           | Notes                |
+| -------- | -------------- | -------------------- |
+| Java     | `Object`       | Runtime type written |
+| Python   | `Any`          | Runtime type written |
+| Go       | `any`          | Runtime type written |
+| Rust     | `Box<dyn Any>` | Runtime type written |
+| C++      | `std::any`     | Runtime type written |
+
+**Example:**
+
+```protobuf
+enum EventType [id=120] {
+    CREATED = 0;
+    DELETED = 1;
+}
+
+message UserCreated [id=121] {
+    string user_id = 1;
+}
+
+message Envelope [id=122] {
+    EventType type = 1;
+    any payload = 2;
+}
+```
+
+**Generated Code (`Envelope.payload`):**
+
+| Language | Generated Field Type    |
+| -------- | ----------------------- |
+| Java     | `Object payload`        |
+| Python   | `payload: Any`          |
+| Go       | `Payload any`           |
+| Rust     | `payload: Box<dyn Any>` |
+| C++      | `std::any payload`      |
+
+**Notes:**
+
+- `any` always writes a null flag (same as `nullable`) because values may be empty.
+- Allowed runtime values are limited to `bool`, `string`, `enum`, `message`, and `union`.
+  Other primitives (numeric, bytes, date/time) and list/map are not supported; wrap them in a
+  message or use explicit fields instead.
+- `ref` is not allowed on `any` fields (including list/map values). Wrap `any` in a message
+  if you need reference tracking.
+- The runtime type must be registered in the target language schema/IDL registration; unknown
+  types fail to deserialize.
+
+### Named Types
+
+Reference other messages, enums, or unions by name:
+
+```protobuf
+enum Status { ... }
+message User { ... }
+
+message Order {
+    User customer = 1;    // Reference to User message
+    Status status = 2;    // Reference to Status enum
+}
+```
+
+### Collection Types
+
+#### List (`list`)
+
+Use the `list<...>` type for list fields. `repeated` is accepted as an alias. See [Field Modifiers](#field-modifiers) for
+modifier combinations and language mapping.
+
+Nested collection types are not supported. Use a message wrapper if you need
+`list<list<...>>`, `list<map<...>>`, or `map<..., list<...>>`.
+
+#### Map
+
+Maps with typed keys and values:
+
+```protobuf
+message Config {
+    map<string, string> properties = 1;
+    map<string, int32> counts = 2;
+    map<int32, User> users = 3;
+}
+```
+
+**Language Mapping:**
+
+| Fory IDL             | Java                   | Python            | Go                 | Rust                    | C++                              |
+| -------------------- | ---------------------- | ----------------- | ------------------ | ----------------------- | -------------------------------- |
+| `map<string, int32>` | `Map<String, Integer>` | `Dict[str, int]`  | `map[string]int32` | `HashMap<String, i32>`  | `std::map<std::string, int32_t>` |
+| `map<string, User>`  | `Map<String, User>`    | `Dict[str, User]` | `map[string]User`  | `HashMap<String, User>` | `std::map<std::string, User>`    |
+
+**Key Type Restrictions:**
+
+- `string` (most common)
+- Integer types (`int8`, `int16`, `int32`, `int64`)
+- `bool`
+
+Avoid using messages or complex types as keys.
+
+### Type Compatibility Matrix
+
+This matrix shows which type conversions are safe across languages:
+
+| From -> To | bool | int8 | int16 | int32 | int64 | float32 | float64 | string |
+| ---------- | ---- | ---- | ----- | ----- | ----- | ------- | ------- | ------ |
+| bool       | Y    | Y    | Y     | Y     | Y     | -       | -       | -      |
+| int8       | -    | Y    | Y     | Y     | Y     | Y       | Y       | -      |
+| int16      | -    | -    | Y     | Y     | Y     | Y       | Y       | -      |
+| int32      | -    | -    | -     | Y     | Y     | -       | Y       | -      |
+| int64      | -    | -    | -     | -     | Y     | -       | -       | -      |
+| float32    | -    | -    | -     | -     | -     | Y       | Y       | -      |
+| float64    | -    | -    | -     | -     | -     | -       | Y       | -      |
+| string     | -    | -    | -     | -     | -     | -       | -       | Y      |
+
+Y = Safe conversion, - = Not recommended
+
+### Best Practices
+
+- Use `int32` as the default for most integers; use `int64` for large values.
+- Use `string` for text data (UTF-8) and `bytes` for binary data.
+- Use `optional` only when the field may legitimately be absent.
+- Use `ref` only when needed for shared or circular references.
+- Prefer `list` for ordered sequences and `map` for key-value lookups.
+
+## Type IDs
+
+Type IDs enable efficient cross-language serialization and are used for
+messages, unions, and enums. When `enable_auto_type_id = true` (default) and
+`id` is omitted, the compiler auto-generates one using
+`MurmurHash3(utf8(package.type_name))` (32-bit) and annotates it in generated
+code. When `enable_auto_type_id = false`, types without explicit IDs are
+registered by namespace and name instead. Collisions are detected at
+compile-time across the current file and all imports; when a collision occurs,
+the compiler raises an error and asks for an explicit `id` or an `alias`.
+
+```protobuf
+enum Color [id=100] { ... }
+message User [id=101] { ... }
+union Event [id=102] { ... }
+```
+
+Enum type IDs remain optional; if omitted they are auto-generated using the same
+hash when `enable_auto_type_id = true`.
+
+### With Explicit Type ID
+
+```protobuf
+message User [id=101] { ... }
+message User [id=101, deprecated=true] { ... }  // Multiple options
+```
+
+### Without Explicit Type ID
+
+```protobuf
+message Config { ... }  // Auto-generated when enable_auto_type_id = true
+```
+
+You can set `[alias="..."]` to change the hash source without renaming the type.
+
+### Practical Notes
+
+- If a type omits `id` and `enable_auto_type_id = true`, Fory generates an ID
+  with `MurmurHash3(utf8(package.type_name))` (32-bit).
+- Package alias and type alias change the hash input and can be used to resolve
+  hash collisions without renaming public types.
+- Manual IDs in the small varint range (`0-127`) are compact on the wire; auto
+  IDs are typically larger and usually consume 4-5 bytes.
+
+### ID Assignment Strategy
+
+```protobuf
+// Enums: 100-199
+enum Status [id=100] { ... }
+enum Priority [id=101] { ... }
+
+// User domain: 200-299
+message User [id=200] { ... }
+message UserProfile [id=201] { ... }
+
+// Order domain: 300-399
+message Order [id=300] { ... }
+message OrderItem [id=301] { ... }
+```
+
+## Complete Example
+
+```protobuf
+// E-commerce domain model
+package com.shop.models;
+
+// Enums with type IDs
+enum OrderStatus [id=100] {
+    PENDING = 0;
+    CONFIRMED = 1;
+    SHIPPED = 2;
+    DELIVERED = 3;
+    CANCELLED = 4;
+}
+
+enum PaymentMethod [id=101] {
+    CREDIT_CARD = 0;
+    DEBIT_CARD = 1;
+    PAYPAL = 2;
+    BANK_TRANSFER = 3;
+}
+
+// Messages with type IDs
+message Address [id=200] {
+    string street = 1;
+    string city = 2;
+    string state = 3;
+    string country = 4;
+    string postal_code = 5;
+}
+
+message Customer [id=201] {
+    string id = 1;
+    string name = 2;
+    optional string email = 3;
+    optional string phone = 4;
+    optional Address billing_address = 5;
+    optional Address shipping_address = 6;
+}
+
+message Product [id=202] {
+    string sku = 1;
+    string name = 2;
+    string description = 3;
+    float64 price = 4;
+    int32 stock = 5;
+    list<string> categories = 6;
+    map<string, string> attributes = 7;
+}
+
+message OrderItem [id=203] {
+    ref Product product = 1;  // Track reference to avoid duplication
+    int32 quantity = 2;
+    float64 unit_price = 3;
+}
+
+message Order [id=204] {
+    string id = 1;
+    ref Customer customer = 2;
+    list<OrderItem> items = 3;
+    OrderStatus status = 4;
+    PaymentMethod payment_method = 5;
+    float64 total = 6;
+    optional string notes = 7;
+    timestamp created_at = 8;
+    optional timestamp shipped_at = 9;
+}
+
+// Config without explicit type ID (auto-generated when enable_auto_type_id = true)
+message ShopConfig {
+    string store_name = 1;
+    string currency = 2;
+    float64 tax_rate = 3;
+    list<string> supported_countries = 4;
+}
+```
+
+For protobuf-specific extension options and `(fory).` syntax, see
+[Protocol Buffers IDL Support](protobuf-idl.md#fory-extension-options-protobuf).
+
+## Grammar Summary
+
+```
+file         := [package_decl] file_option* import_decl* type_def*
+
+package_decl := 'package' package_name ['alias' package_name] ';'
+package_name := IDENTIFIER ('.' IDENTIFIER)*
+
+file_option  := 'option' option_name '=' option_value ';'
+option_name  := IDENTIFIER
+
+import_decl  := 'import' STRING ';'
+
+type_def     := enum_def | message_def | union_def
+
+enum_def     := 'enum' IDENTIFIER [type_options] '{' enum_body '}'
+enum_body    := (reserved_stmt | enum_value)*
+enum_value   := IDENTIFIER '=' INTEGER ';'
+
+message_def  := 'message' IDENTIFIER [type_options] '{' message_body '}'
+message_body := (reserved_stmt | nested_type | field_def)*
+nested_type  := enum_def | message_def | union_def
+field_def    := [modifiers] field_type IDENTIFIER '=' INTEGER [field_options] ';'
+
+union_def    := 'union' IDENTIFIER [type_options] '{' union_field* '}'
+union_field  := ['repeated'] field_type IDENTIFIER '=' INTEGER [field_options] ';'
+option_value := 'true' | 'false' | IDENTIFIER | INTEGER | STRING
+
+reserved_stmt := 'reserved' reserved_items ';'
+reserved_items := reserved_item (',' reserved_item)*
+reserved_item := INTEGER | INTEGER 'to' INTEGER | INTEGER 'to' 'max' | STRING
+
+modifiers    := { 'optional' | 'ref' | 'repeated' }
+
+field_type   := primitive_type | named_type | list_type | map_type
+primitive_type := 'bool'
+               | 'int8' | 'int16' | 'int32' | 'int64'
+               | 'uint8' | 'uint16' | 'uint32' | 'uint64'
+               | 'fixed_int32' | 'fixed_int64' | 'fixed_uint32' | 'fixed_uint64'
+               | 'tagged_int64' | 'tagged_uint64'
+               | 'float32' | 'float64'
+               | 'string' | 'bytes'
+               | 'date' | 'timestamp' | 'duration' | 'decimal'
+               | 'any'
+named_type   := qualified_name
+qualified_name := IDENTIFIER ('.' IDENTIFIER)*   // e.g., Parent.Child
+list_type    := 'list' '<' { 'optional' | 'ref' } field_type '>'
+map_type     := 'map' '<' field_type ',' field_type '>'
+
+type_options := '[' type_option (',' type_option)* ']'
+type_option  := IDENTIFIER '=' option_value         // e.g., id=100, deprecated=true
+field_options := '[' field_option (',' field_option)* ']'
+field_option := IDENTIFIER '=' option_value         // e.g., deprecated=true, ref=true
+
+STRING       := '"' [^"\n]* '"' | "'" [^'\n]* "'"
+IDENTIFIER   := [a-zA-Z_][a-zA-Z0-9_]*
+INTEGER      := '-'? [0-9]+
+```
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/cpp/custom-serializers.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/cpp/custom-serializers.md
new file mode 100644
index 0000000000..b66c8e2b3c
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/cpp/custom-serializers.md
@@ -0,0 +1,371 @@
+---
+title: Custom Serializers
+sidebar_position: 6
+id: custom_serializers
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+For types that don't support `FORY_STRUCT`, implement a `Serializer` template specialization manually.
+
+## When to Use Custom Serializers
+
+- External types from third-party libraries
+- Types with special serialization requirements
+- Legacy data format compatibility
+- Performance-critical custom encoding
+- Cross-language interoperability with custom protocols
+
+## Implementing the Serializer Template
+
+To create a custom serializer, specialize the `Serializer` template for your type within the `fory::serialization` namespace:
+
+```cpp
+#include "fory/serialization/fory.h"
+
+using namespace fory::serialization;
+
+// Define your custom type
+struct MyExt {
+  int32_t id;
+  bool operator==(const MyExt &other) const { return id == other.id; }
+};
+
+namespace fory {
+namespace serialization {
+
+template <>
+struct Serializer<MyExt> {
+  // Declare as extension type for custom serialization
+  static constexpr TypeId type_id = TypeId::EXT;
+
+  // Main write method - handles null checking and type info
+  static void write(const MyExt &value, WriteContext &ctx, RefMode ref_mode,
+                    bool write_type, bool has_generics = false) {
+    (void)has_generics;
+    write_not_null_ref_flag(ctx, ref_mode);
+    if (write_type) {
+      auto result = ctx.write_any_type_info(
+          static_cast<uint32_t>(TypeId::UNKNOWN),
+          std::type_index(typeid(MyExt)));
+      if (!result.ok()) {
+        ctx.set_error(std::move(result).error());
+        return;
+      }
+    }
+    write_data(value, ctx);
+  }
+
+  // write only the data (no type info)
+  static void write_data(const MyExt &value, WriteContext &ctx) {
+    Serializer<int32_t>::write_data(value.id, ctx);
+  }
+
+  // write data with generics support
+  static void write_data_generic(const MyExt &value, WriteContext &ctx,
+                                 bool has_generics) {
+    (void)has_generics;
+    write_data(value, ctx);
+  }
+
+  // Main read method - handles null checking and type info
+  static MyExt read(ReadContext &ctx, RefMode ref_mode, bool read_type) {
+    bool has_value = read_null_only_flag(ctx, ref_mode);
+    if (ctx.has_error() || !has_value) {
+      return MyExt{};
+    }
+    if (read_type) {
+      const TypeInfo *type_info = ctx.read_any_type_info(ctx.error());
+      if (ctx.has_error()) {
+        return MyExt{};
+      }
+      if (!type_info) {
+        ctx.set_error(Error::type_error("TypeInfo for MyExt not found"));
+        return MyExt{};
+      }
+    }
+    return read_data(ctx);
+  }
+
+  // Read only the data (no type info)
+  static MyExt read_data(ReadContext &ctx) {
+    MyExt value;
+    value.id = Serializer<int32_t>::read_data(ctx);
+    return value;
+  }
+
+  // Read data with generics support
+  static MyExt read_data_generic(ReadContext &ctx, bool has_generics) {
+    (void)has_generics;
+    return read_data(ctx);
+  }
+
+  // Read with pre-resolved type info
+  static MyExt read_with_type_info(ReadContext &ctx, RefMode ref_mode,
+                                   const TypeInfo &type_info) {
+    (void)type_info;
+    return read(ctx, ref_mode, false);
+  }
+};
+
+} // namespace serialization
+} // namespace fory
+```
+
+## Required Methods
+
+A custom serializer must implement these static methods:
+
+| Method                | Purpose                                         |
+| --------------------- | ----------------------------------------------- |
+| `write`               | Main serialization entry point with type info   |
+| `write_data`          | Serialize data only (no type info)              |
+| `write_data_generic`  | Serialize data with generics support            |
+| `read`                | Main deserialization entry point with type info |
+| `read_data`           | Deserialize data only (no type info)            |
+| `read_data_generic`   | Deserialize data with generics support          |
+| `read_with_type_info` | Deserialize with pre-resolved TypeInfo          |
+
+The `type_id` constant should be set to `TypeId::EXT` for custom extension types.
+
+## Registering Custom Serializers
+
+Register your custom serializer with Fory before use:
+
+```cpp
+auto fory = Fory::builder().xlang(true).build();
+
+// Register with numeric type ID (must match across languages)
+auto result = fory.register_extension_type<MyExt>(103);
+if (!result.ok()) {
+  std::cerr << "Failed to register: " << result.error().to_string() << std::endl;
+}
+
+// Or register with type name for named type systems
+fory.register_extension_type<MyExt>("my_ext");
+
+// Or with namespace and type name
+fory.register_extension_type<MyExt>("com.example", "MyExt");
+```
+
+## Complete Example
+
+```cpp
+#include "fory/serialization/fory.h"
+#include <iostream>
+
+using namespace fory::serialization;
+
+struct CustomType {
+  int32_t value;
+  std::string name;
+
+  bool operator==(const CustomType &other) const {
+    return value == other.value && name == other.name;
+  }
+};
+
+namespace fory {
+namespace serialization {
+
+template <>
+struct Serializer<CustomType> {
+  static constexpr TypeId type_id = TypeId::EXT;
+
+  static void write(const CustomType &value, WriteContext &ctx,
+                    RefMode ref_mode, bool write_type, bool has_generics = false) {
+    (void)has_generics;
+    write_not_null_ref_flag(ctx, ref_mode);
+    if (write_type) {
+      auto result = ctx.write_any_type_info(
+          static_cast<uint32_t>(TypeId::UNKNOWN),
+          std::type_index(typeid(CustomType)));
+      if (!result.ok()) {
+        ctx.set_error(std::move(result).error());
+        return;
+      }
+    }
+    write_data(value, ctx);
+  }
+
+  static void write_data(const CustomType &value, WriteContext &ctx) {
+    // write value as varint for compact encoding
+    Serializer<int32_t>::write_data(value.value, ctx);
+    // Delegate string serialization to built-in serializer
+    Serializer<std::string>::write_data(value.name, ctx);
+  }
+
+  static void write_data_generic(const CustomType &value, WriteContext &ctx,
+                                 bool has_generics) {
+    (void)has_generics;
+    write_data(value, ctx);
+  }
+
+  static CustomType read(ReadContext &ctx, RefMode ref_mode, bool read_type) {
+    bool has_value = read_null_only_flag(ctx, ref_mode);
+    if (ctx.has_error() || !has_value) {
+      return CustomType{};
+    }
+    if (read_type) {
+      const TypeInfo *type_info = ctx.read_any_type_info(ctx.error());
+      if (ctx.has_error()) {
+        return CustomType{};
+      }
+      if (!type_info) {
+        ctx.set_error(Error::type_error("TypeInfo for CustomType not found"));
+        return CustomType{};
+      }
+    }
+    return read_data(ctx);
+  }
+
+  static CustomType read_data(ReadContext &ctx) {
+    CustomType value;
+    value.value = Serializer<int32_t>::read_data(ctx);
+    value.name = Serializer<std::string>::read_data(ctx);
+    return value;
+  }
+
+  static CustomType read_data_generic(ReadContext &ctx, bool has_generics) {
+    (void)has_generics;
+    return read_data(ctx);
+  }
+
+  static CustomType read_with_type_info(ReadContext &ctx, RefMode ref_mode,
+                                        const TypeInfo &type_info) {
+    (void)type_info;
+    return read(ctx, ref_mode, false);
+  }
+};
+
+} // namespace serialization
+} // namespace fory
+
+int main() {
+  auto fory = Fory::builder().xlang(true).build();
+  fory.register_extension_type<CustomType>(100);
+
+  CustomType original{42, "test"};
+
+  auto serialized = fory.serialize(original);
+  if (!serialized.ok()) {
+    std::cerr << "Serialization failed" << std::endl;
+    return 1;
+  }
+
+  auto deserialized = fory.deserialize<CustomType>(serialized.value());
+  if (!deserialized.ok()) {
+    std::cerr << "Deserialization failed" << std::endl;
+    return 1;
+  }
+
+  assert(original == deserialized.value());
+  std::cout << "Custom serializer works!" << std::endl;
+  return 0;
+}
+```
+
+## WriteContext Methods
+
+The `WriteContext` provides methods for writing data:
+
+```cpp
+// Primitive types
+ctx.write_uint8(value);
+ctx.write_int8(value);
+ctx.write_uint16(value);
+
+// Variable-length integers (compact encoding)
+ctx.write_var_uint32(value);   // Unsigned varint
+ctx.write_varint32(value);    // Signed zigzag varint
+ctx.write_var_uint64(value);   // Unsigned varint
+ctx.write_varint64(value);    // Signed zigzag varint
+
+// Tagged integers (for mixed-size encoding)
+ctx.write_tagged_uint64(value);
+ctx.write_tagged_int64(value);
+
+// Raw bytes
+ctx.write_bytes(data_ptr, length);
+
+// Access underlying buffer for advanced operations
+ctx.buffer().write_int32(value);
+ctx.buffer().write_float(value);
+ctx.buffer().write_double(value);
+```
+
+## ReadContext Methods
+
+The `ReadContext` provides methods for reading data:
+
+```cpp
+// Primitive types (use error reference pattern)
+uint8_t u8 = ctx.read_uint8(ctx.error());
+int8_t i8 = ctx.read_int8(ctx.error());
+
+// Variable-length integers
+uint32_t u32 = ctx.read_var_uint32(ctx.error());
+int32_t i32 = ctx.read_varint32(ctx.error());
+uint64_t u64 = ctx.read_var_uint64(ctx.error());
+int64_t i64 = ctx.read_varint64(ctx.error());
+
+// Check for errors after read operations
+if (ctx.has_error()) {
+  return MyType{};  // Return default on error
+}
+
+// Access underlying buffer for advanced operations
+int32_t value = ctx.buffer().read_int32(ctx.error());
+float f = ctx.buffer().read_float(ctx.error());
+double d = ctx.buffer().read_double(ctx.error());
+```
+
+## Delegating to Built-in Serializers
+
+Reuse existing serializers for nested types:
+
+```cpp
+static void write_data(const MyType &value, WriteContext &ctx) {
+  // Delegate to built-in serializers
+  Serializer<int32_t>::write_data(value.int_field, ctx);
+  Serializer<std::string>::write_data(value.string_field, ctx);
+  Serializer<std::vector<int32_t>>::write_data(value.vec_field, ctx);
+}
+
+static MyType read_data(ReadContext &ctx) {
+  MyType value;
+  value.int_field = Serializer<int32_t>::read_data(ctx);
+  value.string_field = Serializer<std::string>::read_data(ctx);
+  value.vec_field = Serializer<std::vector<int32_t>>::read_data(ctx);
+  return value;
+}
+```
+
+## Best Practices
+
+1. **Use variable-length encoding** for integers that may be small
+2. **Check errors after read operations** using `ctx.has_error()`
+3. **Return default values on error** to maintain consistent behavior
+4. **Delegate to built-in serializers** for standard types
+5. **Match type IDs across languages** for cross-language compatibility
+6. **Use `(void)param`** to suppress unused parameter warnings
+
+## Related Topics
+
+- [Type Registration](type_registration) - Registering serializers
+- [Basic Serialization](basic_serialization) - Using FORY_STRUCT macro
+- [Schema Evolution](schema_evolution) - Compatible mode
+- [Cross-Language](cross_language) - Cross-language serialization
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/cpp/polymorphism.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/cpp/polymorphism.md
new file mode 100644
index 0000000000..c52d385fb2
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/cpp/polymorphism.md
@@ -0,0 +1,480 @@
+---
+title: Polymorphic Serialization
+sidebar_position: 5
+id: polymorphism
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+Apache Fory™ supports polymorphic serialization through smart pointers (`std::shared_ptr` and `std::unique_ptr`), enabling dynamic dispatch and type flexibility for inheritance hierarchies.
+
+## Supported Polymorphic Types
+
+- `std::shared_ptr<Base>` - Shared ownership with polymorphic dispatch
+- `std::unique_ptr<Base>` - Exclusive ownership with polymorphic dispatch
+- Collections: `std::vector<std::shared_ptr<Base>>`, `std::map<K, std::unique_ptr<Base>>`
+- Optional: `std::optional<std::shared_ptr<Base>>`
+
+## Basic Polymorphic Serialization
+
+```cpp
+#include "fory/serialization/fory.h"
+
+using namespace fory::serialization;
+
+// Define base class with virtual methods
+struct Animal {
+  virtual ~Animal() = default;
+  virtual std::string speak() const = 0;
+  int32_t age = 0;
+};
+FORY_STRUCT(Animal, age);
+
+// Define derived classes
+struct Dog : Animal {
+  std::string speak() const override { return "Woof!"; }
+  std::string breed;
+};
+FORY_STRUCT(Dog, age, breed);
+
+struct Cat : Animal {
+  std::string speak() const override { return "Meow!"; }
+  std::string color;
+};
+FORY_STRUCT(Cat, age, color);
+
+// Struct with polymorphic field
+struct Zoo {
+  std::shared_ptr<Animal> star_animal;
+};
+FORY_STRUCT(Zoo, star_animal);
+
+int main() {
+  auto fory = Fory::builder().track_ref(true).build();
+
+  // Register all types with unique type IDs
+  fory.register_struct<Zoo>(100);
+  fory.register_struct<Dog>(101);
+  fory.register_struct<Cat>(102);
+
+  // Create object with polymorphic field
+  Zoo zoo;
+  zoo.star_animal = std::make_shared<Dog>();
+  zoo.star_animal->age = 3;
+  static_cast<Dog*>(zoo.star_animal.get())->breed = "Labrador";
+
+  // Serialize
+  auto bytes_result = fory.serialize(zoo);
+  assert(bytes_result.ok());
+
+  // Deserialize - runtime type is preserved
+  auto decoded_result = fory.deserialize<Zoo>(bytes_result.value());
+  assert(decoded_result.ok());
+
+  auto decoded = std::move(decoded_result).value();
+  assert(decoded.star_animal->speak() == "Woof!");
+  assert(decoded.star_animal->age == 3);
+
+  auto* dog_ptr = dynamic_cast<Dog*>(decoded.star_animal.get());
+  assert(dog_ptr != nullptr);
+  assert(dog_ptr->breed == "Labrador");
+}
+```
+
+## Type Registration for Polymorphism
+
+For polymorphic serialization, register derived types with unique type IDs:
+
+```cpp
+// Register with numeric type ID
+fory.register_struct<Derived1>(100);
+fory.register_struct<Derived2>(101);
+```
+
+**Why type ID registration?**
+
+- Compact binary representation
+- Fast type lookup and dispatch
+- Consistent with non-polymorphic type registration
+
+## Automatic Polymorphism Detection
+
+Fory automatically detects polymorphic types using `std::is_polymorphic<T>`:
+
+```cpp
+struct Base {
+  virtual ~Base() = default;  // Virtual destructor makes it polymorphic
+  int32_t value = 0;
+};
+
+struct NonPolymorphic {
+  int32_t value = 0;  // No virtual methods
+};
+
+// Polymorphic field - type info written automatically
+struct Container1 {
+  std::shared_ptr<Base> ptr;  // Auto-detected as polymorphic
+};
+
+// Non-polymorphic field - no type info written
+struct Container2 {
+  std::shared_ptr<NonPolymorphic> ptr;  // Not polymorphic
+};
+```
+
+## Controlling Dynamic Dispatch
+
+Use `fory::dynamic<V>` to override automatic polymorphism detection:
+
+```cpp
+struct Animal {
+  virtual ~Animal() = default;
+  virtual std::string speak() const = 0;
+};
+
+struct Pet {
+  // Auto-detected: type info written (Animal has virtual methods)
+  std::shared_ptr<Animal> animal1;
+
+  // Force dynamic: type info written explicitly
+  fory::field<std::shared_ptr<Animal>, 0, fory::dynamic<true>> animal2;
+
+  // Force non-dynamic: skip type info (faster but no runtime subtyping)
+  fory::field<std::shared_ptr<Animal>, 1, fory::dynamic<false>> animal3;
+};
+FORY_STRUCT(Pet, animal1, animal2, animal3);
+```
+
+**When to use `fory::dynamic<false>`:**
+
+- You know the runtime type will always match the declared type
+- Performance is critical and you don't need subtype support
+- Working with monomorphic data despite having a polymorphic base class
+
+### Field Configuration Without Wrapper Types
+
+Use `FORY_FIELD_CONFIG` to configure fields without `fory::field<>` wrapper:
+
+```cpp
+struct Zoo {
+  std::shared_ptr<Animal> star;      // Auto-detected as polymorphic
+  std::shared_ptr<Animal> backup;    // Nullable polymorphic field
+  std::shared_ptr<Animal> mascot;    // Non-dynamic (no subtype dispatch)
+};
+FORY_STRUCT(Zoo, star, backup, mascot);
+
+// Configure fields with tag IDs and options
+FORY_FIELD_CONFIG(Zoo,
+    (star, fory::F(0)),                    // Tag ID 0, default options
+    (backup, fory::F(1).nullable()),       // Tag ID 1, allow nullptr
+    (mascot, fory::F(2).dynamic(false))    // Tag ID 2, disable polymorphism
+);
+```
+
+See [Field Configuration](field_configuration) for complete details on `fory::nullable`, `fory::ref`, and other field-level options
+
+## std::unique_ptr Polymorphism
+
+`std::unique_ptr` works the same way as `std::shared_ptr` for polymorphic types:
+
+```cpp
+struct Container {
+  std::unique_ptr<Animal> pet;
+};
+FORY_STRUCT(Container, pet);
+
+auto fory = Fory::builder().track_ref(true).build();
+fory.register_struct<Container>(200);
+fory.register_struct<Dog>(201);
+
+Container container;
+container.pet = std::make_unique<Dog>();
+static_cast<Dog*>(container.pet.get())->breed = "Beagle";
+
+auto bytes = fory.serialize(container).value();
+auto decoded = fory.deserialize<Container>(bytes).value();
+
+// Runtime type preserved
+auto* dog = dynamic_cast<Dog*>(decoded.pet.get());
+assert(dog != nullptr);
+assert(dog->breed == "Beagle");
+```
+
+## Collections of Polymorphic Objects
+
+```cpp
+#include <vector>
+#include <map>
+
+struct AnimalShelter {
+  std::vector<std::shared_ptr<Animal>> animals;
+  std::map<std::string, std::unique_ptr<Animal>> registry;
+};
+FORY_STRUCT(AnimalShelter, animals, registry);
+
+auto fory = Fory::builder().track_ref(true).build();
+fory.register_struct<AnimalShelter>(100);
+fory.register_struct<Dog>(101);
+fory.register_struct<Cat>(102);
+
+AnimalShelter shelter;
+shelter.animals.push_back(std::make_shared<Dog>());
+shelter.animals.push_back(std::make_shared<Cat>());
+shelter.registry["pet1"] = std::make_unique<Dog>();
+
+auto bytes = fory.serialize(shelter).value();
+auto decoded = fory.deserialize<AnimalShelter>(bytes).value();
+
+// All runtime types preserved
+assert(dynamic_cast<Dog*>(decoded.animals[0].get()) != nullptr);
+assert(dynamic_cast<Cat*>(decoded.animals[1].get()) != nullptr);
+assert(dynamic_cast<Dog*>(decoded.registry["pet1"].get()) != nullptr);
+```
+
+## Reference Tracking
+
+Reference tracking for `std::shared_ptr` works the same with polymorphic types.
+See [Supported Types](supported_types) for details and examples.
+
+## Nested Polymorphism Depth Limit
+
+To prevent stack overflow from deeply nested polymorphic structures, Fory limits the maximum dynamic nesting depth:
+
+```cpp
+struct Container {
+  virtual ~Container() = default;
+  int32_t value = 0;
+  std::shared_ptr<Container> nested;
+};
+FORY_STRUCT(Container, value, nested);
+
+// Default max_dyn_depth is 5
+auto fory1 = Fory::builder().build();
+assert(fory1.config().max_dyn_depth == 5);
+
+// Increase limit for deeper nesting
+auto fory2 = Fory::builder().max_dyn_depth(10).build();
+fory2.register_struct<Container>(1);
+
+// Create deeply nested structure
+auto level3 = std::make_shared<Container>();
+level3->value = 3;
+
+auto level2 = std::make_shared<Container>();
+level2->value = 2;
+level2->nested = level3;
+
+auto level1 = std::make_shared<Container>();
+level1->value = 1;
+level1->nested = level2;
+
+// Serialization succeeds
+auto bytes = fory2.serialize(level1).value();
+
+// Deserialization succeeds with sufficient depth
+auto decoded = fory2.deserialize<std::shared_ptr<Container>>(bytes).value();
+```
+
+**Depth exceeded error:**
+
+```cpp
+auto fory_shallow = Fory::builder().max_dyn_depth(2).build();
+fory_shallow.register_struct<Container>(1);
+
+// 3 levels exceeds max_dyn_depth=2
+auto result = fory_shallow.deserialize<std::shared_ptr<Container>>(bytes);
+assert(!result.ok());  // Fails with depth exceeded error
+```
+
+**When to adjust:**
+
+- **Increase `max_dyn_depth`**: For legitimate deeply nested polymorphic data structures
+- **Decrease `max_dyn_depth`**: For stricter security requirements or shallow data structures
+
+## Nullability for Polymorphic Fields
+
+By default, `std::shared_ptr<T>` and `std::unique_ptr<T>` fields are treated as
+non-nullable in the schema. To allow `nullptr`, wrap the field with
+`fory::field<>` (or `FORY_FIELD_TAGS`) and opt in with `fory::nullable`.
+
+```cpp
+struct Pet {
+  // Non-nullable (default)
+  std::shared_ptr<Animal> primary;
+
+  // Nullable via explicit field metadata
+  fory::field<std::shared_ptr<Animal>, 0, fory::nullable> optional;
+};
+FORY_STRUCT(Pet, primary, optional);
+```
+
+See [Field Configuration](field_configuration) for more details.
+
+## Combining Polymorphism with Other Features
+
+### Polymorphism + Reference Tracking
+
+```cpp
+struct GraphNode {
+  virtual ~GraphNode() = default;
+  int32_t id = 0;
+  std::vector<std::shared_ptr<GraphNode>> neighbors;
+};
+FORY_STRUCT(GraphNode, id, neighbors);
+
+struct WeightedNode : GraphNode {
+  double weight = 0.0;
+};
+FORY_STRUCT(WeightedNode, id, neighbors, weight);
+
+// Enable ref tracking to handle shared references and cycles
+auto fory = Fory::builder().track_ref(true).build();
+fory.register_struct<GraphNode>(100);
+fory.register_struct<WeightedNode>(101);
+
+// Create cyclic graph
+auto node1 = std::make_shared<WeightedNode>();
+node1->id = 1;
+
+auto node2 = std::make_shared<WeightedNode>();
+node2->id = 2;
+
+node1->neighbors.push_back(node2);
+node2->neighbors.push_back(node1);  // Cycle
+
+auto bytes = fory.serialize(node1).value();
+auto decoded = fory.deserialize<std::shared_ptr<GraphNode>>(bytes).value();
+// Cycle handled correctly
+```
+
+### Polymorphism + Schema Evolution
+
+Use compatible mode for schema evolution with polymorphic types:
+
+```cpp
+auto fory = Fory::builder()
+    .compatible(true)  // Enable schema evolution
+    .track_ref(true)
+    .build();
+```
+
+## Best Practices
+
+1. **Use type ID registration** for polymorphic types:
+
+   ```cpp
+   fory.register_struct<DerivedType>(100);
+   ```
+
+2. **Enable reference tracking** for polymorphic types:
+
+   ```cpp
+   auto fory = Fory::builder().track_ref(true).build();
+   ```
+
+3. **Virtual destructors required**: Ensure base classes have virtual destructors:
+
+   ```cpp
+   struct Base {
+     virtual ~Base() = default;  // Required for polymorphism
+   };
+   ```
+
+4. **Register all concrete types** before serialization/deserialization:
+
+   ```cpp
+   fory.register_struct<Derived1>(100);
+   fory.register_struct<Derived2>(101);
+   ```
+
+5. **Use `dynamic_cast`** to downcast after deserialization:
+
+   ```cpp
+   auto* derived = dynamic_cast<DerivedType*>(base_ptr.get());
+   if (derived) {
+     // Use derived-specific members
+   }
+   ```
+
+6. **Adjust `max_dyn_depth`** based on your data structure depth:
+
+   ```cpp
+   auto fory = Fory::builder().max_dyn_depth(10).build();
+   ```
+
+7. **Use `fory::nullable`** for optional polymorphic fields:
+
+   ```cpp
+   fory::field<std::shared_ptr<Base>, 0, fory::nullable> optional_ptr;
+   ```
+
+## Error Handling
+
+```cpp
+auto bytes_result = fory.serialize(obj);
+if (!bytes_result.ok()) {
+  std::cerr << "Serialization failed: "
+            << bytes_result.error().to_string() << std::endl;
+  return;
+}
+
+auto decoded_result = fory.deserialize<MyType>(bytes_result.value());
+if (!decoded_result.ok()) {
+  std::cerr << "Deserialization failed: "
+            << decoded_result.error().to_string() << std::endl;
+  return;
+}
+```
+
+**Common errors:**
+
+- **Type not registered**: Register all concrete types with unique IDs before use
+- **Depth exceeded**: Increase `max_dyn_depth` for deeply nested structures
+- **Type ID conflict**: Ensure each type has a unique type ID across all registered types
+
+## Performance Considerations
+
+**Polymorphic serialization overhead:**
+
+- Type metadata written for each polymorphic object (~16-32 bytes)
+- Dynamic type resolution during deserialization
+- Virtual function calls for runtime dispatch
+
+**Optimization tips:**
+
+1. **Use `fory::dynamic<false>`** when runtime type matches declared type:
+
+   ```cpp
+   fory::field<std::shared_ptr<Base>, 0, fory::dynamic<false>> fixed_type;
+   ```
+
+2. **Minimize nesting depth** to reduce metadata overhead
+
+3. **Batch polymorphic objects** in collections rather than individual fields
+
+4. **Consider non-polymorphic alternatives** when polymorphism isn't needed:
+
+   ```cpp
+   std::variant<Dog, Cat> animal;  // Type-safe union instead of polymorphism
+   ```
+
+## Related Topics
+
+- [Type Registration](type_registration) - Registering types for serialization
+- [Field Configuration](field_configuration) - Field-level metadata and options
+- [Supported Types](supported_types) - Smart pointers and collections
+- [Configuration](configuration) - `max_dyn_depth` and other settings
+- [Basic Serialization](basic_serialization) - Core serialization concepts
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/java/field-configuration.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/java/field-configuration.md
new file mode 100644
index 0000000000..d9940309aa
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/java/field-configuration.md
@@ -0,0 +1,605 @@
+---
+title: Field Configuration
+sidebar_position: 5
+id: field_configuration
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+This page explains how to configure field-level metadata for serialization in Java.
+
+## Overview
+
+Apache ForyTM provides field-level configuration through annotations:
+
+- **`@ForyField`**: Configure field metadata (id, nullable, ref, dynamic)
+- **`@Ignore`**: Exclude fields from serialization
+- **Integer type annotations**: Control integer encoding (varint, fixed, tagged, unsigned)
+
+This enables:
+
+- **Tag IDs**: Assign compact numeric IDs to reduce struct field meta size overhead for compatible mode
+- **Nullability**: Control whether fields can be null
+- **Reference Tracking**: Enable reference tracking for shared objects
+- **Field Skipping**: Exclude fields from serialization
+- **Encoding Control**: Specify how integers are encoded
+- **Polymorphism Control**: Control type info writing for struct fields
+
+## Basic Syntax
+
+Use annotations on fields:
+
+```java
+import org.apache.fory.annotation.ForyField;
+
+public class Person {
+    @ForyField(id = 0)
+    private String name;
+
+    @ForyField(id = 1)
+    private int age;
+
+    @ForyField(id = 2, nullable = true)
+    private String nickname;
+}
+```
+
+## The `@ForyField` Annotation
+
+Use `@ForyField` to configure field-level metadata:
+
+```java
+public class User {
+    @ForyField(id = 0)
+    private long id;
+
+    @ForyField(id = 1)
+    private String name;
+
+    @ForyField(id = 2, nullable = true)
+    private String email;
+
+    @ForyField(id = 3, ref = true)
+    private List<User> friends;
+
+    @ForyField(id = 4, dynamic = ForyField.Dynamic.TRUE)
+    private Object data;
+}
+```
+
+### Parameters
+
+| Parameter  | Type      | Default | Description                            |
+| ---------- | --------- | ------- | -------------------------------------- |
+| `id`       | `int`     | `-1`    | Field tag ID (-1 = use field name)     |
+| `nullable` | `boolean` | `false` | Whether the field can be null          |
+| `ref`      | `boolean` | `false` | Enable reference tracking              |
+| `dynamic`  | `Dynamic` | `AUTO`  | Control polymorphism for struct fields |
+
+## Field ID (`id`)
+
+Assigns a numeric ID to a field to minimize struct field meta size overhead for compatible mode:
+
+```java
+public class User {
+    @ForyField(id = 0)
+    private long id;
+
+    @ForyField(id = 1)
+    private String name;
+
+    @ForyField(id = 2)
+    private int age;
+}
+```
+
+**Benefits**:
+
+- Smaller serialized size (numeric IDs vs field names in metadata)
+- Reduced struct field meta overhead
+- Allows renaming fields without breaking binary compatibility
+
+**Recommendation**: It is recommended to configure field IDs for compatible mode since it reduces serialization cost.
+
+**Notes**:
+
+- IDs must be unique within a class
+- IDs must be >= 0 (use -1 to use field name encoding, which is the default)
+- If not specified, field name is used in metadata (larger overhead)
+
+**Without field IDs** (field names used in metadata):
+
+```java
+public class User {
+    private long id;
+    private String name;
+}
+```
+
+## Nullable Fields (`nullable`)
+
+Use `nullable = true` for fields that can be `null`:
+
+```java
+public class Record {
+    // Nullable string field
+    @ForyField(id = 0, nullable = true)
+    private String optionalName;
+
+    // Nullable Integer field (boxed type)
+    @ForyField(id = 1, nullable = true)
+    private Integer optionalCount;
+
+    // Non-nullable field (default)
+    @ForyField(id = 2)
+    private String requiredName;
+}
+```
+
+**Notes**:
+
+- Default is `nullable = false` (non-nullable)
+- When `nullable = false`, Fory skips writing the null flag (saves 1 byte)
+- Boxed types (`Integer`, `Long`, etc.) that can be null should use `nullable = true`
+
+## Reference Tracking (`ref`)
+
+Enable reference tracking for fields that may be shared or circular:
+
+```java
+public class RefOuter {
+    // Both fields may point to the same inner object
+    @ForyField(id = 0, ref = true, nullable = true)
+    private RefInner inner1;
+
+    @ForyField(id = 1, ref = true, nullable = true)
+    private RefInner inner2;
+}
+
+public class CircularRef {
+    @ForyField(id = 0)
+    private String name;
+
+    // Self-referencing field for circular references
+    @ForyField(id = 1, ref = true, nullable = true)
+    private CircularRef selfRef;
+}
+```
+
+**Use Cases**:
+
+- Enable for fields that may be circular or shared
+- When the same object is referenced from multiple fields
+
+**Notes**:
+
+- Default is `ref = false` (no reference tracking)
+- When `ref = false`, avoids IdentityMap overhead and skips ref tracking flag
+- Reference tracking only takes effect when global ref tracking is enabled
+
+## Dynamic (Polymorphism Control)
+
+Controls polymorphism behavior for struct fields in cross-language serialization:
+
+```java
+public class Container {
+    // AUTO: Interface/abstract types are dynamic, concrete types are not
+    @ForyField(id = 0, dynamic = ForyField.Dynamic.AUTO)
+    private Animal animal;  // Interface - type info written
+
+    // FALSE: No type info written, uses declared type's serializer
+    @ForyField(id = 1, dynamic = ForyField.Dynamic.FALSE)
+    private Dog dog;  // Concrete - no type info
+
+    // TRUE: Type info written to support runtime subtypes
+    @ForyField(id = 2, dynamic = ForyField.Dynamic.TRUE)
+    private Object data;  // Force polymorphic
+}
+```
+
+**Options**:
+
+| Value   | Description                                                         |
+| ------- | ------------------------------------------------------------------- |
+| `AUTO`  | Auto-detect: interface/abstract are dynamic, concrete types are not |
+| `FALSE` | No type info written, uses declared type's serializer directly      |
+| `TRUE`  | Type info written to support subtypes at runtime                    |
+
+## Skipping Fields
+
+### Using `@Ignore`
+
+Exclude fields from serialization:
+
+```java
+import org.apache.fory.annotation.Ignore;
+
+public class User {
+    @ForyField(id = 0)
+    private long id;
+
+    @ForyField(id = 1)
+    private String name;
+
+    @Ignore
+    private String password;  // Not serialized
+
+    @Ignore
+    private Object internalState;  // Not serialized
+}
+```
+
+### Using `transient`
+
+Java's `transient` keyword also excludes fields:
+
+```java
+public class User {
+    @ForyField(id = 0)
+    private long id;
+
+    private transient String password;  // Not serialized
+    private transient Object cache;     // Not serialized
+}
+```
+
+## Integer Type Annotations
+
+Fory provides annotations to control integer encoding for cross-language compatibility.
+
+### Signed 32-bit Integer (`@Int32Type`)
+
+```java
+import org.apache.fory.annotation.Int32Type;
+
+public class MyStruct {
+    // Variable-length encoding (default) - compact for small values
+    @Int32Type(compress = true)
+    private int compactId;
+
+    // Fixed 4-byte encoding - consistent size
+    @Int32Type(compress = false)
+    private int fixedId;
+}
+```
+
+### Signed 64-bit Integer (`@Int64Type`)
+
+```java
+import org.apache.fory.annotation.Int64Type;
+import org.apache.fory.config.LongEncoding;
+
+public class MyStruct {
+    // Variable-length encoding (default)
+    @Int64Type(encoding = LongEncoding.VARINT)
+    private long compactId;
+
+    // Fixed 8-byte encoding
+    @Int64Type(encoding = LongEncoding.FIXED)
+    private long fixedTimestamp;
+
+    // Tagged encoding (4 bytes for small values, 9 bytes otherwise)
+    @Int64Type(encoding = LongEncoding.TAGGED)
+    private long taggedValue;
+}
+```
+
+### Unsigned Integers
+
+```java
+import org.apache.fory.annotation.Uint8Type;
+import org.apache.fory.annotation.Uint16Type;
+import org.apache.fory.annotation.Uint32Type;
+import org.apache.fory.annotation.Uint64Type;
+import org.apache.fory.config.LongEncoding;
+
+public class UnsignedStruct {
+    // Unsigned 8-bit [0, 255]
+    @Uint8Type
+    private short flags;
+
+    // Unsigned 16-bit [0, 65535]
+    @Uint16Type
+    private int port;
+
+    // Unsigned 32-bit with varint encoding (default)
+    @Uint32Type(compress = true)
+    private long compactCount;
+
+    // Unsigned 32-bit with fixed encoding
+    @Uint32Type(compress = false)
+    private long fixedCount;
+
+    // Unsigned 64-bit with various encodings
+    @Uint64Type(encoding = LongEncoding.VARINT)
+    private long varintU64;
+
+    @Uint64Type(encoding = LongEncoding.FIXED)
+    private long fixedU64;
+
+    @Uint64Type(encoding = LongEncoding.TAGGED)
+    private long taggedU64;
+}
+```
+
+### Encoding Summary
+
+| Annotation                       | Type ID | Encoding | Size         |
+| -------------------------------- | ------- | -------- | ------------ |
+| `@Int32Type(compress = true)`    | 5       | varint   | 1-5 bytes    |
+| `@Int32Type(compress = false)`   | 4       | fixed    | 4 bytes      |
+| `@Int64Type(encoding = VARINT)`  | 7       | varint   | 1-10 bytes   |
+| `@Int64Type(encoding = FIXED)`   | 6       | fixed    | 8 bytes      |
+| `@Int64Type(encoding = TAGGED)`  | 8       | tagged   | 4 or 9 bytes |
+| `@Uint8Type`                     | 9       | fixed    | 1 byte       |
+| `@Uint16Type`                    | 10      | fixed    | 2 bytes      |
+| `@Uint32Type(compress = true)`   | 12      | varint   | 1-5 bytes    |
+| `@Uint32Type(compress = false)`  | 11      | fixed    | 4 bytes      |
+| `@Uint64Type(encoding = VARINT)` | 14      | varint   | 1-10 bytes   |
+| `@Uint64Type(encoding = FIXED)`  | 13      | fixed    | 8 bytes      |
+| `@Uint64Type(encoding = TAGGED)` | 15      | tagged   | 4 or 9 bytes |
+
+**When to Use**:
+
+- `varint`: Best for values that are often small (default)
+- `fixed`: Best for values that use full range (e.g., timestamps, hashes)
+- `tagged`: Good balance between size and performance
+- Unsigned types: For cross-language compatibility with Rust, Go, C++
+
+## Complete Example
+
+```java
+import org.apache.fory.Fory;
+import org.apache.fory.annotation.ForyField;
+import org.apache.fory.annotation.Ignore;
+import org.apache.fory.annotation.Int64Type;
+import org.apache.fory.annotation.Uint64Type;
+import org.apache.fory.config.LongEncoding;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class Document {
+    // Fields with tag IDs (recommended for compatible mode)
+    @ForyField(id = 0)
+    private String title;
+
+    @ForyField(id = 1)
+    private int version;
+
+    // Nullable field
+    @ForyField(id = 2, nullable = true)
+    private String description;
+
+    // Collection fields
+    @ForyField(id = 3)
+    private List<String> tags;
+
+    @ForyField(id = 4)
+    private Map<String, String> metadata;
+
+    @ForyField(id = 5)
+    private Set<String> categories;
+
+    // Integer with different encodings
+    @ForyField(id = 6)
+    @Uint64Type(encoding = LongEncoding.VARINT)
+    private long viewCount;  // varint encoding
+
+    @ForyField(id = 7)
+    @Uint64Type(encoding = LongEncoding.FIXED)
+    private long fileSize;   // fixed encoding
+
+    @ForyField(id = 8)
+    @Uint64Type(encoding = LongEncoding.TAGGED)
+    private long checksum;   // tagged encoding
+
+    // Reference-tracked field for shared/circular references
+    @ForyField(id = 9, ref = true, nullable = true)
+    private Document parent;
+
+    // Ignored field (not serialized)
+    private transient Object cache;
+
+    // Getters and setters...
+}
+
+// Usage
+public class Main {
+    public static void main(String[] args) {
+        Fory fory = Fory.builder()
+            .withXlang(true)
+            .withCompatible(true)
+            .withRefTracking(true)
+            .build();
+
+        fory.register(Document.class, 100);
+
+        Document doc = new Document();
+        doc.setTitle("My Document");
+        doc.setVersion(1);
+        doc.setDescription("A sample document");
+
+        // Serialize
+        byte[] data = fory.serialize(doc);
+
+        // Deserialize
+        Document decoded = (Document) fory.deserialize(data);
+    }
+}
+```
+
+## Cross-Language Compatibility
+
+When serializing data to be read by other languages (Python, Rust, C++, Go), use field IDs and matching type annotations:
+
+```java
+public class CrossLangData {
+    // Use field IDs for cross-language compatibility
+    @ForyField(id = 0)
+    @Int32Type(compress = true)
+    private int intVar;
+
+    @ForyField(id = 1)
+    @Uint64Type(encoding = LongEncoding.FIXED)
+    private long longFixed;
+
+    @ForyField(id = 2)
+    @Uint64Type(encoding = LongEncoding.TAGGED)
+    private long longTagged;
+
+    @ForyField(id = 3, nullable = true)
+    private String optionalValue;
+}
+```
+
+## Schema Evolution
+
+Compatible mode supports schema evolution. It is recommended to configure field IDs to reduce serialization cost:
+
+```java
+// Version 1
+public class DataV1 {
+    @ForyField(id = 0)
+    private long id;
+
+    @ForyField(id = 1)
+    private String name;
+}
+
+// Version 2: Added new field
+public class DataV2 {
+    @ForyField(id = 0)
+    private long id;
+
+    @ForyField(id = 1)
+    private String name;
+
+    @ForyField(id = 2, nullable = true)
+    private String email;  // New field
+}
+```
+
+Data serialized with V1 can be deserialized with V2 (new field will be `null`).
+
+Alternatively, field IDs can be omitted (field names will be used in metadata with larger overhead):
+
+```java
+public class Data {
+    private long id;
+    private String name;
+}
+```
+
+## Native Mode vs Xlang Mode
+
+Field configuration behaves differently depending on the serialization mode:
+
+### Native Mode (Java-only)
+
+Native mode has **relaxed default values** for maximum compatibility:
+
+- **Nullable**: Reference types are nullable by default
+- **Ref tracking**: Enabled by default for object references (except `String`, boxed types, and time types)
+- **Polymorphism**: All non-final classes support polymorphism by default
+
+In native mode, you typically **don't need to configure field annotations** unless you want to:
+
+- Reduce serialized size by using field IDs
+- Optimize performance by disabling unnecessary ref tracking
+- Control integer encoding for specific fields
+
+```java
+// Native mode: works without any annotations
+public class User {
+    private long id;
+    private String name;
+    private List<String> tags;  // Nullable and ref-tracked by default
+}
+```
+
+### Xlang Mode (Cross-language)
+
+Xlang mode has **stricter default values** due to type system differences between languages:
+
+- **Nullable**: Fields are non-nullable by default (`nullable = false`)
+- **Ref tracking**: Disabled by default (`ref = false`)
+- **Polymorphism**: Concrete types are non-polymorphic by default
+
+In xlang mode, you **need to configure fields** when:
+
+- A field can be null (use `nullable = true`)
+- A field needs reference tracking for shared/circular objects (use `ref = true`)
+- Integer types need specific encoding for cross-language compatibility
+- You want to reduce metadata size (use field IDs)
+
+```java
+// Xlang mode: explicit configuration required for nullable/ref fields
+public class User {
+    @ForyField(id = 0)
+    private long id;
+
+    @ForyField(id = 1)
+    private String name;
+
+    @ForyField(id = 2, nullable = true)  // Must declare nullable
+    private String email;
+
+    @ForyField(id = 3, ref = true, nullable = true)  // Must declare ref for shared objects
+    private User friend;
+}
+```
+
+### Default Values Summary
+
+| Option     | Native Mode Default      | Xlang Mode Default                |
+| ---------- | ------------------------ | --------------------------------- |
+| `nullable` | `true` (reference types) | `false`                           |
+| `ref`      | `true`                   | `false`                           |
+| `dynamic`  | `true` (non-final)       | `AUTO` (concrete types are final) |
+
+## Best Practices
+
+1. **Configure field IDs**: Recommended for compatible mode to reduce serialization cost
+2. **Use `nullable = true` for nullable fields**: Required for fields that can be null
+3. **Enable ref tracking for shared objects**: Use `ref = true` when objects are shared or circular
+4. **Use `@Ignore` or `transient` for sensitive data**: Passwords, tokens, internal state
+5. **Choose appropriate encoding**: `varint` for small values, `fixed` for full-range values
+6. **Keep IDs stable**: Once assigned, don't change field IDs
+7. **Configure unsigned types for cross-language compatibility**: When interoperating with unsigned numbers in Rust, Go, C++
+
+## Annotations Reference
+
+| Annotation                    | Description                            |
+| ----------------------------- | -------------------------------------- |
+| `@ForyField(id = N)`          | Field tag ID to reduce metadata size   |
+| `@ForyField(nullable = true)` | Mark field as nullable                 |
+| `@ForyField(ref = true)`      | Enable reference tracking              |
+| `@ForyField(dynamic = ...)`   | Control polymorphism for struct fields |
+| `@Ignore`                     | Exclude field from serialization       |
+| `@Int32Type(compress = ...)`  | 32-bit signed integer encoding         |
+| `@Int64Type(encoding = ...)`  | 64-bit signed integer encoding         |
+| `@Uint8Type`                  | Unsigned 8-bit integer                 |
+| `@Uint16Type`                 | Unsigned 16-bit integer                |
+| `@Uint32Type(compress = ...)` | Unsigned 32-bit integer encoding       |
+| `@Uint64Type(encoding = ...)` | Unsigned 64-bit integer encoding       |
+
+## Related Topics
+
+- [Basic Serialization](basic_serialization) - Getting started with Fory serialization
+- [Schema Evolution](schema_evolution) - Compatible mode and schema evolution
+- [Cross-Language](cross_language) - Interoperability with Python, Rust, C++, Go
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/python/field-configuration.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/python/field-configuration.md
new file mode 100644
index 0000000000..b14d7d4419
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/python/field-configuration.md
@@ -0,0 +1,492 @@
+---
+title: Field Configuration
+sidebar_position: 5
+id: field_configuration
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+This page explains how to configure field-level metadata for serialization in Python.
+
+## Overview
+
+Apache ForyTM provides field-level configuration through:
+
+- **`pyfory.field()`**: Configure field metadata (id, nullable, ref, ignore, dynamic)
+- **Type annotations**: Control integer encoding (varint, fixed, tagged)
+- **`Optional[T]`**: Mark fields as nullable
+
+This enables:
+
+- **Tag IDs**: Assign compact numeric IDs to reduce struct field meta size overhead
+- **Nullability**: Control whether fields can be null
+- **Reference Tracking**: Enable reference tracking for shared objects
+- **Field Skipping**: Exclude fields from serialization
+- **Encoding Control**: Specify how integers are encoded (varint, fixed, tagged)
+- **Polymorphism**: Control whether type info is written for struct fields
+
+## Basic Syntax
+
+Use `@dataclass` decorator with type annotations and `pyfory.field()`:
+
+```python
+from dataclasses import dataclass
+from typing import Optional
+import pyfory
+
+@dataclass
+class Person:
+    name: str = pyfory.field(id=0)
+    age: pyfory.int32 = pyfory.field(id=1, default=0)
+    nickname: Optional[str] = pyfory.field(id=2, nullable=True, default=None)
+```
+
+## The `pyfory.field()` Function
+
+Use `pyfory.field()` to configure field-level metadata:
+
+```python
+@dataclass
+class User:
+    id: pyfory.int64 = pyfory.field(id=0, default=0)
+    name: str = pyfory.field(id=1, default="")
+    email: Optional[str] = pyfory.field(id=2, nullable=True, default=None)
+    friends: List["User"] = pyfory.field(id=3, ref=True, default_factory=list)
+    _cache: dict = pyfory.field(ignore=True, default_factory=dict)
+```
+
+### Parameters
+
+| Parameter         | Type     | Default   | Description                          |
+| ----------------- | -------- | --------- | ------------------------------------ |
+| `id`              | `int`    | `-1`      | Field tag ID (-1 = use field name)   |
+| `nullable`        | `bool`   | `False`   | Whether the field can be null        |
+| `ref`             | `bool`   | `False`   | Enable reference tracking            |
+| `ignore`          | `bool`   | `False`   | Exclude field from serialization     |
+| `dynamic`         | `bool`   | `None`    | Control whether type info is written |
+| `default`         | Any      | `MISSING` | Default value for the field          |
+| `default_factory` | Callable | `MISSING` | Factory function for default value   |
+
+## Field ID (`id`)
+
+Assigns a numeric ID to a field to minimize struct field meta size overhead:
+
+```python
+@dataclass
+class User:
+    id: pyfory.int64 = pyfory.field(id=0, default=0)
+    name: str = pyfory.field(id=1, default="")
+    age: pyfory.int32 = pyfory.field(id=2, default=0)
+```
+
+**Benefits**:
+
+- Smaller serialized size (numeric IDs vs field names in metadata)
+- Reduced struct field meta overhead
+- Allows renaming fields without breaking binary compatibility
+
+**Recommendation**: It is recommended to configure field IDs for compatible mode since it reduces serialization cost.
+
+**Notes**:
+
+- IDs must be unique within a class
+- IDs must be >= 0 (use -1 to use field name encoding, which is the default)
+- If not specified, field name is used in metadata (larger overhead)
+
+**Without field IDs** (field names used in metadata):
+
+```python
+@dataclass
+class User:
+    id: pyfory.int64 = 0
+    name: str = ""
+```
+
+## Nullable Fields (`nullable`)
+
+Use `nullable=True` for fields that can be `None`:
+
+```python
+from typing import Optional
+
+@dataclass
+class Record:
+    # Nullable string field
+    optional_name: Optional[str] = pyfory.field(id=0, nullable=True, default=None)
+
+    # Nullable integer field
+    optional_count: Optional[pyfory.int32] = pyfory.field(id=1, nullable=True, default=None)
+```
+
+**Notes**:
+
+- `Optional[T]` fields must have `nullable=True`
+- Non-optional fields default to `nullable=False`
+
+## Reference Tracking (`ref`)
+
+Enable reference tracking for fields that may be shared or circular:
+
+```python
+@dataclass
+class RefOuter:
+    # Both fields may point to the same inner object
+    inner1: Optional[RefInner] = pyfory.field(id=0, ref=True, nullable=True, default=None)
+    inner2: Optional[RefInner] = pyfory.field(id=1, ref=True, nullable=True, default=None)
+
+
+@dataclass
+class CircularRef:
+    name: str = pyfory.field(id=0, default="")
+    # Self-referencing field for circular references
+    self_ref: Optional["CircularRef"] = pyfory.field(id=1, ref=True, nullable=True, default=None)
+```
+
+**Use Cases**:
+
+- Enable for fields that may be circular or shared
+- When the same object is referenced from multiple fields
+
+**Notes**:
+
+- Reference tracking only takes effect when `Fory(ref=True)` is set globally
+- Field-level `ref=True` AND global `ref=True` must both be enabled
+
+## Skipping Fields (`ignore`)
+
+Exclude fields from serialization:
+
+```python
+@dataclass
+class User:
+    id: pyfory.int64 = pyfory.field(id=0, default=0)
+    name: str = pyfory.field(id=1, default="")
+    # Not serialized
+    _cache: dict = pyfory.field(ignore=True, default_factory=dict)
+    _internal_state: str = pyfory.field(ignore=True, default="")
+```
+
+## Dynamic Fields (`dynamic`)
+
+Control whether type information is written for struct fields. This is essential for polymorphism support:
+
+```python
+from abc import ABC, abstractmethod
+
+class Shape(ABC):
+    @abstractmethod
+    def area(self) -> float:
+        pass
+
+@dataclass
+class Circle(Shape):
+    radius: float = 0.0
+
+    def area(self) -> float:
+        return 3.14159 * self.radius * self.radius
+
+@dataclass
+class Container:
+    # Abstract class: dynamic is always True (type info written)
+    shape: Shape = pyfory.field(id=0)
+
+    # Force type info for concrete type (support runtime subtypes)
+    circle: Circle = pyfory.field(id=1, dynamic=True)
+
+    # Skip type info for concrete type (use declared type directly)
+    fixed_circle: Circle = pyfory.field(id=2, dynamic=False)
+```
+
+**Default Behavior**:
+
+| Mode        | Abstract Class | Concrete Object Types | Numeric/str/time Types |
+| ----------- | -------------- | --------------------- | ---------------------- |
+| Native mode | `True`         | `True`                | `False`                |
+| Xlang mode  | `True`         | `False`               | `False`                |
+
+**Notes**:
+
+- **Abstract classes**: `dynamic` is always `True` (type info must be written)
+- **Native mode**: `dynamic` defaults to `True` for object types, `False` for numeric/str/time types
+- **Xlang mode**: `dynamic` defaults to `False` for concrete types
+- Use `dynamic=True` when a concrete field may hold subclass instances
+- Use `dynamic=False` for performance optimization when type is known
+
+## Integer Type Annotations
+
+Fory provides type annotations to control integer encoding:
+
+### Signed Integers
+
+```python
+@dataclass
+class SignedIntegers:
+    byte_val: pyfory.int8 = 0      # 8-bit signed
+    short_val: pyfory.int16 = 0    # 16-bit signed
+    int_val: pyfory.int32 = 0      # 32-bit signed (varint encoding)
+    long_val: pyfory.int64 = 0     # 64-bit signed (varint encoding)
+```
+
+### Unsigned Integers
+
+```python
+@dataclass
+class UnsignedIntegers:
+    # Fixed-size encoding
+    u8_val: pyfory.uint8 = 0       # 8-bit unsigned (fixed)
+    u16_val: pyfory.uint16 = 0     # 16-bit unsigned (fixed)
+
+    # Variable-length encoding (default for u32/u64)
+    u32_var: pyfory.uint32 = 0     # 32-bit unsigned (varint)
+    u64_var: pyfory.uint64 = 0     # 64-bit unsigned (varint)
+
+    # Explicit fixed-size encoding
+    u32_fixed: pyfory.fixed_uint32 = 0   # 32-bit unsigned (fixed 4 bytes)
+    u64_fixed: pyfory.fixed_uint64 = 0   # 64-bit unsigned (fixed 8 bytes)
+
+    # Tagged encoding (includes type tag)
+    u64_tagged: pyfory.tagged_uint64 = 0  # 64-bit unsigned (tagged)
+```
+
+### Floating Point
+
+```python
+@dataclass
+class FloatingPoint:
+    float_val: pyfory.float32 = 0.0   # 32-bit float
+    double_val: pyfory.float64 = 0.0  # 64-bit double
+```
+
+### Encoding Summary
+
+| Type                   | Encoding | Size       |
+| ---------------------- | -------- | ---------- |
+| `pyfory.int8`          | fixed    | 1 byte     |
+| `pyfory.int16`         | fixed    | 2 bytes    |
+| `pyfory.int32`         | varint   | 1-5 bytes  |
+| `pyfory.int64`         | varint   | 1-10 bytes |
+| `pyfory.uint8`         | fixed    | 1 byte     |
+| `pyfory.uint16`        | fixed    | 2 bytes    |
+| `pyfory.uint32`        | varint   | 1-5 bytes  |
+| `pyfory.uint64`        | varint   | 1-10 bytes |
+| `pyfory.fixed_uint32`  | fixed    | 4 bytes    |
+| `pyfory.fixed_uint64`  | fixed    | 8 bytes    |
+| `pyfory.tagged_uint64` | tagged   | 1-9 bytes  |
+| `pyfory.float32`       | fixed    | 4 bytes    |
+| `pyfory.float64`       | fixed    | 8 bytes    |
+
+**When to Use**:
+
+- `varint`: Best for values that are often small (default for int32/int64/uint32/uint64)
+- `fixed`: Best for values that use full range (e.g., timestamps, hashes)
+- `tagged`: When type information needs to be preserved (uint64 only)
+
+## Complete Example
+
+```python
+from dataclasses import dataclass
+from typing import Optional, List, Dict, Set
+import pyfory
+
+
+@dataclass
+class Document:
+    # Fields with tag IDs (recommended for compatible mode)
+    title: str = pyfory.field(id=0, default="")
+    version: pyfory.int32 = pyfory.field(id=1, default=0)
+
+    # Nullable field
+    description: Optional[str] = pyfory.field(id=2, nullable=True, default=None)
+
+    # Collection fields
+    tags: List[str] = pyfory.field(id=3, default_factory=list)
+    metadata: Dict[str, str] = pyfory.field(id=4, default_factory=dict)
+    categories: Set[str] = pyfory.field(id=5, default_factory=set)
+
+    # Unsigned integers with different encodings
+    view_count: pyfory.uint64 = pyfory.field(id=6, default=0)           # varint encoding
+    file_size: pyfory.fixed_uint64 = pyfory.field(id=7, default=0)      # fixed encoding
+    checksum: pyfory.tagged_uint64 = pyfory.field(id=8, default=0)      # tagged encoding
+
+    # Reference-tracked field for shared/circular references
+    parent: Optional["Document"] = pyfory.field(id=9, ref=True, nullable=True, default=None)
+
+    # Ignored field (not serialized)
+    _cache: dict = pyfory.field(ignore=True, default_factory=dict)
+
+
+def main():
+    fory = pyfory.Fory(xlang=True, compatible=True, ref=True)
+    fory.register_type(Document, type_id=100)
+
+    doc = Document(
+        title="My Document",
+        version=1,
+        description="A sample document",
+        tags=["tag1", "tag2"],
+        metadata={"key": "value"},
+        categories={"cat1"},
+        view_count=42,
+        file_size=1024,
+        checksum=123456789,
+        parent=None,
+    )
+
+    # Serialize
+    data = fory.serialize(doc)
+
+    # Deserialize
+    decoded = fory.deserialize(data)
+    assert decoded.title == doc.title
+    assert decoded.version == doc.version
+
+
+if __name__ == "__main__":
+    main()
+```
+
+## Cross-Language Compatibility
+
+When serializing data to be read by other languages (Java, Rust, C++, Go), use field IDs and matching type annotations:
+
+```python
+@dataclass
+class CrossLangData:
+    # Use field IDs for cross-language compatibility
+    int_var: pyfory.int32 = pyfory.field(id=0, default=0)
+    long_fixed: pyfory.fixed_uint64 = pyfory.field(id=1, default=0)
+    long_tagged: pyfory.tagged_uint64 = pyfory.field(id=2, default=0)
+    optional_value: Optional[str] = pyfory.field(id=3, nullable=True, default=None)
+```
+
+## Schema Evolution
+
+Compatible mode supports schema evolution. It is recommended to configure field IDs to reduce serialization cost:
+
+```python
+# Version 1
+@dataclass
+class DataV1:
+    id: pyfory.int64 = pyfory.field(id=0, default=0)
+    name: str = pyfory.field(id=1, default="")
+
+
+# Version 2: Added new field
+@dataclass
+class DataV2:
+    id: pyfory.int64 = pyfory.field(id=0, default=0)
+    name: str = pyfory.field(id=1, default="")
+    email: Optional[str] = pyfory.field(id=2, nullable=True, default=None)  # New field
+```
+
+Data serialized with V1 can be deserialized with V2 (new field will be `None`).
+
+Alternatively, field IDs can be omitted (field names will be used in metadata with larger overhead):
+
+```python
+@dataclass
+class Data:
+    id: pyfory.int64 = 0
+    name: str = ""
+```
+
+## Native Mode vs Xlang Mode
+
+Field configuration behaves differently depending on the serialization mode:
+
+### Native Mode (Python-only)
+
+Native mode has **relaxed default values** for maximum compatibility:
+
+- **Nullable**: `str` and numeric types are non-nullable by default unless `Optional` is used
+- **Ref tracking**: Enabled by default for object references (except `str` and numeric types)
+
+In native mode, you typically **don't need to configure field annotations** unless you want to:
+
+- Reduce serialized size by using field IDs
+- Optimize performance by disabling unnecessary ref tracking
+
+```python
+# Native mode: works without field configuration
+@dataclass
+class User:
+    id: int = 0
+    name: str = ""
+    tags: List[str] = None
+```
+
+### Xlang Mode (Cross-language)
+
+Xlang mode has **stricter default values** due to type system differences between languages:
+
+- **Nullable**: Fields are non-nullable by default (`nullable=False`)
+- **Ref tracking**: Disabled by default (`ref=False`)
+
+In xlang mode, you **need to configure fields** when:
+
+- A field can be None (use `Optional[T]` with `nullable=True`)
+- A field needs reference tracking for shared/circular objects (use `ref=True`)
+- Integer types need specific encoding for cross-language compatibility
+- You want to reduce metadata size (use field IDs)
+
+```python
+# Xlang mode: explicit configuration required for nullable/ref fields
+@dataclass
+class User:
+    id: pyfory.int64 = pyfory.field(id=0, default=0)
+    name: str = pyfory.field(id=1, default="")
+    email: Optional[str] = pyfory.field(id=2, nullable=True, default=None)  # Must declare nullable
+    friend: Optional["User"] = pyfory.field(id=3, ref=True, nullable=True, default=None)  # Must declare ref
+```
+
+### Default Values Summary
+
+| Option     | Native Mode Default                                   | Xlang Mode Default |
+| ---------- | ----------------------------------------------------- | ------------------ |
+| `nullable` | `False` for `str`/numeric; others nullable by default | `False`            |
+| `ref`      | `True` (except `str` and numeric types)               | `False`            |
+| `dynamic`  | `True` (except numeric/str/time types)                | `False` (concrete) |
+
+## Best Practices
+
+1. **Configure field IDs**: Recommended for compatible mode to reduce serialization cost
+2. **Use `Optional[T]` with `nullable=True`**: Required for nullable fields in xlang mode
+3. **Enable ref tracking for shared objects**: Use `ref=True` when objects are shared or circular
+4. **Use `ignore=True` for sensitive data**: Passwords, tokens, internal state
+5. **Choose appropriate encoding**: `varint` for small values, `fixed` for full-range values
+6. **Keep IDs stable**: Once assigned, don't change field IDs
+
+## Options Reference
+
+| Configuration                                | Description                          |
+| -------------------------------------------- | ------------------------------------ |
+| `pyfory.field(id=N)`                         | Field tag ID to reduce metadata size |
+| `pyfory.field(nullable=True)`                | Mark field as nullable               |
+| `pyfory.field(ref=True)`                     | Enable reference tracking            |
+| `pyfory.field(ignore=True)`                  | Exclude field from serialization     |
+| `pyfory.field(dynamic=True)`                 | Force type info to be written        |
+| `pyfory.field(dynamic=False)`                | Skip type info (use declared type)   |
+| `Optional[T]`                                | Type hint for nullable fields        |
+| `pyfory.int32`, `pyfory.int64`               | Signed integers (varint encoding)    |
+| `pyfory.uint32`, `pyfory.uint64`             | Unsigned integers (varint encoding)  |
+| `pyfory.fixed_uint32`, `pyfory.fixed_uint64` | Fixed-size unsigned                  |
+| `pyfory.tagged_uint64`                       | Tagged encoding for uint64           |
+
+## Related Topics
+
+- [Basic Serialization](basic_serialization) - Getting started with Fory serialization
+- [Schema Evolution](schema_evolution) - Compatible mode and schema evolution
+- [Cross-Language](cross_language) - Interoperability with Java, Rust, C++, Go
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/rust/field-configuration.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/rust/field-configuration.md
new file mode 100644
index 0000000000..1d2080a52c
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/rust/field-configuration.md
@@ -0,0 +1,460 @@
+---
+title: Field Configuration
+sidebar_position: 5
+id: field_configuration
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+This page explains how to configure field-level metadata for serialization in Rust.
+
+## Overview
+
+Apache Fory™ provides the `#[fory(...)]` attribute macro to specify optional field-level metadata at compile time. This enables:
+
+- **Tag IDs**: Assign compact numeric IDs to minimize struct field meta size overhead
+- **Nullability**: Control whether fields can be null
+- **Reference Tracking**: Enable reference tracking for shared ownership types
+- **Field Skipping**: Exclude fields from serialization
+- **Encoding Control**: Specify how integers are encoded (varint, fixed, tagged)
+
+## Basic Syntax
+
+The `#[fory(...)]` attribute is placed on individual struct fields:
+
+```rust
+use fory::ForyObject;
+
+#[derive(ForyObject)]
+struct Person {
+    #[fory(id = 0)]
+    name: String,
+
+    #[fory(id = 1)]
+    age: i32,
+
+    #[fory(id = 2, nullable)]
+    nickname: Option<String>,
+}
+```
+
+Multiple options are separated by commas.
+
+## Available Options
+
+### Field ID (`id = N`)
+
+Assigns a numeric ID to a field to minimize struct field meta size overhead:
+
+```rust
+#[derive(ForyObject)]
+struct User {
+    #[fory(id = 0)]
+    id: i64,
+
+    #[fory(id = 1)]
+    name: String,
+
+    #[fory(id = 2)]
+    age: i32,
+}
+```
+
+**Benefits**:
+
+- Smaller serialized size (numeric IDs vs field names in metadata)
+- Allows renaming fields without breaking binary compatibility
+
+**Recommendation**: It is recommended to configure field IDs for compatible mode since it reduces serialization cost.
+
+**Notes**:
+
+- IDs must be unique within a struct
+- IDs must be >= 0 (use -1 to explicitly opt-out of tag ID encoding)
+- If not specified, field name is used in metadata (larger overhead)
+
+### Skipping Fields (`skip`)
+
+Excludes a field from serialization:
+
+```rust
+#[derive(ForyObject)]
+struct User {
+    #[fory(id = 0)]
+    id: i64,
+
+    #[fory(id = 1)]
+    name: String,
+
+    #[fory(skip)]
+    password: String, // Not serialized
+}
+```
+
+The `password` field will not be included in serialized output and will remain at its default value after deserialization.
+
+### Nullable (`nullable`)
+
+Controls whether null flags are written for fields:
+
+```rust
+use fory::{Fory, RcWeak};
+
+#[derive(ForyObject)]
+struct Record {
+    // RcWeak is nullable by default, override to non-nullable
+    #[fory(id = 0, nullable = false)]
+    required_ref: RcWeak<Data>,
+}
+```
+
+**Default Behavior**:
+
+| Type                      | Default Nullable |
+| ------------------------- | ---------------- |
+| `Option<T>`               | `true`           |
+| `RcWeak<T>`, `ArcWeak<T>` | `true`           |
+| All other types           | `false`          |
+
+**Notes**:
+
+- For `Option<T>`, `RcWeak<T>`, `ArcWeak<T>`, nullable defaults to true
+- For all other types, nullable defaults to false
+- Use `nullable = false` to override defaults for types that are nullable by default
+
+### Reference Tracking (`ref`)
+
+Controls per-field reference tracking for shared ownership types:
+
+```rust
+use std::rc::Rc;
+use std::sync::Arc;
+
+#[derive(ForyObject)]
+struct Container {
+    // Enable reference tracking (default for Rc/Arc)
+    #[fory(id = 0, ref = true)]
+    shared_data: Rc<Data>,
+
+    // Disable reference tracking
+    #[fory(id = 1, ref = false)]
+    unique_data: Rc<Data>,
+}
+```
+
+**Default Behavior**:
+
+| Type                              | Default Ref Tracking |
+| --------------------------------- | -------------------- |
+| `Rc<T>`, `Arc<T>`                 | `true`               |
+| `RcWeak<T>`, `ArcWeak<T>`         | `true`               |
+| `Option<Rc<T>>`, `Option<Arc<T>>` | `true` (inherited)   |
+| All other types                   | `false`              |
+
+**Use Cases**:
+
+- Enable for fields that may be circular or shared
+- Disable for fields that are always unique (optimization)
+
+### Encoding (`encoding`)
+
+Controls how integer fields are encoded:
+
+```rust
+#[derive(ForyObject)]
+struct Metrics {
+    // Variable-length encoding (smaller for small values)
+    #[fory(id = 0, encoding = "varint")]
+    count: i64,
+
+    // Fixed-length encoding (consistent size)
+    #[fory(id = 1, encoding = "fixed")]
+    timestamp: i64,
+
+    // Tagged encoding (includes type tag, u64 only)
+    #[fory(id = 2, encoding = "tagged")]
+    value: u64,
+}
+```
+
+**Supported Encodings**:
+
+| Type         | Options                     | Default  |
+| ------------ | --------------------------- | -------- |
+| `i32`, `u32` | `varint`, `fixed`           | `varint` |
+| `i64`, `u64` | `varint`, `fixed`, `tagged` | `varint` |
+
+**When to Use**:
+
+- `varint`: Best for values that are often small (default)
+- `fixed`: Best for values that use full range (e.g., timestamps, hashes)
+- `tagged`: When type information needs to be preserved (u64 only)
+
+### Compress (`compress`)
+
+A convenience shorthand for controlling integer encoding:
+
+```rust
+#[derive(ForyObject)]
+struct Data {
+    // compress = true -> varint encoding (default)
+    #[fory(id = 0, compress)]
+    small_value: i32,
+
+    // compress = false -> fixed encoding
+    #[fory(id = 1, compress = false)]
+    fixed_value: u32,
+}
+```
+
+**Notes**:
+
+- `compress` or `compress = true` is equivalent to `encoding = "varint"`
+- `compress = false` is equivalent to `encoding = "fixed"`
+- If both `compress` and `encoding` are specified, they must not conflict
+
+## Type Classification
+
+Fory classifies field types to determine default behavior:
+
+| Type Class | Examples                       | Default Nullable | Default Ref |
+| ---------- | ------------------------------ | ---------------- | ----------- |
+| Primitive  | `i8`, `i32`, `f64`, `bool`     | `false`          | `false`     |
+| Option     | `Option<T>`                    | `true`           | `false`     |
+| Rc         | `Rc<T>`                        | `false`          | `true`      |
+| Arc        | `Arc<T>`                       | `false`          | `true`      |
+| RcWeak     | `RcWeak<T>` (fory type)        | `true`           | `true`      |
+| ArcWeak    | `ArcWeak<T>` (fory type)       | `true`           | `true`      |
+| Other      | `String`, `Vec<T>`, user types | `false`          | `false`     |
+
+**Special Case**: `Option<Rc<T>>` and `Option<Arc<T>>` inherit the inner type's ref tracking behavior.
+
+## Complete Example
+
+```rust
+use fory::ForyObject;
+use std::rc::Rc;
+
+#[derive(ForyObject, Default)]
+struct Document {
+    // Required fields with tag IDs
+    #[fory(id = 0)]
+    title: String,
+
+    #[fory(id = 1)]
+    version: i32,
+
+    // Optional field (nullable by default for Option)
+    #[fory(id = 2)]
+    description: Option<String>,
+
+    // Reference-tracked shared pointer
+    #[fory(id = 3)]
+    parent: Rc<Document>,
+
+    // Nullable + reference-tracked
+    #[fory(id = 4, nullable)]
+    related: Option<Rc<Document>>,
+
+    // Counter with varint encoding (small values)
+    #[fory(id = 5, encoding = "varint")]
+    view_count: u64,
+
+    // Timestamp with fixed encoding (full range values)
+    #[fory(id = 6, encoding = "fixed")]
+    created_at: i64,
+
+    // Skip sensitive field
+    #[fory(skip)]
+    internal_state: String,
+}
+
+fn main() {
+    let fory = fory::Fory::default();
+
+    let doc = Document {
+        title: "My Document".to_string(),
+        version: 1,
+        description: Some("A sample document".to_string()),
+        parent: Rc::new(Document::default()),
+        related: None, // Allowed because nullable
+        view_count: 42,
+        created_at: 1704067200,
+        internal_state: "secret".to_string(), // Will be skipped
+    };
+
+    let bytes = fory.serialize(&doc);
+    let decoded: Document = fory.deserialize(&bytes).unwrap();
+}
+```
+
+## Compile-Time Validation
+
+Invalid configurations are caught at compile time:
+
+```rust
+// Error: duplicate field IDs
+#[derive(ForyObject)]
+struct Bad {
+    #[fory(id = 0)]
+    field1: String,
+
+    #[fory(id = 0)]  // Compile error: duplicate id
+    field2: String,
+}
+
+// Error: invalid id value
+#[derive(ForyObject)]
+struct Bad2 {
+    #[fory(id = -2)]  // Compile error: id must be >= -1
+    field: String,
+}
+
+// Error: conflicting encoding attributes
+#[derive(ForyObject)]
+struct Bad3 {
+    #[fory(compress = true, encoding = "fixed")]  // Compile error: conflict
+    field: i32,
+}
+```
+
+## Cross-Language Compatibility
+
+When serializing data to be read by other languages (Java, C++, Go, Python), use field configuration to match encoding expectations:
+
+```rust
+#[derive(ForyObject)]
+struct CrossLangData {
+    // Matches Java Integer with varint
+    #[fory(id = 0, encoding = "varint")]
+    int_var: i32,
+
+    // Matches Java Integer with fixed
+    #[fory(id = 1, encoding = "fixed")]
+    int_fixed: i32,
+
+    // Matches Java Long with tagged encoding
+    #[fory(id = 2, encoding = "tagged")]
+    long_tagged: u64,
+
+    // Nullable pointer matches Java nullable reference
+    #[fory(id = 3, nullable)]
+    optional: Option<String>,
+}
+```
+
+## Schema Evolution
+
+Compatible mode supports schema evolution. It is recommended to configure field IDs to reduce serialization cost:
+
+```rust
+// Version 1
+#[derive(ForyObject)]
+struct DataV1 {
+    #[fory(id = 0)]
+    id: i64,
+
+    #[fory(id = 1)]
+    name: String,
+}
+
+// Version 2: Added new field
+#[derive(ForyObject)]
+struct DataV2 {
+    #[fory(id = 0)]
+    id: i64,
+
+    #[fory(id = 1)]
+    name: String,
+
+    #[fory(id = 2)]
+    email: Option<String>,  // New nullable field
+}
+```
+
+Data serialized with V1 can be deserialized with V2 (new field will be `None`).
+
+Alternatively, field IDs can be omitted (field names will be used in metadata with larger overhead):
+
+```rust
+#[derive(ForyObject)]
+struct Data {
+    id: i64,
+    name: String,
+}
+```
+
+## Default Values
+
+- **Nullable**: `Option<T>`, `RcWeak<T>`, and `ArcWeak<T>` are nullable by default; all other types are non-nullable
+- **Ref tracking**: `Rc<T>`, `Arc<T>`, `RcWeak<T>`, and `ArcWeak<T>` enable ref tracking by default; all other types are disabled
+
+You **need to configure fields** when:
+
+- A field can be None (use `Option<T>`)
+- A field needs reference tracking for shared/circular objects (use `ref = true`)
+- Integer types need specific encoding for cross-language compatibility
+- You want to reduce metadata size (use field IDs)
+
+```rust
+// Xlang mode: explicit configuration required
+#[derive(ForyObject)]
+struct User {
+    #[fory(id = 0)]
+    name: String,                    // Non-nullable by default
+
+    #[fory(id = 1)]
+    email: Option<String>,           // Nullable (Option<T>)
+
+    #[fory(id = 2, ref = true)]
+    friend: Rc<User>,                // Ref tracking (default for Rc)
+}
+```
+
+### Default Values Summary
+
+| Type                      | Default Nullable | Default Ref Tracking |
+| ------------------------- | ---------------- | -------------------- |
+| Primitives, `String`      | `false`          | `false`              |
+| `Option<T>`               | `true`           | `false`              |
+| `Rc<T>`, `Arc<T>`         | `false`          | `true`               |
+| `RcWeak<T>`, `ArcWeak<T>` | `true`           | `true`               |
+
+## Best Practices
+
+1. **Configure field IDs**: Recommended for compatible mode to reduce serialization cost
+2. **Use `skip` for sensitive data**: Passwords, tokens, internal state
+3. **Enable ref tracking for shared objects**: When the same pointer appears multiple times
+4. **Disable ref tracking for unique fields**: Optimization when you know the field is unique
+5. **Choose appropriate encoding**: `varint` for small values, `fixed` for full-range values
+6. **Keep IDs stable**: Once assigned, don't change field IDs
+
+## Options Reference
+
+| Option     | Syntax                             | Description                          | Valid For                  |
+| ---------- | ---------------------------------- | ------------------------------------ | -------------------------- |
+| `id`       | `id = N`                           | Field tag ID to reduce metadata size | All fields                 |
+| `skip`     | `skip`                             | Exclude field from serialization     | All fields                 |
+| `nullable` | `nullable` or `nullable = bool`    | Control null flag writing            | All fields                 |
+| `ref`      | `ref` or `ref = bool`              | Control reference tracking           | `Rc`, `Arc`, weak types    |
+| `encoding` | `encoding = "varint/fixed/tagged"` | Integer encoding method              | `i32`, `u32`, `i64`, `u64` |
+| `compress` | `compress` or `compress = bool`    | Shorthand for varint/fixed           | `i32`, `u32`               |
+
+## Related Topics
+
+- [Basic Serialization](basic_serialization) - Getting started with Fory serialization
+- [Schema Evolution](schema_evolution) - Compatible mode and schema evolution
+- [Cross-Language](cross_language) - Interoperability with Java, C++, Go, Python
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/xlang/field-type-meta.md b/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/xlang/field-type-meta.md
new file mode 100644
index 0000000000..6b3e5b64f2
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current/guide/xlang/field-type-meta.md
@@ -0,0 +1,301 @@
+---
+title: Field Type Meta
+sidebar_position: 46
+id: field_type_meta
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+Field type meta configuration controls whether type information is written during serialization for struct fields. This is essential for supporting polymorphism where the actual runtime type may differ from the declared field type.
+
+## Overview
+
+When serializing a struct field, Fory needs to determine whether to write type metadata:
+
+- **Static typing**: Use the declared field type's serializer directly (no type info written)
+- **Dynamic typing**: Write type information to support runtime subtypes
+
+## When Type Meta Is Needed
+
+Type metadata is required when:
+
+1. **Interface/abstract fields**: The declared type is abstract, so concrete type must be recorded
+2. **Polymorphic fields**: The runtime type may be a subclass of the declared type
+3. **Cross-language compatibility**: When the receiver needs type information to deserialize correctly
+
+Type metadata is NOT needed when:
+
+1. **Final/concrete types**: The declared type is final/sealed and cannot be subclassed
+2. **Primitive types**: Type is known at compile time
+3. **Performance optimization**: When you know the runtime type always matches the declared type
+
+## Language-Specific Configuration
+
+### Java
+
+Java requires explicit configuration because concrete classes can be subclassed unless marked `final`.
+
+Use the `@ForyField` annotation with the `dynamic` parameter:
+
+```java
+import org.apache.fory.annotation.ForyField;
+import org.apache.fory.annotation.ForyField.Dynamic;
+
+public class Container {
+    // AUTO (default): Interface types write type info, concrete types don't
+    @ForyField(id = 0)
+    private Shape shape;  // Interface - type info written
+
+    // FALSE: Never write type info (use declared type's serializer)
+    @ForyField(id = 1, dynamic = Dynamic.FALSE)
+    private Circle circle;  // Always treated as Circle
+
+    // TRUE: Always write type info (support runtime subtypes)
+    @ForyField(id = 2, dynamic = Dynamic.TRUE)
+    private Shape concreteShape;  // Type info written even if concrete
+}
+```
+
+**Dynamic Options**:
+
+| Value   | Behavior                                               |
+| ------- | ------------------------------------------------------ |
+| `AUTO`  | Interface/abstract types are dynamic, concrete are not |
+| `FALSE` | Never write type info, use declared type's serializer  |
+| `TRUE`  | Always write type info to support runtime subtypes     |
+
+**Use Cases**:
+
+- `AUTO`: Default behavior, suitable for most cases
+- `FALSE`: Performance optimization when you know the exact type
+- `TRUE`: When a concrete field may hold subclass instances
+
+### C++
+
+C++ uses the `fory::dynamic<V>` template tag or `.dynamic(bool)` builder method:
+
+**Using `fory::field<>` template**:
+
+```cpp
+#include "fory/serialization/fory.h"
+
+// Abstract base class with pure virtual methods
+struct Animal {
+    virtual ~Animal() = default;
+    virtual std::string speak() const = 0;
+};
+
+struct Zoo {
+    // Auto: type info written because Animal is polymorphic (std::is_polymorphic)
+    fory::field<std::shared_ptr<Animal>, 0, fory::nullable> animal;
+
+    // Force non-dynamic: skip type info even though Animal is polymorphic
+    fory::field<std::shared_ptr<Animal>, 1, fory::nullable, fory::dynamic<false>> fixed_animal;
+
+    // Force dynamic: write type info even for non-polymorphic types
+    fory::field<std::shared_ptr<Data>, 2, fory::dynamic<true>> polymorphic_data;
+};
+FORY_STRUCT(Zoo, animal, fixed_animal, polymorphic_data);
+```
+
+**Using `FORY_FIELD_CONFIG` macro**:
+
+```cpp
+struct Zoo {
+    std::shared_ptr<Animal> animal;
+    std::shared_ptr<Animal> fixed_animal;
+    std::shared_ptr<Data> polymorphic_data;
+};
+
+FORY_STRUCT(Zoo, animal, fixed_animal, polymorphic_data);
+
+FORY_FIELD_CONFIG(Zoo,
+    (animal, fory::F(0).nullable()),                    // Auto-detect polymorphism
+    (fixed_animal, fory::F(1).nullable().dynamic(false)), // Skip type info
+    (polymorphic_data, fory::F(2).dynamic(true))        // Force type info
+);
+```
+
+**Default Behavior**: Fory auto-detects polymorphism via `std::is_polymorphic<T>`. Types with pure virtual methods are treated as dynamic by default.
+
+### Go and Rust
+
+Go and Rust do **not** require explicit dynamic configuration because:
+
+- **Go**: Interface types are inherently dynamic - Fory can determine from the type whether it's an interface
+- **Rust**: Trait objects (`dyn Trait`) are explicitly marked in the type system
+
+The type system in these languages already indicates whether a field is polymorphic:
+
+```go
+// Go: interface types are automatically dynamic
+type Container struct {
+    Shape  Shape       // Interface - type info written automatically
+    Circle Circle      // Concrete struct - no type info needed
+}
+```
+
+```rust
+// Rust: trait objects are explicitly marked
+struct Container {
+    shape: Box<dyn Shape>,  // Trait object - type info written automatically
+    circle: Circle,         // Concrete type - no type info needed
+}
+```
+
+### Python
+
+Use `pyfory.field()` with the `dynamic` parameter:
+
+```python
+from dataclasses import dataclass
+from abc import ABC, abstractmethod
+import pyfory
+
+class Shape(ABC):
+    @abstractmethod
+    def area(self) -> float:
+        pass
+
+@dataclass
+class Circle(Shape):
+    radius: float = 0.0
+
+    def area(self) -> float:
+        return 3.14159 * self.radius * self.radius
+
+@dataclass
+class Container:
+    # Abstract class: dynamic is always True (type info written)
+    shape: Shape = pyfory.field(id=0)
+
+    # Concrete type with explicit dynamic=True (force type info)
+    circle: Circle = pyfory.field(id=1, dynamic=True)
+
+    # Concrete type with explicit dynamic=False (skip type info)
+    fixed_circle: Circle = pyfory.field(id=2, dynamic=False)
+```
+
+**Default Behavior**:
+
+| Mode        | Abstract Class | Concrete Object Types | Numeric/str/time Types |
+| ----------- | -------------- | --------------------- | ---------------------- |
+| Native mode | `True`         | `True`                | `False`                |
+| Xlang mode  | `True`         | `False`               | `False`                |
+
+- **Abstract classes**: `dynamic` is always `True` (type info must be written)
+- **Native mode**: `dynamic` defaults to `True` for object types, `False` for numeric/str/time types
+- **Xlang mode**: `dynamic` defaults to `False` for concrete types
+
+## Default Behavior
+
+| Language | Interface/Abstract Types | Concrete Types   |
+| -------- | ------------------------ | ---------------- |
+| Java     | Dynamic (write type)     | Static (no type) |
+| C++      | Dynamic (virtual)        | Static           |
+| Go       | Dynamic (interface)      | Static (struct)  |
+| Rust     | Dynamic (dyn Trait)      | Static           |
+| Python   | Dynamic (all objects)    | Dynamic          |
+
+## Performance Considerations
+
+Writing type metadata has overhead:
+
+- **Space**: Type information adds bytes to serialized output
+- **Time**: Type resolution during serialization/deserialization
+
+Use `dynamic = FALSE` (Java) or `dynamic(false)` (C++) when:
+
+- You're certain the runtime type matches the declared type
+- Performance is critical and polymorphism is not needed
+- The field type is effectively final
+
+## Cross-Language Compatibility
+
+When serializing data for cross-language consumption:
+
+1. **Use consistent type registration**: Register types with the same ID across languages
+2. **Prefer explicit configuration**: Use `dynamic = TRUE` when unsure about receiver's expectations
+3. **Document polymorphic fields**: Make it clear which fields may contain subtypes
+
+## Example: Polymorphic Container
+
+### Java
+
+```java
+public interface Animal {
+    String speak();
+}
+
+public class Dog implements Animal {
+    private String name;
+
+    @Override
+    public String speak() { return "Woof!"; }
+}
+
+public class Cat implements Animal {
+    private String name;
+
+    @Override
+    public String speak() { return "Meow!"; }
+}
+
+public class Zoo {
+    // Type info written because Animal is an interface
+    @ForyField(id = 0)
+    private Animal animal;
+
+    // Force type info for concrete type that may hold subtypes
+    @ForyField(id = 1, dynamic = Dynamic.TRUE)
+    private Dog maybeMixedBreed;
+}
+```
+
+### C++
+
+```cpp
+// Abstract base class with pure virtual methods
+class Animal {
+public:
+    virtual std::string speak() const = 0;
+    virtual ~Animal() = default;
+};
+
+class Dog : public Animal {
+public:
+    std::string name;
+    std::string speak() const override { return "Woof!"; }
+};
+
+struct Zoo {
+    std::shared_ptr<Animal> animal;
+    std::shared_ptr<Dog> maybe_mixed_breed;
+};
+
+FORY_STRUCT(Zoo, animal, maybe_mixed_breed);
+
+FORY_FIELD_CONFIG(Zoo,
+    (animal, fory::F(0).nullable()),              // Auto-detect (Animal is polymorphic)
+    (maybe_mixed_breed, fory::F(1).dynamic(true)) // Force dynamic for concrete type
+);
+```
+
+## Related Topics
+
+- [Field Nullability](field_nullability) - Controlling null handling for fields
+- [Field Reference Tracking](reference_tracking) - Managing shared/circular references
+- [Type Mapping](../../specification/xlang_type_mapping) - Cross-language type compatibility
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/compiler-guide.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/compiler-guide.md
new file mode 100644
index 0000000000..833ea0d3ff
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/compiler-guide.md
@@ -0,0 +1,657 @@
+---
+title: Compiler Guide
+sidebar_position: 3
+id: compiler_guide
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+This guide covers installation, usage, and integration of the Fory IDL compiler.
+
+## Installation
+
+### From Source
+
+```bash
+cd compiler
+pip install -e .
+```
+
+### Verify Installation
+
+```bash
+foryc --help
+```
+
+## Command Line Interface
+
+### Basic Usage
+
+```bash
+foryc [OPTIONS] FILES...
+```
+
+```bash
+foryc --scan-generated [OPTIONS]
+```
+
+### Options
+
+Compile options:
+
+| Option                                | Description                                           | Default             |
+| ------------------------------------- | ----------------------------------------------------- | ------------------- |
+| `--lang`                              | Comma-separated target languages                      | `all`               |
+| `--output`, `-o`                      | Output directory                                      | `./generated`       |
+| `--package`                           | Override package name from Fory IDL file              | (from file)         |
+| `-I`, `--proto_path`, `--import_path` | Add directory to import search path (can be repeated) | (none)              |
+| `--java_out=DST_DIR`                  | Generate Java code in DST_DIR                         | (none)              |
+| `--python_out=DST_DIR`                | Generate Python code in DST_DIR                       | (none)              |
+| `--cpp_out=DST_DIR`                   | Generate C++ code in DST_DIR                          | (none)              |
+| `--go_out=DST_DIR`                    | Generate Go code in DST_DIR                           | (none)              |
+| `--rust_out=DST_DIR`                  | Generate Rust code in DST_DIR                         | (none)              |
+| `--go_nested_type_style`              | Go nested type naming: `camelcase` or `underscore`    | from schema/default |
+| `--emit-fdl`                          | Print translated Fory IDL for non-`.fdl` inputs       | `false`             |
+| `--emit-fdl-path`                     | Write translated Fory IDL to a file or directory      | (stdout)            |
+
+Scan options (with `--scan-generated`):
+
+| Option       | Description                    | Default |
+| ------------ | ------------------------------ | ------- |
+| `--root`     | Root directory to scan         | `.`     |
+| `--relative` | Print paths relative to root   | `false` |
+| `--delete`   | Delete matched generated files | `false` |
+| `--dry-run`  | Scan/print only, do not delete | `false` |
+
+### Scan Generated Files
+
+Use `--scan-generated` to find files produced by `foryc`. The scanner walks
+the tree recursively, skips `build/`, `target/`, and hidden directories, and prints
+each generated file as it is found.
+
+```bash
+# Scan current directory
+foryc --scan-generated
+
+# Scan a specific root
+foryc --scan-generated --root ./src
+
+# Print paths relative to the scan root
+foryc --scan-generated --root ./src --relative
+
+# Delete scanned generated files
+foryc --scan-generated --root ./src --delete
+
+# Dry-run (scan and print only)
+foryc --scan-generated --root ./src --dry-run
+```
+
+### Examples
+
+**Compile for all languages:**
+
+```bash
+foryc schema.fdl
+```
+
+**Compile for specific languages:**
+
+```bash
+foryc schema.fdl --lang java,python
+```
+
+**Specify output directory:**
+
+```bash
+foryc schema.fdl --output ./src/generated
+```
+
+**Override package name:**
+
+```bash
+foryc schema.fdl --package com.myapp.models
+```
+
+**Compile multiple files:**
+
+```bash
+foryc user.fdl order.fdl product.fdl --output ./generated
+```
+
+**Use import search paths:**
+
+```bash
+# Add a single import path
+foryc src/main.fdl -I libs/common
+
+# Add multiple import paths (repeated option)
+foryc src/main.fdl -I libs/common -I libs/types
+
+# Add multiple import paths (comma-separated)
+foryc src/main.fdl -I libs/common,libs/types,third_party/
+
+# Using --proto_path (protoc-compatible alias)
+foryc src/main.fdl --proto_path=libs/common
+
+# Mix all styles
+foryc src/main.fdl -I libs/common,libs/types --proto_path third_party/
+```
+
+**Language-specific output directories (protoc-style):**
+
+```bash
+# Generate only Java code to a specific directory
+foryc schema.fdl --java_out=./src/main/java
+
+# Generate multiple languages to different directories
+foryc schema.fdl --java_out=./java/gen --python_out=./python/src --go_out=./go/gen
+
+# Combine with import paths
+foryc schema.fdl --java_out=./gen/java -I proto/ -I common/
+```
+
+When using `--{lang}_out` options:
+
+- Only the specified languages are generated (not all languages)
+- The compiler writes under the specified directory (language-specific generators may still create package/module subdirectories)
+- This is compatible with protoc-style workflows
+
+**Inspect translated Fory IDL from proto/fbs input:**
+
+```bash
+# Print translated Fory IDL to stdout
+foryc schema.proto --emit-fdl
+
+# Write translated Fory IDL to a directory
+foryc schema.fbs --emit-fdl --emit-fdl-path ./translated
+```
+
+## Import Path Resolution
+
+When compiling Fory IDL files with imports, the compiler searches for imported files in this order:
+
+1. **Relative to the importing file (default)** - The directory containing the file with the import statement is always searched first, automatically. No `-I` flag needed for same-directory imports.
+2. **Each `-I` path in order** - Additional search paths specified on the command line
+
+**Same-directory imports work automatically:**
+
+```protobuf
+// main.fdl
+import "common.fdl";  // Found if common.fdl is in the same directory
+```
+
+```bash
+# No -I needed for same-directory imports
+foryc main.fdl
+```
+
+**Example project structure:**
+
+```
+project/
+├── src/
+│   └── main.fdl          # import "common.fdl";
+└── libs/
+    └── common.fdl
+```
+
+**Without `-I` (fails):**
+
+```bash
+$ foryc src/main.fdl
+Import error: Import not found: common.fdl
+  Searched in: /project/src
+```
+
+**With `-I` (succeeds):**
+
+```bash
+$ foryc src/main.fdl -I libs/
+Compiling src/main.fdl...
+  Resolved 1 import(s)
+```
+
+## Supported Languages
+
+| Language | Flag     | Output Extension | Description                 |
+| -------- | -------- | ---------------- | --------------------------- |
+| Java     | `java`   | `.java`          | POJOs with Fory annotations |
+| Python   | `python` | `.py`            | Dataclasses with type hints |
+| Go       | `go`     | `.go`            | Structs with struct tags    |
+| Rust     | `rust`   | `.rs`            | Structs with derive macros  |
+| C++      | `cpp`    | `.h`             | Structs with FORY macros    |
+
+## Output Structure
+
+### Java
+
+```
+generated/
+└── java/
+    └── com/
+        └── example/
+            ├── User.java
+            ├── Order.java
+            ├── Status.java
+            └── ExampleForyRegistration.java
+```
+
+- One file per type (enum or message)
+- Package structure matches Fory IDL package
+- Registration helper class generated
+
+### Python
+
+```
+generated/
+└── python/
+    └── example.py
+```
+
+- Single module with all types
+- Module name derived from package
+- Registration function included
+
+### Go
+
+```
+generated/
+└── go/
+    └── example/
+        └── example.go
+```
+
+- Single file with all types
+- Directory and package name are derived from `go_package` or the Fory IDL package
+- Registration function included
+
+### Rust
+
+```
+generated/
+└── rust/
+    └── example.rs
+```
+
+- Single module with all types
+- Module name derived from package
+- Registration function included
+
+### C++
+
+```
+generated/
+└── cpp/
+    └── example.h
+```
+
+- Single header file
+- Namespace matches package (dots to `::`)
+- Header guards and forward declarations
+
+## Build Integration
+
+### Maven (Java)
+
+Add to your `pom.xml`:
+
+```xml
+<build>
+  <plugins>
+    <plugin>
+      <groupId>org.codehaus.mojo</groupId>
+      <artifactId>exec-maven-plugin</artifactId>
+      <version>3.1.0</version>
+      <executions>
+        <execution>
+          <id>generate-fory-types</id>
+          <phase>generate-sources</phase>
+          <goals>
+            <goal>exec</goal>
+          </goals>
+          <configuration>
+            <executable>foryc</executable>
+            <arguments>
+              <argument>${project.basedir}/src/main/fdl/schema.fdl</argument>
+              <argument>--java_out</argument>
+              <argument>${project.build.directory}/generated-sources/fory</argument>
+            </arguments>
+          </configuration>
+        </execution>
+      </executions>
+    </plugin>
+  </plugins>
+</build>
+```
+
+Add generated sources:
+
+```xml
+<build>
+  <plugins>
+    <plugin>
+      <groupId>org.codehaus.mojo</groupId>
+      <artifactId>build-helper-maven-plugin</artifactId>
+      <version>3.4.0</version>
+      <executions>
+        <execution>
+          <phase>generate-sources</phase>
+          <goals>
+            <goal>add-source</goal>
+          </goals>
+          <configuration>
+            <sources>
+              <source>${project.build.directory}/generated-sources/fory</source>
+            </sources>
+          </configuration>
+        </execution>
+      </executions>
+    </plugin>
+  </plugins>
+</build>
+```
+
+### Gradle (Java/Kotlin)
+
+Add to `build.gradle`:
+
+```groovy
+task generateForyTypes(type: Exec) {
+    commandLine 'foryc',
+        "${projectDir}/src/main/fdl/schema.fdl",
+        '--java_out', "${buildDir}/generated/sources/fory"
+}
+
+compileJava.dependsOn generateForyTypes
+
+sourceSets {
+    main {
+        java {
+            srcDir "${buildDir}/generated/sources/fory"
+        }
+    }
+}
+```
+
+### Python (setuptools)
+
+Add to `setup.py` or `pyproject.toml`:
+
+```python
+# setup.py
+from setuptools import setup
+from setuptools.command.build_py import build_py
+import subprocess
+
+class BuildWithForyIdl(build_py):
+    def run(self):
+        subprocess.run([
+            'foryc',
+            'schema.fdl',
+            '--python_out', 'src/generated'
+        ], check=True)
+        super().run()
+
+setup(
+    cmdclass={'build_py': BuildWithForyIdl},
+    # ...
+)
+```
+
+### Go (go generate)
+
+Add to your Go file:
+
+```go
+//go:generate foryc ../schema.fdl --lang go --output .
+package models
+```
+
+Run:
+
+```bash
+go generate ./...
+```
+
+### Rust (build.rs)
+
+Add to `build.rs`:
+
+```rust
+use std::process::Command;
+
+fn main() {
+    println!("cargo:rerun-if-changed=schema.fdl");
+
+    let status = Command::new("foryc")
+        .args(&["schema.fdl", "--rust_out", "src/generated"])
+        .status()
+        .expect("Failed to run foryc");
+
+    if !status.success() {
+        panic!("Fory IDL compilation failed");
+    }
+}
+```
+
+### CMake (C++)
+
+Add to `CMakeLists.txt`:
+
+```cmake
+find_program(FORY_COMPILER foryc)
+
+add_custom_command(
+    OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/generated/example.h
+    COMMAND ${FORY_COMPILER}
+        ${CMAKE_CURRENT_SOURCE_DIR}/schema.fdl
+        --cpp_out ${CMAKE_CURRENT_SOURCE_DIR}/generated
+    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/schema.fdl
+    COMMENT "Generating Fory IDL types"
+)
+
+add_custom_target(generate_fory_idl DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/generated/example.h)
+
+add_library(mylib ...)
+add_dependencies(mylib generate_fory_idl)
+target_include_directories(mylib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/generated)
+```
+
+### Bazel
+
+Create a rule in `BUILD`:
+
+```python
+genrule(
+    name = "generate_fdl",
+    srcs = ["schema.fdl"],
+    outs = ["generated/example.h"],
+    cmd = "$(location //:fory_compiler) $(SRCS) --cpp_out $(RULEDIR)/generated",
+    tools = ["//:fory_compiler"],
+)
+
+cc_library(
+    name = "models",
+    hdrs = [":generate_fdl"],
+    # ...
+)
+```
+
+## Error Handling
+
+### Syntax Errors
+
+```
+Error: Line 5, Column 12: Expected ';' after field declaration
+```
+
+Fix: Check the indicated line for missing semicolons or syntax issues.
+
+### Duplicate Type Names
+
+```
+Error: Duplicate type name: User
+```
+
+Fix: Ensure each enum and message has a unique name within the file.
+
+### Duplicate Type IDs
+
+```
+Error: Duplicate type ID 100: User and Order
+```
+
+Fix: Assign unique type IDs to each type.
+
+### Unknown Type References
+
+```
+Error: Unknown type 'Address' in Customer.address
+```
+
+Fix: Define the referenced type before using it, or check for typos.
+
+### Duplicate Field Numbers
+
+```
+Error: Duplicate field number 1 in User: name and id
+```
+
+Fix: Assign unique field numbers within each message.
+
+## Best Practices
+
+### Project Structure
+
+```
+project/
+├── fdl/
+│   ├── common.fdl       # Shared types
+│   ├── user.fdl         # User domain
+│   └── order.fdl        # Order domain
+├── src/
+│   └── generated/       # Generated code (git-ignored)
+└── build.gradle
+```
+
+### Version Control
+
+- **Track**: Fory IDL schema files
+- **Ignore**: Generated code (can be regenerated)
+
+Add to `.gitignore`:
+
+```
+# Generated Fory IDL code
+src/generated/
+generated/
+```
+
+### CI/CD Integration
+
+Always regenerate during builds:
+
+```yaml
+# GitHub Actions example
+steps:
+  - name: Install Fory IDL Compiler
+    run: pip install ./compiler
+
+  - name: Generate Types
+    run: foryc fdl/*.fdl --output src/generated
+
+  - name: Build
+    run: ./gradlew build
+```
+
+### Schema Evolution
+
+When modifying schemas:
+
+1. **Never reuse field numbers** - Mark as reserved instead
+2. **Never change type IDs** - They're part of the binary format
+3. **Add new fields** - Use new field numbers
+4. **Use `optional`** - For backward compatibility
+
+```protobuf
+message User [id=100] {
+    string id = 1;
+    string name = 2;
+    // Field 3 was removed, don't reuse
+    optional string email = 4;  // New field
+}
+```
+
+## Troubleshooting
+
+### Command Not Found
+
+```
+foryc: command not found
+```
+
+**Solution:** Ensure the compiler is installed and in your PATH:
+
+```bash
+pip install -e ./compiler
+# Or add to PATH
+export PATH=$PATH:~/.local/bin
+```
+
+### Permission Denied
+
+```
+Permission denied: ./generated
+```
+
+**Solution:** Ensure write permissions on the output directory:
+
+```bash
+chmod -R u+w ./generated
+```
+
+### Import Errors in Generated Code
+
+**Java:** Ensure Fory dependency is in your project:
+
+```xml
+<dependency>
+  <groupId>org.apache.fory</groupId>
+  <artifactId>fory-core</artifactId>
+  <version>${fory.version}</version>
+</dependency>
+```
+
+**Python:** Ensure pyfory is installed:
+
+```bash
+pip install pyfory
+```
+
+**Go:** Ensure fory module is available:
+
+```bash
+go get github.com/apache/fory/go/fory
+```
+
+**Rust:** Ensure fory crate is in `Cargo.toml`:
+
+```toml
+[dependencies]
+fory = "x.y.z"
+```
+
+**C++:** Ensure Fory headers are in include path.
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/flatbuffers-idl.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/flatbuffers-idl.md
new file mode 100644
index 0000000000..7362a1028c
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/flatbuffers-idl.md
@@ -0,0 +1,199 @@
+---
+title: FlatBuffers IDL Support
+sidebar_position: 7
+id: flatbuffers_idl
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+This page explains how Apache Fory consumes FlatBuffers schemas (`.fbs`) and
+translates them into Fory IR for code generation.
+
+## What This Page Covers
+
+- When to use FlatBuffers input with Fory
+- Exact FlatBuffers to Fory mapping behavior
+- Supported Fory-specific attributes in `.fbs`
+- Migration notes and generated-code differences
+
+## Why Use Apache Fory
+
+- Idiomatic generated code: Fory generates language-idiomatic classes/structs
+  that can be used directly as domain objects.
+- Java performance: In Java object-serialization workloads, Fory is faster than
+  FlatBuffers in Fory benchmarks.
+- Other languages: serialization performance is generally in a similar range.
+- Deserialization in practice: FlatBuffers does not perform native-object deserialization and is
+  faster by default, but if your application needs native objects, it requires
+  conversion and that conversion step can dominate read cost. In those cases,
+  Fory deserialization is often faster end-to-end.
+- Easier APIs: Fory uses direct native objects, so you do not need to
+  reverse-build tables or manually manage offsets.
+- Better graph modeling: Shared and circular references are first-class features
+  in Fory.
+
+## Quick Decision Guide
+
+| Situation                                                          | Recommended Path       |
+| ------------------------------------------------------------------ | ---------------------- |
+| You already have `.fbs` schemas and want Fory runtime/codegen      | Use FlatBuffers input  |
+| You are starting new schema work and want full Fory syntax control | Use native Fory IDL    |
+| You need FlatBuffers wire compatibility at runtime                 | Keep FlatBuffers stack |
+| You need Fory object-graph semantics (`ref`, weak refs, etc.)      | Use Fory               |
+
+## FlatBuffers to Fory Mapping
+
+### Schema-Level Rules
+
+- `namespace` maps to Fory package namespace.
+- `include` entries map to Fory imports.
+- `table` is translated as `evolving=true`.
+- `struct` is translated as `evolving=false`.
+- `root_type` is parsed but ignored by Fory runtime/codegen.
+- `file_identifier` and `file_extension` are parsed but not used by Fory codegen.
+
+### Field Numbering
+
+FlatBuffers fields do not have explicit field IDs. Fory assigns field numbers by
+source declaration order, starting at `1`.
+
+### Scalar Type Mapping
+
+| FlatBuffers | Fory Type |
+| ----------- | --------- |
+| `byte`      | `int8`    |
+| `ubyte`     | `uint8`   |
+| `short`     | `int16`   |
+| `ushort`    | `uint16`  |
+| `int`       | `int32`   |
+| `uint`      | `uint32`  |
+| `long`      | `int64`   |
+| `ulong`     | `uint64`  |
+| `float`     | `float32` |
+| `double`    | `float64` |
+| `bool`      | `bool`    |
+| `string`    | `string`  |
+
+Vectors (`[T]`) map to Fory lists.
+
+### Unions
+
+FlatBuffers unions map to Fory unions.
+
+- Case IDs are assigned by declaration order, starting at `1`.
+- Case names are derived from type names using snake_case field naming.
+
+**FlatBuffers**
+
+```fbs
+union Payload {
+  Note,
+  Metric
+}
+
+table Container {
+  payload: Payload;
+}
+```
+
+**Fory shape after translation**
+
+```protobuf
+union Payload {
+    Note note = 1;
+    Metric metric = 2;
+}
+
+message Container {
+    Payload payload = 1;
+}
+```
+
+### Defaults and Metadata
+
+- FlatBuffers default values are parsed but not applied as Fory runtime defaults.
+- Non-Fory metadata attributes are preserved as generic options in IR and may be
+  consumed by downstream tooling.
+
+## Fory-Specific Attributes in FlatBuffers
+
+FlatBuffers metadata attributes use `key:value`. For Fory-specific options, use
+`fory_` (or `fory.`) prefix in `.fbs`; the prefix is removed during parsing.
+
+### Supported Field Attributes
+
+| FlatBuffers Attribute            | Effect in Fory                                        |
+| -------------------------------- | ----------------------------------------------------- |
+| `fory_ref:true`                  | Enable reference tracking for the field               |
+| `fory_nullable:true`             | Mark field optional/nullable                          |
+| `fory_weak_ref:true`             | Enable weak reference semantics and implies `ref`     |
+| `fory_thread_safe_pointer:false` | For ref fields, select non-thread-safe pointer flavor |
+
+Semantics:
+
+- `fory_weak_ref:true` implies `ref`.
+- `fory_thread_safe_pointer` only takes effect when the field is ref-tracked.
+- For list fields, `fory_ref:true` applies to list elements.
+
+Example:
+
+```fbs
+table Node {
+  parent: Node (fory_weak_ref: true);
+  children: [Node] (fory_ref: true);
+  cached: Node (fory_ref: true, fory_thread_safe_pointer: false);
+}
+```
+
+## Generated Code Differences
+
+Using `.fbs` as input to Fory still produces normal Fory-generated code, not
+FlatBuffers `ByteBuffer`-style APIs.
+
+- Java: POJOs/records with Fory metadata
+- Python: dataclasses plus registration helpers
+- Go/Rust/C++: native structs and Fory metadata
+
+The serialization format is Fory binary protocol, not FlatBuffers wire format.
+
+## Usage
+
+Compile a FlatBuffers schema directly:
+
+```bash
+foryc schema.fbs --lang java,python --output ./generated
+```
+
+Inspect translated schema syntax for debugging:
+
+```bash
+foryc schema.fbs --emit-fdl --emit-fdl-path ./translated
+```
+
+## Migration Notes
+
+1. Keep existing `namespace` values stable to keep type registration stable.
+2. Review fields that relied on FlatBuffers default literals and set explicit
+   defaults in application code if needed.
+3. Add `fory_ref`/`fory_weak_ref` where object-graph semantics are required.
+4. Validate generated model behavior with roundtrip tests before replacing
+   existing serialization paths.
+
+## Summary
+
+FlatBuffers input lets you reuse existing `.fbs` schemas while moving to Fory's
+runtime and code generation model. This is useful for incremental migration,
+while preserving schema investment and adopting Fory-native object APIs.
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/generated-code.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/generated-code.md
new file mode 100644
index 0000000000..b433374af1
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/generated-code.md
@@ -0,0 +1,714 @@
+---
+title: Generated Code
+sidebar_position: 5
+id: generated_code
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+This document explains generated code for each target language.
+
+Fory IDL generated types are idiomatic in host languages and can be used directly as domain objects. Generated types also include `to/from bytes` helpers and registration helpers.
+
+## Reference Schemas
+
+The examples below use two real schemas:
+
+1. `addressbook.fdl` (explicit type IDs)
+2. `auto_id.fdl` (no explicit type IDs)
+
+### `addressbook.fdl` (excerpt)
+
+```protobuf
+package addressbook;
+
+option go_package = "github.com/myorg/myrepo/gen/addressbook;addressbook";
+
+message Person [id=100] {
+    string name = 1;
+    int32 id = 2;
+
+    enum PhoneType [id=101] {
+        PHONE_TYPE_MOBILE = 0;
+        PHONE_TYPE_HOME = 1;
+        PHONE_TYPE_WORK = 2;
+    }
+
+    message PhoneNumber [id=102] {
+        string number = 1;
+        PhoneType phone_type = 2;
+    }
+
+    list<PhoneNumber> phones = 7;
+    Animal pet = 8;
+}
+
+message Dog [id=104] {
+    string name = 1;
+    int32 bark_volume = 2;
+}
+
+message Cat [id=105] {
+    string name = 1;
+    int32 lives = 2;
+}
+
+union Animal [id=106] {
+    Dog dog = 1;
+    Cat cat = 2;
+}
+
+message AddressBook [id=103] {
+    list<Person> people = 1;
+    map<string, Person> people_by_name = 2;
+}
+```
+
+### `auto_id.fdl` (excerpt)
+
+```protobuf
+package auto_id;
+
+enum Status {
+    UNKNOWN = 0;
+    OK = 1;
+}
+
+message Envelope {
+    string id = 1;
+
+    message Payload {
+        int32 value = 1;
+    }
+
+    union Detail {
+        Payload payload = 1;
+        string note = 2;
+    }
+
+    Payload payload = 2;
+    Detail detail = 3;
+    Status status = 4;
+}
+
+union Wrapper {
+    Envelope envelope = 1;
+    string raw = 2;
+}
+```
+
+## Java
+
+### Output Layout
+
+For `package addressbook`, Java output is generated under:
+
+- `<java_out>/addressbook/`
+- Type files: `AddressBook.java`, `Person.java`, `Dog.java`, `Cat.java`, `Animal.java`
+- Registration helper: `AddressbookForyRegistration.java`
+
+### Type Generation
+
+Messages generate Java classes with `@ForyField`, default constructors, getters/setters, and byte helpers:
+
+```java
+public class Person {
+    public static enum PhoneType {
+        MOBILE,
+        HOME,
+        WORK;
+    }
+
+    public static class PhoneNumber {
+        @ForyField(id = 1)
+        private String number;
+
+        @ForyField(id = 2)
+        private PhoneType phoneType;
+
+        public byte[] toBytes() { ... }
+        public static PhoneNumber fromBytes(byte[] bytes) { ... }
+    }
+
+    @ForyField(id = 1)
+    private String name;
+
+    @ForyField(id = 8)
+    private Animal pet;
+
+    public byte[] toBytes() { ... }
+    public static Person fromBytes(byte[] bytes) { ... }
+}
+```
+
+Unions generate classes extending `org.apache.fory.type.union.Union`:
+
+```java
+public final class Animal extends Union {
+    public enum AnimalCase {
+        DOG(1),
+        CAT(2);
+        public final int id;
+        AnimalCase(int id) { this.id = id; }
+    }
+
+    public static Animal ofDog(Dog v) { ... }
+    public AnimalCase getAnimalCase() { ... }
+    public int getAnimalCaseId() { ... }
+
+    public boolean hasDog() { ... }
+    public Dog getDog() { ... }
+    public void setDog(Dog v) { ... }
+}
+```
+
+### Registration
+
+Generated registration helper:
+
+```java
+public static void register(Fory fory) {
+    org.apache.fory.resolver.TypeResolver resolver = fory.getTypeResolver();
+    resolver.registerUnion(Animal.class, 106L, new org.apache.fory.serializer.UnionSerializer(fory, Animal.class));
+    resolver.register(Person.class, 100L);
+    resolver.register(Person.PhoneType.class, 101L);
+    resolver.register(Person.PhoneNumber.class, 102L);
+    resolver.register(Dog.class, 104L);
+    resolver.register(Cat.class, 105L);
+    resolver.register(AddressBook.class, 103L);
+}
+```
+
+For schemas without explicit `[id=...]`, generated registration uses computed numeric IDs (for example from `auto_id.fdl`):
+
+```java
+resolver.register(Status.class, 1124725126L);
+resolver.registerUnion(Wrapper.class, 1471345060L, new org.apache.fory.serializer.UnionSerializer(fory, Wrapper.class));
+resolver.register(Envelope.class, 3022445236L);
+resolver.registerUnion(Envelope.Detail.class, 1609214087L, new org.apache.fory.serializer.UnionSerializer(fory, Envelope.Detail.class));
+resolver.register(Envelope.Payload.class, 2862577837L);
+```
+
+If `option enable_auto_type_id = false;` is set, registration uses namespace and type name:
+
+```java
+resolver.register(Config.class, "myapp.models", "Config");
+resolver.registerUnion(
+    Holder.class,
+    "myapp.models",
+    "Holder",
+    new org.apache.fory.serializer.UnionSerializer(fory, Holder.class));
+```
+
+### Usage
+
+```java
+Person person = new Person();
+person.setName("Alice");
+person.setPet(Animal.ofDog(new Dog()));
+
+byte[] data = person.toBytes();
+Person restored = Person.fromBytes(data);
+```
+
+## Python
+
+### Output Layout
+
+Python output is one module per schema file, for example:
+
+- `<python_out>/addressbook.py`
+
+### Type Generation
+
+Unions generate a case enum plus a `Union` subclass with typed helpers:
+
+```python
+class AnimalCase(Enum):
+    DOG = 1
+    CAT = 2
+
+class Animal(Union):
+    @classmethod
+    def dog(cls, v: Dog) -> "Animal": ...
+
+    def case(self) -> AnimalCase: ...
+    def case_id(self) -> int: ...
+
+    def is_dog(self) -> bool: ...
+    def dog_value(self) -> Dog: ...
+    def set_dog(self, v: Dog) -> None: ...
+```
+
+Messages generate `@pyfory.dataclass` types, and nested types stay nested:
+
+```python
+@pyfory.dataclass
+class Person:
+    class PhoneType(IntEnum):
+        MOBILE = 0
+        HOME = 1
+        WORK = 2
+
+    @pyfory.dataclass
+    class PhoneNumber:
+        number: str = pyfory.field(id=1, default="")
+        phone_type: Person.PhoneType = pyfory.field(id=2, default=None)
+
+    name: str = pyfory.field(id=1, default="")
+    phones: List[Person.PhoneNumber] = pyfory.field(id=7, default_factory=list)
+    pet: Animal = pyfory.field(id=8, default=None)
+
+    def to_bytes(self) -> bytes: ...
+    @classmethod
+    def from_bytes(cls, data: bytes) -> "Person": ...
+```
+
+### Registration
+
+Generated registration function:
+
+```python
+def register_addressbook_types(fory: pyfory.Fory):
+    fory.register_union(Animal, type_id=106, serializer=AnimalSerializer(fory))
+    fory.register_type(Person, type_id=100)
+    fory.register_type(Person.PhoneType, type_id=101)
+    fory.register_type(Person.PhoneNumber, type_id=102)
+    fory.register_type(Dog, type_id=104)
+    fory.register_type(Cat, type_id=105)
+    fory.register_type(AddressBook, type_id=103)
+```
+
+For schemas without explicit `[id=...]`, generated registration uses computed numeric IDs:
+
+```python
+fory.register_type(Status, type_id=1124725126)
+fory.register_union(Wrapper, type_id=1471345060, serializer=WrapperSerializer(fory))
+fory.register_type(Envelope, type_id=3022445236)
+fory.register_union(Envelope.Detail, type_id=1609214087, serializer=Envelope.DetailSerializer(fory))
+fory.register_type(Envelope.Payload, type_id=2862577837)
+```
+
+If `option enable_auto_type_id = false;` is set:
+
+```python
+fory.register_type(Config, namespace="myapp.models", typename="Config")
+fory.register_union(
+    Holder,
+    namespace="myapp.models",
+    typename="Holder",
+    serializer=HolderSerializer(fory),
+)
+```
+
+### Usage
+
+```python
+person = Person(name="Alice", pet=Animal.dog(Dog(name="Rex", bark_volume=10)))
+
+data = person.to_bytes()
+restored = Person.from_bytes(data)
+```
+
+## Rust
+
+### Output Layout
+
+Rust output is one module file per schema, for example:
+
+- `<rust_out>/addressbook.rs`
+
+### Type Generation
+
+Unions map to Rust enums with `#[fory(id = ...)]` case attributes:
+
+```rust
+#[derive(ForyObject, Debug, Clone, PartialEq)]
+pub enum Animal {
+    #[fory(id = 1)]
+    Dog(Dog),
+    #[fory(id = 2)]
+    Cat(Cat),
+}
+```
+
+Nested types generate nested modules:
+
+```rust
+pub mod person {
+    #[derive(ForyObject, Debug, Clone, PartialEq, Default)]
+    #[repr(i32)]
+    pub enum PhoneType {
+        #[default]
+        Mobile = 0,
+        Home = 1,
+        Work = 2,
+    }
+
+    #[derive(ForyObject, Debug, Clone, PartialEq, Default)]
+    pub struct PhoneNumber {
+        #[fory(id = 1)]
+        pub number: String,
+        #[fory(id = 2)]
+        pub phone_type: PhoneType,
+    }
+}
+```
+
+Messages derive `ForyObject` and include `to_bytes`/`from_bytes` helpers:
+
+```rust
+#[derive(ForyObject, Debug, Clone, PartialEq, Default)]
+pub struct Person {
+    #[fory(id = 1)]
+    pub name: String,
+    #[fory(id = 7)]
+    pub phones: Vec<person::PhoneNumber>,
+    #[fory(id = 8, type_id = "union")]
+    pub pet: Animal,
+}
+```
+
+### Registration
+
+Generated registration function:
+
+```rust
+pub fn register_types(fory: &mut Fory) -> Result<(), fory::Error> {
+    fory.register_union::<Animal>(106)?;
+    fory.register::<person::PhoneType>(101)?;
+    fory.register::<person::PhoneNumber>(102)?;
+    fory.register::<Person>(100)?;
+    fory.register::<Dog>(104)?;
+    fory.register::<Cat>(105)?;
+    fory.register::<AddressBook>(103)?;
+    Ok(())
+}
+```
+
+For schemas without explicit `[id=...]`, generated registration uses computed numeric IDs:
+
+```rust
+fory.register::<Status>(1124725126)?;
+fory.register_union::<Wrapper>(1471345060)?;
+fory.register::<Envelope>(3022445236)?;
+fory.register_union::<envelope::Detail>(1609214087)?;
+fory.register::<envelope::Payload>(2862577837)?;
+```
+
+If `option enable_auto_type_id = false;` is set:
+
+```rust
+fory.register_by_namespace::<Config>("myapp.models", "Config")?;
+fory.register_union_by_namespace::<Holder>("myapp.models", "Holder")?;
+```
+
+### Usage
+
+```rust
+let person = Person {
+    name: "Alice".into(),
+    pet: Animal::Dog(Dog::default()),
+    ..Default::default()
+};
+
+let bytes = person.to_bytes()?;
+let restored = Person::from_bytes(&bytes)?;
+```
+
+## C++
+
+### Output Layout
+
+C++ output is one header per schema file, for example:
+
+- `<cpp_out>/addressbook.h`
+
+### Type Generation
+
+Messages generate `final` classes with typed accessors and byte helpers:
+
+```cpp
+class Person final {
+ public:
+  class PhoneNumber final {
+   public:
+    const std::string& number() const;
+    std::string* mutable_number();
+    template <class Arg, class... Args>
+    void set_number(Arg&& arg, Args&&... args);
+
+    fory::Result<std::vector<uint8_t>, fory::Error> to_bytes() const;
+    static fory::Result<PhoneNumber, fory::Error> from_bytes(const std::vector<uint8_t>& data);
+  };
+
+  const std::string& name() const;
+  std::string* mutable_name();
+  template <class Arg, class... Args>
+  void set_name(Arg&& arg, Args&&... args);
+
+  const Animal& pet() const;
+  Animal* mutable_pet();
+};
+```
+
+Optional message fields generate `has_xxx`, `mutable_xxx`, and `clear_xxx` APIs:
+
+```cpp
+class Envelope final {
+ public:
+  bool has_payload() const { return payload_ != nullptr; }
+  const Envelope::Payload& payload() const { return *payload_; }
+  Envelope::Payload* mutable_payload() {
+    if (!payload_) {
+      payload_ = std::make_unique<Envelope::Payload>();
+    }
+    return payload_.get();
+  }
+  void clear_payload() { payload_.reset(); }
+
+ private:
+  std::unique_ptr<Envelope::Payload> payload_;
+};
+```
+
+Unions generate `std::variant` wrappers:
+
+```cpp
+class Animal final {
+ public:
+  enum class AnimalCase : uint32_t {
+    DOG = 1,
+    CAT = 2,
+  };
+
+  static Animal dog(Dog v);
+  static Animal cat(Cat v);
+
+  AnimalCase animal_case() const noexcept;
+  uint32_t animal_case_id() const noexcept;
+
+  bool is_dog() const noexcept;
+  const Dog* as_dog() const noexcept;
+  Dog* as_dog() noexcept;
+  const Dog& dog() const;
+  Dog& dog();
+
+  template <class Visitor>
+  decltype(auto) visit(Visitor&& vis) const;
+
+ private:
+  std::variant<Dog, Cat> value_;
+};
+```
+
+Generated headers also include `FORY_UNION`, `FORY_FIELD_CONFIG`, `FORY_ENUM`, and `FORY_STRUCT` macros for serialization metadata.
+
+### Registration
+
+Generated registration function:
+
+```cpp
+inline void register_types(fory::serialization::BaseFory& fory) {
+    fory.register_union<Animal>(106);
+    fory.register_enum<Person::PhoneType>(101);
+    fory.register_struct<Person::PhoneNumber>(102);
+    fory.register_struct<Person>(100);
+    fory.register_struct<Dog>(104);
+    fory.register_struct<Cat>(105);
+    fory.register_struct<AddressBook>(103);
+}
+```
+
+For schemas without explicit `[id=...]`, generated registration uses computed numeric IDs:
+
+```cpp
+fory.register_enum<Status>(1124725126);
+fory.register_union<Wrapper>(1471345060);
+fory.register_struct<Envelope>(3022445236);
+fory.register_union<Envelope::Detail>(1609214087);
+fory.register_struct<Envelope::Payload>(2862577837);
+```
+
+If `option enable_auto_type_id = false;` is set:
+
+```cpp
+fory.register_struct<Config>("myapp.models", "Config");
+fory.register_union<Holder>("myapp.models", "Holder");
+```
+
+### Usage
+
+```cpp
+addressbook::Person person;
+person.set_name("Alice");
+*person.mutable_pet() = addressbook::Animal::dog(addressbook::Dog{});
+
+auto bytes = person.to_bytes();
+auto restored = addressbook::Person::from_bytes(bytes.value());
+```
+
+## Go
+
+### Output Layout
+
+Go output path depends on schema options and `--go_out`.
+
+For `addressbook.fdl`, `go_package` is configured and generated output follows the configured import path/package (for example under your `--go_out` root).
+
+Without `go_package`, output uses the requested `--go_out` directory and package-derived file naming.
+
+### Type Generation
+
+Nested types use underscore naming by default (`Person_PhoneType`, `Person_PhoneNumber`):
+
+```go
+type Person_PhoneType int32
+
+const (
+    Person_PhoneTypeMobile Person_PhoneType = 0
+    Person_PhoneTypeHome   Person_PhoneType = 1
+    Person_PhoneTypeWork   Person_PhoneType = 2
+)
+
+type Person_PhoneNumber struct {
+    Number    string           `fory:"id=1"`
+    PhoneType Person_PhoneType `fory:"id=2"`
+}
+```
+
+Messages generate structs with `fory` tags and byte helpers:
+
+```go
+type Person struct {
+    Name   string               `fory:"id=1"`
+    Id     int32                `fory:"id=2,compress=true"`
+    Phones []Person_PhoneNumber `fory:"id=7"`
+    Pet    Animal               `fory:"id=8"`
+}
+
+func (m *Person) ToBytes() ([]byte, error) { ... }
+func (m *Person) FromBytes(data []byte) error { ... }
+```
+
+Unions generate typed case structs with constructors/accessors/visitor APIs:
+
+```go
+type AnimalCase uint32
+
+type Animal struct {
+    case_ AnimalCase
+    value any
+}
+
+func DogAnimal(v *Dog) Animal { ... }
+func CatAnimal(v *Cat) Animal { ... }
+
+func (u Animal) Case() AnimalCase { ... }
+func (u Animal) AsDog() (*Dog, bool) { ... }
+func (u Animal) Visit(visitor AnimalVisitor) error { ... }
+```
+
+### Registration
+
+Generated registration function:
+
+```go
+func RegisterTypes(f *fory.Fory) error {
+    if err := f.RegisterUnion(Animal{}, 106, fory.NewUnionSerializer(...)); err != nil {
+        return err
+    }
+    if err := f.RegisterEnum(Person_PhoneType(0), 101); err != nil {
+        return err
+    }
+    if err := f.RegisterStruct(Person_PhoneNumber{}, 102); err != nil {
+        return err
+    }
+    if err := f.RegisterStruct(Person{}, 100); err != nil {
+        return err
+    }
+    return nil
+}
+```
+
+For schemas without explicit `[id=...]`, generated registration uses computed numeric IDs:
+
+```go
+if err := f.RegisterEnum(Status(0), 1124725126); err != nil { ... }
+if err := f.RegisterUnion(Wrapper{}, 1471345060, fory.NewUnionSerializer(...)); err != nil { ... }
+if err := f.RegisterStruct(Envelope{}, 3022445236); err != nil { ... }
+if err := f.RegisterUnion(Envelope_Detail{}, 1609214087, fory.NewUnionSerializer(...)); err != nil { ... }
+if err := f.RegisterStruct(Envelope_Payload{}, 2862577837); err != nil { ... }
+```
+
+If `option enable_auto_type_id = false;` is set:
+
+```go
+if err := f.RegisterNamedStruct(Config{}, "myapp.models.Config"); err != nil { ... }
+if err := f.RegisterNamedUnion(Holder{}, "myapp.models.Holder", fory.NewUnionSerializer(...)); err != nil { ... }
+```
+
+`go_nested_type_style` controls nested type naming:
+
+```protobuf
+option go_nested_type_style = "camelcase";
+```
+
+### Usage
+
+```go
+person := &Person{
+    Name: "Alice",
+    Pet:  DogAnimal(&Dog{Name: "Rex"}),
+}
+
+data, err := person.ToBytes()
+if err != nil {
+    panic(err)
+}
+var restored Person
+if err := restored.FromBytes(data); err != nil {
+    panic(err)
+}
+```
+
+## Cross-Language Notes
+
+### Type ID Behavior
+
+- Explicit `[id=...]` values are used directly in generated registration.
+- When type IDs are omitted, generated code uses computed numeric IDs (see `auto_id.*` outputs).
+- If `option enable_auto_type_id = false;` is set, generated registration uses namespace/type-name APIs instead of numeric IDs.
+
+### Nested Type Shape
+
+| Language | Nested type form               |
+| -------- | ------------------------------ |
+| Java     | `Person.PhoneNumber`           |
+| Python   | `Person.PhoneNumber`           |
+| Rust     | `person::PhoneNumber`          |
+| C++      | `Person::PhoneNumber`          |
+| Go       | `Person_PhoneNumber` (default) |
+
+### Byte Helper Naming
+
+| Language | Helpers                   |
+| -------- | ------------------------- |
+| Java     | `toBytes` / `fromBytes`   |
+| Python   | `to_bytes` / `from_bytes` |
+| Rust     | `to_bytes` / `from_bytes` |
+| C++      | `to_bytes` / `from_bytes` |
+| Go       | `ToBytes` / `FromBytes`   |
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/grpc-service-design.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/grpc-service-design.md
new file mode 100644
index 0000000000..b1f1883d64
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/grpc-service-design.md
@@ -0,0 +1,219 @@
+---
+title: gRPC Service IDL Design
+sidebar_position: 8
+id: grpc_service_design
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+# gRPC Service IDL Design
+
+## Thoughts and Constraints
+
+- Fory generates native language types for Fory IDL/proto/fbs, not protobuf/flatbuffers runtime types.
+  This makes standard gRPC stubs (which expect protobuf or flatbuffers runtime classes) incompatible
+  with Fory-generated types by default.
+- We should keep the Fory runtime dependency-free from gRPC. Any gRPC integration must be
+  generated code or optional helper files emitted by the compiler.
+- We need to support service definitions in Fory IDL, protobuf, and FlatBuffers, and generate gRPC
+  stubs for Java/Python/Rust/Go/C++.
+
+The design below uses a "service IR" that can be rendered into gRPC stubs in each language,
+with a single serialization strategy (Fory) to keep the system simple and dependency-light.
+
+## Goals
+
+- Add `service` definitions to Fory IDL with protobuf-like syntax.
+- Parse protobuf `service` and FlatBuffers `rpc_service` blocks.
+- Extend the compiler IR with service/method definitions.
+- Generate gRPC stubs for Java/Python/Rust/Go/C++ without adding gRPC runtime deps to Fory.
+- Preserve performance: avoid per-call reflection and minimize allocations in codecs.
+
+## Non-Goals
+
+- Implement a gRPC runtime inside Fory.
+- Provide full interoperability with standard protobuf/flatbuffers gRPC without explicit opt-in.
+- Change core Fory serialization formats or protocol specs.
+
+## IDL Additions
+
+### Fory IDL Service Syntax
+
+Fory IDL service syntax mirrors protobuf:
+
+```protobuf
+service Greeter {
+  rpc SayHello (HelloRequest) returns (HelloReply);
+  rpc LotsOfReplies (HelloRequest) returns (stream HelloReply);
+  rpc LotsOfGreetings (stream HelloRequest) returns (HelloReply);
+  rpc BidiHello (stream HelloRequest) returns (stream HelloReply);
+}
+```
+
+Notes:
+
+- `stream` is supported on request/response for gRPC streaming.
+- Service and method-level `option` blocks are allowed and stored as raw key/value pairs.
+- Service methods must reference message types (not enums or unions).
+
+### Protobuf Service Support
+
+Parse `service` and `rpc` definitions (including `stream`) into proto AST nodes, then
+translate into the shared service IR. Preserve options for round-tripping and future use.
+
+### FlatBuffers `rpc_service` Support
+
+Parse `rpc_service` blocks into the service IR. FlatBuffers methods are mapped to
+unary RPC by default; streaming is a follow-up if FlatBuffers gRPC spec supports it.
+
+## IR Changes
+
+Add new nodes in `compiler/fory_compiler/ir/ast.py`:
+
+```python
+@dataclass
+class RpcMethod:
+    name: str
+    request_type: NamedType
+    response_type: NamedType
+    client_streaming: bool = False
+    server_streaming: bool = False
+    options: dict = field(default_factory=dict)
+    line: int = 0
+    column: int = 0
+    location: Optional[SourceLocation] = None
+
+@dataclass
+class Service:
+    name: str
+    methods: List[RpcMethod] = field(default_factory=list)
+    options: dict = field(default_factory=dict)
+    line: int = 0
+    column: int = 0
+    location: Optional[SourceLocation] = None
+```
+
+Extend `Schema` with `services: List[Service]`.
+
+## Frontend Updates
+
+- Fory IDL lexer/parser: add keywords `service`, `rpc`, `returns`, `stream`.
+- Proto parser: replace the current "skip service block" logic with full parsing.
+- FlatBuffers parser: add `rpc_service` parsing and AST nodes.
+- Translators: map format-specific AST into the shared IR.
+
+## Validation Rules
+
+- Service names must be unique per schema.
+- Method names must be unique per service.
+- Request/response types must resolve to message types (not enums/unions).
+- Streaming flags are only allowed on request/response types.
+- FlatBuffers: enforce request/response are tables (or document the accepted type set).
+
+## Serialization Strategy (Only Fory)
+
+- gRPC always uses a custom codec that serializes request/response with Fory.
+- Works with Fory-generated native types across languages.
+- Not wire-compatible with standard protobuf-based gRPC clients.
+- No external protoc/flatc invocation and no extra runtime dependencies in Fory.
+
+## Codegen Architecture
+
+### Compiler Options
+
+New CLI options:
+
+- `--grpc`: enable gRPC stub generation.
+- `--grpc-backend=<lang-specific>`:
+  - Rust: `tonic` (default), future `grpcio`.
+  - C++: `grpc++`.
+  - Java: `grpc-java`.
+  - Go: `grpc-go`.
+  - Python: `grpcio`.
+
+### Generator Integration
+
+- Add a `generate_services()` hook to each language generator.
+- Emit service stubs into a separate file group (for easy optional compilation).
+- If `--grpc` is not set, only emit pure service interfaces (no gRPC deps).
+
+### File Layout (Proposed)
+
+- Java: `*Service.java` for pure interface, `*Grpc.java` for gRPC bindings.
+- Python: `*_service.py` for interface, `*_grpc.py` for gRPC bindings.
+- Go: `*_service.go` for interface, `*_grpc.go` for gRPC bindings.
+- Rust: `service.rs` module and `service_grpc.rs` with gRPC bindings (feature-gated).
+- C++: `service.h` and `service.grpc.h/.cc`.
+
+## Language-Specific gRPC Generation (High Level)
+
+- Java: generate `Grpc` class with `MethodDescriptor`s, server binder, and client stubs.
+  For `fory` serialization, emit a `Marshaller` using Fory encoders/decoders.
+- Python: generate `Servicer` base class and `Stub` class using `grpc` unary/stream APIs.
+  For `fory` serialization, pass serializer/deserializer callables.
+- Go: generate `ServiceDesc`, server interface, and client wrapper. For `fory`, register
+  a custom codec and use it in `grpc.CallOption`.
+- Rust: use `tonic` with a custom codec for `fory`. For protobuf mode, emit standard
+  `tonic` service traits and clients.
+- C++: generate abstract service and stub classes. For `fory`, use gRPC custom
+  serialization hooks to map between Fory types and byte streams.
+
+## Compatibility and Interop
+
+- Fory gRPC is cross-language compatible within Fory, but not compatible with
+  standard protobuf-based gRPC clients.
+
+## Testing Plan
+
+- Parser tests for Fory IDL/proto/fbs service syntax.
+- IR validation tests for method/type resolution and streaming rules.
+- Golden codegen tests that verify gRPC output file names and key signatures.
+- Cross-language smoke tests (optional): gRPC request/response with `fory` codec.
+
+## Decisions
+
+1. FlatBuffers `rpc_service` supports both table and struct types.
+2. gRPC codegen runs only when `--grpc` is enabled.
+3. Rust backend uses `tonic`.
+4. Ship small, generated helper files instead of a separate `fory-grpc` module.
+
+## Expected Codegen Footprint
+
+The compiler will generate a small, predictable set of service files. The exact line
+count scales with the number of RPC methods and whether streaming is used.
+
+### Files per service (per language)
+
+- Java: 2 files (`*Service.java`, `*Grpc.java`)
+- Python: 2 files (`*_service.py`, `*_grpc.py`)
+- Go: 2 files (`*_service.go`, `*_grpc.go`)
+- Rust: 2 files (`service.rs`, `service_grpc.rs`)
+- C++: 3 files (`service.h`, `service.grpc.h`, `service.grpc.cc`)
+
+### Rough size estimate
+
+Each service generates:
+
+- One interface/trait file: roughly 10-20 lines per method.
+- One gRPC binding file: roughly 25-50 lines per method plus a fixed header (about 80-200 lines).
+
+So a service with `M` methods typically adds:
+
+- Java/Python/Go/Rust: about `~(100-200) + (35-70)*M` lines across 2 files.
+- C++: about `~(150-250) + (45-90)*M` lines across 3 files.
+
+These numbers are intentionally conservative; the final output depends on the exact
+backend template we implement.
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/index.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/index.md
new file mode 100644
index 0000000000..0038018790
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/index.md
@@ -0,0 +1,213 @@
+---
+title: Overview
+sidebar_position: 1
+id: index
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+Fory IDL is a schema definition language for Apache Fory that enables type-safe
+cross-language serialization. Define your data structures once and generate
+native data structure code for Java, Python, Go, Rust, and C++.
+
+## Example Schema
+
+Fory IDL provides a simple, intuitive syntax for defining cross-language data structures:
+
+```protobuf
+package example;
+
+enum Status {
+    PENDING = 0;
+    ACTIVE = 1;
+    COMPLETED = 2;
+}
+
+message User {
+    string name = 1;
+    int32 age = 2;
+    optional string email = 3;
+    list<string> tags = 4;
+}
+
+message Item {
+    string sku = 1;
+    int32 quantity = 2;
+}
+
+message Order {
+    ref User customer = 1;
+    list<Item> items = 2;
+    Status status = 3;
+    map<string, int32> metadata = 4;
+}
+
+message Dog [id=104] {
+    string name = 1;
+    int32 bark_volume = 2;
+}
+
+message Cat [id=105] {
+    string name = 1;
+    int32 lives = 2;
+}
+
+union Animal [id=106] {
+    Dog dog = 1;
+    Cat cat = 2;
+}
+```
+
+## Why Fory IDL?
+
+### Schema-First Development
+
+Define your data model once in Fory IDL and generate consistent, type-safe code across all languages. This ensures:
+
+- **Type Safety**: Catch type errors at compile time, not runtime
+- **Consistency**: All languages use the same field names, types, and structures
+- **Documentation**: Schema serves as living documentation
+- **Evolution**: Managed schema changes across all implementations
+
+### Fory-Native Features
+
+Unlike generic IDLs, Fory IDL is designed specifically for Fory serialization:
+
+- **Reference Tracking**: First-class support for shared and circular references via `ref`
+- **Nullable Fields**: Explicit `optional` modifier for nullable types
+- **Type Registration**: Built-in support for both numeric IDs and namespace-based registration
+- **Native Code Generation**: Generates idiomatic code with Fory annotations/macros
+
+### Low Integration Overhead
+
+Generated code uses native language constructs:
+
+- Java: Plain POJOs with `@ForyField` annotations
+- Python: Dataclasses with type hints
+- Go: Structs with struct tags
+- Rust: Structs with `#[derive(ForyObject)]`
+- C++: Structs with `FORY_STRUCT` macros
+
+## Quick Start
+
+### 1. Install the Compiler
+
+```bash
+pip install fory-compiler
+```
+
+Or install from source:
+
+```bash
+cd compiler
+pip install -e .
+```
+
+### 2. Write Your Schema
+
+Create `example.fdl`:
+
+```protobuf
+package example;
+
+message Person {
+    string name = 1;
+    int32 age = 2;
+    optional string email = 3;
+}
+```
+
+### 3. Generate Code
+
+```bash
+# Generate for all languages
+foryc example.fdl --output ./generated
+
+# Generate for specific languages
+foryc example.fdl --lang java,python --output ./generated
+```
+
+### 4. Use Generated Code
+
+**Java:**
+
+```java
+Person person = new Person();
+person.setName("Alice");
+person.setAge(30);
+byte[] data = person.toBytes();
+```
+
+**Python:**
+
+```python
+import pyfory
+from example import Person
+
+person = Person(name="Alice", age=30)
+data = bytes(person) # or `person.to_bytes()`
+```
+
+## Documentation
+
+| Document                                        | Description                                       |
+| ----------------------------------------------- | ------------------------------------------------- |
+| [Fory IDL Syntax](schema-idl.md)                | Complete language syntax and grammar              |
+| [Type System](schema-idl.md#type-system)        | Primitive types, collections, and type rules      |
+| [Compiler Guide](compiler-guide.md)             | CLI options and build integration                 |
+| [Generated Code](generated-code.md)             | Output format for each target language            |
+| [Protocol Buffers IDL Support](protobuf-idl.md) | Comparison with protobuf and migration guide      |
+| [FlatBuffers IDL Support](flatbuffers-idl.md)   | FlatBuffers mapping rules and codegen differences |
+
+## Key Concepts
+
+### Field Modifiers
+
+- **`optional`**: Field can be null/None
+- **`ref`**: Enable reference tracking for shared/circular references
+- **`list`**: Field is a list/array (alias: `repeated`)
+
+```protobuf
+message Example {
+    optional string nullable = 1;
+    ref Node parent = 2;
+    list<int32> numbers = 3;
+}
+```
+
+### Cross-Language Compatibility
+
+Fory IDL types map to native types in each language:
+
+| Fory IDL Type | Java      | Python         | Go       | Rust     | C++           |
+| ------------- | --------- | -------------- | -------- | -------- | ------------- |
+| `int32`       | `int`     | `pyfory.int32` | `int32`  | `i32`    | `int32_t`     |
+| `string`      | `String`  | `str`          | `string` | `String` | `std::string` |
+| `bool`        | `boolean` | `bool`         | `bool`   | `bool`   | `bool`        |
+
+See [Type System](schema-idl.md#type-system) for complete mappings.
+
+## Best Practices
+
+1. **Use meaningful package names**: Group related types together
+2. **Assign type IDs for performance**: Numeric IDs are faster than name-based registration
+3. **Reserve ID ranges**: Leave gaps for future additions (e.g., 100-199 for users, 200-299 for orders)
+4. **Use `optional` explicitly**: Make nullability clear in the schema
+5. **Use `ref` for shared objects**: Enable reference tracking when objects are shared
+
+## Examples
+
+See the [examples](https://github.com/apache/fory/tree/main/compiler/examples) directory for complete working examples.
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/protobuf-idl.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/protobuf-idl.md
new file mode 100644
index 0000000000..8292a00f5e
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/protobuf-idl.md
@@ -0,0 +1,335 @@
+---
+title: Protobuf IDL Support
+sidebar_position: 10
+id: protobuf_idl_support
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+This page explains how Apache Fory works with Protocol Buffers (`.proto`) schemas,
+how protobuf concepts map to Fory, and how to use protobuf-only Fory extension options.
+
+## What This Page Covers
+
+- Choosing protobuf vs Fory for your use case
+- Syntax and semantic differences that matter during migration
+- Supported Fory extension options in protobuf files
+- Practical migration patterns from protobuf to Fory
+
+## Quick Decision Guide
+
+| Situation                                                     | Recommended Format |
+| ------------------------------------------------------------- | ------------------ |
+| You are building gRPC APIs and rely on protobuf tooling       | Protocol Buffers   |
+| You need maximum object-graph performance and ref tracking    | Fory               |
+| You need circular/shared references in serialized data        | Fory               |
+| You need strong unknown-field behavior for wire compatibility | Protocol Buffers   |
+| You need native structs/classes instead of protobuf wrappers  | Fory               |
+
+## Protobuf vs Fory at a Glance
+
+| Aspect             | Protocol Buffers              | Fory                                  |
+| ------------------ | ----------------------------- | ------------------------------------- |
+| Primary purpose    | RPC/message contracts         | High-performance object serialization |
+| Encoding model     | Tag-length-value              | Fory binary protocol                  |
+| Reference tracking | Not built-in                  | First-class (`ref`)                   |
+| Circular refs      | Not supported                 | Supported                             |
+| Unknown fields     | Preserved                     | Not preserved                         |
+| Generated types    | Protobuf-specific model types | Native language constructs            |
+| gRPC ecosystem     | Native                        | In progress (active development)      |
+
+Fory gRPC support is under active development. For production gRPC
+workflows today, protobuf remains the mature/default choice.
+
+## Why Use Apache Fory
+
+- Idiomatic generated code: Fory IDL generates language-idiomatic classes and
+  structs that can be used directly as domain objects.
+- Faster serialization: In Fory benchmarks, Fory can be around 10x faster than
+  protobuf for object serialization workloads.
+- Better graph modeling: Shared and circular references are first-class features
+  instead of application-level ID-link workarounds.
+
+See benchmark details under [Performance References](#performance-references).
+
+## Syntax and Semantic Mapping
+
+### Package and File Options
+
+**Protocol Buffers**
+
+```protobuf
+syntax = "proto3";
+package example.models;
+option java_package = "com.example.models";
+option go_package = "example.com/models";
+```
+
+**Fory**
+
+```protobuf
+package example.models;
+```
+
+Fory uses one package namespace for cross-language registration. Language-specific
+package placement is still configurable in code generation.
+
+### Message and Enum Definitions
+
+**Protocol Buffers**
+
+```protobuf
+message User {
+  string id = 1;
+  string name = 2;
+  optional string email = 3;
+  int32 age = 4;
+  repeated string tags = 5;
+  map<string, string> metadata = 6;
+}
+
+enum Status {
+  STATUS_UNSPECIFIED = 0;
+  STATUS_ACTIVE = 1;
+}
+```
+
+**Fory**
+
+```protobuf
+message User [id=101] {
+    string id = 1;
+    string name = 2;
+    optional string email = 3;
+    int32 age = 4;
+    list<string> tags = 5;
+    map<string, string> metadata = 6;
+}
+
+enum Status [id=102] {
+    UNKNOWN = 0;
+    ACTIVE = 1;
+}
+```
+
+Key differences:
+
+- Fory can assign stable type IDs directly (`[id=...]`).
+- Fory uses `list<T>` (with `repeated T` as alias).
+- Enum naming conventions are language-driven instead of protobuf prefix style.
+
+### `oneof` to `union`
+
+Protobuf `oneof` is translated to a nested Fory `union` plus an optional field
+referencing that union.
+
+**Protocol Buffers**
+
+```protobuf
+message Event {
+  oneof payload {
+    string text = 1;
+    int32 number = 2;
+  }
+}
+```
+
+**Fory-style shape after translation**
+
+```protobuf
+message Event {
+    union payload {
+        string text = 1;
+        int32 number = 2;
+    }
+    optional payload payload = 1;
+}
+```
+
+Notes:
+
+- Union case IDs are derived from the original `oneof` field numbers.
+- The synthetic union field uses the smallest `oneof` case number.
+
+### Imports and Well-Known Types
+
+Protobuf imports are supported. Common well-known types map directly:
+
+- `google.protobuf.Timestamp` -> `timestamp`
+- `google.protobuf.Duration` -> `duration`
+- `google.protobuf.Any` -> `any`
+
+## Type Mapping Highlights
+
+| Protobuf Type                            | Fory Mapping                             |
+| ---------------------------------------- | ---------------------------------------- |
+| `bool`                                   | `bool`                                   |
+| `int32`, `uint32`                        | variable-length 32-bit integer kinds     |
+| `sint32`                                 | zigzag 32-bit integer                    |
+| `int64`, `uint64`                        | variable-length 64-bit integer kinds     |
+| `sint64`                                 | zigzag 64-bit integer                    |
+| `fixed32`, `fixed64`                     | fixed-width unsigned integer kinds       |
+| `sfixed32`, `sfixed64`                   | fixed-width signed integer kinds         |
+| `float`, `double`                        | `float32`, `float64`                     |
+| `string`, `bytes`                        | `string`, `bytes`                        |
+| `repeated T`                             | `list<T>`                                |
+| `map<K, V>`                              | `map<K, V>`                              |
+| `optional T`                             | `optional T`                             |
+| `oneof`                                  | `union` + optional union reference field |
+| `int64 [(fory).type = "tagged_int64"]`   | `tagged_int64` encoding                  |
+| `uint64 [(fory).type = "tagged_uint64"]` | `tagged_uint64` encoding                 |
+
+## Fory Extension Options (Protobuf)
+
+Fory-specific options in `.proto` use the `(fory).` prefix.
+
+```protobuf
+option (fory).enable_auto_type_id = true;
+
+message TreeNode {
+  TreeNode parent = 1 [(fory).weak_ref = true];
+  repeated TreeNode children = 2 [(fory).ref = true];
+}
+```
+
+### File-Level Options
+
+| Option                               | Type   | Description                                                    |
+| ------------------------------------ | ------ | -------------------------------------------------------------- |
+| `(fory).use_record_for_java_message` | bool   | Generate Java records for all messages in this file            |
+| `(fory).polymorphism`                | bool   | Enable polymorphic serialization metadata by default           |
+| `(fory).enable_auto_type_id`         | bool   | Auto-generate type IDs when omitted (compiler default is true) |
+| `(fory).evolving`                    | bool   | Default schema-evolution behavior for messages                 |
+| `(fory).go_nested_type_style`        | string | Go nested naming style: `underscore` (default) or `camelcase`  |
+
+### Message and Enum Options
+
+| Option                       | Applies To    | Type   | Description                              |
+| ---------------------------- | ------------- | ------ | ---------------------------------------- |
+| `(fory).id`                  | message, enum | int    | Explicit type ID for registration        |
+| `(fory).alias`               | message, enum | string | Alternate name used for auto-ID hashing  |
+| `(fory).evolving`            | message       | bool   | Override file-level evolution setting    |
+| `(fory).use_record_for_java` | message       | bool   | Generate Java record for this message    |
+| `(fory).deprecated`          | message, enum | bool   | Mark type as deprecated                  |
+| `(fory).namespace`           | message       | string | Override default package-based namespace |
+
+### Field-Level Options
+
+| Option                       | Type   | Description                                                  |
+| ---------------------------- | ------ | ------------------------------------------------------------ |
+| `(fory).ref`                 | bool   | Enable reference tracking for this field                     |
+| `(fory).nullable`            | bool   | Treat field as nullable (`optional`)                         |
+| `(fory).weak_ref`            | bool   | Generate weak pointer semantics (C++/Rust codegen)           |
+| `(fory).thread_safe_pointer` | bool   | Rust pointer flavor for ref fields (`Arc` vs `Rc`)           |
+| `(fory).deprecated`          | bool   | Mark field as deprecated                                     |
+| `(fory).type`                | string | Primitive override, currently `tagged_int64`/`tagged_uint64` |
+
+Reference option behavior:
+
+- `weak_ref = true` implies ref tracking.
+- For `repeated` fields, `(fory).ref = true` applies to list elements.
+- For `map<K, V>` fields, `(fory).ref = true` applies to map values.
+- `weak_ref` and `thread_safe_pointer` are codegen hints for C++/Rust.
+
+### Option Examples by Shape
+
+```protobuf
+message Graph {
+  Node root = 1 [(fory).ref = true, (fory).thread_safe_pointer = false];
+  repeated Node nodes = 2 [(fory).ref = true];
+  map<string, Node> cache = 3 [(fory).ref = true];
+  Node parent = 4 [(fory).weak_ref = true];
+}
+```
+
+## Reference Tracking vs Protobuf IDs
+
+Protobuf itself does not preserve shared/cyclic object graphs. With Fory
+protobuf extensions, you can opt into graph semantics.
+
+**Without Fory ref options (protobuf-style IDs):**
+
+```protobuf
+message TreeNode {
+  string id = 1;
+  string parent_id = 2;
+  repeated string child_ids = 3;
+}
+```
+
+**With Fory ref options (object graph):**
+
+```protobuf
+message TreeNode {
+  TreeNode parent = 1 [(fory).weak_ref = true];
+  repeated TreeNode children = 2 [(fory).ref = true];
+}
+```
+
+## Migration Guide: Protobuf to Fory
+
+### Step 1: Translate Schema Syntax
+
+- Keep package names stable.
+- Replace `repeated T` with `list<T>` (or keep `repeated` alias).
+- Add explicit `[id=...]` where you need stable numeric registration.
+
+### Step 2: Convert `oneof` and Special Types
+
+- `oneof` -> `union` + optional union field.
+- Map protobuf well-known types to Fory primitives (`timestamp`, `duration`, `any`).
+
+### Step 3: Replace Protobuf Workarounds with `ref`
+
+Where protobuf used manual ID links for object graphs, switch to Fory `ref`
+modifiers (and optional `ref(weak=true)` where needed).
+
+### Step 4: Update Build/Codegen
+
+Replace protobuf generation steps with the Fory compiler invocation for target
+languages.
+
+### Step 5: Run Compatibility Checks
+
+For staged migrations, keep both formats in parallel and verify payload-level
+parity with integration tests.
+
+## Coexistence Strategy
+
+You can run protobuf and Fory in parallel during migration:
+
+```java
+public byte[] serialize(Object obj, Format format) {
+    if (format == Format.PROTOBUF) {
+        return ((MessageLite) obj).toByteArray();
+    }
+    return fory.serialize(obj);
+}
+```
+
+Use translators at service boundaries while internal object-graph heavy paths
+migrate first.
+
+## Performance References
+
+- Benchmarks: https://fory.apache.org/docs/introduction/benchmark
+- Benchmark code: https://github.com/apache/fory/tree/main/benchmarks
+
+## Summary
+
+Use protobuf when your primary concern is API contracts and gRPC ecosystem
+integration. Use Fory when object-graph performance, native models, and
+reference semantics are the primary concern.
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/schema-idl.md b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/schema-idl.md
new file mode 100644
index 0000000000..4e297aa770
--- /dev/null
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-0.15/compiler/schema-idl.md
@@ -0,0 +1,1398 @@
+---
+title: Schema IDL
+sidebar_position: 2
+id: syntax
+license: |
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+---
+
+This document provides the syntax and semantic reference for Fory IDL.
+
+For compiler usage and build integration, see
+[Compiler Guide](compiler-guide.md). For protobuf/FlatBuffers frontend mapping
+rules, see [Protocol Buffers IDL Support](protobuf-idl.md) and
+[FlatBuffers IDL Support](flatbuffers-idl.md).
+
+## File Structure
+
+An Fory IDL file typically consists of:
+
+1. Optional package declaration
+2. Optional file-level options
+3. Optional import statements
+4. Type definitions (enums, messages, and unions)
+
+```protobuf
+// Optional package declaration
+package com.example.models;
+
+// Optional file-level options
+option java_package = "com.example.models";
+
+// Import statements
+import "common/types.fdl";
+
+// Type definitions
+enum Color [id=100] { ... }
+message User [id=101] { ... }
+message Order [id=102] { ... }
+union Event [id=103] { ... }
+```
+
+## Comments
+
+Fory IDL supports both single-line and block comments:
+
+```protobuf
+// This is a single-line comment
+
+/*
+ * This is a block comment
+ * that spans multiple lines
+ */
+
+message Example {
+    string name = 1;  // Inline comment
+}
+```
+
+## Package Declaration
+
+The package declaration defines the namespace for all types in the file.
+
+```protobuf
+package com.example.models;
+```
+
+You can optionally specify a package alias used for auto-generated type IDs:
+
+```protobuf
+package com.example.models alias models_v1;
+```
+
+**Rules:**
+
+- Optional but recommended
+- Must appear before any type definitions
+- Only one package declaration per file
+- Used for namespace-based type registration
+- Package alias is used for auto-ID hashing
+
+**Language Mapping:**
+
+| Language | Package Usage                     |
+| -------- | --------------------------------- |
+| Java     | Java package                      |
+| Python   | Module name (dots to underscores) |
+| Go       | Package name (last component)     |
+| Rust     | Module name (dots to underscores) |
+| C++      | Namespace (dots to `::`)          |
+
+## File-Level Options
+
+Options can be specified at file level to control language-specific code generation.
+
+### Syntax
+
+```protobuf
+option option_name = value;
+```
+
+### Java Package Option
+
+Override the Java package for generated code:
+
+```protobuf
+package payment;
+option java_package = "com.mycorp.payment.v1";
+
+message Payment {
+    string id = 1;
+}
+```
+
+**Effect:**
+
+- Generated Java files will be in `com/mycorp/payment/v1/` directory
+- Java package declaration will be `package com.mycorp.payment.v1;`
+- Type registration still uses the Fory IDL package (`payment`) for cross-language compatibility
+
+### Go Package Option
+
+Specify the Go import path and package name:
+
+```protobuf
+package payment;
+option go_package = "github.com/mycorp/apis/gen/payment/v1;paymentv1";
+
+message Payment {
+    string id = 1;
+}
+```
+
+**Format:** `"import/path;package_name"` or just `"import/path"` (last segment used as package name)
+
+**Effect:**
+
+- Generated Go files will have `package paymentv1`
+- The import path can be used in other Go code
+- Type registration still uses the Fory IDL package (`payment`) for cross-language compatibility
+
+### Java Outer Classname Option
+
+Generate all types as inner classes of a single outer wrapper class:
+
+```protobuf
+package payment;
+option java_outer_classname = "DescriptorProtos";
+
+enum Status {
+    UNKNOWN = 0;
+    ACTIVE = 1;
+}
+
+message Payment {
+    string id = 1;
+    Status status = 2;
+}
+```
+
+**Effect:**
+
+- Generates a single file `DescriptorProtos.java` instead of separate files
+- All enums and messages become `public static` inner classes
+- The outer class is `public final` with a private constructor
+- Useful for grouping related types together
+
+**Generated structure:**
+
+```java
+public final class DescriptorProtos {
+    private DescriptorProtos() {}
+
+    public static enum Status {
+        UNKNOWN,
+        ACTIVE;
+    }
+
+    public static class Payment {
+        private String id;
+        private Status status;
+        // ...
+    }
+}
+```
+
+**Combined with java_package:**
+
+```protobuf
+package payment;
+option java_package = "com.example.proto";
+option java_outer_classname = "PaymentProtos";
+
+message Payment {
+    string id = 1;
+}
+```
+
+This generates `com/example/proto/PaymentProtos.java` with all types as inner classes.
+
+### Java Multiple Files Option
+
+Control whether types are generated in separate files or as inner classes:
+
+```protobuf
+package payment;
+option java_outer_classname = "PaymentProtos";
+option java_multiple_files = true;
+
+message Payment {
+    string id = 1;
+}
+
+message Receipt {
+    string id = 1;
+}
+```
+
+**Behavior:**
+
+| `java_outer_classname` | `java_multiple_files` | Result                                      |
+| ---------------------- | --------------------- | ------------------------------------------- |
+| Not set                | Any                   | Separate files (one per type)               |
+| Set                    | `false` (default)     | Single file with all types as inner classes |
+| Set                    | `true`                | Separate files (overrides outer class)      |
+
+**Effect of `java_multiple_files = true`:**
+
+- Each top-level enum and message gets its own `.java` file
+- Overrides `java_outer_classname` behavior
+- Useful when you want separate files but still specify an outer class name for other purposes
+
+**Example without java_multiple_files (default):**
+
+```protobuf
+option java_outer_classname = "PaymentProtos";
+// Generates: PaymentProtos.java containing Payment and Receipt as inner classes
+```
+
+**Example with java_multiple_files = true:**
+
+```protobuf
+option java_outer_classname = "PaymentProtos";
+option java_multiple_files = true;
+// Generates: Payment.java, Receipt.java (separate files)
+```
+
+### Multiple Options
+
+Multiple options can be specified:
+
+```protobuf
+package payment;
+option java_package = "com.mycorp.payment.v1";
+option go_package = "github.com/mycorp/apis/gen/payment/v1;paymentv1";
+option deprecated = true;
+
+message Payment {
+    string id = 1;
+}
+```
+
+### Protobuf Extension Syntax
+
+In `.fdl` files, use native Fory IDL syntax only (for example, `[id=100]`, `ref`,
+`optional`, `nullable=true`).
+
+Protobuf extension syntax with `(fory).` is for `.proto` files and the protobuf
+frontend only.
+
+For protobuf extension options, see
+[Protocol Buffers IDL Support](protobuf-idl.md#fory-extension-options-protobuf).
+
+### Option Priority
+
+For language-specific packages:
+
+1. Command-line package override (highest priority)
+2. Language-specific option (`java_package`, `go_package`)
+3. Fory IDL package declaration (fallback)
+
+**Example:**
+
+```protobuf
+package myapp.models;
+option java_package = "com.example.generated";
+```
+
+| Scenario                  | Java Package Used         |
+| ------------------------- | ------------------------- |
+| No override               | `com.example.generated`   |
+| CLI: `--package=override` | `override`                |
+| No java_package option    | `myapp.models` (fallback) |
+
+### Cross-Language Type Registration
+
+Language-specific options only affect where code is generated, not the type namespace used for serialization. This ensures cross-language compatibility:
+
+```protobuf
+package myapp.models;
+option java_package = "com.mycorp.generated";
+option go_package = "github.com/mycorp/gen;genmodels";
+
+message User {
+    string name = 1;
+}
+```
+
+All languages will register `User` with namespace `myapp.models`, enabling:
+
+- Java serialized data → Go deserialization
+- Go serialized data → Java deserialization
+- Any language combination works seamlessly
+
+## Import Statement
+
+Import statements allow you to use types defined in other Fory IDL files.
+
+### Basic Syntax
+
+```protobuf
+import "path/to/file.fdl";
+```
+
+### Multiple Imports
+
+```protobuf
+import "common/types.fdl";
+import "common/enums.fdl";
+import "models/address.fdl";
+```
+
+### Path Resolution
+
+Import paths are resolved relative to the importing file:
+
+```
+project/
+├── common/
+│   └── types.fdl
+├── models/
+│   ├── user.fdl      # import "../common/types.fdl"
+│   └── order.fdl     # import "../common/types.fdl"
+└── main.fdl          # import "common/types.fdl"
+```
+
+**Rules:**
+
+- Import paths are quoted strings (double or single quotes)
+- Paths are resolved relative to the importing file's directory
+- Imported types become available as if defined in the current file
+- Circular imports are detected and reported as errors
+- Transitive imports work (if A imports B and B imports C, A has access to C's types)
+
+### Complete Example
+
+**common/types.fdl:**
+
+```protobuf
+package common;
+
+enum Status [id=100] {
+    PENDING = 0;
+    ACTIVE = 1;
+    COMPLETED = 2;
+}
+
+message Address [id=101] {
+    string street = 1;
+    string city = 2;
+    string country = 3;
+}
+```
+
+**models/user.fdl:**
+
+```protobuf
+package models;
+import "../common/types.fdl";
+
+message User [id=200] {
+    string id = 1;
+    string name = 2;
+    Address home_address = 3;  // Uses imported type
+    Status status = 4;          // Uses imported enum
+}
+```
+
+### Unsupported Import Syntax
+
+The following protobuf import modifiers are **not supported**:
+
+```protobuf
+// NOT SUPPORTED - will produce an error
+import public "other.fdl";
+import weak "other.fdl";
+```
+
+**`import public`**: Fory IDL uses a simpler import model. All imported types are available to the importing file only. Re-exporting is not supported. Import each file directly where needed.
+
+**`import weak`**: Fory IDL requires all imports to be present at compile time. Optional dependencies are not supported.
+
+### Import Errors
+
+The compiler reports errors for:
+
+- **File not found**: The imported file doesn't exist
+- **Circular import**: A imports B which imports A (directly or indirectly)
+- **Parse errors**: Syntax errors in imported files
+- **Unsupported syntax**: `import public` or `import weak`
+
+## Enum Definition
+
+Enums define a set of named integer constants.
+
+### Basic Syntax
+
+```protobuf
+enum Status {
+    PENDING = 0;
+    ACTIVE = 1;
+    COMPLETED = 2;
+}
+```
+
+### With Explicit Type ID
+
+```protobuf
+enum Status [id=100] {
+    PENDING = 0;
+    ACTIVE = 1;
+    COMPLETED = 2;
+}
+```
+
+### Reserved Values
+
+Reserve field numbers or names to prevent reuse:
+
+```protobuf
+enum Status {
+    reserved 2, 15, 9 to 11, 40 to max;  // Reserved numbers
+    reserved "OLD_STATUS", "DEPRECATED"; // Reserved names
+    PENDING = 0;
+    ACTIVE = 1;
+    COMPLETED = 3;
+}
+```
+
+### Enum Type Options
+
+Enum-level options are declared inline in `[]` after the enum name:
+
+```protobuf
+enum Status [deprecated=true] {
+    PENDING = 0;
+    ACTIVE = 1;
+}
+```
+
+FDL does not support `option ...;` statements inside enum bodies.
+
+**Unsupported:**
+
+- `allow_alias` is **not supported**. Each enum value must have a unique integer.
+
+### Language Mapping
+
+| Language | Implementation                         |
+| -------- | -------------------------------------- |
+| Java     | `enum Status { UNKNOWN, ACTIVE, ... }` |
+| Python   | `class Status(IntEnum): UNKNOWN = 0`   |
+| Go       | `type Status int32` with constants     |
+| Rust     | `#[repr(i32)] enum Status { Unknown }` |
+| C++      | `enum class Status : int32_t { ... }`  |
+
+### Enum Prefix Stripping
+
+When enum values use a protobuf-style prefix (enum name in UPPER_SNAKE_CASE), the compiler automatically strips the prefix for languages with scoped enums:
+
+```protobuf
+// Input with prefix
+enum DeviceTier {
+    DEVICE_TIER_UNKNOWN = 0;
+    DEVICE_TIER_TIER1 = 1;
+    DEVICE_TIER_TIER2 = 2;
+}
+```
+
+**Generated code:**
+
+| Language | Output                                    | Style          |
+| -------- | ----------------------------------------- | -------------- |
+| Java     | `UNKNOWN, TIER1, TIER2`                   | Scoped enum    |
+| Rust     | `Unknown, Tier1, Tier2`                   | Scoped enum    |
+| C++      | `UNKNOWN, TIER1, TIER2`                   | Scoped enum    |
+| Python   | `UNKNOWN, TIER1, TIER2`                   | Scoped IntEnum |
+| Go       | `DeviceTierUnknown, DeviceTierTier1, ...` | Unscoped const |
+
+**Note:** The prefix is only stripped if the remainder is a valid identifier. For example, `DEVICE_TIER_1` is kept unchanged because `1` is not a valid identifier name.
+
+**Grammar:**
+
+```
+enum_def     := 'enum' IDENTIFIER [type_options] '{' enum_body '}'
+type_options := '[' type_option (',' type_option)* ']'
+type_option  := IDENTIFIER '=' option_value
+enum_body    := (reserved_stmt | enum_value)*
+reserved_stmt := 'reserved' reserved_items ';'
+enum_value   := IDENTIFIER '=' INTEGER ';'
+```
+
+**Rules:**
+
+- Enum names must be unique within the file
+- Enum values must have explicit integer assignments
+- Value integers must be unique within the enum (no aliases)
+- Type ID (`[id=100]`) is optional for enums but recommended for cross-language use
+
+**Example with All Features:**
+
+```protobuf
+// HTTP status code categories
+enum HttpCategory [id=200] {
+    reserved 10 to 20;           // Reserved for future use
+    reserved "UNKNOWN";          // Reserved name
+    INFORMATIONAL = 1;
+    SUCCESS = 2;
+    REDIRECTION = 3;
+    CLIENT_ERROR = 4;
+    SERVER_ERROR = 5;
+}
+```
+
+## Message Definition
+
+Messages define structured data types with typed fields.
+
+### Basic Syntax
+
+```protobuf
+message Person {
+    string name = 1;
+    int32 age = 2;
+}
+```
+
+### With Explicit Type ID
+
+```protobuf
+message Person [id=101] {
+    string name = 1;
+    int32 age = 2;
+}
+```
+
+### Without Explicit Type ID
+
+```protobuf
+message Person {  // Auto-generated when enable_auto_type_id = true
+    string name = 1;
+    int32 age = 2;
+}
+```
+
+### Language Mapping
+
+| Language | Implementation                      |
+| -------- | ----------------------------------- |
+| Java     | POJO class with getters/setters     |
+| Python   | `@dataclass` class                  |
+| Go       | Struct with exported fields         |
+| Rust     | Struct with `#[derive(ForyObject)]` |
+| C++      | Struct with `FORY_STRUCT` macro     |
+
+Type IDs control cross-language registration for messages, unions, and enums. See
+[Type IDs](#type-ids) for auto-generation, aliases, and collision handling.
+
+### Reserved Fields
+
+Reserve field numbers or names to prevent reuse after removing fields:
+
+```protobuf
+message User {
+    reserved 2, 15, 9 to 11;       // Reserved field numbers
+    reserved "old_field", "temp";  // Reserved field names
+    string id = 1;
+    string name = 3;
+}
+```
+
+### Message Type Options
+
+Message-level options are declared inline in `[]` after the message name:
+
+```protobuf
+message User [deprecated=true] {
+    string id = 1;
+    string name = 2;
+}
+```
+
+FDL does not support `option ...;` statements inside message or enum bodies.
+
+**Grammar:**
+
+```
+message_def  := 'message' IDENTIFIER [type_options] '{' message_body '}'
+type_options := '[' type_option (',' type_option)* ']'
+type_option  := IDENTIFIER '=' option_value
+message_body := (reserved_stmt | nested_type | field_def)*
+nested_type  := enum_def | message_def | union_def
+```
+
+**Rules:**
+
+- Type IDs follow the rules in [Type IDs](#type-ids).
+
+## Nested Types
+
+Messages can contain nested message, enum, and union definitions. This is useful for defining types that are closely related to their parent message.
+
+### Nested Messages
+
+```protobuf
+message SearchResponse {
+    message Result {
+        string url = 1;
+        string title = 2;
+        list<string> snippets = 3;
+    }
+    list<Result> results = 1;
+}
+```
+
+### Nested Enums
+
+```protobuf
+message Container {
+    enum Status {
+        STATUS_UNKNOWN = 0;
+        STATUS_ACTIVE = 1;
+        STATUS_INACTIVE = 2;
+    }
+    Status status = 1;
+}
+```
+
+### Qualified Type Names
+
+Nested types can be referenced from other messages using qualified names (Parent.Child):
+
+```protobuf
+message SearchResponse {
+    message Result {
+        string url = 1;
+        string title = 2;
+    }
+}
+
+message SearchResultCache {
+    // Reference nested type with qualified name
+    SearchResponse.Result cached_result = 1;
+    list<SearchResponse.Result> all_results = 2;
+}
+```
+
+### Deeply Nested Types
+
+Nesting can be multiple levels deep:
+
+```protobuf
+message Outer {
+    message Middle {
+        message Inner {
+            string value = 1;
+        }
+        Inner inner = 1;
+    }
+    Middle middle = 1;
+}
+
+message OtherMessage {
+    // Reference deeply nested type
+    Outer.Middle.Inner deep_ref = 1;
+}
+```
+
+### Language-Specific Generation
+
+| Language | Nested Type Generation                                                            |
+| -------- | --------------------------------------------------------------------------------- |
+| Java     | Static inner classes (`SearchResponse.Result`)                                    |
+| Python   | Nested classes within dataclass                                                   |
+| Go       | Flat structs with underscore (`SearchResponse_Result`, configurable to camelcase) |
+| Rust     | Nested modules (`search_response::Result`)                                        |
+| C++      | Nested classes (`SearchResponse::Result`)                                         |
+
+**Note:** Go defaults to underscore-separated nested names; set `option go_nested_type_style = "camelcase";` to use concatenated names. Rust emits nested modules for nested types.
+
+### Nested Type Rules
+
+- Nested type names must be unique within their parent message
+- Nested types can have their own type IDs
+- Numeric type IDs must be globally unique (including nested types); see [Type IDs](#type-ids)
+  for auto-generation and collision handling
+- Within a message, you can reference nested types by simple name
+- From outside, use the qualified name (Parent.Child)
+
+## Union Definition
+
+Unions define a value that can hold exactly one of several case types.
+
+### Basic Syntax
+
+```protobuf
+union Animal [id=106] {
+    Dog dog = 1;
+    Cat cat = 2;
+}
+```
+
+### Using a Union in a Message
+
+```protobuf
+message Person [id=100] {
+    Animal pet = 1;
+    optional Animal favorite_pet = 2;
+}
+```
+
+### Rules
+
+- Case IDs must be unique within the union
+- Cases cannot be `optional` or `ref`
+- Union cases do not support field options
+- Case types can be primitives, enums, messages, or other named types
+- Union type IDs follow the rules in [Type IDs](#type-ids).
+
+**Grammar:**
+
+```
+union_def  := 'union' IDENTIFIER [type_options] '{' union_field* '}'
+union_field := field_type IDENTIFIER '=' INTEGER ';'
+```
+
+## Field Definition
+
+Fields define the properties of a message.
+
+### Basic Syntax
+
+```protobuf
+field_type field_name = field_number;
+```
+
+### With Modifiers
+
+```protobuf
+optional list<string> tags = 1;  // Nullable list
+list<optional string> tags = 2;  // Elements may be null
+ref list<Node> nodes = 3;        // Collection tracked as a reference
+list<ref Node> nodes = 4;        // Elements tracked as references
+```
+
+**Grammar:**
+
+```
+field_def    := [modifiers] field_type IDENTIFIER '=' INTEGER ';'
+modifiers    := { 'optional' | 'ref' }
+field_type   := primitive_type | named_type | list_type | map_type
+list_type    := 'list' '<' { 'optional' | 'ref' } field_type '>'
+```
+
+Modifiers apply to the field/collection. Use `list<...>` to describe element
+modifiers. `repeated` is accepted as an alias for `list`.
+
+### Field Modifiers
+
+#### `optional`
+
+Marks the field as nullable:
+
+```protobuf
+message User {
+    string name = 1;           // Required, non-null
+    optional string email = 2; // Nullable
+}
+```
+
+**Generated Code:**
+
+| Language | Non-optional       | Optional                                        |
+| -------- | ------------------ | ----------------------------------------------- |
+| Java     | `String name`      | `String email` with `@ForyField(nullable=true)` |
+| Python   | `name: str`        | `name: Optional[str]`                           |
+| Go       | `Name string`      | `Name *string`                                  |
+| Rust     | `name: String`     | `name: Option<String>`                          |
+| C++      | `std::string name` | `std::optional<std::string> name`               |
+
+**Default Values:**
+
+| Type               | Default Value       |
+| ------------------ | ------------------- |
+| Non-optional types | Language default    |
+| Optional types     | `null`/`None`/`nil` |
+
+#### `ref`
+
+Enables reference tracking for shared/circular references:
+
+```protobuf
+message Node {
+    string value = 1;
+    ref Node parent = 2;     // Can point to shared object
+    list<ref Node> children = 3;
+}
+```
+
+**Use Cases:**
+
+- Shared objects (same object referenced multiple times)
+- Circular references (object graphs with cycles)
+- Tree structures with parent pointers
+
+**Generated Code:**
+
+| Language | Without `ref`  | With `ref`                                |
+| -------- | -------------- | ----------------------------------------- |
+| Java     | `Node parent`  | `Node parent` with `@ForyField(ref=true)` |
+| Python   | `parent: Node` | `parent: Node = pyfory.field(ref=True)`   |
+| Go       | `Parent Node`  | `Parent *Node` with `fory:"ref"`          |
+| Rust     | `parent: Node` | `parent: Arc<Node>`                       |
+| C++      | `Node parent`  | `std::shared_ptr<Node> parent`            |
+
+Rust uses `Arc` by default; use `ref(thread_safe=false)` or `ref(weak=true)`
+to customize pointer types. For protobuf option syntax, see
+[Protocol Buffers IDL Support](protobuf-idl.md#field-level-options).
+
+#### `list`
+
+Marks the field as a list/array:
+
+```protobuf
+message Document {
+    list<string> tags = 1;
+    list<User> authors = 2;
+}
+```
+
+**Generated Code:**
+
+| Language | Type                       |
+| -------- | -------------------------- |
+| Java     | `List<String>`             |
+| Python   | `List[str]`                |
+| Go       | `[]string`                 |
+| Rust     | `Vec<String>`              |
+| C++      | `std::vector<std::string>` |
+
+### Combining Modifiers
+
+Modifiers can be combined:
+
+```fdl
+message Example {
+    optional list<string> tags = 1;  // Nullable list
+    list<optional string> aliases = 2; // Elements may be null
+    ref list<Node> nodes = 3;          // Collection tracked as a reference
+    list<ref Node> children = 4;       // Elements tracked as references
+    optional ref User owner = 5;          // Nullable tracked reference
+}
+```
+
+Modifiers before `list` apply to the field/collection. Modifiers after `list`
+apply to elements. `repeated` is accepted as an alias for `list`.
+
+**List modifier mapping:**
+
+| Fory IDL                | Java                                           | Python                                  | Go                      | Rust                  | C++                                       |
+| ----------------------- | ---------------------------------------------- | --------------------------------------- | ----------------------- | --------------------- | ----------------------------------------- |
+| `optional list<string>` | `List<String>` + `@ForyField(nullable = true)` | `Optional[List[str]]`                   | `[]string` + `nullable` | `Option<Vec<String>>` | `std::optional<std::vector<std::string>>` |
+| `list<optional string>` | `List<String>` (nullable elements)             | `List[Optional[str]]`                   | `[]*string`             | `Vec<Option<String>>` | `std::vector<std::optional<std::string>>` |
+| `ref list<User>`        | `List<User>` + `@ForyField(ref = true)`        | `List[User]` + `pyfory.field(ref=True)` | `[]User` + `ref`        | `Arc<Vec<User>>`      | `std::shared_ptr<std::vector<User>>`      |
+| `list<ref User>`        | `List<User>`                                   | `List[User]`                            | `[]*User` + `ref=false` | `Vec<Arc<User>>`      | `std::vector<std::shared_ptr<User>>`      |
+
+Use `ref(thread_safe=false)` in Fory IDL (or `[(fory).thread_safe_pointer = false]` in protobuf)
+to generate `Rc` instead of `Arc` in Rust.
+
+## Field Numbers
+
+Each field must have a unique positive integer identifier:
+
+```protobuf
+message Example {
+    string first = 1;
+    string second = 2;
+    string third = 3;
+}
+```
+
+**Rules and best practices:**
+
+- Numbers must be unique within a message.
+- Numbers must be positive integers.
+- Gaps are allowed and are useful when fields are removed.
+- Prefer sequential numbering from `1`.
+- Never reuse a removed field number for a different field.
+
+## Type System
+
+Fory IDL provides a cross-language type system for primitives, named types, and
+collections. Field modifiers (`optional`, `list`, `ref`) control nullability,
+collection behavior, and reference tracking (see
+[Field Modifiers](#field-modifiers)).
+
+### Primitive Types
+
+| Type            | Description                               | Size     |
+| --------------- | ----------------------------------------- | -------- |
+| `bool`          | Boolean value                             | 1 byte   |
+| `int8`          | Signed 8-bit integer                      | 1 byte   |
+| `int16`         | Signed 16-bit integer                     | 2 bytes  |
+| `int32`         | Signed 32-bit integer (varint encoding)   | 4 bytes  |
+| `int64`         | Signed 64-bit integer (varint encoding)   | 8 bytes  |
+| `uint8`         | Unsigned 8-bit integer                    | 1 byte   |
+| `uint16`        | Unsigned 16-bit integer                   | 2 bytes  |
+| `uint32`        | Unsigned 32-bit integer (varint encoding) | 4 bytes  |
+| `uint64`        | Unsigned 64-bit integer (varint encoding) | 8 bytes  |
+| `fixed_int32`   | Signed 32-bit integer (fixed encoding)    | 4 bytes  |
+| `fixed_int64`   | Signed 64-bit integer (fixed encoding)    | 8 bytes  |
+| `fixed_uint32`  | Unsigned 32-bit integer (fixed encoding)  | 4 bytes  |
+| `fixed_uint64`  | Unsigned 64-bit integer (fixed encoding)  | 8 bytes  |
+| `tagged_int64`  | Signed 64-bit integer (tagged encoding)   | 8 bytes  |
+| `tagged_uint64` | Unsigned 64-bit integer (tagged encoding) | 8 bytes  |
+| `float32`       | 32-bit floating point                     | 4 bytes  |
+| `float64`       | 64-bit floating point                     | 8 bytes  |
+| `string`        | UTF-8 string                              | Variable |
+| `bytes`         | Binary data                               | Variable |
+| `date`          | Calendar date                             | Variable |
+| `timestamp`     | Date and time with timezone               | Variable |
+| `duration`      | Duration                                  | Variable |
+| `decimal`       | Decimal value                             | Variable |
+| `any`           | Dynamic value (runtime type)              | Variable |
+
+#### Boolean
+
+| Language | Type                  | Notes              |
+| -------- | --------------------- | ------------------ |
+| Java     | `boolean` / `Boolean` | Primitive or boxed |
+| Python   | `bool`                |                    |
+| Go       | `bool`                |                    |
+| Rust     | `bool`                |                    |
+| C++      | `bool`                |                    |
+
+#### Integer Types
+
+Fory IDL provides fixed-width signed integers (varint encoding for 32/64-bit by default):
+
+| Fory IDL Type | Size   | Range             |
+| ------------- | ------ | ----------------- |
+| `int8`        | 8-bit  | -128 to 127       |
+| `int16`       | 16-bit | -32,768 to 32,767 |
+| `int32`       | 32-bit | -2^31 to 2^31 - 1 |
+| `int64`       | 64-bit | -2^63 to 2^63 - 1 |
+
+**Language Mapping (Signed):**
+
+| Fory IDL | Java    | Python         | Go      | Rust  | C++       |
+| -------- | ------- | -------------- | ------- | ----- | --------- |
+| `int8`   | `byte`  | `pyfory.int8`  | `int8`  | `i8`  | `int8_t`  |
+| `int16`  | `short` | `pyfory.int16` | `int16` | `i16` | `int16_t` |
+| `int32`  | `int`   | `pyfory.int32` | `int32` | `i32` | `int32_t` |
+| `int64`  | `long`  | `pyfory.int64` | `int64` | `i64` | `int64_t` |
+
+Fory IDL provides fixed-width unsigned integers (varint encoding for 32/64-bit by default):
+
+| Fory IDL | Size   | Range         |
+| -------- | ------ | ------------- |
+| `uint8`  | 8-bit  | 0 to 255      |
+| `uint16` | 16-bit | 0 to 65,535   |
+| `uint32` | 32-bit | 0 to 2^32 - 1 |
+| `uint64` | 64-bit | 0 to 2^64 - 1 |
+
+**Language Mapping (Unsigned):**
+
+| Fory IDL | Java    | Python          | Go       | Rust  | C++        |
+| -------- | ------- | --------------- | -------- | ----- | ---------- |
+| `uint8`  | `short` | `pyfory.uint8`  | `uint8`  | `u8`  | `uint8_t`  |
+| `uint16` | `int`   | `pyfory.uint16` | `uint16` | `u16` | `uint16_t` |
+| `uint32` | `long`  | `pyfory.uint32` | `uint32` | `u32` | `uint32_t` |
+| `uint64` | `long`  | `pyfory.uint64` | `uint64` | `u64` | `uint64_t` |
+
+#### Integer Encoding Variants
+
+For 32/64-bit integers, Fory IDL uses varint encoding by default. Use explicit types when
+you need fixed-width or tagged encoding:
+
+| Fory IDL Type   | Encoding | Notes                    |
+| --------------- | -------- | ------------------------ |
+| `fixed_int32`   | fixed    | Signed 32-bit            |
+| `fixed_int64`   | fixed    | Signed 64-bit            |
+| `fixed_uint32`  | fixed    | Unsigned 32-bit          |
+| `fixed_uint64`  | fixed    | Unsigned 64-bit          |
+| `tagged_int64`  | tagged   | Signed 64-bit (hybrid)   |
+| `tagged_uint64` | tagged   | Unsigned 64-bit (hybrid) |
+
+#### Floating-Point Types
+
+| Fory IDL Type | Size   | Precision     |
+| ------------- | ------ | ------------- |
+| `float32`     | 32-bit | ~7 digits     |
+| `float64`     | 64-bit | ~15-16 digits |
+
+**Language Mapping:**
+
+| Fory IDL  | Java     | Python           | Go        | Rust  | C++      |
+| --------- | -------- | ---------------- | --------- | ----- | -------- |
+| `float32` | `float`  | `pyfory.float32` | `float32` | `f32` | `float`  |
+| `float64` | `double` | `pyfory.float64` | `float64` | `f64` | `double` |
+
+#### String Type
+
+| Language | Type          | Notes                 |
+| -------- | ------------- | --------------------- |
+| Java     | `String`      | Immutable             |
+| Python   | `str`         |                       |
+| Go       | `string`      | Immutable             |
+| Rust     | `String`      | Owned, heap-allocated |
+| C++      | `std::string` |                       |
+
+#### Bytes Type
+
+| Language | Type                   | Notes     |
+| -------- | ---------------------- | --------- |
+| Java     | `byte[]`               |           |
+| Python   | `bytes`                | Immutable |
+| Go       | `[]byte`               |           |
+| Rust     | `Vec<u8>`              |           |
+| C++      | `std::vector<uint8_t>` |           |
+
+#### Temporal Types
+
+##### Date
+
+| Language | Type                        | Notes                   |
+| -------- | --------------------------- | ----------------------- |
+| Java     | `java.time.LocalDate`       |                         |
+| Python   | `datetime.date`             |                         |
+| Go       | `time.Time`                 | Time portion ignored    |
+| Rust     | `chrono::NaiveDate`         | Requires `chrono` crate |
+| C++      | `fory::serialization::Date` |                         |
+
... 3078 lines suppressed ...


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fory.apache.org
For additional commands, e-mail: commits-help@fory.apache.org