Internationalization
Overview

Internationalization (i18n)

TimberCloud provides comprehensive internationalization support, allowing you to operate globally with proper currency formatting, locale-specific displays, and regional configurations.

Overview

Our internationalization system supports:

  • 135+ Currencies: Full ISO 4217 currency code support via Stripe integration
  • 27+ Locales: Regional date, number, and currency formatting
  • 193 Countries: Complete country database with automatic currency detection
  • Regional Formats: Dates, numbers, addresses, phone numbers, and postal codes
  • Tax Variations: Country-specific tax labels (VAT, GST, Sales Tax, etc.)
  • Measurement Units: Automatic imperial/metric switching based on region
  • Payment Processing: Multi-currency Stripe integration with zero-decimal support

Quick Setup

Step 1: Configure Company Locale

  1. Navigate to SettingsCompanyLocale & Currency Settings
  2. Select your country from the dropdown
  3. Currency and locale are automatically detected based on country
  4. Review the format preview (date, number, currency display)
  5. Click "Save Changes"

Step 2: Review Currency Settings

  • Lock to Country Currency: Enable to automatically sync currency with country
  • Manual Currency: Disable the lock to select a different currency
  • The currency symbol is automatically set based on your selection

Supported Locales

TimberCloud supports 27 locales with full formatting capabilities:

Americas

LocaleNameDate FormatNumber Format
en-USEnglish (United States)MM/DD/YYYY1,234.56
en-CAEnglish (Canada)DD/MM/YYYY1,234.56
fr-CAFrench (Canada)DD/MM/YYYY1 234,56
es-MXSpanish (Mexico)DD/MM/YYYY1,234.56
pt-BRPortuguese (Brazil)DD/MM/YYYY1.234,56

Europe

LocaleNameDate FormatNumber Format
en-GBEnglish (United Kingdom)DD/MM/YYYY1,234.56
de-DEGerman (Germany)DD.MM.YYYY1.234,56
fr-FRFrench (France)DD/MM/YYYY1 234,56
es-ESSpanish (Spain)DD/MM/YYYY1.234,56
it-ITItalian (Italy)DD/MM/YYYY1.234,56
pt-PTPortuguese (Portugal)DD/MM/YYYY1.234,56
nl-NLDutch (Netherlands)DD-MM-YYYY1.234,56
sv-SESwedish (Sweden)YYYY-MM-DD1 234,56
no-NONorwegian (Norway)DD.MM.YYYY1 234,56
da-DKDanish (Denmark)DD-MM-YYYY1.234,56
fi-FIFinnish (Finland)DD.MM.YYYY1 234,56
pl-PLPolish (Poland)DD.MM.YYYY1 234,56
ru-RURussian (Russia)DD.MM.YYYY1 234,56
tr-TRTurkish (Turkey)DD.MM.YYYY1.234,56

Asia-Pacific

LocaleNameDate FormatNumber Format
en-AUEnglish (Australia)DD/MM/YYYY1,234.56
ja-JPJapanese (Japan)YYYY/MM/DD1,234.56
zh-CNChinese (China)YYYY/MM/DD1,234.56
ko-KRKorean (South Korea)YYYY.MM.DD1,234.56

Middle East

LocaleNameDate FormatNumber Format
ar-SAArabic (Saudi Arabia)DD/MM/YYYY١٬٢٣٤٫٥٦
he-ILHebrew (Israel)DD/MM/YYYY1,234.56
hi-INHindi (India)DD/MM/YYYY1,23,456.78

Currency Support

Standard Currencies (2 Decimals)

Most currencies use two decimal places:

  • USD - $1,234.56 (US Dollar)
  • EUR - €1.234,56 (Euro)
  • GBP - £1,234.56 (British Pound)
  • CAD - C$1,234.56 (Canadian Dollar)
  • AUD - A$1,234.56 (Australian Dollar)

Zero-Decimal Currencies

These currencies have no decimal places:

  • JPY - ¥1,234 (Japanese Yen)
  • KRW - ₩1,234 (South Korean Won)
  • VND - ₫1,234 (Vietnamese Dong)
  • HUF - 1,234 Ft (Hungarian Forint)
  • CLP - $1,234 (Chilean Peso)
  • TWD - NT$1,234 (New Taiwan Dollar)

Three-Decimal Currencies

These currencies use three decimal places:

  • BHD - BD 1.234 (Bahraini Dinar)
  • KWD - KD 1.234 (Kuwaiti Dinar)
  • OMR - OMR 1.234 (Omani Rial)
  • JOD - JD 1.234 (Jordanian Dinar)

Special Formatting

  • Indian Rupee: ₹12,34,567.89 (lakh/crore grouping system)
  • Swiss Franc: CHF 1'234.56 (apostrophe separator)
  • Arabic Numerals: ١٬٢٣٤٫٥٦ (Eastern Arabic numerals for ar-SA)

Regional Configurations

Tax Labels

Tax terminology varies by country:

RegionTax Label
United StatesSales Tax
CanadaGST/PST
European UnionVAT
United KingdomVAT
AustraliaGST
GermanyMwSt (VAT)
JapanConsumption Tax

Address Formats

United States

Street Address
City, State ZIP
Country

United Kingdom

Street Address
City
County
Postcode
Country

Japan

〒 Postal Code
Prefecture
City
Street Address

Postal Code Validation

Country-specific postal code formats are validated automatically:

