logo hsb.horse
← Back to snippets index

Snippets

Build-time Message ID Hash Store

A TypeScript function that hashes and shortens message IDs and contexts at build time. Useful when a target platform restricts allowed translation keys.

Published: Updated:

Some translation platforms restrict the character set or length of translation keys. IDs like user.profile.edit.title may not be accepted as-is. Hashing and shortening IDs at build time sidesteps these constraints.

Code

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 }
}

Using the Web Crypto API (crypto.subtle.digest) makes this universal — it runs in browsers, Node.js, Deno, and Bun without modification. Valid values for alg are 'SHA-1', 'SHA-256', 'SHA-384', and 'SHA-512'.

How It Works

saveContext and saveMsgId return hashes while caching results in a Map. For the same input, the hash is computed only once. Contexts (namespaces) are trimmed to the first 7 characters, message IDs to 10. Contexts tend to be fewer in number and carry less collision risk, so a shorter prefix is sufficient.

Usage in Practice

Integrate into a build plugin (Vite plugin, custom code transform) to replace message IDs in source code with their hashes. At runtime, the translation table is keyed by hash rather than the original string.

To change the hashing algorithm, pass a different alg to createHashStore. Adjust truncation length via the slice argument.