-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add utils for ranking and finding labels (#2)
- Loading branch information
1 parent
3552e49
commit 37e7773
Showing
5 changed files
with
192 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Changelog | ||
|
||
All notable changes to this project will be documented in this file. | ||
|
||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | ||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
|
||
## [Unreleased] | ||
|
||
### Added | ||
- Add utils for ranking and finding labels | ||
|
||
### Deprecated | ||
|
||
### Removed | ||
|
||
### Security |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export const PREF_LABEL = "prefLabel"; | ||
export const ALT_LABEL = "altLabel"; | ||
export const HIDDEN_LABEL = "hiddenLabel"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import { | ||
ALT_LABEL, | ||
HIDDEN_LABEL, | ||
PREF_LABEL, | ||
} from "@/arches_vue_utils/constants.ts"; | ||
import { getItemLabel, rankLabel } from "@/arches_vue_utils/utils.ts"; | ||
|
||
import type { Label } from "@/arches_vue_utils/types"; | ||
|
||
// Test utils | ||
function asLabel(valuetype_id: string, language_id: string): Label { | ||
return { | ||
value: "arbitrary", | ||
valuetype_id, | ||
language_id, | ||
}; | ||
} | ||
|
||
const systemLanguageCode = "en-ZA"; // arbitrary | ||
|
||
describe("rankLabel() util", () => { | ||
const rank = ( | ||
valuetype_id: string, | ||
labelLanguageCode: string, | ||
desiredLanguageCode: string, | ||
) => | ||
rankLabel( | ||
asLabel(valuetype_id, labelLanguageCode), | ||
desiredLanguageCode, | ||
systemLanguageCode, | ||
); | ||
|
||
// Test cases inspired from python module | ||
it("Prefers explicit region", () => { | ||
expect(rank(PREF_LABEL, "fr-CA", "fr-CA")).toBeGreaterThan( | ||
rank(PREF_LABEL, "fr", "fr-CA"), | ||
); | ||
}); | ||
it("Prefers pref over alt", () => { | ||
expect(rank(PREF_LABEL, "fr", "fr-CA")).toBeGreaterThan( | ||
rank(ALT_LABEL, "fr", "fr-CA"), | ||
); | ||
}); | ||
it("Prefers alt over hidden", () => { | ||
expect(rank(ALT_LABEL, "fr", "fr-CA")).toBeGreaterThan( | ||
rank(HIDDEN_LABEL, "fr", "fr-CA"), | ||
); | ||
}); | ||
it("Prefers alt label in system language to anything else", () => { | ||
expect(rank(ALT_LABEL, systemLanguageCode, "en")).toBeGreaterThan( | ||
rank(PREF_LABEL, "de", "en"), | ||
); | ||
}); | ||
it("Prefers region-insensitive match in system language", () => { | ||
expect(rank(PREF_LABEL, "en", "de")).toBeGreaterThan( | ||
rank(PREF_LABEL, "fr", "de"), | ||
); | ||
}); | ||
}); | ||
|
||
describe("getItemLabel() util", () => { | ||
it("Errors if no labels", () => { | ||
expect(() => | ||
getItemLabel( | ||
{ labels: [] }, | ||
systemLanguageCode, | ||
systemLanguageCode, | ||
), | ||
).toThrow(); | ||
expect(() => | ||
getItemLabel( | ||
{ values: [] }, | ||
systemLanguageCode, | ||
systemLanguageCode, | ||
), | ||
).toThrow(); | ||
}); | ||
it("Falls back to system language", () => { | ||
expect( | ||
getItemLabel( | ||
{ | ||
labels: [ | ||
asLabel(PREF_LABEL, "de"), | ||
asLabel(PREF_LABEL, systemLanguageCode), | ||
], | ||
}, | ||
"fr", | ||
systemLanguageCode, | ||
).language_id, | ||
).toEqual(systemLanguageCode); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { ALT_LABEL, PREF_LABEL } from "@/arches_vue_utils/constants.ts"; | ||
|
||
import type { | ||
Label, | ||
Labellable, | ||
WithLabels, | ||
WithValues, | ||
} from "@/arches_vue_utils/types"; | ||
|
||
/* Port of rank_label in arches.app.utils.i18n python module */ | ||
export const rankLabel = ( | ||
label: Label, | ||
preferredLanguageCode: string, | ||
systemLanguageCode: string, | ||
): number => { | ||
let rank = 1; | ||
if (label.valuetype_id === PREF_LABEL) { | ||
rank = 10; | ||
} else if (label.valuetype_id === ALT_LABEL) { | ||
rank = 4; | ||
} | ||
|
||
// Some arches deployments may not have standardized capitalizations. | ||
const labelLanguageFull = label.language_id.toLowerCase(); | ||
const labelLanguageNoRegion = label.language_id | ||
.split(/[-_]/)[0] | ||
.toLowerCase(); | ||
const preferredLanguageFull = preferredLanguageCode.toLowerCase(); | ||
const preferredLanguageNoRegion = preferredLanguageCode | ||
.split(/[-_]/)[0] | ||
.toLowerCase(); | ||
const systemLanguageFull = systemLanguageCode.toLowerCase(); | ||
const systemLanguageNoRegion = systemLanguageCode | ||
.split(/[-_]/)[0] | ||
.toLowerCase(); | ||
|
||
if (labelLanguageFull === preferredLanguageFull) { | ||
rank *= 10; | ||
} else if (labelLanguageNoRegion === preferredLanguageNoRegion) { | ||
rank *= 5; | ||
} else if (labelLanguageFull === systemLanguageFull) { | ||
rank *= 3; | ||
} else if (labelLanguageNoRegion === systemLanguageNoRegion) { | ||
rank *= 2; | ||
} | ||
|
||
return rank; | ||
}; | ||
|
||
export const getItemLabel = ( | ||
item: Labellable, | ||
preferredLanguageCode: string, | ||
systemLanguageCode: string, | ||
): Label => { | ||
const labels = (item as WithLabels).labels ?? (item as WithValues).values; | ||
if (!labels.length) { | ||
throw new Error(); | ||
} | ||
return labels.sort( | ||
(a, b) => | ||
rankLabel(b, preferredLanguageCode, systemLanguageCode) - | ||
rankLabel(a, preferredLanguageCode, systemLanguageCode), | ||
)[0]; | ||
}; |