Repository: joke2k/faker (language: python)

Issue:
Add Provider for vi_VN (Vietnamese)
* Faker version: Any
* OS: Any

Currently, the Faker library does not provide support for Vietnamese locale (vi_VN). To improve the localization and make it more useful for Vietnamese users, we should add a provider for Vietnamese names and other locale-specific data.

### Steps to reproduce

```
from faker import Faker
fake = Faker("vi_VN")
```

### Expected behavior

The provider should generate realistic Vietnamese names and other locale-specific data, such as:

Vietnamese male and female first names
Vietnamese last names
Addresses formatted according to Vietnamese standards

### Actual behavior

Currently, the vi_VN locale does not exist, and attempting to use it results in errors or fallback data.



Discussion / hints:

Fix patch:
diff --git a/faker/providers/address/vi_VN/__init__.py b/faker/providers/address/vi_VN/__init__.py
new file mode 100644
index 0000000000..1bd55ed67e
--- /dev/null
+++ b/faker/providers/address/vi_VN/__init__.py
@@ -0,0 +1,308 @@
+"""This module provides address-related functionalities for Vietnamese addresses."""
+
+from collections import OrderedDict
+from typing import Optional, Tuple
+
+from .. import Provider as AddressProvider
+
+
+class Provider(AddressProvider):
+    """Provider for generating Vietnamese addresses.
+    Sources:
+
+    # https://vi.wikipedia.org/wiki/B%E1%BA%A3n_m%E1%BA%ABu:K%C3%BD_hi%E1%BB%87u_quy_%C6%B0%E1%BB%9Bc_c%C3%A1c_t%E1%BB%89nh_th%C3%A0nh_Vi%E1%BB%87t_Nam
+    """
+
+    city_prefixes = ("Thành phố", "Quận", "Huyện", "Thị xã")
+
+    city_suffixes = (
+        "Thành phố",
+        "Quận",
+        "Huyện",
+        "Thị xã",
+        "Xã",
+        "Phường",
+    )
+
+    building_number_formats = ("###", "##", "#")
+
+    street_suffixes = (
+        "Đường",
+        "Ngõ",
+        "Hẻm",
+        "Làng",
+        "Khu",
+        "Tổ",
+        "Số",
+        "Dãy",
+    )
+
+    postcode_formats = ("######",)
+
+    provinces = (
+        "An Giang",
+        "Bà Rịa – Vũng Tàu",
+        "Bạc Liêu",
+        "Bắc Kạn",
+        "Bắc Giang",
+        "Bắc Ninh",
+        "Bến Tre",
+        "Bình Dương",
+        "Bình Định",
+        "Bình Phước",
+        "Bình Thuận",
+        "Cà Mau",
+        "Cao Bằng",
+        "Cần Thơ",
+        "Đà Nẵng",
+        "Đắk Lắk",
+        "Đắk Nông",
+        "Điện Biên",
+        "Đồng Nai",
+        "Đồng Tháp",
+        "Gia Lai",
+        "Hà Giang",
+        "Hà Nam",
+        "Hà Nội",
+        "Hà Tĩnh",
+        "Hải Dương",
+        "Hải Phòng",
+        "Hậu Giang",
+        "Hòa Bình",
+        "Thành phố Hồ Chí Minh",
+        "Hưng Yên",
+        "Khánh Hòa",
+        "Kiên Giang",
+        "Kon Tum",
+        "Lai Châu",
+        "Lạng Sơn",
+        "Lào Cai",
+        "Lâm Đồng",
+        "Long An",
+        "Nam Định",
+        "Nghệ An",
+        "Ninh Bình",
+        "Ninh Thuận",
+        "Phú Thọ",
+        "Phú Yên",
+        "Quảng Bình",
+        "Quảng Nam",
+        "Quảng Ngãi",
+        "Quảng Ninh",
+        "Quảng Trị",
+        "Sóc Trăng",
+        "Sơn La",
+        "Tây Ninh",
+        "Thái Bình",
+        "Thái Nguyên",
+        "Thanh Hóa",
+        "Thừa Thiên Huế",
+        "Tiền Giang",
+        "Trà Vinh",
+        "Tuyên Quang",
+        "Vĩnh Long",
+        "Vĩnh Phúc",
+        "Yên Bái",
+    )
+
+    provinces_abbr = (
+        "AG",
+        "BV",
+        "BL",
+        "BK",
+        "BG",
+        "BN",
+        "BT",
+        "BD",
+        "BĐ",
+        "BP",
+        "BTh",
+        "CM",
+        "CB",
+        "CT",
+        "ĐNa",
+        "ĐL",
+        "ĐNo",
+        "ĐB",
+        "ĐN",
+        "ĐT",
+        "GL",
+        "HG",
+        "HNa",
+        "HN",
+        "HT",
+        "HD",
+        "HP",
+        "HGi",
+        "HB",
+        "SG",
+        "HY",
+        "KH",
+        "KG",
+        "KT",
+        "LC",
+        "LS",
+        "LCa",
+        "LĐ",
+        "LA",
+        "NĐ",
+        "NA",
+        "NB",
+        "NT",
+        "PT",
+        "PY",
+        "QB",
+        "QNa",
+        "QNg",
+        "QN",
+        "QT",
+        "ST",
+        "SL",
+        "TN",
+        "TB",
+        "TNg",
+        "TH",
+        "TTH",
+        "TG",
+        "TV",
+        "TQ",
+        "VL",
+        "VP",
+        "YB",
+    )
+
+    provinces_postcode = {
+        "AG": (88000, 88999),
+        "BV": (79000, 79999),
+        "BL": (96000, 96999),
+        "BK": (26000, 26999),
+        "BG": (23000, 23999),
+        "BN": (22000, 22999),
+        "BT": (93000, 93999),
+        "BD": (82000, 82999),
+        "BĐ": (59000, 59999),
+        "BP": (83000, 83999),
+        "BTh": (80000, 80999),
+        "CM": (97000, 97999),
+        "CB": (27000, 27999),
+        "CT": (92000, 92999),
+        "ĐNa": (55000, 55999),
+        "ĐL": (63000, 63999),
+        "ĐNo": (64000, 64999),
+        "ĐB": (38000, 38999),
+        "ĐN": (81000, 81999),
+        "ĐT": (87000, 87999),
+        "GL": (60000, 60999),
+        "HG": (31000, 31999),
+        "HNa": (40000, 40999),
+        "HN": (10000, 15999),
+        "HT": (48000, 48999),
+        "HD": (17000, 17999),
+        "HP": (18000, 18999),
+        "HGi": (91000, 91999),
+        "HB": (35000, 35999),
+        "SG": (70000, 76999),
+        "HY": (16000, 16999),
+        "KH": (65000, 65999),
+        "KG": (92000, 92999),
+        "KT": (58000, 58999),
+        "LC": (39000, 39999),
+        "LS": (24000, 24999),
+        "LCa": (33000, 33999),
+        "LĐ": (67000, 67999),
+        "LA": (85000, 85999),
+        "NĐ": (42000, 42999),
+        "NA": (46000, 47999),
+        "NB": (43000, 43999),
+        "NT": (66000, 66999),
+        "PT": (29000, 29999),
+        "PY": (62000, 62999),
+        "QB": (51000, 51999),
+        "QNa": (56000, 56999),
+        "QNg": (57000, 57999),
+        "QN": (20000, 20999),
+        "QT": (52000, 52999),
+        "ST": (95000, 95999),
+        "SL": (36000, 36999),
+        "TN": (84000, 84999),
+        "TB": (41000, 41999),
+        "TNg": (25000, 25999),
+        "TH": (44000, 45999),
+        "TTH": (53000, 53999),
+        "TG": (86000, 86999),
+        "TV": (94000, 94999),
+        "TQ": (30000, 30999),
+        "VL": (89000, 89999),
+        "VP": (28000, 28999),
+        "YB": (32000, 32999),
+    }
+
+    address_formats = OrderedDict(
+        (
+            ("{{street_address}}\n{{city}}, {{postcode}}", 25.0),
+            ("{{city}}\n{{street_address}}, {{postcode}}", 1.0),
+        )
+    )
+
+    city_formats = (
+        "{{city_prefix}} {{first_name}}{{city_suffix}}",
+        "{{first_name}}{{city_suffix}}",
+    )
+
+    street_name_formats = (
+        "{{first_name}} {{street_suffix}}",
+        "{{last_name}} {{street_suffix}}",
+    )
+
+    street_address_formats = (
+        "{{building_number}} {{street_name}}",
+    )
+
+    def city_prefix(self) -> str:
+        """Returns a random city prefix."""
+        return self.random_element(self.city_prefixes)
+
+    def administrative_unit(self) -> str:
+        """Returns a random administrative unit (province)."""
+        return self.random_element(self.provinces)
+
+    state = administrative_unit
+
+    def state_abbr(self) -> str:
+        """
+        Returns a random two-letter abbreviation for Vietnamese provinces.
+
+        """
+        abbreviations: Tuple[str, ...] = self.provinces_abbr
+        return self.random_element(abbreviations)
+
+    def postcode(self) -> str:
+        """Returns a random postcode."""
+        return f"{self.generator.random.randint(100000, 999999):06d}"
+
+    def postcode_in_state(self, state_abbr: Optional[str] = None) -> str:
+        """
+        Returns a random postcode within the provided province abbreviation.
+
+        :param state_abbr: A province abbreviation.
+        :returns: A random postcode within the provided province abbreviation.
+        """
+        if state_abbr is None:
+            state_abbr = self.random_element(self.provinces_abbr)
+
+        if state_abbr in self.provinces_abbr:
+            postcode = f"{self.generator.random.randint(
+                self.provinces_postcode[state_abbr][0],
+                self.provinces_postcode[state_abbr][1]
+            )}"
+
+            # zero left pad up until desired length (length is 6)
+            target_postcode_len = 6
+            current_postcode_len = len(postcode)
+            if current_postcode_len < target_postcode_len:
+                pad = target_postcode_len - current_postcode_len
+                postcode = f"{'0' * pad}{postcode}"
+
+            return postcode
+
+        raise ValueError("Province Abbreviation not found in list")
diff --git a/faker/providers/color/vi_VN/__init__.py b/faker/providers/color/vi_VN/__init__.py
new file mode 100644
index 0000000000..1d06fd0b2e
--- /dev/null
+++ b/faker/providers/color/vi_VN/__init__.py
@@ -0,0 +1,90 @@
+from collections import OrderedDict
+
+from .. import Provider as ColorProvider
+
+localized = True
+
+
+class Provider(ColorProvider):
+    """
+    Implement color provider for ``vi_VN`` locale.
+
+    #Sources: https://vi.wikipedia.org/wiki/Danh_s%C3%A1ch_m%C3%A0u
+    """
+
+    all_colors = OrderedDict(
+        (
+            ("Trắng Antique", "#FAEBD7"),
+            ("Aquamarine", "#7FFFD4"),
+            ("Azure", "#F0FFFF"),
+            ("Beige", "#F5F5DC"),
+            ("Đen", "#000000"),
+            ("Xanh dương", "#0000FF"),
+            ("Xanh tím", "#8A2BE2"),
+            ("Nâu", "#A52A2A"),
+            ("Sô cô la", "#D2691E"),
+            ("San hô", "#FF7F50"),
+            ("Xanh hải quân", "#6495ED"),
+            ("Hồng đào", "#DC143C"),
+            ("Xanh đậm", "#00008B"),
+            ("Xanh biển đậm", "#008B8B"),
+            ("Xám đậm", "#A9A9A9"),
+            ("Xanh lá đậm", "#006400"),
+            ("Rêu đậm", "#BDB76B"),
+            ("Cam đậm", "#FF8C00"),
+            ("Đỏ đậm", "#8B0000"),
+            ("Xanh ngọc đậm", "#00CED1"),
+            ("Tím đậm", "#9400D3"),
+            ("Hồng đậm", "#FF1493"),
+            ("Xám xỉn", "#696969"),
+            ("Hồng fuchsia", "#FF00FF"),
+            ("Vàng", "#FFD700"),
+            ("Xám", "#808080"),
+            ("Xanh lá cây", "#008000"),
+            ("Xanh lá cây nhạt", "#ADFF2F"),
+            ("Hồng sáng", "#FF69B4"),
+            ("Indigo", "#4B0082"),
+            ("Ngà voi", "#FFFFF0"),
+            ("Rêu", "#F0E68C"),
+            ("Hồng lavender", "#FFF0F5"),
+            ("Xanh dương nhạt", "#ADD8E6"),
+            ("Xanh biển nhạt", "#E0FFFF"),
+            ("Xám sáng", "#D3D3D3"),
+            ("Xanh lá cây sáng", "#90EE90"),
+            ("Hồng sáng", "#FFB6C1"),
+            ("Xanh biển sáng", "#87CEFA"),
+            ("Vàng sáng", "#FFFFE0"),
+            ("Hạt Dẻ", "#800000"),
+            ("Cam", "#FFA500"),
+            ("Cam đỏ", "#FF4500"),
+            ("Xanh lá cây nhạt", "#98FB98"),
+            ("Xanh biển nhạt", "#AFEEEE"),
+            ("Hồng", "#FFC0CB"),
+            ("Tím", "#DDA0DD"),
+            ("Tím đậm", "#800080"),
+            ("Đỏ", "#FF0000"),
+            ("Xanh biển xanh", "#2E8B57"),
+            ("Bạc", "#C0C0C0"),
+            ("Xanh lục bảo", "#40E0D0"),
+            ("Tím violet", "#EE82EE"),
+            ("Trắng", "#FFFFFF"),
+            ("Vàng", "#FFFF00"),
+            ("Xanh lá cây vàng", "#9ACD32"),
+        )
+    )
+
+    safe_colors = (
+        "đen",
+        "đỏ rượu",
+        "xanh lá cây",
+        "rêu",
+        "tím",
+        "xanh biển",
+        "xanh chanh",
+        "xanh dương",
+        "bạc",
+        "xám",
+        "vàng",
+        "hồng fuchsia",
+        "trắng",
+    )
diff --git a/faker/providers/company/vi_VN/__init__.py b/faker/providers/company/vi_VN/__init__.py
new file mode 100644
index 0000000000..480b74d2be
--- /dev/null
+++ b/faker/providers/company/vi_VN/__init__.py
@@ -0,0 +1,24 @@
+from .. import Provider as CompanyProvider
+
+
+class Provider(CompanyProvider):
+    # Source: https://vi.wikipedia.org/wiki/Danh_s%C3%A1ch_c%C3%B4ng_ty_Vi%E1%BB%87t_Nam
+    formats = (
+        "{{last_name}} {{company_suffix}}",
+        "{{last_name}} {{last_name}} {{company_suffix}}",
+        "{{last_name}} và {{last_name}} {{company_suffix}}",
+        "{{last_name}} và đối tác {{company_suffix}}",
+    )
+
+    company_suffixes = (
+        "Công ty TNHH",
+        "Công ty Cổ phần",
+        "Doanh nghiệp tư nhân",
+        "Công ty TNHH MTV",
+        "Công ty Hợp danh",
+        "Công ty Trách nhiệm hữu hạn",
+        "Tập Đoàn",
+    )
+
+    def company_suffix(self) -> str:
+        return self.random_element(self.company_suffixes)
diff --git a/faker/providers/currency/vi_VN/__init__.py b/faker/providers/currency/vi_VN/__init__.py
new file mode 100644
index 0000000000..a98a283654
--- /dev/null
+++ b/faker/providers/currency/vi_VN/__init__.py
@@ -0,0 +1,9 @@
+from .. import Provider as CurrencyProvider
+
+
+class Provider(CurrencyProvider):
+    # Source: https://vi.wikipedia.org/wiki/%C4%90%E1%BB%93ng_(%C4%91%C6%A1n_v%E1%BB%8B_ti%E1%BB%81n_t%E1%BB%87)#Ti%E1%BB%81n_gi%E1%BA%A5y_-_Ti%E1%BB%81n_polymer
+    price_formats = ["#.##", "%#.##", "%##.##", "%,###.##", "%#,###.##"]
+
+    def pricetag(self) -> str:
+        return "₫" + self.numerify(self.random_element(self.price_formats))
diff --git a/faker/providers/date_time/vi_VN/__init__.py b/faker/providers/date_time/vi_VN/__init__.py
new file mode 100644
index 0000000000..9de93fe0e2
--- /dev/null
+++ b/faker/providers/date_time/vi_VN/__init__.py
@@ -0,0 +1,37 @@
+from .. import Provider as DateTimeProvider
+
+
+class Provider(DateTimeProvider):
+    # Source: https://vi.wikipedia.org/wiki/%C4%90%E1%BB%8Bnh_d%E1%BA%A1ng_ng%C3%A0y_v%C3%A0_gi%E1%BB%9D_%E1%BB%9F_Vi%E1%BB%87t_Nam
+    DAY_NAMES = {
+        "0": "Chủ Nhật",
+        "1": "Thứ Hai",
+        "2": "Thứ Ba",
+        "3": "Thứ Tư",
+        "4": "Thứ Năm",
+        "5": "Thứ Sáu",
+        "6": "Thứ Bảy",
+    }
+
+    MONTH_NAMES = {
+        "01": "Tháng Một",
+        "02": "Tháng Hai",
+        "03": "Tháng Ba",
+        "04": "Tháng Tư",
+        "05": "Tháng Năm",
+        "06": "Tháng Sáu",
+        "07": "Tháng Bảy",
+        "08": "Tháng Tám",
+        "09": "Tháng Chín",
+        "10": "Tháng Mười",
+        "11": "Tháng Mười Một",
+        "12": "Tháng Mười Hai",
+    }
+
+    def day_of_week(self):
+        day = self.date("%w")
+        return self.DAY_NAMES[day]
+
+    def month_name(self):
+        month = self.month()
+        return self.MONTH_NAMES[month]
diff --git a/faker/providers/job/vi_VN/__init__.py b/faker/providers/job/vi_VN/__init__.py
new file mode 100644
index 0000000000..ab22d56e62
--- /dev/null
+++ b/faker/providers/job/vi_VN/__init__.py
@@ -0,0 +1,47 @@
+from .. import Provider as JobProvider
+
+
+class Provider(JobProvider):
+    """Translated from Super class"""
+
+    jobs = (
+        # Information technology field
+        "Lập trình viên", "Kỹ sư phần mềm", "Kiến trúc sư phần mềm", "Nhà phân tích dữ liệu", "Chuyên viên bảo mật",
+        "Tester", "DevOps Engineer", "Project Manager", "UX/UI Designer", "Digital Marketer", "Thực Tập",
+
+        # Finance - banking sector
+        "Nhân viên ngân hàng", "Chuyên viên tín dụng", "Kế toán", "Kiểm toán", "Nhà tư vấn tài chính",
+        "Chuyên viên phân tích thị trường",
+
+        # Business areas
+        "Giám đốc kinh doanh", "Trưởng phòng kinh doanh", "Nhân viên kinh doanh", "Marketing Manager",
+        "Sales Representative", "Chuyên viên bán hàng trực tuyến",
+
+        # Education Department
+        "Giáo viên", "Giảng viên", "Chuyên viên tư vấn tuyển sinh", "Thực tập sinh giáo dục",
+
+        # Medical
+        "Bác sĩ", "Y tá", "Dược sĩ", "Điều Dưỡng",
+
+        # Building sector
+        "Kỹ sư xây dựng", "Kiến trúc sư", "Thợ xây", "Kỹ sư giám sát",
+
+        # Service sector
+        "Nhân viên khách sạn", "Nhân viên nhà hàng", "Tư vấn khách hàng", "Nhân viên lễ tân",
+
+        # Manufacturing sector
+        "Công nhân sản xuất", "Kỹ sư sản xuất", "Quản lý sản xuất",
+
+        # Agriculture sector
+        "Nông dân", "Kỹ sư nông nghiệp",
+
+        # Law field
+        "Luật sư", "Thư ký pháp lý",
+
+        # Other areas
+        "Nhà báo", "Biên dịch viên", "Nghệ sĩ", "Nhà thiết kế đồ họa", "Nhân viên hành chính", "Chuyên viên nhân sự",
+        "Nhân Viên Bán Hàng",
+    )
+
+    def job(self) -> str:
+        return self.random_element(self.jobs)
diff --git a/faker/providers/lorem/vi_VN/__init__.py b/faker/providers/lorem/vi_VN/__init__.py
new file mode 100644
index 0000000000..a4aff13c49
--- /dev/null
+++ b/faker/providers/lorem/vi_VN/__init__.py
@@ -0,0 +1,193 @@
+from typing import Dict
+
+from .. import Provider as LoremProvider
+
+
+class Provider(LoremProvider):
+    """Implement lorem provider for ``vi_VN`` locale.
+
+    Word list is based on common Vietnamese words and phrases.
+    # Source : https://vi.wikipedia.org/wiki/Ng%E1%BB%AF_ph%C3%A1p_ti%E1%BA%BFng_Vi%E1%BB%87t
+    """
+
+    word_list = (
+        "cái",
+        "đó",
+        "là",
+        "và",
+        "có",
+        "như",
+        "một",
+        "để",
+        "cũng",
+        "với",
+        "cho",
+        "trong",
+        "tôi",
+        "của",
+        "người",
+        "không",
+        "sẽ",
+        "đã",
+        "này",
+        "theo",
+        "làm",
+        "nơi",
+        "đang",
+        "nếu",
+        "bạn",
+        "được",
+        "khi",
+        "thì",
+        "về",
+        "mà",
+        "cũng",
+        "nào",
+        "của",
+        "nhưng",
+        "vì",
+        "rất",
+        "tại",
+        "tại",
+        "thế",
+        "để",
+        "giữa",
+        "với",
+        "cách",
+        "từ",
+        "lớn",
+        "có",
+        "vài",
+        "hơn",
+        "vẫn",
+        "dưới",
+        "đi",
+        "đến",
+        "vậy",
+        "điều",
+        "hoặc",
+        "chỉ",
+        "hơn",
+        "khiến",
+        "giống",
+        "sau",
+        "trong",
+        "đúng",
+        "của",
+        "mỗi",
+        "như",
+        "bên",
+        "để",
+        "chưa",
+        "như",
+        "thay",
+        "như",
+        "các",
+        "tự",
+        "số",
+        "từng",
+        "nhiều",
+        "gần",
+        "từ",
+    )
+
+    parts_of_speech: Dict[str, tuple] = {
+        "verb": (
+            "là",
+            "có",
+            "làm",
+            "đi",
+            "nói",
+            "thấy",
+            "nghe",
+            "đọc",
+            "viết",
+            "muốn",
+            "đi",
+            "ngồi",
+            "uống",
+            "ăn",
+            "học",
+            "chơi",
+            "nhìn",
+            "được",
+            "tìm",
+            "đặt",
+            "giúp",
+            "hỏi",
+            "giải",
+            "mua",
+            "bán",
+            "nói",
+        ),
+        "noun": (
+            "người",
+            "sách",
+            "máy",
+            "bàn",
+            "ghế",
+            "cửa",
+            "nhà",
+            "bút",
+            "xe",
+            "điện thoại",
+            "bánh",
+            "cà phê",
+            "nước",
+            "trường",
+            "chúng tôi",
+            "học sinh",
+            "giáo viên",
+            "bố",
+            "mẹ",
+            "em",
+            "anh",
+            "chị",
+        ),
+        "adverb": (
+            "thực sự",
+            "rất",
+            "nhanh",
+            "chậm",
+            "tốt",
+            "xấu",
+            "đúng",
+            "sai",
+            "vui",
+            "buồn",
+            "mới",
+            "cũ",
+            "dễ",
+            "khó",
+            "gần",
+            "xa",
+            "hơn",
+            "vẫn",
+            "đã",
+            "mới",
+        ),
+        "adjective": (
+            "đẹp",
+            "xấu",
+            "tốt",
+            "xấu",
+            "to",
+            "nhỏ",
+            "ngọt",
+            "chua",
+            "mặn",
+            "nhanh",
+            "chậm",
+            "đầu",
+            "cuối",
+            "mới",
+            "cũ",
+            "dễ",
+            "khó",
+            "hơi",
+            "vui",
+            "buồn",
+            "mạnh",
+            "yếu",
+        ),
+    }
diff --git a/faker/providers/person/vi_VN/__init__.py b/faker/providers/person/vi_VN/__init__.py
new file mode 100644
index 0000000000..94774884de
--- /dev/null
+++ b/faker/providers/person/vi_VN/__init__.py
@@ -0,0 +1,131 @@
+from .. import Provider as PersonProvider
+
+
+class Provider(PersonProvider):
+    formats_female = (
+        "{{first_name_female}} {{last_name}}",
+        "{{first_name_unisex}} {{last_name}}",
+        "{{prefix_female}} {{first_name_unisex}} {{last_name}}",
+        "{{prefix_female}} {{first_name_female}} {{last_name}}",
+    )
+    formats_male = (
+        "{{first_name_male}} {{last_name}}",
+        "{{first_name_male}} {{middle_name}} {{last_name}}",
+        "{{first_name_unisex}} {{middle_name}} {{last_name}}",
+        "{{prefix_male}} {{first_name_male}} {{last_name}}",
+    )
+    formats = formats_female + formats_male
+
+    # Name from : https://en.wikipedia.org/wiki/Vietnamese_name
+    # and https://vinpearl.com/en/vietnamese-names-top-200-popular-names-for-boys-and-girls
+
+    first_names_female = (
+        "Ngọc",
+        "Hương",
+        "Lan",
+        "Mai",
+        "Thảo",
+        "Linh",
+        "Hồng",
+        "Chi",
+        "Vân",
+        "Duyên"
+        "Dương",
+        "Yến",
+        "Vi",
+        "Ánh",
+        "Xuân"
+    )
+
+    first_names_unisex = (
+        "An",
+        "Hà",
+        "Bảo",
+        "Lâm",
+        "Hạnh",
+        "Thành",
+        "Kim",
+        "Nhật",
+        "Phương",
+        "Khoa"
+        "Hải",
+        "Nhật",
+    )
+
+    first_names_male = (
+        "Nam",
+        "Hưng",
+        "Vũ",
+        "Tú",
+        "Hoàng",
+        "Phúc",
+        "Trung",
+        "Quang",
+        "Anh",
+        "Khoa",
+        "Dũng",
+        "Quang",
+        "Thành",
+        "Huy",
+        "Bảo",
+        "Châu",
+        "Minh",
+        "Tùng",
+        "Nhiên",
+        "Trọng"
+    )
+
+    middle_names = (
+        "Văn",
+        "Thị",
+        "Quang",
+        "Đức",
+        "Trí",
+        "Xuân",
+        "Hoàng",
+        "Hải",
+        "Đức",
+        "Thế",
+        "Tấn",
+        "Phú",
+        "Hữu",
+        "Bảo",
+        "Mai",
+        "Mai Bảo",
+    )
+
+    last_names = (
+        "Nguyễn",
+        "Trần",
+        "Lê",
+        "Phạm",
+        "Vũ",
+        "Đặng",
+        "Bùi",
+        "Dương",
+        "Mai",
+        "Hoàng"
+    )
+
+    # Typically, Vietnamese will be addressed with their given name and a prefix
+    # https://en.wikipedia.org/wiki/Vietnamese_name#Given_name
+
+    prefixes_female = (
+        "Cô",
+        "Chị",
+        "Bà",
+        "Quý cô"
+    )
+
+    prefixes_male = (
+        "Ông",
+        "Anh",
+        "Bác",
+        "Quý ông"
+    )
+
+    def first_name_unisex(self) -> str:
+        return self.random_element(self.first_names_unisex)
+
+    def middle_name(self) -> str:
+        return self.random_element(self.middle_names)
diff --git a/faker/providers/phone_number/vi_VN/__init__.py b/faker/providers/phone_number/vi_VN/__init__.py
new file mode 100644
index 0000000000..c76cc3af16
--- /dev/null
+++ b/faker/providers/phone_number/vi_VN/__init__.py
@@ -0,0 +1,16 @@
+from .. import Provider as PhoneNumberProvider
+
+
+class Provider(PhoneNumberProvider):
+    """ Implement phone_number provider for ``vi_VN`` locale.
+        # Source : https://vi.wikipedia.org/wiki/M%C3%A3_%C4%91i%E1%BB%87n_tho%E1%BA%A1i_Vi%E1%BB%87t_Nam
+    """
+    formats = (
+        "+84 ## #######",
+        "(0#) #### ####",
+        "0# #### ####",
+        "0# #######",
+        "+84-##-######",
+        "+84-##-### ####",
+        "(0#)###-####",
+    )


Test patch:
diff --git a/tests/providers/test_address.py b/tests/providers/test_address.py
index 45607994cf..d8b805eeba 100644
--- a/tests/providers/test_address.py
+++ b/tests/providers/test_address.py
@@ -52,6 +52,7 @@
 from faker.providers.address.ta_IN import Provider as TaInAddressProvider
 from faker.providers.address.th_TH import Provider as ThThAddressProvider
 from faker.providers.address.uk_UA import Provider as UkUaAddressProvider
+from faker.providers.address.vi_VN import Provider as ViVNAddressProvider
 from faker.providers.address.zh_CN import Provider as ZhCnAddressProvider
 from faker.providers.address.zh_TW import Provider as ZhTwAddressProvider
 
@@ -2332,6 +2333,51 @@ def test_region(self, faker, num_samples):
             assert region in UkUaAddressProvider.region_names
 
 
+class TestViVn:
+    """Test vi_VN address provider methods"""
+
+    def test_city_prefix(self, faker, num_samples):
+        for _ in range(num_samples):
+            city_prefix = faker.city_prefix()
+            assert isinstance(city_prefix, str)
+            assert city_prefix in ViVNAddressProvider.city_prefixes
+
+    def test_state(self, faker, num_samples):
+        for _ in range(num_samples):
+            state = faker.state()
+            assert isinstance(state, str)
+            assert state in ViVNAddressProvider.provinces
+
+    def test_state_abbr(self, faker, num_samples):
+        for _ in range(num_samples):
+            state_abbr = faker.state_abbr()
+            assert isinstance(state_abbr, str)
+            assert state_abbr in ViVNAddressProvider.provinces_abbr
+
+    def test_postcode(self, faker, num_samples):
+        for _ in range(num_samples):
+            postcode = faker.postcode()
+            assert isinstance(postcode, str) and len(postcode) == 6
+            assert 100000 <= int(postcode) <= 999999
+
+    def test_postcode_in_state(self, faker, num_samples):
+        for _ in range(num_samples):
+            for state_abbr in ViVNAddressProvider.provinces_abbr:
+                postcode = faker.postcode_in_state(state_abbr)
+                assert re.fullmatch(r"\d{6}", postcode)
+                assert int(postcode) >= ViVNAddressProvider.provinces_postcode[state_abbr][0]
+                assert int(postcode) <= ViVNAddressProvider.provinces_postcode[state_abbr][1]
+
+        with pytest.raises(ValueError):
+            faker.postcode_in_state("XX")
+
+    def test_state_abbr_determinism(self, faker):
+        faker.seed_instance(0)
+        first = faker.state_abbr()
+        faker.seed_instance(0)
+        assert faker.state_abbr() == first
+
+
 class TestFrCa:
     """Test fr_CA address provider methods"""
 
