1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

韓国で個人運営しているブラウザゲームサイトを 8 言語対応にした話(Python・Docker・無料 LLM 翻訳)

1
Last updated at Posted at 2026-10-17

はじめに

2026 年 9 月から私が個人で運営しているブラウザゲームプラットフォーム Yeoul Games(여울게임터) を、2026 年 10 月に 8 言語(韓国語・英語・日本語・ポルトガル語・スペイン語・ベトナム語・トルコ語・ドイツ語)対応にしました。もとは自作のブラウザゲームと韓国語のテキスト MUD を置くための場所でしたが、ほかの韓国の個人開発者もゲームを載せてくれるようになりました。URL に ?lang=ja などのクエリを付与するだけで、画面の文言が切り替わります。この記事では、実装の概要とハマった点、まだできていないことをまとめます。韓国人が翻訳の助けを借りて書いているので、不自然な日本語があればご容赦ください。

サイトについて

  • 運用環境: 自宅の Synology NAS 上の Docker で動かしている Python 製の Web サーバです。
  • ゲームの掲載方法: 開発者が HTML 1 ファイルをアップロードするか、自分のゲームページへのリンクを指定するだけです。
  • 遊ぶ側: 登録不要で、ブラウザだけでプレイできます。
  • 広告・手数料: ありません。掲載したゲームは私が韓国の SNS やコミュニティでも紹介しています。

多言語化の仕組み

  1. 画面文言の置き換え
    固定文言は JSON 形式の翻訳テーブルに登録し、全ての HTML 応答を翻訳フィルタで処理します。タグで区切られた文は「文全体」をキーとしてテーブルを参照し、対応する言語の文字列に差し替えます。

  2. ゲーム説明の自動翻訳
    開発者がゲームをアップロードするときに「ゲーム自体が対応している言語」にチェックを入れます。説明文はそのチェックに関係なく、ほかの 7 言語へ自動翻訳します。韓国語だけのゲームでも、何のゲームかは読めるようにするためです。翻訳は Groq の無料 API を利用し、バックグラウンドスレッドが元文のハッシュを比較して変更があれば再翻訳を実行します。

  3. 告知・規約の表示
    運営者が作成した告知や利用規約は韓国語原文を基準に機械翻訳した結果を表示し、原文へのリンクを付与しています。利用者の投稿は原文のまま掲載します。

  4. 言語別ゲームフィルタ
    韓国語以外の画面では「自分の言語で遊べるゲーム」だけを絞り込めます(開発者のチェックが基準です)。

コード(抜粋)

実際のコードから、説明文の自動翻訳まわりを抜き出しました(API キーの読み込みや保存処理は省略)。

import hashlib, json, re, time

def src_hash(src, fields):
    """翻訳対象の欄(名前・説明など)の指紋"""
    body = {f: canon(get_field(src, f)) for f in sorted(fields)}
    raw = json.dumps(body, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
    return hashlib.sha256(raw.encode("utf-8")).hexdigest()[:16]

def auto_ok(src, tr):
    """訳文に残ったハングルが原文にそのまま無ければ不合格(「半分韓国語のまま」を弾く)"""
    if isinstance(src, list):
        return isinstance(tr, list) and len(tr) == len(src) and all(auto_ok(a, b) for a, b in zip(src, tr))
    if not isinstance(tr, str) or not tr.strip():
        return False
    return all(w in str(src) for w in re.findall(r"[가-힣]+", tr))

def auto_loop():
    time.sleep(90)
    while True:
        r = auto_once()                 # 1 回に「ゲーム 1 本 × 言語グループ 1 つ」だけ訳す
        time.sleep(70 if r else 240)    # 無料枠の上限に当たらないよう間隔をあける

表示する側は、保存しておいた _src(訳したときの指紋)と今の原文の指紋が一致するときだけ訳文を使います。開発者が説明を書き換えると指紋が変わるので、新しい訳ができるまでは韓国語の原文がそのまま出ます。古い訳が残って内容がずれる、ということがありません。

ハマったところ

  • 無料 API の制限
    Groq の無料枠では 1 分あたりトークン上限に達すると HTTP 413(リクエストが大きすぎる)や 429(レート制限) が返ってきます。1 回に送る量を「ゲーム 1 本 × 言語グループ 1 つ」に小さく分け、max_tokens も抑え、リクエストの間を 70 秒(やることが無ければ 240 秒)あけることで回避しました。

  • 混在する韓国語
    機械翻訳の結果に韓国語が混在するケースが数件ありました。日本語訳の文の半分が韓国語のまま残っていた、というものです。最初は手で直していましたが、上の auto_ok のように「原文に無いハングルが訳文に残っていたら捨てる」チェックを入れてからは自動で弾けるようになりました。

まだできていないこと

  • 掲載している 42 本のゲームのほとんどは韓国の個人開発者の作品で、ゲーム内テキストは韓国語のままです。日本語で遊べるタグが付いたゲームはほぼ存在しません。
  • ゲーム本体の多言語化は行っておらず、対象は UI と説明文に限られます。
  • 機械翻訳にはまだ崩れがあります。

おわりに

日本語のブラウザゲームはまだほとんどないので、もし載せてもいいという方がいればうれしいです。掲載は無料で、HTML 1 ファイルのアップロードか、自分のゲームページへのリンクだけで済みます。説明文はほかの 7 言語に自動翻訳され、私が韓国の SNS・コミュニティでも紹介します。広告や手数料はありません。

もし機械翻訳で読みにくい箇所があれば教えていただけると助かります。
https://yeoulgame.com/?lang=ja&ref=qiita

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?