DEV Community

Cover image for Building Multilingual Financial Apps: A Developer's Guide to i18n for FinTech
Diogo Heleno
Diogo Heleno

Posted on • Originally published at m21global.com

Building Multilingual Financial Apps: A Developer's Guide to i18n for FinTech

Building Multilingual Financial Apps: A Developer's Guide to i18n for FinTech

Internationalizing financial applications comes with unique challenges that go beyond typical i18n work. While most apps worry about translating button labels and error messages, financial software must handle regulatory terminology, number formatting, and compliance requirements that vary dramatically across markets.

This guide covers the technical considerations for developers building financial apps that need to work across Portuguese, Spanish, and English markets.

Why Financial i18n Is Different

Financial applications deal with regulated terminology where precision matters legally. Unlike e-commerce apps where "Add to Cart" can be localized creatively, financial terms like "EBITDA" or "Balance Sheet" have specific regulatory translations that must be used consistently.

Three technical challenges make financial i18n complex:

Regulatory context switching: The same financial concept may require different terminology depending on the regulatory framework. "Goodwill" in US GAAP vs IFRS contexts needs different handling in your translation keys.

Regional variations within languages: Spanish for Spain vs Latin America isn't just about accent marks. The accounting standards and terminology differ significantly, requiring separate localization branches.

Number formatting with legal implications: A misformatted financial figure isn't just a UX issue—it can create legal liability.

Setting Up Your Translation Architecture

Start with a namespace structure that accounts for regulatory context:

// en/financial.json
{
  "ifrs": {
    "balance_sheet": "Balance Sheet",
    "goodwill": "Goodwill",
    "impairment": "Impairment"
  },
  "us_gaap": {
    "balance_sheet": "Balance Sheet",
    "goodwill": "Goodwill", 
    "impairment": "Impairment"
  }
}

// pt/financial.json
{
  "ifrs": {
    "balance_sheet": "Balanço",
    "goodwill": "Goodwill",
    "impairment": "Imparidade"
  },
  "snc": {
    "balance_sheet": "Balanço",
    "goodwill": "Activos intangíveis adquiridos",
    "impairment": "Imparidade"
  }
}
Enter fullscreen mode Exit fullscreen mode

This structure lets you switch terminology based on the regulatory context your user operates under:

function getFinancialTerm(term, locale, framework) {
  return i18n.t(`financial.${framework}.${term}`, { lng: locale });
}

// Usage
const balanceSheetLabel = getFinancialTerm('balance_sheet', 'pt', 'ifrs');
// Returns: "Balanço"
Enter fullscreen mode Exit fullscreen mode

Handling Number Formatting

Financial numbers need locale-specific formatting that goes beyond JavaScript's built-in Intl.NumberFormat. Different regions have different conventions for thousands separators and decimal points:

class FinancialFormatter {
  constructor(locale, currency = 'EUR') {
    this.locale = locale;
    this.currency = currency;

    // Configure formatters based on target market
    this.formatters = {
      'pt-PT': new Intl.NumberFormat('pt-PT', {
        style: 'currency',
        currency: this.currency,
        minimumFractionDigits: 2
      }),
      'es-ES': new Intl.NumberFormat('es-ES', {
        style: 'currency', 
        currency: this.currency,
        minimumFractionDigits: 2
      }),
      'en-GB': new Intl.NumberFormat('en-GB', {
        style: 'currency',
        currency: this.currency,
        minimumFractionDigits: 2
      })
    };
  }

  formatCurrency(amount) {
    return this.formatters[this.locale].format(amount);
  }

  formatPercentage(value) {
    const formatter = new Intl.NumberFormat(this.locale, {
      style: 'percent',
      minimumFractionDigits: 2,
      maximumFractionDigits: 2
    });
    return formatter.format(value / 100);
  }
}

// Usage
const ptFormatter = new FinancialFormatter('pt-PT');
console.log(ptFormatter.formatCurrency(1500.50)); 
// Output: "1 500,50 €"

const gbFormatter = new FinancialFormatter('en-GB');
console.log(gbFormatter.formatCurrency(1500.50));
// Output: "€1,500.50"
Enter fullscreen mode Exit fullscreen mode

Managing Financial Acronyms

Financial documents are full of acronyms that may or may not translate. Some (like EBITDA) stay the same across languages, others need localization:

const acronymMap = {
  'en': {
    'P&L': 'Profit & Loss',
    'EBITDA': 'EBITDA',
    'SNC': 'SNC (Portuguese Accounting Standards)'
  },
  'pt': {
    'P&L': 'Demonstração de Resultados',
    'EBITDA': 'EBITDA', 
    'SNC': 'Sistema de Normalização Contabilística'
  },
  'es': {
    'P&L': 'Cuenta de Resultados',
    'EBITDA': 'EBITDA',
    'SNC': 'SNC (Normas Contables Portuguesas)'
  }
};

function expandAcronym(acronym, locale) {
  return acronymMap[locale][acronym] || acronym;
}
Enter fullscreen mode Exit fullscreen mode

Building a Glossary Management System

For financial apps, maintaining terminology consistency is critical. Build a glossary management system that your translators and compliance team can both access:

class FinancialGlossary {
  constructor() {
    this.terms = new Map();
    this.loadGlossary();
  }

  async loadGlossary() {
    // Load from your preferred data source
    const glossaryData = await fetch('/api/financial-glossary').then(r => r.json());

    glossaryData.forEach(entry => {
      this.terms.set(entry.id, {
        en: entry.en_term,
        pt: entry.pt_term,
        es: entry.es_term,
        context: entry.regulatory_context,
        notes: entry.usage_notes
      });
    });
  }

  getTerm(termId, locale, context = 'general') {
    const entry = this.terms.get(termId);
    if (!entry) return termId;

    // Return context-specific translation if available
    if (entry.context && entry.context[context]) {
      return entry.context[context][locale] || entry[locale];
    }

    return entry[locale] || termId;
  }

  validateTranslation(termId, proposedTranslation, locale) {
    const officialTerm = this.getTerm(termId, locale);
    return officialTerm === proposedTranslation;
  }
}
Enter fullscreen mode Exit fullscreen mode

Testing Your Financial i18n

Financial i18n requires more rigorous testing than typical applications. Create test suites that verify:

describe('Financial Translation Tests', () => {
  test('consistent terminology across document', () => {
    const document = generateFinancialReport('pt', 'ifrs');
    const balanceSheetMentions = document.match(/balanço/gi) || [];
    const inconsistentTerms = document.match(/folha de balanço/gi) || [];

    expect(balanceSheetMentions.length).toBeGreaterThan(0);
    expect(inconsistentTerms.length).toBe(0);
  });

  test('number formatting matches regulatory requirements', () => {
    const formatter = new FinancialFormatter('pt-PT');
    expect(formatter.formatCurrency(1500.50)).toBe('1 500,50 €');
    expect(formatter.formatCurrency(1500.50)).not.toBe('1.500,50€');
  });

  test('regulatory acronyms are properly contextualized', () => {
    const snc_pt = expandAcronym('SNC', 'pt');
    const snc_en = expandAcronym('SNC', 'en');

    expect(snc_pt).toContain('Sistema de Normalização');
    expect(snc_en).toContain('Portuguese Accounting');
  });
});
Enter fullscreen mode Exit fullscreen mode

Tools and Libraries

For financial i18n, consider these specialized tools:

  • react-intl or vue-i18n for framework integration
  • date-fns with locale support for financial date formatting
  • big.js or decimal.js for precise financial calculations that avoid floating-point errors
  • Phrase or Lokalise for translation management with approval workflows

Working with Financial Translators

Provide your translation team with technical context they need:

  • Regulatory framework (IFRS, US GAAP, SNC, etc.)
  • Target market (Portugal vs Brazil for Portuguese, Spain vs LATAM for Spanish)
  • Document type (annual report vs prospectus vs internal memo)
  • Existing terminology databases

A detailed exploration of financial terminology differences across these languages is available in this comprehensive guide to financial terminology in Portuguese, English, and Spanish.

Conclusion

Financial i18n requires more precision than typical application localization. The combination of regulatory requirements, regional variations, and legal implications means developers need structured approaches to terminology management, number formatting, and translation validation.

Start with a solid namespace structure, build in regulatory context from the beginning, and create robust testing for terminology consistency. The extra effort pays off when your app can confidently operate across different financial markets without compliance issues.

Top comments (0)