• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

coditory / quark-i18n / #12

pending completion
#12

push

github-actions

ogesaku
Expand localized messages api

22 of 22 new or added lines in 3 files covered. (100.0%)

1596 of 2144 relevant lines covered (74.44%)

0.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.31
/src/main/java/com/coditory/quark/i18n/loader/I18nClassPathLoader.java
1
package com.coditory.quark.i18n.loader;
2

3
import com.coditory.quark.i18n.I18nKey;
4
import com.coditory.quark.i18n.I18nPath;
5
import com.coditory.quark.i18n.loader.I18nPathPattern.I18nPathGroups;
6
import com.coditory.quark.i18n.parser.I18nParser;
7
import org.jetbrains.annotations.NotNull;
8
import org.slf4j.Logger;
9
import org.slf4j.LoggerFactory;
10

11
import java.io.BufferedReader;
12
import java.io.InputStreamReader;
13
import java.util.ArrayList;
14
import java.util.List;
15
import java.util.Locale;
16
import java.util.Map;
17
import java.util.Set;
18

19
import static java.util.Collections.unmodifiableList;
20
import static java.util.Objects.requireNonNull;
21

22
final class I18nClassPathLoader implements I18nLoader {
23
    static I18nFileLoaderBuilder builder() {
24
        return builder(Thread.currentThread().getContextClassLoader());
×
25
    }
26

27
    static I18nFileLoaderBuilder builder(ClassLoader classLoader) {
28
        return new I18nFileLoaderBuilder()
1✔
29
                .scanClassPath(classLoader);
1✔
30
    }
31

32
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
1✔
33
    private final Set<I18nPathPattern> pathPatterns;
34
    private final ClassLoader classLoader;
35
    private final I18nParser parser;
36
    private final Map<String, I18nParser> parsersByExtension;
37
    private final I18nPath staticPrefix;
38

39
    I18nClassPathLoader(
40
            Set<I18nPathPattern> pathPatterns,
41
            ClassLoader classLoader,
42
            I18nParser fileParser,
43
            Map<String, I18nParser> parsersByExtension,
44
            I18nPath staticPrefix
45
    ) {
1✔
46
        this.classLoader = requireNonNull(classLoader);
1✔
47
        this.staticPrefix = requireNonNull(staticPrefix);
1✔
48
        this.pathPatterns = Set.copyOf(pathPatterns);
1✔
49
        this.parsersByExtension = Map.copyOf(parsersByExtension);
1✔
50
        this.parser = fileParser;
1✔
51
    }
1✔
52

53
    @NotNull
54
    @Override
55
    public synchronized List<I18nMessageBundle> load() {
56
        List<I18nMessageBundle> result = new ArrayList<>();
1✔
57
        for (I18nPathPattern pathPattern : pathPatterns) {
1✔
58
            List<Resource> resources = scanFiles(pathPattern);
1✔
59
            for (Resource resource : resources) {
1✔
60
                I18nMessageBundle templates = load(pathPattern, resource);
1✔
61
                result.add(templates);
1✔
62
                logger.debug("Loaded message bundle: {}", resource.url());
1✔
63
            }
1✔
64
        }
1✔
65
        return unmodifiableList(result);
1✔
66
    }
67

68
    private I18nMessageBundle load(I18nPathPattern pathPattern, Resource resource) {
69
        I18nPathGroups matchedGroups = pathPattern.matchGroups(resource.name());
1✔
70
        return load(resource, matchedGroups);
1✔
71
    }
72

73
    private I18nMessageBundle load(Resource resource, I18nPathGroups matchedGroups) {
74
        Locale locale = matchedGroups.locale();
1✔
75
        I18nPath prefix = matchedGroups.path() != null
1✔
76
                ? staticPrefix.child(matchedGroups.path())
1✔
77
                : staticPrefix;
1✔
78
        Map<I18nKey, String> parsed = parseFile(locale, resource);
1✔
79
        return new I18nMessageBundle(parsed, prefix);
1✔
80
    }
81

82
    private List<Resource> scanFiles(I18nPathPattern pathPattern) {
83
        return ResourceScanner.scanClassPath(classLoader, pathPattern);
1✔
84
    }
85

86
    private Map<I18nKey, String> parseFile(Locale locale, Resource resource) {
87
        String extension = getExtension(resource.name());
1✔
88
        I18nParser parser = parsersByExtension.getOrDefault(extension, this.parser);
1✔
89
        if (parser == null) {
1✔
90
            throw new I18nLoadException("No file parser defined for: " + resource.name());
×
91
        }
92
        String content = readFile(resource);
1✔
93
        if (content.isBlank()) {
1✔
94
            return Map.of();
×
95
        }
96
        try {
97
            return parser.parse(content, locale);
1✔
98
        } catch (Throwable e) {
×
99
            throw new I18nLoadException("Could not parse file: " + resource.name(), e);
×
100
        }
101
    }
102

103
    private String readFile(Resource resource) {
104
        try {
105
            StringBuilder resultStringBuilder = new StringBuilder();
1✔
106
            try (BufferedReader br = new BufferedReader(new InputStreamReader(resource.url().openStream()))) {
1✔
107
                String line;
108
                while ((line = br.readLine()) != null) {
1✔
109
                    resultStringBuilder.append(line).append("\n");
1✔
110
                }
111
            }
112
            return resultStringBuilder.toString();
1✔
113
        } catch (Throwable e) {
×
114
            throw new I18nLoadException("Could not read classpath resource: " + resource.name(), e);
×
115
        }
116
    }
117

118
    private String getExtension(String resourceName) {
119
        int idx = resourceName.lastIndexOf('.');
1✔
120
        return idx == 0 || idx == resourceName.length() - 1
1✔
121
                ? null
×
122
                : resourceName.substring(idx + 1);
1✔
123
    }
124
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc