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

PatternDetail
Per-field argname(locale: "fr"): String
Context localeUse ctx.locale as default
All translationsReturn 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

SchemaDetail
Wide rowname_en, name_fr, name_es columns
Translation table(entity, entityId, locale, field, value)
JSONB columnname 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

ApproachDetail
Server returns ISOClient formats with Intl.DateTimeFormat
Server formatsField arg format: String
Tz-awareAlways include timezone offset

7. Formatting Numbers

TypePattern
DecimalServer returns raw, client formats
Locale-awareIntl.NumberFormat
MoneyUse 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

AspectDetail
Schema neutralRTL is a presentation concern
Locale fieldClient uses Intl.Locale.textInfo.direction
CSSdir="rtl" + logical properties

10. Using Accept-Language Header

Example: Locale from header

context: ({ req }) => ({
  locale: parseAcceptLanguage(req.headers["accept-language"], ["en", "fr", "es"], "en")
})