How to organize Java properties entries for internationalization? - java

In our app we have a messages.properties file which contains all of the strings that will be shown to the UI. We have a small app with a few screens and it's already getting unwieldy with duplicate string values throughout.
Right now we have it organized with page specific strings separated out with whitespace and comments, with a section for each jsp with the property name having a prefix of the page name. We also have sections for entities, for instance, anywhere we show the user's email address, we would reference the property user.email for the label for that input or output field. We have another section for error and status messages, and finally one last section with global messages like "Submit" and "Cancel"
There's got to be a better way, and I'm wondering if you know what it is.

I don't think there is a universal "better way". I tried Googling for "best practice" advice on this, and found nothing that talked about how best to structure the property namespace for i18n.
(This I found somewhat surprising. There's usually someone out there who is prepared to put forward their ill-considered opinions on something like this as "best practice". Or perhaps, I'm too cynical.)
FWIW, my general advice would be:
be systematic and consistent about the property names and the property file structure,.
don't be afraid to use resource bundle inheritance if there is a lot of duplication,
if the property files or resource bundles get too large, partition them.
But I expect you already know and do all of that.
Finally, don't get too hung up about getting this "just right". There is no perfect solution, and what you are currently doing is probably good enough ... according to the criteria of whoever is paying you to do this work.

Related

Save values to file(e.g yml) in java

First of all this might be a dumb question and I searched for some days but didn't find an answer. So if there is an existing answer concerning my question, I would be grateful for a link.
I don't know if anyone of you ever coded Spigot, Paper or Bukkit, but there was a class called YamlConfiguration which had the following methods:
public FileConfiguration cfg = YamlConfiguration.loadConfiguration(file);
cfg.set(path.path2, "hello");
cfg.getInt/String/...(path.path2); (which obviously returns "hello")
cfg.save(file);
The produced file then looks like this:
path:
path2: "hello"
So you could basically save any value in those files and reuse them even if your program has been restarted.
I know have moved forward from Spigot/Paper to native Java and I'm missing something like that Yaml-thing. The only thing I found was a kind of a config file, where every time the whole file is overwritten, when I try to add values.
Can you show me a proper way of saving values to a file? (would be nice without libraries)
I'm missing sth like that Yaml-thing
SnakeYAML should have you covered. Without knowing anything about your use-case, it makes no sense to discuss its usage here since its documentation already does cover the general topics.
The only thing I found was a kind of a config file, where everytime the whole file is overwritten, when I try to add values.
Saving as YAML will always overwrite the complete file as well. Serialization does not really work with append-only. (Serialization is the term to search for when you want functionality like this, by the way.)
If you mean that previous values were deleted, that probably was because you didn't load the file's content before or some other coding error, but since you don't show your code, we can only speculate.
Can you show me a proper way of saving values to a file?
People will have quite different opinions on what would be a proper way and therefore it is not a good question to ask here. It also heavily depends on your use-case.
would be nice without libraries
So you're basically saying „previously I used a library which had a nice feature but I want to have that feature without using a library“. This stance won't get you far in today's increasingly modular software world.
For example, JAXB which offers (de)serialization from/to XML was previously part of Java SE, but has been removed as of Java SE 11 and is a separate library now.

Is there any other alternative to template specific exclusion of pages from search

