npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

egypt-geo-navigator

v1.0.0

Published

Bilingual (Arabic/English) administrative address library of Egypt (Governorates, Districts/Markaz, Villages/Neighborhoods) for Node.js, React, and MongoDB.

Readme

Egypt Geo Navigator

A lightweight, bilingual (Arabic & English) administrative address database and API for Egypt (Governorates ➔ Districts/Markaz/Qism ➔ Villages/Neighborhoods). Built with Node.js, React, MongoDB, and TypeScript.

Features:

  • 100% complete coverage: Includes all 27 Governorates, 173 Districts, and 12,067 Villages & Neighborhoods.
  • Bilingual names: Every record has correct Arabic (nameAr) and English (nameEn) names, using advanced phonetic transliteration for records missing Arabic data in GeoNames.
  • Geospatial coordinates: Includes latitude and longitude coordinates for districts and locations.
  • Nearest-neighbor mapping: Every village is automatically mapped to its closest administrative district center.
  • Ready for MongoDB: Generates a flat JSON array structured for direct MongoDB import.
  • Bilingual Autocomplete Search: In-memory prefix search for dropdown inputs in React.
  • Geolocation support: Query closest locations by latitude and longitude.

📦 Project Structure

  • data/
    • egypt-hierarchy.json: Hierarchical structure (Governorates ➔ Districts ➔ Locations) perfect for cascading dropdowns in React.
    • egypt-locations-mongo.json: Flat JSON array ready to be imported into MongoDB.
  • src/
    • consts.py: Curated governorate name constants.
    • transliterate.py: Phonetic Romanized-to-Arabic place name transliterator.
    • parser.py: Python processing engine that parses GeoNames EG.txt and exports database files.
  • dist/: Compiled TypeScript library.
  • index.ts: TypeScript library interface and query functions.
  • tests/: Automated Python and Node integration test suites.

💾 MongoDB Integration

You can easily load the data into your MongoDB database.

1. Import with mongoimport

Run the following command in your terminal to import the flat JSON array directly into a MongoDB collection (e.g. locations in database erp):

mongoimport --db erp --collection locations --file data/egypt-locations-mongo.json --jsonArray --drop

2. Mongoose Schema Definition (TypeScript)

Define your schema and TypeScript interfaces in your Node.js backend:

import { Schema, model, Document } from 'mongoose';

export interface IEgyptLocation extends Document {
  _id: string; // E.g., "gov_09", "dist_345955", "loc_346077"
  name: {
    ar: string;
    en: string;
  };
  type: 'governorate' | 'district' | 'village' | 'neighborhood';
  coordinates?: {
    lat: number;
    lng: number;
  };
  parentId?: string; // Links to parent _id
  hierarchy: {
    governorate: {
      id: string;
      nameAr: string;
      nameEn: string;
    };
    district?: {
      id: string;
      nameAr: string;
      nameEn: string;
    };
  };
}

const EgyptLocationSchema = new Schema<IEgyptLocation>({
  _id: { type: String, required: true },
  name: {
    ar: { type: String, required: true },
    en: { type: String, required: true }
  },
  type: { type: String, enum: ['governorate', 'district', 'village', 'neighborhood'], required: true },
  coordinates: {
    lat: { type: Number },
    lng: { type: Number }
  },
  parentId: { type: String },
  hierarchy: {
    governorate: {
      id: { type: String, required: true },
      nameAr: { type: String, required: true },
      nameEn: { type: String, required: true }
    },
    district: {
      id: { type: String },
      nameAr: { type: String },
      nameEn: { type: String }
    }
  }
});

// Create text index for bilingual search in MongoDB
EgyptLocationSchema.index({ 'name.ar': 'text', 'name.en': 'text' });

export const EgyptLocation = model<IEgyptLocation>('Location', EgyptLocationSchema);

⚡ React & Node.js Library API (Highly Optimized)

The package provides TypeScript query functions. Statically imported metadata is synchronous, while larger datasets are asynchronously lazyloaded on-demand to keep your frontend bundle footprint extremely small (less than 20KB!).

Import the library

import { 
  getGovernorates, 
  getDistricts, 
  getLocations, 
  search, 
  getNearestLocations 
} from 'egypt-geo-navigator';

1. Cascading Dropdowns in React (Code-Split)

// 1. Load all governorates for the first select field (Synchronous: ~1.5KB)
const governorates = getGovernorates();
// Output: [{ id: "09", nameAr: "المنوفية", nameEn: "Monufia" }, ...]

// 2. Load districts when a governorate is selected (Synchronous: ~1KB)
const districts = getDistricts("09");
// Output: [{ id: "345955", nameAr: "الباجور", nameEn: "Al Bajur", coordinates: { lat: 30.42, lng: 31.05 } }, ...]

// 3. Load villages when a district is selected (Asynchronous: dynamically loads gov-09.json chunk ~100KB)
const villages = await getLocations("09", "345955");
// Output: [{ id: "346077", nameAr: "زاوية جروان", nameEn: "Zawiyat Jarwan", type: "village", coordinates: { lat: 30.44, lng: 31.03 } }, ...]

2. Autocomplete Bilingual Search (Asynchronous)

Instantly search across all governorates, districts, and villages. Lazy-loads the full hierarchy on-demand:

const results = await search("دمنهور");
// Or search in English:
const resultsEn = await search("tanta");

3. Geolocation & Shipping Distance (Asynchronous)

Find the nearest villages or branches to a customer's location. Lazy-loads the full hierarchy on-demand:

// Query closest locations to coordinates (lat, lng)
const nearest = await getNearestLocations(29.9792, 31.1342, 3);
// Output:
// [
//   { id: "346002", nameAr: "نزلة السمان", nameEn: "Nazlat As Samman", distanceKm: 0.47, ... },
//   ...
// ]

🧪 Testing

Run Python tests:

python -m unittest tests/test_parser.py

Run Node integration tests:

node tests/test_library.js

🤝 Contributing

We welcome contributions from the community! If you find any misspelled place name (Arabic or English), formatting error, or missing location:

  1. Open an Issue: Report the incorrect place name with its correct spelling.
  2. Submit a Pull Request (PR): Feel free to submit a PR correcting the spelling in the source files.

For major features or database updates, please open an issue first to discuss your proposed changes.


📄 License

This project is licensed under the MIT License - see the LICENSE file for details.