mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-07 22:44:49 +00:00
ICU-22081 Addressed review comments:
- Changed all public Javadoc to use the proper verbiage for identifying this code as a tech preview. - Changed all references to ULocale in the API to use Locale instead. - Changed PersonNameFormatter and SimplePersonName so that they're constructed by way of separate builder objects. - Added an internal constructor for PersonNameFormatter just for the use of the unit tests, and added some unit tests that take advantage of the new constructor to test the internals more thoroughly. - Renamed format() to formatToString(), to make room to add a format() method later that returns a FormattedPersonName. - Added logic to guess the locale of a name object when the name object doesn't supply a locale. - Moved the function that constructs a SimplePersonName from a single string containing key-value pairs out of the API and into the unit tests. - Various smaller changes in response to API- and code-review comments.
This commit is contained in:
parent
53775accd5
commit
df93dd00bf
5 changed files with 550 additions and 150 deletions
|
@ -7,8 +7,8 @@ import com.ibm.icu.text.BreakIterator;
|
|||
import com.ibm.icu.text.CaseMap;
|
||||
import com.ibm.icu.text.PersonNameFormatter;
|
||||
import com.ibm.icu.text.SimpleFormatter;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
|
@ -66,9 +66,9 @@ abstract class FieldModifierImpl {
|
|||
* for the "allCaps" modifier.
|
||||
*/
|
||||
private static class AllCapsModifier extends FieldModifierImpl {
|
||||
private final ULocale locale;
|
||||
private final Locale locale;
|
||||
|
||||
public AllCapsModifier(ULocale locale) {
|
||||
public AllCapsModifier(Locale locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
|
@ -83,16 +83,16 @@ abstract class FieldModifierImpl {
|
|||
* the default behavior of the "initialCap" modifier.
|
||||
*/
|
||||
private static class InitialCapModifier extends FieldModifierImpl {
|
||||
private final ULocale locale;
|
||||
private final Locale locale;
|
||||
private static final CaseMap.Title TO_TITLE_WHOLE_STRING_NO_LOWERCASE = CaseMap.toTitle().wholeString().noLowercase();
|
||||
|
||||
public InitialCapModifier(ULocale locale) {
|
||||
public InitialCapModifier(Locale locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String modifyField(String fieldValue) {
|
||||
return TO_TITLE_WHOLE_STRING_NO_LOWERCASE.apply(locale.toLocale(), null, fieldValue);
|
||||
return TO_TITLE_WHOLE_STRING_NO_LOWERCASE.apply(locale, null, fieldValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ abstract class FieldModifierImpl {
|
|||
}
|
||||
|
||||
// (currently, no locale overrides the grapheme-break rules, so we just use "root" instead of passing in the locale)
|
||||
BreakIterator bi = BreakIterator.getCharacterInstance(ULocale.ROOT);
|
||||
BreakIterator bi = BreakIterator.getCharacterInstance(Locale.ROOT);
|
||||
bi.setText(s);
|
||||
return s.substring(0, bi.next());
|
||||
}
|
||||
|
|
|
@ -5,12 +5,15 @@ package com.ibm.icu.impl.personname;
|
|||
import com.ibm.icu.impl.ICUData;
|
||||
import com.ibm.icu.impl.ICUResourceBundle;
|
||||
import com.ibm.icu.lang.UScript;
|
||||
import com.ibm.icu.text.FormattedValue;
|
||||
import com.ibm.icu.text.PersonNameFormatter;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
import com.ibm.icu.util.UResourceBundle;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.ibm.icu.util.UResourceBundle.ARRAY;
|
||||
import static com.ibm.icu.util.UResourceBundle.STRING;
|
||||
|
@ -19,7 +22,7 @@ import static com.ibm.icu.util.UResourceBundle.STRING;
|
|||
* Actual implementation class for PersonNameFormatter.
|
||||
*/
|
||||
public class PersonNameFormatterImpl {
|
||||
private final ULocale locale;
|
||||
private final Locale locale;
|
||||
private final PersonNamePattern[] gnFirstPatterns;
|
||||
private final PersonNamePattern[] snFirstPatterns;
|
||||
private final Set<String> gnFirstLocales;
|
||||
|
@ -34,7 +37,7 @@ public class PersonNameFormatterImpl {
|
|||
private final PersonNameFormatter.Formality formality;
|
||||
private final Set<PersonNameFormatter.Options> options;
|
||||
|
||||
public PersonNameFormatterImpl(ULocale locale,
|
||||
public PersonNameFormatterImpl(Locale locale,
|
||||
PersonNameFormatter.Length length,
|
||||
PersonNameFormatter.Usage usage,
|
||||
PersonNameFormatter.Formality formality,
|
||||
|
@ -71,7 +74,7 @@ public class PersonNameFormatterImpl {
|
|||
}
|
||||
|
||||
// load the actual formatting patterns-- since we don't know the name order until formatting time (it can be
|
||||
// different for different names), load patterns for both GN-first and SN-first names. (If the user has
|
||||
// different for different names), load patterns for both given-first and surname-first names. (If the user has
|
||||
// specified SORTING, we don't need to do this-- we just load the "sorting" patterns and ignore the name's order.)
|
||||
final String RESOURCE_PATH_PREFIX = "personNames/namePattern/";
|
||||
String resourceNameBody = length.toString().toLowerCase() + "-" + usage.toString().toLowerCase() + "-"
|
||||
|
@ -97,17 +100,41 @@ public class PersonNameFormatterImpl {
|
|||
}
|
||||
}
|
||||
|
||||
public String format(PersonNameFormatter.PersonName name) {
|
||||
/**
|
||||
* THIS IS A DUMMY CONSTRUCTOR JUST FOR THE USE OF THE UNIT TESTS TO CHECK SOME OF THE INTERNAL IMPLEMENTATION!
|
||||
*/
|
||||
public PersonNameFormatterImpl(Locale locale, String[] patterns) {
|
||||
// first, set dummy values for the other fields
|
||||
snFirstPatterns = null;
|
||||
gnFirstLocales = null;
|
||||
snFirstLocales = null;
|
||||
length = PersonNameFormatter.Length.MEDIUM;
|
||||
usage = PersonNameFormatter.Usage.REFERRING;
|
||||
formality = PersonNameFormatter.Formality.FORMAL;
|
||||
options = Collections.emptySet();
|
||||
initialPattern = "{0}.";
|
||||
initialSequencePattern = "{0} {1}";
|
||||
capitalizeSurname = false;
|
||||
foreignSpaceReplacement = " ";
|
||||
formatterLocaleUsesSpaces = true;
|
||||
|
||||
// then, set values for the fields we actually care about
|
||||
this.locale = locale;
|
||||
gnFirstPatterns = PersonNamePattern.makePatterns(patterns, this);
|
||||
|
||||
}
|
||||
|
||||
public String formatToString(PersonNameFormatter.PersonName name) {
|
||||
// TODO: Should probably return a FormattedPersonName object
|
||||
|
||||
// if the formatter is for a language that doesn't use spaces between words and the name is from a language
|
||||
// that does, create a formatter for the NAME'S locale and use THAT to format the name
|
||||
ULocale nameLocale = name.getNameLocale();
|
||||
Locale nameLocale = getNameLocale(name);
|
||||
boolean nameLocaleUsesSpaces = !LOCALES_THAT_DONT_USE_SPACES.contains(nameLocale.getLanguage());
|
||||
if (!formatterLocaleUsesSpaces && nameLocaleUsesSpaces) {
|
||||
PersonNameFormatterImpl nativeFormatter = new PersonNameFormatterImpl(nameLocale, this.length,
|
||||
this.usage, this.formality, this.options);
|
||||
String result = nativeFormatter.format(name);
|
||||
String result = nativeFormatter.formatToString(name);
|
||||
|
||||
// BUT, if the name is actually written in the formatter locale's script, replace any spaces in the name
|
||||
// with the foreignSpaceReplacement character
|
||||
|
@ -117,8 +144,8 @@ public class PersonNameFormatterImpl {
|
|||
return result;
|
||||
}
|
||||
|
||||
// if we get down to here, we're just doing normal formatting-- if we have both GN-first and SN-first rules,
|
||||
// choose which one to use based on the name's locale and preferred field order
|
||||
// if we get down to here, we're just doing normal formatting-- if we have both given-first and surname-first
|
||||
// rules, choose which one to use based on the name's locale and preferred field order
|
||||
if (snFirstPatterns == null || nameIsGnFirst(name)) {
|
||||
return getBestPattern(gnFirstPatterns, name).format(name);
|
||||
} else {
|
||||
|
@ -126,10 +153,18 @@ public class PersonNameFormatterImpl {
|
|||
}
|
||||
}
|
||||
|
||||
public ULocale getLocale() {
|
||||
public Locale getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
public PersonNameFormatter.Length getLength() { return length; }
|
||||
|
||||
public PersonNameFormatter.Usage getUsage() { return usage; }
|
||||
|
||||
public PersonNameFormatter.Formality getFormality() { return formality; }
|
||||
|
||||
public Set<PersonNameFormatter.Options> getOptions() { return options; }
|
||||
|
||||
public String getInitialPattern() {
|
||||
return initialPattern;
|
||||
}
|
||||
|
@ -142,7 +177,7 @@ public class PersonNameFormatterImpl {
|
|||
return capitalizeSurname;
|
||||
}
|
||||
|
||||
private final Set<String> LOCALES_THAT_DONT_USE_SPACES = new HashSet<>(Arrays.asList("ja", "zh", "th", "yue"));
|
||||
private final Set<String> LOCALES_THAT_DONT_USE_SPACES = new HashSet<>(Arrays.asList("ja", "zh", "th", "yue", "km", "lo"));
|
||||
|
||||
/**
|
||||
* Returns the value of the resource, as a string array.
|
||||
|
@ -164,7 +199,7 @@ public class PersonNameFormatterImpl {
|
|||
* Returns the field order to use when formatting this name, taking into account the name's preferredOrder
|
||||
* field, as well as the name and formatter's respective locales.
|
||||
* @param name The name to be formatted.
|
||||
* @return If true, use GN-first order to format the name; if false, use SN-first order.
|
||||
* @return If true, use given-first order to format the name; if false, use surname-first order.
|
||||
*/
|
||||
private boolean nameIsGnFirst(PersonNameFormatter.PersonName name) {
|
||||
// the name can declare its order-- check that first (it overrides any locale-based calculation)
|
||||
|
@ -180,7 +215,7 @@ public class PersonNameFormatterImpl {
|
|||
}
|
||||
}
|
||||
|
||||
String localeStr = name.getNameLocale().toString();
|
||||
String localeStr = getNameLocale(name).toString();
|
||||
do {
|
||||
if (gnFirstLocales.contains(localeStr)) {
|
||||
return true;
|
||||
|
@ -228,12 +263,53 @@ public class PersonNameFormatterImpl {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to figure out the name's locale when the name doesn't specify it.
|
||||
* (Note that this code assumes that if the locale is specified, it includes a language
|
||||
* code.)
|
||||
* @param name The name for which we need the locale
|
||||
* @return The name's (real or guessed) locale.
|
||||
*/
|
||||
private Locale getNameLocale(PersonNameFormatter.PersonName name) {
|
||||
// if the name specifies its locale, we can just return it
|
||||
Locale nameLocale = name.getNameLocale();
|
||||
if (nameLocale == null) {
|
||||
// if not, we look at the characters in the name. If their script matches the default script for the formatter's
|
||||
// locale, we use the formatter's locale as the name's locale
|
||||
int formatterScript = UScript.getCodeFromName(ULocale.addLikelySubtags(ULocale.forLocale(locale)).getScript());
|
||||
String givenName = name.getFieldValue(PersonNameFormatter.NameField.GIVEN, new HashSet<PersonNameFormatter.FieldModifier>());
|
||||
int nameScript = UScript.INVALID_CODE;
|
||||
for (int i = 0; nameScript == UScript.INVALID_CODE && i < givenName.length(); i++) {
|
||||
// the script of the name is the script of the first character in the name whose script isn't
|
||||
// COMMON or INHERITED
|
||||
int script = UScript.getScript(givenName.charAt(i));
|
||||
if (script != UScript.COMMON && script != UScript.INHERITED) {
|
||||
nameScript = script;
|
||||
}
|
||||
}
|
||||
if (formatterScript == nameScript) {
|
||||
nameLocale = this.locale;
|
||||
} else {
|
||||
// if the name's script is different from the formatter's script, we use addLikelySubtags() to find the
|
||||
// default language for the name's script and use THAT as the name's locale
|
||||
nameLocale = new Locale(ULocale.addLikelySubtags(new ULocale("und_" + UScript.getShortName(nameScript))).getLanguage());
|
||||
}
|
||||
// TODO: This algorithm has a few deficiencies: First, it assumes the script of the string is the script of the first
|
||||
// character in the string that's not COMMON or INHERITED. This won't work well for some languages, such as Japanese,
|
||||
// that use multiple scripts. Doing better would require adding a new getScript(String) method on UScript, which
|
||||
// might be something we want. Second, we only look at the given-name field. This field should always be populated,
|
||||
// but if it isn't, we're stuck. Looking at all the fields requires API on PersonName that we don't need anywhere
|
||||
// else.
|
||||
}
|
||||
return nameLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the script of `s` is one of the default scripts for `locale`.
|
||||
* This function only checks the script of the first character whose script isn't "common,"
|
||||
* so it probably won't work right on mixed-script strings.
|
||||
*/
|
||||
private boolean scriptMatchesLocale(String s, ULocale locale) {
|
||||
private boolean scriptMatchesLocale(String s, Locale locale) {
|
||||
int[] localeScripts = UScript.getCode(locale);
|
||||
int stringScript = UScript.COMMON;
|
||||
for (int i = 0; stringScript == UScript.COMMON && i < s.length(); i++) {
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
package com.ibm.icu.text;
|
||||
|
||||
import com.ibm.icu.impl.personname.PersonNameFormatterImpl;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
@ -21,7 +22,8 @@ import java.util.Set;
|
|||
* | MEDIUM | James E. Carter Jr. | Jimmy Carter | Mr. Carter | Jimmy | C | J |
|
||||
* | SHORT | J. E. Carter | Jimmy Carter | Mr. Carter | Jimmy | C | J |
|
||||
*
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public class PersonNameFormatter {
|
||||
//==============================================================================
|
||||
|
@ -29,43 +31,51 @@ public class PersonNameFormatter {
|
|||
|
||||
/**
|
||||
* Specifies the desired length of the formatted name.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public enum Length {
|
||||
/**
|
||||
* The longest name length. Generally uses most of the fields in the name object.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
LONG,
|
||||
|
||||
/**
|
||||
* The most typical name length. Generally includes the given name and surname, but generally
|
||||
* nost most of the other fields.
|
||||
* @internal
|
||||
* not most of the other fields.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
MEDIUM,
|
||||
|
||||
/**
|
||||
* A shortened name. Skips most fields and may abbreviate some name fields to just their initials.
|
||||
* When Formality is INFORMAL, may only include one field.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
SHORT
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the intended usage of the formatted name.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public enum Usage {
|
||||
/**
|
||||
* Used for when the name is going to be used to address the user directly: "Turn left here, John."
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
ADDRESSING,
|
||||
|
||||
/**
|
||||
* Used in general cases, when the name is used to refer to somebody else.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
REFERRING,
|
||||
|
||||
|
@ -74,47 +84,54 @@ public class PersonNameFormatter {
|
|||
* like chat avatars. In English, this is usually the person's initials, but this isn't true in all
|
||||
* languages. When the caller specifies Usage.MONOGRAM, the Length parameter can be used to get different
|
||||
* lengths of monograms: Length.SHORT is generally a single letter; Length.LONG may be as many as three or four.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
MONOGRAM
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the intended formality of the formatted name.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public enum Formality {
|
||||
/**
|
||||
* The more formal version of the name.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
FORMAL,
|
||||
|
||||
/**
|
||||
* The more informal version of the name. In English, this might omit fields or use the "informal" variant
|
||||
* of the given name.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
INFORMAL
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional options to customize the behavior of the formatter.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public enum Options {
|
||||
/**
|
||||
* Causes the formatter to generate results suitable for inclusion in a sorted list. For GN-first languages,
|
||||
* this generally means moving the surname to the beginning of the string, with a comma between it and
|
||||
* the rest of the name: e.g., "Carter, James E. Jr.".
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
SORTING,
|
||||
|
||||
/**
|
||||
* Requests that the surname in the formatted result be rendered in ALL CAPS. This is often done with
|
||||
* Japanese names to highlight which name is the surname.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
SURNAME_ALLCAPS
|
||||
}
|
||||
|
@ -124,31 +141,36 @@ public class PersonNameFormatter {
|
|||
|
||||
/**
|
||||
* Identifiers for the name fields supported by the PersonName object.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public enum NameField {
|
||||
/**
|
||||
* Contains titles and other words that precede the actual name, such as "Mr."
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
PREFIX("prefix"),
|
||||
|
||||
/**
|
||||
* The given name. May contain more than one token.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
GIVEN("given"),
|
||||
|
||||
/**
|
||||
* Additional given names. (In English, this is usually the "middle name" and
|
||||
* may contain more than one word.)
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
GIVEN2("given2"),
|
||||
|
||||
/**
|
||||
* The surname. In Spanish, this is the patronymic surname.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
SURNAME("surname"),
|
||||
|
||||
|
@ -156,14 +178,16 @@ public class PersonNameFormatter {
|
|||
* Additional surnames. This is only used in a few languages, such as Spanish,
|
||||
* where it is the matronymic surname. (In most languages, multiple surnames all
|
||||
* just go in the SURNAME field.)
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
SURNAME2("surname2"),
|
||||
|
||||
/**
|
||||
* Generational and professional qualifiers that generally follow the actual name,
|
||||
* such as "Jr." or "M.D."
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
SUFFIX("suffix"),
|
||||
|
||||
|
@ -173,7 +197,8 @@ public class PersonNameFormatter {
|
|||
* the locales of the name of the formatter. But this can be used to force a particular
|
||||
* field order, generally in cases where the deduction logic in PersonNameFormatter would
|
||||
* guess wrong. When used, the only valid values are "givenFirst" and "surnameFirst".
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
PREFERRED_ORDER("preferredOrder");
|
||||
|
||||
|
@ -185,7 +210,8 @@ public class PersonNameFormatter {
|
|||
|
||||
/**
|
||||
* Returns the NameField's display name.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -194,7 +220,8 @@ public class PersonNameFormatter {
|
|||
|
||||
/**
|
||||
* Returns the appropriate NameField for its display name.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public static NameField forString(String name) {
|
||||
for (NameField field : values()) {
|
||||
|
@ -208,7 +235,8 @@ public class PersonNameFormatter {
|
|||
|
||||
/**
|
||||
* Identifiers for the name field modifiers supported by the PersonName and PersonNameFormatter objects.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public enum FieldModifier {
|
||||
/**
|
||||
|
@ -216,7 +244,8 @@ public class PersonNameFormatter {
|
|||
* if "given" is "James", "given-informal" might be "Jimmy". Only applied to the "given"
|
||||
* field. If the PersonName object doesn't apply this modifier, PersonNameFormatter just
|
||||
* uses the unmodified version of "given".
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
INFORMAL("informal"),
|
||||
|
||||
|
@ -225,7 +254,8 @@ public class PersonNameFormatter {
|
|||
* "van den Hul", this requests just the prefixes ("van den"). Only applied to the "surname"
|
||||
* field. If the PersonName object doesn't apply this modifier, PersonNameFormatter
|
||||
* assumes there are no prefixes.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
PREFIX("prefix"),
|
||||
|
||||
|
@ -234,7 +264,8 @@ public class PersonNameFormatter {
|
|||
* "van den Hul", this requests just the main word ("Hul"). Only applied to the "surname"
|
||||
* field. If the implementing class doesn't apply this modifier, PersonNameFormatter
|
||||
* assumes the entire "surname" field is the "core".
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
CORE("core"),
|
||||
|
||||
|
@ -242,31 +273,35 @@ public class PersonNameFormatter {
|
|||
* Requests an initial for the specified field. PersonNameFormatter will do
|
||||
* this algorithmically, but a PersonName object can apply this modifier itself if it wants
|
||||
* different initial-generation logic (or stores the initial separately).
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
INITIAL("initial"),
|
||||
|
||||
/**
|
||||
* Requests an initial for the specified field, suitable for use in a monogram
|
||||
* (this usually differs from "initial" in that "initial" adds a period and "monogram" doesn't).
|
||||
* PersonNameFormatter will do this algorithmically, but a PersonName object can apply
|
||||
* this modifier itself if it wants different monogram-generation logic.
|
||||
* @internal
|
||||
* (this usually differs from "initial" in that "initial" often adds a period and "monogram"
|
||||
* never does). PersonNameFormatter will do this algorithmically, but a PersonName object can
|
||||
* apply this modifier itself if it wants different monogram-generation logic.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
MONOGRAM("monogram"),
|
||||
|
||||
/**
|
||||
* Requests the field value converted to ALL CAPS. PersonName objects
|
||||
* generally won't need to handle this modifier themselves.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
ALL_CAPS("allCaps"),
|
||||
|
||||
/**
|
||||
* Requests the field value with the first letter of each word capitalized.
|
||||
* Requests the field value with the first grapheme of each word converted to titlecase.
|
||||
* A PersonName object might handle this modifier itself to capitalize words more
|
||||
* selectively.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
INITIAL_CAP("initialCap");
|
||||
|
||||
|
@ -278,7 +313,8 @@ public class PersonNameFormatter {
|
|||
|
||||
/**
|
||||
* Returns the FieldModifier's display name.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -287,7 +323,8 @@ public class PersonNameFormatter {
|
|||
|
||||
/**
|
||||
* Returns the appropriate fieldModifier for its display name.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public static FieldModifier forString(String name) {
|
||||
for (FieldModifier modifier : values()) {
|
||||
|
@ -309,16 +346,18 @@ public class PersonNameFormatter {
|
|||
* object just for formatting) or to override the default modifier behavior described
|
||||
* above. A concrete SimplePersonName object that does store the field values directly
|
||||
* is provided.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
* @see SimplePersonName
|
||||
*/
|
||||
public interface PersonName {
|
||||
/**
|
||||
* Returns the locale of the name-- that is, the language or country of origin for the person being named.
|
||||
* @return The name's locale.
|
||||
* @internal
|
||||
* @return The name's locale, or null if it's not known.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public ULocale getNameLocale();
|
||||
public Locale getNameLocale();
|
||||
|
||||
/**
|
||||
* Returns one field of the name, possibly in a modified form.
|
||||
|
@ -329,31 +368,131 @@ public class PersonNameFormatter {
|
|||
* DIDN'T handle.
|
||||
* @return The value of the requested field, optionally modified by some or all of the requested modifiers, or
|
||||
* null if the requested field isn't present in the name.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public String getFieldValue(NameField identifier, Set<FieldModifier> modifiers);
|
||||
}
|
||||
|
||||
private final PersonNameFormatterImpl impl;
|
||||
|
||||
//==============================================================================
|
||||
// Builder for PersonNameformatter
|
||||
|
||||
/**
|
||||
* A utility class that can be used to construct a PersonNameFormatter.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public static class Builder {
|
||||
/**
|
||||
* Sets the locale for the formatter to be constructed.
|
||||
* @param locale The new formatter locale.
|
||||
* @return This builder.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public Builder setLocale(Locale locale) {
|
||||
this.locale = locale;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name length for the formatter to be constructed.
|
||||
* @param length The new name length.
|
||||
* @return This builder.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public Builder setLength(Length length) {
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name usage for the formatter to be constructed.
|
||||
* @param usage The new name length.
|
||||
* @return This builder.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public Builder setUsage(Usage usage) {
|
||||
this.usage = usage;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name formality for the formatter to be constructed.
|
||||
* @param formality The new name length.
|
||||
* @return This builder.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public Builder setFormality(Formality formality) {
|
||||
this.formality = formality;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the options set for the formatter to be constructed.
|
||||
* @param options The new options set.
|
||||
* @return This builder.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public Builder setOptions(Set<Options> options) {
|
||||
this.options = options;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new PersonNameFormatter with the values that were passed to this builder.
|
||||
* @return A new PersonNameFormatter.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public PersonNameFormatter build() {
|
||||
return new PersonNameFormatter(locale, length, usage, formality, options);
|
||||
}
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
private Locale locale = null;
|
||||
private Length length = Length.MEDIUM;
|
||||
private Usage usage = Usage.REFERRING;
|
||||
private Formality formality = Formality.FORMAL;
|
||||
private Set<Options> options = new HashSet<>();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Public API on PersonNameFormatter
|
||||
|
||||
/**
|
||||
* Constructs a PersonNameFormatter.
|
||||
* @param locale The target locale for formatted names.
|
||||
* @param length The requested length.
|
||||
* @param usage The requested usage.
|
||||
* @param formality The requested formality.
|
||||
* @param options A set containing additional formatting options. May be null.
|
||||
* @see Length
|
||||
* @see Usage
|
||||
* @see Formality
|
||||
* @see Options
|
||||
* @internal
|
||||
* Returns a Builder object that can be used to construct a new PersonNameFormatter.
|
||||
* @return A new Builder.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public PersonNameFormatter(ULocale locale, Length length, Usage usage, Formality formality, Set<Options> options) {
|
||||
this.impl = new PersonNameFormatterImpl(locale, length, usage, formality, options);
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Builder object whose fields match those used to construct this formatter,
|
||||
* allowing a new formatter to be created based on this one.
|
||||
* @return A new Builder that can be used to create a new formatter based on this formatter.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public Builder builderFromThis() {
|
||||
Builder builder = builder();
|
||||
builder.setLocale(impl.getLocale());
|
||||
builder.setLength(impl.getLength());
|
||||
builder.setUsage(impl.getUsage());
|
||||
builder.setFormality(impl.getFormality());
|
||||
builder.setOptions(impl.getOptions());
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -361,10 +500,24 @@ public class PersonNameFormatter {
|
|||
* @param name A PersonName object that supplies individual field values (optionally, with modifiers applied)
|
||||
* to the formatter for formatting.
|
||||
* @return The name, formatted according to the locale and other parameters passed to the formatter's constructor.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public String format(PersonName name) {
|
||||
// TODO: Should probably return a FormattedPersonName object
|
||||
return impl.format(name);
|
||||
public String formatToString(PersonName name) {
|
||||
// TODO: Add a format() method that returns a FormattedPersonName object that descends from FormattedValue.
|
||||
return impl.formatToString(name);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Internal implementation
|
||||
private PersonNameFormatter(Locale locale, Length length, Usage usage, Formality formality, Set<Options> options) {
|
||||
this.impl = new PersonNameFormatterImpl(locale, length, usage, formality, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal For unit testing only!
|
||||
*/
|
||||
public PersonNameFormatter(Locale locale, String[] patterns) {
|
||||
this.impl = new PersonNameFormatterImpl(locale, patterns);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,14 @@
|
|||
// License & terms of use: http://www.unicode.org/copyright.html
|
||||
package com.ibm.icu.text;
|
||||
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* A concrete implementation of PersonNameFormatter.PersonName that simply stores the field
|
||||
|
@ -13,71 +18,117 @@ import java.util.*;
|
|||
* A caller can store both raw field values (such as "given") and modified field values (such as "given-informal")
|
||||
* in a SimplePersonName. But beyond storing and returning modified field values provided to it by the caller,
|
||||
* SimplePersonName relies on the PersonNameFormatter's default handling of field modifiers.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public class SimplePersonName implements PersonNameFormatter.PersonName {
|
||||
/**
|
||||
* Simple constructor.
|
||||
* @param nameLocale The locale of the name (i.e., its ethnic or national origin).
|
||||
* @param fieldValues A Map mapping from field names to field values. The field names
|
||||
* are the values returned by NameField.toString().
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*
|
||||
*/
|
||||
public SimplePersonName(ULocale nameLocale, Map<String, String> fieldValues) {
|
||||
public static class Builder {
|
||||
/**
|
||||
* Set the locale for the new name object.
|
||||
* @param locale The locale for the new name object.
|
||||
* @return This builder.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public Builder setLocale(Locale locale) {
|
||||
this.locale = locale;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value for one field (with optional modifiers) in the new name object.
|
||||
* @param field A NameField object specifying the field to set.
|
||||
* @param modifiers A collection of FieldModifier objects for any modifiers that apply
|
||||
* to this field value. May be null, which is the same as the empty set.
|
||||
* @param value The value for this field.
|
||||
* @return This builder.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public Builder addField(PersonNameFormatter.NameField field,
|
||||
Collection<PersonNameFormatter.FieldModifier> modifiers,
|
||||
String value) {
|
||||
// generate the modifiers' internal names, and sort them alphabetically
|
||||
Set<String> modifierNames = new TreeSet<>();
|
||||
if (modifiers != null) {
|
||||
for (PersonNameFormatter.FieldModifier modifier : modifiers) {
|
||||
modifierNames.add(modifier.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// construct the modified field name, which is the field name, with all the modifier names attached in
|
||||
// alphabetical order, delimited by hyphens
|
||||
StringBuilder fieldName = new StringBuilder();
|
||||
fieldName.append(field.toString());
|
||||
for (String modifierName : modifierNames) {
|
||||
fieldName.append("-");
|
||||
fieldName.append(modifierName);
|
||||
}
|
||||
|
||||
fieldValues.put(fieldName.toString(), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a SimplePersonName with the field values and name locale that were passed to this builder.
|
||||
* @return A SimplePersonName with the field values and name locale that were passed to this builder.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public SimplePersonName build() {
|
||||
// special-case code for the "surname" field -- if it isn't specified, but "surname-prefix" and
|
||||
// "surname-core" both are, let "surname" be the other two fields joined with a space
|
||||
if (fieldValues.get("surname") == null) {
|
||||
String surnamePrefix = fieldValues.get("surname-prefix");
|
||||
String surnameCore = fieldValues.get("surname-core");
|
||||
if (surnamePrefix != null && surnameCore != null) {
|
||||
fieldValues.put("surname", surnamePrefix + " " + surnameCore);
|
||||
}
|
||||
}
|
||||
|
||||
return new SimplePersonName(locale, fieldValues);
|
||||
}
|
||||
|
||||
private Builder() {
|
||||
locale = null;
|
||||
fieldValues = new HashMap<>();
|
||||
}
|
||||
|
||||
private Locale locale;
|
||||
private Map<String, String> fieldValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Builder object that can be used to construct a new SimplePersonName object.
|
||||
* @return A Builder object that can be used to construct a new SimplePersonName object.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal constructor used by the Builder object.
|
||||
*/
|
||||
private SimplePersonName(Locale nameLocale, Map<String, String> fieldValues) {
|
||||
this.nameLocale = nameLocale;
|
||||
this.fieldValues = new HashMap<>(fieldValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructor that takes the locale ID and field values as a single String. This constructor is really
|
||||
* intended only for the use of the PersonNameFormatter unit tests.
|
||||
* @param keysAndValues A single string containing the locale ID and field values. This string is organized
|
||||
* into key-value pairs separated by commas. The keys are separated from the values
|
||||
* by equal signs. The keys themselves are field names, as returned by
|
||||
* NameField.toString(), optionally followed by a hyphen-delimited set of modifier names,
|
||||
* as returned by FieldModifier.toString().
|
||||
* @internal
|
||||
*/
|
||||
public SimplePersonName(String keysAndValues) {
|
||||
this.fieldValues = new HashMap<>();
|
||||
|
||||
StringTokenizer tok = new StringTokenizer(keysAndValues, ",");
|
||||
ULocale tempLocale = null;
|
||||
while (tok.hasMoreTokens()) {
|
||||
String entry = tok.nextToken();
|
||||
int equalPos = entry.indexOf('=');
|
||||
if (equalPos < 0) {
|
||||
throw new IllegalArgumentException("No = found in name field entry");
|
||||
}
|
||||
String fieldName = entry.substring(0, equalPos);
|
||||
String fieldValue = entry.substring(equalPos + 1);
|
||||
|
||||
if (fieldName.equals("locale")) {
|
||||
tempLocale = new ULocale(fieldValue);
|
||||
} else {
|
||||
this.fieldValues.put(fieldName, fieldValue);
|
||||
}
|
||||
}
|
||||
this.nameLocale = tempLocale;
|
||||
|
||||
// special-case code for the "surname" field-- if it isn't specified, but "surname-prefix" and
|
||||
// "surname-core" both are, let "surname" be the other two fields joined with a space
|
||||
if (this.fieldValues.get("surname") == null) {
|
||||
String surnamePrefix = this.fieldValues.get("surname-prefix");
|
||||
String surnameCore = this.fieldValues.get("surname-core");
|
||||
if (surnamePrefix != null && surnameCore != null) {
|
||||
this.fieldValues.put("surname", surnamePrefix + " " + surnameCore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the locale of the name-- that is, the language or country of origin for the person being named.
|
||||
* @return The name's locale.
|
||||
* @internal
|
||||
* @return The name's locale, or null if it's unknown.
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
@Override
|
||||
public ULocale getNameLocale() {
|
||||
public Locale getNameLocale() {
|
||||
return nameLocale;
|
||||
}
|
||||
|
||||
|
@ -92,7 +143,8 @@ public class SimplePersonName implements PersonNameFormatter.PersonName {
|
|||
* was provided at construction time.
|
||||
* @return The value of the requested field, optionally modified by some or all of the requested modifiers, or
|
||||
* null if the requested field isn't present in the name.
|
||||
* @internal
|
||||
* @internal ICU 72 technology preview
|
||||
* @deprecated This API is for technology preview only.
|
||||
*/
|
||||
@Override
|
||||
public String getFieldValue(PersonNameFormatter.NameField nameField, Set<PersonNameFormatter.FieldModifier> modifiers) {
|
||||
|
@ -158,6 +210,6 @@ public class SimplePersonName implements PersonNameFormatter.PersonName {
|
|||
return result;
|
||||
}
|
||||
|
||||
private final ULocale nameLocale;
|
||||
private final Locale nameLocale;
|
||||
private final Map<String, String> fieldValues;
|
||||
}
|
|
@ -5,7 +5,6 @@ package com.ibm.icu.dev.test.format;
|
|||
import com.ibm.icu.dev.test.TestFmwk;
|
||||
import com.ibm.icu.text.PersonNameFormatter;
|
||||
import com.ibm.icu.text.SimplePersonName;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
@ -24,23 +23,56 @@ public class PersonNameFormatterTest extends TestFmwk{
|
|||
}
|
||||
}
|
||||
|
||||
private SimplePersonName buildPersonName(String fieldsAndValues) {
|
||||
SimplePersonName.Builder builder = SimplePersonName.builder();
|
||||
|
||||
StringTokenizer entrySplitter = new StringTokenizer(fieldsAndValues, ",");
|
||||
while (entrySplitter.hasMoreTokens()) {
|
||||
String entry = entrySplitter.nextToken();
|
||||
int equalPos = entry.indexOf('=');
|
||||
if (equalPos < 0) {
|
||||
throw new IllegalArgumentException("No = found in name field entry");
|
||||
}
|
||||
String fieldName = entry.substring(0, equalPos);
|
||||
String fieldValue = entry.substring(equalPos + 1);
|
||||
|
||||
if (fieldName.equals("locale")) {
|
||||
// cheating here, because java.util.Locale doesn't have a constructor that parses an ICU-style
|
||||
// locale ID
|
||||
builder.setLocale(Locale.forLanguageTag(fieldValue.replace("_", "-")));
|
||||
} else if (fieldName.indexOf('-') < 0) {
|
||||
builder.addField(PersonNameFormatter.NameField.forString(fieldName), null, fieldValue);
|
||||
} else {
|
||||
StringTokenizer fieldNameSplitter = new StringTokenizer(fieldName, "-");
|
||||
Set<PersonNameFormatter.FieldModifier> modifiers = new HashSet<>();
|
||||
PersonNameFormatter.NameField fieldID = PersonNameFormatter.NameField.forString(fieldNameSplitter.nextToken());
|
||||
while (fieldNameSplitter.hasMoreTokens()) {
|
||||
modifiers.add(PersonNameFormatter.FieldModifier.forString(fieldNameSplitter.nextToken()));
|
||||
}
|
||||
builder.addField(fieldID, modifiers, fieldValue);
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void executeTestCases(NameAndTestCases[] namesAndTestCases, boolean forDebugging) {
|
||||
for (NameAndTestCases nameAndTestCases : namesAndTestCases) {
|
||||
SimplePersonName name = new SimplePersonName(nameAndTestCases.nameFields);
|
||||
SimplePersonName name = buildPersonName(nameAndTestCases.nameFields);
|
||||
if (forDebugging) {
|
||||
System.out.println(nameAndTestCases.nameFields);
|
||||
}
|
||||
|
||||
for (String[] testCase : nameAndTestCases.testCases) {
|
||||
ULocale formatterLocale = new ULocale(testCase[0]);
|
||||
Locale formatterLocale = Locale.forLanguageTag(testCase[0].replace('_', '-'));
|
||||
PersonNameFormatter.Length formatterLength = PersonNameFormatter.Length.valueOf(testCase[1]);
|
||||
PersonNameFormatter.Usage formatterUsage = PersonNameFormatter.Usage.valueOf(testCase[2]);
|
||||
PersonNameFormatter.Formality formatterFormality = PersonNameFormatter.Formality.valueOf(testCase[3]);
|
||||
Set<PersonNameFormatter.Options> formatterOptions = makeOptionsSet(testCase[4]);
|
||||
String expectedResult = testCase[5];
|
||||
|
||||
PersonNameFormatter formatter = new PersonNameFormatter(formatterLocale, formatterLength, formatterUsage, formatterFormality, formatterOptions);
|
||||
String actualResult = formatter.format(name);
|
||||
PersonNameFormatter formatter = PersonNameFormatter.builder().setLocale(formatterLocale).setLength(formatterLength).
|
||||
setUsage(formatterUsage).setFormality(formatterFormality).setOptions(formatterOptions).build();
|
||||
String actualResult = formatter.formatToString(name);
|
||||
|
||||
if (forDebugging) {
|
||||
System.out.println(" " + formatterLocale + "," + formatterLength + "," + formatterUsage + "," + formatterFormality + "," + formatterOptions + " => " + actualResult);
|
||||
|
@ -209,7 +241,7 @@ public class PersonNameFormatterTest extends TestFmwk{
|
|||
{ "en_US", "LONG", "MONOGRAM", "FORMAL", "", "JSS" },
|
||||
{ "en_US", "LONG", "MONOGRAM", "INFORMAL", "", "JS" },
|
||||
}),
|
||||
}, false);
|
||||
}, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -336,6 +368,93 @@ public class PersonNameFormatterTest extends TestFmwk{
|
|||
}, false);
|
||||
}
|
||||
|
||||
// need tests (and implementation?) for:
|
||||
// - foreign space replacement
|
||||
@Test
|
||||
public void TestScriptGuessing() {
|
||||
executeTestCases(new NameAndTestCases[]{
|
||||
// here, we're leaving out the locale on the name object. In the first case, we
|
||||
// see the Latin letters and assume English, giving us GN-first ordering. In the
|
||||
// second, we see the Han characters and guess Japanese, giving us SN-first ordering.
|
||||
new NameAndTestCases("given=Hayao,surname=Miyazaki", new String[][]{
|
||||
{"en_US", "LONG", "REFERRING", "FORMAL", "", "Hayao Miyazaki"},
|
||||
}),
|
||||
new NameAndTestCases("given=駿,surname=宮崎", new String[][]{
|
||||
{"en_US", "LONG", "REFERRING", "FORMAL", "", "宮崎 駿"},
|
||||
}),
|
||||
}, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestLiteralTextElision2() {
|
||||
// a more extensive text of the literal text elision logic
|
||||
PersonNameFormatter pnf = new PersonNameFormatter(Locale.US, new String[] {
|
||||
"1{prefix}1 2{given}2 3{given2}3 4{surname}4 5{surname2}5 6{suffix}6"
|
||||
});
|
||||
|
||||
String[][] testCases = new String[][] {
|
||||
{ "locale=en_US,prefix=Dr.,given=Richard,given2=Theodore,surname=Gillam,surname2=Morgan,suffix=III", "1Dr.1 2Richard2 3Theodore3 4Gillam4 5Morgan5 6III6" },
|
||||
{ "locale=en_US,prefix=Mr.,given=Richard,given2=Theodore,surname=Gillam", "1Mr.1 2Richard2 3Theodore3 4Gillam" },
|
||||
{ "locale=en_US,given=Richard,given2=Theodore,surname=Gillam", "Richard2 3Theodore3 4Gillam" },
|
||||
{ "locale=en_US,given=Richard,surname=Gillam", "Richard2 4Gillam" },
|
||||
{ "locale=en_US,given=Richard", "Richard" },
|
||||
{ "locale=en_US,prefix=Dr.,suffix=III", "1Dr.1 6III6" }
|
||||
};
|
||||
|
||||
for (String[] testCase : testCases) {
|
||||
SimplePersonName name = buildPersonName(testCase[0]);
|
||||
String expectedResult = testCase[1];
|
||||
String actualResult = pnf.formatToString(name);
|
||||
|
||||
assertEquals("Wrong result", expectedResult, actualResult);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestPatternSelection() {
|
||||
// a more extensive test of the logic that selects an appropriate pattern when the formatter has more than one
|
||||
PersonNameFormatter pnf = new PersonNameFormatter(Locale.US, new String[] {
|
||||
"A {prefix} {given} {given2} {surname} {surname2} {suffix}",
|
||||
"B {given} {given2} {surname} {surname2}",
|
||||
"C {given} {surname}",
|
||||
});
|
||||
|
||||
String[][] testCases = new String[][] {
|
||||
{ "locale=en_US,prefix=Dr.,given=Richard,given2=Theodore,surname=Gillam,surname2=Morgan,suffix=III", "A Dr. Richard Theodore Gillam Morgan III" },
|
||||
{ "locale=en_US,prefix=Mr.,given=Richard,given2=Theodore,surname=Gillam", "A Mr. Richard Theodore Gillam" },
|
||||
{ "locale=en_US,given=Richard,given2=Theodore,surname=Gillam", "B Richard Theodore Gillam" },
|
||||
{ "locale=en_US,given=Richard,surname=Gillam", "C Richard Gillam" },
|
||||
{ "locale=en_US,given=Richard", "C Richard" },
|
||||
{ "locale=en_US,prefix=Dr.,suffix=III", "A Dr. III" }
|
||||
};
|
||||
|
||||
for (String[] testCase : testCases) {
|
||||
SimplePersonName name = buildPersonName(testCase[0]);
|
||||
String expectedResult = testCase[1];
|
||||
String actualResult = pnf.formatToString(name);
|
||||
|
||||
assertEquals("Wrong result", expectedResult, actualResult);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestCapitalization() {
|
||||
// a more extensive test of the capitalization logic to make sure it works right with characters that
|
||||
// have a separate titlecase form
|
||||
SimplePersonName name = buildPersonName("locale=hu_HU,given=dzsárgál,surname=dziatkowicz");
|
||||
|
||||
String[][] testCases = new String[][] {
|
||||
{ "{surname} {given}", "dziatkowicz dzsárgál" },
|
||||
{ "{surname-initialCap} {given-initialCap}", "Dziatkowicz Dzsárgál"},
|
||||
{ "{surname-allCaps} {given-allCaps}", "DZIATKOWICZ DZSÁRGÁL" },
|
||||
{ "{surname-monogram}{given-monogram}", "dzdz" },
|
||||
{ "{surname-initial} {given-initial}", "dz. dz." }
|
||||
};
|
||||
|
||||
for (String[] testCase : testCases) {
|
||||
PersonNameFormatter pnf = new PersonNameFormatter(new Locale("hu", "HU"), new String[] { testCase[0] } );
|
||||
String expectedResult = testCase[1];
|
||||
String actualResult = pnf.formatToString(name);
|
||||
|
||||
assertEquals("Wrong result", expectedResult, actualResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue