翻訳プラットフォームによっては、翻訳キーに使える文字種や長さが制限されていることがある。user.profile.edit.title のような階層的なIDをそのまま使えないケースだ。ビルド時にIDをハッシュ化して短縮しておけば、プラットフォームの制約を回避できる。
コード
function toHex(buffer: ArrayBuffer): string { return [...new Uint8Array(buffer)] .map((b) => b.toString(16).padStart(2, '0')) .join('')}
export function createHashStore(alg: string = 'SHA-256') { const contextHash = new Map<string, string>() const msgIdHash = new Map<string, string>()
async function digestContext(context: string): Promise<string> { const data = new TextEncoder().encode(context) const buf = await crypto.subtle.digest(alg, data) return toHex(buf).slice(0, 7) }
async function digestMsgId(msgId: string): Promise<string> { const data = new TextEncoder().encode(msgId) const buf = await crypto.subtle.digest(alg, data) return toHex(buf).slice(0, 10) }
async function saveContext(context: string): Promise<string> { const cached = contextHash.get(context) if (cached) return cached const hash = await digestContext(context) contextHash.set(context, hash) return hash }
async function saveMsgId(msgId: string): Promise<string> { const cached = msgIdHash.get(msgId) if (cached) return cached const hash = await digestMsgId(msgId) msgIdHash.set(msgId, hash) return hash }
return { contextHash, msgIdHash, saveContext, saveMsgId }}Web Crypto API(crypto.subtle.digest)を使っているためブラウザ・Node.js・Deno・Bun など実行環境を問わない。alg には 'SHA-1'、'SHA-256'、'SHA-384'、'SHA-512' が指定できる。
解説
saveContext と saveMsgId はそれぞれ Map にキャッシュしながらハッシュを返す。同じ入力に対して何度呼んでも計算は初回のみ。コンテキスト(名前空間)は先頭 7 文字、メッセージ ID は先頭 10 文字に切り詰める。コンテキストは数が少なく衝突リスクが低いため短くしている。
応用
ビルドプラグイン(Vite プラグイン、独自のコード変換処理)に組み込んで、ソース中のメッセージ ID をハッシュに置き換える。実行時は元の文字列ではなくハッシュをキーとして翻訳テーブルを参照する構成になる。
アルゴリズムを変えたい場合は createHashStore の引数に別の alg を渡す。切り詰め長は slice の引数で調整する。
実務メモ
このスニペットは、TypeScript、JavaScript、i18n の周辺で同じ操作や判定を毎回書きたくない時に向く。小さな補助として切り出しておくと、呼び出し側では意図だけを追いやすい。
逆に、分岐や前提条件が増えて責務が膨らむなら、1本のスニペットに詰め込まない方がよい。手順と helper を分けるか、役割ごとに切り出す方が保守しやすい。
hsb.horse