Handle International Addresses in Ruby

Published

Handle International Addresses in Ruby

You're building an e-commerce site. Everything's going great until a customer from Japan tries to check out and your form is asking them for a "State" and "ZIP code."

Spoiler alert: Japan doesn't use either of those.

Or maybe you're printing shipping labels and discover that the USPS wants certain fields in ALL CAPS for automated sorting, but you have no idea which fields or why.

Welcome to the nightmare that is international address handling.

The problem nobody warns you about

Here's what makes addresses so deceptively difficult:

  • The UK calls it a "postcode." Americans call it a "ZIP code." Canadians call it a "postal code."
  • Japanese addresses go from largest to smallest (the complete opposite of Western addresses)
  • Some countries don't have postal codes at all
  • Ireland uses "County" but the US uses "State" and Canada uses "Province" (or sometimes "Territory")
  • For automated mail sorting, you need to uppercase specific fields in specific countries

You can spend weeks researching postal systems across 200+ countries, or you can use a library that's already done the work.

That's where Addressing comes in.

What it does

Addressing is a Ruby gem that handles the messy reality of postal addresses worldwide:

  • 250+ country definitions with proper translations (powered by CLDR data)
  • 200+ address formats so you know which fields to show and in what order
  • Subdivisions for 60 countries (states, provinces, prefectures, whatever they call them locally)
  • Smart formatting in both HTML and plain text
  • Built-in validation for Active Record models

Let's see it in action.

Your first address

Here's a simple example displaying an address:

ruby
address = Addressing::Address.new(
country_code: "US",
administrative_area: "CA",
locality: "Mountain View",
address_line1: "1600 Amphitheatre Parkway",
given_name: "Sundar",
family_name: "Pichai"
)
formatter = Addressing::DefaultFormatter.new
puts formatter.format(address)

This outputs properly formatted HTML with fields in the right order for the US, complete with semantic CSS classes. The country name is automatically localized.

No guessing. No hardcoding. Just correct addresses.

Real-world examples

Building a checkout form that works everywhere

Different countries need different fields. Nobody in Japan needs a "State" dropdown, but they absolutely need a "Prefecture" field:

ruby
# Get the address format for Japan
format = Addressing::AddressFormat.get('JP')
# Build your form dynamically
format.used_fields.each do |field|
puts "#{format.label_for(field)}: [input field]"
end

Your Japanese customers see the fields they expect. Your UK customers don't see irrelevant fields. Simple.

Rails validation

Your model needs to accept addresses from anywhere:

ruby
class Order < ApplicationRecord
validates_address_format
end

Done. Postal codes get validated against country-specific patterns. Required fields get enforced. Customers can actually complete checkout.

Printing shipping labels

You're printing labels for international shipments. Some countries require specific fields in ALL CAPS for automated sorting:

ruby
address = Addressing::Address.new(
country_code: "US",
administrative_area: "CA",
locality: "Mountain View",
address_line1: "1098 Alta Ave"
)
formatter = Addressing::PostalLabelFormatter.new(origin_country: "FR")
puts formatter.format(address)
# Output:
# 1098 Alta Ave
# MOUNTAIN VIEW, CA 94043
# ÉTATS-UNIS - UNITED STATES

Notice what happened:

  • City and state got uppercased (USPS requirement)
  • Country name appears in both French and English (Universal Postal Union recommendation)
  • Everything formatted for international mail from France

Zero manual formatting. Zero postal regulation research.

Country selectors in any language

Need a dropdown in the user's language?

ruby
# Get all countries in Japanese
countries = Addressing::Country.list('ja-JP')
# => { "JP" => "日本", "US" => "アメリカ合衆国", ... }
# Or get detailed info
brazil = Addressing::Country.get('BR')
puts brazil.currency_code # "BRL"
puts brazil.timezones # All timezones Brazil spans

French users see "États-Unis." Japanese users see "アメリカ合衆国." Automatic.

Cascading location dropdowns

Those forms where selecting a country shows states, then cities:

ruby
# Get all states in Brazil
states = Addressing::Subdivision.all(['BR'])
# User selected Ceará? Get municipalities
municipalities = Addressing::Subdivision.all(['BR', 'CE'])
# Traverse the hierarchy
states.each do |state|
state.children.each do |municipality|
puts "#{state.name} - #{municipality.name}"
end
end

The data is hierarchical and translated. You just wire it up.

Why this beats rolling your own

Packaged research. This builds on Google's Address Data Service and the CLDR project—years of work across every country. One bundle install gets you all of it.

No surprises. You won't discover months into production that Singapore uses six-digit postal codes or that Russia uses Cyrillic addresses.

Stays current. Address formats change. Countries split. Subdivisions get renamed. The gem tracks CLDR updates automatically.

Battle-tested. This ports the PHP addressing library from CommerceGuys, already proven in major e-commerce platforms.

When to use this

E-commerce platforms where wrong addresses mean failed deliveries and lost money.

Booking systems needing accurate location data from international customers.

Multi-tenant SaaS where customers operate across different countries.

Shipping tools generating labels that comply with postal regulations worldwide.

Getting started

Check out Addressing on GitHub for installation and complete documentation.

Add it to your Gemfile, wire up the validators and formatters, and you're done. No more failed deliveries, no more checkout abandonment, no more becoming a postal regulation expert for every market.

Wrong addresses cost real money through failed shipments and frustrated customers. This gem packages up years of research into something you install once and forget about.

It's focused. It solves one problem really well. Sometimes that's exactly what you need.

Next time you're about to add a "State" field to an international form, remember: there's a better way.

Have you dealt with address format nightmares? I'd love to hear about your solutions!