Tutorials & Beginner-First May 25, 2026

Your First Ren'Py Language Selector After Weblate PO Import in One Evening - 2026 Beginner Pipeline

2026 beginner Ren'Py tutorial—Weblate PO import, language selector screen, clean rebuild, and language_receipt_v1.json before visual novel fest demo upload.

By GamineAI Team

Your First Ren'Py Language Selector After Weblate PO Import in One Evening - 2026 Beginner Pipeline

Pixel-art hero for your first Ren'Py language selector after Weblate PO import beginner pipeline 2026

Your Weblate dashboard shows 100% for Chinese, Japanese, and Korean. Steam capsule screenshots look localized. You launch the fest demo, open Preferences → Language, and only English appears—or switching languages does nothing until restart crashes.

October 2026 visual-novel fest traffic expects store copy and in-game menus to match. Weblate proves PO files; Ren'Py proves translate blocks + UI wiring + clean builds. This Tutorials & Beginner-First pipeline runs one evening: import PO, regenerate translations, wire the language screen, boot-smoke three locales, file language_receipt_v1.json.

Non-repetition note: 7-day Ren'Py freeze challenge owns label and asset freeze—not selector wiring. Steam 300-char CJK help is store text—not in-game menus. Planned help: Ren'Py language selector stuck English.

Pair with Weblate merge-conflict help, 14-free Weblate PO tools, localization tooling resource, and store-page QA checklist.

Who this is for and what you get

Audience You will be able to…
First-time Ren'Py localizer Wire a language menu after Weblate export
Producer Require language_receipt_v1.json before fest promotion
Writer Know when PO import requires rebuild vs hotfix

Time: one evening (3–4 hours first locale set; 60 minutes when repeating for one new language).
Prerequisites: Ren'Py 8.x project with tl/ or generate translations enabled, Weblate PO export access, Windows build target for Steam demo.

Why this matters now (July–October 2026)

  1. Weblate + fest capsules — Teams pass string freeze on store strings but ship English-only executables.
  2. Refund optics — Players quote localized store tags then call the demo “English scam.”
  3. Ren'Py .rpyc cache — Stale bytecode hides new translate blocks until clean build.
  4. Freeze week pairingRen'Py freeze challenge Gate 7 should include language smoke rows.
  5. Metadata diff gapWednesday store metadata diff cannot see Preferences screen text.

Direct answer: Export PO from Weblate → import into Ren'Py tl/renpy.compile_all() or launcher regenerate → add Language screen entries → delete cache/ → build → smoke en + two fest localeslanguage_receipt_v1.json.

Evening overview (five blocks)

Block Minutes Output
1 — Weblate export proof 30 weblate_export_manifest.json
2 — PO placement + generate 45 tl/zh_CN/, tl/ja/, tl/ko/ populated
3 — Language screen (L1–L3) 45 Preferences lists all shipped locales
4 — Clean build + L4–L5 60 Standalone exe per smoke matrix
5 — Receipt + store parity 20 language_receipt_v1.json

Mental model — three localization layers

Layer Tool Player sees
Store Weblate + Steamworks Capsule, description
Engine strings translate blocks in tl/ Dialogue + UI
Selector screen language / Preferences Pickable languages

Passing layer 1 alone creates the “localized store, English game” bug this pipeline fixes.

Block 1 — Weblate export proof

Before touching Ren'Py, prove PO left Weblate cleanly (pairs merge-conflict help):

{
  "export_utc": "2026-05-25T18:00:00Z",
  "components": [
    { "name": "game/tl/zh_CN", "po": "zh_CN.po", "fuzzy_count": 0, "translated_percent": 100 },
    { "name": "game/tl/ja", "po": "ja.po", "fuzzy_count": 0, "translated_percent": 100 },
    { "name": "game/tl/ko", "po": "ko.po", "fuzzy_count": 0, "translated_percent": 100 }
  ],
  "string_freeze_receipt": "release-evidence/localization/string_freeze_receipt_v1.json"
}

Beginner rule: Any fuzzy_count greater than 0 on fest locales → stop and resolve in Weblate, not in Ren'Py.

Gates L1–L5 (language pass)

