diff --git a/pom.xml b/pom.xml
index e784fe5..c0514c0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -234,7 +234,7 @@
org.apache.sling
org.apache.sling.commons.osgi
- 2.1.0
+ 2.4.0
provided
@@ -349,7 +349,7 @@
org.apache.sling
org.apache.sling.testing.sling-mock.junit4
- 2.5.0
+ 3.2.2
test
diff --git a/src/main/java/org/apache/sling/scripting/sightly/engine/extension/i18n/I18nBasenameProvider.java b/src/main/java/org/apache/sling/scripting/sightly/engine/extension/i18n/I18nBasenameProvider.java
new file mode 100644
index 0000000..8f652ad
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/engine/extension/i18n/I18nBasenameProvider.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.sling.scripting.sightly.engine.extension.i18n;
+
+import org.apache.sling.scripting.sightly.render.RenderContext;
+import org.jetbrains.annotations.Nullable;
+import org.osgi.annotation.versioning.ConsumerType;
+
+@ConsumerType
+public interface I18nBasenameProvider {
+
+ /**
+ * Provides a way to define a basename that is not passed as parameter on the i18n runtime extension
+ *
+ * @param renderContext the renderContext passed initially to the HTL Script Engine
+ * @return the basename if one is found, {@code null} otherwise
+ */
+ @Nullable String getBasename(RenderContext renderContext);
+
+}
diff --git a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/I18nRuntimeExtension.java b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/I18nRuntimeExtension.java
index 39a8236..4e65484 100644
--- a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/I18nRuntimeExtension.java
+++ b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/I18nRuntimeExtension.java
@@ -31,10 +31,13 @@
import org.apache.sling.api.scripting.SlingScriptHelper;
import org.apache.sling.i18n.ResourceBundleProvider;
import org.apache.sling.scripting.sightly.extension.RuntimeExtension;
+import org.apache.sling.scripting.sightly.engine.extension.i18n.I18nBasenameProvider;
import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
import org.apache.sling.scripting.sightly.render.RenderContext;
import org.apache.sling.scripting.sightly.render.RuntimeObjectModel;
import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -48,6 +51,9 @@ public class I18nRuntimeExtension implements RuntimeExtension {
private static final Logger LOG = LoggerFactory.getLogger(I18nRuntimeExtension.class);
+ @Reference(cardinality = ReferenceCardinality.OPTIONAL)
+ private I18nBasenameProvider i18nBasenameProvider;
+
@Override
public Object call(final RenderContext renderContext, Object... arguments) {
ExtensionUtils.checkArgumentCount(RuntimeExtension.I18N, arguments, 2);
@@ -56,11 +62,20 @@ public Object call(final RenderContext renderContext, Object... arguments) {
Map options = (Map) arguments[1];
String locale = runtimeObjectModel.toString(options.get("locale"));
String hint = runtimeObjectModel.toString(options.get("hint"));
- String basename = runtimeObjectModel.toString(options.get("basename"));
+ String basename = getBasename(renderContext, options);
final Bindings bindings = renderContext.getBindings();
return get(bindings, text, locale, basename, hint);
}
+ private String getBasename(RenderContext renderContext, Map options) {
+ RuntimeObjectModel runtimeObjectModel = renderContext.getObjectModel();
+ String basename = runtimeObjectModel.toString(options.get("basename"));
+ if (StringUtils.isEmpty(basename) && i18nBasenameProvider != null) {
+ return i18nBasenameProvider.getBasename(renderContext);
+ }
+ return basename;
+ }
+
private String get(final Bindings bindings, String text, String locale, String basename, String hint) {
final SlingScriptHelper slingScriptHelper = BindingsUtils.getHelper(bindings);
diff --git a/src/test/java/org/apache/sling/scripting/sightly/impl/engine/extension/I18nRuntimeExtensionTest.java b/src/test/java/org/apache/sling/scripting/sightly/impl/engine/extension/I18nRuntimeExtensionTest.java
new file mode 100644
index 0000000..d175a99
--- /dev/null
+++ b/src/test/java/org/apache/sling/scripting/sightly/impl/engine/extension/I18nRuntimeExtensionTest.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.sling.scripting.sightly.impl.engine.extension;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.sling.api.scripting.SlingBindings;
+import org.apache.sling.i18n.ResourceBundleProvider;
+import org.apache.sling.scripting.sightly.SightlyException;
+import org.apache.sling.scripting.sightly.engine.extension.i18n.I18nBasenameProvider;
+import org.apache.sling.scripting.sightly.render.AbstractRuntimeObjectModel;
+import org.apache.sling.scripting.sightly.render.RenderContext;
+import org.apache.sling.scripting.sightly.render.RuntimeObjectModel;
+import org.apache.sling.testing.mock.sling.MockResourceBundle;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.script.Bindings;
+import javax.script.SimpleBindings;
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+
+public class I18nRuntimeExtensionTest {
+
+ @Rule
+ public final SlingContext slingContext = new SlingContext();
+
+
+ public static final String BASENAME = "test-basename";
+ public static final String KEY = "test-key";
+ public static final String DEFAULT_VALUE = "test-value";
+ public static final String BASENAME_VALUE = "test-basename-value";
+
+ private RenderContext renderContext;
+ private I18nRuntimeExtension subject;
+
+ @Before
+ public void before() {
+ setupResourceBundles();
+ renderContext = setupRenderContext();
+ }
+
+ @NotNull
+ private RenderContext setupRenderContext() {
+ return new RenderContext() {
+ @Override
+ public RuntimeObjectModel getObjectModel() {
+ return new AbstractRuntimeObjectModel() {
+ };
+ }
+
+ @Override
+ public Bindings getBindings() {
+ Bindings bindings = new SimpleBindings();
+ bindings.put(SlingBindings.SLING, slingContext.slingScriptHelper());
+ bindings.put(SlingBindings.REQUEST, slingContext.request());
+ return bindings;
+ }
+
+ @Override
+ public Object call(String s, Object... objects) {
+ return null;
+ }
+ };
+ }
+
+ private void setupResourceBundles() {
+ ResourceBundleProvider resourceBundleProvider = slingContext.getService(ResourceBundleProvider.class);
+ MockResourceBundle defaultResourceBundle = (MockResourceBundle) resourceBundleProvider.getResourceBundle(slingContext.request().getLocale());
+ MockResourceBundle basenameResourceBundle = (MockResourceBundle) resourceBundleProvider.getResourceBundle(BASENAME, slingContext.request().getLocale());
+ defaultResourceBundle.put(KEY, DEFAULT_VALUE);
+ basenameResourceBundle.put(KEY, BASENAME_VALUE);
+ }
+
+
+ @Test
+ public void testNonExistingKey() {
+ subject = slingContext.registerInjectActivateService(new I18nRuntimeExtension());
+ String key = "non-existing";
+ assertEquals("Key should not change when it does not exist", key, subject.call(renderContext, key, Collections.emptyMap()));
+ }
+
+ @Test(expected = SightlyException.class)
+ public void testMissingArguments() {
+ subject = slingContext.registerInjectActivateService(new I18nRuntimeExtension());
+ subject.call(renderContext, "fails");
+ }
+
+ @Test
+ public void testDefaultValue() {
+ subject = slingContext.registerInjectActivateService(new I18nRuntimeExtension());
+ assertEquals(DEFAULT_VALUE, subject.call(renderContext, KEY, Collections.emptyMap()));
+ }
+
+ @Test
+ public void testBasenameValue() {
+ subject = slingContext.registerInjectActivateService(new I18nRuntimeExtension());
+ assertEquals(BASENAME_VALUE, subject.call(renderContext, KEY, ImmutableMap.of("basename", BASENAME)));
+ }
+
+ @Test
+ public void testBasenameThroughProviderValue() {
+ slingContext.registerService(I18nBasenameProvider.class, new MockI18nBasenameProvider(BASENAME));
+ subject = slingContext.registerInjectActivateService(new I18nRuntimeExtension());
+ assertEquals(BASENAME_VALUE, subject.call(renderContext, KEY, Collections.emptyMap()));
+ }
+
+ @Test
+ public void testEmptyBasenameThroughProviderValue() {
+ slingContext.registerService(I18nBasenameProvider.class, new MockI18nBasenameProvider(null));
+ subject = slingContext.registerInjectActivateService(new I18nRuntimeExtension());
+ assertEquals(DEFAULT_VALUE, subject.call(renderContext, KEY, Collections.emptyMap()));
+ }
+
+ static class MockI18nBasenameProvider implements I18nBasenameProvider {
+
+ private final String basename;
+
+ public MockI18nBasenameProvider(String basename) {
+ this.basename = basename;
+ }
+
+ @Override
+ public @Nullable String getBasename(RenderContext renderContext) {
+ return basename;
+ }
+ }
+
+
+}