(i18n) Improve Japanese `ja.ts` error messages to be japanese friendly
enhancement
This might be somewhat related to https://github.com/open-circle/valibot/issues/1453 . However, I believe this issue is worth fixing even in the current i18 version, at least in Japanese.
# Motivation
The current Japanese translation in `ja.ts` embeds `issue.expected` and `issue.received` directly into messages. These values use programmer-oriented symbols defined in Valibot's core (e.g. `>=3`, `!0`, `!"banned"`), which is consistent with how the English default messages work.
However, when Japanese messages are displayed, those symbols appear inside natural Japanese sentences and feel deeply unnatural to Japanese speakers.
## Example: what users actually see
The `>=3` notation is arguably acceptable in English because it reads naturally as a mathematical expression in that context. In Japanese, however, embedding symbols like `>=3` or `!0` inside a Japanese sentence creates a jarring, unnatural reading experience that most Japanese speakers would find confusing.
### `minBytes(3)` with input `"a"`
```
無効なバイト数: >=3 を期待しましたが、 1 を受け取りました
```
### `nonEmpty()` with empty string
```
無効な長さ: !0 を期待しましたが、 0 を受け取りました
```
### `notValue("banned")` with `"banned"`
```
無効な値: !"banned" を期待しましたが、 "banned" を受け取りました
```
## end-user exposure
One might argue that Valibot error messages are only read by developers. This is true in many cases. For example, when inspecting API error responses during development.
However, there are common real-world scenarios where these messages are exposed directly to end users.
### Frontend validation
```ts
// Valibot is used to validate form input on the client side
const result = v.safeParse(schema, formData);
if (!result.success) {
showToast(result.issues[0].message); // shown directly to the user
}
```
### Backend validation with pass-through error responses
```ts
// Backend validates request body and returns issues as-is
const result = v.safeParse(schema, req.body);
if (!result.success) {
return res.status(400).json({ errors: result.issues.map(i => i.message) });
}
// Frontend displays these messages directly in the UI
```
In both cases, a message like `無効な長さ: !0 を期待しましたが、 0 を受け取りました` would be shown to a general user. The expression `!0` is not common in Japan, so many end users will not understand its meaning.
While developers can always override messages with `setSpecificMessage`, requiring them to redefine every validator message just to make them human-readable is a significant burden. I believe the content should be understandable to anyone, whether they are a programmer or a non-programmer end-user.
# Proposal
The direct translation of `en.ts` into `ja.ts` sounds very unnatural to Japanese speakers due to cultural and grammatical differences.
Therefore, instead of simply using a direct translation of `en.ts` for `ja.ts`, how about revising the message to something that both programmers and average Japanese speakers can understand?
The approach is simple: don't embed `issue.expected` directly into the Japanese text. Instead, use `issue.requirement` (the actual constraint value). This alone will make the Japanese text sound overwhelmingly more natural.
## `min` / `max` / `gt` / `lt` series
```ts
// Before
minBytes: (issue) => `無効なバイト数: ${issue.expected} を期待しましたが、 ${issue.received} を受け取りました`,
// After
minBytes: (issue) => `バイト数が不足しています: ${issue.requirement} バイト以上である必要がありますが、 ${issue.received} バイトを受け取りました`,
maxBytes: (issue) => `バイト数が超過しています: ${issue.requirement} バイト以下である必要がありますが、 ${issue.received} バイトを受け取りました`,
minLength: (issue) => `文字数が不足しています: ${issue.requirement} 文字以上である必要がありますが、 ${issue.received} 文字を受け取りました`,
maxLength: (issue) => `文字数が超過しています: ${issue.requirement} 文字以下である必要がありますが、 ${issue.received} 文字を受け取りました`,
minValue: (issue) => `値が小さすぎます: ${issue.requirement} 以上である必要がありますが、 ${issue.received} を受け取りました`,
maxValue: (issue) => `値が大きすぎます: ${issue.requirement} 以下である必要がありますが、 ${issue.received} を受け取りました`,
gtValue: (issue) => `値が小さすぎます: ${issue.requirement} より大きい値である必要がありますが、 ${issue.received} を受け取りました`,
ltValue: (issue) => `値が大きすぎます: ${issue.requirement} より小さい値である必要がありますが、 ${issue.received} を受け取りました`,
```
## `nonEmpty` / `empty` series
```ts
// Before
nonEmpty: (issue) => `無効な長さ: ${issue.expected} を期待しましたが、 ${issue.received} を受け取りました`,
// → "無効な長さ: !0 を期待しましたが、 0 を受け取りました"
// After...Very Simple!!
nonEmpty: (_issue) => `空にすることはできません`,
empty: (_issue) => `空である必要があります`,
```
## `not` series
```ts
// Before
notBytes: (issue) => `無効なバイト数: ${issue.expected} を期待しましたが、 ${issue.received} を受け取りました`,
// → "無効なバイト数: !5 を期待しましたが、 5 を受け取りました"
// After
notBytes: (issue) => `無効なバイト数: ${issue.requirement} バイトは使用できません`,
notLength: (issue) => `無効な文字数: ${issue.requirement} 文字は使用できません`,
notGraphemes: (issue) => `無効な書記素数: ${issue.requirement} は使用できません`,
notEntries: (issue) => `無効な項目数: ${issue.requirement} 件は使用できません`,
notSize: (issue) => `無効なサイズ: ${issue.requirement} は使用できません`,
notWords: (issue) => `無効な単語数: ${issue.requirement} 単語は使用できません`,
notValue: (issue) => `使用できない値です: ${issue.requirement} は入力できません`,
notValues: (_issue) => `使用できない値が含まれています`,
```
2 条评论