Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for (biblatex) langid to be an optional field in entry editor #12071

Merged
merged 20 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>
*/

Siedlerchr marked this conversation as resolved.
Show resolved Hide resolved
public enum Langid {
mag-sun marked this conversation as resolved.
Show resolved Hide resolved
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 testStringConversion() {
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 testStringConversionWithHumanReadableName() {
// 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 testHandlingNullValue() {
// Test the handling of a null value
Langid result = languageEditorViewModel.getStringConverter().fromString(null);
assertNull(result, "Null input should return null Langid");
}

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

Loading
Loading