summaryrefslogtreecommitdiffstats
path: root/i18npool/source/ordinalsuffix/ordinalsuffix.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'i18npool/source/ordinalsuffix/ordinalsuffix.cxx')
-rw-r--r--i18npool/source/ordinalsuffix/ordinalsuffix.cxx164
1 files changed, 164 insertions, 0 deletions
diff --git a/i18npool/source/ordinalsuffix/ordinalsuffix.cxx b/i18npool/source/ordinalsuffix/ordinalsuffix.cxx
new file mode 100644
index 000000000..76dd0440f
--- /dev/null
+++ b/i18npool/source/ordinalsuffix/ordinalsuffix.cxx
@@ -0,0 +1,164 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <i18nlangtag/languagetag.hxx>
+#include <i18nlangtag/languagetagicu.hxx>
+#include <sal/log.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <ordinalsuffix.hxx>
+
+#include <unicode/rbnf.h>
+#include <unicode/normlzr.h>
+#include <memory>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star;
+
+namespace i18npool {
+
+
+OrdinalSuffixService::OrdinalSuffixService()
+{
+}
+
+OrdinalSuffixService::~OrdinalSuffixService()
+{
+}
+
+namespace
+{
+ OUString mungeUnicodeStringToOUString(const icu::UnicodeString &rIn, UErrorCode &rCode)
+ {
+ // Apply NFKC normalization to get normal letters
+ icu::UnicodeString normalized;
+ icu::Normalizer::normalize(rIn, UNORM_NFKC, 0, normalized, rCode);
+ // Convert the normalized UnicodeString to OUString
+ OUString sRet = (U_SUCCESS(rCode))
+ ? OUString(reinterpret_cast<const sal_Unicode *>(normalized.getBuffer()), normalized.length())
+ : OUString();
+ // replace any minus signs with hyphen-minus so that negative numbers
+ // from the simple number formatter and heavy-duty pattern formatter
+ // agree as to their negative number sign
+ return sRet.replace(0x2212, '-');
+ }
+}
+
+/*
+ * For this method to properly return the ordinal suffix for other locales
+ * than english ones, ICU 4.2+ has to be used.
+ */
+uno::Sequence< OUString > SAL_CALL OrdinalSuffixService::getOrdinalSuffix( sal_Int32 nNumber,
+ const lang::Locale &rLocale )
+{
+ uno::Sequence< OUString > retValue;
+
+ // Get the value from ICU
+ UErrorCode nCode = U_ZERO_ERROR;
+ const icu::Locale aIcuLocale( LanguageTagIcu::getIcuLocale( LanguageTag( rLocale)));
+
+ icu::RuleBasedNumberFormat formatter(icu::URBNF_ORDINAL, aIcuLocale, nCode);
+ if (!U_SUCCESS(nCode))
+ return retValue;
+
+ std::unique_ptr<icu::NumberFormat> xNumberFormat(icu::NumberFormat::createInstance(aIcuLocale, nCode));
+ if (!U_SUCCESS(nCode))
+ return retValue;
+
+ icu::UnicodeString sFormatWithNoOrdinal;
+ icu::Formattable ftmNumber(static_cast<int32_t>(nNumber));
+ icu::FieldPosition icuPosA;
+ xNumberFormat->format(ftmNumber, sFormatWithNoOrdinal, icuPosA, nCode);
+ if (!U_SUCCESS(nCode))
+ return retValue;
+
+ OUString sValueWithNoOrdinal = mungeUnicodeStringToOUString(sFormatWithNoOrdinal, nCode);
+ if (!U_SUCCESS(nCode))
+ return retValue;
+
+ int32_t nRuleSets = formatter.getNumberOfRuleSetNames( );
+ std::vector<OUString> retVec;
+ retVec.reserve(nRuleSets);
+ for (int32_t i = 0; i < nRuleSets; ++i)
+ {
+ icu::UnicodeString ruleSet = formatter.getRuleSetName(i);
+
+ // format the string
+ icu::UnicodeString sFormatWithOrdinal;
+ icu::FieldPosition icuPosB;
+ formatter.format(static_cast<int32_t>(nNumber), ruleSet, sFormatWithOrdinal, icuPosB, nCode);
+
+ if (!U_SUCCESS(nCode))
+ continue;
+
+ OUString sValueWithOrdinal = mungeUnicodeStringToOUString(sFormatWithOrdinal, nCode);
+ if (!U_SUCCESS(nCode))
+ continue;
+
+ // fdo#54486 lets make sure that the ordinal format and the non-ordinal
+ // format match at the start, so that the expectation can be verified
+ // that there is some trailing "ordinal suffix" which can be extracted
+ bool bSimpleOrdinalSuffix = sValueWithOrdinal.startsWith(sValueWithNoOrdinal);
+
+ SAL_WARN_IF(!bSimpleOrdinalSuffix, "i18npool", "ordinal " <<
+ sValueWithOrdinal << " didn't start with expected " <<
+ sValueWithNoOrdinal << " prefix");
+
+ if (!bSimpleOrdinalSuffix)
+ continue;
+
+ // Remove the number to get the prefix
+ sal_Int32 len = sValueWithNoOrdinal.getLength();
+ retVec.push_back(sValueWithOrdinal.copy(len));
+ }
+
+ return comphelper::containerToSequence(retVec);
+}
+
+constexpr OUStringLiteral cOrdinalSuffix = u"com.sun.star.i18n.OrdinalSuffix";
+
+OUString SAL_CALL OrdinalSuffixService::getImplementationName()
+{
+ return cOrdinalSuffix;
+}
+
+sal_Bool SAL_CALL OrdinalSuffixService::supportsService( const OUString& rServiceName)
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+Sequence< OUString > SAL_CALL OrdinalSuffixService::getSupportedServiceNames()
+{
+ return { cOrdinalSuffix };
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_i18n_OrdinalSuffix_get_implementation(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new i18npool::OrdinalSuffixService());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */