Skip to content

Commit

Permalink
Add utils for ranking and finding labels
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobtylerwalls committed Sep 12, 2024
1 parent f93f0c0 commit eae5b95
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 1 deletion.
17 changes: 17 additions & 0 deletions CHANGELOG.md
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
3 changes: 3 additions & 0 deletions arches_vue_utils/src/arches_vue_utils/constants.ts
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";
1 change: 0 additions & 1 deletion arches_vue_utils/src/arches_vue_utils/declarations.test.ts

This file was deleted.

18 changes: 18 additions & 0 deletions arches_vue_utils/src/arches_vue_utils/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export interface Language {
code: string;
default_direction: "ltr" | "rtl";
id: number;
isdefault: boolean;
name: string;
scope: string;
}

export interface Label {
value: string;
languageCode: string;
valuetype: "prefLabel" | "altLabel" | "hiddenLabel";
}

export interface Labellable {
labels: Label[];
}
88 changes: 88 additions & 0 deletions arches_vue_utils/src/arches_vue_utils/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
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
const asLabel = (
valuetype: "prefLabel" | "altLabel" | "hiddenLabel",
languageCode: string,
): Label => {
return {
value: "arbitrary",
valuetype,
languageCode,
};
};

const systemLanguageCode = "en-ZA"; // arbitrary

describe("rankLabel() util", () => {
const rank = (
valuetype: "prefLabel" | "altLabel" | "hiddenLabel",
labelLanguageCode: string,
desiredLanguageCode: string,
) =>
rankLabel(
asLabel(valuetype, 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();
});
it("Falls back to system language", () => {
expect(
getItemLabel(
{
labels: [
asLabel(PREF_LABEL, "de"),
asLabel(PREF_LABEL, systemLanguageCode),
],
},
"fr",
systemLanguageCode,
).languageCode,
).toEqual(systemLanguageCode);
});
});
58 changes: 58 additions & 0 deletions arches_vue_utils/src/arches_vue_utils/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { ALT_LABEL, PREF_LABEL } from "@/arches_vue_utils/constants.ts";

import type { Label, Labellable } 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 === PREF_LABEL) {
rank = 10;
} else if (label.valuetype === ALT_LABEL) {
rank = 4;
}

// Some arches deployments may not have standardized capitalizations.
const labelLanguageFull = label.languageCode.toLowerCase();
const labelLanguageNoRegion = label.languageCode
.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 => {
if (!item.labels.length) {
throw new Error();
}
return item.labels.sort(
(a, b) =>
rankLabel(b, preferredLanguageCode, systemLanguageCode) -
rankLabel(a, preferredLanguageCode, systemLanguageCode),
)[0];
};

0 comments on commit eae5b95

Please sign in to comment.