CountryFormatExample
US5 digits or 5+412345, 12345-6789
CanadaLetter-Number alternatingK1A 0B1
UKAlphanumericSW1A 1AA
Germany5 digits10115
Japan3-4 digits100-0001
Australia4 digits2000
Netherlands4 digits + 2 letters1234 AB

Phone Number Formats

International phone formatting by region:

CountryFormat
US/Canada+1 (555) 123-4567
UK+44 20 1234 5678
Germany+49 30 12345678
Japan+81 3-1234-5678
Australia+61 2 1234 5678

Measurement Units

Automatic unit system selection:

CountrySystemLengthWeight
United StatesImperialincheslb
United KingdomMixedmmkg
CanadaMetriccmkg
AustraliaMetriccmkg
Most OthersMetriccmkg

For Developers

Currency Formatting Hook

import { useCurrencyFormatter } from '@/hooks/useCurrencyFormatter';
 
function PriceDisplay({ company, amount }) {
  const formatter = useCurrencyFormatter(company);
  
  return (
    <div>
      {/* Format as currency: $1,234.56 */}
      <p>{formatter.format(amount)}</p>
      
      {/* Format number only: 1,234.56 */}
      <p>{formatter.formatNumber(amount)}</p>
      
      {/* Convert to Stripe units (cents) */}
      <p>Stripe amount: {formatter.toSmallestUnit(amount)}</p>
    </div>
  );
}

Date Formatting Hook

import { useDateFormatter } from '@/hooks/useDateFormatter';
 
function DateDisplay({ date }) {
  const { formatDate, formatRelative, formatCalendar } = useDateFormatter();
  
  return (
    <div>
      {/* Locale-aware short date: 12/31/2024 or 31/12/2024 */}
      <p>{formatDate(date, 'date.short')}</p>
      
      {/* Medium format: Dec 31, 2024 */}
      <p>{formatDate(date, 'date.medium')}</p>
      
      {/* Relative: 2 days ago */}
      <p>{formatRelative(date)}</p>
      
      {/* Calendar: Yesterday at 3:30 PM */}
      <p>{formatCalendar(date)}</p>
    </div>
  );
}

i18n Utility Functions

import i18n from '@/util/i18n';
 
// Get currency for a country
const currency = i18n.getCurrencyByCountry('GB');
// { code: 'GBP', symbol: '£', name: 'Pound Sterling', digits: 2 }
 
// Format currency with locale
const formatted = i18n.formatCurrency(1234.56, 'EUR', 'de-DE');
// "1.234,56 €"
 
// Get decimal places for Stripe integration
const decimals = i18n.getDecimalPlaces('JPY'); // 0
 
// Convert to Stripe smallest unit
const stripeAmount = i18n.toStripeCurrencyUnit(100, 'USD'); // 10000
const stripeAmountJPY = i18n.toStripeCurrencyUnit(100, 'JPY'); // 100
 
// Validate postal code
const isValid = i18n.validatePostalCode('SW1A 1AA', 'GB'); // true
 
// Get country info
const country = i18n.getCountryByCode('US');
// { code: 'US', name: 'United States', currencies: ['USD'], ... }

Stripe Integration

Multi-Currency Payments

TimberCloud integrates with Stripe for payment processing:

  • 135+ Currencies: Process payments in customer's preferred currency
  • Zero-Decimal Handling: Automatic conversion for currencies like JPY, KRW
  • Three-Decimal Support: Proper handling for BHD, KWD, OMR
  • Settlement Options: Receive funds in your base currency

Currency Unit Conversion

All Stripe amounts are handled in the smallest currency unit:

// USD: $12.34 → 1234 cents
i18n.toStripeCurrencyUnit(12.34, 'USD'); // 1234
 
// JPY: ¥100 → 100 (no conversion needed)
i18n.toStripeCurrencyUnit(100, 'JPY'); // 100
 
// KWD: KD 1.234 → 1234 fils
i18n.toStripeCurrencyUnit(1.234, 'KWD'); // 1234

Company Schema Fields

The following fields control internationalization at the company level:

FieldTypeDefaultDescription
country_codestring(2)"US"ISO 3166-1 alpha-2 country code
currencystring(3)"USD"ISO 4217 currency code
currency_symbolstring(5)"$"Currency display symbol
default_localestring(10)"en-US"BCP 47 locale identifier

Best Practices

  1. Always Use Formatters: Use useCurrencyFormatter and useDateFormatter hooks instead of manual formatting
  2. Store Raw Values: Store amounts in database as raw numbers, format only for display
  3. ISO Standards: Use ISO country codes (US, GB) and currency codes (USD, GBP)
  4. Test Edge Cases: Verify formatting with zero-decimal currencies and large numbers
  5. Stripe Compatibility: Always convert to smallest unit before sending to Stripe
  6. Locale Consistency: Match currency to locale for proper formatting

Troubleshooting

Currency Display Issues

  • Verify currency and currency_symbol are set on company
  • Check that currency code is valid ISO 4217
  • Ensure locale supports the selected currency

Date Format Mismatches

  • Confirm default_locale is set correctly
  • Verify moment.js locale is loaded for the target locale
  • Check browser timezone settings for date/time discrepancies

Postal Code Validation Failing

  • Ensure country code is correctly set
  • Check that postal code matches the expected format for that country
  • Spaces and formatting may vary by region

Number Parsing Issues

  • Different locales use different decimal separators (. vs ,)
  • Use formatter.parse() to correctly parse locale-formatted numbers
  • Always normalize to standard format before calculations