Gate Name Pass criterion
L1 PO on disk Each fest locale has tl/<lang>/ with non-empty .po
L2 Translate blocks Launcher Generate Translations or CLI compile sees new strings
L3 Selector UI Preferences lists en, zh_CN, ja, ko (your set)
L4 Boot smoke Each locale reaches main menu without traceback
L5 Switch smoke Change language in Preferences → UI updates without restart crash

L3–L5 block promotion when RED.

Block 2 — PO placement and generate

Folder layout (Ren'Py 8.x convention)

game/
  tl/
    None/           # optional source hooks
    zh_CN/
      common.rpy
      screens.rpy
      script.rpy
    ja/
      ...
    ko/
      ...

Copy Weblate-exported PO into matching folders—or configure Weblate Ren'Py component paths to push directly to game/tl/<lang>/.

Generate translations (launcher)

  1. Open Ren'Py Launcher → project.
  2. Generate Translations → select languages → Generate.
  3. Confirm new translate chinese strings: (etc.) blocks appear in tl/zh_CN/*.rpy.

CLI-oriented teams:

# illustrative: use your project's documented renpy.sh path
renpy.sh . compile

Outbound: Ren'Py translation documentation.

Common beginner mistakes

Mistake Symptom Fix
PO in wrong folder 0% strings update Match Weblate component path to tl/
Edit only .po, never regenerate English in game Run Generate Translations
Old translate IDs Mixed old/new lines Delete obsolete tl files per Ren'Py doc
Hardcoded language "english" in script Selector ignored Remove forced language in start label

Block 3 — Language screen wiring (L3)

Minimal Preferences pattern in screens.rpy (adapt to your UI skin):

screen preferences():
    tag menu
    vbox:
        textbutton _("Return") action Return()
        text _("Language")
        textbutton "English" action Language(None)
        textbutton "简体中文" action Language("chinese")
        textbutton "日本語" action Language("japanese")
        textbutton "한국어" action Language("korean")

Critical: Language("chinese") must match Ren'Py language name in project settings—not always ISO code. Check Launcher → Translate → List languages for exact identifiers.

Map Weblate locale codes to Ren'Py names in language_map_v1.json:

{
  "weblate_to_renpy": {
    "zh_CN": "chinese",
    "ja": "japanese",
    "ko": "korean"
  }
}

Store beside receipt—prevents “Weblate says zh_CN, Ren'Py expects chinese” drift.

config.default_language trap

If options.rpy contains:

define config.default_language = "english"

that is fine for first boot—but do not hardcode renpy.change_language("english") on every start label after the player picks another language.

Block 4 — Clean build and boot smoke (L4–L5)

Delete stale cache

Before distribution build:

rm -rf game/cache/
# Windows: delete game\cache\ folder in Explorer

Stale .rpyc is the #1 “Weblate 100% but game English” support cause.

Smoke matrix (standalone exe)

Run Start language Action Pass
A English Reach main menu No traceback
B 简体中文 Preferences → 简体中文 → main menu UI Chinese
C 日本語 Switch mid-menu No crash
D 한국어 Save slot → quit → relaunch Korean Save loads

Log in renpy_language_smoke.md:

# Ren'Py language smoke — 2026-05-25
build_id: nextfest-vn-rc3
| locale | L4 | L5 | notes |
| english | pass | pass | |
| chinese | pass | pass | font fallback OK |
| japanese | pass | pass | |
| korean | pass | YELLOW | one untranslated preferences line — fixed |

Pair with Wednesday demo smoke on promotion day—smoke gameplay after language smoke passes.

language_receipt_v1.json

{
  "schema": "language_receipt_v1",
  "build_id": "nextfest-vn-rc3",
  "weblate_export_manifest": "release-evidence/localization/weblate_export_manifest.json",
  "language_map": "release-evidence/localization/language_map_v1.json",
  "shipped_locales": ["english", "chinese", "japanese", "korean"],
  "gates": {
    "L1_po_on_disk": "pass",
    "L2_translate_blocks": "pass",
    "L3_selector_ui": "pass",
    "L4_boot_smoke": "pass",
    "L5_switch_smoke": "pass"
  },
  "store_parity": {
    "steam_supported_languages_claims": ["schinese", "japanese", "koreana"],
    "in_game_selector_matches": true
  },
  "promotion_allowed": true,
  "paired_renpy_freeze": "release-evidence/renpy/freeze-week/renpy_freeze_receipt_v1.json"
}

Attach to BUILD_RECEIPT notes and Thursday row review when string_table_receipt rows exist for Unity siblings—VN teams still file language_receipt for Ren'Py.

Store parity check (15 minutes)

Store claim In-game proof
Steam Supported languages includes Chinese Selector shows Chinese; dialogue Chinese
Screenshots CN At least one screenshot from chinese playthrough
Short description JP Preferences Japanese + sample line JP

Use store-page QA localization resource—checklist row in-game language selector matches Supported languages.

Fonts and CJK (beginner)

Issue Fix
tofu squares Add CJK font in gui.rpy / style.default.font
overflow Test 1280×720; shorten UI strings in Weblate
vertical JP Optional preferences — document if unsupported

Ship font license in release-evidence/localization/fonts/README.md.

Weblate ↔ Ren'Py workflow (ongoing)

Event Owner Action
String freeze Producer Lock Weblate per help
Export PO Localization lead Manifest JSON
Import Engineer Blocks 2–4 tonight
Writer typo Writer Fix in Weblate → re-export → regenerate
Fest promotion Producer language_receipt.promotion_allowed

Do not email PO files without updating weblate_export_manifest.json version.

Engine version pin

Log in receipt:

"renpy_version": "8.3.2",
"build_classification": "development"

Mismatch with freeze challenge build_classification_freeze.md → restart freeze Gate 2.

Troubleshooting table

Symptom Check
Only English in list L3 screen; config.languages
Language flips back on restart start label forcing english
Some lines English Missing translate for those strings
Crash on switch Font missing glyphs
Weblate 100%, game 0% L2 not run; cache not cleared
Steam CN, game EN This whole pipeline skipped

PowerShell clean cache (Windows)

Remove-Item -Recurse -Force "game\cache" -ErrorAction SilentlyContinue

Rebuild distribution before Steam upload.

Integration with fest ops week

Day Task
Mon Weblate freeze
Tue This pipeline (evening)
Wed Metadata diff
Wed PM Demo smoke
Thu Row review

Outbound references

Related GamineAI reads

Key takeaways

  • Weblate 100% does not imply Ren'Py shipped translations—run Generate Translations and clean cache.
  • Wire Preferences language buttons with correct Ren'Py language names (chinese, not only zh_CN).
  • Gates L1–L5 block fest promotion when selector or smoke fails.
  • File language_receipt_v1.json with store parity booleans.
  • Pair with Ren'Py freeze challenge and weekly metadata + demo smoke.
  • Store capsules and in-game selector must match Supported languages.
  • One evening first time; ~one hour per new locale after map exists.
  • Planned help article covers failure-first fixes; this URL is the first success path.

FAQ

Do I need Weblate?

No—but you need PO files from somewhere consistent. Manual PO works if paths match tl/.

Can I use Ren'Py native dialogue translator without Weblate?

Yes for small demos; fest teams outgrow spreadsheet handoff—Weblate returns in July stacks.

Does this change save compatibility?

Changing translation only usually preserves saves; changing script labels after freeze does not—see freeze challenge.

What about voice lines?

VO is separate; this pipeline is text UI + dialogue. Subtitles may still English if VO not localized.

Mac build too?

Smoke Windows first for Steam fest; add macOS matrix row to receipt when depot ships.

Where does Blender-Fab ORM backlog fit?

Unrelated art pipeline—finish language receipt before ORM proof sphere challenge week (now published).

Worked example (three-person VN studio)

Context: nextfest-vn-rc3 — Weblate green for zh_CN, ja, ko; Steam Supported Languages updated; demo still English.

Step Finding Fix
L1 tl/ko/ missing screens.rpy Re-export Korean component
L2 Generate Translations not run after PO drop Launcher regenerate
L3 Selector showed English only Added Language("chinese") buttons
Cache Old .rpyc Deleted game/cache/
L5 Korean crash on switch Missing Noto Sans KR in gui.rpy

Outcome: language_receipt_v1.json promotion_allowed: true Thursday; metadata diff GREEN Wednesday—no more “localized store” refund tags.

Scan for untranslated dialogue (developer)

# illustrative ripgrep — strings still using _() without translate
rg "^\s+\"[^\"]+\"$" game/ --glob "*.rpy" | head

Pair with Ren'Py Lint in launcher—untranslated dialogue warnings before build. Log warning count in renpy_language_smoke.md.

Poedit lane (no Weblate yet)

Tool When
Poedit Solo dev, fewer than 3 locales
Weblate Contractors + freeze windows

Same tl/ folders—export PO from Poedit, drop files, run Block 2 identically. Receipt still uses language_receipt_v1.json; set weblate_export_manifest to null and po_source: poedit in notes.

renpy.known_languages() debug (L3 aid)

Add temporary debug screen during development:

screen language_debug():
    text "[renpy.known_languages()]"

Screenshot output into smoke log—proves engine sees languages even if Preferences UI broken.

Remove debug screen before Steam upload—fails dev console opinion spirit on fest builds.

Narration vs UI strings

String type File usual location Weblate component
Dialogue script.rpy / chapters game/script
Menus screens.rpy game/screens
System common.rpy game/common

Split components in Weblate prevent translator merge conflicts on unrelated files—mirrors merge-conflict help.

Steam depot + language smoke order

  1. This pipeline on internal folder build.
  2. Upload to playtest branch.
  3. Demo smoke on chinese boot path once.
  4. Promote fest branch.

Skipping step 1 on playtest branch wastes player trust.

Receipt validation one-liner

jq -e '.gates.L3_selector_ui == "pass" and .store_parity.in_game_selector_matches == true' language_receipt_v1.json

Add to validate-packet when VN in Q3 diligence packet.

Writer rules during fest week (paste in Discord)

- No new language codes mid-week without producer sign-off
- Typos: fix in Weblate → re-export → engineer reruns Blocks 2–4
- No renaming dialogue labels (freeze challenge)
- Screenshot requests: specify locale (CN/JP/KR)

Compare Unity localization empty tables

Unity teams hit String Tables empty after strip—different engine, same store vs build lesson. VN producers on mixed-engine portfolios should read both helps—receipt types differ (string_table_receipt vs language_receipt).

Accessibility note

Language toggle should remain reachable without obscure gamepad combo—Deck glyph tutorial culture applies if VN ships Deck controls; Ren'Py _() strings in selector must fit button width at 1280×800.

Evidence folder (copy tree)

release-evidence/localization/
  weblate_export_manifest.json
  language_map_v1.json
  language_receipt_v1.json
  renpy_language_smoke.md
  fonts/README.md
  screenshots/
    menu_chinese_1280x720.png
    menu_japanese_1280x720.png

Friday Block 5 archives screenshots older than eight weeks—keep latest three locales only.

Minute-by-minute evening (first locale set)

Min Task
0–30 Export PO + manifest JSON
30–75 Copy tl/, Generate Translations
75–120 Wire Preferences + language_map_v1.json
120–180 Delete cache, build, smoke matrix A–D
180–200 language_receipt_v1.json + store parity row

Second language add is mostly smoke matrix row + Weblate export—under 60 minutes.

False positives that waste evenings

Report Usually means
“Translation broken” Cache not cleared
“Weblate wrong” PO never imported to tl/
“Steam lied” Supported languages checkbox ahead of build
“Crash on Korean” Font/glyph, not PO

Teach facilitators to ask for language_receipt before debating translator quality.

Forward link for Help-Create

When Ren'Py language selector help publishes, it should link here first for success path—help owns traceback fixes; blog owns first evening order of operations.

Checklist card (printable)

[ ] Weblate export manifest — fuzzy 0 on fest locales
[ ] tl/ folders populated
[ ] Generate Translations run
[ ] Language screen lists every shipped locale
[ ] game/cache deleted
[ ] Standalone smoke A–D GREEN
[ ] language_receipt_v1.json promotion_allowed
[ ] Store Supported languages matches selector

Tape inside localization tooling resource bookmark folder—physical reminders beat Slack pins during crunch week.

Producer sign-off line: “I will not promote the fest branch until language_receipt_v1.json shows promotion_allowed: true and screenshots exist for every Supported language we claim on Steam.”