solidjs / solid-site

Code that powers the SolidJS.com platform.
https://www.solidjs.com
159 stars 173 forks source link

Website translation structure proposal #116

Closed davedbase closed 2 years ago

davedbase commented 3 years ago

Hi folks, I'm looking for some advice on setting up structure for translate the whole Solid Site. Here are a few options I've come up with:

Option 1 - Use JSON files to outline copy throughout the pages then use solid-i18n to manage lang switching.

Option 2 - Use a different format like TOML or YAML because it's easier to write than JSON. Convert them to JSON and use solid-i18n. Example of TOML:

hero = "A declarative, efficient and flexible JavaScript library for building user interfaces."
sub_hero = "Solid is a purely reactive library. It was designed from the groun up with a reactive core. It's influenced by reactive principles developed by previous libraries."

[features.performant]
img = "assets/icons/performant.svg"
title = "Performant"
description = "Consistently tops recognized UI speed and memory utilization benchmarks."

[features.powerful]
img = "assets/icons/powerful.svg"
title = "Powerful"
description = "Composable reactive primitives married with the flexibility of JSX."

[features.pragmatic]
img = "assets/icons/pragmatic.svg"
title = "Pragmatic"
description = "A sensible and tailored API makes developing fun and simple."

[features.productive]
img = "assets/icons/productive.svg"
title = "Productive"
description = "Ergonomics and familiarity make building simple or complex things a breeze."

[quickfeatures.stars]
title = "9.5k+"
subtitle = "Github Stars"
link = "https://star-history.t9t.io/#solidjs/solid"

[quickfeatures.years]
title = "5+ years"
subtitle = "In development"

[quickfeatures.typescript]
title = "TypeScript"
subtitle = "Support"

[quickfeatures.rated]
title = "Top Rated"
subtitle = "In performance"

Option 3 - Find a way to support MDX on the site and manage translations in Markdown and write Solid JSX components into the file as needed.

Other suggestions are more than welcomed.

yamiteru commented 3 years ago

For simple things like hero JSON/YAML is a good solution. But for things that have some fixed structure like features it'd be best to use TS to minimise the possibility of a stupid bug caused by a wrong type or a missing required property.

So why not write everything in TS?

davedbase commented 3 years ago

I think right now I'm leaning towards YAML. TS could work. That's basically how we're structuring the Resources section of the site which benefits from strict typing since there's a lot of categorization + tagging of content. With languages it's just strings so it would get less type benefit.

I'd likely want to structure it in a way that only the language data needed for the language the user is viewing gets shipped. Not all the languages.

davedbase commented 3 years ago

Ok, I've gone ahead and put all the copy into a TS file: https://github.com/solidjs/solid-site/blob/i18n/langs/en.ts

@amoutonbrady if you have a moment I'd love your opinion on this. To mitigate the issue of loading many translations I suppose we could just lazy load the TS. The alternative is just turn this into a flat JSON file.

davedbase commented 3 years ago

Oh also I'm wondering about how to propagate the localization. Thinking use the browser locale and then override it if a user forces a different language. Store the value in localStorage. The other options are: a) query string override, b) subdomains ie jp.solidjs.com.

I've seen it done every which way, localStorage feels the cleanest with the option to specify query string to set the store value.

amoutonbrady commented 3 years ago

@davedbase I think the structure you've setup is pretty fine. If we want to optimize a little more, I'd say, instead of purt everything into a single file / folder, we could instead have it on a per page / component bases. I doubt that many translations are shared.

What I mean is for instance to have all the Home.tsx translations in the Home.tsx page. That would get the benefit of being lazy loaded with the page.

As per the location strategy, I often see it store in the cookies for some reasons. This is what the nuxt translation module does by default. That's probably for some SSR reasons so that you can know the language preference ahead of rendering and serve the page properly.

Either way, the path you mentioned seemed completely appropriate, first check if the user has a preference already set, if not, pick the browser preference (or the proper header in doing SSR) and then fallback to English.

davedbase commented 3 years ago

Yup I agree. I separated the en.ts into separate .ts files named after each section. Could we use the data fetch in the router to resolve both the page specific data and the lang file? If so I'm wondering the best way to model that? They all export basic JSON via a function right now though. A few things to solve:

  1. How can I fetch the Global.ts to provide data for the nav and footer across every route.
  2. Should I just add onto the current data components that already exist or is there a more global way ie. perhaps wrap each data resolver function with a lang resolve? I don't actually like this, but it's a thought: { path: '/docs', data: GetLang('./langs/en/Docs.ts', DocsData) }
  3. Use context somehow?
  4. I put nav and footer inside a Global.ts because it's basically always fetched. Those should be resolved and cached across all routes.

You make a good point about cookies. I'm finishing up a new primitive that to that, so once I figure it out I'll switch to that. Then you're right we get SSR'd page resolution. I like it!

I prototyped the lang selector on dev: https://dev.solidjs.com/

davedbase commented 3 years ago

Quick update @amoutonbrady I've decided to store the translations as basic JSON files. If you review the i18n branch I have it and en done so far. The next step is deciding how to actually request and maintain the translations via the router fetch alongside the pages regular dataset. ie. Docs gets data from one JSON and langs from a different one.