项目国际化中QLocale的使用

目录

一、项目背景

二、QLocale基本介绍        

三、实际使用举例


一、项目背景

        在停车收费软件在海外应用中对于不同的国家,收费金额、过车时间等等虽然可以按照统一格式进行存储,但是界面展示等需要遵循当地习俗,不同国家地区习俗不同,如货币符号,数字分割符号,数字分割格式,时间展示方式等,此时QLocale模块可以根据不同国家给出合理的显示方式。

二、QLocale基本介绍
        

        QLocale是 Qt 框架中用于实现国际化和本地化的核心类,它定义了用户所在区域的特定文化规则,确保应用程序能以符合用户习惯的方式展示数字、日期、货币等信息,以下是货币和时间等本地化代码。

三、实际使用举例

继承QSharedData提升数据效率

class LocalManagerData : public QSharedData {
public:
	QLocale locale;

	LocalManagerData(const QLocale &loc)
		: locale(loc) {}
};

LocalManager 单例便于集成到项目

class LocalManager  {
public:
	enum Country {
		UnitedStates,
		China,
		Japan,
		Germany,
		France,
		UnitedKingdom,
		SouthKorea,
		Canada,
		Australia,
		Russia,
		Vietnam
		// 添加更多国家...
	};


    //枚举时间格式
	enum DateTimeFormat {
		LongDate,
		LongTime,
		ShortTime,
		BaseTime1,//"yyyy-MM-ddTHH:mm:ss"
		BaseTime2,// "yyyy-MM-dd HH:mm:ss"
		BaseTime3,//"yyyyMMddHHmmss"
		BaseTime4,//"yyyy-MM-dd-HH-mm-ss"
		BaseTime5,//"HH:ss"
		BaseTime6,//"yyyyMMddHHmmsszzz"
		BaseTime7,//"HH:mm"
		BaseTime8,//"yyyy/MM/dd HH:mm:ss"
		BaseTime9  //"HH:mm:ss"
	};

	static LocalManager* instance()
	{
		static LocalManager instance;
		return &instance;
	}

    //根据locate获取时区
	QString getTimeZoneIdForLocale(const QLocale &locale)
	{
		switch (locale.country()) {
		case QLocale::China:
			return "Asia/Shanghai";
		case QLocale::UnitedStates:
			return "America/New_York"; // 东部时间作为美国代表
		case QLocale::Germany:
			return "Europe/Berlin";
		case QLocale::Japan:
			return "Asia/Tokyo";
		case QLocale::UnitedKingdom:
			return "Europe/London";
		case QLocale::France:
			return "Europe/Paris";
		case QLocale::Canada:
			return "America/Toronto";
		case QLocale::Australia:
			return "Australia/Sydney";
		case QLocale::Vietnam:
			return "Asia/Ho_Chi_Minh"; 
		case QLocale::Russia:
			return "Europe/Moscow";
		default:
			// 如果无法识别,则回落到系统时区
			return QTimeZone::systemTimeZone().id();
		}
	}


	// 切换国家(自动匹配语言和货币)
	void switchCountry(Country country) {
		QMutexLocker locker(&m_mutex);
		static const QHash<Country, QLocale> localeMap = {
			{ UnitedStates, QLocale(QLocale::English, QLocale::UnitedStates) },
			{ China, QLocale(QLocale::Chinese, QLocale::China) },
			{ Japan, QLocale(QLocale::Japanese, QLocale::Japan) },
			{ Germany, QLocale(QLocale::German, QLocale::Germany) },
			{ France, QLocale(QLocale::French, QLocale::France) },
			{ UnitedKingdom, QLocale(QLocale::English, QLocale::UnitedKingdom) },
			{ SouthKorea, QLocale(QLocale::Korean, QLocale::SouthKorea) },
			{ Canada, QLocale(QLocale::English, QLocale::Canada) },
			{ Australia, QLocale(QLocale::English, QLocale::Australia) },
			{ Russia, QLocale(QLocale::Russian, QLocale::Russia) },
			{ Vietnam, QLocale(QLocale::Vietnamese, QLocale::Vietnam) }
		};
		auto it = localeMap.find(country);
		d->locale = (it != localeMap.end()) ? it.value() : QLocale::system();
	}

	// 格式化价格
	QString formatPrice(qreal price, int precision = 2) const {
		if (std::isnan(price) || std::isinf(price))
			return QObject::tr("Invalid amount");

		QMutexLocker locker(&m_mutex);
		QString amount = QString::number(price, 'f', precision); // 强制保留precision位小数
		return d->locale.toCurrencyString(amount.toDouble());
	}


