Translating notifications raised by mailman-core in postorius

Hi,
Currently Postorius handles form submissions like this:
- Check to see if inputs are malformed, raise error if so
- Submit to mailman-core and see what the response is.
- ConnectionError: Mailman-core is unreachable, display error message
- Success: Display some success notification
- HttpError: This happens when mailman-core rejects the request for some reason.
Currently the HttpErrors are passed without modification to the user in a notification. Postorius should have some way of translating these. We can't translate the raw messages because they sometimes contain specific strings like emails and it would require us to manually add the strings to the .pot files.
Theoretically the core could translate the messages before passing them to postorius. This would require core to know about the language it should translate to. I don't think this is a very good approach because we would have to make sure we offer the same languages for core and postorius and I'm not sure how we would pass the languages to core...
I propose core to return an error code with each request. That way postorius can add strings for all the errors that it cares about and translate them accordingly. This would require an api change. Since 3.1 would change the api anyway, it would be nice to include the changes there.
What do you think of my proposal? Do you have a better idea? The specifics have to be worked out of course.
Simon

On May 17, 2016, at 11:15 AM, Simon Hanna wrote:
Probably Accept-Language could be used to specify that, but I (think I) agree it's not the right approach. My only hesitation is to remember that Postorius isn't technically the only web front-end that could be connected to the core. If some homegrown ui also wanted translations, it's not clear how much they could leverage of existing work if all the translations lived in Postorius.
If we're going to return an application-specific error code (in addition to the HTTP response code we already return), then I think it means we'll be returning a JSON structure even on error conditions. Right now, JSON is only returned on success, and strings are returned on errors.
If we say in API 3.1 that JSON is always returned, then we have some additional options. What makes the most sense to me would be to always return a dictionary with some well-defined keys. That at least gives us a chance to evolve the API probably without having to rev the API version in the future.
One problem with returning Mailman-specific error codes is that we'll need *a lot* of them. Essentially one for every error condition in the REST API. I've always found such arrangements a nightmare to maintain and debug. Error codes have no obvious meaning so the mapping of code to meaning always has to be looked up. We could segment the error space so that there's some semantic equivalence (e.g. 01xx means a list-specific error, 02xx means a membership-specific error, etc.) but there's always some twisting that goes on the keep those up-to-date and meaningful within the semantics we give them.
And it's still not enough, because as you point out, there is always going to be variable data that has to be associated with the error. A good example is when a mailing list is created within a nonexistent domain. The error reason is something like:
'Domain does not exist: example.net'
which gets interpolated on the server side. So obviously an error code like 0135 won't help because you could only translate that to 'Domain does not exist' without also knowing the name of the domain that failed.
So now we also have to include some variable data in the JSON response. Which leads me to think, why do we need error codes when we already have a format perfectly suited to the cause, and which we already use internally for other translatable contexts, i.e. PEP 292 strings ($-strings).
Thus, our error responses could be something like:
{ 'reason': 'Domain does not exist: example.net', 'template': 'Domain does not exist: $domain', 'data': { 'domain': 'example.net', }, }
'reason' would always be the interpolated English (i.e. source) string. 'template', and 'data' should be obvious. We need a separate namespace for the interpolation data.
A front-end could just use the English reason, or it could translate the template and interpolate the data dictionary into it.
Making this change would be a lot of work, but it could be done in several branches.
One branch would provide the infrastructure to return JSON error responses. These would only be done for API 3.1, and possibly you'd also want to check the Accept header to make sure the client is prepared to accept JSON. Then all of the error reporting call sites would have to be changed to pass in the template and data dictionaries, with the helpers doing the interpolation for 'reason' and the setting up of the response correctly. Then tests and documentation. :)
If you like the general approach we can hash out implementation details. Given however that Pycon is near and I *really* want to get 3.1 out during Pycon and there are already at least two big features that still have to be added (unsubscription workflow and template support), it might be better to defer this to core 3.2 and API 3.2. That way, we can get it right without rushing it in.
Cheers, -Barry

On May 17, 2016, at 11:15 AM, Simon Hanna wrote:
Probably Accept-Language could be used to specify that, but I (think I) agree it's not the right approach. My only hesitation is to remember that Postorius isn't technically the only web front-end that could be connected to the core. If some homegrown ui also wanted translations, it's not clear how much they could leverage of existing work if all the translations lived in Postorius.
If we're going to return an application-specific error code (in addition to the HTTP response code we already return), then I think it means we'll be returning a JSON structure even on error conditions. Right now, JSON is only returned on success, and strings are returned on errors.
If we say in API 3.1 that JSON is always returned, then we have some additional options. What makes the most sense to me would be to always return a dictionary with some well-defined keys. That at least gives us a chance to evolve the API probably without having to rev the API version in the future.
One problem with returning Mailman-specific error codes is that we'll need *a lot* of them. Essentially one for every error condition in the REST API. I've always found such arrangements a nightmare to maintain and debug. Error codes have no obvious meaning so the mapping of code to meaning always has to be looked up. We could segment the error space so that there's some semantic equivalence (e.g. 01xx means a list-specific error, 02xx means a membership-specific error, etc.) but there's always some twisting that goes on the keep those up-to-date and meaningful within the semantics we give them.
And it's still not enough, because as you point out, there is always going to be variable data that has to be associated with the error. A good example is when a mailing list is created within a nonexistent domain. The error reason is something like:
'Domain does not exist: example.net'
which gets interpolated on the server side. So obviously an error code like 0135 won't help because you could only translate that to 'Domain does not exist' without also knowing the name of the domain that failed.
So now we also have to include some variable data in the JSON response. Which leads me to think, why do we need error codes when we already have a format perfectly suited to the cause, and which we already use internally for other translatable contexts, i.e. PEP 292 strings ($-strings).
Thus, our error responses could be something like:
{ 'reason': 'Domain does not exist: example.net', 'template': 'Domain does not exist: $domain', 'data': { 'domain': 'example.net', }, }
'reason' would always be the interpolated English (i.e. source) string. 'template', and 'data' should be obvious. We need a separate namespace for the interpolation data.
A front-end could just use the English reason, or it could translate the template and interpolate the data dictionary into it.
Making this change would be a lot of work, but it could be done in several branches.
One branch would provide the infrastructure to return JSON error responses. These would only be done for API 3.1, and possibly you'd also want to check the Accept header to make sure the client is prepared to accept JSON. Then all of the error reporting call sites would have to be changed to pass in the template and data dictionaries, with the helpers doing the interpolation for 'reason' and the setting up of the response correctly. Then tests and documentation. :)
If you like the general approach we can hash out implementation details. Given however that Pycon is near and I *really* want to get 3.1 out during Pycon and there are already at least two big features that still have to be added (unsubscription workflow and template support), it might be better to defer this to core 3.2 and API 3.2. That way, we can get it right without rushing it in.
Cheers, -Barry
participants (2)
-
Barry Warsaw
-
Simon Hanna