LibreOffice Module i18npool (master) 1
ordinalsuffix.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
22#include <sal/log.hxx>
25#include <ordinalsuffix.hxx>
26
27#include <unicode/rbnf.h>
28#include <unicode/normlzr.h>
29#include <memory>
30
31namespace com::sun::star::uno { class XComponentContext; }
32
33using namespace ::com::sun::star::i18n;
34using namespace ::com::sun::star::uno;
35using namespace ::com::sun::star;
36
37namespace i18npool {
38
39
41{
42}
43
45{
46}
47
48namespace
49{
50 OUString mungeUnicodeStringToOUString(const icu::UnicodeString &rIn, UErrorCode &rCode)
51 {
52 // Apply NFKC normalization to get normal letters
53 icu::UnicodeString normalized;
54 icu::Normalizer::normalize(rIn, UNORM_NFKC, 0, normalized, rCode);
55 // Convert the normalized UnicodeString to OUString
56 OUString sRet = (U_SUCCESS(rCode))
57 ? OUString(reinterpret_cast<const sal_Unicode *>(normalized.getBuffer()), normalized.length())
58 : OUString();
59 // replace any minus signs with hyphen-minus so that negative numbers
60 // from the simple number formatter and heavy-duty pattern formatter
61 // agree as to their negative number sign
62 return sRet.replace(0x2212, '-');
63 }
64}
65
66/*
67 * For this method to properly return the ordinal suffix for other locales
68 * than english ones, ICU 4.2+ has to be used.
69 */
70uno::Sequence< OUString > SAL_CALL OrdinalSuffixService::getOrdinalSuffix( sal_Int32 nNumber,
71 const lang::Locale &rLocale )
72{
73 uno::Sequence< OUString > retValue;
74
75 // Get the value from ICU
76 UErrorCode nCode = U_ZERO_ERROR;
77 const icu::Locale aIcuLocale( LanguageTagIcu::getIcuLocale( LanguageTag( rLocale)));
78
79 icu::RuleBasedNumberFormat formatter(icu::URBNF_ORDINAL, aIcuLocale, nCode);
80 if (!U_SUCCESS(nCode))
81 return retValue;
82
83 std::unique_ptr<icu::NumberFormat> xNumberFormat(icu::NumberFormat::createInstance(aIcuLocale, nCode));
84 if (!U_SUCCESS(nCode))
85 return retValue;
86
87 icu::UnicodeString sFormatWithNoOrdinal;
88 icu::Formattable ftmNumber(static_cast<int32_t>(nNumber));
89 icu::FieldPosition icuPosA;
90 xNumberFormat->format(ftmNumber, sFormatWithNoOrdinal, icuPosA, nCode);
91 if (!U_SUCCESS(nCode))
92 return retValue;
93
94 OUString sValueWithNoOrdinal = mungeUnicodeStringToOUString(sFormatWithNoOrdinal, nCode);
95 if (!U_SUCCESS(nCode))
96 return retValue;
97
98 int32_t nRuleSets = formatter.getNumberOfRuleSetNames( );
99 std::vector<OUString> retVec;
100 retVec.reserve(nRuleSets);
101 for (int32_t i = 0; i < nRuleSets; ++i)
102 {
103 icu::UnicodeString ruleSet = formatter.getRuleSetName(i);
104
105 // format the string
106 icu::UnicodeString sFormatWithOrdinal;
107 icu::FieldPosition icuPosB;
108 formatter.format(static_cast<int32_t>(nNumber), ruleSet, sFormatWithOrdinal, icuPosB, nCode);
109
110 if (!U_SUCCESS(nCode))
111 continue;
112
113 OUString sValueWithOrdinal = mungeUnicodeStringToOUString(sFormatWithOrdinal, nCode);
114 if (!U_SUCCESS(nCode))
115 continue;
116
117 // fdo#54486 lets make sure that the ordinal format and the non-ordinal
118 // format match at the start, so that the expectation can be verified
119 // that there is some trailing "ordinal suffix" which can be extracted
120 bool bSimpleOrdinalSuffix = sValueWithOrdinal.startsWith(sValueWithNoOrdinal);
121
122 SAL_WARN_IF(!bSimpleOrdinalSuffix, "i18npool", "ordinal " <<
123 sValueWithOrdinal << " didn't start with expected " <<
124 sValueWithNoOrdinal << " prefix");
125
126 if (!bSimpleOrdinalSuffix)
127 continue;
128
129 // Remove the number to get the prefix
130 sal_Int32 len = sValueWithNoOrdinal.getLength();
131 retVec.push_back(sValueWithOrdinal.copy(len));
132 }
133
134 return comphelper::containerToSequence(retVec);
135}
136
137constexpr OUStringLiteral cOrdinalSuffix = u"com.sun.star.i18n.OrdinalSuffix";
138
140{
141 return cOrdinalSuffix;
142}
143
144sal_Bool SAL_CALL OrdinalSuffixService::supportsService( const OUString& rServiceName)
145{
146 return cppu::supportsService(this, rServiceName);
147}
148
150{
151 return { cOrdinalSuffix };
152}
153
154}
155
156extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
158 css::uno::XComponentContext *,
159 css::uno::Sequence<css::uno::Any> const &)
160{
161 return cppu::acquire(new i18npool::OrdinalSuffixService());
162}
163
164/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static icu::Locale getIcuLocale(const LanguageTag &rLanguageTag)
virtual OUString SAL_CALL getImplementationName() override
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
virtual ~OrdinalSuffixService() override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
virtual css::uno::Sequence< OUString > SAL_CALL getOrdinalSuffix(sal_Int32 nNumber, const css::lang::Locale &rLocale) override
float u
#define SAL_WARN_IF(condition, area, stream)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
int i
Constant values shared between i18npool and, for example, the number formatter.
constexpr OUStringLiteral cOrdinalSuffix
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_i18n_OrdinalSuffix_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
unsigned char sal_Bool
sal_uInt16 sal_Unicode