All files / utils i18n.js

100% Statements 31/31
96.66% Branches 29/30
100% Functions 6/6
100% Lines 30/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127        1x                                         18x                 12x 2x     10x 4x       6x 6x 2x     8x                       13x 2x       11x 4x       7x 2x       5x 3x       2x 1x       1x 1x                   18x 5x     13x 6x     7x                   7x 7x     1x                
/**
 * I18n utilities for multilingual support
 */
 
const SUPPORTED_LANGUAGES = [
  'en', // English
  'fr', // French
  'es', // Spanish
  'de', // German
  'it', // Italian
  'pt', // Portuguese
  'nl', // Dutch
  'pl', // Polish
  'ru', // Russian
  'ja', // Japanese
  'zh', // Chinese (Simplified)
  'ar' // Arabic
]
 
/**
 * Validate if a language code is supported
 * @param {string} lang - Language code to validate
 * @returns {boolean} True if language is supported
 */
function isValidLanguage(lang) {
  return SUPPORTED_LANGUAGES.includes(lang)
}
 
/**
 * Validate multilingual value structure
 * @param {any} value - Value to validate
 * @returns {boolean} True if value is valid multilingual object or string
 */
function isValidMultilingualValue(value) {
  if (typeof value === 'string') {
    return true // Backward compatibility
  }
 
  if (typeof value !== 'object' || value === null) {
    return false
  }
 
  // Check if all keys are valid language codes
  const keys = Object.keys(value)
  if (keys.length === 0) {
    return false
  }
 
  return keys.every((key) => isValidLanguage(key))
}
 
/**
 * Get value in specific language with fallback
 * @param {string|object} value - Multilingual value
 * @param {string} lang - Desired language
 * @param {string} defaultLang - Fallback language (default: 'en')
 * @returns {string} Value in requested language or fallback
 */
function getTranslation(value, lang, defaultLang = 'en') {
  // If value is a simple string, return it
  if (typeof value === 'string') {
    return value
  }
 
  // If value is null/undefined, return empty string
  if (!value || typeof value !== 'object') {
    return ''
  }
 
  // Try requested language
  if (value[lang]) {
    return value[lang]
  }
 
  // Try default language
  if (value[defaultLang]) {
    return value[defaultLang]
  }
 
  // Try English as last resort
  if (value['en']) {
    return value['en']
  }
 
  // Return first available translation
  const firstKey = Object.keys(value)[0]
  return value[firstKey] || ''
}
 
/**
 * Normalize multilingual value (convert string to object if needed)
 * @param {string|object} value - Value to normalize
 * @param {string} defaultLang - Default language for string values
 * @returns {object} Normalized multilingual object
 */
function normalizeMultilingualValue(value, defaultLang = 'en') {
  if (typeof value === 'string') {
    return { [defaultLang]: value }
  }
 
  if (typeof value === 'object' && value !== null) {
    return value
  }
 
  return { [defaultLang]: '' }
}
 
/**
 * Merge multilingual values (useful for updates)
 * @param {object} existing - Existing multilingual value
 * @param {object} updates - New translations to merge
 * @returns {object} Merged multilingual object
 */
function mergeTranslations(existing, updates) {
  const normalized = normalizeMultilingualValue(existing)
  return { ...normalized, ...updates }
}
 
module.exports = {
  SUPPORTED_LANGUAGES,
  isValidLanguage,
  isValidMultilingualValue,
  getTranslation,
  normalizeMultilingualValue,
  mergeTranslations
}