StoreLocales.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. <?php
  2. declare(strict_types=1);
  3. namespace EKSRelay\Core;
  4. /**
  5. * Maps WPML language codes to ISO 4217 currency codes.
  6. *
  7. * Used to resolve the correct shop currency based on the detected language
  8. * of the customer's message. Handles fallback to EUR for currencies that are
  9. * not configured in the shop's multicurrency plugin.
  10. *
  11. * Supported currencies are read from the STORE_CURRENCIES env variable
  12. * (comma-separated ISO 4217 codes). Default matches the shop configuration.
  13. */
  14. final class StoreLocales
  15. {
  16. /**
  17. * WPML language code → natural ISO 4217 currency code.
  18. * Based on the official currency of the country/region for each language.
  19. */
  20. private const CURRENCY_MAP = [
  21. 'aed' => 'AED', // Arabic (UAE) → UAE Dirham
  22. 'be' => 'BYN', // Belarusian → Belarusian ruble (not in shop → fallback)
  23. 'bg' => 'BGN', // Bulgarian → Bulgarian lev
  24. 'hr' => 'EUR', // Croatian → Euro (adopted 2023)
  25. 'cs' => 'CZK', // Czech → Czech koruna
  26. 'da' => 'DKK', // Danish → Danish krone
  27. 'nl' => 'EUR', // Dutch → Euro
  28. 'en' => 'EUR', // English → Euro (default for EU context)
  29. 'et' => 'EUR', // Estonian → Euro
  30. 'fi' => 'EUR', // Finnish → Euro
  31. 'fr' => 'EUR', // French → Euro
  32. 'de' => 'EUR', // German → Euro
  33. 'el' => 'EUR', // Greek → Euro
  34. 'hu' => 'HUF', // Hungarian → Hungarian forint
  35. 'it' => 'EUR', // Italian → Euro
  36. 'lv' => 'EUR', // Latvian → Euro
  37. 'lt' => 'EUR', // Lithuanian → Euro
  38. 'no' => 'NOK', // Norwegian → Norwegian krone
  39. 'pl' => 'PLN', // Polish → Polish złoty
  40. 'pt-pt' => 'EUR', // Portuguese (Portugal) → Euro
  41. 'ro' => 'RON', // Romanian → Romanian leu
  42. 'sk' => 'EUR', // Slovak → Euro
  43. 'sl' => 'EUR', // Slovenian → Euro
  44. 'es' => 'EUR', // Spanish → Euro
  45. 'sv' => 'SEK', // Swedish → Swedish krona
  46. 'tr' => 'TRY', // Turkish → Turkish lira (not in shop → fallback)
  47. 'uk' => 'UAH', // Ukrainian → Ukrainian hryvnia (not in shop → fallback)
  48. ];
  49. /** Fallback currency used when the natural currency is not supported. */
  50. public const FALLBACK_CURRENCY = 'EUR';
  51. /**
  52. * Default list of currencies configured in the shop's multicurrency plugin.
  53. * Used when STORE_CURRENCIES env variable is not set.
  54. * Keep in sync with WooCommerce multicurrency configuration.
  55. */
  56. private const DEFAULT_SUPPORTED = 'PLN,EUR,AED,CZK,HUF,DKK,SEK,NOK,RON,BGN,GBP';
  57. /**
  58. * Resolve a WPML language code to a shop-supported ISO 4217 currency.
  59. *
  60. * Returns an array with:
  61. * currency — ISO 4217 code to pass to the WooCommerce API
  62. * fallback — true if we had to fall back from the natural currency
  63. * natural_currency — (only when fallback=true) the natural currency for the language
  64. * reason — (only when fallback=true) 'unknown_language' | 'unsupported_currency'
  65. *
  66. * @param string|null $language WPML language code (e.g. 'de', 'pl', 'pt-pt')
  67. */
  68. public static function resolve(?string $language): array
  69. {
  70. if ($language === null || $language === '') {
  71. return ['currency' => self::FALLBACK_CURRENCY, 'fallback' => false];
  72. }
  73. $lang = strtolower(trim($language));
  74. $natural = self::CURRENCY_MAP[$lang] ?? null;
  75. if ($natural === null) {
  76. return [
  77. 'currency' => self::FALLBACK_CURRENCY,
  78. 'fallback' => true,
  79. 'reason' => 'unknown_language',
  80. ];
  81. }
  82. if (!in_array($natural, self::supportedCurrencies(), true)) {
  83. return [
  84. 'currency' => self::FALLBACK_CURRENCY,
  85. 'fallback' => true,
  86. 'reason' => 'unsupported_currency',
  87. 'natural_currency' => $natural,
  88. ];
  89. }
  90. return ['currency' => $natural, 'fallback' => false];
  91. }
  92. /**
  93. * Check whether a currency code is supported by the shop's multicurrency configuration.
  94. *
  95. * @param string $currency ISO 4217 code (comparison is case-insensitive)
  96. */
  97. public static function isSupported(string $currency): bool
  98. {
  99. return in_array(strtoupper($currency), self::supportedCurrencies(), true);
  100. }
  101. /**
  102. * @return string[]
  103. */
  104. private static function supportedCurrencies(): array
  105. {
  106. $raw = Env::get('STORE_CURRENCIES', self::DEFAULT_SUPPORTED);
  107. return array_values(array_filter(array_map('trim', explode(',', strtoupper($raw)))));
  108. }
  109. }