intl-address-format
Version:
Lightweight address formatter with country and locale support.
540 lines (537 loc) • 10.7 kB
JavaScript
const templates = {
"US": `{name}
{company}
{houseNumber} {street}
{street2}
{city}, {state} {postalCode}
{country}
Tax ID: {taxNumber}`,
"CA": `{name}
{company}
{houseNumber} {street}
{street2}
{city}, {state} {postalCode}
{country}
Tax Number: {taxNumber}`,
"MX": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}, {state}
{country}
Tax Number: {taxNumber}`,
"DE": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
USt-IdNr.: {taxNumber}`,
"FR": `{name}
{company}
{houseNumber} {street}
{street2}
{postalCode} {city}
{country}
Numéro TVA: {taxNumber}`,
"IT": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Partita IVA: {taxNumber}`,
"ES": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
NIF: {taxNumber}`,
"GB": `{name}
{company}
{houseNumber} {street}
{street2}
{city}
{postalCode}
{country}
VAT Reg No.: {taxNumber}`,
"NL": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"BE": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"CH": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"AT": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"PT": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"IE": `{name}
{company}
{houseNumber} {street}
{street2}
{city}
{postalCode}
{country}
Tax Number: {taxNumber}`,
"SE": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"NO": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"DK": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"FI": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"IS": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"PL": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"CZ": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"SK": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"HU": `{name}
{company}
{city}
{street} {houseNumber}
{street2}
{postalCode}
{country}
Tax Number: {taxNumber}`,
"RO": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"BG": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"HR": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"SI": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"RU": `{name}
{company}
{street} {houseNumber}
{street2}
{city}
{postalCode}
{country}
Tax Number: {taxNumber}`,
"UA": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"BY": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"JP": `{name}
{company}
{postalCode}
{state}{city}
{street} {houseNumber}
{street2}
{country}
Tax Number: {taxNumber}`,
"KR": `{name}
{company}
{postalCode}
{state} {city}
{street} {houseNumber}
{street2}
{country}
Tax Number: {taxNumber}`,
"CN": `{name}
{company}
{state} {city}
{street} {houseNumber}
{street2}
{postalCode}
{country}
Tax Number: {taxNumber}`,
"TW": `{name}
{company}
{postalCode}
{state}{city}
{street} {houseNumber}
{street2}
{country}
Tax Number: {taxNumber}`,
"HK": `{name}
{company}
{houseNumber} {street}
{street2}
{city}
{country}
Tax Number: {taxNumber}`,
"SG": `{name}
{company}
{houseNumber} {street}
{street2}
Singapore {postalCode}
{country}
Tax Number: {taxNumber}`,
"MY": `{name}
{company}
{houseNumber} {street}
{street2}
{postalCode} {city}, {state}
{country}
Tax Number: {taxNumber}`,
"TH": `{name}
{company}
{houseNumber} {street}
{street2}
{city} {postalCode}
{country}
Tax Number: {taxNumber}`,
"VN": `{name}
{company}
{houseNumber} {street}
{street2}
{city} {postalCode}
{country}
Tax Number: {taxNumber}`,
"ID": `{name}
{company}
{street} {houseNumber}
{street2}
{city} {postalCode}
{country}
Tax Number: {taxNumber}`,
"PH": `{name}
{company}
{houseNumber} {street}
{street2}
{city} {postalCode}
{country}
Tax Number: {taxNumber}`,
"IN": `{name}
{company}
{houseNumber} {street}
{street2}
{city} - {postalCode}
{state}
{country}
Tax Number: {taxNumber}`,
"PK": `{name}
{company}
{houseNumber} {street}
{street2}
{city} {postalCode}
{country}
Tax Number: {taxNumber}`,
"BD": `{name}
{company}
{houseNumber} {street}
{street2}
{city} - {postalCode}
{country}
Tax Number: {taxNumber}`,
"LK": `{name}
{company}
{houseNumber} {street}
{street2}
{city} {postalCode}
{country}
Tax Number: {taxNumber}`,
"AU": `{name}
{company}
{houseNumber} {street}
{street2}
{city} {state} {postalCode}
{country}
Tax Number: {taxNumber}`,
"NZ": `{name}
{company}
{houseNumber} {street}
{street2}
{city} {postalCode}
{country}
Tax Number: {taxNumber}`,
"TR": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"SA": `{name}
{company}
{houseNumber} {street}
{street2}
{city} {postalCode}
{country}
Tax Number: {taxNumber}`,
"AE": `{name}
{company}
{houseNumber} {street}
{street2}
{city}
{country}
Tax Number: {taxNumber}`,
"ZA": `{name}
{company}
{houseNumber} {street}
{street2}
{city} {postalCode}
{country}
Tax Number: {taxNumber}`,
"EG": `{name}
{company}
{houseNumber} {street}
{street2}
{city}
{country}
Tax Number: {taxNumber}`,
"NG": `{name}
{company}
{houseNumber} {street}
{street2}
{city}
{country}
Tax Number: {taxNumber}`,
"KE": `{name}
{company}
{houseNumber} {street}
{street2}
{city} {postalCode}
{country}
Tax Number: {taxNumber}`,
"BR": `{name}
{company}
{street}, {houseNumber}
{street2}
{city} - {state}
{postalCode}
{country}
Tax Number: {taxNumber}`,
"AR": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}, {state}
{country}
Tax Number: {taxNumber}`,
"CL": `{name}
{company}
{street} {houseNumber}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`,
"CO": `{name}
{company}
{street} {houseNumber}
{street2}
{city}, {state}
{postalCode}
{country}
Tax Number: {taxNumber}`,
"PE": `{name}
{company}
{street} {houseNumber}
{street2}
{city} {postalCode}
{country}
Tax Number: {taxNumber}`,
"default": `{name}
{company}
{houseNumber} {street}
{street2}
{postalCode} {city}
{country}
Tax Number: {taxNumber}`
};
class IntlAddress extends HTMLElement {
static get observedAttributes() {
return ["data", "country-code", "locale"];
}
connectedCallback() {
this.render();
}
attributeChangedCallback() {
this.render();
}
render() {
try {
const addressData = this.getAddressData();
if (!addressData) {
this.innerHTML = '<div class="intl-address-error">No address data provided</div>';
return;
}
const formatted = formatAddress({ ...addressData, output: "string" });
const cleanedLines = formatted.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.match(/^[:\s]*$/));
this.innerHTML = `<div class="intl-address">${cleanedLines.join("<br>")}</div>`;
this.addStyles();
} catch (error) {
console.error("IntlAddress error:", error);
this.innerHTML = '<div class="intl-address-error">Invalid address data</div>';
}
}
getAddressData() {
const dataAttr = this.getAttribute("data");
if (dataAttr) {
try {
return JSON.parse(dataAttr);
} catch {
}
}
const countryCode = this.getAttribute("country-code");
if (!countryCode) return null;
const address = {
name: this.getAttribute("name") || void 0,
company: this.getAttribute("company") || void 0,
houseNumber: this.getAttribute("house-number") || void 0,
street: this.getAttribute("street") || void 0,
street2: this.getAttribute("street2") || void 0,
city: this.getAttribute("city") || void 0,
state: this.getAttribute("state") || void 0,
postalCode: this.getAttribute("postal-code") || void 0,
country: this.getAttribute("country") || void 0,
taxNumber: this.getAttribute("tax-number") || void 0
};
return {
countryCode,
locale: this.getAttribute("locale") || void 0,
address
};
}
addStyles() {
if (document.getElementById("intl-address-styles")) return;
const style = document.createElement("style");
style.id = "intl-address-styles";
style.textContent = `
intl-address {
display: block;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
line-height: 1.4;
}
intl-address .intl-address {
white-space: pre-line;
}
intl-address .intl-address-error {
color: #d32f2f;
font-style: italic;
padding: 8px;
background-color: #ffebee;
border: 1px solid #ffcdd2;
border-radius: 4px;
}
`;
document.head.appendChild(style);
}
}
customElements.define("intl-address", IntlAddress);
function formatAddress({
countryCode,
locale,
address,
output = "string"
}) {
const template = templates[countryCode.toUpperCase()] || templates["default"];
const formatted = template.replace("{name}", address.name || "").replace("{company}", address.company || "").replace("{houseNumber}", address.houseNumber || "").replace("{street}", address.street || "").replace("{street2}", address.street2 || "").replace("{city}", address.city || "").replace("{state}", address.state || "").replace("{postalCode}", address.postalCode || "").replace("{country}", address.country || "").replace("{taxNumber}", address.taxNumber || "");
if (output === "html") {
const div = document.createElement("div");
div.innerHTML = formatted.replace(/\n/g, "<br>");
return div;
}
if (output === "webcomponent") {
const el = document.createElement("intl-address");
el.setAttribute("data", JSON.stringify({ countryCode, locale, address }));
return el;
}
return formatted;
}
export {
IntlAddress,
formatAddress
};