-
Notifications
You must be signed in to change notification settings - Fork 18
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
Handle multi language input fields in web ui #141
Changes from 26 commits
a54d8fe
4cec4df
75b94c4
c2a72a4
36cb948
b2f0f1d
4191775
aad5f6e
2e3b656
ca9d9a3
5f56fe7
6e14652
01c4d92
60149e1
1c6e208
a8511d8
5307495
c85a7c9
230a7b3
887857b
d10a5f5
b4037a9
3c6b6b8
56145a8
bb2a4a4
2d3cd16
c7dafb7
ac96e11
141f6e3
3ff6617
c603def
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
defmodule Api.Worker.Enricher.I18NFieldConverter do | ||
|
||
alias Api.Core.CategoryTreeList | ||
alias Api.Worker.Enricher.Utils | ||
|
||
defp convert_string(resource, field_name, field_value) when not is_map(field_value) do # this is from legacy project then | ||
put_in(resource, [field_name], %{ "unspecifiedLanguage" => field_value }) | ||
end | ||
defp convert_string resource, _field_name, _field_value do | ||
resource | ||
end | ||
|
||
defp convert_string_array_item(item) when not is_map(item) do # legacy | ||
%{ "unspecifiedLanguage" => item } | ||
end | ||
defp convert_string_array_item item do | ||
item | ||
end | ||
|
||
defp convert_string_array(resource, field_name, field_value) do | ||
put_in(resource, [field_name], Enum.map(field_value, &convert_string_array_item/1)) | ||
end | ||
|
||
defp convert_dating_source(dating_item_source) when not is_map(dating_item_source) do # from legacy project | ||
# TODO review, here we use keyword, above we use string | ||
%{ unspecifiedLanguage: dating_item_source } | ||
end | ||
defp convert_dating_source dating_item_source do | ||
dating_item_source | ||
end | ||
|
||
defp convert_dating_item dating_item do | ||
put_in(dating_item.source, convert_dating_source(dating_item.source)) | ||
end | ||
|
||
defp convert_dating resource, field_name, field_value do | ||
put_in(resource, [field_name], Enum.map(field_value, &convert_dating_item/1)) | ||
end | ||
|
||
defp convert_dimension_measurement_comment(dimension_measurement_comment) when not is_map(dimension_measurement_comment) do # legacy project | ||
%{ unspecifiedLanguage: dimension_measurement_comment } | ||
end | ||
defp convert_dimension_measurement_comment dimension_measurement_comment do | ||
dimension_measurement_comment | ||
end | ||
|
||
defp convert_dimension_item dimension_item do | ||
put_in(dimension_item.measurementComment, convert_dimension_measurement_comment(dimension_item.measurementComment)) | ||
end | ||
|
||
defp convert_dimension resource, field_name, field_value do | ||
put_in(resource, [field_name], Enum.map(field_value, &convert_dimension_item/1)) | ||
end | ||
|
||
defp convert_resource_field category_definition_groups do | ||
fn {field_name, field_value}, resource -> | ||
field_definition = Utils.get_field_definition category_definition_groups, Atom.to_string(field_name) | ||
|
||
if is_nil(field_definition[:inputType]) do | ||
resource | ||
else | ||
cond do | ||
field_definition.inputType == "dating" -> | ||
convert_dating resource, field_name, field_value | ||
|
||
field_definition.inputType == "dimension" -> | ||
convert_dimension resource, field_name, field_value | ||
|
||
field_definition.inputType == "multiInput" | ||
or field_definition.inputType == "simpleMultiInput" -> | ||
convert_string_array resource, field_name, field_value | ||
|
||
field_definition.inputType == "input" | ||
or field_definition.inputType == "simpleInput" | ||
or field_definition.inputType == "text" -> | ||
convert_string resource, field_name, field_value | ||
|
||
true -> | ||
resource | ||
end | ||
end | ||
end | ||
end | ||
|
||
def convert_category change = %{ doc: %{ resource: resource } }, category_definition_groups do | ||
resource = Enum.reduce(resource, resource, convert_resource_field(category_definition_groups)) | ||
put_in(change.doc.resource, resource) | ||
end | ||
|
||
def convert change, configuration do | ||
name = change.doc.resource.category.name # TODO review category.name, maybe document the expectation | ||
category_definition = CategoryTreeList.find_by_name(name, configuration) | ||
convert_category change, category_definition.groups | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
defmodule Api.Worker.Enricher.Utils do | ||
|
||
# TODO extract | ||
def get_field_definition(category_definition_groups, field_name) do | ||
group = Enum.find(category_definition_groups, &get_field_definition_from_group(&1, field_name)) | ||
get_field_definition_from_group(group, field_name) | ||
end | ||
|
||
defp get_field_definition_from_group(%{ fields: fields }, field_name) do | ||
Enum.find(fields, fn field -> field.name == field_name end) | ||
end | ||
defp get_field_definition_from_group(_, _), do: nil | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
defmodule Api.Worker.Enricher.I18NFieldConverterTest do | ||
|
||
use ExUnit.Case, async: true | ||
use Plug.Test | ||
alias Api.Worker.Enricher.I18NFieldConverter | ||
|
||
test "convert input, simpleInput, multiInput, simpleMultiInput" do | ||
change = %{ | ||
doc: %{ | ||
resource: %{ | ||
category: %{ | ||
name: "Trench" | ||
}, | ||
legacyInputField: "hallo", | ||
inputField: %{ "de" => "hallo-de" }, | ||
simpleInputField: "hallo-simple-input", | ||
legacyTextField: "hallo\ntext", | ||
textField: %{ "de" => "hallo-de\ntext" }, | ||
legacyMultiInputField: ["a", "b"], | ||
multiInputField: [%{ "de" => "a" }, %{ "de" => "b" }], | ||
simpleMultiInputField: ["a", "b"] | ||
} | ||
}, | ||
} | ||
category_definition_groups = | ||
[ | ||
%{ | ||
fields: [ | ||
%{ inputType: "input", name: "legacyInputField" }, | ||
%{ inputType: "input", name: "inputField" }, | ||
%{ inputType: "simpleInput", name: "simpleInputField" }, | ||
%{ inputType: "text", name: "legacyTextField" }, | ||
%{ inputType: "text", name: "textField" }, | ||
%{ inputType: "multiInput", name: "legacyMultiInputField" }, | ||
%{ inputType: "multiInput", name: "multiInputField" }, | ||
%{ inputType: "simpleMultiInput", name: "simpleMultiInputField" } | ||
] | ||
} | ||
] | ||
|
||
resource = (I18NFieldConverter.convert_category change, category_definition_groups).doc.resource | ||
|
||
assert %{ "unspecifiedLanguage" => "hallo" } == resource.legacyInputField | ||
assert %{ "de" => "hallo-de" } == resource.inputField | ||
assert %{ "unspecifiedLanguage" => "hallo-simple-input" } == resource.simpleInputField | ||
assert %{ "unspecifiedLanguage" => "hallo\ntext" } == resource.legacyTextField | ||
assert %{ "de" => "hallo-de\ntext" } == resource.textField | ||
assert [%{ "unspecifiedLanguage" => "a" }, %{ "unspecifiedLanguage" => "b" }] == resource.legacyMultiInputField | ||
assert [%{ "de" => "a" }, %{ "de" => "b" }] == resource.multiInputField | ||
assert [%{ "unspecifiedLanguage" => "a" }, %{ "unspecifiedLanguage" => "b" }] == resource.simpleMultiInputField | ||
end | ||
|
||
test "convert dating" do | ||
category_definition_groups = | ||
[ | ||
%{ | ||
fields: [ | ||
%{ inputType: "dating", name: "datingField" }, | ||
%{ inputType: "dating", name: "legacyDatingField" }, | ||
] | ||
} | ||
] | ||
change = %{ | ||
doc: %{ | ||
resource: %{ | ||
category: %{ | ||
name: "Trench" | ||
}, | ||
datingField: [%{ | ||
source: %{de: "Eine Datierung", en: "A Dating"} | ||
}], | ||
legacyDatingField: [%{ | ||
source: "Eine Datierung" | ||
}] | ||
} | ||
}, | ||
} | ||
|
||
resource = (I18NFieldConverter.convert_category change, category_definition_groups).doc.resource | ||
|
||
assert %{ de: "Eine Datierung", en: "A Dating" } == (List.first resource.datingField).source | ||
assert %{ unspecifiedLanguage: "Eine Datierung" } == (List.first resource.legacyDatingField).source | ||
end | ||
|
||
test "convert dimension" do | ||
category_definition_groups = | ||
[ | ||
%{ | ||
fields: [ | ||
%{ inputType: "dimension", name: "dimensionField" }, | ||
%{ inputType: "dimension", name: "legacyDimensionField" }, | ||
] | ||
} | ||
] | ||
change = %{ | ||
doc: %{ | ||
resource: %{ | ||
category: %{ | ||
name: "Trench" | ||
}, | ||
dimensionField: [%{ | ||
measurementComment: %{de: "Eine Abmessung", en: "A dimension"} | ||
}], | ||
legacyDimensionField: [%{ | ||
measurementComment: "Eine Abmessung" | ||
}] | ||
} | ||
}, | ||
} | ||
|
||
resource = (I18NFieldConverter.convert_category change, category_definition_groups).doc.resource | ||
|
||
assert %{ de: "Eine Abmessung", en: "A dimension" } == (List.first resource.dimensionField).measurementComment | ||
assert %{ unspecifiedLanguage: "Eine Abmessung" } == (List.first resource.legacyDimensionField).measurementComment | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ import { Card } from 'react-bootstrap'; | |
import { useTranslation } from 'react-i18next'; | ||
import { Link, useLocation, useParams } from 'react-router-dom'; | ||
import ReactMarkdown from 'react-markdown'; | ||
import { I18N } from 'idai-field-core'; | ||
import { Document, FieldValue, getDocumentImages, getFieldValue } from '../../api/document'; | ||
import { get, search } from '../../api/documents'; | ||
import { buildProjectQueryTemplate, parseFrontendGetParams, Query } from '../../api/query'; | ||
|
@@ -25,6 +26,7 @@ import { EXCLUDED_CATEGORIES } from '../constants'; | |
import CategoryFilter from '../filter/CategoryFilter'; | ||
import ProjectHierarchyButton from './ProjectHierarchyButton'; | ||
import ProjectMap from './ProjectMap'; | ||
import { getTranslation } from '../../shared/languages'; | ||
|
||
|
||
const MAP_FIT_OPTIONS = { padding : [ 10, 10, 10, 10 ], duration: 500 }; | ||
|
@@ -87,17 +89,20 @@ export default function ProjectHome(): ReactElement { | |
} | ||
|
||
|
||
const renderTitle = (title: string, projectDocument: Document) => | ||
<div className="d-flex p-2 m-2" style={ headerStyle }> | ||
<div className="flex-fill"> | ||
<h2><img src="/marker-icon.svg" alt="Home" style={ homeIconStyle } /> {title}</h2> | ||
</div> | ||
<div className="text-right" style={ buttonsStyle }> | ||
<LicenseInformationButton license={ projectDocument.resource.license } /> | ||
<DocumentPermalinkButton url={ getDocumentPermalink(projectDocument) } /> | ||
</div> | ||
</div>; | ||
const renderTitle = (title: string, projectDocument: Document) => { | ||
|
||
const titleStr = getTranslation(title as undefined as I18N.String); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fix typing. param |
||
|
||
return (<div className="d-flex p-2 m-2" style={ headerStyle }> | ||
<div className="flex-fill"> | ||
<h2><img src="/marker-icon.svg" alt="Home" style={ homeIconStyle } /> {titleStr}</h2> | ||
</div> | ||
<div className="text-right" style={ buttonsStyle }> | ||
<LicenseInformationButton license={ projectDocument.resource.license } /> | ||
<DocumentPermalinkButton url={ getDocumentPermalink(projectDocument) } /> | ||
</div> | ||
</div>); | ||
}; | ||
|
||
const renderSidebar = (projectId: string, projectDocument: Document, categoryFilter: ResultFilter, | ||
setHighlightedCategories: (categories: string[]) => void, t: TFunction, typeCatalogCount: number, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,19 @@ | ||
import { ResultDocument } from '../api/result'; | ||
import { Document } from '../api/document'; | ||
import { getTranslation } from '../shared/languages'; | ||
|
||
|
||
const MAX_LABEL_LENGTH = 35; | ||
|
||
|
||
export const getProjectLabel = (projectDocument: ResultDocument|Document): string => { | ||
|
||
return projectDocument.resource.shortName ?? | ||
(projectDocument.resource.shortDescription | ||
&& projectDocument.resource.shortDescription.length <= MAX_LABEL_LENGTH | ||
? projectDocument.resource.shortDescription | ||
const shortDescription = getTranslation(projectDocument.resource.shortDescription); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. resource.shortDescription kann leer sein. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ich lasse getTranslation jetzt immer '' zurückgeben (siehe unten in |
||
const shortName = getTranslation(projectDocument.resource.shortName); | ||
|
||
return shortName ?? | ||
(shortDescription | ||
&& shortDescription.length <= MAX_LABEL_LENGTH | ||
? shortDescription | ||
: projectDocument.resource.identifier); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Das TODO kann raus, oder?