Skip to content

Commit c513e80

Browse files
committed
feat: Replace custom MessageFormatParser with ICUTemplateArgumentsParser for improved i18n argument handling
- Remove obsolete MessageFormatParser.java and related code - Implement ICUTemplateArgumentsParser parsing ICU format arguments with comprehensive type resolution - Update I18nJavaPoetCodeGenerator to use new parser for method parameter generation - Add extensive test suite for parser covering all ICU argument types and edge cases
1 parent c108b95 commit c513e80

7 files changed

Lines changed: 610 additions & 174 deletions

File tree

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.vgerbot.propify;
2+
3+
import com.ibm.icu.text.MessageFormat;
4+
5+
import java.text.FieldPosition;
6+
import java.util.Date;
7+
import java.util.HashMap;
8+
import java.util.Map;
9+
10+
public class Main {
11+
public static void main(String[] args) {
12+
test1();
13+
}
14+
private static void test1() {
15+
16+
String format = "hello {name}";
17+
MessageFormat mf = new MessageFormat(format);
18+
Map<Object, Object> arguments = new HashMap<>();
19+
arguments.put("name", "world");
20+
21+
FieldPosition fp = new FieldPosition(1);
22+
StringBuffer sb = new StringBuffer();
23+
try{
24+
sb = mf.format(arguments, sb, fp);
25+
System.out.println(sb.toString());
26+
}catch(IllegalArgumentException e){
27+
e.printStackTrace();
28+
}
29+
}
30+
private static void test0() {
31+
String format = "At {1,time,::jmm} on {1,date,::dMMMM}, there was {2} on planet {3,number,integer}.";
32+
MessageFormat mf = new MessageFormat(format);
33+
// Map<Object, Object> arguments = new HashMap<>();
34+
// arguments.put(1, new Date());
35+
// arguments.put(2, new Date());
36+
// arguments.put(3, "a Disturbance in the Force");
37+
// arguments.put(4, 5);
38+
39+
Object[] arguments = new Object[]{
40+
new Date(),
41+
new Date(),
42+
"a Disturbance in the Force",
43+
5
44+
};
45+
46+
FieldPosition fp = new FieldPosition(1);
47+
StringBuffer sb = new StringBuffer();
48+
try{
49+
sb = mf.format(arguments, sb, fp);
50+
System.out.println(sb.toString());
51+
}catch(IllegalArgumentException e){
52+
e.printStackTrace();
53+
}
54+
}
55+
}

propify/src/main/java/com/vgerbot/propify/common/MessageFormatParser.java

Lines changed: 0 additions & 85 deletions
This file was deleted.

propify/src/main/java/com/vgerbot/propify/common/Utils.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ public static String[] getClassesFromAnnotationValue(AnnotationValue annotationV
241241
}).toArray(String[]::new);
242242
}
243243
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
244+
System.err.println("access javac util list error" + e.toString());
244245
throw new RuntimeException(e);
245246
}
246247
}
Lines changed: 14 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
11
package com.vgerbot.propify.generator;
22

3-
import com.ibm.icu.text.MessageFormat;
4-
import com.ibm.icu.text.MeasureFormat;
5-
import com.ibm.icu.text.MessagePattern;
63
import com.squareup.javapoet.*;
7-
import com.vgerbot.propify.common.MessageFormatParser;
84
import com.vgerbot.propify.common.Utils;
5+
import com.vgerbot.propify.i18n.ICUMessageTemplateExtension;
6+
import com.vgerbot.propify.i18n.ICUTemplateArgumentsParser;
97
import com.vgerbot.propify.i18n.Message;
108
import com.vgerbot.propify.i18n.PropifyI18nResourceBundle;
11-
import com.vgerbot.propify.i18n.ICUMessageTemplateExtension;
129

1310
import javax.lang.model.element.Modifier;
14-
import java.lang.reflect.Field;
15-
import java.text.Format;
16-
import java.util.*;
11+
import java.util.ArrayList;
12+
import java.util.List;
13+
import java.util.Locale;
14+
import java.util.ResourceBundle;
1715
import java.util.stream.Collectors;
18-
import java.util.Date;
1916

2017
public class I18nJavaPoetCodeGenerator {
2118
private static class SingletonHolder {
@@ -69,43 +66,28 @@ private Iterable<MethodSpec> generateInterfaceMethods(ResourceBundle bundle) {
6966
return bundle.keySet().stream().map(key -> {
7067
String methodName = Utils.convertToFieldName(key);
7168
Object value = bundle.getObject(key);
72-
List<ParameterSpec> parameterSpecs = new ArrayList<>();;
73-
Set<String> formatArgumentNames = new HashSet<>();
74-
if (value instanceof CharSequence) {
75-
List<MessageFormatParser.PlaceholderInfo> placeholders = MessageFormatParser.parsePlaceholders(value.toString());
69+
List<ICUTemplateArgumentsParser.Argument> arguments;
7670

77-
placeholders.forEach(placeholder -> {
78-
Class<?> type = getArgType(placeholder.getFormatType());
79-
String argName = placeholder.getName();
80-
formatArgumentNames.add(argName);
81-
parameterSpecs.add(
82-
ParameterSpec.builder(type, Utils.convertToFieldName(argName)).build()
83-
);
84-
});
71+
if (value instanceof CharSequence) {
72+
arguments = ICUTemplateArgumentsParser.parseTemplate(value.toString());
73+
} else {
74+
arguments = new ArrayList<>(0);
8575
}
8676

87-
String[] parameterNames = parameterSpecs.stream().map(it -> it.name).toArray(String[]::new);
88-
String format = "{" + String.join(",", Arrays.stream(parameterNames).map(v -> "$S").toArray(String[]::new)) + "}";
77+
String format = "{" + arguments.stream().map(v -> "$S").collect(Collectors.joining(",")) + "}";
8978
AnnotationSpec annotation = AnnotationSpec.builder(Message.class)
9079
.addMember("key", CodeBlock.of("$S", key))
91-
.addMember("arguments", CodeBlock.of(format, formatArgumentNames.stream().toArray()))
80+
.addMember("arguments", CodeBlock.of(format, arguments.stream().map(ICUTemplateArgumentsParser.Argument::getName).toArray()))
9281
.build();
9382
return MethodSpec.methodBuilder(methodName)
9483
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
9584
.returns(String.class)
96-
.addParameters(parameterSpecs)
85+
.addParameters(arguments.stream().map(it -> ParameterSpec.builder(it.getType(), Utils.convertToFieldName(it.getName())).build()).collect(Collectors.toList()))
9786
.addAnnotation(annotation)
9887
.build();
9988
}).collect(Collectors.toList());
10089
}
10190

102-
private List<ParameterSpec> generateMethodParameters(String pattern) {
103-
MessageFormat format = new MessageFormat(pattern);
104-
Set<String> argumentNames = format.getArgumentNames();
105-
return argumentNames.stream().map(argName -> ParameterSpec.builder(String.class, Utils.convertToFieldName(argName)).build())
106-
.collect(Collectors.toList());
107-
}
108-
10991
private MethodSpec generateGetMethod() {
11092
return MethodSpec.methodBuilder("get")
11193
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
@@ -125,61 +107,4 @@ private MethodSpec generateGetDefaultMethod(String defaultLocale) {
125107
: CodeBlock.of("return get($T.forLanguageTag($S))", Locale.class, defaultLocale))
126108
.build();
127109
}
128-
129-
/**
130-
* Determines the appropriate Java type based on the format type
131-
* @param format The ICU Format object
132-
* @return The appropriate Java class type for the parameter
133-
*/
134-
private Class<?> getArgTypeFromFormat(Format format) {
135-
if (format == null) {
136-
return String.class;
137-
}
138-
139-
// ICU NumberFormat and its subclasses
140-
if (format instanceof com.ibm.icu.text.NumberFormat) {
141-
return Number.class;
142-
}
143-
144-
// ICU DateFormat and its subclasses
145-
if (format instanceof com.ibm.icu.text.DateFormat) {
146-
return Date.class;
147-
}
148-
149-
// MeasureFormat uses Measure objects with Number values
150-
if (format instanceof com.ibm.icu.text.MeasureFormat) {
151-
return Number.class;
152-
}
153-
154-
// Plural format typically takes numbers
155-
if (format instanceof com.ibm.icu.text.PluralFormat) {
156-
return Number.class;
157-
}
158-
159-
// Select format takes strings
160-
if (format instanceof com.ibm.icu.text.SelectFormat) {
161-
return String.class;
162-
}
163-
164-
// For any other format type
165-
return Object.class;
166-
}
167-
private Class<?> getArgType(String type) {
168-
if(type == null) {
169-
return String.class;
170-
}
171-
switch (type) {
172-
case "date":
173-
return Date.class;
174-
case "number":
175-
return Number.class;
176-
case "select":
177-
return String.class;
178-
case "plural":
179-
case "selectordinal":
180-
case "choice":
181-
return Number.class;
182-
}
183-
return Object.class;
184-
}
185110
}

0 commit comments

Comments
 (0)