logo hsb.horse
← スニペット一覧に戻る

Snippets

ビルド時メッセージIDハッシュストア

ビルド時にメッセージIDとコンテキストをハッシュ化して短縮・正規化するTypeScript関数。翻訳キーに文字種制限があるプラットフォームで役立つ。

公開日: 更新日:

翻訳プラットフォームによっては、翻訳キーに使える文字種や長さが制限されていることがある。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' が指定できる。

解説

saveContextsaveMsgId はそれぞれ Map にキャッシュしながらハッシュを返す。同じ入力に対して何度呼んでも計算は初回のみ。コンテキスト(名前空間)は先頭 7 文字、メッセージ ID は先頭 10 文字に切り詰める。コンテキストは数が少なく衝突リスクが低いため短くしている。

応用

ビルドプラグイン(Vite プラグイン、独自のコード変換処理)に組み込んで、ソース中のメッセージ ID をハッシュに置き換える。実行時は元の文字列ではなくハッシュをキーとして翻訳テーブルを参照する構成になる。

アルゴリズムを変えたい場合は createHashStore の引数に別の alg を渡す。切り詰め長は slice の引数で調整する。

実務メモ

このスニペットは、TypeScript、JavaScript、i18n の周辺で同じ操作や判定を毎回書きたくない時に向く。小さな補助として切り出しておくと、呼び出し側では意図だけを追いやすい。

逆に、分岐や前提条件が増えて責務が膨らむなら、1本のスニペットに詰め込まない方がよい。手順と helper を分けるか、役割ごとに切り出す方が保守しやすい。