One locale, three scripts
Japanese is refreshingly simple on the locale axis. Unlike Spanish (es-ES/es-MX) or Chinese (zh-Hans/zh-Hant), it's monocentric: there is essentially one standard locale, ja-JP, with no regional split you need to ship. Apple keys it as ja (the folder is ja.lproj); Android uses values-ja. One slot, no variant matrix to reason about.
The complexity moves into the writing system. Japanese interleaves three scripts inside a single sentence:
- Kanji (漢字) — logographic characters for most content words: 設定 (Settings), 検索 (Search), 完了 (Done).
- Hiragana (ひらがな) — grammar glue: particles, verb endings, function words like が, を, します.
- Katakana (カタカナ) — foreign loanwords and much of the tech vocabulary.
Mobile UI leans hard on katakana loanwords: Download → ダウンロード, Update → アップデート, Login → ログイン, App → アプリ. But not everything foreign-sounding becomes katakana — Settings stays 設定 (kanji), and Share is usually 共有, not シェア. Knowing when a term is idiomatically katakana versus a native kanji word is a judgment call generic MT frequently gets wrong, producing stiff or unnatural labels.
The decision that actually matters: politeness register
This is where localizing for Japan gets decided. Japanese encodes social distance grammatically, so the same "Saved" can be written several ways depending on how the app should sound to the user:
| Register |
"Saved" |
When you'd use it |
| Plain form (常体) |
保存した |
Casual, terse — a friendly social app talking to itself |
| Polite / teineigo (丁寧語) |
保存しました |
The default for most consumer apps |
| Honorific / keigo (敬語) |
保存いたしました |
Formal, deferential — banking, enterprise, concierge |
None of these is "correct" in the abstract — the right one depends on your app's voice. Most consumer apps ship teineigo (です・ます) throughout; a casual app might deliberately pick plain form; a financial app reaches for keigo.
The real failure mode is mixing them within one app. If onboarding greets the user with おかえりなさい (polite) but an error dialog drops to plain 失敗した, a Japanese reader feels the seam instantly — as jarring as flipping between buttoned-up and slangy English mid-flow. Because strings.dev feeds your app description into every translation, it can hold one register across all your strings instead of re-guessing the politeness level string by string, which is exactly where generic translation drifts.
A real string: honorific, counter, placeholders intact
Here's an English source string with two iOS placeholders and its actual Japanese translation in polite register:
/* English source (Localizable.strings) */
"inbox_greeting" = "Welcome back, %@! You have %lld unread messages.";
/* Japanese (ja) — teineigo, placeholders preserved */
"inbox_greeting" = "%@さん、おかえりなさい。未読メッセージが%lld件あります。";
Several things happen at once. The %@ and %lld placeholders survive untouched. The name placeholder picks up the honorific suffix さん (%@さん) — the natural, polite way to address a user. あります is the polite existential verb, matching the register. And %lld件 stays fixed no matter the count — which is the next thing worth understanding.
No plural forms — but you do need counters
Japanese has no grammatical plural inflection. In CLDR terms it has a single cardinal category, other; a noun is identical whether there is one item or a thousand. The English 1 message / 5 messages branch simply collapses:
1 unread message → 未読メッセージが1件あります
5 unread messages → 未読メッセージが5件あります
So you don't need <plurals> quantity branches or per-count String Catalog variations for Japanese the way you do for English or Russian. What you do need is the right counter word (助数詞) glued to the number: 件 for items and notifications, 通 for messages and mail, 人 for people, 個 for generic objects. strings.dev keeps your %lld/%d and pairs it with the natural counter rather than emitting a mechanical "5 メッセージ."
CJK compression bends your layout two ways
Japanese usually renders in far fewer characters than English. "Settings" (8 letters) becomes 設定 (2 characters); "Done" becomes 完了; "Search" becomes 検索. Your buttons and labels often shrink — which is its own trap, because two things push back:
- Katakana loanwords can run longer than you'd expect: アップデート is six characters for "Update."
- Japanese has no spaces between words, so wrapping happens per-character under kinsoku (禁則処理) rules that forbid certain characters at the start or end of a line. Fixed-width buttons sized around English can break in awkward places.
Test your tightest labels and your longest katakana strings — the average case will lie to you.
Locale codes at a glance
| Platform |
Identifier |
| BCP-47 |
ja-JP (or bare ja) |
| Apple / iOS |
ja → ja.lproj |
| Android |
values-ja |
The full cross-platform mapping lives in the iOS & Android locale codes reference.
Adding Japanese to your project
strings.dev takes your native export — an Xcode .xcloc or Android strings.xml — and returns the same format with Japanese filled in, placeholders (%@ %lld %1$@, %s %d %1$s) and brand phrases protected. Your app description sets the register once, so teineigo stays teineigo everywhere instead of sliding into plain form on the screens you forgot to check.
One honest note on tiers: the free Indie plan covers your first language (1 project, 1 language, unlimited words). If Japanese is that first language, it's free. If you're adding Japanese as a second locale alongside an existing one, that needs Indie Plus — unlimited languages, 2 projects, brand context, and the QA dashboard — at $20/mo, or $10/mo billed annually (pricing). Start from free app localization, or open the platform to upload a file.