getConstrainedTranslation(
    hash: PatternHash,
    tokenConstraints: TokenToConstraint,
  ): ?string {
    const constraintKeys = [];
    for (const token in this._tokenToMask) {
      constraintKeys.push([token, tokenConstraints[token] || '*']);
    }
    const constraintMap = this._getConstraintMapWithMemoization(hash);
    const aggregateKey = buildConstraintKey(constraintKeys);
    const translation = constraintMap[aggregateKey];
    if (!translation) {
      return null;
    }
    for (let ii = 0; ii < constraintKeys.length; ++ii) {
      const [token, constraint] = constraintKeys[ii];
      if (constraint === '*') {
        continue;
      }

      // If any of the constraints share the same translation as the wildcard
      // (default) entry at this level, don't add an entry to the table.  They
      // will be in the table under the '*' key.
      constraintKeys[ii] = [token, '*'];
      const wildKey = buildConstraintKey(constraintKeys);
      const wildTranslation = constraintMap[wildKey];
      if (wildTranslation === translation) {
        return null;
      }
      // Set the constraint back
      constraintKeys[ii] = [token, constraint];
    }
    return translation;
  }
Given a hash and restraints on the token variations, retrieve the
appropriate translation for our map.  A null entry is a signal
not to add the translation to the map, because it's already in
the map via its fallback ('*') keys.