Skip to content

Conversation

@Josip-Ledic
Copy link
Contributor

@Josip-Ledic Josip-Ledic commented Nov 6, 2025

Summary

  • add core functionality based on the following syntax: t('someKey', "Default value in English co-located like this")
  • works with SSR setup
  • detects browser language automatically
  • sample translations in German
  • added documentation to README
  • cleaned up code

- Install i18next and react-i18next with full SSR support
- Configure client-side i18n with browser language detection
- Configure server-side i18n with filesystem backend
- Add improved German translations (idiomatic business German)
- Integrate with Vite via i18next-loader plugin
- Add i18next middleware to Express server
- Update server-side entry to serialize translations for hydration
- Update client-side entry to hydrate with server state
- Translate all Welcome page content with defaultValue pattern
- Document i18n usage and architecture in CLAUDE.md

English text stays inline in components as defaultValue.
Other languages defined in src/locales/*.json files.
Browser automatically detects user's preferred language.
No language flicker due to proper SSR hydration.
@Josip-Ledic Josip-Ledic requested a review from rodet as a code owner November 6, 2025 16:37
@github-actions
Copy link

github-actions bot commented Nov 6, 2025

All contributors have signed the DCO.
Posted by the DCO Assistant Lite bot.

@Josip-Ledic
Copy link
Contributor Author

I have read the DCO document and I hereby sign the DCO.

import i18n from './i18n.client.js';

// Hydrate i18n with server state to prevent flicker
const { initialI18nStore, initialLanguage } =
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this we get "Willkommen" -> "Welcome" -> "Willkommen" because server first gets the language from the headers, returns German, then the client side is initializing its json language file and because this is async it shows English for a split second and this causes flicker. Happy to do it in a more elegant way but this is what Bob suggested after a lot of back and forth 😄

supportedLngs: ['en', 'de'],

// Important for SSR
useSuspense: false,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReactDOMServer does not yet support Suspense

preload: ['en', 'de'], // Preload all languages on server

// Important for SSR
useSuspense: false,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReactDOMServer does not yet support Suspense

};

const head = `<meta name="description" content="Server-side rendered page">
<script>window.__INITIAL_I18N_STATE__ = ${JSON.stringify(initialState).replace(/</g, '\\u003c')}</script>`;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this even the very first response from the server will contain the correct language that was sent in the request headers.

// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
plugins: [
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can also be loaded via native json file loaders but this one seemed reasonable to use https://www.npmjs.com/package/vite-plugin-i18next-loader

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant