Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 142 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# vn-number 🇻🇳
# vn-number

🛠 A bunch of utility functions that work with number in 🇻🇳 Vietnamese language
A bunch of utility functions that work with numbers in Vietnamese language.

[![Publish](https://github.com/hckhanh/vn-number/actions/workflows/publish.yml/badge.svg)](https://github.com/hckhanh/vn-number/actions/workflows/publish.yml)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=hckhanh_vn-number&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=hckhanh_vn-number)
Expand All @@ -14,45 +14,167 @@
- Built-in support for Edge runtime
- Typesafe with TypeScript
- Fully documented
- Works with `number`, `string`, and `bigint` types
- Handles very large numbers (up to quintillions)

## Functions
## Installation

### Read Vietnamese number
```bash
npm install vn-number
```

```bash
deno add jsr:@hckhanh/vn-number
```

## Quick Start

### Read Vietnamese Numbers

Convert numbers to Vietnamese text:

```ts
import { readVnNumber } from 'vn-number'

readVnNumber(1250000)
// Output: "một triệu hai trăm năm mươi nghìn"

readVnNumber(15)
// Output: "mười lăm"

readVnNumber(21)
// Output: "hai mươi mốt"
```

### Format Numbers in Vietnamese Style

Format numbers with Vietnamese thousand separators (dots):

```ts
import { formatVnNumber } from 'vn-number'

formatVnNumber(1250000)
// Output: "1.250.000"

formatVnNumber(BigInt('9999999999999999'))
// Output: "9.999.999.999.999.999"
```

### Format Vietnamese Currency (VND)

Format numbers as Vietnamese Dong currency:

```ts
import { formatVnCurrency } from 'vn-number'

formatVnCurrency(1250000)
// Output: "1.250.000 ₫"

formatVnCurrency(null, 'Không giới hạn')
// Output: "Không giới hạn"
```

### Format Percentages

Format numbers as Vietnamese-style percentages:

```ts
import { readVnNumber } from '@hckhanh/vn-number'
import { formatVnPercent } from 'vn-number'

formatVnPercent(0.991)
// Output: "99,1%"

const result = readVnNumber(1250000)
console.log(result) // một triệu hai trăm năm mươi nghìn
formatVnPercent(0.5)
// Output: "50%"
```

### Format number in Vietnamese format
## Documentation

For detailed documentation, examples, and API reference, visit:

**[https://vn-number.khanh.id](https://vn-number.khanh.id)**

## Common Use Cases

### E-commerce

```ts
import { formatVnNumber } from '@hckhanh/vn-number'
import { formatVnCurrency, readVnNumber } from 'vn-number'

const price = 1500000

console.log(formatVnCurrency(price))
// Output: "1.500.000 ₫"

const result = formatVnNumber(1250000)
console.log(result) // 1.250.000
console.log(readVnNumber(price))
// Output: "một triệu năm trăm nghìn"
```

### Format VN currency (VND - ₫)
### Banking and Financial Documents

```ts
import { formatVnCurrency } from '@hckhanh/vn-number'
import { readVnNumber, formatVnCurrency } from 'vn-number'

const result = formatVnCurrency(1250000)
console.log(result) // 1.250.000 ₫
const amount = 2450000

console.log(`Số tiền: ${formatVnCurrency(amount)}`)
// Output: "Số tiền: 2.450.000 ₫"

console.log(`Bằng chữ: ${readVnNumber(amount)} đồng`)
// Output: "Bằng chữ: hai triệu bốn trăm năm mươi nghìn đồng"
```

### Format percentage in Vietnamese format
### Data Visualization

```ts
import { formatVnPercent } from '@hckhanh/vn-number'
import { formatVnNumber, formatVnPercent } from 'vn-number'

const totalUsers = 1234567
const growthRate = 0.157

const result = formatVnPercent(0.991)
console.log(result) // 99,1%
console.log(`Tổng người dùng: ${formatVnNumber(totalUsers)}`)
// Output: "Tổng người dùng: 1.234.567"

console.log(`Tăng trưởng: ${formatVnPercent(growthRate)}`)
// Output: "Tăng trưởng: 15,7%"
```

## Vietnamese Language Rules

The `readVnNumber` function follows Vietnamese language conventions:

- **"lăm" rule**: 15 → "mười lăm", 25 → "hai mươi lăm"
- **"mốt" rule**: 21 → "hai mươi mốt", 31 → "ba mươi mốt"
- **"lẻ" rule**: 101 → "một trăm lẻ một", 305 → "ba trăm lẻ năm"
- **Zero handling**: 1001 → "một nghìn không trăm lẻ một"

## API Functions

| Function | Description | Example |
|----------|-------------|---------|
| `readVnNumber(number)` | Convert number to Vietnamese text | `readVnNumber(1250000)` → `"một triệu hai trăm năm mươi nghìn"` |
| `formatVnNumber(number, fallback?)` | Format number in Vietnamese style | `formatVnNumber(1250000)` → `"1.250.000"` |
| `formatVnCurrency(money, fallback?)` | Format as VND currency | `formatVnCurrency(1250000)` → `"1.250.000 ₫"` |
| `formatVnPercent(value, fallback?)` | Format as percentage | `formatVnPercent(0.991)` → `"99,1%"` |

## Browser and Runtime Compatibility

- ✅ Node.js 14+
- ✅ Bun
- ✅ Deno
- ✅ Modern browsers (Chrome, Firefox, Safari, Edge)
- ✅ React Native
- ✅ Electron
- ✅ Edge Runtime (Vercel, Cloudflare Workers, etc.)

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

MIT © [Khánh Hoàng](https://www.khanh.id)

## Release Notes

You can go to [the Releases](https://github.com/hckhanh/vn-number/releases) page to see the release notes.
See [Releases](https://github.com/hckhanh/vn-number/releases) for changelog and release notes.
26 changes: 26 additions & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# deps
/node_modules

# generated content
.source

# test & build
/coverage
/.next/
/out/
/build
*.tsbuildinfo

# misc
.DS_Store
*.pem
/.pnp
.pnp.js
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# others
.env*.local
.vercel
next-env.d.ts
45 changes: 45 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# web

This is a Next.js application generated with
[Create Fumadocs](https://github.com/fuma-nama/fumadocs).

Run development server:

```bash
npm run dev
# or
pnpm dev
# or
yarn dev
```

Open http://localhost:3000 with your browser to see the result.

## Explore

In the project, you can see:

- `lib/source.ts`: Code for content source adapter, [`loader()`](https://fumadocs.dev/docs/headless/source-api) provides the interface to access your content.
- `lib/layout.shared.tsx`: Shared options for layouts, optional but preferred to keep.

| Route | Description |
| ------------------------- | ------------------------------------------------------ |
| `app/(home)` | The route group for your landing page and other pages. |
| `app/docs` | The documentation layout and pages. |
| `app/api/search/route.ts` | The Route Handler for search. |

### Fumadocs MDX

A `source.config.ts` config file has been included, you can customise different options like frontmatter schema.

Read the [Introduction](https://fumadocs.dev/docs/mdx) for further details.

## Learn More

To learn more about Next.js and Fumadocs, take a look at the following
resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js
features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
- [Fumadocs](https://fumadocs.dev) - learn about Fumadocs
45 changes: 45 additions & 0 deletions docs/biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"$schema": "../node_modules/@biomejs/biome/configuration_schema.json",
"extends": "//",
"root": false,
"files": {
"ignoreUnknown": true,
"includes": ["**", "!node_modules", "!.next", "!dist", "!build", "!.source"]
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"style": {
"useConsistentCurlyBraces": {
"level": "warn",
"fix": "safe"
}
},
"security": {
"noDangerouslySetInnerHtml": "off"
}
},
"domains": {
"next": "recommended",
"react": "recommended"
}
},
"assist": {
"actions": {
"source": {
"useSortedAttributes": "on"
}
}
},
"css": {
"parser": {
"tailwindDirectives": true
}
},
"javascript": {
"formatter": {
"jsxQuoteStyle": "single"
}
}
}
Loading
Loading