Implementing Internationalization
1. Implementing Locale Arguments
Example: locale arg
type Query {
product(id: ID!, locale: String = "en-US"): Product
}
type Product {
name(locale: String): String!
description(locale: String): String!
}
2. Translating Field Values
| Pattern | Detail |
|---|---|
| Per-field arg | name(locale: "fr"): String |
| Context locale | Use ctx.locale as default |
| All translations | Return list of LocalizedString |
3. Using Translation Objects
Example: All translations
type LocalizedString { locale: String!, value: String! }
type Product {
name(locale: String): String!
nameAll: [LocalizedString!]!
}
4. Storing Translations
| Schema | Detail |
|---|---|
| Wide row | name_en, name_fr, name_es columns |
| Translation table | (entity, entityId, locale, field, value) |
| JSONB column | name JSONB = {"en": "x", "fr": "y"} |
5. Implementing Fallback Locale
Example: Locale fallback chain
function translate(field, locale, fallback = "en") {
return field[locale] ?? field[locale.split("-")[0]] ?? field[fallback];
}
6. Formatting Dates
| Approach | Detail |
|---|---|
| Server returns ISO | Client formats with Intl.DateTimeFormat |
| Server formats | Field arg format: String |
| Tz-aware | Always include timezone offset |
7. Formatting Numbers
| Type | Pattern |
|---|---|
| Decimal | Server returns raw, client formats |
| Locale-aware | Intl.NumberFormat |
| Money | Use Money type with amount + currency |
8. Formatting Currency
Example: Money type
type Money {
amount: Int! # minor units (cents)
currency: String! # ISO 4217
formatted(locale: String): String!
}
9. Implementing RTL Support
| Aspect | Detail |
|---|---|
| Schema neutral | RTL is a presentation concern |
| Locale field | Client uses Intl.Locale.textInfo.direction |
| CSS | dir="rtl" + logical properties |