	//格式化时间
	QString formatDateTime(const QDateTime& dt,  DateTimeFormat type = DateTimeFormat::LongDate) {
		if (type >= DateTimeFormat::LongDate && type <= DateTimeFormat::BaseTime9)
		{
			switch (type)
			{
			case DateTimeFormat::LongDate:
				return d->locale.toString(dt.date(), QLocale::LongFormat);
			case DateTimeFormat::LongTime:
				return d->locale.toString(dt.time(), QLocale::LongFormat);
			case DateTimeFormat::ShortTime:
				return d->locale.toString(dt.time(), QLocale::ShortFormat);
			case DateTimeFormat::BaseTime1:
				return d->locale.toString(dt, "yyyy-MM-ddTHH:mm:ss");
			case DateTimeFormat::BaseTime2:
				return d->locale.toString(dt, "yyyy-MM-dd HH:mm:ss");			
			case DateTimeFormat::BaseTime3:
				return d->locale.toString(dt, "yyyyMMddHHmmss");			
			case DateTimeFormat::BaseTime4:
				return d->locale.toString(dt, "yyyy-MM-dd-HH-mm-ss");	
			case DateTimeFormat::BaseTime5:
				return d->locale.toString(dt, "HH:ss");	
			case DateTimeFormat::BaseTime6:
				return d->locale.toString(dt, "yyyyMMddHHmmsszzz");	
			case DateTimeFormat::BaseTime7:
				return d->locale.toString(dt, "HH:mm");
			case DateTimeFormat::BaseTime8:
				return d->locale.toString(dt, "yyyy/MM/dd HH:mm:ss");
			case DateTimeFormat::BaseTime9:
				return d->locale.toString(dt, "HH:mm:ss");
			}
		}
		return "";
	}
	
	QString formatToLocalDisplay(const QString &isoTime, DateTimeFormat type = DateTimeFormat::LongDate) {
		// 解析 ISO 时间(移除末尾的 'Z' 并解析为 UTC)
		QString cleanIso = isoTime;
		if (cleanIso.endsWith('Z') || cleanIso.endsWith('z')) {
			cleanIso.chop(1);
		}
		QDateTime utcTime = QDateTime::fromString(cleanIso, Qt::ISODate);
		utcTime.setTimeZone(QTimeZone("UTC"));

		if (!utcTime.isValid()) {
			return isoTime; // 返回原始字符串作为 fallback
		}

		QString tzId = getTimeZoneIdForLocale(d->locale);
		QTimeZone targetZone(tzId.toUtf8());

		if (!targetZone.isValid()) {
			targetZone = QTimeZone::systemTimeZone(); // 回退
		}

		// 设置目标时区
		QDateTime localizedLocalTime = utcTime.toTimeZone(targetZone);
		return formatDateTime(localizedLocalTime, type);
	}

	// 获取当前系统本地化的日期时间
	QString currentDateLocalTime(const QString& format = "yyyy-MM-dd HH:mm:ss") {
		QString tzId = getTimeZoneIdForLocale(d->locale);
		QTimeZone targetZone(tzId.toUtf8());

		if (!targetZone.isValid()) {
			targetZone = QTimeZone::systemTimeZone(); 
		}

		// 设置目标时区
		QDateTime localizedLocalTime = QDateTime::currentDateTime().toTimeZone(targetZone);
		return  d->locale.toString(localizedLocalTime, format);
	}
	
	//获取当前的UTC时间
    QString currentUtcIsoTime() {
		return QDateTime::currentDateTimeUtc().toString(Qt::ISODate) + "Z";
	}


	// 获取当前货币代码(如 USD, CNY)
	QString currencyCode() const {
		QMutexLocker locker(&m_mutex);
		return d->locale.currencySymbol(QLocale::CurrencyIsoCode);
	}

	// 获取当前国家名称(本地化)
	QString countryName() const {
		QMutexLocker locker(&m_mutex);
		return d->locale.countryToString(d->locale.country());
	}

	// 获取语言名称
	QString languageName() const {
		QMutexLocker locker(&m_mutex);
		return d->locale.languageToString(d->locale.language());
	}

	QLocale currentLocale() const {
		QMutexLocker locker(&m_mutex);
		return d->locale;
	}

private:
	explicit LocalManager()
		: d(new LocalManagerData(QLocale::system())) {}

	static LocalManager *m_instance;
	QSharedDataPointer<LocalManagerData> d;
	mutable QMutex m_mutex;
};

// 静态成员初始化
LocalManager* LocalManager::m_instance = nullptr;

使用举例

void Test()
{
	auto *cm = LocalManager::instance();

	cm->switchCountry(LocalManager::China);
	qreal testPrice = qRound(5432108.45 * 100.0) / 100.0;
	ui.label_rmb->setText(cm->formatPrice(testPrice));
	ui.label_rmb_systime->setText(cm->currentDateLocalTime());
	//ui.label_rmb_systime->setText(cm->formatDateTime(QDateTime::currentDateTime()));
	

	cm->switchCountry(LocalManager::UnitedStates);
	ui.label_us->setText(cm->formatPrice(testPrice));
	ui.label_us_systime->setText(cm->currentDateLocalTime());
	//ui.label_us_systime->setText(cm->formatDateTime(QDateTime::currentDateTime()));

	cm->switchCountry(LocalManager::Russia);
	ui.label_russia->setText(cm->formatPrice(testPrice));
	ui.label_russia_systime->setText(cm->currentDateLocalTime());
	//ui.label_russia_systime->setText(cm->formatDateTime(QDateTime::currentDateTime()));

	cm->switchCountry(LocalManager::UnitedKingdom);
	ui.label_uk->setText(cm->formatPrice(testPrice));
	ui.label_uk_sysytime->setText(cm->currentDateLocalTime());
	//ui.label_uk_sysytime->setText(cm->formatDateTime(QDateTime::currentDateTime()));

	cm->switchCountry(LocalManager::Vietnam);
	ui.label_yn->setText(cm->formatPrice(testPrice));
	ui.label_yn_systime->setText(cm->currentDateLocalTime());
	//ui.label_yn_systime->setText(cm->formatDateTime(QDateTime::currentDateTime()));

}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值