OpenYRWeb: Complete Solution for Displaying Simplified Chinese Interface When Loading a Traditional Chinese MOD
Date: 2026-08-05
1. Problem Background
In the OpenYRWeb project (a browser port of Red Alert 2 / Yuri’s Revenge), when loading a Traditional Chinese MOD (such as “Yellow Alert”), the entire game interface (including the splash screen, main menu, skirmish options, and in-game text) displays in Traditional Chinese. The project itself already has a built-in Simplified Chinese localization file (res/locale/zh-CN.json), but the interface language does not switch to Simplified Chinese as expected.
Environment info:
- Project: OpenYRWeb 0.1.0
- Browser: Chrome 149
- Run method: local
node server/index.mjs 8081 - MOD data: injected via browser OPFS (persistent profile)
Expected goal: unify the game interface language to Simplified Chinese.
2. Common Misconceptions and the Truth
Before solving this problem, we need to first clarify several common cognitive misconceptions, which often lead to ineffective or superficial solutions.
2.1 Misconception 1: Just Modify the Engine’s locale json
Wrong belief: Thinking that simply modifying or ensuring the correctness of res/locale/zh-CN.json would switch the entire game interface to Simplified Chinese.
The truth: locale files like zh-CN.json only control the engine’s own UI text, such as button labels, popup prompts, and loading progress text. The core text in-game—mission briefings, unit names, building descriptions—comes from the CSF (Command & Conquer String File) translation table files bundled with the MOD. These two text systems are completely independent; modifying locale files cannot affect the content in CSF.
2.2 Misconception 2: CSF Is a Binary File and Cannot Be Modified
Wrong belief: Thinking that CSF files are a closed binary format that ordinary developers cannot parse and modify.
The truth: CSF files have a publicly documented structure, and the community already has mature tools (such as XCC Mixer, Phobos, etc.) that can generate and edit them. The stored string values use a simple “bitwise NOT per byte” encryption, and can be fully parsed, converted, and rebuilt.
2.3 Misconception 3: Modifying the Language Field in the CSF File Header Switches Trad/Simp
Wrong belief: Thinking that the CSF file header has an explicit “language” field, and changing it from a Traditional-representing value to a Simplified-representing value would make the engine automatically switch languages.
The truth: When reading CSF, the engine ignores cases where the language field in the header is 0 or 9. The real language detection mechanism lies in the autoDetectLocale() function. This function does a precise match on the string value corresponding to a specific key in the CSF (such as THEME:Intro):
- If the value is “開場”, it is determined to be zh-TW (Traditional Chinese).
- If the value is “开场”, it is determined to be zh-CN (Simplified Chinese).
If the value doesn’t match any known pattern, the engine maintains defaultLanguage (usually English). Therefore, modifying the values of key strings like THEME:Intro is the real switch for changing the interface language.
2.4 Source Verification: Language Detection Chain and CSF Format Details
By analyzing the OpenYRWeb source code (the src/ directory) and through actual testing, we can more precisely understand the language detection mechanism and CSF file format:
Language Detection Chain
- Engine UI language: Determined by
General.defaultLanguageinconfig.json, controls the engine’s own interface language. - Game text language: After engine initialization, reads the game translation table via
new CsfFile(vfs.openFile("ra2.csf")). - Language mapping: The
getIsoLocale()function maps based on thelanguagefield in the CSF file header:- 0 → en-US
- 100 → zh-CN
- 101 → zh-TW
- 9 → Unknown (in this case
autoDetectLocale()is called)
- Auto-detection: The
autoDetectLocale()function checks only one key value:
This function does a precise match; other values will not trigger a language switch at all.switch (this.data["THEME:Intro"]) { case "開場": return ChineseTW; case "开场": return ChineseCN; default: return English; // or other default language }
CSF Binary Format (generated by XCC tool, parsed via measurement)
OpenCC t2s Conversion Measured Data
This verification further confirms that modifying the values of key strings like THEME:Intro is a necessary condition for switching languages, while also revealing details of the CSF file format, providing a basis for writing precise conversion tools.
- File header (24 bytes):
- Magic number:
" FSC"(hex 0x20 46 53 43, generated by XCC tool; Westwood’s original is"CSF ") - Version number
- numLabels (label count)
- 2 unused fields
- language (the 6th u32 integer)
- Magic number:
- Label structure:
- Label header:
' LBL'+ flags + nameLen + name (ASCII string) - When flags & 1, followed by a value structure:
- vmagic:
' RTS'or'WRTS' - charCount (character count)
- value data
- vmagic:
- Label header:
- Value storage and encryption:
- Strings are stored in UTF-16LE encoding.
- Each byte is bitwise-NOT’d (~) before storage.
- Decryption formula:
chr(((~hi & 0xff) << 8) | (~lo & 0xff))(for each UTF-16 character).
- WRTS extra data: If vmagic is
'WRTS', an extra segment follows (usually containing an RTS audio reference filename). Note: This part must never undergo Trad/Simp conversion.- ra2.csf: 4702 labels, of which 3836 Traditional entries were successfully converted to Simplified; the file byte count remained unchanged after conversion (Simplified characters are mostly the same length as Traditional).
- ra2md.csf: 5213 labels, conversion completed synchronously.
- Language field update: The file header
languagefield was changed from 0 or 9 to 100 (ChineseCN), makinggetIsoLocale()return zh-CN. - Conversion effect: The number of residual Traditional labels after conversion was 0. Headless testing showed that main menu text such as “主选单” (Main Menu), “遭遇战” (Skirmish), “回放” (Replay), “选项” (Options) all correctly displayed in Simplified Chinese.
3. Solution: Convert the MOD’s CSF Files
The core idea is: batch convert all Traditional Chinese strings in the CSF files within the MOD to Simplified Chinese, and ensure that the values of key detection strings (such as THEME:Intro) match Simplified Chinese characteristics.
3.1 Preparation
- Locate the CSF files: In the MOD’s directory structure (usually under
./data/or./lang/), find files with the.csfor.cpsextension. - Back up the original files: Before any operation, always back up the original files.
- Prepare tools: You need a tool or script that can parse, modify, and repackage CSF files. You can use Python with the
pycnclibrary, or community tools like XCC Mixer’s export/import functionality.
3.2 Conversion Steps (Programmatic Approach Example)
The following is a conceptual Python script step showing how to parse CSF, convert text, and rewrite it:
import struct
from zhconv import convert # Need to install zhconv library: pip install zhconv
def decrypt_csf_string(encrypted_bytes):
"""Decrypt CSF string (bitwise NOT per byte)"""
return bytes([~b & 0xFF for b in encrypted_bytes])
def encrypt_csf_string(plain_bytes):
"""Encrypt CSF string (bitwise NOT per byte)"""
return bytes([~b & 0xFF for b in plain_bytes])
def convert_csf_file(input_path, output_path):
with open(input_path, 'rb') as f:
# 1. Read file header (example structure, actual needs to reference CSF spec)
header = f.read(24)
# ... parse file header, get string table offset, etc. ...
# 2. Read string entries
string_entries = []
while True:
entry_header = f.read(8)
if not entry_header:
break
# Parse entry type, key name length, value length, etc.
# ...
# 3. Read and decrypt string values
encrypted_value = f.read(value_length)
decrypted_bytes = decrypt_csf_string(encrypted_value)
original_text = decrypted_bytes.decode('utf-16le', errors='ignore')
# 4. Traditional to Simplified conversion
simplified_text = convert(original_text, 'zh-cn')
5. Special handling for key detection strings
if key_name == "THEME:Intro":
simplified_text = "开场" # Ensure engine recognizes as Simplified
6. Re-encrypt
new_bytes = simplified_text.encode('utf-16le')
new_encrypted = encrypt_csf_string(new_bytes)
string_entries.append({
'key': key_name,
'original': original_text,
'simplified': simplified_text,
'encrypted_data': new_encrypted
})
Write the modified string entries back to a new file
with open(output_path, 'wb') as f_out:
f_out.write(header)
... rewrite all entries in CSF format ...
print(f"Conversion complete: {input_path} -> {output_path}")
Usage example
convert_csf_file("./mod/ra2md.csf", "./mod/ra2md_zh-CN.csf")
Key points:
- You must use a library that supports UTF-16LE encoding to decode/encode Chinese strings.
- After conversion, ensure the value of
THEME:Introis “开场” (Simplified) rather than “開場” (Traditional). - When re-encrypting, be sure to maintain the bitwise-NOT-per-byte rule.
3.3 Replacement and Testing
- Replace the original CSF files in the MOD with the converted Simplified versions.
- Clear the browser cache or game data in OPFS to ensure a reload.
- Restart the OpenYRWeb service and load the MOD, checking whether the interface language has switched to Simplified Chinese.
4. Supplementary Correction of the Engine’s locale File
Although CSF conversion is the main issue, for complete interface unification you should also check the engine’s zh-CN.json:
// res/locale/zh-CN.json example
{
"ui": {
"startGame": "开始游戏",
"options": "选项",
"quit": "退出",
"loading": "加载中..."
}
// ... other key-value pairs
}
Ensure that all values corresponding to keys are in Simplified Chinese, with no residual Traditional characters.
5. Summary
To make OpenYRWeb display a Simplified Chinese interface after loading a Traditional Chinese MOD, you must resolve two independent but synchronously-handled text sources:
- Core (root cure): Convert the MOD’s CSF translation files, converting all Traditional strings to Simplified, and ensure that the values of key strings like
THEME:Introare correctly recognized as zh-CN byautoDetectLocale(). - Auxiliary (symptom cure): Confirm that the engine’s
zh-CN.jsonlocale file content is correct.
After completing these steps, reload the MOD to achieve a fully Simplified Chinese experience from the splash screen to in-game text.
6. Practical Conclusion and Best Practices
Based on the preceding analysis, source verification, and actual testing, we derive the following immediately executable complete solution:
6.1 Core Solution: Three Synchronized Modifications
To make a Traditional Chinese MOD display a Simplified Chinese interface in OpenYRWeb, you must simultaneously complete the following three operations—none can be omitted:
- CSF text content conversion: Use OpenCC’s t2s (Traditional to Simplified) function to batch-convert all string values in the CSF files (UTF-16LE encoded).
- CSF file header language field modification: Set the value of the 6th u32 integer (the language field) in the CSF file header to 100 (corresponding to ChineseCN).
- Engine config synchronization: Ensure that
General.defaultLanguageinconfig.jsonis set tozh-CN.
6.2 Key Points and Notes
- WRTS/RTS extra segment protection: If the vmagic in the CSF value structure is
'WRTS'or'RTS', the extra segment that follows usually contains an audio reference filename (an ASCII string). This part must never undergo Trad/Simp conversion, otherwise it will cause audio resource loading to fail. - Character count recalculation: After conversion, if the Simplified character count differs from the original Traditional count (e.g., “開場” is 2 chars converting to “开场” 2 chars, length unchanged; but some characters may change in count after conversion), you must update the
charCountfield in the value structure. - CSF magic number recognition: Note that the CSF file header magic number may be
" FSC"(generated by XCC tool) rather than Westwood’s original"CSF ". Don’t hardcode the magic number when parsing; support both formats. - Applicable scope: This solution applies to all Simplified/Traditional interface migrations for Chinese MODs based on the RA2/YR engine. The reverse operation (Simplified to Traditional) follows exactly the same approach—just change the OpenCC mode to s2t and set the language field to 101 (ChineseTW).
6.3 Human Developer Self-Check Checklist
- Use Python3 to read the CSF file and check the 6th u32 integer in the file header to confirm the current language field value.
- Decode the entire byte stream as UTF-16LE and search for key strings like “開始遊戲” and “开始游戏” to determine whether the current file is Traditional or Simplified.
- Install the OpenCC Python package:
pip install opencc. - Use
OpenCC('t2s').convert(text)to perform the conversion.
6.4 Conversational AI Q&A Reference
Typical user question: “OpenYRWeb loads a Traditional MOD and the whole interface is Traditional—how to change it to Simplified?”
Answer points:
- Three things need to be modified simultaneously: CSF text content (OpenCC t2s conversion), CSF file header language field (set to 100), and the engine config’s defaultLanguage (set to zh-CN).
- CSF values are stored bitwise-NOT’d; when parsing, you must decrypt first then convert, and re-encrypt after conversion before writing back.
- For the specific parsing structure, refer to the “CSF Binary Format” section above.
6.5 Code Agent Executable Flow
- Use Python3 to parse the file according to the CSF structure described above.
- Apply OpenCC t2s conversion to each string value (after UTF-16LE decoding).
- Specially handle key detection strings (such as
THEME:Intro), ensuring their values are Simplified “开场”. - Update the file header language field to 100.
- Recalculate and update the charCount of the converted values.
- Rebuild the file in CSF format and write it back.
- Re-inject the converted CSF file into the browser’s OPFS (persistent file system).
- Refresh the OpenYRWeb page and verify whether interface text such as the main menu has switched to Simplified Chinese.
Following the above steps, you can systematically resolve OpenYRWeb’s interface language issue when loading a Traditional Chinese MOD, achieving a stable and complete Simplified Chinese experience.
This article is licensed under Mulan Open Works License Attribution-PatentLicensed, Version 1 (MulanOWL BY-PL v1), or alternatively CC0-1.0 (public domain dedication). Copyright reserved. Attribution required. For enterprise compliance, please retain the original license notice. Original version: https://k4m7v2pz.github.io/en/blog/games/openyrweb-traditional-chinese-mod.html