diff --git a/tests/providers/test_color.py b/tests/providers/test_color.py
index 359041f350..609c4cf7d4 100644
--- a/tests/providers/test_color.py
+++ b/tests/providers/test_color.py
@@ -17,6 +17,7 @@
 from faker.providers.color.hy_AM import Provider as HyAmColorProvider
 from faker.providers.color.id_ID import Provider as IdIdColorProvider
 from faker.providers.color.sk_SK import Provider as SkSkColorProvider
+from faker.providers.color.vi_VN import Provider as ViVNColorProvider
 
 
 class TestColorProvider:
@@ -443,3 +444,19 @@ def test_safe_color_name(self, faker, num_samples):
             safe_color_name = faker.safe_color_name()
             assert isinstance(safe_color_name, str)
             assert safe_color_name in IdIdColorProvider.safe_colors
+
+
+class TestViVn:
+    """Test vi_VN color provider methods"""
+
+    def test_color_name(self, faker, num_samples):
+        for _ in range(num_samples):
+            color_name = faker.color_name()
+            assert isinstance(color_name, str)
+            assert color_name in ViVNColorProvider.all_colors.keys()
+
+    def test_safe_color_name(self, faker, num_samples):
+        for _ in range(num_samples):
+            safe_color_name = faker.safe_color_name()
+            assert isinstance(safe_color_name, str)
+            assert safe_color_name in ViVNColorProvider.safe_colors
diff --git a/tests/providers/test_company.py b/tests/providers/test_company.py
index 33a007b3ec..2face87f1d 100644
--- a/tests/providers/test_company.py
+++ b/tests/providers/test_company.py
@@ -25,6 +25,7 @@
 from faker.providers.company.ru_RU import calculate_checksum
 from faker.providers.company.th_TH import Provider as ThThCompanyProvider
 from faker.providers.company.tr_TR import Provider as TrTrCompanyProvider
