@natlibfi/marc-record-validators-melinda 12.0.15 → 12.0.16-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fixRelatorTerms.js +2 -0
- package/dist/fixRelatorTerms.js.map +2 -2
- package/package.json +9 -12
- package/src/fixRelatorTerms.js +5 -0
- package/test-fixtures/fix-relator-terms/f02/metadata.json +1 -1
- package/test-fixtures/fix-relator-terms/f04/expectedResult.json +18 -0
- package/test-fixtures/fix-relator-terms/f04/metadata.json +5 -0
- package/test-fixtures/fix-relator-terms/f04/record.json +20 -0
- package/test-fixtures/merge-fields/f15/metadata.json +1 -1
- package/test-fixtures/merge-fields/f16/metadata.json +1 -1
- package/test-fixtures/remove-inferior-datafields/f20/metadata.json +1 -1
package/dist/fixRelatorTerms.js
CHANGED
|
@@ -43,6 +43,8 @@ const relatorTerms = [
|
|
|
43
43
|
{ "code": "drt", "eng": "director", "fin": "ohjaaja", "swe": "regiss\xF6r" },
|
|
44
44
|
{ "code": "edt", "eng": "editor", "fin": "toimittaja", "swe": "redakt\xF6r" },
|
|
45
45
|
{ "code": "ill", "eng": "illustrator", "fin": "kuvittaja", "swe": "illustrat\xF6r" },
|
|
46
|
+
{ "code": "ive", "eng": "interviewee", "fin": "haastateltava", "swe": "intervjuobjekt" },
|
|
47
|
+
{ "code": "ivr", "eng": "interviewer", "fin": "haastattelija", "swe": "intervjuare" },
|
|
46
48
|
{ "code": "lyr", "eng": "lyricist", "fin": "sanoittaja", "swe": "s\xE5ngtext" },
|
|
47
49
|
{ "code": "nrt", "eng": "narrator", "fin": "kertoja", "swe": "ber\xE4ttare" },
|
|
48
50
|
// berättare/inläsare
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/fixRelatorTerms.js"],
|
|
4
|
-
"sourcesContent": ["import clone from 'clone';\nimport {fieldFixPunctuation} from './punctuation2.js';\nimport {fieldToString, getCatalogingLanguage, nvdebug, subfieldToString} from './utils.js';\nimport createDebugLogger from 'debug';\n\n// Currently mainly translates X00$e values, so that we don't have \"$a Name, $e kirjoittaja, $e f\u00F6rfattare.\".\n// Later on we could try and handle $4 stuff here as well.\n\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:fixRelatorterms');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\nexport default function () {\n return {\n description: 'Fix $e subfields in field [1678][01]0 and 720',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n\n const language = getCatalogingLanguage(record);\n\n record.fields.forEach(field => {\n fieldFixRelatorTerms(field, language, language);\n });\n\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n const language = getCatalogingLanguage(record);\n\n record.fields.forEach(field => {\n const clonedField = clone(field);\n // Rather hackily/abnormally use language as both fromLanguage and toLanguage.\n // fromLanguage is used to expand \"esitt.\" => \"esitt\u00E4j\u00E4\".\n // toLanguage is used by translations (fixes \"f\u00F6rfattere\" to \"kirjoittaja\", if 040$b is \"fin\")\n fieldFixRelatorTerms(field, language, language);\n const clonedFieldAsString = fieldToString(clonedField);\n const fieldAsString = fieldToString(field);\n if (fieldAsString !== clonedFieldAsString) {\n res.message.push(`${fieldAsString} => ${clonedFieldAsString}`);\n }\n });\n\n res.valid = !(res.message.length >= 1);\n return res;\n }\n}\n\n\n/*\nexport default () => (base, source) => {\n recordTranslateRelatorTerms(base);\n recordTranslateRelatorTerms(source);\n recordHandleRelatorTermAbbreviations(base);\n recordHandleRelatorTermAbbreviations(source);\n const result = {base, source};\n return result;\n};\n*/\n\n\n// Partial source: https://marc21.kansalliskirjasto.fi/funktiot_koodit.htm\n// https://wiki.helsinki.fi/display/MARC21svenska/Funktions-+och+relationskoder+-+alfabetiskt+efter+funktion\n// New, better source: https://id.kb.se/find?q=relator&_sort=_sortKeyByLang.en\n\n\n// NB! How to handle German sex-based Verfasser/Verfasserin pairs?\nconst relatorTerms = [\n {'code': 'arr', 'eng': 'arranger', 'fin': 'sovittaja', 'swe': 'arrang\u00F6r av musikalisk komposition'},\n {'code': 'art', 'eng': 'artist', 'fin': 'taiteilija', 'swe': 'konstn\u00E4r'},\n {'code': 'aui', 'eng': 'author of introduction', 'fin': 'esipuheen tekij\u00E4'},\n {'code': 'aut', 'eng': 'author', 'fin': 'kirjoittaja', 'swe': 'f\u00F6rfattare'},\n {'code': 'cmp', 'eng': 'composer', 'fin': 's\u00E4velt\u00E4j\u00E4', 'swe': 'komposit\u00F6r'},\n {'code': 'drt', 'eng': 'director', 'fin': 'ohjaaja', 'swe': 'regiss\u00F6r'},\n {'code': 'edt', 'eng': 'editor', 'fin': 'toimittaja', 'swe': 'redakt\u00F6r'},\n {'code': 'ill', 'eng': 'illustrator', 'fin': 'kuvittaja', 'swe': 'illustrat\u00F6r'},\n {'code': 'lyr', 'eng': 'lyricist', 'fin': 'sanoittaja', 'swe': 's\u00E5ngtext'},\n {'code': 'nrt', 'eng': 'narrator', 'fin': 'kertoja', 'swe': 'ber\u00E4ttare'}, // ber\u00E4ttare/inl\u00E4sare\n {'code': 'pbl', 'eng': 'publisher', 'fin': 'julkaisija', 'swe': 'utgivare'},\n {'code': 'pht', 'eng': 'photographer', 'fin': 'valokuvaaja', 'swe': 'fotograf'},\n {'code': 'prf', 'eng': 'performer', 'fin': 'esitt\u00E4j\u00E4', 'swe': 'framf\u00F6rande'},\n {'code': 'pro', 'eng': 'producer', 'fin': 'tuottaja', 'swe': 'producent'},\n {'code': 'trl', 'eng': 'translator', 'fin': 'k\u00E4\u00E4nt\u00E4j\u00E4', 'swe': '\u00F6vers\u00E4ttare'},\n {'code': '__FAKE_VALUE1__', 'fin': 'sarjakuvantekij\u00E4', 'swe': 'serieskapare'}\n];\n\n/*\nfunction recordNormalizeRelatorTerms(record, defaultLanguageCode = undef) {\n const languageCode = defaultLanguageCode ? defaultLanguageCode : getCatalogingLanguage(record);\n if (!languageCode || ['eng', 'fin', 'swe'].includes(languageCode)) {\n return;\n }\n\n}\n*/\n\n\nconst finnishAbbreviations = {\n 'esitt.': 'esitt\u00E4j\u00E4',\n 'k\u00E4\u00E4nt.': 'k\u00E4\u00E4nt\u00E4j\u00E4',\n 'n\u00E4ytt.': 'n\u00E4yttelij\u00E4',\n 'san.': 'sanoittaja',\n 'sov.': 'sovittaja',\n 's\u00E4v.': 's\u00E4velt\u00E4j\u00E4',\n 'toim.': 'toimittaja',\n // Quick and dirty implementation of https://github.com/NatLibFi/USEMARCON-BOOKWHERE-RDA/blob/master/bw_rda_kyril.rul#L651\n // As per M.I./Slavica\n '\u0445\u0443\u0434\u043E\u0436.': 'kuvittaja',\n '\u043F\u0435\u0440.': 'k\u00E4\u00E4nt\u00E4j\u00E4',\n '\u0441\u043E\u0441\u0442.': 'toimittaja', // might also be 'kokoaja'\n '\u0440\u0435\u0434.': 'toimittaja'\n};\n\nfunction subfieldHandleRelatorTermAbbreviation(subfield, language) {\n if (subfield.code !== 'e') {\n return;\n }\n nvdebug(`Relator cand subfield: '${subfieldToString(subfield)}', lang: ${language ? language : 'NULL'}`, debugDev);\n if (!language || language === 'mul') {\n subfieldHandleRelatorTermAbbreviation(subfield, 'fin');\n // Maybe later add Swedish here...\n return;\n }\n const value = subfield.value.replace(/,$/u, '');\n const punc = value === subfield.value ? '' : ',';\n\n const lcValue = value.toLowerCase(); // Check \u00C5, \u00C4, \u00D6...\n\n // NB: Policy: if no language or multi-language: apply all rules! (Not much overlap I hope...)\n if (!language || language === 'fin' || language === 'mul') {\n nvdebug(`Relator try Finnish for '${lcValue}}'...`, debugDev);\n if (lcValue in finnishAbbreviations) {\n const hit = `${finnishAbbreviations[lcValue]}${punc}`;\n nvdebug(`Relator hit: ${hit}`, debugDev);\n // NB! 'esitt.' => 'esitt\u00E4j\u00E4'\n subfield.value = hit;\n return;\n }\n }\n}\n\n\nfunction isRelatorField(field) {\n // Tag list might be incomplete!\n return field.tag.match(/^(?:100|110|600|610|700|710|720|800|810)$/u);\n}\n\nfunction fieldHandleRelatorTermAbbreviations(field, language) {\n if (!isRelatorField(field)) {\n return;\n }\n\n const originalValue = fieldToString(field);\n field.subfields.forEach(sf => subfieldHandleRelatorTermAbbreviation(sf, language));\n const modifiedValue = fieldToString(field);\n if (modifiedValue === originalValue) {\n return;\n }\n // Changes have happened... Try to punctuate.\n // (NB! We need punctuation as a module, if we are to make abbr expansion a marc-record-validators-melinda validator/fixer)\n fieldFixPunctuation(field);\n}\n\nfunction termIsInGivenLanguage(term, language) {\n return relatorTerms.some(row => language in row && row[language] === term);\n}\n\nfunction anyToLanguage(originalTerm) {\n // Sometimes there's no 040$b or 040$b and, say, 040$b and 700$e value don't correlate\n if (termIsInGivenLanguage(originalTerm, 'fin')) {\n return 'fin';\n }\n if (termIsInGivenLanguage(originalTerm, 'swe')) {\n return 'swe';\n }\n if (termIsInGivenLanguage(originalTerm, 'eng')) {\n return 'eng';\n }\n return null;\n}\n\nfunction translateRelatorTerm(originalTerm, defaultFromLanguage, toLanguage) {\n\n // originalTerm is supposed to be normal version (abbrs have been expanded), possibly with punctuation\n const term = originalTerm.replace(/[,.]$/u, '');\n nvdebug(`Try to translate '${term}' from ${defaultFromLanguage} to ${toLanguage}`, debugDev);\n\n // Kind of hacky... If term is in toLanguage, do nothing. defaultFromLanguage (040$b) isn't that reliable.\n if (termIsInGivenLanguage(term, toLanguage)) {\n return originalTerm;\n }\n // defaultFomLanguage (typically 040$b) isn't that reliable:\n const fromLanguage = defaultFromLanguage === null || !termIsInGivenLanguage(term, defaultFromLanguage) ? anyToLanguage(term) : defaultFromLanguage;\n\n const [candRow] = relatorTerms.filter(row => fromLanguage in row && toLanguage in row && row[fromLanguage] === term);\n if (candRow) {\n const punc = term === originalTerm ? '' : originalTerm.slice(-1);\n const translation = `${candRow[toLanguage]}${punc}`;\n nvdebug(`Translate relator term: ${originalTerm} => ${translation}`, debugDev);\n return translation;\n }\n return originalTerm;\n}\n\nfunction subfieldTranslateRelatorTerm(subfield, fromLanguage, toLanguage) {\n if (subfield.code !== 'e') {\n return;\n }\n subfield.value = translateRelatorTerm(subfield.value, fromLanguage, toLanguage);\n}\n\nexport function fieldFixRelatorTerms(field, fromLanguage, toLanguage) {\n // fromLanguage can not be relied upon.\n if (!isRelatorField(field)/* || fromLanguage === toLanguage*/) {\n return;\n }\n fieldHandleRelatorTermAbbreviations(field, fromLanguage);\n\n field.subfields.forEach(sf => subfieldTranslateRelatorTerm(sf, fromLanguage, toLanguage));\n}\n\n\nexport function recordFixRelatorTerms(record, defaultToLanguage = null, defaultFromLanguage = null) { // WAS: translateRecord()\n const fromLanguage = defaultFromLanguage ? defaultFromLanguage : getCatalogingLanguage(record);\n const toLanguage = defaultToLanguage ? defaultToLanguage : getCatalogingLanguage(record);\n\n record.fields.forEach(field => translateField(field, fromLanguage, toLanguage));\n\n function translateField(field, from, to) {\n fieldFixRelatorTerms(field, from, to);\n }\n}\n\n\n"],
|
|
5
|
-
"mappings": "AAAA,OAAO,WAAW;AAClB,SAAQ,2BAA0B;AAClC,SAAQ,eAAe,uBAAuB,SAAS,wBAAuB;AAC9E,OAAO,uBAAuB;AAM9B,MAAM,QAAQ,kBAAkB,0DAA0D;AAE1F,MAAM,WAAW,MAAM,OAAO,KAAK;AAEnC,0BAA2B;AACzB,SAAO;AAAA,IACL,aAAa;AAAA,IACb;AAAA,IAAU;AAAA,EACZ;AAEA,WAAS,IAAI,QAAQ;AACnB,UAAM,MAAM,EAAC,SAAS,CAAC,GAAG,KAAK,CAAC,GAAG,OAAO,KAAI;AAE9C,UAAM,WAAW,sBAAsB,MAAM;AAE7C,WAAO,OAAO,QAAQ,WAAS;AAC7B,2BAAqB,OAAO,UAAU,QAAQ;AAAA,IAChD,CAAC;AAED,WAAO;AAAA,EACT;AAEA,WAAS,SAAS,QAAQ;AACxB,UAAM,MAAM,EAAC,SAAS,CAAC,EAAC;AAExB,UAAM,WAAW,sBAAsB,MAAM;AAE7C,WAAO,OAAO,QAAQ,WAAS;AAC7B,YAAM,cAAc,MAAM,KAAK;AAI/B,2BAAqB,OAAO,UAAU,QAAQ;AAC9C,YAAM,sBAAsB,cAAc,WAAW;AACrD,YAAM,gBAAgB,cAAc,KAAK;AACzC,UAAI,kBAAkB,qBAAqB;AACzC,YAAI,QAAQ,KAAK,GAAG,aAAa,OAAO,mBAAmB,EAAE;AAAA,MAC/D;AAAA,IACF,CAAC;AAED,QAAI,QAAQ,EAAE,IAAI,QAAQ,UAAU;AACpC,WAAO;AAAA,EACT;AACF;
|
|
4
|
+
"sourcesContent": ["import clone from 'clone';\nimport {fieldFixPunctuation} from './punctuation2.js';\nimport {fieldToString, getCatalogingLanguage, nvdebug, subfieldToString} from './utils.js';\nimport createDebugLogger from 'debug';\n\n// Currently mainly translates X00$e values, so that we don't have \"$a Name, $e kirjoittaja, $e f\u00F6rfattare.\".\n// Later on we could try and handle $4 stuff here as well.\n\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:fixRelatorterms');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\nexport default function () {\n return {\n description: 'Fix $e subfields in field [1678][01]0 and 720',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n\n const language = getCatalogingLanguage(record);\n\n record.fields.forEach(field => {\n fieldFixRelatorTerms(field, language, language);\n });\n\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n const language = getCatalogingLanguage(record);\n\n record.fields.forEach(field => {\n const clonedField = clone(field);\n // Rather hackily/abnormally use language as both fromLanguage and toLanguage.\n // fromLanguage is used to expand \"esitt.\" => \"esitt\u00E4j\u00E4\".\n // toLanguage is used by translations (fixes \"f\u00F6rfattere\" to \"kirjoittaja\", if 040$b is \"fin\")\n fieldFixRelatorTerms(field, language, language);\n const clonedFieldAsString = fieldToString(clonedField);\n const fieldAsString = fieldToString(field);\n if (fieldAsString !== clonedFieldAsString) {\n res.message.push(`${fieldAsString} => ${clonedFieldAsString}`);\n }\n });\n\n res.valid = !(res.message.length >= 1);\n return res;\n }\n}\n\n\n/*\nexport default () => (base, source) => {\n recordTranslateRelatorTerms(base);\n recordTranslateRelatorTerms(source);\n recordHandleRelatorTermAbbreviations(base);\n recordHandleRelatorTermAbbreviations(source);\n const result = {base, source};\n return result;\n};\n*/\n\n\n// Partial source: https://marc21.kansalliskirjasto.fi/funktiot_koodit.htm\n// https://wiki.helsinki.fi/display/MARC21svenska/Funktions-+och+relationskoder+-+alfabetiskt+efter+funktion\n// New, better source: https://id.kb.se/find?q=relator&_sort=_sortKeyByLang.en\n\n// NOTE: There are problematic relatorterms that do not diffrentiate between agent+work vs agent+ekspression relation\n// ie. teoksen haastattelija vs haastattelija (ekspressio)\n// current solution ignores them and handles just \"plain\" relator terms\n\n// NB! How to handle German sex-based Verfasser/Verfasserin pairs?\nconst relatorTerms = [\n {'code': 'arr', 'eng': 'arranger', 'fin': 'sovittaja', 'swe': 'arrang\u00F6r av musikalisk komposition'},\n {'code': 'art', 'eng': 'artist', 'fin': 'taiteilija', 'swe': 'konstn\u00E4r'},\n {'code': 'aui', 'eng': 'author of introduction', 'fin': 'esipuheen tekij\u00E4'},\n {'code': 'aut', 'eng': 'author', 'fin': 'kirjoittaja', 'swe': 'f\u00F6rfattare'},\n {'code': 'cmp', 'eng': 'composer', 'fin': 's\u00E4velt\u00E4j\u00E4', 'swe': 'komposit\u00F6r'},\n {'code': 'drt', 'eng': 'director', 'fin': 'ohjaaja', 'swe': 'regiss\u00F6r'},\n {'code': 'edt', 'eng': 'editor', 'fin': 'toimittaja', 'swe': 'redakt\u00F6r'},\n {'code': 'ill', 'eng': 'illustrator', 'fin': 'kuvittaja', 'swe': 'illustrat\u00F6r'},\n {'code': 'ive', 'eng': 'interviewee', 'fin': 'haastateltava', 'swe': 'intervjuobjekt'},\n {'code': 'ivr', 'eng': 'interviewer', 'fin': 'haastattelija', 'swe': 'intervjuare'},\n {'code': 'lyr', 'eng': 'lyricist', 'fin': 'sanoittaja', 'swe': 's\u00E5ngtext'},\n {'code': 'nrt', 'eng': 'narrator', 'fin': 'kertoja', 'swe': 'ber\u00E4ttare'}, // ber\u00E4ttare/inl\u00E4sare\n {'code': 'pbl', 'eng': 'publisher', 'fin': 'julkaisija', 'swe': 'utgivare'},\n {'code': 'pht', 'eng': 'photographer', 'fin': 'valokuvaaja', 'swe': 'fotograf'},\n {'code': 'prf', 'eng': 'performer', 'fin': 'esitt\u00E4j\u00E4', 'swe': 'framf\u00F6rande'},\n {'code': 'pro', 'eng': 'producer', 'fin': 'tuottaja', 'swe': 'producent'},\n {'code': 'trl', 'eng': 'translator', 'fin': 'k\u00E4\u00E4nt\u00E4j\u00E4', 'swe': '\u00F6vers\u00E4ttare'},\n {'code': '__FAKE_VALUE1__', 'fin': 'sarjakuvantekij\u00E4', 'swe': 'serieskapare'}\n];\n\n/*\nfunction recordNormalizeRelatorTerms(record, defaultLanguageCode = undef) {\n const languageCode = defaultLanguageCode ? defaultLanguageCode : getCatalogingLanguage(record);\n if (!languageCode || ['eng', 'fin', 'swe'].includes(languageCode)) {\n return;\n }\n\n}\n*/\n\n\nconst finnishAbbreviations = {\n 'esitt.': 'esitt\u00E4j\u00E4',\n 'k\u00E4\u00E4nt.': 'k\u00E4\u00E4nt\u00E4j\u00E4',\n 'n\u00E4ytt.': 'n\u00E4yttelij\u00E4',\n 'san.': 'sanoittaja',\n 'sov.': 'sovittaja',\n 's\u00E4v.': 's\u00E4velt\u00E4j\u00E4',\n 'toim.': 'toimittaja',\n // Quick and dirty implementation of https://github.com/NatLibFi/USEMARCON-BOOKWHERE-RDA/blob/master/bw_rda_kyril.rul#L651\n // As per M.I./Slavica\n '\u0445\u0443\u0434\u043E\u0436.': 'kuvittaja',\n '\u043F\u0435\u0440.': 'k\u00E4\u00E4nt\u00E4j\u00E4',\n '\u0441\u043E\u0441\u0442.': 'toimittaja', // might also be 'kokoaja'\n '\u0440\u0435\u0434.': 'toimittaja'\n};\n\nfunction subfieldHandleRelatorTermAbbreviation(subfield, language) {\n if (subfield.code !== 'e') {\n return;\n }\n nvdebug(`Relator cand subfield: '${subfieldToString(subfield)}', lang: ${language ? language : 'NULL'}`, debugDev);\n if (!language || language === 'mul') {\n subfieldHandleRelatorTermAbbreviation(subfield, 'fin');\n // Maybe later add Swedish here...\n return;\n }\n const value = subfield.value.replace(/,$/u, '');\n const punc = value === subfield.value ? '' : ',';\n\n const lcValue = value.toLowerCase(); // Check \u00C5, \u00C4, \u00D6...\n\n // NB: Policy: if no language or multi-language: apply all rules! (Not much overlap I hope...)\n if (!language || language === 'fin' || language === 'mul') {\n nvdebug(`Relator try Finnish for '${lcValue}}'...`, debugDev);\n if (lcValue in finnishAbbreviations) {\n const hit = `${finnishAbbreviations[lcValue]}${punc}`;\n nvdebug(`Relator hit: ${hit}`, debugDev);\n // NB! 'esitt.' => 'esitt\u00E4j\u00E4'\n subfield.value = hit;\n return;\n }\n }\n}\n\n\nfunction isRelatorField(field) {\n // Tag list might be incomplete!\n return field.tag.match(/^(?:100|110|600|610|700|710|720|800|810)$/u);\n}\n\nfunction fieldHandleRelatorTermAbbreviations(field, language) {\n if (!isRelatorField(field)) {\n return;\n }\n\n const originalValue = fieldToString(field);\n field.subfields.forEach(sf => subfieldHandleRelatorTermAbbreviation(sf, language));\n const modifiedValue = fieldToString(field);\n if (modifiedValue === originalValue) {\n return;\n }\n // Changes have happened... Try to punctuate.\n // (NB! We need punctuation as a module, if we are to make abbr expansion a marc-record-validators-melinda validator/fixer)\n fieldFixPunctuation(field);\n}\n\nfunction termIsInGivenLanguage(term, language) {\n return relatorTerms.some(row => language in row && row[language] === term);\n}\n\nfunction anyToLanguage(originalTerm) {\n // Sometimes there's no 040$b or 040$b and, say, 040$b and 700$e value don't correlate\n if (termIsInGivenLanguage(originalTerm, 'fin')) {\n return 'fin';\n }\n if (termIsInGivenLanguage(originalTerm, 'swe')) {\n return 'swe';\n }\n if (termIsInGivenLanguage(originalTerm, 'eng')) {\n return 'eng';\n }\n return null;\n}\n\nfunction translateRelatorTerm(originalTerm, defaultFromLanguage, toLanguage) {\n\n // originalTerm is supposed to be normal version (abbrs have been expanded), possibly with punctuation\n const term = originalTerm.replace(/[,.]$/u, '');\n nvdebug(`Try to translate '${term}' from ${defaultFromLanguage} to ${toLanguage}`, debugDev);\n\n // Kind of hacky... If term is in toLanguage, do nothing. defaultFromLanguage (040$b) isn't that reliable.\n if (termIsInGivenLanguage(term, toLanguage)) {\n return originalTerm;\n }\n // defaultFomLanguage (typically 040$b) isn't that reliable:\n const fromLanguage = defaultFromLanguage === null || !termIsInGivenLanguage(term, defaultFromLanguage) ? anyToLanguage(term) : defaultFromLanguage;\n\n const [candRow] = relatorTerms.filter(row => fromLanguage in row && toLanguage in row && row[fromLanguage] === term);\n if (candRow) {\n const punc = term === originalTerm ? '' : originalTerm.slice(-1);\n const translation = `${candRow[toLanguage]}${punc}`;\n nvdebug(`Translate relator term: ${originalTerm} => ${translation}`, debugDev);\n return translation;\n }\n return originalTerm;\n}\n\nfunction subfieldTranslateRelatorTerm(subfield, fromLanguage, toLanguage) {\n if (subfield.code !== 'e') {\n return;\n }\n subfield.value = translateRelatorTerm(subfield.value, fromLanguage, toLanguage);\n}\n\nexport function fieldFixRelatorTerms(field, fromLanguage, toLanguage) {\n // fromLanguage can not be relied upon.\n if (!isRelatorField(field)/* || fromLanguage === toLanguage*/) {\n return;\n }\n fieldHandleRelatorTermAbbreviations(field, fromLanguage);\n\n field.subfields.forEach(sf => subfieldTranslateRelatorTerm(sf, fromLanguage, toLanguage));\n}\n\n\nexport function recordFixRelatorTerms(record, defaultToLanguage = null, defaultFromLanguage = null) { // WAS: translateRecord()\n const fromLanguage = defaultFromLanguage ? defaultFromLanguage : getCatalogingLanguage(record);\n const toLanguage = defaultToLanguage ? defaultToLanguage : getCatalogingLanguage(record);\n\n record.fields.forEach(field => translateField(field, fromLanguage, toLanguage));\n\n function translateField(field, from, to) {\n fieldFixRelatorTerms(field, from, to);\n }\n}\n\n\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"url": "https://github.com/NatLibFi/marc-record-validators-melinda"
|
|
15
15
|
},
|
|
16
16
|
"license": "MIT",
|
|
17
|
-
"version": "12.0.
|
|
17
|
+
"version": "12.0.16-alpha.1",
|
|
18
18
|
"main": "./dist/index.js",
|
|
19
19
|
"publishConfig": {
|
|
20
20
|
"access": "public"
|
|
@@ -35,30 +35,27 @@
|
|
|
35
35
|
"dev:debug": "cross-env LOG_LEVEL=debug DEBUG=@natlibfi/* NODE_ENV=test"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@natlibfi/iso9-1995": "^1.1.
|
|
39
|
-
"@natlibfi/issn-verify": "^2.0.
|
|
40
|
-
"@natlibfi/marc-record": "^10.0.
|
|
41
|
-
"@natlibfi/marc-record-serializers": "^11.0.
|
|
42
|
-
"@natlibfi/marc-record-validate": "^9.0.
|
|
38
|
+
"@natlibfi/iso9-1995": "^1.1.4",
|
|
39
|
+
"@natlibfi/issn-verify": "^2.0.3",
|
|
40
|
+
"@natlibfi/marc-record": "^10.0.2",
|
|
41
|
+
"@natlibfi/marc-record-serializers": "^11.0.3",
|
|
42
|
+
"@natlibfi/marc-record-validate": "^9.0.1",
|
|
43
43
|
"@natlibfi/melinda-commons": "^14.0.2",
|
|
44
44
|
"@natlibfi/sfs-4900": "^2.0.0",
|
|
45
|
-
"@natlibfi/sru-client": "^7.0.
|
|
45
|
+
"@natlibfi/sru-client": "^7.0.2",
|
|
46
46
|
"clone": "^2.1.2",
|
|
47
47
|
"debug": "^4.4.3",
|
|
48
48
|
"franc": "^6.2.0",
|
|
49
|
-
"isbn3": "^2.0.
|
|
49
|
+
"isbn3": "^2.0.9",
|
|
50
50
|
"xml2js": "^0.6.2",
|
|
51
51
|
"xregexp": "^5.1.2"
|
|
52
52
|
},
|
|
53
|
-
"peerDependencies": {
|
|
54
|
-
"@natlibfi/marc-record-validate": "^9.0.0"
|
|
55
|
-
},
|
|
56
53
|
"devDependencies": {
|
|
57
54
|
"@natlibfi/fixugen": "^3.0.1",
|
|
58
55
|
"@natlibfi/fixura": "^4.0.1",
|
|
59
56
|
"cross-env": "^10.1.0",
|
|
60
57
|
"esbuild": "^0.28.0",
|
|
61
|
-
"eslint": "^10.
|
|
58
|
+
"eslint": "^10.7.0",
|
|
62
59
|
"fetch-mock": "^12.6.0"
|
|
63
60
|
}
|
|
64
61
|
}
|
package/src/fixRelatorTerms.js
CHANGED
|
@@ -69,6 +69,9 @@ export default () => (base, source) => {
|
|
|
69
69
|
// https://wiki.helsinki.fi/display/MARC21svenska/Funktions-+och+relationskoder+-+alfabetiskt+efter+funktion
|
|
70
70
|
// New, better source: https://id.kb.se/find?q=relator&_sort=_sortKeyByLang.en
|
|
71
71
|
|
|
72
|
+
// NOTE: There are problematic relatorterms that do not diffrentiate between agent+work vs agent+ekspression relation
|
|
73
|
+
// ie. teoksen haastattelija vs haastattelija (ekspressio)
|
|
74
|
+
// current solution ignores them and handles just "plain" relator terms
|
|
72
75
|
|
|
73
76
|
// NB! How to handle German sex-based Verfasser/Verfasserin pairs?
|
|
74
77
|
const relatorTerms = [
|
|
@@ -80,6 +83,8 @@ const relatorTerms = [
|
|
|
80
83
|
{'code': 'drt', 'eng': 'director', 'fin': 'ohjaaja', 'swe': 'regissör'},
|
|
81
84
|
{'code': 'edt', 'eng': 'editor', 'fin': 'toimittaja', 'swe': 'redaktör'},
|
|
82
85
|
{'code': 'ill', 'eng': 'illustrator', 'fin': 'kuvittaja', 'swe': 'illustratör'},
|
|
86
|
+
{'code': 'ive', 'eng': 'interviewee', 'fin': 'haastateltava', 'swe': 'intervjuobjekt'},
|
|
87
|
+
{'code': 'ivr', 'eng': 'interviewer', 'fin': 'haastattelija', 'swe': 'intervjuare'},
|
|
83
88
|
{'code': 'lyr', 'eng': 'lyricist', 'fin': 'sanoittaja', 'swe': 'sångtext'},
|
|
84
89
|
{'code': 'nrt', 'eng': 'narrator', 'fin': 'kertoja', 'swe': 'berättare'}, // berättare/inläsare
|
|
85
90
|
{'code': 'pbl', 'eng': 'publisher', 'fin': 'julkaisija', 'swe': 'utgivare'},
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_validationOptions": {},
|
|
3
|
+
"leader": "01331cam a22003494i 4500",
|
|
4
|
+
"fields": [
|
|
5
|
+
{ "tag": "040", "ind1": " ", "ind2": " ", "subfields": [ { "code": "b", "value": "fin" } ] },
|
|
6
|
+
{ "tag": "700", "ind1": " ", "ind2": " ",
|
|
7
|
+
"subfields": [
|
|
8
|
+
{ "code": "a", "value": "Nimi," },
|
|
9
|
+
{ "code": "e", "value": "kirjoittaja,"},
|
|
10
|
+
{ "code": "e", "value": "haastattelija."}
|
|
11
|
+
] },
|
|
12
|
+
{ "tag": "700", "ind1": " ", "ind2": " ",
|
|
13
|
+
"subfields": [
|
|
14
|
+
{ "code": "a", "value": "Nimi2," },
|
|
15
|
+
{ "code": "e", "value": "haastateltava."}
|
|
16
|
+
]}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"leader": "01331cam a22003494i 4500",
|
|
3
|
+
"fields": [
|
|
4
|
+
{ "tag": "040", "ind1": " ", "ind2": " ", "subfields": [ { "code": "b", "value": "fin" } ] },
|
|
5
|
+
{ "tag": "700", "ind1": " ", "ind2": " ",
|
|
6
|
+
"subfields": [
|
|
7
|
+
{ "code": "a", "value": "Nimi," },
|
|
8
|
+
{ "code": "e", "value": "författare,"},
|
|
9
|
+
{ "code": "e", "value": "intervjuare."}
|
|
10
|
+
] },
|
|
11
|
+
{ "tag": "700", "ind1": " ", "ind2": " ",
|
|
12
|
+
"subfields": [
|
|
13
|
+
{ "code": "a", "value": "Nimi2," },
|
|
14
|
+
{ "code": "e", "value": "intervjuobjekt."}
|
|
15
|
+
] }
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
]
|
|
20
|
+
}
|