Skip to main content

🏝️ NusaNLP: Low-Resource NLP Toolkit for West Nusa Tenggara, Indonesia

PyPI Version Python 3.9+ License: MIT Tests: 147 passed Coverage: 82%

NusaNLP is an open-source Natural Language Processing (NLP) toolkit engineered specifically for the regional languages of West Nusa Tenggara (Nusa Tenggara Barat / NTB) and Bahasa Indonesia:

  1. Bahasa Sasak (sasak) — Spoken by ~3 million people across the island of Lombok.
  2. Bahasa Samawa / Sumbawa (samawa) — Spoken in Sumbawa and West Sumbawa regencies.
  3. Bahasa Mbojo / Bima (mbojo) — Spoken in Bima Regency, Bima City, and Dompu Regency.
  4. Bahasa Indonesia (indonesian) — Fully integrated with tokenization, clitic handling, stopword filtering, morphological stemming, language identification (100% test accuracy), and bilingual translation alignment.

NusaNLP is built to be production-ready, modular, extensible via a plugin language registry, and research-grade.


📦 Installation

Install NusaNLP directly from PyPI using pip:

pip install nusanlp

Optional Feature Sets

# REST API (FastAPI + Uvicorn server)
pip install "nusanlp[api]"

# Machine Learning additions (Scikit-Learn vectorizers & metrics)
pip install "nusanlp[ml]"

# Development, testing, and linting tools
pip install "nusanlp[dev]"

# All optional dependencies
pip install "nusanlp[api,ml,dev]"

From Source (For Development & Research)

git clone https://github.com/kodetr/nusanlp.git
cd nusanlp
pip install -e ".[dev]"

🚀 Quick Start

1. Unified Pipeline (with Auto-Detection)

import nusanlp
from nusanlp import Pipeline

# Initialize pipeline with automatic language detection
nlp = Pipeline(language="auto")

result = nlp.process("Tiang lalo mangan leq bale")
print(result)

Output:

{
  "language": "sasak",
  "original_text": "Tiang lalo mangan leq bale",
  "normalized_text": "tiang lalo mangan leq bale",
  "tokens": ["tiang", "lalo", "mangan", "leq", "bale"],
  "tokens_without_stopwords": ["lalo", "mangan", "bale"],
  "analysis": [
    {"word": "tiang", "root": "tiang", "prefix": null, "suffix": null, "features": []},
    {"word": "lalo", "root": "lalo", "prefix": null, "suffix": null, "features": []},
    {"word": "mangan", "root": "ang", "prefix": "m", "suffix": "an", "features": ["SUFF:an", "PREF:m"]},
    {"word": "leq", "root": "leq", "prefix": null, "suffix": null, "features": []},
    {"word": "bale", "root": "bal", "prefix": null, "suffix": "e", "features": ["SUFF:e"]}
  ],
  "pos_tags": [
    ["tiang", "NOUN"],
    ["lalo", "VERB"],
    ["mangan", "VERB"],
    ["leq", "ADP"],
    ["bale", "NOUN"]
  ]
}

2. Language Detection

Detect whether a sentence is Sasak, Samawa, Mbojo, or Indonesian:

import nusanlp

res = nusanlp.detect_language("Tiang lalo leq peken")
print(res)
# {'language': 'sasak', 'confidence': 1.0}

res_smw = nusanlp.detect_language("Kaji lalo tama ko peken ling ina")
print(res_smw)
# {'language': 'samawa', 'confidence': 1.0}

res_mbj = nusanlp.detect_language("Nahu ngaha di uma labo ita")
print(res_mbj)
# {'language': 'mbojo', 'confidence': 1.0}

3. Text Normalization

# Lowercasing, whitespace, repeated character & slang normalization
norm = nusanlp.normalize("AQ   LEKOOOOK  GATI", language="sasak")
print(norm)
# Output: "aku lekook gati"

4. Modular Tokenizer & Clitic Separation

tokens = nusanlp.tokenize("Kaji lalo-mo ko peken", language="samawa")
print(tokens)
# Output: ['Kaji', 'lalo', '-mo', 'ko', 'peken']

5. Stopword Removal