I have restricted some pages like admin pages from not getting visible in search results.Using the below code
map.put("group.1_group.1_property","**jcr:content/cq:template**");
map.put("group.1_group.1_property.1_value","**/apps/MyApp/templates/SampleTemplate**");
map.put("group.1_group.1_property.and","true");
map.put("group.1_group.1_property.operation","unequals");
final Query finalQuery = builder.createQuery(PredicateGroup.create(map),
session);
which means it is template specific search filtration,means that Im telling the query builder not to display those pages having the above specified template .However the drawback is that, in future if we want to restrict more pages, those pages also must be mapped to the above template. So instead of specifying the template in the map, can we put any other property in the map, so that search restriction is not template specific.
Thanks,
Balaji
What other properties do your pages have available (specifically, the admin pages)? For example, if you have a specific property that you add to your admin pages, or other pages that you could sort on, that could work. On one site I worked on, we had a property we put into certain content items called hideInNav. So along those lines, this is how I would do it:
map.put("group.1_group.1_property","jcr:content/hideInNav");
map.put("group.1_group.1_property.1_value","/content/somepath/you/want");
map.put("group.1_group.1_property.and","true");
map.put("group.1_group.1_property.operation","unequals");
I hope that helps to make sense of it. Am I understanding it correctly? If not, please clarify and I'll try to help more.
---------------EDIT-----------------------
If you don't have a custom property, but you know the path these pages are located, and maybe a default property they all have in common (like a jcr:title), you could try doing that instead. Like this:
map.put(1_group.0_path","/content/yoursite");
map.put(2_group.0_type","cq:Page");
map.put(3_group.fulltext","test text");
map.put(3_group.fulltext.relPath","jcr:content/#jcr:title");
You can see how this would run on a local query debugger when you have CQ running:
http://localhost:4502/libs/cq/search/content/querydebug.html?_charset_=UTF-8&query=http%3A%2F%2Flocalhost%3A4502%2Fcontent%2Fsalesportal%2Fen%2Fmobile%2Fresources.assets.get.json%3Fp.limit%3D7%0D%0A1_group.0_path%3D%2Fcontent%2Fyoursite%0D%0A2_group.0_type%3Dcq%3APage%0D%0A3_group.fulltext%3Dtest+text%0D%0A3_group.fulltext.relPath%3Djcr%3Acontent%2F%40jcr%3Atitle
Hopefully that's more helpful.
EDIT #2
This is a summary of both my answers, and will hopefully answer your last comment as well.
In order to more fully answer your question (since you're still not quite getting what you want), I dug a little deeper to find the information you need. Just as a reference, any time you're doing XPath querying, this is a great tool to look at: JCR Query Usecases - jboss
Anyway, you said that you were getting results that didn't include items that were missing the 'hideInNav' property. Here is how you can get those results, specifically:
map.put("1_group.0_path","/content/yoursite");
map.put("2_group.0_type","cq:Page");
map.put("3_group.1_property","jcr:content/hideInNav");
map.put("3_group.1_property.1_value","not");
map.put("3_group.1_property.operation","not");
This way, you're searching in the path you want, getting the type of result you want (cq:Page, if that is what you're actually looking for), and you're getting the results that DO NOT HAVE the property 'hideInNav'.

Property file dot separated key names

I just noticed that almost all the key values in property files are in dot separated names.
eg -some.key=some value
Does anyone know why? Just asked out of curiosity.
It's basically a convention that makes it easier to see what properties are related.
For example:
person.title="Title"
person.surname="Surname"
job.description="Some description"
It's easy to see which properties are related and, using a smart editor, you can then chose to only see the properties for person. A few IDE's and editors can even use this to add code completion for you, as you know you want to work with person, but might not remember the exact property.
We sometimes underestimate the power of readability, yet a convention like this makes it easy for anyone to add, edit or maintain these properties. This becomes very important when working in teams or when on-boarding juniors.
There is no any specific reason for that but it's just for better understanding of programmers nothing else. you can also directly write key=value without using any kind of "some" :-)

How to group resources in a resource bundle?

What is the best approach for grouping resources in a resource bundle file? The one I see most common is to group resources by web page, an example would be:
# -- company page
company.name.lbl=Name:
company.address.lbl=Address:
# -- contact page
contact.name.lbl=Name:
contact.email.lbl=Email:
The problem with this is that a lot of fields with the same name are duplicated. Would you then recommend identifying all the common names and group them separately? Something like:
name.lbl=Name:
address.lbl=Address:
email.lbl=Email:
Of course this also has some drawbacks, if you want to change the company name label to 'Company Name' then it is possible you change the contact name label without meaning to. Of course you should create a new resource for this, but it is possible the person making the change might overlook creating a new resource.
I would keep to the former example of grouping by web page, since the text displayed on each page has its own separate context.
You could try to keep things DRY and identify all of the common text, but should the context of any page change, you may find yourself creating new resources that you would have already done if you kept the page resources separate.
Another reason for keeping the resources separated by page is that if you ever need to translate your resources, the context for creating translations will be self-evident. That helps you keep a clean separation of concerns, so your coders will not have to worry about how words might be translated, and your translators will not have to mess with any code.
The first option may mean repeating texts, but is more flexible. What happens if, for example, company name is completely different from personal name? Or if tomorrow you boss decides that the label for the name of the company should change from "Name" to "Company name".
If you use the second option you are losing most of the advantages of using resource bundles.

Some kind of Data persistency

Basically what I need to know is this:
I have to show a drop down list of countries to my users each country also has a code associated to it. I will have to work with both the country and the code What would be the best approach:
-We (the dev.) are thinking about a table in our app database with this data, or XML file.
-Our "architect" says that is old school and that we should use constants in our app with a map that associates the country with the code
Please Help me feel smart
I agree with you that you should not hard code this or use constants. There are a few good options depending on yours needs:
Java Properties Files - If you just have a few key-value pairs to store, these are the simplest way and easy to use.
XML Storage - If you are looking for persistence and are looking at XML for storage, I would recommend looking at JAXB. It is part of Java 6 and will make your life easier than trying to use the DOM.
Database Persistence - If you have more data that is changing often, you could also look at storing it in a database. JPA is a great standard library for doing this. That is probably overkill for what you are looking for though.
Bottom line is hard coding is a thing of the past. There are lots of great ways to get data in quickly and easily without resorting to hard coding everything.
Countries rarely change, so adding them statically as code or a config file seems reasonable. If you don't use a database for anything else, don't add one just for this feature.
If you already have XML parsing in your app, use an XML file to define the data. It already solves all kinds of issues (for example if you need to add a second attribute per country or something).
If you don't use XML for anything else, I suggest to give it a try. It doesn't add much to your app. Otherwise, use a plain text file, maybe a CSV one.
The different methods have different advantages and drawbacks:
Database:
allows you to use the country data in queries
data can be changed without redeploying the app
editing the data requires you to write some sort of frontend or do it manually via some generic SQL browser
requires database access code, and some sort of caching strategy
Any country-based logic in the code can break when the DB changes, or has to be reflected in the DB
XML:
Very easy to edit
can be changed without recompiling the app, but changes have to be deployed somehow
Requires parsing code and some sort of caching strategy
Any country-based logic in the code can break when the XML changes, or has to be reflected in the XML
Code:
Easy to edit - for developers
Changes require compilation and deployment
Requires no extra technical layers
Code and country data can't get out of synch
All in all, the "code as data" solution is indeed the nicest, if the compile&deploy step for each change is acceptable to you. The other solutions create overhead and duplication of structure (or even logic) - and no, they don't magically make it "safe" to do last-minute changes "because it's not code". Code is data, and data is code.
In short your architect is wrong (Or at least he is if your paraphrase of his position is accurate). It shouldn't be in the code.
This data is not static; a country's name changes, a new one is founded, or some cease to exist.
As far as what mechanism, it doesn't necessarily matter. Just make sure you can retrieve the data easily, that you have unit tests, and that there is straightforward mechanism to update the data.
I think that "table solution" has more flexible approach:
1. You can manage data and connecting properties
2. You can work with table directly
3. You can create associated map, based on db table))
I would certainly not use them as constants in the code.
Names can change, while countries can be created, merge, disappear, etc.
If you are already using a database, adding this may make sense. For one, it ensures that the codes that may be stored with client data are valid in terms of your country code list. So if a country disappears but a client record still refers to it, the data stays valid.
Make sure that your UI loads and caches the list; no point making a query every time if you can avoid it.
By the way, correctly handling countries in an internationalized application is much more complicated than just dealing with renames. For example, if a country or part of a country declares independence, some countries will recognize it, while others do not.

Categories