Multi-language, multi-currency card payment processing using Global Payments GP API. This project demonstrates how to build a globally accessible checkout experience with automatic locale detection, independent language and currency selection, and session-based preference persistence. All implementations use the official Global Payments SDK (GpApiConfig).
- Multi-Language Support: 5 languages (English, Spanish, French, German, Portuguese)
- Multi-Currency Support: 6 currencies (USD, EUR, GBP, CAD, AUD, JPY)
- Independent Selection: Language and currency can be chosen independently
- Automatic Locale Detection: Detects browser language preferences via Accept-Language header
- Session Persistence: User preferences saved across page reloads
- Client-Side Tokenization: Secure card data handling with GP API JavaScript SDK
- Localized Error Messages: Error responses in user's selected language
- Currency Formatting: Locale-aware number and currency formatting
- Dynamic Country Routing: GP API routes payments based on selected currency
Each implementation runs on http://localhost:8000 with the same features:
- Language selector (English, Spanish, French, German, Portuguese)
- Currency selector (USD, EUR, GBP, CAD, AUD, JPY)
- Real-time currency formatting based on locale
- Localized UI elements and messages
- Session-based preference persistence
All implementations provide identical functionality with platform-specific best practices:
Tech Stack: ASP.NET Core Minimal API + GP API .NET SDK
Session: ASP.NET Core session middleware with distributed memory cache
Token Generation: SDK GpApiService.GenerateTransactionKey()
Key Features: Modern minimal API approach, 24-hour session timeout
Tech Stack: Express.js + GP API Node.js SDK
Session: express-session middleware with memory store
Token Generation: SDK GpApiService.generateTransactionKey()
Key Features: ES6 modules, async/await patterns, production Redis example
Tech Stack: Jakarta EE Servlets + GP API Java SDK
Session: HttpSession with servlet container
Token Generation: SDK GpApiService.generateTransactionKey()
Key Features: Annotation-based servlets, Maven Cargo plugin, Tomcat deployment
Tech Stack: Native PHP + GP API PHP SDK
Session: PHP native sessions
Token Generation: SDK GpApiService::generateTransactionKey()
Key Features: Symfony Translation component, PSR-12 compliant, built-in server routing
- Global Payments account with GP API credentials (Get credentials)
- Development environment for your chosen language
-
Navigate to your language directory:
cd dotnet/ # or nodejs/, java/, php/
-
Copy environment template:
cp .env.sample .env
-
Add your GP API credentials to
.env:GP_API_APP_ID=your_gp_api_app_id_here GP_API_APP_KEY=your_gp_api_app_key_here GP_API_ENVIRONMENT=sandbox
-
Run the application:
./run.sh
-
Open in browser:
http://localhost:8000
User opens page
↓
Frontend: POST /config with Accept-Language header
↓
Backend: Detect locale from header (e.g., "es-ES" → "es")
↓
Backend: Check session for saved preference
↓
Backend: Return locale + currency + translations + access token
↓
Frontend: Initialize UI with detected/saved preferences
User selects new language or currency
↓
Frontend: POST /api/locale with {locale, currency}
↓
Backend: Update session storage
↓
Backend: Return new translations
↓
Frontend: Update UI without page reload
User enters card details
↓
GP API JavaScript SDK: Tokenize card (client-side)
↓
Frontend: POST /process-payment with token + amount + currency + locale
↓
Backend: Reconfigure SDK with currency-specific country code
↓
Backend: Process payment via GP API
↓
Backend: Return localized success/error message
↓
Frontend: Display message in user's language
| Code | Language | Native Name | Default Currency | Flag |
|---|---|---|---|---|
| en | English | English | USD | 🇺🇸 |
| es | Spanish | Español | EUR | 🇪🇸 |
| fr | French | Français | EUR | 🇫🇷 |
| de | German | Deutsch | EUR | 🇩🇪 |
| pt | Portuguese | Português | EUR | 🇵🇹 |
| Code | Currency | Symbol | Decimals | Country Code |
|---|---|---|---|---|
| USD | US Dollar | $ | 2 | US |
| EUR | Euro | € | 2 | GB |
| GBP | British Pound | £ | 2 | GB |
| CAD | Canadian Dollar | C$ | 2 | CA |
| AUD | Australian Dollar | A$ | 2 | AU |
| JPY | Japanese Yen | ¥ | 0 | JP |
Generate GP API access token with locale/currency configuration.
Request Headers:
Accept-Language: es-ES,es;q=0.9,en;q=0.8
Response:
{
"success": true,
"data": {
"accessToken": "PMT_...",
"locale": "es",
"currency": "EUR",
"supportedLocales": {...},
"supportedCurrencies": {...}
}
}Get current user's locale and currency preferences.
Update user's locale and currency preferences.
Request:
{
"locale": "fr",
"currency": "CAD"
}Process payment with localized preferences.
Request:
{
"payment_token": "PMT_xxx",
"amount": 25.00,
"currency": "EUR",
"locale": "es"
}Response:
{
"success": true,
"data": {
"transactionId": "txn_xxx",
"amount": 25.00,
"currency": "EUR",
"status": "CAPTURED"
},
"message": "¡Pago Exitoso!"
}Visa - Successful:
- Number:
4263 9826 4026 9299 - Expiry: Any future date (e.g.,
12/25) - CVV: Any 3 digits (e.g.,
123)
Visa - Declined:
- Number:
4000120000001154
Mastercard - Successful:
- Number:
5425 2334 2424 1200
Test 1: Automatic Locale Detection
- Set browser language to Spanish
- Open application
- Verify UI displays in Spanish
- Verify default currency is EUR
Test 2: Independent Language/Currency
- Select "English" language
- Select "JPY" currency
- Verify amount displays as "¥2,500" (no decimals)
- Process payment
- Verify success message in English
Test 3: Session Persistence
- Select "Français" and "CAD"
- Reload page (F5)
- Verify French + CAD persisted
- Close browser
- Reopen within session timeout
- Verify preferences still saved
Test 4: Currency Formatting
- USD:
$25.00(symbol before, period decimal) - EUR:
25,00 €(symbol after, comma decimal) - JPY:
¥2500(no decimal places)
All implementations use the SDK's generateTransactionKey() method for consistent, secure token generation:
PHP:
$accessTokenInfo = GpApiService::generateTransactionKey($config);
$accessToken = $accessTokenInfo->accessToken;.NET:
var accessTokenInfo = GpApiService.GenerateTransactionKey(config);
var accessToken = accessTokenInfo.Token;Java:
var accessTokenInfo = GpApiService.generateTransactionKey(config);
String accessToken = accessTokenInfo.getAccessToken();Node.js:
const accessTokenInfo = await GpApiService.generateTransactionKey(config);
const accessToken = accessTokenInfo.accessToken;This approach provides consistent behavior across all platforms with proper SDK integration.
| Platform | Technology | Default Timeout | Production Options |
|---|---|---|---|
| .NET | ASP.NET Core Session | 24 hours | Redis, SQL Server |
| Node.js | express-session | 24 hours | Redis, MongoDB |
| Java | HttpSession | 30 minutes | Redis, Database |
| PHP | Native Sessions | 24 minutes | Redis, Memcached |
localized-checkout-experience/
├── dotnet/ # .NET Core implementation
│ ├── Services/ # LocaleService, CurrencyConfig, TranslationService
│ ├── translations/ # JSON translation files
│ ├── wwwroot/ # Frontend assets
│ └── Program.cs # Main application
├── nodejs/ # Node.js implementation
│ ├── services/ # Localization services
│ ├── translations/ # JSON translation files
│ └── server.js # Express application
├── java/ # Java implementation
│ └── src/main/
│ ├── java/ # Servlets and services
│ ├── resources/ # Translation files
│ └── webapp/ # Frontend assets
├── php/ # PHP implementation
│ ├── services/ # Localization classes
│ ├── translations/ # JSON translation files
│ └── *.php # Endpoints
└── README.md # This file
To add a new language (e.g., Italian):
- Create translation file:
translations/it.json - Update LocaleService: Add Italian to supported locales
- Update frontend translations: Add Italian to
js/translations.js - Update HTML: Add Italian option to language selector
See individual implementation READMEs for language-specific details.
To add a new currency (e.g., Swiss Franc):
- Update CurrencyConfig: Add CHF with country code "CH"
- Update frontend formatter: Add CHF to currency configurations
- Update HTML: Add CHF option to currency selector
- Verify GP API support: Ensure GP API supports country code
All implementations include three core services:
LocaleService:
- Detects locale from Accept-Language header
- Manages session-based locale/currency storage
- Provides locale validation and fallbacks
CurrencyConfig:
- Defines currency metadata (symbol, decimals, country)
- Maps currencies to GP API country codes
- Provides currency validation
TranslationService:
- Loads translations from JSON files
- Provides key-based translation lookup
- Supports parameterized messages
User preferences stored in server-side sessions:
locale- Selected language code (e.g., "es")currency- Selected currency code (e.g., "EUR")
Benefits:
- Survives page reloads
- Works without client-side storage
- Supports multiple tabs/windows
- Configurable timeout periods
Each payment request reconfigures the SDK with currency-specific country code:
// User selects EUR
const countryCode = CurrencyConfig.getCountryCode("EUR"); // Returns "GB"
config.country = countryCode;
ServicesContainer.configureService(config);This ensures GP API routes payments to the correct regional endpoint.
All implementations follow security best practices:
- No Card Data on Server: Token-based payments only (PCI DSS compliant)
- Environment Variables: Credentials stored in
.envfiles (not committed) - CORS Configuration: Configurable cross-origin support
- Input Validation: Amount, currency, and locale validation
- Error Handling: Sanitized error messages (no sensitive data leaked)
Add these for production deployments:
- Rate Limiting: Prevent brute force attacks on payment endpoints
- CSRF Protection: Implement anti-CSRF tokens
- Security Headers: Add Content-Security-Policy, X-Frame-Options, etc.
- Logging: Comprehensive request/response logging
- HTTPS: TLS required for payment processing
- Session Store: Use Redis/database instead of memory
- Secrets Management: Use vault services (AWS Secrets Manager, Azure Key Vault)
Cause: Invalid or incorrect GP API credentials
Solution:
- Verify
.envhas correctGP_API_APP_IDandGP_API_APP_KEY - Ensure credentials are for GP API (not Portico/Heartland)
- Check credentials at https://developer.globalpayments.com/
- Verify environment is set to
sandboxfor test credentials
Cause: Session configuration or cookie issues
Solution:
- Enable cookies in browser
- Check session timeout configuration
- For production, use persistent session store (Redis)
- Verify session middleware is properly configured
Cause: Browser doesn't support Intl.NumberFormat
Solution:
- Update browser to latest version
- Check browser console for Intl errors
- Verify locale codes are correct (e.g., "en" not "en-US")
- Global Payments Developer Portal
- GP API Documentation
- GP API Reference
- Test Cards
- Accept-Language Header Spec
- Intl.NumberFormat API
For detailed implementation-specific information:
- .NET Implementation Guide - 546 lines
- Node.js Implementation Guide - 594 lines
- Java Implementation Guide - 605 lines
- PHP Implementation Guide - 409 lines
Each guide includes:
- Complete setup instructions
- API endpoint documentation
- Session management details
- Testing procedures
- Troubleshooting guides
- Security considerations
- 🌐 Developer Portal — developer.globalpayments.com
- 💬 Discord — Join the community
- 📋 GitHub Discussions — github.com/orgs/globalpayments/discussions
- 📧 Newsletter — Subscribe
- 💼 LinkedIn — Global Payments for Developers
Have a question or found a bug? Open an issue or reach out at communityexperience@globalpay.com.
MIT License - See LICENSE file for details