+from faker.providers.company.vi_VN import Provider as ViVnCompanyProvider
 from faker.utils.checksums import luhn_checksum
 
 
@@ -492,3 +493,18 @@ def test_company(self, faker, num_samples):
         for _ in range(num_samples):
             company = faker.company()
             assert isinstance(company, str)
+
+
+class TestViVn:
+    """Test vi_VN company provider methods"""
+
+    def test_company_suffix(self, faker, num_samples):
+        for _ in range(num_samples):
+            suffix = faker.company_suffix()
+            assert isinstance(suffix, str)
+            assert suffix in ViVnCompanyProvider.company_suffixes
+
+    def test_company(self, faker, num_samples):
+        for _ in range(num_samples):
+            company = faker.company()
+            assert isinstance(company, str)
diff --git a/tests/providers/test_currency.py b/tests/providers/test_currency.py
index 5161749de6..30699c1f91 100644
--- a/tests/providers/test_currency.py
+++ b/tests/providers/test_currency.py
@@ -485,3 +485,26 @@ def test_pricetag(self, faker, num_samples):
         for _ in range(num_samples):
             pricetag = faker.pricetag()
             assert isinstance(pricetag, str)
+
+
+class TestViVn:
+    """Test vi_VN currency provider"""
+
+    num_samples = 100
+
+    @classmethod
+    def setup_class(cls):
+        from faker.providers.currency.vi_VN import Provider as ViVNCurrencyProvider
+
+        cls.provider = ViVNCurrencyProvider
+        cls.currencies = cls.provider.currencies
+
+    def test_currency(self, faker, num_samples):
+        for _ in range(num_samples):
+            cur = faker.currency()
+            assert isinstance(cur, tuple) and cur in self.currencies
+
+    def test_pricetag(self, faker, num_samples):
+        for _ in range(num_samples):
+            pricetag = faker.pricetag()
+            assert isinstance(pricetag, str)
diff --git a/tests/providers/test_date_time.py b/tests/providers/test_date_time.py
index f6fba5408b..d708bf849e 100644
--- a/tests/providers/test_date_time.py
+++ b/tests/providers/test_date_time.py
@@ -40,6 +40,7 @@
 from faker.providers.date_time.sl_SI import Provider as SlSiProvider
 from faker.providers.date_time.ta_IN import Provider as TaInProvider
 from faker.providers.date_time.tr_TR import Provider as TrTrProvider
