mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-07 14:57:12 -04:00
Merge 6cfaf63502
into 63fbd3b45c
This commit is contained in:
commit
b62538b1b6
9 changed files with 3278 additions and 45 deletions
|
@ -72,6 +72,7 @@
|
||||||
"js-base64": "^3.7.6",
|
"js-base64": "^3.7.6",
|
||||||
"json5": "^2.2.3",
|
"json5": "^2.2.3",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^3.1.2",
|
||||||
|
"korean-unpacker": "^1.0.3",
|
||||||
"libphonenumber-js": "^1.10.28",
|
"libphonenumber-js": "^1.10.28",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"markdown-it": "^14.0.0",
|
"markdown-it": "^14.0.0",
|
||||||
|
|
13
pnpm-lock.yaml
generated
13
pnpm-lock.yaml
generated
|
@ -113,6 +113,9 @@ dependencies:
|
||||||
jwt-decode:
|
jwt-decode:
|
||||||
specifier: ^3.1.2
|
specifier: ^3.1.2
|
||||||
version: 3.1.2
|
version: 3.1.2
|
||||||
|
korean-unpacker:
|
||||||
|
specifier: ^1.0.3
|
||||||
|
version: 1.0.3
|
||||||
libphonenumber-js:
|
libphonenumber-js:
|
||||||
specifier: ^1.10.28
|
specifier: ^1.10.28
|
||||||
version: 1.10.28
|
version: 1.10.28
|
||||||
|
@ -3412,7 +3415,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@unhead/dom': 0.5.1
|
'@unhead/dom': 0.5.1
|
||||||
'@unhead/schema': 0.5.1
|
'@unhead/schema': 0.5.1
|
||||||
'@vueuse/shared': 11.0.3(vue@3.3.4)
|
'@vueuse/shared': 11.1.0(vue@3.3.4)
|
||||||
unhead: 0.5.1
|
unhead: 0.5.1
|
||||||
vue: 3.3.4
|
vue: 3.3.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
@ -4054,8 +4057,8 @@ packages:
|
||||||
- vue
|
- vue
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@vueuse/shared@11.0.3(vue@3.3.4):
|
/@vueuse/shared@11.1.0(vue@3.3.4):
|
||||||
resolution: {integrity: sha512-0rY2m6HS5t27n/Vp5cTDsKTlNnimCqsbh/fmT2LgE+aaU42EMfXo8+bNX91W9I7DDmxfuACXMmrd7d79JxkqWA==}
|
resolution: {integrity: sha512-YUtIpY122q7osj+zsNMFAfMTubGz0sn5QzE5gPzAIiCmtt2ha3uQUY1+JPyL4gRCTsLPX82Y9brNbo/aqlA91w==}
|
||||||
dependencies:
|
dependencies:
|
||||||
vue-demi: 0.14.10(vue@3.3.4)
|
vue-demi: 0.14.10(vue@3.3.4)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
@ -6699,6 +6702,10 @@ packages:
|
||||||
resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
|
resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/korean-unpacker@1.0.3:
|
||||||
|
resolution: {integrity: sha512-s0VIyZOFOtalBSp51NECPvM1g9Af8M0Oxe1ZdMMGL7nvG/ecVNYkCAzPU+f52f0R83ytVCOd3fd14TTOFx2GXQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/less@4.1.3:
|
/less@4.1.3:
|
||||||
resolution: {integrity: sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==}
|
resolution: {integrity: sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
3
src/tools/text-to-nato-alphabet/korean-unpacker.d.ts
vendored
Normal file
3
src/tools/text-to-nato-alphabet/korean-unpacker.d.ts
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
declare module 'korean-unpacker' {
|
||||||
|
function unpack(text: string): string;
|
||||||
|
}
|
2844
src/tools/text-to-nato-alphabet/nato.alphabets.json
Normal file
2844
src/tools/text-to-nato-alphabet/nato.alphabets.json
Normal file
File diff suppressed because it is too large
Load diff
137
src/tools/text-to-nato-alphabet/nato.test.data.json
Normal file
137
src/tools/text-to-nato-alphabet/nato.test.data.json
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"lang": "(International)",
|
||||||
|
"input": "TesYW 123 ? = !@",
|
||||||
|
"output": "TANGO echo sierra YANKEE WHISKEY (SPACE) ONE TWO THREE (SPACE) (?) (SPACE) (=) (SPACE) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "(France)",
|
||||||
|
"input": "TesYW 123 ? = !@",
|
||||||
|
"output": "THÉRÈSE eugène suzanne YVONNE WILLIAM (ESPACE) UN DEUX TROIS (ESPACE) (?) (ESPACE) (=) (ESPACE) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "(Belgium)",
|
||||||
|
"input": "TesYW 123 ? = !@",
|
||||||
|
"output": "TELEFOON emiel sofie YVONNE WATERLOO (ESPACE) (1) (2) (3) (ESPACE) (?) (ESPACE) (=) (ESPACE) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "(Switzerland)",
|
||||||
|
"input": "TesYW 123 ? = !@",
|
||||||
|
"output": "THÉRÈSE émile suzanne (Y) WILLIAM (ESPACE) (1) (2) (3) (ESPACE) (?) (ESPACE) (=) (ESPACE) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "(Québec)",
|
||||||
|
"input": "TesYW 123 ? = !@",
|
||||||
|
"output": "THOMAS édouard samuel (Y) WILLIAM (ESPACE) (1) (2) (3) (ESPACE) (?) (ESPACE) (=) (ESPACE) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "(Germany, 2022)",
|
||||||
|
"input": "TesYü 123 ? = !@",
|
||||||
|
"output": "TÜBINGEN essen salzwedel YPSILON umlaut-unna (LEERZEICHEN) (1) (2) (3) (LEERZEICHEN) (?) (LEERZEICHEN) (=) (LEERZEICHEN) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "(Austria)",
|
||||||
|
"input": "TesYW 123 ? = !@",
|
||||||
|
"output": "THEODOR emil samuel/siegfried YPSILON WILHELM (LEERZEICHEN) (1) (2) (3) (LEERZEICHEN) (?) (LEERZEICHEN) (=) (LEERZEICHEN) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "(Germany, informal, 2022)",
|
||||||
|
"input": "TesYü 123 ? = !@",
|
||||||
|
"output": "THEODOR emil samuel YPSILON überfluss (LEERZEICHEN) (1) (2) (3) (LEERZEICHEN) (?) (LEERZEICHEN) (=) (LEERZEICHEN) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "(Netherlands)",
|
||||||
|
"input": "TesY huis rij 123 ? = !@",
|
||||||
|
"output": "THEODOR eduard simon YPSILON (SPATIE) hendrik utrecht izaak simon (SPATIE) richard/rudolf ijmuiden/ijsbrand (SPATIE) (1) (2) (3) (SPATIE) (?) (SPATIE) (=) (SPATIE) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Italian",
|
||||||
|
"input": "TesYj 123 ? = !@",
|
||||||
|
"output": "TORINO empoli savona YORK, YOGURT jolly/juventus (SPAZIO) (1) (2) (3) (SPAZIO) (?) (SPAZIO) (=) (SPAZIO) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Spanish",
|
||||||
|
"input": "TesYñj 123 ? = !@",
|
||||||
|
"output": "TOLEDO españa sábado YOLANDA ñoño josé (ESPACIO) (1) (2) (3) (ESPACIO) (?) (ESPACIO) (=) (ESPACIO) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "(Brazil)",
|
||||||
|
"input": "TesYÇj 123 ? = !@",
|
||||||
|
"output": "TATU estrela saci YOLANDA (Ç) josé (ESPAÇO) (1) (2) (3) (ESPAÇO) (?) (ESPAÇO) (=) (ESPAÇO) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "(Portugal)",
|
||||||
|
"input": "TesYúj 123 ? = !@",
|
||||||
|
"output": "TAVIRA évora setúbal YORK (ú) josé (ESPAÇO) (1) (2) (3) (ESPAÇO) (?) (ESPAÇO) (=) (ESPAÇO) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Swedish",
|
||||||
|
"input": "TesYj 123 ? = !@",
|
||||||
|
"output": "TORE erik sigurd YNGVE johan (UTRYMME) (1) (2) (3) (UTRYMME) (?) (UTRYMME) (=) (UTRYMME) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Danish",
|
||||||
|
"input": "TesÆYj 123 ? = !@",
|
||||||
|
"output": "THEODOR erik søren ÆGIR YRSA johan (MELLEMRUMSTEGN) (1) (2) (3) (MELLEMRUMSTEGN) (?) (MELLEMRUMSTEGN) (=) (MELLEMRUMSTEGN) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Norwegian",
|
||||||
|
"input": "TesYÅj 123 ? = !@",
|
||||||
|
"output": "TEODOR edith sigrid YNGLING ÅSE johan (MELLOMROMSTEGN) (1) (2) (3) (MELLOMROMSTEGN) (?) (MELLOMROMSTEGN) (=) (MELLOMROMSTEGN) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Finnish",
|
||||||
|
"input": "TesYj 123 ? = !@",
|
||||||
|
"output": "TYYNE eemeli sakari YRJÖ jussi (VÄLILYÖNTI) (1) (2) (3) (VÄLILYÖNTI) (?) (VÄLILYÖNTI) (=) (VÄLILYÖNTI) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Turkish",
|
||||||
|
"input": "TesYj 123 ? = !@",
|
||||||
|
"output": "TOKAT edirne sinop YOZGAT jandarma (BOŞLUK) (1) (2) (3) (BOŞLUK) (?) (BOŞLUK) (=) (BOŞLUK) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Romanian",
|
||||||
|
"input": "TesYj 123 ? = !@",
|
||||||
|
"output": "TUDOR elena sandu I-GREC jean (SPAȚIU) (1) (2) (3) (SPAȚIU) (?) (SPAȚIU) (=) (SPAȚIU) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Czech",
|
||||||
|
"input": "TesYj 123 ? = !@",
|
||||||
|
"output": "TOMÁŠ emil svatopluk YPSILON josef (PROSTOROVÝ) (1) (2) (3) (PROSTOROVÝ) (?) (PROSTOROVÝ) (=) (PROSTOROVÝ) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Yugoslav",
|
||||||
|
"input": "TesYČj 123 ? = !@",
|
||||||
|
"output": "TUZLA evropa skopje IPSILON ČAČAK jadran (PRIESTOROVÝ) (1) (2) (3) (PRIESTOROVÝ) (?) (PRIESTOROVÝ) (=) (PRIESTOROVÝ) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Serbian",
|
||||||
|
"input": "TesYČj 123 ? = !@",
|
||||||
|
"output": "TIMOK evropa sava IPSILON ČAČAK jadran (PROSTORNI) (1) (2) (3) (PROSTORNI) (?) (PROSTORNI) (=) (PROSTORNI) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Slovene",
|
||||||
|
"input": "TesYČj 123 ? = !@",
|
||||||
|
"output": "TRIGLAV evropa soča IPSILON ČATEŽ jadran (PRESLEDKA) (1) (2) (3) (PRESLEDKA) (?) (PRESLEDKA) (=) (PRESLEDKA) (!) (@)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Russian",
|
||||||
|
"input": "Зинаида !.?",
|
||||||
|
"output": "ЗИНАИДА иван николай анна иван дмитрий анна ( ) (!) (.) (?)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Korean",
|
||||||
|
"input": "안녕하세요 여러분",
|
||||||
|
"output": "잉어 아버지 나폴리 나폴리 연못 잉어 한강 아버지 서울 엑스레이 잉어 요지경 ( ) 잉어 연못 로마 어머니 바가지 우편 나폴리"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Greek",
|
||||||
|
"input": "τίγρης !?",
|
||||||
|
"output": "τίγρης (ί) γαλή ρήγας ηρώ σοφός ( ) (!) (?)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "Japanese",
|
||||||
|
"input": "数字のひと おしまいのン ?:",
|
||||||
|
"output": "(数) (字) 野原のノ 飛行機のヒ 東京のト ( ) 大阪のオ 新聞のシ マッチのマ いろはのイ 野原のノ おしまいのン ( ) (?) (:)"
|
||||||
|
}
|
||||||
|
]
|
|
@ -1,28 +1,29 @@
|
||||||
export const natoAlphabet = [
|
export const allLanguagesAndCountries = [
|
||||||
'Alpha',
|
'(International)',
|
||||||
'Bravo',
|
'(France)',
|
||||||
'Charlie',
|
'(Belgium)',
|
||||||
'Delta',
|
'(Switzerland)',
|
||||||
'Echo',
|
'(Québec)',
|
||||||
'Foxtrot',
|
'(Germany, 2022)',
|
||||||
'Golf',
|
'(Austria)',
|
||||||
'Hotel',
|
'(Germany, informal, 2022)',
|
||||||
'India',
|
'(Netherlands)',
|
||||||
'Juliet',
|
'Italian',
|
||||||
'Kilo',
|
'Spanish',
|
||||||
'Lima',
|
'(Brazil)',
|
||||||
'Mike',
|
'(Portugal)',
|
||||||
'November',
|
'Swedish',
|
||||||
'Oscar',
|
'Danish',
|
||||||
'Papa',
|
'Norwegian',
|
||||||
'Quebec',
|
'Finnish',
|
||||||
'Romeo',
|
'Turkish',
|
||||||
'Sierra',
|
'Romanian',
|
||||||
'Tango',
|
'Czech',
|
||||||
'Uniform',
|
'Yugoslav',
|
||||||
'Victor',
|
'Serbian',
|
||||||
'Whiskey',
|
'Slovene',
|
||||||
'X-ray',
|
'Russian',
|
||||||
'Yankee',
|
'Korean',
|
||||||
'Zulu',
|
'Greek',
|
||||||
|
'Japanese',
|
||||||
];
|
];
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { textToNatoAlphabet } from './text-to-nato-alphabet.service';
|
||||||
|
|
||||||
|
const TestCase_TestYW = 'TesYW 123 ? = !@';
|
||||||
|
const TestCase_TestYJ = 'TesYj 123 ? = !@';
|
||||||
|
const natoTests = [
|
||||||
|
{
|
||||||
|
lang: '(International)',
|
||||||
|
input: TestCase_TestYW,
|
||||||
|
output: 'TANGO echo sierra YANKEE WHISKEY (SPACE) (digit 1) (digit 2) (digit 3) (SPACE) (punctuation ?) (SPACE) (punctuation =) (SPACE) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: '(France)',
|
||||||
|
input: TestCase_TestYW,
|
||||||
|
output: 'THÉRÈSE eugène suzanne YVONNE WILLIAM (ESPACE) (digit 1) (digit 2) (digit 3) (ESPACE) (punctuation ?) (ESPACE) (punctuation =) (ESPACE) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: '(Belgium)',
|
||||||
|
input: TestCase_TestYW,
|
||||||
|
output: 'TELEFOON emiel sofie YVONNE WATERLOO (ESPACE) (digit 1) (digit 2) (digit 3) (ESPACE) (punctuation ?) (ESPACE) (punctuation =) (ESPACE) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: '(Switzerland)',
|
||||||
|
input: TestCase_TestYW,
|
||||||
|
output: 'THÉRÈSE émile suzanne (Y) WILLIAM (ESPACE) (digit 1) (digit 2) (digit 3) (ESPACE) (punctuation ?) (ESPACE) (punctuation =) (ESPACE) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: '(Québec)',
|
||||||
|
input: TestCase_TestYW,
|
||||||
|
output: 'THOMAS édouard samuel (Y) WILLIAM (ESPACE) (digit 1) (digit 2) (digit 3) (ESPACE) (punctuation ?) (ESPACE) (punctuation =) (ESPACE) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: '(Germany, 2022)',
|
||||||
|
input: 'TesYü 123 ? = !@',
|
||||||
|
output: 'TÜBINGEN essen salzwedel YPSILON umlaut-unna (LEERZEICHEN) (digit 1) (digit 2) (digit 3) (LEERZEICHEN) (punctuation ?) (LEERZEICHEN) (punctuation =) (LEERZEICHEN) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: '(Austria)',
|
||||||
|
input: TestCase_TestYW,
|
||||||
|
output: 'THEODOR emil samuel/siegfried YPSILON WILHELM (LEERZEICHEN) (digit 1) (digit 2) (digit 3) (LEERZEICHEN) (punctuation ?) (LEERZEICHEN) (punctuation =) (LEERZEICHEN) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: '(Germany, informal, 2022)',
|
||||||
|
input: 'TesYü 123 ? = !@',
|
||||||
|
output: 'THEODOR emil samuel YPSILON überfluss (LEERZEICHEN) (digit 1) (digit 2) (digit 3) (LEERZEICHEN) (punctuation ?) (LEERZEICHEN) (punctuation =) (LEERZEICHEN) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: '(Netherlands)',
|
||||||
|
input: 'TesY huis rij 123 ? = !@',
|
||||||
|
output: 'THEODOR eduard simon YPSILON (SPATIE) hendrik utrecht izaak simon (SPATIE) richard/rudolf ijmuiden/ijsbrand (SPATIE) (digit 1) (digit 2) (digit 3) (SPATIE) (punctuation ?) (SPATIE) (punctuation =) (SPATIE) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Italian',
|
||||||
|
input: TestCase_TestYJ,
|
||||||
|
output: 'TORINO empoli savona YORK, YOGURT jolly/juventus (SPAZIO) (digit 1) (digit 2) (digit 3) (SPAZIO) (punctuation ?) (SPAZIO) (punctuation =) (SPAZIO) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Spanish',
|
||||||
|
input: 'TesYñj 123 ? = !@',
|
||||||
|
output: 'TOLEDO españa sábado YOLANDA ñoño josé (ESPACIO) (digit 1) (digit 2) (digit 3) (ESPACIO) (punctuation ?) (ESPACIO) (punctuation =) (ESPACIO) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: '(Brazil)',
|
||||||
|
input: 'TesYÇj 123 ? = !@',
|
||||||
|
output: 'TATU estrela saci YOLANDA (Ç) josé (ESPAÇO) (digit 1) (digit 2) (digit 3) (ESPAÇO) (punctuation ?) (ESPAÇO) (punctuation =) (ESPAÇO) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: '(Portugal)',
|
||||||
|
input: 'TesYúj 123 ? = !@',
|
||||||
|
output: 'TAVIRA évora setúbal YORK (ú) josé (ESPAÇO) (digit 1) (digit 2) (digit 3) (ESPAÇO) (punctuation ?) (ESPAÇO) (punctuation =) (ESPAÇO) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Swedish',
|
||||||
|
input: TestCase_TestYJ,
|
||||||
|
output: 'TORE erik sigurd YNGVE johan (UTRYMME) (digit 1) (digit 2) (digit 3) (UTRYMME) (punctuation ?) (UTRYMME) (punctuation =) (UTRYMME) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Danish',
|
||||||
|
input: 'TesÆYj 123 ? = !@',
|
||||||
|
output: 'THEODOR erik søren ÆGIR YRSA johan (MELLEMRUMSTEGN) (digit 1) (digit 2) (digit 3) (MELLEMRUMSTEGN) (punctuation ?) (MELLEMRUMSTEGN) (punctuation =) (MELLEMRUMSTEGN) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Norwegian',
|
||||||
|
input: 'TesYÅj 123 ? = !@',
|
||||||
|
output: 'TEODOR edith sigrid YNGLING ÅSE johan (MELLOMROMSTEGN) (digit 1) (digit 2) (digit 3) (MELLOMROMSTEGN) (punctuation ?) (MELLOMROMSTEGN) (punctuation =) (MELLOMROMSTEGN) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Finnish',
|
||||||
|
input: TestCase_TestYJ,
|
||||||
|
output: 'TYYNE eemeli sakari YRJÖ jussi (VÄLILYÖNTI) (digit 1) (digit 2) (digit 3) (VÄLILYÖNTI) (punctuation ?) (VÄLILYÖNTI) (punctuation =) (VÄLILYÖNTI) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Turkish',
|
||||||
|
input: TestCase_TestYJ,
|
||||||
|
output: 'TOKAT edirne sinop YOZGAT jandarma (BOŞLUK) (digit 1) (digit 2) (digit 3) (BOŞLUK) (punctuation ?) (BOŞLUK) (punctuation =) (BOŞLUK) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Romanian',
|
||||||
|
input: TestCase_TestYJ,
|
||||||
|
output: 'TUDOR elena sandu I-GREC jean (SPAȚIU) (digit 1) (digit 2) (digit 3) (SPAȚIU) (punctuation ?) (SPAȚIU) (punctuation =) (SPAȚIU) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Czech',
|
||||||
|
input: TestCase_TestYJ,
|
||||||
|
output: 'TOMÁŠ emil svatopluk YPSILON josef (PROSTOROVÝ) (digit 1) (digit 2) (digit 3) (PROSTOROVÝ) (punctuation ?) (PROSTOROVÝ) (punctuation =) (PROSTOROVÝ) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Yugoslav',
|
||||||
|
input: 'TesYČj 123 ? = !@',
|
||||||
|
output: 'TUZLA evropa skopje IPSILON ČAČAK jadran (PRIESTOROVÝ) (digit 1) (digit 2) (digit 3) (PRIESTOROVÝ) (punctuation ?) (PRIESTOROVÝ) (punctuation =) (PRIESTOROVÝ) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Serbian',
|
||||||
|
input: 'TesYČj 123 ? = !@',
|
||||||
|
output: 'TIMOK evropa sava IPSILON ČAČAK jadran (PROSTORNI) (digit 1) (digit 2) (digit 3) (PROSTORNI) (punctuation ?) (PROSTORNI) (punctuation =) (PROSTORNI) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Slovene',
|
||||||
|
input: 'TesYČj 123 ? = !@',
|
||||||
|
output: 'TRIGLAV evropa soča IPSILON ČATEŽ jadran (PRESLEDKA) (digit 1) (digit 2) (digit 3) (PRESLEDKA) (punctuation ?) (PRESLEDKA) (punctuation =) (PRESLEDKA) (punctuation !) (punctuation @)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Russian',
|
||||||
|
input: 'Зинаида !.?',
|
||||||
|
output: 'ЗИНАИДА иван николай анна иван дмитрий анна ( ) (punctuation !) (punctuation .) (punctuation ?)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Korean',
|
||||||
|
input: '안녕하세요 여러분',
|
||||||
|
output: '잉어 아버지 나폴리 나폴리 연못 잉어 한강 아버지 서울 엑스레이 잉어 요지경 ( ) 잉어 연못 로마 어머니 바가지 우편 나폴리',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Greek',
|
||||||
|
input: 'τίγρης !?',
|
||||||
|
output: 'τίγρης (ί) γαλή ρήγας ηρώ σοφός ( ) (punctuation !) (punctuation ?)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang: 'Japanese',
|
||||||
|
input: '数字のひと おしまいのン ?:',
|
||||||
|
output: '(数) (字) 野原のノ 飛行機のヒ 東京のト ( ) 大阪のオ 新聞のシ マッチのマ いろはのイ 野原のノ おしまいのン ( ) (punctuation ?) (punctuation :)',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('text-to-nato', () => {
|
||||||
|
it('Convert text to NATO', async () => {
|
||||||
|
for (const nato of natoTests) {
|
||||||
|
const { lang, input, output } = nato;
|
||||||
|
expect(textToNatoAlphabet({ text: input, langOrCountry: lang })).to.equal(output);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Convert text to NATO (includes punctuations and digits names)', async () => {
|
||||||
|
expect(textToNatoAlphabet({ text: 'a 1 2 3 ! % ? ;', langOrCountry: '(France)', useDigitsNames: true, usePunctuationsNames: true })).to.equal(
|
||||||
|
'anatole (ESPACE) {digit 1 => un} (ESPACE) {digit 2 => deux} (ESPACE) {digit 3 => trois} (ESPACE) {punctuation ! => point d\'exclamation} (ESPACE) {punctuation % => pour cent} (ESPACE) {punctuation ? => point d\'interrogation} (ESPACE) {punctuation ; => point-virgule}');
|
||||||
|
expect(textToNatoAlphabet({ text: 'и 1 2 3 ! % ? ;', langOrCountry: 'Russian', useDigitsNames: true, usePunctuationsNames: true })).to.equal(
|
||||||
|
'иван ( ) {digit 1 => один (odin)} ( ) {digit 2 => два (dva)} ( ) {digit 3 => три (tri)} ( ) {punctuation ! => восклицательный знак (vosklitsatel\'nyy znak)} ( ) {punctuation % => процент (protsent)} ( ) {punctuation ? => вопросительный знак (voprositel\'nyy znak)} ( ) {punctuation ; => точка с запятой (tochka s zapyatoy)}');
|
||||||
|
expect(textToNatoAlphabet({ text: 'TesYj 1 2 3 ! % ? ;', langOrCountry: 'Swedish', useDigitsNames: true, usePunctuationsNames: true })).to.equal(
|
||||||
|
'TORE erik sigurd YNGVE johan (UTRYMME) {digit 1 => ett} (UTRYMME) {digit 2 => två} (UTRYMME) {digit 3 => tre} (UTRYMME) {punctuation ! => utropstecken} (UTRYMME) {punctuation % => procent} (UTRYMME) {punctuation ? => frågetecken} (UTRYMME) {punctuation ; => semikolon}');
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,19 +1,80 @@
|
||||||
import { natoAlphabet } from './text-to-nato-alphabet.constants';
|
import hangul from 'korean-unpacker';
|
||||||
|
import allAlphabets from './nato.alphabets.json';
|
||||||
|
|
||||||
|
type AllAlphabetsKeys = keyof typeof allAlphabets[0];
|
||||||
|
|
||||||
export { textToNatoAlphabet };
|
export { textToNatoAlphabet };
|
||||||
|
|
||||||
function getLetterPositionInAlphabet({ letter }: { letter: string }) {
|
function isPunctuation(char: string) {
|
||||||
return letter.toLowerCase().charCodeAt(0) - 'a'.charCodeAt(0);
|
const punctuations = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~';
|
||||||
|
return punctuations.includes(char);
|
||||||
|
}
|
||||||
|
function isDigit(char: string) {
|
||||||
|
const digits = '0123456789';
|
||||||
|
return digits.includes(char);
|
||||||
}
|
}
|
||||||
|
|
||||||
function textToNatoAlphabet({ text }: { text: string }) {
|
function escapeRegExp(string: string) {
|
||||||
return text
|
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
||||||
.split('')
|
}
|
||||||
.map((character) => {
|
|
||||||
const alphabetIndex = getLetterPositionInAlphabet({ letter: character });
|
function textToNatoAlphabet({
|
||||||
const natoWord = natoAlphabet[alphabetIndex];
|
text, langOrCountry = '(International)',
|
||||||
|
useDigitsNames = false, usePunctuationsNames = false,
|
||||||
return natoWord ?? character;
|
}: {
|
||||||
})
|
text: string
|
||||||
.join(' ');
|
langOrCountry: string
|
||||||
|
useDigitsNames?: boolean
|
||||||
|
usePunctuationsNames?: boolean
|
||||||
|
}) {
|
||||||
|
const getNatoWord = (searchChar: string) => {
|
||||||
|
const alphabetLetter = allAlphabets.find(letter => letter.Letter === searchChar);
|
||||||
|
if (alphabetLetter && alphabetLetter[langOrCountry as AllAlphabetsKeys]) {
|
||||||
|
return alphabetLetter[langOrCountry as AllAlphabetsKeys] || '';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const charRegex = new RegExp(
|
||||||
|
`(${
|
||||||
|
allAlphabets
|
||||||
|
.sort((a, b) => b.Letter.length - a.Letter.length)
|
||||||
|
.filter(a => a[langOrCountry as AllAlphabetsKeys])
|
||||||
|
.map(a => escapeRegExp(a.Letter))
|
||||||
|
.join('|')
|
||||||
|
}|.)`,
|
||||||
|
'gi');
|
||||||
|
return hangul.unpack(text)
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.replace(
|
||||||
|
charRegex,
|
||||||
|
(character) => {
|
||||||
|
const searchChar = character.toUpperCase();
|
||||||
|
const isUpper = character[0].toUpperCase() === character[0];
|
||||||
|
const natoWord = getNatoWord(searchChar);
|
||||||
|
|
||||||
|
if (isDigit(searchChar)) {
|
||||||
|
if (useDigitsNames) {
|
||||||
|
return ` {digit ${searchChar} => ${natoWord}}`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ` (digit ${character})`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isPunctuation(searchChar)) {
|
||||||
|
if (usePunctuationsNames) {
|
||||||
|
return ` {punctuation ${searchChar} => ${natoWord}}`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ` (punctuation ${character})`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (natoWord) {
|
||||||
|
return ` ${isUpper ? natoWord.toUpperCase() : natoWord.toLowerCase()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ` (${character})`;
|
||||||
|
})
|
||||||
|
.trim();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,33 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { textToNatoAlphabet } from './text-to-nato-alphabet.service';
|
import { textToNatoAlphabet } from './text-to-nato-alphabet.service';
|
||||||
|
import { allLanguagesAndCountries } from './text-to-nato-alphabet.constants';
|
||||||
import { useCopy } from '@/composable/copy';
|
import { useCopy } from '@/composable/copy';
|
||||||
|
|
||||||
|
const lang = useStorage('text-to-nato:lang', '(International)');
|
||||||
const input = ref('');
|
const input = ref('');
|
||||||
const natoText = computed(() => textToNatoAlphabet({ text: input.value }));
|
const useDigitsNames = useStorage('text-to-nato:digits', false);
|
||||||
|
const usePunctuationsNames = useStorage('text-to-nato:puncts', false);
|
||||||
|
const natoText = computed(() => textToNatoAlphabet({ text: input.value, langOrCountry: lang.value }));
|
||||||
const { copy } = useCopy({ source: natoText, text: 'NATO alphabet string copied.' });
|
const { copy } = useCopy({ source: natoText, text: 'NATO alphabet string copied.' });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
<c-select
|
||||||
|
v-model:value="lang"
|
||||||
|
:options="allLanguagesAndCountries"
|
||||||
|
searchable
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div flex justify-center>
|
||||||
|
<n-form-item label="Use digits pronunciation">
|
||||||
|
<n-checkbox v-model:checked="usePunctuationsNames" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="Use punctuations pronunciation">
|
||||||
|
<n-checkbox v-model:checked="useDigitsNames" />
|
||||||
|
</n-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
<c-input-text
|
<c-input-text
|
||||||
v-model:value="input"
|
v-model:value="input"
|
||||||
label="Your text to convert to NATO phonetic alphabet"
|
label="Your text to convert to NATO phonetic alphabet"
|
||||||
|
@ -19,7 +38,7 @@ const { copy } = useCopy({ source: natoText, text: 'NATO alphabet string copied.
|
||||||
|
|
||||||
<div v-if="natoText">
|
<div v-if="natoText">
|
||||||
<div mb-2>
|
<div mb-2>
|
||||||
Your text in NATO phonetic alphabet
|
Your text in NATO phonetic alphabet ({{ lang }})
|
||||||
</div>
|
</div>
|
||||||
<c-card>
|
<c-card>
|
||||||
{{ natoText }}
|
{{ natoText }}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue