Search code examples
internationalizationi18next

When using i18Next, switch between "a" and "an" depending on the first letter in an interpolated variable


I'm using i18Next. I'd like the word "A"/"An" preceding an interpolated variable to switch based on the first letter of the interpolated variable.

Here is an example localized key:value pair:

"error": "A {{tagName}} html tag cannot be within a "p" tag."

There are two scenarios: 1) tagName can be "a"(or some tag starting with a vowel, generally) in which case the returned localized and interpolated string should be:

An "h1" html tag cannot be within a "p" tag.

OR:

2) tagName can be "section"(or some tag starting with a consonant) in which case the returned localized and interpolated string should be:

A "section" html tag cannot be within a "p" tag.

Thoughts on the best way to do this?


Solution

  • The first part of this is that this "a vs. an" issue is specific to English only and so it makes sense that i18next doesn't have a specific answer for it.

    However, i18next can handle it in the following way using the "format" function as part of the i18n interpolation process.

    Documentation for the solution below is here: http://i18next.com/translate/formatting/

    Here is the key that you would use for this implementation:

    "sample-key": "{{tag, en-handle-an-capitalized}} <{{tag}}> tag always needs a closing </{{tag}}> tag. Writing <{{tag}}/> is not allowed.",
    

    "en-handle-an"/"en-handle-an-capitalized" mean the following:

    • "en"-that this is only appropriate for "en" locale strings
    • "handle-an"-what it is doing
    • "capitalized"- that the A or An should/should not be capitalized.

    Here is the i18n initialization(including the helper function that is called by the format step of interpolation process if the format key and language are matched):

    const getVariationOfAOrAn = function(value, capitalize) {
      const letters = ['a','e','i','o','u','h'];
      let firstLetter = value.substring(0,1);
      let correctWordForm = '';
      if (letters.find(function(l) {
        return firstLetter === l;
      })) {
        correctWordForm = capitalize ? 'An' : 'an';
      } else {
        correctWordForm = capitalize ? 'A' : 'a';
      }
    
      return correctWordForm;
    }
    
    export default function() {
      init({
        fallbackLng: 'en',
        resources,
        interpolation: {
          format: function(value, format, lng) {
            if (format === 'en-handle-an') return (!lng || lng === 'en') ? getVariationOfAOrAn(value, false) : '';
            if (format === 'en-handle-an-capitalized') return (!lng || lng === 'en') ? getVariationAOrAn(value, true) : '';
            return value;
          }
       }
      });
    }