prpm-dbp 0.3.0 → 0.5.0
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/README.md +1 -0
- package/SKILL.md +53 -0
- package/bin/cli.js +20 -0
- package/package.json +1 -1
- package/src/nama.js +70 -0
- package/src/pedoman.js +84 -0
- package/src/tukar.js +50 -2
package/README.md
CHANGED
|
@@ -128,6 +128,7 @@ Pengguna kemudian menarik versi baharu dengan `npx skills update`.
|
|
|
128
128
|
| `jawi <fail>` | tukar teks Rumi ke Jawi ikut ejaan DBP |
|
|
129
129
|
| `rumi <fail>` | tukar teks Jawi ke Rumi dari cache |
|
|
130
130
|
| `import-tsv <fail>` | import dataset rumi/jawi tambahan |
|
|
131
|
+
| `nama <rumi> <jawi>` | sahkan satu nama khas |
|
|
131
132
|
| `banding <kata...>` | silang semak PRPM lawan KamusDBP |
|
|
132
133
|
| `cache` | status cache, `--buang <kata>` untuk padam satu |
|
|
133
134
|
|
package/SKILL.md
CHANGED
|
@@ -91,6 +91,59 @@ Sesetengah entri memulangkan **dua perkataan Jawi untuk satu perkataan Rumi**: `
|
|
|
91
91
|
|
|
92
92
|
**Teks Arab yang dipetik dibiarkan sepenuhnya.** Jawi Melayu tidak menggunakan baris tanda vokal, jadi kehadiran fathah, kasrah, dammah, sukun atau tanwin bermakna potongan itu Arab, bukan Jawi. Ayat al-Quran dan hadis dalam dokumen Melayu lulus tanpa disentuh dan dilaporkan dalam medan `arab`.
|
|
93
93
|
|
|
94
|
+
## Nama khas
|
|
95
|
+
|
|
96
|
+
Diuji terhadap PRPM: **nama tokoh dan nama surah tiada sumber berwibawa.** `muhammad`, `ibrahim`, `musa`, `umar`, `aisyah`, `khadijah` semuanya tiada entri. Nama surah seperti `fatihah`, `baqarah`, `yasin` ada entri tetapi tanpa ejaan Jawi. Dataset komuniti meliputi nama tempat (`mekah` مکة, `mesir` مسير, `pahang` ڤاهڠ) tetapi bukan nama orang.
|
|
97
|
+
|
|
98
|
+
Alat ini **tidak mereka ejaan nama**. Sebaliknya:
|
|
99
|
+
|
|
100
|
+
- Perkataan berhuruf besar di **tengah** ayat dikira nama khas dan dilaporkan dalam medan `namaKhas`, berasingan daripada `belumDisahkan`. Nama bukan salah eja.
|
|
101
|
+
- Sahkan sekali, guna selamanya:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
npx prpm-dbp nama Muhammad <ejaan-jawi>
|
|
105
|
+
npx prpm-dbp nama # senaraikan yang sudah disahkan
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Ejaan yang disimpan begini ditandakan datang daripada pengguna, bukan daripada DBP. Sahkan dengan guru atau rujukan bertulis dahulu.
|
|
109
|
+
|
|
110
|
+
**Jangan keliru antara dua benda:**
|
|
111
|
+
|
|
112
|
+
| | Layanan |
|
|
113
|
+
|---|---|
|
|
114
|
+
| Petikan bahasa Arab (ayat, doa, hadis) | kekal Arab, tidak disentuh |
|
|
115
|
+
| Nama khas dalam ayat Melayu | **ditulis dalam Jawi**, bukan dikekalkan |
|
|
116
|
+
|
|
117
|
+
Bagi nama berasal Arab, ejaan Jawinya memang ejaan Arab asal, jadi ia nampak seperti dikekalkan. Bagi nama bukan Arab ia ditransliterasi penuh: `Kuala Lumpur` menjadi `کوالا لومڤور`.
|
|
118
|
+
|
|
119
|
+
## Peraturan Pedoman DBP
|
|
120
|
+
|
|
121
|
+
Satu fail sahaja dalam pakej ini **menjana** ejaan dan bukan mencarinya: `src/pedoman.js`. Ia dibenarkan kerana setiap peraturan di dalamnya datang daripada *Pedoman Umum Ejaan Jawi Bahasa Melayu* terbitan DBP, dan dirujuk pada seksyennya.
|
|
122
|
+
|
|
123
|
+
**§14.1 — kata sendi `di` dan `ke` ditulis sebagai satu kata dengan kata yang mengikutinya.**
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
di Mekah -> دمکة bukan د مکة
|
|
127
|
+
ke sekolah -> کسکوله bukan ک سکوله
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Nota seksyen yang sama: jika kata berikutnya bermula dengan alif, hamzah dibubuh di atas alif itu. `di Asrama` menjadi `دأسراما`, bukan `داسراما`.
|
|
131
|
+
|
|
132
|
+
Kodpoint hamzah (U+0623) disahkan secara empirik daripada dataset, bukan diandaikan: `abai` bermula `ا` U+0627, `diabaikan` bermula `د` + `أ` U+0623. Corak sama pada `diambil`, `diajar`, `diurus`.
|
|
133
|
+
|
|
134
|
+
Bentuk bercantum tidak wujud sebagai entri kamus, jadi pembacaan songsang memisahkannya semula dan memulihkan hamzah kepada alif. Peraturan ini simetri.
|
|
135
|
+
|
|
136
|
+
Kata sendi **tidak** dicantum apabila kata berikutnya belum disahkan, kerana hasilnya akan menjadi Jawi bercantum dengan teks Rumi bertanda.
|
|
137
|
+
|
|
138
|
+
**§11 — kata serapan Arab, dua peringkat:**
|
|
139
|
+
|
|
140
|
+
| Seksyen | Jenis | Cara eja | Contoh |
|
|
141
|
+
|---|---|---|---|
|
|
142
|
+
| §11.1 | istilah khusus | ikut ejaan asal Arab | `wuduk`, `Qur'an`, `sunah`, `hadis`, `tayamum` |
|
|
143
|
+
| §11.2 | kata umum yang sudah terserap | ikut kaedah kata jati Melayu | `sabun` |
|
|
144
|
+
|
|
145
|
+
Pakej tidak perlu memilih antara dua ini. DBP sudah memilih, dan pilihan itu terkandung dalam ejaan yang dipulangkan PRPM. Ia didokumenkan supaya tiada siapa "membetulkan" `صلاة` kepada ejaan fonetik Melayu kemudian hari.
|
|
146
|
+
|
|
94
147
|
## Rantai kepercayaan
|
|
95
148
|
|
|
96
149
|
Setiap ejaan Jawi yang dikeluarkan membawa asal-usulnya. Jangan runtuhkan lapisan ini.
|
package/bin/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import { pasangSkill } from '../src/install.js'
|
|
|
6
6
|
import { banding, cariKamus } from '../src/kamus.js'
|
|
7
7
|
import { keJawi, keRumi } from '../src/tukar.js'
|
|
8
8
|
import { huraiTsv, muatDataset, simpanDataset } from '../src/dataset.js'
|
|
9
|
+
import { NAMA_PATH, muatNama, tambahNama } from '../src/nama.js'
|
|
9
10
|
import {
|
|
10
11
|
CACHE_PATH,
|
|
11
12
|
auditJawi,
|
|
@@ -26,6 +27,8 @@ const BANTUAN = `prpm-dbp — semak Bahasa Melayu dan Jawi terhadap PRPM DBP
|
|
|
26
27
|
npx prpm-dbp jawi <fail.txt> tukar teks Rumi ke Jawi ikut ejaan DBP
|
|
27
28
|
npx prpm-dbp rumi <fail.txt> tukar teks Jawi ke Rumi dari cache
|
|
28
29
|
npx prpm-dbp import-tsv <fail.tsv> import dataset rumi<TAB>jawi (dilabel bukan DBP)
|
|
30
|
+
npx prpm-dbp nama <rumi> <jawi> sahkan satu nama khas (tokoh, surah, tempat)
|
|
31
|
+
npx prpm-dbp nama senaraikan nama khas yang disahkan
|
|
29
32
|
npx prpm-dbp banding <kata...> silang semak PRPM lawan KamusDBP
|
|
30
33
|
npx prpm-dbp cache [--buang <kata>] status cache
|
|
31
34
|
npx prpm-dbp install [--link] pasang sebagai Claude Code skill
|
|
@@ -160,6 +163,12 @@ async function main() {
|
|
|
160
163
|
h.adaEntriTanpaJawi.join(', '),
|
|
161
164
|
)
|
|
162
165
|
}
|
|
166
|
+
if (h.namaKhas.length) {
|
|
167
|
+
console.error(
|
|
168
|
+
`nama khas belum disahkan (${h.namaKhas.length}): ${h.namaKhas.join(', ')}\n` +
|
|
169
|
+
` sahkan dengan: npx prpm-dbp nama <rumi> <jawi>`,
|
|
170
|
+
)
|
|
171
|
+
}
|
|
163
172
|
if (h.terbitanSah.length) {
|
|
164
173
|
console.error(
|
|
165
174
|
`terbitan sah tanpa ejaan Jawi (${h.terbitanSah.length}): ` +
|
|
@@ -183,6 +192,17 @@ async function main() {
|
|
|
183
192
|
break
|
|
184
193
|
}
|
|
185
194
|
|
|
195
|
+
case 'nama': {
|
|
196
|
+
if (baki.length >= 2) {
|
|
197
|
+
const rec = await tambahNama(baki[0], baki[1], { jenis: pilihan.jenis ?? null })
|
|
198
|
+
keluar({ disimpan: rec, fail: NAMA_PATH, nota: 'Ejaan ini datang dari anda, bukan dari DBP.' })
|
|
199
|
+
break
|
|
200
|
+
}
|
|
201
|
+
const peta = await muatNama()
|
|
202
|
+
keluar({ fail: NAMA_PATH, jumlah: Object.keys(peta).length, nama: peta })
|
|
203
|
+
break
|
|
204
|
+
}
|
|
205
|
+
|
|
186
206
|
case 'import-tsv': {
|
|
187
207
|
if (!baki[0]) throw new Error('perlu fail TSV: rumi<TAB>jawi setiap baris')
|
|
188
208
|
const { peta, dilangkau, jumlah } = huraiTsv(await readFile(baki[0], 'utf8'))
|
package/package.json
CHANGED
package/src/nama.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simpanan nama khas yang disahkan pengguna.
|
|
3
|
+
*
|
|
4
|
+
* Kenapa ini wujud: nama tokoh dan nama surah tiada sumber berwibawa yang
|
|
5
|
+
* boleh dicapai. Diuji terhadap PRPM, muhammad, ibrahim, musa, umar, aisyah
|
|
6
|
+
* dan khadijah semuanya TIADA entri. Dataset komuniti pula meliputi nama
|
|
7
|
+
* tempat (مکة, مسير, ڤاهڠ) tetapi bukan nama orang atau nama surah.
|
|
8
|
+
*
|
|
9
|
+
* Alat ini TIDAK mereka ejaan nama. Ia menyimpan apa yang pengguna sahkan
|
|
10
|
+
* sendiri, dengan sumber dicatat, supaya kerja pengesahan itu dibuat sekali
|
|
11
|
+
* sahaja dan boleh diaudit kemudian.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises'
|
|
15
|
+
import { dirname, join } from 'node:path'
|
|
16
|
+
|
|
17
|
+
import { CACHE_PATH } from './prpm.js'
|
|
18
|
+
|
|
19
|
+
export const NAMA_PATH = process.env.PRPM_NAMA ?? join(dirname(CACHE_PATH), 'nama-khas.json')
|
|
20
|
+
|
|
21
|
+
let dimuat = null
|
|
22
|
+
|
|
23
|
+
export async function muatNama() {
|
|
24
|
+
if (dimuat !== null) return dimuat
|
|
25
|
+
try {
|
|
26
|
+
dimuat = JSON.parse(await readFile(NAMA_PATH, 'utf8'))
|
|
27
|
+
} catch {
|
|
28
|
+
dimuat = {}
|
|
29
|
+
}
|
|
30
|
+
return dimuat
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function simpanNama(peta) {
|
|
34
|
+
await mkdir(dirname(NAMA_PATH), { recursive: true })
|
|
35
|
+
const tmp = `${NAMA_PATH}.tmp`
|
|
36
|
+
await writeFile(tmp, JSON.stringify(peta, null, 1), 'utf8')
|
|
37
|
+
await rename(tmp, NAMA_PATH)
|
|
38
|
+
dimuat = peta
|
|
39
|
+
return NAMA_PATH
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function tambahNama(rumi, jawi, { sumber = 'pengguna', jenis = null } = {}) {
|
|
43
|
+
const peta = { ...(await muatNama()) }
|
|
44
|
+
const kunci = String(rumi).trim().toLowerCase()
|
|
45
|
+
if (!kunci || !jawi) throw new Error('perlu rumi dan jawi')
|
|
46
|
+
peta[kunci] = { rumi: kunci, jawi: String(jawi).trim(), sumber, jenis }
|
|
47
|
+
await simpanNama(peta)
|
|
48
|
+
return peta[kunci]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function cariNama(kata) {
|
|
52
|
+
const peta = await muatNama()
|
|
53
|
+
const rec = peta[String(kata).trim().toLowerCase()]
|
|
54
|
+
if (!rec) return null
|
|
55
|
+
return { ...rec, dijumpai: true, disahkanDbp: false }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Teka sama ada perkataan itu nama khas.
|
|
60
|
+
*
|
|
61
|
+
* Huruf besar di TENGAH ayat ialah isyarat yang munasabah dalam teks Melayu.
|
|
62
|
+
* Ia sengaja tidak digunakan pada perkataan pertama ayat, kerana di situ
|
|
63
|
+
* huruf besar tidak bermakna apa-apa.
|
|
64
|
+
*/
|
|
65
|
+
export function mungkinNamaKhas(kata, sebelumnya) {
|
|
66
|
+
if (!/^[A-Z]/.test(kata)) return false
|
|
67
|
+
// Awal teks, atau selepas noktah, tanda soal, tanda seru, atau baris baru.
|
|
68
|
+
const awalAyat = !sebelumnya || /[.!?:\n]\s*$/.test(sebelumnya)
|
|
69
|
+
return !awalAyat
|
|
70
|
+
}
|
package/src/pedoman.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Peraturan daripada Pedoman Umum Ejaan Jawi Bahasa Melayu (DBP).
|
|
3
|
+
*
|
|
4
|
+
* Ini satu-satunya tempat dalam pakej yang MENJANA ejaan dan bukan sekadar
|
|
5
|
+
* mencarinya. Ia dibenarkan kerana setiap peraturan di sini datang daripada
|
|
6
|
+
* dokumen rasmi DBP dan dirujuk pada seksyennya, bukan direka.
|
|
7
|
+
*
|
|
8
|
+
* Sumber: Pedoman Umum Ejaan Jawi Bahasa Melayu, Dewan Bahasa dan Pustaka.
|
|
9
|
+
* Berasaskan Pedoman Ejaan Jawi yang Disempurnakan (1986, ed. 3 1993),
|
|
10
|
+
* hasil Konvensyen Tulisan Jawi Peringkat Kebangsaan 1984, diselaraskan
|
|
11
|
+
* 1991 dan 1993, disahkan Jawatankuasa Teknikal Ejaan Jawi 1993-1994.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const ALIF = 'ا' // ا
|
|
15
|
+
const ALIF_HAMZAH = 'أ' // أ
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* §14.1 — Kata sendi nama `di` dan `ke` ditulis sebagai SATU KATA dengan
|
|
19
|
+
* kata yang mengikutinya.
|
|
20
|
+
*
|
|
21
|
+
* Nota §14.1: jika kata yang mengikutinya bermula dengan huruf alif, huruf
|
|
22
|
+
* hamzah dibubuh di atas alif itu.
|
|
23
|
+
*
|
|
24
|
+
* Kodpoint hamzah disahkan secara empirik daripada dataset, bukan diandaikan:
|
|
25
|
+
* abai ا U+0627 ...
|
|
26
|
+
* diabaikan د + أ U+0623 ...
|
|
27
|
+
* Corak sama pada diambil, diajar, diurus.
|
|
28
|
+
*/
|
|
29
|
+
export const KATA_SENDI = new Map([
|
|
30
|
+
['di', 'د'], // د
|
|
31
|
+
['ke', 'ک'], // ک
|
|
32
|
+
])
|
|
33
|
+
|
|
34
|
+
export function bolehCantumSendi(kata) {
|
|
35
|
+
return KATA_SENDI.has(String(kata).toLowerCase())
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Cantumkan kata sendi dengan ejaan Jawi kata yang mengikutinya.
|
|
40
|
+
* Pulangkan null jika kata itu bukan kata sendi yang dicakupi.
|
|
41
|
+
*/
|
|
42
|
+
export function cantumSendi(kataSendi, jawiSelepas) {
|
|
43
|
+
const awalan = KATA_SENDI.get(String(kataSendi).toLowerCase())
|
|
44
|
+
if (!awalan || !jawiSelepas) return null
|
|
45
|
+
|
|
46
|
+
const selepas = jawiSelepas.startsWith(ALIF)
|
|
47
|
+
? ALIF_HAMZAH + jawiSelepas.slice(ALIF.length)
|
|
48
|
+
: jawiSelepas
|
|
49
|
+
|
|
50
|
+
return { jawi: awalan + selepas, rujukan: 'Pedoman DBP §14.1' }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* §11 — Kata serapan Arab dieja dalam dua cara berbeza:
|
|
55
|
+
* §11.1 istilah khusus -> ikut ejaan asal bahasa Arab (wuduk, Qur'an,
|
|
56
|
+
* sunah, hadis, tayamum, wuquf, reda)
|
|
57
|
+
* §11.2 kata umum yang -> ikut cara mengeja kata jati Melayu (sabun)
|
|
58
|
+
* sudah terserap
|
|
59
|
+
*
|
|
60
|
+
* Pakej ini tidak perlu memilih antara dua ini: DBP sudah memilih, dan
|
|
61
|
+
* pilihan itu terkandung dalam ejaan yang dipulangkan PRPM. Peraturan ini
|
|
62
|
+
* didokumenkan di sini supaya tiada siapa "membetulkan" صلاة kepada ejaan
|
|
63
|
+
* fonetik Melayu kemudian hari.
|
|
64
|
+
*/
|
|
65
|
+
export const NOTA_SERAPAN_ARAB = 'Pedoman DBP §11.1 dan §11.2'
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Songsangan §14.1: pisahkan kata sendi yang bercantum.
|
|
69
|
+
*
|
|
70
|
+
* Bentuk bercantum seperti دمکة tidak wujud sebagai entri kamus, jadi
|
|
71
|
+
* pembacaan songsang mesti mencubanya sendiri. Hamzah dipulihkan kepada
|
|
72
|
+
* alif kerana hamzah itu ditambah oleh peraturan, bukan sebahagian ejaan
|
|
73
|
+
* kata dasar.
|
|
74
|
+
*/
|
|
75
|
+
export function pisahSendi(jawi) {
|
|
76
|
+
const calon = []
|
|
77
|
+
for (const [rumi, awalan] of KATA_SENDI) {
|
|
78
|
+
if (!jawi.startsWith(awalan) || jawi.length <= awalan.length) continue
|
|
79
|
+
let baki = jawi.slice(awalan.length)
|
|
80
|
+
if (baki.startsWith(ALIF_HAMZAH)) baki = ALIF + baki.slice(ALIF_HAMZAH.length)
|
|
81
|
+
calon.push({ sendi: rumi, baki, rujukan: 'Pedoman DBP §14.1' })
|
|
82
|
+
}
|
|
83
|
+
return calon
|
|
84
|
+
}
|
package/src/tukar.js
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
import { lookup } from './prpm.js'
|
|
12
12
|
import { normalisasiJawi } from './kamus.js'
|
|
13
13
|
import { cariDataset, muatDataset } from './dataset.js'
|
|
14
|
+
import { cariNama, mungkinNamaKhas } from './nama.js'
|
|
15
|
+
import { bolehCantumSendi, cantumSendi, pisahSendi } from './pedoman.js'
|
|
14
16
|
|
|
15
17
|
// Baris tanda vokal Arab (fathah, kasrah, dammah, sukun, syaddah, tanwin,
|
|
16
18
|
// alef superscript). Jawi Melayu TIDAK menggunakannya; teks al-Quran dan
|
|
@@ -130,6 +132,8 @@ export async function keJawi(teks, cache, opts = {}) {
|
|
|
130
132
|
const dariDataset = []
|
|
131
133
|
const dbp = []
|
|
132
134
|
const adaEntriTanpaJawi = []
|
|
135
|
+
const dariNama = []
|
|
136
|
+
const namaKhas = []
|
|
133
137
|
const bahagian = teks.split(PECAH_RUMI)
|
|
134
138
|
const keluar = []
|
|
135
139
|
|
|
@@ -155,6 +159,14 @@ export async function keJawi(teks, cache, opts = {}) {
|
|
|
155
159
|
}
|
|
156
160
|
}
|
|
157
161
|
|
|
162
|
+
// Nama khas yang pengguna sudah sahkan sendiri.
|
|
163
|
+
const nm = await cariNama(cebis)
|
|
164
|
+
if (nm?.jawi) {
|
|
165
|
+
dariNama.push({ kata: cebis, jawi: nm.jawi })
|
|
166
|
+
keluar.push(nm.jawi)
|
|
167
|
+
continue
|
|
168
|
+
}
|
|
169
|
+
|
|
158
170
|
if (cubaDasar) {
|
|
159
171
|
const dasar = await cariDasar(cebis.toLowerCase(), cache, opts)
|
|
160
172
|
if (dasar) {
|
|
@@ -166,18 +178,43 @@ export async function keJawi(teks, cache, opts = {}) {
|
|
|
166
178
|
}
|
|
167
179
|
}
|
|
168
180
|
|
|
169
|
-
|
|
181
|
+
// Nama khas yang belum disahkan bukan salah eja. Ia dilaporkan
|
|
182
|
+
// berasingan supaya pengguna tahu apa yang perlu disahkan sekali, dan
|
|
183
|
+
// bukan mengulang menyemak ejaan yang memang betul.
|
|
184
|
+
if (mungkinNamaKhas(cebis, bahagian[i - 1])) namaKhas.push(cebis)
|
|
185
|
+
else belumDisahkan.push(cebis)
|
|
170
186
|
keluar.push(penanda[0] + cebis + penanda[1])
|
|
171
187
|
}
|
|
172
188
|
|
|
189
|
+
// Pedoman DBP §14.1: kata sendi di dan ke bercantum dengan kata berikutnya.
|
|
190
|
+
// Dibuat sebagai lulusan kedua supaya logik carian di atas kekal mudah.
|
|
191
|
+
const sendiDicantum = []
|
|
192
|
+
for (let k = 1; k < keluar.length - 2; k += 2) {
|
|
193
|
+
const asal = bahagian[k]
|
|
194
|
+
if (!bolehCantumSendi(asal)) continue
|
|
195
|
+
if (!/^\s+$/.test(keluar[k + 1])) continue
|
|
196
|
+
const seterusnya = keluar[k + 2]
|
|
197
|
+
// Hanya cantum bila kata berikutnya benar-benar bertukar, bukan ditanda.
|
|
198
|
+
if (!seterusnya || seterusnya.startsWith(penanda[0])) continue
|
|
199
|
+
const gabung = cantumSendi(asal, seterusnya)
|
|
200
|
+
if (!gabung) continue
|
|
201
|
+
sendiDicantum.push({ sendi: asal, jawi: gabung.jawi, rujukan: gabung.rujukan })
|
|
202
|
+
keluar[k] = gabung.jawi
|
|
203
|
+
keluar[k + 1] = ''
|
|
204
|
+
keluar[k + 2] = ''
|
|
205
|
+
}
|
|
206
|
+
|
|
173
207
|
return {
|
|
174
208
|
teks: keluar.join(''),
|
|
209
|
+
sendiDicantum,
|
|
175
210
|
disahkanDbp: dbp.length,
|
|
176
211
|
dariDataset,
|
|
212
|
+
dariNama,
|
|
213
|
+
namaKhas: [...new Set(namaKhas)],
|
|
177
214
|
adaEntriTanpaJawi: [...new Set(adaEntriTanpaJawi)],
|
|
178
215
|
belumDisahkan: [...new Set(belumDisahkan)],
|
|
179
216
|
terbitanSah,
|
|
180
|
-
lengkap: belumDisahkan.length === 0 && terbitanSah.length === 0,
|
|
217
|
+
lengkap: belumDisahkan.length === 0 && terbitanSah.length === 0 && namaKhas.length === 0,
|
|
181
218
|
// Sepenuhnya DBP bermakna setiap perkataan datang dari sumber rasmi.
|
|
182
219
|
semuanyaDbp: dariDataset.length === 0 && belumDisahkan.length === 0 && terbitanSah.length === 0,
|
|
183
220
|
}
|
|
@@ -195,6 +232,7 @@ export function keRumi(teksJawi, cache, { penanda = ['«', '»'], dataset = null
|
|
|
195
232
|
const tidakDikenali = []
|
|
196
233
|
const kabur = []
|
|
197
234
|
const arab = []
|
|
235
|
+
const sendiDipisah = []
|
|
198
236
|
const bahagian = teksJawi.split(PECAH_JAWI)
|
|
199
237
|
const keluar = []
|
|
200
238
|
|
|
@@ -232,6 +270,15 @@ export function keRumi(teksJawi, cache, { penanda = ['«', '»'], dataset = null
|
|
|
232
270
|
}
|
|
233
271
|
|
|
234
272
|
if (!padanan) {
|
|
273
|
+
// Pedoman DBP §14.1 songsang: bentuk bercantum seperti دمکة tiada
|
|
274
|
+
// dalam kamus, jadi cuba pisahkan kata sendi di hadapan.
|
|
275
|
+
let dipisah = null
|
|
276
|
+
for (const calon of pisahSendi(bahagian[i])) {
|
|
277
|
+
const jumpa = peta.get(normalisasiJawi(calon.baki))
|
|
278
|
+
if (jumpa?.length === 1) { dipisah = calon.sendi + ' ' + jumpa[0]; break }
|
|
279
|
+
}
|
|
280
|
+
if (dipisah) { keluar.push(dipisah); sendiDipisah.push(bahagian[i]); continue }
|
|
281
|
+
|
|
235
282
|
tidakDikenali.push(bahagian[i])
|
|
236
283
|
keluar.push(penanda[0] + bahagian[i] + penanda[1])
|
|
237
284
|
continue
|
|
@@ -250,6 +297,7 @@ export function keRumi(teksJawi, cache, { penanda = ['«', '»'], dataset = null
|
|
|
250
297
|
tidakDikenali: [...new Set(tidakDikenali)],
|
|
251
298
|
kabur,
|
|
252
299
|
arab: [...new Set(arab)],
|
|
300
|
+
sendiDipisah,
|
|
253
301
|
saizPeta: peta.size,
|
|
254
302
|
lengkap: tidakDikenali.length === 0,
|
|
255
303
|
}
|