Skip to main content

How string hashes are calculated

Learn how string hashes are created in Transifex.

Written by Transifex

Transifex identifies each string by a string hash, so you can match a translation to its source string. The hash is the md5 digest of the key and the context, joined with a colon, as a hexadecimal string. If a string has no context, use an empty string.

Terms used here: the key is the identifier of the string in your file (for example hello_world), and the context is the optional context value of the string.

Calculate the hash in Python and JavaScript

The input to md5 is always key:context, encoded as UTF-8. With no context, it is key: (the key, a colon and nothing after it).

In Python 3:

from hashlib import md5


def string_hash(key, context=None):
"""Return the Transifex string hash for a key and an optional context."""
if isinstance(context, list):
# Several context values: key and all values, joined with colons.
keys = [key] + context if context else [key, '']
elif context is None or context == 'None':
keys = [key, '']
else:
keys = [key, context]
return md5(':'.join(keys).encode('utf-8')).hexdigest()


print(string_hash('hello_world'))
print(string_hash('hello_world', 'Greeting on the home page'))
print(string_hash('hello_world', ['a', 'b']))

Output:

ea52ef516193f5144e791df71474bd41
82da6346ab22bb292228b004e36eb365
46915ee28161fdc962b2ef59c59c1319

In JavaScript (Node.js):

const { createHash } = require('crypto');

function stringHash(key, context = '') {
// The context is an empty string when the string has none.
const parts = Array.isArray(context)
? (context.length ? [key, ...context] : [key, ''])
: [key, context || ''];
return createHash('md5').update(parts.join(':'), 'utf8').digest('hex');
}

console.log(stringHash('hello_world'));
console.log(stringHash('hello_world', 'Greeting on the home page'));
console.log(stringHash('hello_world', ['a', 'b']));

Output:

ea52ef516193f5144e791df71474bd41
82da6346ab22bb292228b004e36eb365
46915ee28161fdc962b2ef59c59c1319

Both functions return the same hash for the same input.


String hash exceptions

  1. JSON and RequireJS need an extra step before hashing: escape every backslash (\) and dot (.) in the key. Escape backslashes first, then dots. Nested JSON (objects and lists) also changes the key, because the key is the path to the string. The JSON article has a full example program and explanation.

  2. For PO, the key is the msgid, or for plural entries the msgid and msgid_plural joined with a colon. Escape every backslash (\) and colon (:) inside the msgid and msgid_plural with a backslash first, then join them. The msgctxt is the context and is not escaped.

  3. In Python 3, a str is already Unicode and md5(...encode('utf-8')) handles any character. If your key is a bytes object, decode it first: key.decode('utf-8').

Escaping example for JSON, in Python 3:

from hashlib import md5


def escape(key):
key = key.replace('\\', r'\\') # backslash first
return key.replace('.', r'\.')


key = r'Version 1.0\beta'
print(escape(key))
print(md5(':'.join([escape(key), '']).encode('utf-8')).hexdigest())

Output:

Version 1\.0\\beta
2b8504ca253f9e36f75b61c4001789af


💡 Tip

Looking for more help? Get support from our Transifex Community Forum!

Find answers or post to get help from Transifex Support and our Community.

Did this answer your question?