1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package io.wcm.maven.plugins.i18n;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.nio.charset.StandardCharsets;
25 import java.util.Collections;
26 import java.util.List;
27
28 import javax.inject.Inject;
29
30 import org.apache.commons.lang3.StringUtils;
31 import org.apache.commons.lang3.Strings;
32 import org.apache.maven.model.Build;
33 import org.apache.maven.model.Resource;
34 import org.apache.maven.plugin.AbstractMojo;
35 import org.apache.maven.plugin.MojoExecutionException;
36 import org.apache.maven.plugin.MojoFailureException;
37 import org.apache.maven.plugins.annotations.LifecyclePhase;
38 import org.apache.maven.plugins.annotations.Mojo;
39 import org.apache.maven.plugins.annotations.Parameter;
40 import org.apache.maven.project.MavenProject;
41 import org.codehaus.plexus.util.FileUtils;
42 import org.codehaus.plexus.util.Scanner;
43 import org.sonatype.plexus.build.incremental.BuildContext;
44
45 import io.wcm.maven.plugins.i18n.readers.I18nReader;
46 import io.wcm.maven.plugins.i18n.readers.JsonI18nReader;
47 import io.wcm.maven.plugins.i18n.readers.PropertiesI18nReader;
48 import io.wcm.maven.plugins.i18n.readers.XmlI18nReader;
49
50
51
52
53 @Mojo(name = "transform", defaultPhase = LifecyclePhase.GENERATE_RESOURCES, requiresProject = true, threadSafe = true)
54 @SuppressWarnings("java:S6813")
55 public class TransformMojo extends AbstractMojo {
56
57
58 private static final String FILE_EXTENSION_JSON = "json";
59 private static final String FILE_EXTENSION_XML = "xml";
60 private static final String FILE_EXTENSION_PROPERTIES = "properties";
61
62 private static final String ALL_FILES = "**/*.";
63 private static final String[] SOURCE_FILES_INCLUDES = new String[] {
64 ALL_FILES + FILE_EXTENSION_PROPERTIES,
65 ALL_FILES + FILE_EXTENSION_XML,
66 ALL_FILES + FILE_EXTENSION_JSON
67 };
68
69
70
71
72 @Parameter(defaultValue = "${basedir}/src/main/resources/i18n")
73 private String source;
74
75
76
77
78 @Parameter(defaultValue = "SLING-INF/app-root/i18n")
79 private String target;
80
81
82
83
84
85
86
87
88
89
90 @Parameter(defaultValue = "JSON")
91 private String outputFormat;
92
93 @Parameter(defaultValue = "generated-i18n-resources")
94 private String generatedResourcesFolderPath;
95
96 @Parameter(property = "project", required = true, readonly = true)
97 private MavenProject project;
98
99 @Inject
100 private BuildContext buildContext;
101
102 private File generatedResourcesFolder;
103 private List<File> i18nSourceFiles;
104
105 @Override
106 public void execute() throws MojoExecutionException, MojoFailureException {
107 OutputFormat selectedOutputFormat = OutputFormat.valueOf(StringUtils.upperCase(outputFormat));
108 try {
109 File sourceDirectory = getSourceDirectory();
110 intialize(sourceDirectory);
111
112
113 if (buildContext.isIncremental() && !isI18nSourceFileChanged(sourceDirectory)) {
114 return;
115 }
116
117 List<File> sourceFiles = getI18nSourceFiles(sourceDirectory);
118 for (File file : sourceFiles) {
119 transformFile(file, selectedOutputFormat);
120 }
121 }
122 catch (IOException ex) {
123 throw new MojoFailureException("Failure to transform i18n resources", ex);
124 }
125 }
126
127 private void transformFile(File file, OutputFormat selectedOutputFormat) throws MojoFailureException {
128 try {
129
130 String languageKey = FileUtils.removeExtension(file.getName());
131 I18nReader reader = getI18nReader(file);
132 SlingI18nMap i18nMap = new SlingI18nMap(languageKey, reader.read(file));
133
134
135 File targetFile = getTargetFile(file, selectedOutputFormat);
136 writeTargetI18nFile(i18nMap, targetFile, selectedOutputFormat);
137
138 getLog().info("Transformed " + file.getPath() + " to " + targetFile.getPath());
139 }
140 catch (IOException ex) {
141 throw new MojoFailureException("Unable to transform i18n resource: " + file.getPath(), ex);
142 }
143 }
144
145
146
147
148
149
150 private boolean isI18nSourceFileChanged(File sourceDirectory) {
151 Scanner scanner = buildContext.newScanner(sourceDirectory);
152 Scanner deleteScanner = buildContext.newDeleteScanner(sourceDirectory);
153 return isI18nSourceFileChanged(scanner) || isI18nSourceFileChanged(deleteScanner);
154 }
155
156 private boolean isI18nSourceFileChanged(Scanner scanner) {
157 scanner.setIncludes(SOURCE_FILES_INCLUDES);
158 scanner.addDefaultExcludes();
159 scanner.scan();
160 return scanner.getIncludedFiles().length > 0;
161 }
162
163
164
165
166
167 private void intialize(File sourceDirectory) throws IOException {
168 getLog().debug("Initializing i18n plugin...");
169
170
171 if (!getI18nSourceFiles(sourceDirectory).isEmpty()) {
172 File myGeneratedResourcesFolder = getGeneratedResourcesFolder();
173 addResource(myGeneratedResourcesFolder.getPath(), target);
174 }
175
176 }
177
178 private void addResource(String generatedResourcesDirectory, String targetPath) {
179
180
181 Resource resource = new Resource();
182 resource.setDirectory(generatedResourcesDirectory);
183 resource.setTargetPath(targetPath);
184
185
186 Build build = this.project.getBuild();
187 build.addResource(resource);
188 getLog().debug("Added resource: " + resource.getDirectory() + " -> " + resource.getTargetPath());
189 }
190
191
192
193
194
195
196 private List<File> getI18nSourceFiles(File sourceDirectory) throws IOException {
197
198 if (i18nSourceFiles == null) {
199 if (!sourceDirectory.isDirectory()) {
200 i18nSourceFiles = Collections.emptyList();
201 }
202 else {
203
204 String includes = StringUtils.join(SOURCE_FILES_INCLUDES, ",");
205 String excludes = FileUtils.getDefaultExcludesAsString();
206
207 i18nSourceFiles = FileUtils.getFiles(sourceDirectory, includes, excludes);
208 }
209 }
210
211 return i18nSourceFiles;
212 }
213
214
215
216
217
218 private File getSourceDirectory() throws IOException {
219 File file = new File(source);
220 if (!file.isDirectory()) {
221 getLog().debug("Could not find directory at '" + source + "'");
222 }
223 return file.getCanonicalFile();
224 }
225
226
227
228
229
230
231
232 private void writeTargetI18nFile(SlingI18nMap i18nMap, File targetfile, OutputFormat selectedOutputFormat) throws IOException {
233 switch (selectedOutputFormat) {
234 case XML:
235 FileUtils.fileWrite(targetfile, StandardCharsets.UTF_8.name(), i18nMap.getI18nXmlString());
236 break;
237 case PROPERTIES:
238 FileUtils.fileWrite(targetfile, StandardCharsets.ISO_8859_1.name(), i18nMap.getI18nPropertiesString());
239 break;
240 case JSON:
241 FileUtils.fileWrite(targetfile, StandardCharsets.UTF_8.name(), i18nMap.getI18nJsonString());
242 break;
243 case JSON_PROPERTIES:
244 FileUtils.fileWrite(targetfile, StandardCharsets.UTF_8.name(), i18nMap.getI18nJsonPropertiesString());
245 break;
246 default:
247 throw new IllegalArgumentException("Unsupported ouptut format: " + selectedOutputFormat);
248
249 }
250 buildContext.refresh(targetfile);
251 }
252
253
254
255
256
257
258
259 private File getTargetFile(File sourceFile, OutputFormat selectedOutputFormat) throws IOException {
260
261 File sourceDirectory = getSourceDirectory();
262 String relativePath = StringUtils.substringAfter(sourceFile.getAbsolutePath(), sourceDirectory.getAbsolutePath());
263 String relativeTargetPath = FileUtils.removeExtension(relativePath) + "." + selectedOutputFormat.getFileExtension();
264
265 File jsonFile = new File(getGeneratedResourcesFolder().getPath() + relativeTargetPath);
266
267 jsonFile = jsonFile.getCanonicalFile();
268
269 File parentDirectory = jsonFile.getParentFile();
270 if (!parentDirectory.exists()) {
271 if (!parentDirectory.mkdirs()) {
272 throw new IOException("Unable to create directory: " + parentDirectory.getPath());
273 }
274 buildContext.refresh(parentDirectory);
275 }
276
277 return jsonFile;
278 }
279
280 private File getGeneratedResourcesFolder() throws IOException {
281 if (generatedResourcesFolder == null) {
282 generatedResourcesFolder = new File(this.project.getBuild().getDirectory(), generatedResourcesFolderPath);
283 if (!generatedResourcesFolder.exists()) {
284 if (!generatedResourcesFolder.mkdirs()) {
285 throw new IOException("Unable to create directory: " + generatedResourcesFolder.getPath());
286 }
287 buildContext.refresh(generatedResourcesFolder);
288 }
289 }
290 return generatedResourcesFolder;
291 }
292
293
294
295
296
297
298 private I18nReader getI18nReader(File sourceFile) throws MojoFailureException {
299 String extension = FileUtils.getExtension(sourceFile.getName());
300 if (Strings.CI.equals(extension, FILE_EXTENSION_PROPERTIES)) {
301 return new PropertiesI18nReader();
302 }
303 if (Strings.CI.equals(extension, FILE_EXTENSION_XML)) {
304 return new XmlI18nReader();
305 }
306 if (Strings.CI.equals(extension, FILE_EXTENSION_JSON)) {
307 return new JsonI18nReader();
308 }
309 throw new MojoFailureException("Unsupported file extension '" + extension + "': " + sourceFile.getAbsolutePath());
310 }
311
312 }