C++ std::locale | Internationalization and formatting guide

C++ std::locale | Internationalization and formatting guide

이 글의 핵심

Practical notes on std::locale: imbue on streams, parsing locale-dependent numbers, avoiding global locale changes, and when to prefer ICU or fixed protocols.

Basic usage

#include <locale>
#include <iostream>
using namespace std;

int main() {
    // Current locale
    locale currentLocale;
    cout << currentLocale.name() << endl;
    
    // Set global locale (example name — adjust to your system)
    locale::global(locale("en_US.UTF-8"));
    
    // Apply to stream
    cout.imbue(locale());
}

Number formatting

#include <locale>
#include <iomanip>

int main() {
    // Thousands separators
    cout.imbue(locale("en_US.UTF-8"));
    cout << 1234567 << endl;  // 1,234,567
    
    // Money
    cout << showbase << put_money(123456) << endl;  // e.g. $1,234.56
}

Date and time

#include <locale>
#include <iomanip>

int main() {
    auto now = chrono::system_clock::now();
    auto time = chrono::system_clock::to_time_t(now);
    
    // Example locale
    cout.imbue(locale("ko_KR.UTF-8"));
    cout << put_time(localtime(&time), "%c") << endl;
    
    cout.imbue(locale("en_US.UTF-8"));
    cout << put_time(localtime(&time), "%c") << endl;
}

Practical examples

Example 1: Simple message map (i18n sketch)

#include <map>

class I18n {
private:
    map<string, map<string, string>> messages;
    string currentLang = "en";
    
public:
    void addMessage(const string& lang, const string& key, const string& value) {
        messages[lang][key] = value;
    }
    
    void setLanguage(const string& lang) {
        currentLang = lang;
    }
    
    string get(const string& key) const {
        auto langIt = messages.find(currentLang);
        if (langIt != messages.end()) {
            auto msgIt = langIt->second.find(key);
            if (msgIt != langIt->second.end()) {
                return msgIt->second;
            }
        }
        return key;  // fallback
    }
};

int main() {
    I18n i18n;
    
    i18n.addMessage("en", "hello", "Hello");
    i18n.addMessage("en", "goodbye", "Goodbye");
    i18n.addMessage("ko", "hello", "안녕하세요");
    i18n.addMessage("ko", "goodbye", "안녕히 가세요");
    
    i18n.setLanguage("ko");
    cout << i18n.get("hello") << endl;
    cout << i18n.get("goodbye") << endl;
}

Example 2: Parsing numbers with a locale

double parseNumber(const string& str, const locale& loc) {
    istringstream iss(str);
    iss.imbue(loc);
    
    double value;
    iss >> value;
    
    return value;
}

int main() {
    double us = parseNumber("1,234.56", locale("en_US.UTF-8"));
    cout << us << endl;  // 1234.56
    
    double eu = parseNumber("1.234,56", locale("de_DE.UTF-8"));
    cout << eu << endl;  // 1234.56
}

Example 3: Character classification

#include <locale>

int main() {
    locale loc("en_US.UTF-8");
    
    char c = 'A';
    
    if (isalpha(c, loc)) {
        cout << c << " is alphabetic" << endl;
    }
    
    if (isupper(c, loc)) {
        cout << c << " is uppercase" << endl;
    }
    
    char lower = tolower(c, loc);
    cout << "lower: " << lower << endl;  // a
}

Currency formatting

#include <iomanip>

int main() {
    cout.imbue(locale("en_US.UTF-8"));
    cout << showbase << put_money(123456) << endl;
    
    cout.imbue(locale("ko_KR.UTF-8"));
    cout << showbase << put_money(123456) << endl;
}

Common pitfalls

Pitfall 1: Locale not installed

try {
    locale loc("ko_KR.UTF-8");
} catch (const runtime_error& e) {
    cout << "locale not available" << endl;
}

// Install locales on Linux: locale-gen, etc.

Pitfall 2: Changing the global locale

// ❌ Affects unrelated code
locale::global(locale("ko_KR.UTF-8"));

// ✅ Per-stream
cout.imbue(locale("ko_KR.UTF-8"));

Pitfall 3: Performance

// ❌ Constructing a locale each iteration
for (int i = 0; i < 1000; i++) {
    locale loc("en_US.UTF-8");
}

// ✅ Reuse
locale loc("en_US.UTF-8");
for (int i = 0; i < 1000; i++) {
}

FAQ

Q1: When do I use locale?

A:

  • Multilingual UI strings (often with higher-level i18n systems)
  • Locale-specific number and date display
  • Currency formatting
  • Character classification

Q2: Performance overhead?

A: Some. For tight loops, consider fixed formats or custom formatting.

Q3: UTF-8 support?

A: Improved in newer standards; legacy behavior can still be limited—verify on your targets.

Q4: Which locale strings?

A: Common examples: en_US.UTF-8, ko_KR.UTF-8, ja_JP.UTF-8—availability depends on the OS.

Q5: How do I list locales?

A: On Unix, locale -a.

Q6: Learning resources?

A:


  • C++ string_view
  • C++ Allocator guide
  • C++ Chrono guide

Practical tips

Debugging

  • Fix compiler warnings first.
  • Reproduce with a small test.

Performance

  • Profile before optimizing.
  • Set measurable targets.

Code review

  • Follow team conventions.

Production checklist

Before coding

  • Right tool for the job?
  • Maintainable by the team?
  • Meets performance needs?

While coding

  • Warnings cleared?
  • Edge cases covered?
  • Error handling OK?

At review

  • Intent clear?
  • Tests enough?
  • Documented?

Keywords

C++, locale, i18n, localization, formatting


  • Arrays and lists (algo series)
  • C++ Adapter Pattern
  • C++ ADL |
  • C++ Aggregate Initialization |
  • C++ Aggregate Initialization guide