wolkenkit: How to localization - localization

The data I store is at the moment written in english. So I plan to make this content localized/translatable and would like to give this option to users.
Here are my user stories:
(1) As a user I want to select the preferred language of my content (e.g. german). If the text is not available in german, please give me the content in the fallback language (e.g. english).
(2) As a user I want to be able to translate a given model.
Given the following:
1) A model, e.g. Message with two properties: title and description. It can be expected these two properties are in english (by default).
2) A command, e.g. translateMessage which will receive a payload with: title, description and locale.
What's an accepted way to handle localization of those models?

A solution I come up with:
Let's say our Message will have the following properties (in Typescript):
{
title: string;
description: string;
}
I would extend it with a translations object. Where each key in there is a locale and has an object with translated strings.
{
title: string;
description: string;
translations: {
[key: string]: {
title: string;
description: string;
}
}
}
The readModel will be the same as above and it is up to the client to decide which strings to display.
The command translateMessage will receive the payload as described above and publish an event with that. The readModel will react to that event in a way, that it pushes the new payload data onto the translations object in that model.
For model creation, if the data is received in a different locale than the default one, then the event handler will put those translated strings prefix with the locale they were written in, into the root, e.g. model.title can be something like [de] Nachrichtentitel. The model would look like this:
{
title: '[de] Nachrichtentitel'
description: '[de] Nachrichteninhalt'
translations: {
de: {
title: 'Nachrichtentitel'
description: 'Nachrichteninhalt'
}
}
}
You see any problems with that? Are there other already established best-practices on how to do that?

Related

How to add an item from another class? Swift

I’m doing a news management exercise. I have some classes:
Author
News (father)
NewsVideo (son) (this class has the same properties as the father, plus it has two properties)
NewsManagement
From the NewsManagement class, I have to create a function that inserts a news.
I have already created an empty array of type News.
NewsManagement class has only one property, an empty News array.
var newsCollection: [News] = []
class NewsManagement {
var news: [News] = []
init(news: [News]) {
self.news = news
}
func insertNews(title: String, text: String, date: Int, author: Autore, urlVideo: String?, videoLength: Double?) -> String? {
//these are the properties of the newsVideo class
guard let urlVideo = urlVideo, let videoLength = videoLength else {
return nil
}
self.news.append(News.init(title: String, text: String, date: Int, author: Author))
return "news addition”
}
}
var manager = NewsManagement.init(news: newsCollection)
manager.insertNews(title: "prima prova", text: "spero funzioni", date: 13, author: authors[3], urlVideo: "www.prova.it", videoLength: 4.5)
//authors is an array of instance of class Author
Unfortunately, it’s not working.
Do you know where the error is?
Or do you know another way?
I’ve been trying solutions for too long, but none of them work
Thank you!
Syntactic issues
There are a couple of syntax issues that prevent the code from compiling.
THere's a small typo with Autore instead of Author.
Then the bigger syntactical issue: replace the line which does not provide any value for the arguments:
self.news.append(News.init(title: String, text: String, date: Int, author: Author))
with a line that privides the named arguments:
self.news.append(News.init(title: title, text: text, date: date, author: author))
There is by the way no need to call explicitly init. And there's no need to use self when there is no ambiguity between a property and an argument. So you could further simplify:
news.append(News(title: title, text: text, date: date, author: author))
Not related: Design issues
The fact of providing all the parameters to create a News to the news manager is a design issue:
to add news, one must provide all the required parameters for all kind of news to the news manager.
the news manager has then not only the responsibility to manage the news collection, it suddenly has the additional responsibility to create each single News. As a consequence if a new kind of News is added (e.g. AudioNews) or if one of the news constructor would change the news manager would have to change too. More than one reason to change is a problem in view of the Single Responsibility Principle.
the news manager must also know the details of each constructor of each possible kind of news. ANd it has to know the rule which parameters create a which kind of news. So it needs to know much more about a lot of classes than really necessary. This could be seen as a problem in view of the Principle of Least Knowledge
Worse, the insertNews() has an interface that is cluttered with a lot of parameters that are not always needed. This is a problem in view of the interface segregation principle.
My advice: have News created separately using the right kind of news (e.g. VideoNews) with the appropriate constructor, and simplify NewsManager to insert, access and remove already existing news.

