Skip to main content
FomiVIP
Service Cases

A Three-Language Inbound Travel Site — Held Up by Date Formats

An inbound travel site needed Chinese, English and Japanese over 60 itinerary pages — a main table plus a translations table, not three sites. Dates stalled us: 2026年11月5日 in Japanese, 05 Nov 2026 in English. A CSV backfill broke 37 of 2,000+ rows on line breaks; fgetcsv and a format table fixed it.

July 22, 2016MultilingualTravel WebsiteData Model

This client runs inbound tourism, mainly serving groups from Japan and English-speaking countries. The site needed Chinese, English, and Japanese, with about 60 itinerary pages, each holding six blocks: title, intro, duration, departure dates, price, and notes. Sounds simple — but the hardest part wasn't translation. It was dates and currency.

Structure First, and Lock It Down

We didn't build a separate set of pages per language. The database keeps an itinerary main table for shared fields (duration, price, departure-city id) plus a translations table keyed by language_code and item_id — three languages, three rows. When the admin adds an itinerary, the editor fills in text three times, no page duplication.

Language sits in the first URL segment: /ja/tours/12, /en/tours/12. One Nginx rewrite rule covers it — no per-language routing.

The Date Format Argument Ran Two Rounds

The Japanese site had to show 2026年11月5日, the English site 05 Nov 2026, the Chinese site 2026-11-05. One departure date, three different renderings. We first tried PHP's strftime with locale switching, but the server's locales were incomplete — no Japanese locale installed, output falling straight back to English.

So we wrote a small function instead: dates stored uniformly as DATE in the database; at output time, look up a format table by language_code — three template strings. Under twenty lines of code, and far steadier than fighting system locales.

Prices Don't Convert, but Formats Change

The client was explicit: pages show RMB only, no automatic exchange conversion — they didn't want rates drifting out of sync. But number separators and currency-symbol placement differ on the English and Japanese sites: ¥12,800 vs 12,800 元. That's part of the format table too. Also, the Japanese 'notes' blocks ran noticeably longer than the Chinese, so card heights couldn't be fixed — we switched the list to flex wrapping with no hard-coded heights.

The Two Weeks of Translation Backfill

We didn't do the translating — the client hired translators. The admin offered a bulk import, a 3-column CSV: item_id, language_code, text. The first import script didn't handle line breaks: translators had hit Enter inside cells, splitting one row into two, and 37 of 2,000+ rows came in wrong. It only became accurate after switching to PHP's fgetcsv with the enclosure set correctly. That day we verified the entire imported dataset, sorted by item_id, printed page by page, and compared.

After Launch

The language dropdown sits at the top right; the choice is remembered in a cookie so returning visitors land in their language. No auto-redirect by browser language — the client said some team members run English browsers but want the Chinese site, and we shouldn't decide for them.

The site still runs. A visa application form was added later, but that's another story.

Consulting · Free initial chat

Need advice for your scenario?

Tell us your business context and current systems, and we'll give an actionable approach.

Contact us

Mon–Fri 9:00–18:00 · We respond on business days within one business day.

WeChat (Business Only)
WeChat (Business Only)二维码

Scan and add our WeChat for consulting

Or fill out the requirements form