From 758d2d719f7499bc639b0ab613db8f05dc8b2ee1 Mon Sep 17 00:00:00 2001 From: skip405 Date: Wed, 5 Apr 2023 23:03:56 +0300 Subject: [PATCH] v2.0.0 --- CHANGELOG.md | 22 ++++++ README.md | 19 ++--- index.js | 206 ++++++++++++++++----------------------------------- package.json | 13 ++-- test.js | 153 +++++++++++++++----------------------- 5 files changed, 153 insertions(+), 260 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a1bff44 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,22 @@ +# Changelog + +## v2.0.0 - 2023-04-05 + +### Changed + +- **Breaking:** `geographical` option changed into `geo-2000` +- Bump `jest` to v29.5.0 +- Internal data structure + +### Added + +- `geo-2023` style option + +### Removed + +- **Breaking:** `slugify` style option and @sindresorhus/slugify dependency +- **Breaking:** `geographical` style option. Use `geo-2000` instead + +## v1.0.0 - 2022-12-30 + +Initial version. \ No newline at end of file diff --git a/README.md b/README.md index 42ad0bd..5bb5fd5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # belLat -Convert cyrillic Belarusian characters to Latin characters using transliteration. Can transliterate in accordance with the ["Instruction on transliteration of geographical names"](https://en.wikipedia.org/wiki/Instruction_on_transliteration_of_Belarusian_geographical_names_with_letters_of_Latin_script) or in accordance with the rules of the [Belarusian Latin alphabet (Łacinka)](https://en.wikipedia.org/wiki/Belarusian_Latin_alphabet). Can slugify the resulted transliterated string. +Convert cyrillic Belarusian characters to Latin characters using transliteration. Can transliterate in accordance with the ["Instruction on transliteration of geographical names"](https://en.wikipedia.org/wiki/Instruction_on_transliteration_of_Belarusian_geographical_names_with_letters_of_Latin_script) (2000 and 2023) or in accordance with the rules of the [Belarusian Latin alphabet (Łacinka)](https://en.wikipedia.org/wiki/Belarusian_Latin_alphabet). ## Installation @@ -28,22 +28,13 @@ belLat('Лацінка', { style: 'lacinka' }); // Łacinka ## Instruction for geographical names -You can specify conversion in accordance with the instruction for geographical names, e.g. +You can specify conversion in accordance with the instructions for geographical names (2000 and 2023), e.g. ```javascript import belLat from '@skip405/bel-lat'; -belLat('Лацінка', { style: 'geographical' }); // Lacinka -``` - -## Creating slugs - -The package uses the wonderful [@sindresorhus/slugify](https://github.com/sindresorhus/slugify) package to create slugified strings after conversion. - -```javascript -import belLat from '@skip405/bel-lat'; - -belLat("прывітанне, сусвет", { style: 'slugify' }); // pryvitannie-susviet +belLat('Шчучыншчына', { style: 'geo-2000' }); // Ščučynščyna +belLat('Шчучыншчына', { style: 'geo-2023' }); // Shchuchynshchyna ``` ## Basic replacements @@ -54,7 +45,7 @@ The package allows to specify own replacement symbols. import belLat from '@skip405/bel-lat'; belLat("№", { - customReplacements: [ ['№', { regular: '#' }] ] + customReplacements: [ ['№', ['#']] ] }); // # ``` diff --git a/index.js b/index.js index 07de0f3..88625e3 100644 --- a/index.js +++ b/index.js @@ -1,29 +1,27 @@ -import slugify from '@sindresorhus/slugify'; - const processSpecialCase = (char, nextChar, prevChar, style, replacement) => { - let variant = 'regular'; + let index = 0; switch( char.toLowerCase() ) { case 'ў' : - variant = 'with-breve'; + index = 1; - if( 'slugify' === style ) { - variant = 'regular'; + if( 'geo-2023' === style ) { + index = 2; } break; case 'л' : - if( 'geographic' === style ) { + if( 'geo-2000' === style ) { if( ['ь'].includes(nextChar.toLowerCase()) ) { - variant = 'with-acute'; + index = 2; } else { - variant = 'regular'; + index = 0; } } else if( 'lacinka' === style ) { if( ['е', 'ё', 'ю', 'я', 'ь'].includes(nextChar.toLowerCase()) ) { - variant = 'regular'; + index = 0; } else { - variant = 'with-stroke'; + index = 1; } } @@ -32,10 +30,8 @@ const processSpecialCase = (char, nextChar, prevChar, style, replacement) => { case 'ё' : case 'ю' : case 'я' : - variant = 'with-i'; - if( ['а', 'і', 'о', 'у', 'ы', 'ў', 'э', 'ь', '’', '‘'].includes(prevChar.toLowerCase()) || '' === prevChar ) { - variant = 'with-j'; + index = 1; } break; @@ -44,26 +40,26 @@ const processSpecialCase = (char, nextChar, prevChar, style, replacement) => { case 'с' : case 'ц' : if( ['ь'].includes(nextChar.toLowerCase()) ) { - variant = 'with-acute'; + index = 1; } - if( 'slugify' === style ) { - variant = 'regular'; + if( 'geo-2023' === style ) { + index = 0; } break; case 'ж' : case 'ч' : case 'ш' : - variant = 'with-caron'; + index = 1; - if( 'slugify' === style ) { - variant = 'regular'; + if( 'geo-2023' === style ) { + index = 2; } break; } - return processReturnValue(replacement[variant], char, nextChar, style); + return processReturnValue(replacement[index], char, nextChar, style); } const processChar = (char, nextChar, prevChar, style, replacement) => { @@ -77,20 +73,22 @@ const processChar = (char, nextChar, prevChar, style, replacement) => { return processSpecialCase(char, nextChar, prevChar, style, replacement); } - return processReturnValue(replacement.regular, char, nextChar, style); + let replacementValue = replacement[0]; + + if( 'geo-2023' === style && replacement[1] ) { + replacementValue = replacement[1]; + } + + return processReturnValue(replacementValue, char, nextChar, style); } const processReturnValue = (value, char, nextChar, style) => { - if( 'slugify' === style ) { - return value.toLowerCase(); - } else { - if( char === char.toUpperCase() && char !== char.toLowerCase() ) { - if( '' !== nextChar && nextChar === nextChar.toUpperCase() ) { - return value.toUpperCase(); - } - - return `${value[0].toUpperCase()}${value.slice(1)}`; + if( char === char.toUpperCase() && char !== char.toLowerCase() ) { + if( '' !== nextChar && nextChar === nextChar.toUpperCase() ) { + return value.toUpperCase(); } + + return `${value[0].toUpperCase()}${value.slice(1)}`; } return value; @@ -108,123 +106,45 @@ export default function belLat(string, options) { }; const replacements = new Map([ - ['а', { - 'regular': 'a', - }], - ['б', { - 'regular': 'b', - }], - ['в', { - 'regular': 'v', - }], - ['г', { - 'regular': 'h', - }], - ['ґ', { - 'regular': 'g', - }], - ['д', { - 'regular': 'd', - }], - ['е', { - 'with-i': 'ie', - 'with-j': 'je', - }], - ['ё', { - 'with-i': 'io', - 'with-j': 'jo', - }], - ['ж', { - 'regular': 'z', - 'with-caron': 'ž', - }], - ['з', { - 'regular': 'z', - 'with-acute': 'ź', - }], - ['і', { - 'regular': 'i', - }], - ['й', { - 'regular': 'j', - }], - ['к', { - 'regular': 'k', - }], - ['л', { - 'regular': 'l', - 'with-stroke': 'ł', - 'with-acute': 'ĺ', - }], - ['м', { - 'regular': 'm', - }], - ['н', { - 'regular': 'n', - 'with-acute': 'ń', - }], - ['о', { - 'regular': 'o', - }], - ['п', { - 'regular': 'p', - }], - ['р', { - 'regular': 'r', - }], - ['с', { - 'regular': 's', - 'with-acute': 'ś', - }], - ['т', { - 'regular': 't', - }], - ['у', { - 'regular': 'u', - }], - ['ў', { - 'regular': 'u', - 'with-breve': 'ŭ', - }], - ['ф', { - 'regular': 'f', - }], - ['х', { - 'regular': 'ch', - }], - ['ц', { - 'regular': 'c', - 'with-acute': 'ć', - }], - ['ч', { - 'regular': 'c', - 'with-caron': 'č', - }], - ['ш', { - 'regular': 's', - 'with-caron': 'š', - }], + ['а', ['a']], + ['б', ['b']], + ['в', ['v']], + ['г', ['h', 'g']], + ['ґ', ['g']], + ['д', ['d']], + ['е', ['ie', 'je']], + ['ё', ['io', 'jo']], + ['ж', ['z', 'ž', 'zh']], + ['з', ['z', 'ź']], + ['і', ['i']], + ['й', ['j']], + ['к', ['k']], + ['л', ['l', 'ł', 'ĺ']], + ['м', ['m']], + ['н', ['n', 'ń']], + ['о', ['o']], + ['п', ['p']], + ['р', ['r']], + ['с', ['s', 'ś']], + ['т', ['t']], + ['у', ['u']], + ['ў', ['u', 'ŭ', 'w']], + ['ф', ['f']], + ['х', ['ch', 'h']], + ['ц', ['c', 'ć']], + ['ч', ['c', 'č', 'ch']], + ['ш', ['s', 'š', 'sh']], ['ь', '_omitted'], - ['ы', { - 'regular': 'y', - }], - ['э', { - 'regular': 'e', - }], - ['ю', { - 'with-i': 'iu', - 'with-j': 'ju', - }], - ['я', { - 'with-i': 'ia', - 'with-j': 'ja' - }], + ['ы', ['y']], + ['э', ['e']], + ['ю', ['iu', 'ju']], + ['я', ['ia', 'ja']], ['’', '_omitted'], ['‘', '_omitted'], ...options.customReplacements ]); - const transformedString = string.split(' ').map( word => { + return string.split(' ').map( word => { if( '' === word ) { return ''; } @@ -248,6 +168,4 @@ export default function belLat(string, options) { return resultForWord.join(''); } ).join(' '); - - return 'slugify' === options.style ? slugify( transformedString ) : transformedString; } diff --git a/package.json b/package.json index 263d5f7..44d3834 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "@skip405/bel-lat", - "version": "1.0.2", + "version": "2.0.0", "repository": { "type": "git", "url": "https://github.com/skip405/bel-lat.git" }, - "description": "Convert cyrillic Belarusian characters to Latin characters using transliteration. Can transliterate in accordance with the \"Instruction on transliteration of geographical names\" or in accordance with the rules of the Belarusian Latin alphabet (Łacinka). Can slugify the resulted transliterated string.", + "description": "Convert cyrillic Belarusian characters to Latin characters using transliteration. Can transliterate in accordance with the \"Instruction on transliteration of geographical names\" or in accordance with the rules of the Belarusian Latin alphabet (Łacinka).", "exports": "./index.js", "main": "index.js", "scripts": { @@ -15,8 +15,8 @@ "node": ">=12" }, "bugs": { - "url" : "https://github.com/skip405/bel-lat/issues", - "email" : "skip405@gmail.com" + "url": "https://github.com/skip405/bel-lat/issues", + "email": "skip405@gmail.com" }, "files": [ "LICENSE.md", @@ -48,10 +48,7 @@ "transform": {} }, "license": "MIT", - "dependencies": { - "@sindresorhus/slugify": "^2.1.1" - }, "devDependencies": { - "jest": "^29.3.1" + "jest": "^29.5.0" } } diff --git a/test.js b/test.js index 12f107f..e68fcce 100644 --- a/test.js +++ b/test.js @@ -2,6 +2,10 @@ import belLat from './index'; test('tests it works', () => { expect(belLat("прывітанне, сусвет")).toBe("pryvitannie, susviet"); + + expect(belLat("Шчучыншчына", { style: 'lacinka' })).toBe("Ščučynščyna"); + expect(belLat("Шчучыншчына", { style: 'geo-2000' })).toBe("Ščučynščyna"); + expect(belLat("Шчучыншчына", { style: 'geo-2023' })).toBe("Shchuchynshchyna"); }); describe('Letters', () => { @@ -64,10 +68,39 @@ describe('Letters', () => { }); }); +describe('Instruction on transliteration of geographical names (2023)', () => { + test('Lowercase', () => { + expect(belLat("г", { style: 'geo-2023' })).toBe("g"); + expect(belLat("ж", { style: 'geo-2023' })).toBe("zh"); + expect(belLat("ў", { style: 'geo-2023' })).toBe("w"); + expect(belLat("х", { style: 'geo-2023' })).toBe("h"); + expect(belLat("ч", { style: 'geo-2023' })).toBe("ch"); + expect(belLat("ш", { style: 'geo-2023' })).toBe("sh"); + }); + + test('Uppercase', () => { + expect(belLat("Г", { style: 'geo-2023' })).toBe("G"); + expect(belLat("Ж", { style: 'geo-2023' })).toBe("Zh"); + expect(belLat("Ў", { style: 'geo-2023' })).toBe("W"); + expect(belLat("Х", { style: 'geo-2023' })).toBe("H"); + expect(belLat("Ч", { style: 'geo-2023' })).toBe("Ch"); + expect(belLat("Ш", { style: 'geo-2023' })).toBe("Sh"); + }); + + test('If next letter is uppercase (capslock)', () => { + expect(belLat("ГА", { style: 'geo-2023' })).toBe("GA"); + expect(belLat("ЖБ", { style: 'geo-2023' })).toBe("ZHB"); + expect(belLat("ЎВ", { style: 'geo-2023' })).toBe("WV"); + expect(belLat("ХА", { style: 'geo-2023' })).toBe("HA"); + expect(belLat("ЧА", { style: 'geo-2023' })).toBe("CHA"); + expect(belLat("ША", { style: 'geo-2023' })).toBe("SHA"); + }); +}); + describe('Special cases', () => { describe('Е, Ё, Ю, Я', () => { describe('Render with J', () => { - describe('In the beginning of a word', () => { + describe('At the beginning of a word', () => { test('Lowercase', () => { expect(belLat("е")).toBe("je"); expect(belLat("ё")).toBe("jo"); @@ -319,18 +352,37 @@ describe('Special cases', () => { expect(belLat("Сь")).toBe("Ś"); expect(belLat("Ць")).toBe("Ć"); }); + + test('As per instruction on transliteration of geographical names (2023)', () => { + expect(belLat("з", { style: 'geo-2023' })).toBe("z"); + expect(belLat("н", { style: 'geo-2023' })).toBe("n"); + expect(belLat("с", { style: 'geo-2023' })).toBe("s"); + expect(belLat("ц", { style: 'geo-2023' })).toBe("c"); + + expect(belLat("З", { style: 'geo-2023' })).toBe("Z"); + expect(belLat("Н", { style: 'geo-2023' })).toBe("N"); + expect(belLat("С", { style: 'geo-2023' })).toBe("S"); + expect(belLat("Ц", { style: 'geo-2023' })).toBe("C"); + }); }); describe('Л', () => { - describe('As per the Instruction on transliteration of geographical names', () => { + describe('As per the Instruction on transliteration of geographical names (2000)', () => { test('Renders without an acute sign', () => { - expect(belLat("л", { style: 'geographic' })).toBe("l"); - expect(belLat("Л", { style: 'geographic' })).toBe("L"); + expect(belLat("л", { style: 'geo-2000' })).toBe("l"); + expect(belLat("Л", { style: 'geo-2000' })).toBe("L"); }); test('Renders with an acute sign before Ь', () => { - expect(belLat("ль", { style: 'geographic' })).toBe("ĺ"); - expect(belLat("Ль", { style: 'geographic' })).toBe("Ĺ"); + expect(belLat("ль", { style: 'geo-2000' })).toBe("ĺ"); + expect(belLat("Ль", { style: 'geo-2000' })).toBe("Ĺ"); + }); + }); + + describe('As per the Instruction on transliteration of geographical names (2023)', () => { + test('Renders as l', () => { + expect(belLat("л", { style: 'geo-2023' })).toBe("l"); + expect(belLat("Л", { style: 'geo-2023' })).toBe("L"); }); }); @@ -356,93 +408,6 @@ describe('Special cases', () => { }); }); }); - -describe('Slugify', () => { - test('Renders without diacritical signs', () => { - expect(belLat("ж", { style: 'slugify' })).toBe("z"); - expect(belLat("з", { style: 'slugify' })).toBe("z"); - expect(belLat("л", { style: 'slugify' })).toBe("l"); - expect(belLat("н", { style: 'slugify' })).toBe("n"); - expect(belLat("с", { style: 'slugify' })).toBe("s"); - expect(belLat("ў", { style: 'slugify' })).toBe("u"); - expect(belLat("ц", { style: 'slugify' })).toBe("c"); - expect(belLat("ч", { style: 'slugify' })).toBe("c"); - expect(belLat("ш", { style: 'slugify' })).toBe("s"); - }); - - test('Renders letters as lowercase', () => { - expect(belLat("а", { style: 'slugify' })).toBe("a"); - expect(belLat("б", { style: 'slugify' })).toBe("b"); - expect(belLat("в", { style: 'slugify' })).toBe("v"); - expect(belLat("г", { style: 'slugify' })).toBe("h"); - expect(belLat("ґ", { style: 'slugify' })).toBe("g"); - expect(belLat("д", { style: 'slugify' })).toBe("d"); - expect(belLat("е", { style: 'slugify' })).toBe("je"); - expect(belLat("ё", { style: 'slugify' })).toBe("jo"); - expect(belLat("ж", { style: 'slugify' })).toBe("z"); - expect(belLat("з", { style: 'slugify' })).toBe("z"); - expect(belLat("і", { style: 'slugify' })).toBe("i"); - expect(belLat("й", { style: 'slugify' })).toBe("j"); - expect(belLat("к", { style: 'slugify' })).toBe("k"); - expect(belLat("л", { style: 'slugify' })).toBe("l"); - expect(belLat("м", { style: 'slugify' })).toBe("m"); - expect(belLat("н", { style: 'slugify' })).toBe("n"); - expect(belLat("о", { style: 'slugify' })).toBe("o"); - expect(belLat("п", { style: 'slugify' })).toBe("p"); - expect(belLat("р", { style: 'slugify' })).toBe("r"); - expect(belLat("с", { style: 'slugify' })).toBe("s"); - expect(belLat("т", { style: 'slugify' })).toBe("t"); - expect(belLat("у", { style: 'slugify' })).toBe("u"); - expect(belLat("ў", { style: 'slugify' })).toBe("u"); - expect(belLat("ф", { style: 'slugify' })).toBe("f"); - expect(belLat("х", { style: 'slugify' })).toBe("ch"); - expect(belLat("ц", { style: 'slugify' })).toBe("c"); - expect(belLat("ч", { style: 'slugify' })).toBe("c"); - expect(belLat("ш", { style: 'slugify' })).toBe("s"); - expect(belLat("ы", { style: 'slugify' })).toBe("y"); - expect(belLat("э", { style: 'slugify' })).toBe("e"); - expect(belLat("ю", { style: 'slugify' })).toBe("ju"); - expect(belLat("я", { style: 'slugify' })).toBe("ja"); - - expect(belLat("А", { style: 'slugify' })).toBe("a"); - expect(belLat("Б", { style: 'slugify' })).toBe("b"); - expect(belLat("В", { style: 'slugify' })).toBe("v"); - expect(belLat("Г", { style: 'slugify' })).toBe("h"); - expect(belLat("Ґ", { style: 'slugify' })).toBe("g"); - expect(belLat("Д", { style: 'slugify' })).toBe("d"); - expect(belLat("Е", { style: 'slugify' })).toBe("je"); - expect(belLat("Ё", { style: 'slugify' })).toBe("jo"); - expect(belLat("Ж", { style: 'slugify' })).toBe("z"); - expect(belLat("З", { style: 'slugify' })).toBe("z"); - expect(belLat("І", { style: 'slugify' })).toBe("i"); - expect(belLat("Й", { style: 'slugify' })).toBe("j"); - expect(belLat("К", { style: 'slugify' })).toBe("k"); - expect(belLat("Л", { style: 'slugify' })).toBe("l"); - expect(belLat("М", { style: 'slugify' })).toBe("m"); - expect(belLat("Н", { style: 'slugify' })).toBe("n"); - expect(belLat("О", { style: 'slugify' })).toBe("o"); - expect(belLat("П", { style: 'slugify' })).toBe("p"); - expect(belLat("Р", { style: 'slugify' })).toBe("r"); - expect(belLat("С", { style: 'slugify' })).toBe("s"); - expect(belLat("Т", { style: 'slugify' })).toBe("t"); - expect(belLat("У", { style: 'slugify' })).toBe("u"); - expect(belLat("Ў", { style: 'slugify' })).toBe("u"); - expect(belLat("Ф", { style: 'slugify' })).toBe("f"); - expect(belLat("Х", { style: 'slugify' })).toBe("ch"); - expect(belLat("Ц", { style: 'slugify' })).toBe("c"); - expect(belLat("Ч", { style: 'slugify' })).toBe("c"); - expect(belLat("Ш", { style: 'slugify' })).toBe("s"); - expect(belLat("Ы", { style: 'slugify' })).toBe("y"); - expect(belLat("Э", { style: 'slugify' })).toBe("e"); - expect(belLat("Ю", { style: 'slugify' })).toBe("ju"); - expect(belLat("Я", { style: 'slugify' })).toBe("ja"); - }); - - test('Creates a slug with dashes', () => { - expect(belLat("прывітанне, сусвет", { style: 'slugify' })).toBe("pryvitannie-susviet"); - }); -}); - describe('Misc', () => { test('Throws a type error if wrong data type is provided', () => { expect(() => { belLat(1) }).toThrow(TypeError); @@ -458,7 +423,7 @@ describe('Misc', () => { test('Allows basic custom replacements', () => { expect(belLat("№", { - customReplacements: [['№', { regular: '#' }] ] + customReplacements: [['№', ['#']] ] })).toBe("#"); });