De-localize preferences#8050
Conversation
…to unlocalized-preferences
| for (Map.Entry<String, Set<Field>> tab : entryEditorPreferences.getEntryEditorTabList().entrySet()) { | ||
| entryEditorTabs.add(new UserDefinedFieldsTab(tab.getKey(), tab.getValue(), databaseContext, libraryTab.getSuggestionProviders(), undoManager, dialogService, preferencesService, stateManager, Globals.entryTypesManager, ExternalFileTypes.getInstance(), Globals.TASK_EXECUTOR, Globals.journalAbbreviationRepository)); | ||
| String key = tab.getKey(); | ||
| if (key.equals(preferencesService.getDefaults().get(JabRefPreferences.CUSTOM_TAB_NAME + "_def" + i))) { |
There was a problem hiding this comment.
I'm not a big fan that the constants like CUSTOM_TAB_NAME are exposed. They are an implementation detail and shouldn't exposed outside. So for example, here you could add the default tab names to the entryEditorPreferences.
But actually I'm not sure why you need to check if its a default tab name in the first place. I think it's a nice touch that if the user chooses a name that we happen to have localized, why not always show the localized string. Simple example: the user decides to switch the abstract and the comment tab.
There was a problem hiding this comment.
Hi!
I'm not a big fan that the constants like CUSTOM_TAB_NAME are exposed.
I agree it would be better to have that directly in the Preferences Objects. This goes for the keys and the default values. So each Preference Object would have it's own keys and it's own defaults-Map for those Strings. @calixtus argues this makes the list of preferences harder to implement.
But actually I'm not sure why you need to check if its a default tab name in the first place.
Some background on this. We had some preferences that need localization. So for example the Entry-Editor-Tab name 'Abstract'. The default for the preference is 'Abstract'. JabRef should show 'Abstract' for english and 'Zusammenfassung' for german. Now we can think of a couple of cases:
When loading:
- The preference that was loaded says 'Abstract'. We need to localize that since the language may not be set to english
- The preference says something else. We don't localize this because it was changed by the user.
When storing:
- JabRef is set to english. The new value to store says 'Abstract'. We can store that.
- JabRef is set to german. The new value says 'Zusammenfassung'. This was localized. We actually want to store 'Abstract' so it can be correctly localized next time it is needed (also if the language was changed in the meantime).
why not always show the localized string
When the user changes the name, we cannot localize it anymore.
There was a problem hiding this comment.
So each Preference Object would have it's own keys and it's own defaults-Map for those Strings.
Not necessarily. My proposal would be to have a variable defaultTabNames in the preference object, which is initialized to the value of getDefaults().get(JabRefPreferences.CUSTOM_TAB_NAME + "_def" + i)) using a constructor argument when the preference object is initialized in JabRefPreferences. In this way, you can access the default outside of JabRefPreferences without needing to worry how the preferences are stored there.
When the user changes the name, we cannot localize it anymore.
We can still try to localize it, or not? So if the user puts "Abstract" as a custom tab name (assume it's not in default for the moment), then when displaying the tab, we get the localized string, say "Zusamenfassung" if the language is set to german. If the user already puts "Zusammenfassung" in the preferences, then Localization.lang doesn't do anything and returns "Zusammenfassung" again. There might be very rare cases where the user puts in a word in some language, which is a valid english word with a different translation (artificial example: Chinese user puts yue (moon) in, which is a valid english word (synonymy for Cantonese), so that Jabref would show Guǎngdōng huà (Cantonese in Chinese)). But these cases should be super rare with our limited dictionary. Would make the implementation a lot easier and might actually be what the user hopes to get
| } | ||
| Set<Field> fields = tab.getValue(); | ||
| if (fields.equals(FieldFactory.parseFieldList((String) Objects.requireNonNullElse(preferencesService.getDefaults().get(JabRefPreferences.CUSTOM_TAB_FIELDS + "_def" + i), "")))) { | ||
| fields = fields.stream().map(Field::getName).map(Localization::lang).map(FieldFactory::parseField).collect(Collectors.toSet()); |
There was a problem hiding this comment.
I'm not sure if that really works as intended, or if it now also stores the value typed in the field under the localized field name. But maybe we shouldn't localize field names at all or be consistently and localize all field names, also in other tabs.
There was a problem hiding this comment.
The idea is to store pref X only as X if it was changed by the user. Otherwise store the default value.
This is needed because JabRef writes all preferences once it's closed. Otherwise, if we localize 'Abstract' to 'Zusammenfassung' it would be stored as 'Zusammenfassung' and cannot be localized again. So no matter what language I set, JabRef would always say 'Zusammenfassung'.
There was a problem hiding this comment.
But isn't it then also storing the value (what the user types into the field in the entry editor) in the bibtex field "Zusammenfassung" because the variable field only contains localized fields.
There was a problem hiding this comment.
No the value should not be recorded in the preferences, only the heading of the tab and the fields to display in that tab. Those strings can be changed in the preferences, not directly in the entry editor AFAIK.
There was a problem hiding this comment.
I meant not the preferences, but how the field is written in the Bib file
No more special treatment necessary since localization is done where needed, not in the preferences.
…to unlocalized-preferences
…to unlocalized-preferences
# Conflicts: # docs/getting-into-the-code/guidelines-for-setting-up-a-local-workspace.md
|
For checking the localization strings, I switched to Java Parser. Needed to fix two parsing errors (javaparser/javaparser#3362 and javaparser/javaparser#3361). I build a custom JAR containing these patches. Works great here. Our decision was to allow variable references in |
| Store the preference only when it was changed by the user. Otherwise, leave it empty. | ||
|
|
||
| * Good, because When a consumer gets such an empty preference, it knows that it needs to read the default and localize it. | ||
| * Bad, because this won't work if users actually want something to be empty. |
There was a problem hiding this comment.
Given the large amount of hacks / workarounds that are needed to make our localization tests work with the third approach, maybe this second approach is more efficient? One could use null / empty optional as the default value so that users can still provide an empty string if they wish.
There was a problem hiding this comment.
So the defaults hash-map would have an empy optional / null. When accessing we test against that. If it is not null/empty, we use that string without localization. If not, we localize a string. The question is, what string? Where do we store the actual default? Storing it where it is accessed is not a good idea IMO.
One solution would be to introduce a 'LocalizablePreference' class that has a boolean flag 'overwrittenByUser' and value. If the flag is set, we read the value from the preferences. If not, it stores the default value. Consumers can then decide whether to localize the value based on the flag.
There was a problem hiding this comment.
One option would be to have the localized default in the corresponding preference object or in the get* method. The latter is in my opinion anyway a better solution than the huge defaults map.
|
DevCall impulse: Store only changed values. Do not store default values. - Still unclear how to deal with the localized things. Empty strings appear nice. |
|
We should make a decision here about how to proceed. Better not the very best decision now as the best decision never. Whatever we decide, we need to move forward here! @JabRef/developers |
|
@calixtus Would you mind to start an ADR here (https://adr.github.io/adr-manager/#)? Then we could decide more easily. |
|
@btut already created an ADR in this PR |
Co-authored-by: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com>
Co-authored-by: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Co-authored-by: Benedikt Tutzer <btut@users.noreply.github.com>
|
We finished ADR-0023 today (https://github.com/JabRef/jabref/blob/unlocalized-preferences/docs/adr/0023-unlocalized-preferences.md). Follow-up: A new PR will be crafted (as this one has conflicts and the "update" to Java-parser is unnecessary) |
This PR implements ADR-0023
CHANGELOG.mddescribed in a way that is understandable for the average user (if applicable)