Skip to content

Commit

Permalink
Added support for (biblatex) langid to be an optional field in entr…
Browse files Browse the repository at this point in the history
…y editor (#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]>
  • Loading branch information
3 people authored Dec 2, 2024
1 parent 17c3e2c commit d9b38ce
Show file tree
Hide file tree
Showing 11 changed files with 341 additions and 11 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
- 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)
- 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)
- We added a new plain citation parser that uses LLMs. [#11825](https://github.com/JabRef/jabref/issues/11825)
- We added support for `langid` field for biblatex libraries. [#10868](https://github.com/JabRef/jabref/issues/10868)
- 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)
- We added an importer for SSRN URLs. [#12021](https://github.com/JabRef/jabref/pull/12021)
- 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)
Expand Down Expand Up @@ -82,6 +83,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
- We disabled the actions "Open Terminal here" and "Reveal in file explorer" for unsaved libraries. [#11920](https://github.com/JabRef/jabref/issues/11920)
- JabRef now opens the corresponding directory in the library properties when "Browse" is clicked. [#12223](https://github.com/JabRef/jabref/pull/12223)


### Fixed

- We fixed an issue where certain actions were not disabled when no libraries were open. [#11923](https://github.com/JabRef/jabref/issues/11923)
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.jabref.gui.autocompleter.SuggestionProvider;
import org.jabref.gui.autocompleter.SuggestionProviders;
import org.jabref.gui.fieldeditors.identifier.IdentifierEditor;
import org.jabref.gui.fieldeditors.optioneditors.LanguageEditorViewModel;
import org.jabref.gui.fieldeditors.optioneditors.MonthEditorViewModel;
import org.jabref.gui.fieldeditors.optioneditors.OptionEditor;
import org.jabref.gui.fieldeditors.optioneditors.mapbased.CustomFieldEditorViewModel;
Expand Down Expand Up @@ -85,7 +86,10 @@ public static FieldEditorFX getForField(final Field field,
} else if (fieldProperties.contains(FieldProperty.YES_NO)) {
return new OptionEditor<>(new YesNoEditorViewModel(field, suggestionProvider, fieldCheckers, undoManager));
} else if (fieldProperties.contains(FieldProperty.MONTH)) {
return new OptionEditor<>(new MonthEditorViewModel(field, suggestionProvider, databaseContext.getMode(), fieldCheckers, undoManager));
return new OptionEditor<>(new
MonthEditorViewModel(field, suggestionProvider, databaseContext.getMode(), fieldCheckers, undoManager));
} else if (fieldProperties.contains(FieldProperty.LANGUAGE)) {
return new OptionEditor<>(new LanguageEditorViewModel(field, suggestionProvider, databaseContext.getMode(), fieldCheckers, undoManager));
} else if (field == StandardField.GENDER) {
return new OptionEditor<>(new GenderEditorViewModel(field, suggestionProvider, fieldCheckers, undoManager));
} else if (fieldProperties.contains(FieldProperty.EDITOR_TYPE)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.jabref.gui.fieldeditors.optioneditors;

import java.util.Arrays;
import java.util.Collection;

import javax.swing.undo.UndoManager;

import javafx.util.StringConverter;

import org.jabref.gui.autocompleter.SuggestionProvider;
import org.jabref.logic.integrity.FieldCheckers;
import org.jabref.model.database.BibDatabaseMode;
import org.jabref.model.entry.Langid;
import org.jabref.model.entry.field.Field;
import org.jabref.model.strings.StringUtil;

public class LanguageEditorViewModel extends OptionEditorViewModel<Langid> {
private BibDatabaseMode databaseMode;

public LanguageEditorViewModel(Field field, SuggestionProvider<?> suggestionProvider, BibDatabaseMode databaseMode, FieldCheckers fieldCheckers, UndoManager undoManager) {
super(field, suggestionProvider, fieldCheckers, undoManager);
this.databaseMode = databaseMode;
}

@Override
public StringConverter<Langid> getStringConverter() {
return new StringConverter<>() {
@Override
public String toString(Langid object) {
if (object == null) {
return null;
} else {
return object.getLangid(); // Langid used as both display and value
}
}

@Override
public Langid fromString(String string) {
if (StringUtil.isNotBlank(string)) {
return Langid.parse(string).orElse(null);
} else {
return null;
}
}
};
}

@Override
public Collection<Langid> getItems() {
return Arrays.asList(Langid.values());
}

@Override
public String convertToDisplayText(Langid object) {
return object.getName(); // Langid and display text are the same
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import org.jabref.model.strings.StringUtil;

public class MonthEditorViewModel extends OptionEditorViewModel<Month> {
private BibDatabaseMode databaseMode;
private final BibDatabaseMode databaseMode;

public MonthEditorViewModel(Field field, SuggestionProvider<?> suggestionProvider, BibDatabaseMode databaseMode, FieldCheckers fieldCheckers, UndoManager undoManager) {
super(field, suggestionProvider, fieldCheckers, undoManager);
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/jabref/model/entry/BibEntry.java
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ public Optional<FieldChange> setMonth(Month parsedMonth) {
return setField(StandardField.MONTH, parsedMonth.getJabRefFormat());
}

public Optional<FieldChange> setLangid(Langid parsedLangid) {
return setField(StandardField.LANGUAGEID, parsedLangid.getJabRefFormat());
}

public Optional<String> getResolvedFieldOrAlias(OrFields fields, BibDatabase database) {
for (Field field : fields.getFields()) {
Optional<String> value = getResolvedFieldOrAlias(field, database);
Expand Down
95 changes: 95 additions & 0 deletions src/main/java/org/jabref/model/entry/Langid.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package org.jabref.model.entry;

import java.util.Optional;

import org.jabref.logic.bibtex.FieldWriter;
/**
* Language identifiers based on BibLaTeX manual specifications.
* See the BibLaTeX documentation for full details:
* <a href="http://mirrors.ctan.org/macros/latex/contrib/biblatex/doc/biblatex.pdfhangelo">BibLaTeX manual</a>
*/

public enum Langid {
BASQUE("Basque", "basque"),
BULGARIAN("Bulgarian", "bulgarian"),
CATALAN("Catalan", "catalan"),
CROATIAN("Croatian", "croatian"),
CZECH("Czech", "czech"),
DANISH("Danish", "danish"),
AMERICAN("American", "american"),
USENGLISH("US English", "USenglish"),
ENGLISH("English", "english"),
BRITISH("British", "british"),
UKENGLISH("UK English", "UKenglish"),
CANADIAN("Canadian", "canadian"),
AUSTRALIAN("Australian", "australian"),
NEWZEALAND("New Zealand", "newzealand"),
ESTONIAN("Estonian", "estonian"),
FINNISH("Finnish", "finnish"),
FRENCH("French", "french"),
GERMAN("German", "german"),
AUSTRIAN("Austrian", "austrian"),
SWISSGERMAN("Swiss German", "swissgerman"),
NGERMAN("German (New)", "ngerman"),
NAUSTRIAN("Austrian (New)", "naustrian"),
NSWISSGERMAN("Swiss German (New)", "nswissgerman"),
GREEK("Greek", "greek"),
MAGYAR("Hungarian", "hungarian"),
HUNGARIAN("Hungarian", "hungarian"),
ICELANDIC("Icelandic", "icelandic"),
ITALIAN("Italian", "italian"),
LATVIAN("Latvian", "latvian"),
LITHUANIAN("Lithuanian", "lithuanian"),
MARATHI("Marathi", "marathi"),
NORSK("Norwegian (Bokmål)", "norsk"),
NYNORSK("Norwegian (Nynorsk)", "nynorsk"),
POLISH("Polish", "polish"),
BRAZIL("Portuguese (Brazilian)", "brazil"),
PORTUGUESE("Portuguese", "portuguese"),
PORTUGES("Portuguese (alt)", "portuges"),
ROMANIAN("Romanian", "romanian"),
RUSSIAN("Russian", "russian"),
SERBIAN("Serbian (Latin)", "serbian"),
SERBIANC("Serbian (Cyrillic)", "serbianc"),
SLOVAK("Slovak", "slovak"),
SLOVENE("Slovene", "slovene"),
SLOVENIAN("Slovenian", "slovenian"),
SPANISH("Spanish", "spanish"),
SWEDISH("Swedish", "swedish"),
TURKISH("Turkish", "turkish"),
UKRAINIAN("Ukrainian", "ukrainian");


private final String name;
private final String langid;

Langid(String name, String langid) {
this.name = name;
this.langid = langid;
}

public String getLangid() {
return langid;
}

public String getName() {
return name;
}

public static Optional<Langid> getByLangid(String id) {
for (Langid lang : Langid.values()) {
if (lang.langid.equalsIgnoreCase(id)) {
return Optional.of(lang);
}
}
return Optional.empty();
}

public static Optional<Langid> parse(String value) {
return Langid.getByLangid(value.trim().toLowerCase());
}

public String getJabRefFormat() {
return (FieldWriter.BIBTEX_STRING_START_END_SYMBOL + "%s" + FieldWriter.BIBTEX_STRING_START_END_SYMBOL).formatted(langid);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public static Collection<Field> getNotTextFields() {
// These fields are not marked as verbatim, because they could include LaTeX code
result.add(StandardField.MONTH);
result.add(StandardField.DATE);
result.add(StandardField.LANGUAGEID);
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class BiblatexEntryTypeDefinitions {
.withImportantFields(
StandardField.SUBTITLE, StandardField.EDITOR, StandardField.SERIES, StandardField.VOLUME, StandardField.NUMBER,
StandardField.EID, StandardField.ISSUE, StandardField.PAGES, StandardField.NOTE, StandardField.ISSN, StandardField.DOI,
StandardField.EPRINT, StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE)
StandardField.EPRINT, StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE, StandardField.LANGUAGEID)
.withDetailFields(
StandardField.TRANSLATOR, StandardField.ANNOTATOR, StandardField.COMMENTATOR,
StandardField.TITLEADDON, StandardField.EDITORA, StandardField.EDITORB, StandardField.EDITORC,
Expand All @@ -39,7 +39,7 @@ public class BiblatexEntryTypeDefinitions {
StandardField.SUBTITLE, StandardField.TITLEADDON, StandardField.MAINTITLE, StandardField.MAINSUBTITLE,
StandardField.MAINTITLEADDON, StandardField.VOLUME, StandardField.EDITION, StandardField.PUBLISHER, StandardField.ISBN,
StandardField.CHAPTER, StandardField.PAGES, StandardField.PAGETOTAL, StandardField.DOI, StandardField.EPRINT,
StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE)
StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE, StandardField.LANGUAGEID)
.withDetailFields(StandardField.EDITORA, StandardField.EDITORB, StandardField.EDITORC,
StandardField.TRANSLATOR, StandardField.ANNOTATOR, StandardField.COMMENTATOR, StandardField.INTRODUCTION,
StandardField.FOREWORD, StandardField.AFTERWORD,
Expand All @@ -55,7 +55,7 @@ public class BiblatexEntryTypeDefinitions {
.withRequiredFields(StandardField.AUTHOR, StandardField.TITLE, StandardField.DATE)
.withImportantFields(StandardField.EDITOR, StandardField.SUBTITLE, StandardField.TITLEADDON, StandardField.EDITION,
StandardField.PUBLISHER, StandardField.ISBN, StandardField.PAGETOTAL, StandardField.DOI, StandardField.EPRINT,
StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE)
StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE, StandardField.LANGUAGEID)
.withDetailFields(StandardField.EDITORA, StandardField.EDITORB, StandardField.EDITORC,
StandardField.TRANSLATOR, StandardField.ANNOTATOR, StandardField.COMMENTATOR, StandardField.INTRODUCTION,
StandardField.FOREWORD, StandardField.AFTERWORD,
Expand All @@ -72,7 +72,7 @@ public class BiblatexEntryTypeDefinitions {
StandardField.MAINTITLE, StandardField.MAINSUBTITLE, StandardField.MAINTITLEADDON, StandardField.BOOKSUBTITLE,
StandardField.BOOKTITLEADDON, StandardField.VOLUME, StandardField.EDITION, StandardField.PUBLISHER,
StandardField.ISBN, StandardField.CHAPTER, StandardField.PAGES, StandardField.DOI, StandardField.EPRINT,
StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE)
StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE, StandardField.LANGUAGEID)
.withDetailFields(StandardField.EDITORA, StandardField.EDITORB,
StandardField.EDITORC, StandardField.TRANSLATOR, StandardField.ANNOTATOR, StandardField.COMMENTATOR,
StandardField.INTRODUCTION, StandardField.FOREWORD, StandardField.AFTERWORD,
Expand Down Expand Up @@ -101,7 +101,7 @@ public class BiblatexEntryTypeDefinitions {
.withRequiredFields(new OrFields(StandardField.AUTHOR, StandardField.EDITOR), StandardField.TITLE, StandardField.DATE)
.withImportantFields(StandardField.SUBTITLE, StandardField.TITLEADDON, StandardField.HOWPUBLISHED,
StandardField.CHAPTER, StandardField.PAGES, StandardField.DOI, StandardField.EPRINT, StandardField.EPRINTCLASS,
StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE)
StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE, StandardField.LANGUAGEID)
.withDetailFields(StandardField.LANGUAGE,
StandardField.TYPE, StandardField.NOTE, StandardField.LOCATION,
StandardField.PAGETOTAL, StandardField.ADDENDUM, StandardField.PUBSTATE)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package org.jabref.gui.fieldeditors.optioneditors;

import java.util.Collection;
import java.util.EnumSet;
import java.util.HashSet;

import javax.swing.undo.UndoManager;

import org.jabref.gui.autocompleter.SuggestionProvider;
import org.jabref.logic.FilePreferences;
import org.jabref.logic.integrity.FieldCheckers;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.database.BibDatabaseMode;
import org.jabref.model.entry.Langid;
import org.jabref.model.entry.field.StandardField;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.Mockito.mock;

public class LanguageEditorViewModelTest {

private LanguageEditorViewModel languageEditorViewModel;

@BeforeEach
void setUp() {
BibDatabaseContext databaseContext = mock(BibDatabaseContext.class);
FilePreferences filePreferences = mock(FilePreferences.class);
JournalAbbreviationRepository abbreviationRepository = mock(JournalAbbreviationRepository.class);
FieldCheckers fieldCheckers = new FieldCheckers(databaseContext, filePreferences, abbreviationRepository, false);
SuggestionProvider<?> suggestionProvider = mock(SuggestionProvider.class);

languageEditorViewModel = new LanguageEditorViewModel(
StandardField.LANGUAGEID,
suggestionProvider,
BibDatabaseMode.BIBLATEX,
fieldCheckers,
new UndoManager()
);
}

@Test
void getItemsShouldReturnAllLangidValues() {
Collection<Langid> items = new HashSet<>(languageEditorViewModel.getItems());
assertEquals(EnumSet.allOf(Langid.class), items);
}

@Test
void stringConversion() {
String langidString = "bulgarian";
Langid langid = languageEditorViewModel.getStringConverter().fromString(langidString);
assertEquals(Langid.BULGARIAN, langid, "String should convert to the corresponding Langid");

String convertedString = languageEditorViewModel.getStringConverter().toString(Langid.BULGARIAN);
assertEquals(langidString, convertedString, "Langid should convert back to its string representation");
}

@Test
void stringConversionWithHumanReadableName() {
// Test conversion from human-readable name to Langid
String langidString = "Basque";
Langid langid = languageEditorViewModel.getStringConverter().fromString(langidString);
assertEquals(Langid.BASQUE, langid, "Human-readable name should convert to the corresponding Langid");

// Test conversion from Langid to human-readable name
String convertedString = languageEditorViewModel.getStringConverter().toString(Langid.BASQUE);
assertEquals("basque", convertedString, "Langid should convert back to its lowercase string representation");
}

@Test
void handlingNullValue() {
// Test the handling of a null value
Langid result = languageEditorViewModel.getStringConverter().fromString(null);
assertNull(result, "Null input should return null Langid");
}

@Test
void handlingBlankValue() {
// Test the handling of a blank string
Langid result = languageEditorViewModel.getStringConverter().fromString(" ");
assertNull(result, "Blank input should return null Langid");
}
}

Loading

0 comments on commit d9b38ce

Please sign in to comment.