+from faker.providers.date_time.vi_VN import Provider as ViVNProvider
 from faker.providers.date_time.zh_CN import Provider as ZhCnProvider
 from faker.providers.date_time.zh_TW import Provider as ZhTwProvider
 
@@ -1317,3 +1318,21 @@ def test_month(self):
     def test_traditional_month(self):
         month = self.fake.traditional_month_name()
         assert month in JaJpProvider.TRADITIONAL_MONTH_NAMES.values()
+
+
+class TestViVn(unittest.TestCase):
+    """Tests date_time in the vi_VN locale"""
+
+    def setUp(self):
+        self.fake = Faker("vi_VN")
+        Faker.seed(0)
+
+    def test_day(self):
+        day = self.fake.day_of_week()
+        assert isinstance(day, str)
+        assert day in ViVNProvider.DAY_NAMES.values()
+
+    def test_month(self):
+        month = self.fake.month_name()
+        assert isinstance(month, str)
+        assert month in ViVNProvider.MONTH_NAMES.values()
diff --git a/tests/providers/test_job.py b/tests/providers/test_job.py
index eeb32704d3..607fbe3c89 100644
--- a/tests/providers/test_job.py
+++ b/tests/providers/test_job.py
@@ -15,6 +15,7 @@
 from faker.providers.job.sk_SK import Provider as SkSkJobProvider
 from faker.providers.job.th_TH import Provider as ThThJobProvider
 from faker.providers.job.tr_TR import Provider as TrTrJobProvider
