← back

Death to imperial units

Imperial units are stupid.

They're very stupid as there is no pattern or link between the units and sub-units. Why are there 12 inches in a foot? and why 3 feet in a yard? This system just doesn't make sense and is much harder to use than the metric system.

Another disadvantage is that the use of several unit systems is moronic and can only bring conversion mistakes and crash a $604 million craft with a single mistake. This isn't an issue with the imperial system itself, but it's a clear sign that a single system must be chosen over the other, and the historical advantages of the imperial system (namely always having a ruler with you because your body was the ruler) aren't valid anymore.

To avoid any situation in which i might have took at those horrific units and appreciate the simplicity of SI units, i created an extension that replaces all imperial units by their metric equivalents.

This extension can replace this:

13.2 in

by this:

~~13.2 in~~ (33.53 cm)

The extension

Creating an extension that replaces some text by another is really easy:

function replaceText(node) {
    if (node.nodeType === Node.TEXT_NODE) {
        node.textContent = node.textContent.replace(/\bthe\b/gi, '<most common word in the english language>');
    } else {
        for (let child of node.childNodes) {
            replaceText(child);
        }
    }
}

replaceText(document.body);

const observer = new MutationObserver(mutations => {
    mutations.forEach(mutation => {
        mutation.addedNodes.forEach(node => {
            if (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.TEXT_NODE) {
                replaceText(node);
            }
        });
    });
});

observer.observe(document.body, {
    childList: true,
    subtree: true
});

This is most of the extension done already! Now we just need to have a way to detect and translate all imperial units, which is relatively trivial with the power of regex expressions:

// conversion ratios
const conversions = {
  // distance
  'mile': { ratio: 1.60934, unit: 'km', plural: 'miles' },
  'foot': { ratio: 0.3048, unit: 'm', plural: 'feet' },
  'feet': { ratio: 0.3048, unit: 'm', plural: 'feet' },
  'inch': { ratio: 2.54, unit: 'cm', plural: 'inches' },
  'yard': { ratio: 0.9144, unit: 'm', plural: 'yards' },

  // weight
  'pound': { ratio: 0.453592, unit: 'kg', plural: 'pounds' },
  'ounce': { ratio: 28.3495, unit: 'g', plural: 'ounces' },
  'oz': { ratio: 28.3495, unit: 'g', plural: 'oz' },
  'lb': { ratio: 0.453592, unit: 'kg', plural: 'lbs' },

  // volume
  'gallon': { ratio: 3.78541, unit: 'L', plural: 'gallons' },
  'quart': { ratio: 0.946353, unit: 'L', plural: 'quarts' },
  'pint': { ratio: 0.473176, unit: 'L', plural: 'pints' },

  // temperature (special case)
  'fahrenheit': { ratio: null, unit: '°C', plural: 'fahrenheit' },
  '°f': { ratio: null, unit: '°C', plural: '°f' },
};

function convertImperial(text) {
  // pattern: number + optional space + unit
  const pattern = /(\d+(?:\.\d+)?)\s*(miles?|feet|ft|inches?|in|yards?|yd|pounds?|lbs?|ounces?|oz|gallons?|gal|quarts?|qt|pints?|pt|°f|fahrenheit)\b/gi;

  return text.replace(pattern, (match, num, unit) => {
    const unitLower = unit.toLowerCase();
    let conversion = conversions[unitLower];

    // handle abbreviations
    if (unitLower === 'ft') conversion = conversions['foot'];
    if (unitLower === 'in') conversion = conversions['inch'];
    if (unitLower === 'yd') conversion = conversions['yard'];
    if (unitLower === 'gal') conversion = conversions['gallon'];
    if (unitLower === 'qt') conversion = conversions['quart'];
    if (unitLower === 'pt') conversion = conversions['pint'];

    if (!conversion) return match;

    const numVal = parseFloat(num);
    let converted;

    // special case for fahrenheit
    if (unitLower === '°f' || unitLower === 'fahrenheit') {
      converted = ((numVal - 32) * 5 / 9).toFixed(1);
    } else {
      converted = (numVal * conversion.ratio).toFixed(2);
    }

    return `${match} (= ${converted} ${conversion.unit})`;
  });
}

function replaceText(node) {
  if (node.nodeType === Node.TEXT_NODE) {
    const newText = convertImperial(node.textContent);
    if (newText !== node.textContent) {
      node.textContent = newText;
    }
  } else if (node.nodeType === Node.ELEMENT_NODE) {
    // skip script, style, and input elements
    if (['SCRIPT', 'STYLE', 'INPUT', 'TEXTAREA'].includes(node.tagName)) {
      return;
    }
    for (let child of node.childNodes) {
      replaceText(child);
    }
  }
}

replaceText(document.body);

// watch for dynamic content
const observer = new MutationObserver(mutations => {
  mutations.forEach(mutation => {
    mutation.addedNodes.forEach(node => {
      if (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.TEXT_NODE) {
        replaceText(node);
      }
    });
  });
});

observer.observe(document.body, {
  childList: true,
  subtree: true
});

If you want to eradicate all imperial units from your web browsing, you can get the extension here.

PS:

this is what the beginning of this text looks like with the extension on: