github
Github: github.com/zhouyueyued…
introduce
EasyIntern is an internationalization plug-in based on IDEA IDE. Based on the excel internationalization form given by the product, it can flexibly handle the internationalization of the language in the form. The main features are as follows
- Currently supported
<string>
The labels and<string-array>
The label. - The plug-in will default to the values given by the form
name
Value, and supports pairsname
Values andvalue
Value of editing - Special characters such as Spaces and & are replaced by default
- For text substitution problems, the plugin will automatically extract suspected conflicts by comparing the similarity of a single item before writing to the file
name
andvalue
Let the user edit in the page, of course you can also directly generate new files, copy and paste, and then in studiostrings-xx
In-file editing
Easyintern origin
In international dictionaries, a large number of newly added and revised international texts are often involved. The common solution is to use scripting languages to write scripts for specific scenarios. The disadvantages are shown below
- You can’t use a scripting language multiple times.
- Scripts generally have no specific editing capabilities
I also couldn’t find a project on Github to solve this problem. In view of the above pain points, it is found that idea plug-in mode can be well solved. Just do one thing, use Excel to write internationalization copywriting, and in the plug-in in the subsequent extension can flexibly add support for various formats, even for white users, call the translation engine developed by ourselves, forming an automatic internationalization process is also very convenient.
Easyintern principle
The UI uses the Java Swing-based API provided by IDEA
Read Excel data usingorg.apache.poi
A set of Excel reading framework can be
The user can flexibly specify the valid data area and the
tag area in Excel, and then use the above reading framework to transform the UI to display the desired data
At the bottom of similarity calculation, text editing distance is used, as shown in the following figure
The Java-XML conversion uses JAXB parsing, as shown in the following example
- Build based on
strings.xml
The model of
package com.youdao.model;
import javax.xml.bind.annotation.*;
import java.util.List;
/ * * *@XmlRootElement(name = "resources") The root element is <resources></resource> *@XmlAccessorTypeFIELD: Maps all fields in this class to XML * XmlAccessType.PROPERTY: Map attributes in this class (get/set methods) to XML * XmlAccessType.PUBLIC_MEMBER: Map all public fields or properties in this class simultaneously to XML (default) * XmlAccessType.NONE: Does not map * *@XmlElement(name = "string") maps the child element * labeled <string> under the root element@XmlAttribute(name = "name") The attribute under the mapping element is name to XML,<string name = "XXX "></string> *@XmlValueThe value under the mapping element, for example, <string name=""> XXX </>, XXX indicates the value of the field under the annotation of the label */
@XmlRootElement(name = "resources")
@XmlAccessorType(XmlAccessType.FIELD)
public class AndroidStringXmlModel {
@XmlElement(name = "string")
private List<StringMapModel> stringMapModelList;
@XmlElement(name = "string-array")
private List<StringArrayMapModel> stringArrayMapModels;
@XmlAccessorType(XmlAccessType.FIELD)
public static class StringMapModel {
@XmlAttribute(name = "name")
String name;
@XmlValue
String value;
@XmlAttribute(name = "tools:ignore")
String toolIgnore;
public String getName(a) {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue(a) {
return value;
}
public String getToolIgnore(a) {
return toolIgnore;
}
public void setToolIgnore(String toolIgnore) {
this.toolIgnore = toolIgnore;
}
public void setValue(String value) {
this.value = value; }}@XmlAccessorType(XmlAccessType.FIELD)
public static class StringArrayMapModel {
@XmlAttribute(name = "name")
String name;
List<String> item;
public String getName(a) {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getItems(a) {
return item;
}
public void setItems(List<String> item) {
this.item = item; }}public List<StringMapModel> getStringMapModelList(a) {
return stringMapModelList;
}
public void setStringMapModelList(List<StringMapModel> stringMapModelList) {
this.stringMapModelList = stringMapModelList;
}
public List<StringArrayMapModel> getStringArrayMapModels(a) {
return stringArrayMapModels;
}
public void setStringArrayMapModels(List<StringArrayMapModel> stringArrayMapModels) {
this.stringArrayMapModels = stringArrayMapModels;
}
public String getXmlnsTools(a) {
return xmlnsTools;
}
public void setXmlnsTools(String xmlnsTools) {
this.xmlnsTools = xmlnsTools; }}Copy the code
- The input
strings.xml
Deserialize the file to a Java Model
fun readStringsXmlByPath(path: String): AndroidStringXmlModel {
val mJaxb = JAXBContext.newInstance(AndroidStringXmlModel::class.java)
val unmarshaller = mJaxb.createUnmarshaller()
val stream = FileInputStream(path)
val model = unmarshaller.unmarshal(stream) as AndroidStringXmlModel
return model
}
Copy the code
- Enter the Java Model, serialized to strings.xml
fun writeModelToXml(model: AndroidStringXmlModel? , path: String, append: kotlin.Boolean) {
// To get JAXB's context, you need to pass in the concrete Java bean -> use Student here
val context = JAXBContext.newInstance(AndroidStringXmlModel::class.java/ / createMarshallerThe instanceval marshaller = context.createMarshaller()
// Set conversion parameters -> Here is an example of telling the serializer whether to format output
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE)
// Build the output environment
val out = FileOutputStream(path, append)
// Serialize the desired object -> This method returns no value
marshaller.marshal(model, out)
}
Copy the code
Potholes encountered during development
java.lang.ClassCastException: com.sun.org.apache.xerces.internal.parsers.SAXParser cannot be cast to org.xml.sax.XMLReader
The SAXParser class and the XmlReader class are loaded with two different classloaders
Solution: Search the network fruitless, find the reason as shown in the picture below:
- Special characters need to be handled in XML parsing