Yanagi (柳)

Deterministic Japanese → Ukrainian transliteration and policy enforcement gem.

柳 (yanagi = willow / верба) — a symbol of Ukraine and a tree equally at home in Japanese poetry.

Features

  • Zero runtime dependencies — standard library only (yaml, json, set, unicode_normalize).
  • Mode A (Generation): Deterministic kana and romaji to Ukrainian Cyrillic rendering.
  • Mode B (Audit): Lexicon-anchored prose audit and policy violation detector:
    • Tier 1: AUTOFIX-eligible (matches lexicon entry via forbidden Polivanov/anglicism substitution).
    • Tier 2: High-confidence report for unknown Japanese terms (contains JP markers, unanchored in lexicon/allowlist).
    • Tier 3: Polivanov markers check (off by default).
  • Policy Synchronization (DocSync): Asserts agreement between markdown policy documents (shared/transliteration.md) and executable YAML rules.

Corpus data

The gem ships the policy rules only: the mora table, combinatorial rules, exonyms and the exceptions table.

Mode B additionally needs two files generated from a specific translation project — a lexicon of known Japanese terms and an allowlist of native Ukrainian vocabulary. These are not distributed, because they are one project's editorial research rather than transliteration policy.

Mode A (cyrillic, romaji) needs neither and works out of the box. Without them Mode B simply reports nothing, since it only ever rewrites tokens anchored to a known lexical item.

To use Mode B, generate the files and point the gem at them:

export YANAGI_DATA_DIR=/path/to/your/data
yanagi lexicon build --glossary /path/to/glossary.org

Installation

Add this line to your application's Gemfile:

gem 'yanagi'

Or reference via git repository:

gem 'yanagi', git: 'https://github.com/shogi-dojo/yanagi.git', tag: 'v0.1.0'

Ruby API Usage

Mode A: Transliteration

require 'yanagi'

# Kana to Cyrillic
Yanagi.cyrillic("しゅうさい")
# => #<Yanagi::Result text="шюсай" source=:derived confidence=1.0>

Yanagi.cyrillic("シュウサイ")
# => #<Yanagi::Result text="шюсай" source=:derived confidence=1.0>

# Exonyms
Yanagi.cyrillic("とうきょう")
# => #<Yanagi::Result text="Токіо" source=:exonym confidence=1.0>

# Kana to Modified Hepburn Romaji
Yanagi.romaji("しゅうさい")
# => "shuusai"

# From Romaji to Cyrillic
Yanagi.from_romaji("shuusai")
# => "шюсай"

Mode B: Prose Audit & Correction

# Scan files or directories
findings = Yanagi.audit(["path/to/chapter.org"], tier2: true, tier3: false)

# Apply approved findings
Yanagi::Audit.apply("audit/findings.yml")

Policy Agreement Check

sync = Yanagi.doc_sync(path: "shared/transliteration.md")
sync.synced? # => true
sync.diff    # => []

CLI Usage

# Romaji & Cyrillic generation
yanagi romaji しゅうさい
yanagi cyrillic しゅうさい
yanagi cyrillic しゅうさい --format json

# Prose auditing
yanagi audit books/meijin/translation/ua --format human
yanagi audit books/meijin/translation/ua --out audit/findings.yml

# Applying approved findings
yanagi apply audit/findings.yml

# Document synchronization & gold verification
yanagi doc-sync shared/transliteration.md
yanagi verify-gold

License

MIT License. Copyright (c) 2026 shogi-dojo.