diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/language/Translatable.java b/guacamole-ext/src/main/java/org/apache/guacamole/language/Translatable.java new file mode 100644 index 000000000..0b4381463 --- /dev/null +++ b/guacamole-ext/src/main/java/org/apache/guacamole/language/Translatable.java @@ -0,0 +1,41 @@ +/* + * 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.guacamole.language; + +/** + * An interface which requires the definition of a translatable message that + * can be passed through an arbitrary translation service, producing a + * human-readable message in the user's native language. + * + * @author Michael Jumper + */ +public interface Translatable { + + /** + * Returns a message which can be translated using a translation service, + * consisting of a translation key and optional set of substitution + * variables. + * + * @return + * A message which can be translated using a translation service. + */ + TranslatableMessage getTranslatableMessage(); + +} diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/language/TranslatableMessage.java b/guacamole-ext/src/main/java/org/apache/guacamole/language/TranslatableMessage.java new file mode 100644 index 000000000..4aeba9ab1 --- /dev/null +++ b/guacamole-ext/src/main/java/org/apache/guacamole/language/TranslatableMessage.java @@ -0,0 +1,96 @@ +/* + * 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.guacamole.language; + +/** + * A message which can be translated using a translation service, providing a + * translation key and optional set of values to be substituted into the + * translation string associated with that key. + * + * @author Michael Jumper + */ +public class TranslatableMessage { + + /** + * The arbitrary key which can be used to look up the message to be + * displayed in the user's native language. + */ + private final String key; + + /** + * An arbitrary object whose properties should be substituted for the + * corresponding placeholders within the string associated with the key. + */ + private final Object variables; + + /** + * Creates a new TranslatableMessage associated with the given translation + * key, without any associated variables. + * + * @param key + * The translation key to associate with the TranslatableMessage. + */ + public TranslatableMessage(String key) { + this(key, null); + } + + /** + * Creates a new TranslatableMessage associated with the given translation + * key and associated variables. + * + * @param key + * The translation key to associate with the TranslatableMessage. + * + * @param variables + * An arbitrary object whose properties should be substituted for the + * corresponding placeholders within the string associated with the + * given translation key. + */ + public TranslatableMessage(String key, Object variables) { + this.key = key; + this.variables = variables; + } + + /** + * Returns the arbitrary key which can be used to look up the message to be + * displayed in the user's native language. + * + * @return + * The arbitrary key associated with the human-readable message. + */ + public String getKey() { + return key; + } + + /** + * Returns an arbitrary object whose properties should be substituted for + * the corresponding placeholders within the string associated with the key. + * If not applicable, null is returned. + * + * @return + * An arbitrary object whose properties should be substituted for the + * corresponding placeholders within the string associated with the key, + * or null if not applicable. + */ + public Object getVariables() { + return variables; + } + +} diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/APIError.java b/guacamole/src/main/java/org/apache/guacamole/rest/APIError.java index 7727b85b0..2bec055ba 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/APIError.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/APIError.java @@ -25,6 +25,8 @@ import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleResourceNotFoundException; import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.form.Field; +import org.apache.guacamole.language.Translatable; +import org.apache.guacamole.language.TranslatableMessage; import org.apache.guacamole.net.auth.credentials.GuacamoleCredentialsException; import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException; import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException; @@ -39,10 +41,15 @@ import org.apache.guacamole.tunnel.GuacamoleStreamException; public class APIError { /** - * The error message. + * The human-readable error message. */ private final String message; + /** + * A translatable message representing the error that occurred. + */ + private final TranslatableMessage translatableMessage; + /** * The associated Guacamole protocol status code. */ @@ -148,7 +155,9 @@ public class APIError { /** * Creates a new APIError which exposes the details of the given - * GuacamoleException. + * GuacamoleException. If the given GuacamoleException implements + * Translatable, then its translation string and values will be exposed as + * well. * * @param exception * The GuacamoleException from which the details of the new APIError @@ -176,6 +185,14 @@ public class APIError { else this.statusCode = null; + // Pull translatable message and values if available + if (exception instanceof Translatable) { + Translatable translatable = (Translatable) exception; + this.translatableMessage = translatable.getTranslatableMessage(); + } + else + this.translatableMessage = new TranslatableMessage(this.message); + } /** @@ -223,4 +240,16 @@ public class APIError { return message; } + /** + * Returns a translatable message describing the error that occurred. If no + * translatable message is associated with the error, this will be null. + * + * @return + * A translatable message describing the error that occurred, or null + * if there is no such message defined. + */ + public TranslatableMessage getTranslatableMessage() { + return translatableMessage; + } + } diff --git a/guacamole/src/main/webapp/app/rest/types/Error.js b/guacamole/src/main/webapp/app/rest/types/Error.js index 43fdc9602..47f9cf770 100644 --- a/guacamole/src/main/webapp/app/rest/types/Error.js +++ b/guacamole/src/main/webapp/app/rest/types/Error.js @@ -42,6 +42,15 @@ angular.module('rest').factory('Error', [function defineError() { */ this.message = template.message; + /** + * A message which can be translated using the translation service, + * consisting of a translation key and optional set of substitution + * variables. + * + * @type TranslatableMessage + */ + this.translatableMessage = template.translatableMessage; + /** * The Guacamole protocol status code associated with the error that * occurred. This is only valid for errors of type STREAM_ERROR. diff --git a/guacamole/src/main/webapp/app/rest/types/TranslatableMessage.js b/guacamole/src/main/webapp/app/rest/types/TranslatableMessage.js new file mode 100644 index 000000000..454224840 --- /dev/null +++ b/guacamole/src/main/webapp/app/rest/types/TranslatableMessage.js @@ -0,0 +1,63 @@ +/* + * 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. + */ + +/** + * Service which defines the TranslatableMessage class. + */ +angular.module('rest').factory('TranslatableMessage', [function defineTranslatableMessage() { + + /** + * The object returned by REST API calls when representing a message which + * can be translated using the translation service, providing a translation + * key and optional set of values to be substituted into the translation + * string associated with that key. + * + * @constructor + * @param {TranslatableMessage|Object} [template={}] + * The object whose properties should be copied within the new + * TranslatableMessage. + */ + var TranslatableMessage = function TranslatableMessage(template) { + + // Use empty object by default + template = template || {}; + + /** + * The key associated with the translation string that used when + * displaying this message. + * + * @type String + */ + this.key = template.key; + + /** + * The object which should be passed through to the translation service + * for the sake of variable substitution. Each property of the provided + * object will be substituted for the variable of the same name within + * the translation string. + * + * @type Object + */ + this.variables = template.variables; + + }; + + return TranslatableMessage; + +}]); \ No newline at end of file