clean = nusanlp.remove_stopwords("nahu ngaha di uma labo ita", language="mbojo")
print(clean)
# Output: ['ngaha', 'uma']

6. Multilingual Dictionary Lookup

entry = nusanlp.lookup("mangan", language="sasak")
print(entry)
# {'word': 'mangan', 'language': 'sasak', 'translations': {'indonesian': 'makan'}, 'pos': 'VERB', 'lemma': 'mangan'}

entry_smw = nusanlp.lookup("balong", language="samawa")
print(entry_smw)
# {'word': 'balong', 'language': 'samawa', 'translations': {'indonesian': 'baik / bagus', 'english': 'good'}, 'pos': 'ADJ', 'lemma': 'balong'}

7. Machine Learning & TF-IDF Integration (Scikit-Learn)

NusaNLP seamlessly integrates into TfidfVectorizer and CountVectorizer, providing morphological lemmatization and low-resource stopword removal to prevent vocabulary explosion:

from sklearn.feature_extraction.text import TfidfVectorizer
import nusanlp

corpus = [
    "Tiang lalo mangan leq bale adat Sasak.",
    "Kaji mangan leq bale adat Samawa.",
    "Nahu ngaha di uma rime Mbojo."
]

# Method A: Use NusaNLP custom tokenizer callable directly
vectorizer = TfidfVectorizer(tokenizer=nusanlp.get_tfidf_tokenizer(), lowercase=False)
X = vectorizer.fit_transform(corpus)
print("TF-IDF Features:", vectorizer.get_feature_names_out())

# Method B: Preprocess texts beforehand
clean_docs = [nusanlp.preprocess_for_tfidf(doc) for doc in corpus]
# clean_docs: ['mangan bale adat sasak', 'mangan bale adat samawa', 'ngaha uma rime mbojo']

🏛️ Architecture & Project Structure

nusanlp/
│
├── src/
│   ├── nusanlp/
│   │   ├── __init__.py                 # Unified API exports
│   │   ├── core/
│   │   │   ├── pipeline.py             # Unified Pipeline engine
│   │   │   ├── language.py             # BaseLanguage & LanguageRegistry
│   │   │   ├── config.py               # Pipeline & Normalizer configs
│   │   │   └── types.py                # Pydantic models & enums
│   │   │
│   │   ├── languages/
│   │   │   ├── base.py                 # AbstractLanguageHandler
│   │   │   ├── sasak/                  # Sasak modules
│   │   │   ├── samawa/                 # Samawa (Sumbawa) modules
│   │   │   ├── mbojo/                  # Mbojo (Bima) modules
│   │   │   └── indonesian/             # Indonesian language module
│   │   │
│   │   ├── preprocessing/
│   │   │   ├── normalize.py            # Multi-language normalization
│   │   │   └── clean.py                # Text cleaning utilities
│   │   │
│   │   ├── tokenization/
│   │   │   └── tokenizer.py            # RuleBasedTokenizer
│   │   │
│   │   ├── morphology/
│   │   │   └── analyzer.py             # MorphologicalAnalyzer
│   │   │
│   │   ├── lexicon/
│   │   │   ├── dictionary.py           # Multilingual dictionary
│   │   │   └── loader.py               # JSON/CSV loaders
│   │   │
│   │   ├── language_detection/
│   │   │   ├── detector.py             # detect_language API
│   │   │   └── model.py                # N-gram Statistical Classifier
│   │   │
│   │   ├── cli/
│   │   │   └── main.py                 # CLI entry point
│   │   │
│   │   ├── api/
│   │   │   └── app.py                  # FastAPI REST API
│   │   │
│   │   └── utils/
│   │       ├── loaders.py              # Resource discovery
│   │       └── validators.py           # Pydantic data validators
│   │
│   └── sasaknlp/                       # Backward-compatibility layer
│
├── resources/
│   ├── sasak/                          # Balai Bahasa NTB lexicon & stopwords
│   ├── samawa/                         # Sumbawa lexicon & stopwords
│   └── mbojo/                          # Bima/Dompu lexicon & stopwords
│
├── datasets/
├── training/                           # Language detector training scripts
├── tests/                              # 134 automated unit tests
├── examples/                           # Usage examples
└── pyproject.toml