Tackle Localization with Graphql

In a json file, I have some fields that have a list of dictionaries with the locale and the translated text:
description_localized: [
{
locale: "en-UK",
value: "Read along"
},
{
locale: "de-DE",
value: "Lesen und"
},
{
locale: "fr-FR",
value: "Lis avec"
},
]
There are other fields where there are two keys in the value key:
path_localized: [
{
locale: "de-DE",
value: "{"identifier"=>"", "value"=>"http://path_6987.path"}"
},
{
locale: "es-ES",
value: "{"identifier"=>"", "value"=>"http://path_4685.path"}"
},
I already created a schema that grabs these fields, but instead of pulling the entire dictionary, on Graphql, I will need to be able to make a query where I only specify the language-locale I want (e.g. fr-FR) and that would only fetch the translated value for that one language (fr-FR). I don't want to get an array of all localized languages as this will be very taxing and will take longer to load per query.
Does anyone have any ideas on how I could accomplish this? Maybe through a resolver where I pass in the language as a parameter? But where would the languages be defined? I may need to clean this but we have an assortment of locale definitions: en_UK, en-UK, UK, en_UK_CO... Also, if the queried language is not found, how could I define a fallback?
Any guidance would be appreciated.
Thanks!
What stack are you working on, Node.js? If so, you can find a localization example here: https://github.com/kriasoft/nodejs-api-starter ..it uses "i18next" module to detect user's language, fallback to default language etc. then you can pass "lng" string as a context variable and use that inside of your "resolve()" methods. See src/app.js, src/Context.js.

Check if entered text is valid in Xtext

lets say we have some grammar like this.
Model:
greeting+=Greeting*;
Greeting:
'Hello' name=ID '!';
I would like to check whether the text written text in name is a valid text.
All the valid words are saved in an array.
Also the array should be filled with words from a given file.
So is it possible to check this at runtime and maybe also use this words as suggestions.
Thanks
For this purpose you can use a validator.
A simple video tutorial about it can be found here
In your case the function in the validator could look like this:
public static val INVALID_NAME = "greeting_InvalidName"
#Check
def nameIsValid(Greeting grt) {
val name = grt.getName() //or just grt.Name
val validNames = NewArrayList
//add all valid names to this list
if (!validNames.contains(name)) {
val errorMsg = "Name is not valid"
error(errorMsg, GreetingsPackage.eINSTANCE.Greeting_name, INVALID_NAME)
}
}
You might have to replace the "GreetingsPackage" if your DSL isn't named Greetings.
The static String passed to the error-method serves for identification of the error. This gets important when you want to implement Quickfixes which is the second thing you have asked for as they provide the possibility to give the programmer a few ideas how to actually fix this particular problem.
Because I don't have any experience with implementing quickfixes myself I can just give you this as a reference.

Override Grails Error Messages to format Dates and Numbers

I have created a domain with a Double field. When the validation occurs it throws the error message with size value showing the number with commas. Following are the detials
Groovy Class
class Quote {
String content;
Double size;
static constraints = {
content(maxSize:1000, blank:false)
size(min: 0.00D, max:999.99D)
}
}
Value entered "11111", error obtained "Size 11,111 is exceeded the limit". I have added the property key/value pair in messages.properties.
Here, I would like to get the message back without the commas. My main aim is to take the key and format the message returned based on my requirements. I require this as I have other fields that need conversion. For example, a date is validated but when showing the error the Gregorian date needs to be converted to an Islamic date and shown to user.
Does anyone know if I can do something to make this work.
I have tried the solution provided in http://ishanf.tumblr.com/post/434379583/custom-property-editor-for-grails but this did not work.
I have also tried modifying the messages values, but this is not flexible in case of my date issue. Example, for a key value pair, instead of using {2} as a place holder I could use {2, date, mm/dd/yyyy}, but for Islamic dates I want to format and show things differently.
Also, please note I have created a separate key for default date formatting for my application.
Would appreciate the help.
In grails, the return of a constrain is an already translated string.
You can create a taglib to format that, or enhance the
Another option would be custom validators. A custom validator can return false or a key when failing.
For example in your domain class, to vaildate a field:
myDateField validator: {val, obj -> obj.myShinyDateValidatorMethod(val) }
private myShinyDateValidatorMethod() {
if (isNotValidDate(val) {
return [the_message_key, val.formatedAsYouWand]
}
}
and, in your properties file you have to have defined the key:
the_message_key=This date: {3} is not valid
The trick here is that in the return from the validator, first string is the key and the rest are parameters for that key, but grails already uses {0}, {1}, {2} placeholders for className, fieldName and value, and the first parameter that you pass will be used as {3} placeholder.
Hope this helps

Best way of storing an "array of records" at design-time

I have a set of data that I need to store at design-time to construct the contents of a group of components at run-time.
Something like this:
type
TVulnerabilityData = record
Vulnerability: TVulnerability;
Name: string;
Description: string;
ErrorMessage: string;
end;
What's the best way of storing this data at design-time for later retrieval at run-time? I'll have about 20 records for which I know all the contents of each "record" but I'm stuck on what's the best way of storing the data.
The only semi-elegant idea I've come up with is "construct" each record on the unit's initialization like this:
var
VulnerabilityData: array[Low(TVulnerability)..High(TVulnerability)] of TVulnerabilityData;
....
initialization
VulnerabilityData[0].Vulnerability := vVulnerability1;
VulnerabilityData[0].Name := 'Name of Vulnerability1';
VulnerabilityData[0].Description := 'Description of Vulnerability1';
VulnerabilityData[0].ErrorMessage := 'Error Message of Vulnerability1';
VulnerabilityData[1]......
.....
VulnerabilityData[20]......
Is there a better and/or more elegant solution than this?
Thanks for reading and for any insights you might provide.
You can also declare your array as consts and initialize it...
const
VulnerabilityData: array[Low(TVulnerability)..High(TVulnerability)] of TVulnerabilityData =
(
(Vulnerability : vVulnerability1; Name : Name1; Description : Description1; ErrorMessage : ErrorMessage1),
(Vulnerability : vVulnerability2; Name : Name2; Description : Description2; ErrorMessage : ErrorMessage2),
[...]
(Vulnerability : vVulnerabilityX; Name : NameX; Description : DescriptionX; ErrorMessage : ErrorMessageX)
)
);
I don't have an IDE on this computer to double check the syntax... might be a comma or two missing. But this is how you should do it I think.
not an answer but may be a clue: design-time controls can have images and other binary data associated with it, why not write your data to a resource file and read from there? iterating of course, to make it simpler, extensible and more elegant
The typical way would be a file, either properties style (a=b\n on each line) cdf, xml, yaml (preferred if you have a parser for it) or a database.
If you must specify it in code as in your example, you should start by putting it in something you can parse into a simple format then iterate over it. For instance, in Java I'd instantiate an array:
String[] vals=new String[]{
"Name of Vulnerability1", "Description of Vulnerability1", "Error Message of Vulnerability1",
"Name of Vulnerability2", ...
}
This puts all your data into one place and the loop that reads it can easily be changed to read it from a file.
I use this pattern all the time to create menus and for other string-intensive initialization.
Don't forget that you can throw some logic in there too! For instance, with menus I will sometimes create them using data like this:
"^File", "Open", "Close", "^Edit", "Copy", "Paste"
As I'm reading this in I scan for the ^ which tells the code to make this entry a top level item. I also use "+Item" to create a sub-group and "-Item" to go back up to the previous group.
Since you are completely specifying the format you can add power later. For instance, if you coded menus using the above system, you might decide at first that you could use the first letter of each item as an accelerator key. Later you find out that File/Close conflicts with another "C" item, you can just change the protocol to allow "Close*e" to specify that E should be the accelerator. You could even include ctrl-x with a different character. (If you do shorthand data entry tricks like this, document it with comments!)
Don't be afraid to write little tools like this, in the long run they will help you immensely, and I can turn out a parser like this and copy/paste the values into my code faster than you can mold a text file to fit your example.

Resources