+from faker.providers.job.vi_VN import Provider as ViVNJobProvider
 
 
 class TestJobProvider:
@@ -152,3 +153,13 @@ class TestRoRo:
 
     def test_job(self, faker, num_samples):
         assert faker.job() in RoRoJobProvider.jobs
+
+
+class TestViVn:
+    """Test vi_VN job provider"""
+
+    def test_job(self, faker, num_samples):
+        for _ in range(num_samples):
+            job = faker.job()
+            assert isinstance(job, str)
+            assert job in ViVNJobProvider.jobs
diff --git a/tests/providers/test_lorem.py b/tests/providers/test_lorem.py
index e3e0e0ffba..eae239118b 100644
--- a/tests/providers/test_lorem.py
+++ b/tests/providers/test_lorem.py
@@ -11,6 +11,7 @@
 from faker.providers.lorem.fa_IR import Provider as FaIrLoremProvider
 from faker.providers.lorem.nl_BE import Provider as NlBeLoremProvider
 from faker.providers.lorem.uk_UA import Provider as UkUaLoremProvider
+from faker.providers.lorem.vi_VN import Provider as ViVNLoremProvider
 
 
 class TestLoremProvider:
@@ -712,3 +713,72 @@ def test_words(self, faker, num_samples):
         for _ in range(num_samples):
             words = faker.words(num_words)
             assert all(isinstance(word, str) and word in UkUaLoremProvider.word_list for word in words)