💻 Command Line Interface (CLI)

# Language Detection
nusanlp detect "Tiang lalo leq peken"

# Tokenize
nusanlp tokenize --lang sasak "Tiang lalo leq peken"

# Normalize
nusanlp normalize --lang mbojo "NAHU MAI DI KAMPUNG"

# Dictionary Lookup
nusanlp dictionary lookup --lang samawa "bale"

# End-to-end Process
nusanlp process --lang auto "Tiang lalo mangan leq bale" --json

🌐 REST API

Run the optional FastAPI server:

uvicorn nusanlp.api.app:app --host 127.0.0.1 --port 8000 --reload

Endpoints available:

  • POST /detect-language
  • POST /tokenize
  • POST /normalize
  • POST /process
  • GET /dictionary/{language}/{word}
  • GET /docs (Interactive Swagger UI)

🧪 Testing & Evaluation

Run test suite with pytest:

pytest tests -v

Run unified scientific evaluation benchmark across all 3 languages:

python3 scripts/evaluate_nusanlp_all.py

📊 Scientific Evaluation Highlights

NusaNLP has undergone rigorous empirical validation across 30,000 morphological pairs and 3,000 language detection sentences:

Evaluation Dimension Dataset Metric Score
Sasak Stemmer Benchmark 10k Exact Match Accuracy 93.23% (11,279 words/s)
Samawa Stemmer Benchmark 10k Exact Match Accuracy 94.65% (43,365 words/s)
Mbojo Stemmer Benchmark 10k Exact Match Accuracy 93.22% (42,836 words/s)
Language Identification Test Set 3,000 sentences Global Accuracy 99.90% (Macro-F1: 99.90%)
Pipeline Latency Authentic Sentences Mean Latency 0.038 - 0.139 ms / sentence
Downstream TF-IDF ML Multi-dialect Corpus Vocabulary Compression 9.9% feature reduction (100% Acc)

See the complete evaluation report in docs/laporan_evaluasi_nusanlp.md.


📚 Datasets & Resources

  • Total Dataset Volume: 959,279 records (Sentence corpora, morphology benchmarks, language detection, and official dictionaries).
  • Official Dictionaries (Balai Bahasa NTB): 3,352 Sasak, 659 Samawa, 2,777 Mbojo entries (100% Pydantic compliant).
  • Curated Stopwords: 440 functional words (159 Sasak, 147 Samawa, 134 Mbojo).
  • See detailed documentation in datasets/README.md and docs/PANDUAN_LENGKAP.md.

📖 Citation

If you use NusaNLP in your academic work or research, please cite:

@software{nusanlp2026,
  author = {NusaNLP Contributors},
  title = {NusaNLP: An Open-Source Natural Language Processing Toolkit for Low-Resource Languages of West Nusa Tenggara, Indonesia},
  year = {2026},
  url = {https://github.com/kodetr/nusanlp}
}

📄 License

Distributed under the MIT License. See LICENSE for details.

Metadata

Release files for nusanlp 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nusanlp 0.2.1
File Size Uploaded Provenance
nusanlp-0.2.1.tar.gz 603.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for nusanlp 0.2.1
File Interpreter ABI Platform
nusanlp-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 1.3 MB

Release files / nusanlp-0.2.1.tar.gz

Download URL nusanlp-0.2.1.tar.gz
Size 603.0 kB
Tags Source
SHA-256 checksum
How to use checksums
ab4f3d184c8fdbb9f8aeb5c33b4e5019f482ce8c070d838ac617ffad351c5454
BLAKE2b-256 checksum
How to use checksums
333f15edf59e3d496000a68933cbb584bfbedccae89972d7e2ad71b9cf6fd279
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.0

Release files / nusanlp-0.2.1-py3-none-any.whl

Download URL nusanlp-0.2.1-py3-none-any.whl
Size 656.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
900a0f222cd5460a15ea58c28578afb957891c83d06f469c914ee839ef9211e1
BLAKE2b-256 checksum
How to use checksums
b1f6dec17663bb6b6230b6419bdb9db6e35fbe1572efdf391b08df4dbce51f7b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.0

Security for nusanlp 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page