diff --git a/server/src/main/resources/web/officeweb.ftl b/server/src/main/resources/web/officeweb.ftl index 8f6c2b77..f174ad18 100644 --- a/server/src/main/resources/web/officeweb.ftl +++ b/server/src/main/resources/web/officeweb.ftl @@ -30,15 +30,15 @@ watermark_y: 0, watermark_rows: 0, watermark_cols: 0, - watermark_x_space: ${watermarkXSpace!10}, - watermark_y_space: ${watermarkYSpace!10}, + watermark_x_space: ${watermarkXSpace!'10'}, + watermark_y_space: ${watermarkYSpace!'10'}, watermark_font: '${watermarkFont!'微软雅黑'}', watermark_fontsize: '${watermarkFontsize!'18px'}', watermark_color: '${watermarkColor!'black'}', - watermark_alpha: ${watermarkAlpha!0.2}, - watermark_width: ${watermarkWidth!240}, - watermark_height: ${watermarkHeight!80}, - watermark_angle: ${watermarkAngle!10}, + watermark_alpha: ${watermarkAlpha!'0.2'}, + watermark_width: ${watermarkWidth!'240'}, + watermark_height: ${watermarkHeight!'80'}, + watermark_angle: ${watermarkAngle!'10'}, }); } } diff --git a/server/src/test/java/cn/keking/web/OfficeWebWatermarkDefaultsTests.java b/server/src/test/java/cn/keking/web/OfficeWebWatermarkDefaultsTests.java index b71b571b..70c4cb13 100644 --- a/server/src/test/java/cn/keking/web/OfficeWebWatermarkDefaultsTests.java +++ b/server/src/test/java/cn/keking/web/OfficeWebWatermarkDefaultsTests.java @@ -3,10 +3,12 @@ package cn.keking.web; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateExceptionHandler; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import java.io.StringWriter; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -24,21 +26,36 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * * The first test therefore renders with a model that carries no watermark* entry at all. * Do not add them "to make it realistic" - that is the condition under test. + * + * The template's defaults are string literals on purpose: a numeric default goes through + * FreeMarker's locale-aware number format, so under de_DE 0.2 renders as "0,2" and under + * ar_EG the digits become Arabic-Indic - either way the inline script no longer parses. + * The locale comes from the request's Accept-Language, which is why both tests run per + * locale and every numeric value is asserted, not just one. */ class OfficeWebWatermarkDefaultsTests { - @Test - void shouldRenderXlsxPreviewPageWhenWatermarkAttributesAreMissing() throws Exception { - String html = render(baseModel()); + @ParameterizedTest + @ValueSource(strings = {"zh-CN", "en-US", "de-DE", "fr-FR", "ar-EG"}) + void shouldRenderXlsxPreviewPageWhenWatermarkAttributesAreMissing(String languageTag) throws Exception { + String html = render(baseModel(), Locale.forLanguageTag(languageTag)); assertTrue(html.contains(""), "page was truncated before "); assertTrue(html.contains("let watermarkTxt = '';"), "watermarkTxt did not fall back to an empty string"); - assertTrue(html.contains("watermark_width: 240,"), "watermarkWidth did not fall back to its declared default"); - assertTrue(html.contains("watermark_font: '\u5fae\u8f6f\u96c5\u9ed1',"), "watermarkFont did not fall back to its declared default"); + assertRendered(html, "watermark_x_space: 10,"); + assertRendered(html, "watermark_y_space: 10,"); + assertRendered(html, "watermark_font: '微软雅黑',"); + assertRendered(html, "watermark_fontsize: '18px',"); + assertRendered(html, "watermark_color: 'black',"); + assertRendered(html, "watermark_alpha: 0.2,"); + assertRendered(html, "watermark_width: 240,"); + assertRendered(html, "watermark_height: 80,"); + assertRendered(html, "watermark_angle: 10,"); } - @Test - void shouldKeepConfiguredWatermarkSettingsWhenAttributesArePresent() throws Exception { + @ParameterizedTest + @ValueSource(strings = {"zh-CN", "de-DE", "ar-EG"}) + void shouldKeepConfiguredWatermarkSettingsWhenAttributesArePresent(String languageTag) throws Exception { Map model = baseModel(); model.put("watermarkTxt", "kkFileView"); model.put("watermarkXSpace", "20"); @@ -51,18 +68,26 @@ class OfficeWebWatermarkDefaultsTests { model.put("watermarkHeight", "120"); model.put("watermarkAngle", "45"); - String html = render(model); + String html = render(model, Locale.forLanguageTag(languageTag)); assertTrue(html.contains("let watermarkTxt = 'kkFileView';")); - assertTrue(html.contains("watermark_x_space: 20,")); - assertTrue(html.contains("watermark_y_space: 30,")); - assertTrue(html.contains("watermark_font: 'Arial',")); - assertTrue(html.contains("watermark_fontsize: '24px',")); - assertTrue(html.contains("watermark_color: 'red',")); - assertTrue(html.contains("watermark_alpha: 0.5,")); - assertTrue(html.contains("watermark_width: 300,")); - assertTrue(html.contains("watermark_height: 120,")); - assertTrue(html.contains("watermark_angle: 45,")); + assertRendered(html, "watermark_x_space: 20,"); + assertRendered(html, "watermark_y_space: 30,"); + assertRendered(html, "watermark_font: 'Arial',"); + assertRendered(html, "watermark_fontsize: '24px',"); + assertRendered(html, "watermark_color: 'red',"); + assertRendered(html, "watermark_alpha: 0.5,"); + assertRendered(html, "watermark_width: 300,"); + assertRendered(html, "watermark_height: 120,"); + assertRendered(html, "watermark_angle: 45,"); + } + + /** On failure, show the line that was actually emitted for that key. */ + private static void assertRendered(String html, String expected) { + String key = expected.substring(0, expected.indexOf(':') + 1); + int start = html.indexOf(key); + String actual = start < 0 ? "" : html.substring(start, html.indexOf('\n', start)).trim(); + assertTrue(html.contains(expected), "expected \"" + expected + "\" but rendered \"" + actual + "\""); } /** Everything officeweb.ftl needs except the watermark attributes. */ @@ -78,13 +103,14 @@ class OfficeWebWatermarkDefaultsTests { return model; } - private String render(Map model) throws Exception { + /** Same lookup as Spring's FreeMarkerView: the template is resolved for the request locale. */ + private String render(Map model, Locale locale) throws Exception { Configuration configuration = new Configuration(Configuration.VERSION_2_3_32); configuration.setClassLoaderForTemplateLoading(getClass().getClassLoader(), "web"); configuration.setDefaultEncoding("UTF-8"); configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); - Template template = configuration.getTemplate("officeweb.ftl"); + Template template = configuration.getTemplate("officeweb.ftl", locale); StringWriter out = new StringWriter(); template.process(model, out); return out.toString();