Powered by AppSignal & Oban Pro

日本語パスワードとローマ字出力

notebooks/i18n_japanese.livemd

日本語パスワードとローマ字出力

Mix.install([
  {:exk_passwd, "~> 0.2.0"}
])

The Romaji transform converts Hiragana and Katakana to keyboard-friendly ASCII. It does not perform Kanji readings or morphological analysis.

Load a kana dictionary

japanese_words = [
  "さくら", # cherry blossom
  "たいよう", # sun
  "うみ", # sea
  "やま", # mountain
  "かぜ", # wind
  "ほし", # star
  "つき", # moon
  "はな", # flower
  "みず", # water
  "そら", # sky
  "ゆき", # snow
  "あめ", # rain
  "ひかり", # light
  "こころ", # heart
  "ゆめ", # dream
  "コーヒー", # coffee
  "ファイル", # file
  "ウィンドウ", # window
  "パーティー", # party
  "チェック" # check
]

:ok = ExkPasswd.Dictionary.load_custom(:japanese_demo, japanese_words)
transform = %ExkPasswd.Transform.Romaji{}

Validate output and collisions

converted =
  Map.new(japanese_words, fn word ->
    {word, ExkPasswd.Transform.apply(transform, word, nil)}
  end)

unmapped = Enum.filter(converted, fn {_source, output} -> output =~ ~r/[^a-z]/ end)
collisions = converted |> Map.values() |> Enum.frequencies() |> Enum.filter(fn {_, n} -> n > 1 end)

%{converted: converted, unmapped: unmapped, collisions: collisions}

Run these checks against the complete application dictionary. Deterministic romanization can merge different source words, and those collisions reduce the reachable output space.

Generate passwords

config =
  ExkPasswd.Config.new!(
    dictionary: :japanese_demo,
    word_length: 2..6,
    word_length_bounds: 1..10,
    num_words: 3,
    separator: "-",
    digits: {2, 2},
    padding: %{char: "", before: 0, after: 0, to_length: 0},
    case_transform: :none,
    meta: %{transforms: [transform]}
  )

for _ <- 1..10, do: ExkPasswd.generate(config)

Inspect the actual output space

details = ExkPasswd.Entropy.calculate_seen_detailed(config)

%{
  word_entropy: Float.round(details.word_entropy, 2),
  digit_entropy: Float.round(details.digit_entropy, 2),
  total: Float.round(details.total, 2)
}

This 20-word list is an API demonstration, not a production dictionary. The calculation should guide claims about the example; memorability does not replace an adequate number of random choices.

Romanization checks

examples = [
  {"さくら", "sakura"},
  {"がっこう", "gakkou"},
  {"まっちゃ", "matcha"},
  {"きょう", "kyou"},
  {"しゃしん", "shashin"},
  {"さんぽ", "sampo"},
  {"しんぶん", "shimbun"},
  {"コーヒー", "koohii"},
  {"ファイル", "fairu"},
  {"パーティー", "paatii"},
  {"ウィンドウ", "windou"},
  {"チェック", "chekku"},
  {"ヴァイオリン", "vaiorin"}
]

for {source, expected} <- examples do
  actual = ExkPasswd.Transform.apply(transform, source, nil)
  {source, actual, actual == expected}
end

The implementation uses modified Hepburn conventions together with common Wāpuro keyboard spellings. Long Katakana vowels are duplicated in ASCII (コーヒーkoohii) rather than written with macrons.

Kanji limitation

alias ExkPasswd.Transform.Romaji

%{
  kana: ExkPasswd.Transform.apply(transform, "さくら", nil),
  kanji_passes_through: ExkPasswd.Transform.apply(transform, "桜", nil),
  detects_kanji: Romaji.contains_kanji?("日本語")
}

Use kana-only entries when ASCII output is required. Particles such as は and を are romanized by character value (ha, wo); sentence-level grammatical readings would require context the transform does not have.