+
+
+class TestViVn:
+    """Test vi_VN lorem provider"""
+
+    word_list = [word.lower() for word in ViVNLoremProvider.word_list]
+
+    def test_paragraph(self, faker, num_samples):
+        num_sentences = 10
+        for _ in range(num_samples):
+            paragraph = faker.paragraph(nb_sentences=num_sentences)
+            assert isinstance(paragraph, str)
+            words = paragraph.replace(".", "").split()
+            assert all(word.lower() in self.word_list for word in words)
+
+    def test_paragraphs(self, faker, num_samples):
+        num_paragraphs = 5
+        for _ in range(num_samples):
+            paragraphs = faker.paragraphs(nb=num_paragraphs)
+            for paragraph in paragraphs:
+                assert isinstance(paragraph, str)
+                words = paragraph.replace(".", "").split()
+                assert all(word.lower() in self.word_list for word in words)
+
+    def test_sentence(self, faker, num_samples):
+        num_words = 10
+        for _ in range(num_samples):
+            sentence = faker.sentence(nb_words=num_words)
+            assert isinstance(sentence, str)
+            words = sentence.replace(".", "").split()
+            assert all(word.lower() in self.word_list for word in words)
+
+    def test_sentences(self, faker, num_samples):
+        num_sentences = 5
+        for _ in range(num_samples):
+            sentences = faker.sentences(nb=num_sentences)
+            for sentence in sentences:
+                assert isinstance(sentence, str)
+                words = sentence.replace(".", "").split()
+                assert all(word.lower() in self.word_list for word in words)
+
+    def test_text(self, faker, num_samples):
+        num_chars = 25
+        for _ in range(num_samples):
+            text = faker.text(max_nb_chars=num_chars)
+            assert isinstance(text, str)
+            words = re.sub(r"[.\n]+", " ", text).split()
+            assert all(word.lower() in self.word_list for word in words)
+
+    def test_texts(self, faker, num_samples):
+        num_texts = 5
+        num_chars = 25
+        for _ in range(num_samples):
+            texts = faker.texts(max_nb_chars=num_chars, nb_texts=num_texts)
+            for text in texts:
+                assert isinstance(text, str)
+                words = re.sub(r"[.\n]+", " ", text).split()
+                assert all(word.lower() in self.word_list for word in words)
+
+    def test_word(self, faker, num_samples):
+        for _ in range(num_samples):
+            word = faker.word()
+            assert isinstance(word, str) and word in ViVNLoremProvider.word_list
+
+    def test_words(self, faker, num_samples):
+        num_words = 5
+        for _ in range(num_samples):
+            words = faker.words(num_words)
+            assert all(isinstance(word, str) and word in ViVNLoremProvider.word_list for word in words)
diff --git a/tests/providers/test_person.py b/tests/providers/test_person.py
index 5cece79ef7..d0d002d455 100644
--- a/tests/providers/test_person.py
+++ b/tests/providers/test_person.py
@@ -37,6 +37,7 @@
 from faker.providers.person.th_TH import Provider as ThThProvider
 from faker.providers.person.uk_UA import Provider as UkUAProvider
 from faker.providers.person.uk_UA import translit as UkUATranslit
