Skip to content

Commit d9b38ce

Browse files
mag-sunkopporSiedlerchr
authored
Added support for (biblatex) langid to be an optional field in entry editor (JabRef#12071)
* Configured project and started integrating langid into classes * Successfully integrated a langid dropdown menu with all langid values into gui and program logic * Fixed style in tests * Introduced display name to Langid enum and wrote more tests * Updated CHANGELOG.md to reflect that the langid optional field has been integrated. * Updated files in accordance to feedback from maintainers, including: - removed redundant description in CHANGELOG.md - removed unnecessary gradle properties - removed unnecessary tests - fixed formatting/commented out code * Discard changes to gradle.properties * Update langid field entry in CHANGELOG.md Co-authored-by: Oliver Kopp <[email protected]> * Updated some files in accordance to feedback from maintainers, including: - refactored and renamed LangidEditorViewModel.java to LanguageEditorViewModel (and tests) - re-added gradle property - reverted edits to BibtexEntryTypeDefinitions.java - removed FieldProperty.LANGUAGEID so both language and langid standard fields have FieldProperty.LANGUAGE NB: Still yet to fix tests * re-added gradle parallel property * cleanup * use set * checkstyle * disable test rule * apply rules * revert junit recipe --------- Co-authored-by: Oliver Kopp <[email protected]> Co-authored-by: Christoph <[email protected]>
1 parent 17c3e2c commit d9b38ce

File tree

11 files changed

+341
-11
lines changed

11 files changed

+341
-11
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
3838
- We added a different background color to the search bar to indicate when the search syntax is wrong. [#11658](https://github.com/JabRef/jabref/pull/11658)
3939
- We added a setting which always adds the literal "Cited on pages" text before each JStyle citation. [#11691](https://github.com/JabRef/jabref/pull/11732)
4040
- We added a new plain citation parser that uses LLMs. [#11825](https://github.com/JabRef/jabref/issues/11825)
41+
- We added support for `langid` field for biblatex libraries. [#10868](https://github.com/JabRef/jabref/issues/10868)
4142
- We added support for modifier keys when dropping a file on an entry in the main table. [#12001](https://github.com/JabRef/jabref/pull/12001)
4243
- We added an importer for SSRN URLs. [#12021](https://github.com/JabRef/jabref/pull/12021)
4344
- We added a compare button to the duplicates in the citation relations tab to open the "Possible duplicate entries" window. [#11192](https://github.com/JabRef/jabref/issues/11192)
@@ -82,6 +83,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
8283
- We disabled the actions "Open Terminal here" and "Reveal in file explorer" for unsaved libraries. [#11920](https://github.com/JabRef/jabref/issues/11920)
8384
- JabRef now opens the corresponding directory in the library properties when "Browse" is clicked. [#12223](https://github.com/JabRef/jabref/pull/12223)
8485

86+
8587
### Fixed
8688

8789
- We fixed an issue where certain actions were not disabled when no libraries were open. [#11923](https://github.com/JabRef/jabref/issues/11923)

src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.jabref.gui.autocompleter.SuggestionProvider;
1111
import org.jabref.gui.autocompleter.SuggestionProviders;
1212
import org.jabref.gui.fieldeditors.identifier.IdentifierEditor;
13+
import org.jabref.gui.fieldeditors.optioneditors.LanguageEditorViewModel;
1314
import org.jabref.gui.fieldeditors.optioneditors.MonthEditorViewModel;
1415
import org.jabref.gui.fieldeditors.optioneditors.OptionEditor;
1516
import org.jabref.gui.fieldeditors.optioneditors.mapbased.CustomFieldEditorViewModel;
@@ -85,7 +86,10 @@ public static FieldEditorFX getForField(final Field field,
8586
} else if (fieldProperties.contains(FieldProperty.YES_NO)) {
8687
return new OptionEditor<>(new YesNoEditorViewModel(field, suggestionProvider, fieldCheckers, undoManager));
8788
} else if (fieldProperties.contains(FieldProperty.MONTH)) {
88-
return new OptionEditor<>(new MonthEditorViewModel(field, suggestionProvider, databaseContext.getMode(), fieldCheckers, undoManager));
89+
return new OptionEditor<>(new
90+
MonthEditorViewModel(field, suggestionProvider, databaseContext.getMode(), fieldCheckers, undoManager));
91+
} else if (fieldProperties.contains(FieldProperty.LANGUAGE)) {
92+
return new OptionEditor<>(new LanguageEditorViewModel(field, suggestionProvider, databaseContext.getMode(), fieldCheckers, undoManager));
8993
} else if (field == StandardField.GENDER) {
9094
return new OptionEditor<>(new GenderEditorViewModel(field, suggestionProvider, fieldCheckers, undoManager));
9195
} else if (fieldProperties.contains(FieldProperty.EDITOR_TYPE)) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package org.jabref.gui.fieldeditors.optioneditors;
2+
3+
import java.util.Arrays;
4+
import java.util.Collection;
5+
6+
import javax.swing.undo.UndoManager;
7+
8+
import javafx.util.StringConverter;
9+
10+
import org.jabref.gui.autocompleter.SuggestionProvider;
11+
import org.jabref.logic.integrity.FieldCheckers;
12+
import org.jabref.model.database.BibDatabaseMode;
13+
import org.jabref.model.entry.Langid;
14+
import org.jabref.model.entry.field.Field;
15+
import org.jabref.model.strings.StringUtil;
16+
17+
public class LanguageEditorViewModel extends OptionEditorViewModel<Langid> {
18+
private BibDatabaseMode databaseMode;
19+
20+
public LanguageEditorViewModel(Field field, SuggestionProvider<?> suggestionProvider, BibDatabaseMode databaseMode, FieldCheckers fieldCheckers, UndoManager undoManager) {
21+
super(field, suggestionProvider, fieldCheckers, undoManager);
22+
this.databaseMode = databaseMode;
23+
}
24+
25+
@Override
26+
public StringConverter<Langid> getStringConverter() {
27+
return new StringConverter<>() {
28+
@Override
29+
public String toString(Langid object) {
30+
if (object == null) {
31+
return null;
32+
} else {
33+
return object.getLangid(); // Langid used as both display and value
34+
}
35+
}
36+
37+
@Override
38+
public Langid fromString(String string) {
39+
if (StringUtil.isNotBlank(string)) {
40+
return Langid.parse(string).orElse(null);
41+
} else {
42+
return null;
43+
}
44+
}
45+
};
46+
}
47+
48+
@Override
49+
public Collection<Langid> getItems() {
50+
return Arrays.asList(Langid.values());
51+
}
52+
53+
@Override
54+
public String convertToDisplayText(Langid object) {
55+
return object.getName(); // Langid and display text are the same
56+
}
57+
}

src/main/java/org/jabref/gui/fieldeditors/optioneditors/MonthEditorViewModel.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import org.jabref.model.strings.StringUtil;
1616

1717
public class MonthEditorViewModel extends OptionEditorViewModel<Month> {
18-
private BibDatabaseMode databaseMode;
18+
private final BibDatabaseMode databaseMode;
1919

2020
public MonthEditorViewModel(Field field, SuggestionProvider<?> suggestionProvider, BibDatabaseMode databaseMode, FieldCheckers fieldCheckers, UndoManager undoManager) {
2121
super(field, suggestionProvider, fieldCheckers, undoManager);

src/main/java/org/jabref/model/entry/BibEntry.java

+4
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ public Optional<FieldChange> setMonth(Month parsedMonth) {
172172
return setField(StandardField.MONTH, parsedMonth.getJabRefFormat());
173173
}
174174

175+
public Optional<FieldChange> setLangid(Langid parsedLangid) {
176+
return setField(StandardField.LANGUAGEID, parsedLangid.getJabRefFormat());
177+
}
178+
175179
public Optional<String> getResolvedFieldOrAlias(OrFields fields, BibDatabase database) {
176180
for (Field field : fields.getFields()) {
177181
Optional<String> value = getResolvedFieldOrAlias(field, database);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package org.jabref.model.entry;
2+
3+
import java.util.Optional;
4+
5+
import org.jabref.logic.bibtex.FieldWriter;
6+
/**
7+
* Language identifiers based on BibLaTeX manual specifications.
8+
* See the BibLaTeX documentation for full details:
9+
* <a href="http://mirrors.ctan.org/macros/latex/contrib/biblatex/doc/biblatex.pdfhangelo">BibLaTeX manual</a>
10+
*/
11+
12+
public enum Langid {
13+
BASQUE("Basque", "basque"),
14+
BULGARIAN("Bulgarian", "bulgarian"),
15+
CATALAN("Catalan", "catalan"),
16+
CROATIAN("Croatian", "croatian"),
17+
CZECH("Czech", "czech"),
18+
DANISH("Danish", "danish"),
19+
AMERICAN("American", "american"),
20+
USENGLISH("US English", "USenglish"),
21+
ENGLISH("English", "english"),
22+
BRITISH("British", "british"),
23+
UKENGLISH("UK English", "UKenglish"),
24+
CANADIAN("Canadian", "canadian"),
25+
AUSTRALIAN("Australian", "australian"),
26+
NEWZEALAND("New Zealand", "newzealand"),
27+
ESTONIAN("Estonian", "estonian"),
28+
FINNISH("Finnish", "finnish"),
29+
FRENCH("French", "french"),
30+
GERMAN("German", "german"),
31+
AUSTRIAN("Austrian", "austrian"),
32+
SWISSGERMAN("Swiss German", "swissgerman"),
33+
NGERMAN("German (New)", "ngerman"),
34+
NAUSTRIAN("Austrian (New)", "naustrian"),
35+
NSWISSGERMAN("Swiss German (New)", "nswissgerman"),
36+
GREEK("Greek", "greek"),
37+
MAGYAR("Hungarian", "hungarian"),
38+
HUNGARIAN("Hungarian", "hungarian"),
39+
ICELANDIC("Icelandic", "icelandic"),
40+
ITALIAN("Italian", "italian"),
41+
LATVIAN("Latvian", "latvian"),
42+
LITHUANIAN("Lithuanian", "lithuanian"),
43+
MARATHI("Marathi", "marathi"),
44+
NORSK("Norwegian (Bokmål)", "norsk"),
45+
NYNORSK("Norwegian (Nynorsk)", "nynorsk"),
46+
POLISH("Polish", "polish"),
47+
BRAZIL("Portuguese (Brazilian)", "brazil"),
48+
PORTUGUESE("Portuguese", "portuguese"),
49+
PORTUGES("Portuguese (alt)", "portuges"),
50+
ROMANIAN("Romanian", "romanian"),
51+
RUSSIAN("Russian", "russian"),
52+
SERBIAN("Serbian (Latin)", "serbian"),
53+
SERBIANC("Serbian (Cyrillic)", "serbianc"),
54+
SLOVAK("Slovak", "slovak"),
55+
SLOVENE("Slovene", "slovene"),
56+
SLOVENIAN("Slovenian", "slovenian"),
57+
SPANISH("Spanish", "spanish"),
58+
SWEDISH("Swedish", "swedish"),
59+
TURKISH("Turkish", "turkish"),
60+
UKRAINIAN("Ukrainian", "ukrainian");
61+
62+
63+
private final String name;
64+
private final String langid;
65+
66+
Langid(String name, String langid) {
67+
this.name = name;
68+
this.langid = langid;
69+
}
70+
71+
public String getLangid() {
72+
return langid;
73+
}
74+
75+
public String getName() {
76+
return name;
77+
}
78+
79+
public static Optional<Langid> getByLangid(String id) {
80+
for (Langid lang : Langid.values()) {
81+
if (lang.langid.equalsIgnoreCase(id)) {
82+
return Optional.of(lang);
83+
}
84+
}
85+
return Optional.empty();
86+
}
87+
88+
public static Optional<Langid> parse(String value) {
89+
return Langid.getByLangid(value.trim().toLowerCase());
90+
}
91+
92+
public String getJabRefFormat() {
93+
return (FieldWriter.BIBTEX_STRING_START_END_SYMBOL + "%s" + FieldWriter.BIBTEX_STRING_START_END_SYMBOL).formatted(langid);
94+
}
95+
}

src/main/java/org/jabref/model/entry/field/FieldFactory.java

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public static Collection<Field> getNotTextFields() {
6969
// These fields are not marked as verbatim, because they could include LaTeX code
7070
result.add(StandardField.MONTH);
7171
result.add(StandardField.DATE);
72+
result.add(StandardField.LANGUAGEID);
7273
return result;
7374
}
7475

src/main/java/org/jabref/model/entry/types/BiblatexEntryTypeDefinitions.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class BiblatexEntryTypeDefinitions {
2323
.withImportantFields(
2424
StandardField.SUBTITLE, StandardField.EDITOR, StandardField.SERIES, StandardField.VOLUME, StandardField.NUMBER,
2525
StandardField.EID, StandardField.ISSUE, StandardField.PAGES, StandardField.NOTE, StandardField.ISSN, StandardField.DOI,
26-
StandardField.EPRINT, StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE)
26+
StandardField.EPRINT, StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE, StandardField.LANGUAGEID)
2727
.withDetailFields(
2828
StandardField.TRANSLATOR, StandardField.ANNOTATOR, StandardField.COMMENTATOR,
2929
StandardField.TITLEADDON, StandardField.EDITORA, StandardField.EDITORB, StandardField.EDITORC,
@@ -39,7 +39,7 @@ public class BiblatexEntryTypeDefinitions {
3939
StandardField.SUBTITLE, StandardField.TITLEADDON, StandardField.MAINTITLE, StandardField.MAINSUBTITLE,
4040
StandardField.MAINTITLEADDON, StandardField.VOLUME, StandardField.EDITION, StandardField.PUBLISHER, StandardField.ISBN,
4141
StandardField.CHAPTER, StandardField.PAGES, StandardField.PAGETOTAL, StandardField.DOI, StandardField.EPRINT,
42-
StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE)
42+
StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE, StandardField.LANGUAGEID)
4343
.withDetailFields(StandardField.EDITORA, StandardField.EDITORB, StandardField.EDITORC,
4444
StandardField.TRANSLATOR, StandardField.ANNOTATOR, StandardField.COMMENTATOR, StandardField.INTRODUCTION,
4545
StandardField.FOREWORD, StandardField.AFTERWORD,
@@ -55,7 +55,7 @@ public class BiblatexEntryTypeDefinitions {
5555
.withRequiredFields(StandardField.AUTHOR, StandardField.TITLE, StandardField.DATE)
5656
.withImportantFields(StandardField.EDITOR, StandardField.SUBTITLE, StandardField.TITLEADDON, StandardField.EDITION,
5757
StandardField.PUBLISHER, StandardField.ISBN, StandardField.PAGETOTAL, StandardField.DOI, StandardField.EPRINT,
58-
StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE)
58+
StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE, StandardField.LANGUAGEID)
5959
.withDetailFields(StandardField.EDITORA, StandardField.EDITORB, StandardField.EDITORC,
6060
StandardField.TRANSLATOR, StandardField.ANNOTATOR, StandardField.COMMENTATOR, StandardField.INTRODUCTION,
6161
StandardField.FOREWORD, StandardField.AFTERWORD,
@@ -72,7 +72,7 @@ public class BiblatexEntryTypeDefinitions {
7272
StandardField.MAINTITLE, StandardField.MAINSUBTITLE, StandardField.MAINTITLEADDON, StandardField.BOOKSUBTITLE,
7373
StandardField.BOOKTITLEADDON, StandardField.VOLUME, StandardField.EDITION, StandardField.PUBLISHER,
7474
StandardField.ISBN, StandardField.CHAPTER, StandardField.PAGES, StandardField.DOI, StandardField.EPRINT,
75-
StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE)
75+
StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE, StandardField.LANGUAGEID)
7676
.withDetailFields(StandardField.EDITORA, StandardField.EDITORB,
7777
StandardField.EDITORC, StandardField.TRANSLATOR, StandardField.ANNOTATOR, StandardField.COMMENTATOR,
7878
StandardField.INTRODUCTION, StandardField.FOREWORD, StandardField.AFTERWORD,
@@ -101,7 +101,7 @@ public class BiblatexEntryTypeDefinitions {
101101
.withRequiredFields(new OrFields(StandardField.AUTHOR, StandardField.EDITOR), StandardField.TITLE, StandardField.DATE)
102102
.withImportantFields(StandardField.SUBTITLE, StandardField.TITLEADDON, StandardField.HOWPUBLISHED,
103103
StandardField.CHAPTER, StandardField.PAGES, StandardField.DOI, StandardField.EPRINT, StandardField.EPRINTCLASS,
104-
StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE)
104+
StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE, StandardField.LANGUAGEID)
105105
.withDetailFields(StandardField.LANGUAGE,
106106
StandardField.TYPE, StandardField.NOTE, StandardField.LOCATION,
107107
StandardField.PAGETOTAL, StandardField.ADDENDUM, StandardField.PUBSTATE)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package org.jabref.gui.fieldeditors.optioneditors;
2+
3+
import java.util.Collection;
4+
import java.util.EnumSet;
5+
import java.util.HashSet;
6+
7+
import javax.swing.undo.UndoManager;
8+
9+
import org.jabref.gui.autocompleter.SuggestionProvider;
10+
import org.jabref.logic.FilePreferences;
11+
import org.jabref.logic.integrity.FieldCheckers;
12+
import org.jabref.logic.journals.JournalAbbreviationRepository;
13+
import org.jabref.model.database.BibDatabaseContext;
14+
import org.jabref.model.database.BibDatabaseMode;
15+
import org.jabref.model.entry.Langid;
16+
import org.jabref.model.entry.field.StandardField;
17+
18+
import org.junit.jupiter.api.BeforeEach;
19+
import org.junit.jupiter.api.Test;
20+
21+
import static org.junit.jupiter.api.Assertions.assertEquals;
22+
import static org.junit.jupiter.api.Assertions.assertNull;
23+
import static org.mockito.Mockito.mock;
24+
25+
public class LanguageEditorViewModelTest {
26+
27+
private LanguageEditorViewModel languageEditorViewModel;
28+
29+
@BeforeEach
30+
void setUp() {
31+
BibDatabaseContext databaseContext = mock(BibDatabaseContext.class);
32+
FilePreferences filePreferences = mock(FilePreferences.class);
33+
JournalAbbreviationRepository abbreviationRepository = mock(JournalAbbreviationRepository.class);
34+
FieldCheckers fieldCheckers = new FieldCheckers(databaseContext, filePreferences, abbreviationRepository, false);
35+
SuggestionProvider<?> suggestionProvider = mock(SuggestionProvider.class);
36+
37+
languageEditorViewModel = new LanguageEditorViewModel(
38+
StandardField.LANGUAGEID,
39+
suggestionProvider,
40+
BibDatabaseMode.BIBLATEX,
41+
fieldCheckers,
42+
new UndoManager()
43+
);
44+
}
45+
46+
@Test
47+
void getItemsShouldReturnAllLangidValues() {
48+
Collection<Langid> items = new HashSet<>(languageEditorViewModel.getItems());
49+
assertEquals(EnumSet.allOf(Langid.class), items);
50+
}
51+
52+
@Test
53+
void stringConversion() {
54+
String langidString = "bulgarian";
55+
Langid langid = languageEditorViewModel.getStringConverter().fromString(langidString);
56+
assertEquals(Langid.BULGARIAN, langid, "String should convert to the corresponding Langid");
57+
58+
String convertedString = languageEditorViewModel.getStringConverter().toString(Langid.BULGARIAN);
59+
assertEquals(langidString, convertedString, "Langid should convert back to its string representation");
60+
}
61+
62+
@Test
63+
void stringConversionWithHumanReadableName() {
64+
// Test conversion from human-readable name to Langid
65+
String langidString = "Basque";
66+
Langid langid = languageEditorViewModel.getStringConverter().fromString(langidString);
67+
assertEquals(Langid.BASQUE, langid, "Human-readable name should convert to the corresponding Langid");
68+
69+
// Test conversion from Langid to human-readable name
70+
String convertedString = languageEditorViewModel.getStringConverter().toString(Langid.BASQUE);
71+
assertEquals("basque", convertedString, "Langid should convert back to its lowercase string representation");
72+
}
73+
74+
@Test
75+
void handlingNullValue() {
76+
// Test the handling of a null value
77+
Langid result = languageEditorViewModel.getStringConverter().fromString(null);
78+
assertNull(result, "Null input should return null Langid");
79+
}
80+
81+
@Test
82+
void handlingBlankValue() {
83+
// Test the handling of a blank string
84+
Langid result = languageEditorViewModel.getStringConverter().fromString(" ");
85+
assertNull(result, "Blank input should return null Langid");
86+
}
87+
}
88+

0 commit comments

Comments
 (0)