Theme-ui: Support for localized theme overrides

Created on 18 Feb 2020  路  3Comments  路  Source: system-ui/theme-ui

Is your feature request related to a problem? Please describe.
When creating an internationalized site, sometimes you would want different stylings for different languages. For example, languages such as Japanese or Chinese might require a different font family and font size, and some widths need to be adjusted to account for different text lengths across languages.

Currently, the only way to really do this is to query on individual languages across styles.

const { locale } = useIntl() // get locale from some provider
<Box
  sx={{
    fontFamily: locale === "ja" ? "Mincho" : "Helvetica"
  }} />

This is cumbersome, especially when multiple languages are involved across multiple components and styles.

Describe the solution you'd like
Ideally, theme-ui would be able to define overrides on themes based on locale:

theme = {
  fonts: {
    body: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif',
    heading: 'Georgia, serif',
    monospace: 'Menlo, monospace',
  },
  fontSizes: [
    12, 14, 16, 20, 24, 32, 48, 64
  ],
  ja: { // Override fonts and font sizes for Japanese
    fonts: {
      body: 'Mincho, system-ui'
    },
    fontSizes: [
      10, 12, 14, 18, 22, 30, 40, 60
    ]
  }
}

The locale can be set using a useLocale() hook that works much like the useColorMode() hook:

const [, setLocale] = useLocale()
setLocale(locale) // set to locale

Describe alternatives you've considered
N/A

Additional context
Related: #689

enhancement help wanted

Most helpful comment

I feel like the "partial themes" option is better and would be easier to work with from a developer perspective. You're usually looking at a page in a single locale and thinking "what are the style edits I need to do to make this work" rather than, say, scrolling through all the languages and checking the fonts for each one.

As for interfacing with other i18n related tools -- most of them provide a locale or lang value through a hook, HOC, or render prop and as long as theme-ui can interface with that, we should be good.

Some popular i18n tools for React are:

All 3 comments

First of all, I love this idea and thanks for opening these issues! Anything that can make styling for localization easier seems like a great fit for Theme UI.

There's probably more than one way to handle this, but my first thought is that the shape of the overrides could maybe follow the same conventions as color modes (with locale replacing modes) and have general/default values at the top level of each scale, with locale-specific objects nested within, e.g.:

{
  fonts: {
    body: 'system-ui, sans-serif',
    ja: {
      body: 'Mincho, system-ui', 
    }
  }
}

The other way I've been thinking about some things related to this is support for top-level theme modes, so that a base theme object can be overridden/merged with another partial theme object. E.g.:

// base theme
{
  fonts: {
    body: 'system-ui, sans-serif',
    monospace: 'Menlo, monospace',
  },  
}

// partial theme or "mode"
ja: {
  fonts: {
    body: 'Mincho, system-ui',
  }
}
<ThemeProvider
  theme={theme}
  modes={{
    ja: japaneseTheme,
    zh: chineseTheme,
  }}  
/>

Curious if you have any thoughts around that part of the API.

The other question I have is: are there existing i18n-related tools that this should easily integrate with or is it helpful for Theme UI to handle internal React state/hooks/etc.?

I feel like the "partial themes" option is better and would be easier to work with from a developer perspective. You're usually looking at a page in a single locale and thinking "what are the style edits I need to do to make this work" rather than, say, scrolling through all the languages and checking the fonts for each one.

As for interfacing with other i18n related tools -- most of them provide a locale or lang value through a hook, HOC, or render prop and as long as theme-ui can interface with that, we should be good.

Some popular i18n tools for React are:

This sounds great, but I don鈥檛 think we need to make any changes for now for this to be supported. We recommend making separate theme files for each locale, sharing the same base theme & using standard JavaScript (and/or our merge utility, documented here) to make locale-specific changes to the theme. Then, wherever you鈥檙e implementing your <ThemeProvider>, import the themes as necessary & pass the correct one depending on user context. We鈥檙e closing for now, & it鈥檇 definitely be great to add this technique specifically to the docs, but please let us know if there鈥檚 more we should support.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

johno picture johno  路  3Comments

kiastorm-zz picture kiastorm-zz  路  4Comments

jxnblk picture jxnblk  路  4Comments

cwgw picture cwgw  路  3Comments

blummis picture blummis  路  4Comments