+from faker.providers.person.vi_VN import Provider as ViVNProvider
 from faker.providers.person.yo_NG import Provider as YoNGProvider
 from faker.providers.person.zh_CN import Provider as ZhCNProvider
 from faker.providers.person.zh_TW import Provider as ZhTWProvider
@@ -1704,5 +1705,37 @@ def test_short_full_name(self):
         assert res.count(" ") == 1
 
 
+class TestViVn(unittest.TestCase):
+
+    """Test vi_VN person provider methods"""
+    def setUp(self):
+        self.fake = Faker("vi_VN")
+        Faker.seed(0)
+
+    def test_first_names(self):
+        """simple test to verify that we are pulling gender specific names"""
+        name = self.fake.first_name_female()
+        assert name in ViVNProvider.first_names_female
+
+        name = self.fake.first_name_male()
+        assert name in ViVNProvider.first_names_male
+
+        name = self.fake.first_name_unisex()
+        assert name in ViVNProvider.first_names_unisex
+
+        name = self.fake.first_name()
+        assert name in ViVNProvider.first_names
+
+    def test_middle_names(self):
+        """test the middle name"""
+        name = self.fake.middle_name()
+        assert name in ViVNProvider.middle_names
+
+    def test_last_names(self):
+        """test the last name is generating from the provided tuple"""
+        last_name = self.fake.last_name()
+        assert last_name in ViVNProvider.last_names
+
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/tests/providers/test_phone_number.py b/tests/providers/test_phone_number.py
index 39cf2ea624..75608369fe 100644
--- a/tests/providers/test_phone_number.py
+++ b/tests/providers/test_phone_number.py
@@ -417,3 +417,24 @@ def test_basic_phone_number(self, faker, num_samples):
                     pattern_is_found = True
                     break
             assert pattern_is_found
+
+
+class TestViVn:
+    """Test vi_VN phone number provider methods"""
+
+    def test_phone_number(self, faker, num_samples):
+        pattern: Pattern = re.compile(
+            r"(?:"  # Non-capturing group
+            r"\+84 \d{2} \d{7}|"  # Example: +84 12 3456789
+            r"\(0\d\) \d{4} \d{4}|"  # Example: (012) 3456 7890
+            r"0\d \d{4} \d{4}|"  # Example: 012 3456 7890
+            r"0\d \d{7}|"  # Example: 012 3456789
+            r"\+84-\d{2}-\d{6}|"  # Example: +84-12-345678
+            r"\+84-\d{2}-\d{3} \d{4}|"  # Example: +84-12-345 6789
+            r"\(0\d\)\d{3}-\d{4}"  # Example: (012)345-6789
+            r")"  # Closing non-capturing group
+        )
+        for _ in range(num_samples):
+            phone_number = faker.phone_number()
+            assert isinstance(phone_number, str)
+            assert pattern.fullmatch(phone_number)