Replies: 11 comments 53 replies
-
Yes pls! How is this not a bigger issue yet??! The world has many languages people.. |
Beta Was this translation helpful? Give feedback.
-
Thanks for putting this together. Looking forward to some solutions soon! |
Beta Was this translation helpful? Give feedback.
-
For people that don't need a bilingual website, they can use the english language file to store their texts. It just makes the code cleaner. For people in bilingual coutries like me in Canada, it's a must ! If I can't set up i18n in a framework, I just can't use it as a tool because most of my clients need a bilingual website. Remix has pretty much everything so that we don't have to reinvent the wheel every time we start a new project. The internationalization package is the one thing missing !!! |
Beta Was this translation helpful? Give feedback.
-
Of all the points @sergiodxa mentioned in this proposal:
I think 2-4 make a lot of sense to bake into Remix & seem like the more straightforward ones as other frameworks like Next have solutions for 2-4. Resource / brainstorm point The localization of strings would need to work for common cases like:
Shopify does i18n at scale currently (see: https://www.shopify.com/) so i hope |
Beta Was this translation helpful? Give feedback.
-
I will contribute with my experience using remix-i18next. We started the project with remix-i18next integrated because we needed to ship fast with translations without thinking much about what library to use. After some months developing our application we started to focus on Core Web Vitals and performance in general. We found out that i18next has several CPU issues causing our app to be CPU intensive in the SSR and also executing some long-tasks in the browser. So we decided to migrate it and analyzing all the options available we opted for react-intl. We liked that it uses the native Intl API and use polyfills when not supported. After this migration both problems CPU and re-render have gone. I cannot share the implementation because it's in a private repository but if you want i can make an example app showing it. |
Beta Was this translation helpful? Give feedback.
-
Hi, using Remix-i18next myself (thank you for that Sergio!), but found https://github.com/nanostores/i18n and that seems be a reasonable option? Probably overlooking a gazillion other possible issues, but it could be worth to consider as well? |
Beta Was this translation helpful? Give feedback.
-
There's also https://github.com/ivanhofer/typesafe-i18n which might serve as inspiration |
Beta Was this translation helpful? Give feedback.
-
I have been experimenting on this front and feel having a Provider (and even React components) for this is probably overkill (please let me know if I am wrong). Since Remix nicely ties server-side with client code (through loaders), we can just load the locales only on the server, use a library like Some code that I tried myself:
{
"message": "Hello, today is {ts, date, ::yyyyMMdd}"
}
import { IntlMessageFormat } from "intl-messageformat"
import invariant from "tiny-invariant"
// loads all locales server-side
import messages from "~/locales"
import { get_closest_match } from "~/utils"
export function formatMessage(
locale: string,
key: string,
variables: Record<string, string>
) {
const closestLocale = get_closest_match(locale, Object.keys(messages))
invariant(messages[closestLocale], `Locale ${closestLocale} not found`)
invariant(messages[closestLocale][key], `Message ${key} in ${closestLocale} not found`)
const message = messages[closestLocale][key]
return new IntlMessageFormat(message, closestLocale).format(variables)
} Your route: import { useLoaderData } from "@remix-run/react"
import { formatMessage } from "~/utils/formatMessage.server"
export const loader = async () => {
// the locale can be fetched either from browser request or from stored entry for user in a database
return formatMessage("en-US", "message", { ts: Date.now().toString() })
}
export default function Index() {
const message = useLoaderData<typeof loader>()
// outputs: Hello, today is 08/02/2023
return <div>{message}</div>
} |
Beta Was this translation helpful? Give feedback.
-
We are exploring building a framework-agnostic i18n library with deep integration for Remix. We would bundle the efforts of making i18n simple for the web, providing every framework with best-in-class i18n support instead of every framework building its own solution for months. See some of the apps we already provide for localization in the repo https://github.com/inlang/inlang. Is there interest from the Remix community to support our efforts? |
Beta Was this translation helpful? Give feedback.
-
Updates? |
Beta Was this translation helpful? Give feedback.
-
Have you guys looked at linguijs? I really liked to automated extraction tools |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Proposal
Add internationalization support to Remix out of the box.
Background
Internationalization is something a lot of apps needs, even if you only support a single language it's great to have it from the beginning too because adding it later it's way harder.
From my experience with remix-i18next, answering #help threads or GH Discussions with other developers, I think built-in support from Remix could help to implement it properly, and more importantly out of the box so Remix devs don't need to reach out to popular and huge libraries.
Example i18next core libray is 56.3kB plus 21kB for react-i18next integration, and while remix-i18next is smaller (6.9kB) and most code lives server-side there's a still a need for the other two.
Use Case
API/Examples
Loading localized strings
This is maybe the more important part, one way to do this is to tell devs to return them from the loader
This works, but you may want to load localized messages with a different cache policy then your route data, so one option could be to export a new function just to do this
Then Remix can even prefetch this endpoint when using
<Link prefetch>
so the messages and the data can be prefetched in parallel and cached independently.Another option is that if Remix supports loading namespaced messages it could be possible to simplify this to a static export
Then Remix should need to know how to load messages for those namespaces and for the current user locale.
The current version of remix-i18next does something like this using the handle export and with a hook and other functions in entry.server and entry.client it uses this values to load the namespaces messages.
The problem remix-i18next has with this approach so far is that when doing a client-side navigation Remix waits for preloaded links, loader's data and code, but not for the localized messages causing a flash of missing translations.
Doing it this is way more simpler for the devs but also complex for Remix since now Remix needs to know:
Translation route meta
Meta tags needs to be translated along the UI texts, here's it's tricky to do add this to Remix, the way I do it right now is that I get the
t
function from i18next inside my loader, then I generate my translated texts and return them, and in the MetaFunction I get that from dataIdeally, we want to be able to translate messages directly in MetaFunction and only use the loader to get data we need like the title of an article
This would be ideal, but now Remix needs to pass
t
.Localized route segments
This is something I haven't do myself but lots of people asks, usually for SEO, the idea is that if I have
routes/about.tsx
I want the pathnames/about
and/sobre
(Spanish) to serve the same route.Right now, the the usually recommended way to do this is by changing the routes in the routes function in
remix.config.js
.Another option is to re-export everything from
routes/about.tsx
fromroutes/sobre.tsx
and keep doing that per locale, but this will not scale IMO.One option could be to let developers provide a static list of other pathnames a route may serve
If
paths
is not define use the file name, otherwise use them.For this I think providing a different optional file-system convention to use in
remix.config.js
may be simpler.Detect user language
There are many ways to detect the user preferred language
/:locale/route/path
/route/path?locale
Most SPA do of them client-side, but in Remix you can keep all of this server-side only, set the
lang
attribute on the<html>
tag in the root route then use that to detect the locale client-side.Doing all of these things is not hard by itself and it's all in remix-i18next but I think Remix could provide a way to detect the locale automatically and pass it to loaders and actions
If the developer needs it client-side it can return it from the loader.
The only tricky part here is how to read from a DB/API, what cookie to use, what session and session key to use, what's the name of the search param and what's the possible name of the route param.
If this could be configured somewhere like in
entry.server
then the user could use default values or customize itThis could also be implemented by users if middlewares (see remix-run/react-router#9564) is implemented first.
Probably provide a way to render localized messages
This would be the most complext one, Remix could provide out of the box i18n support, something like i18next or another i18n library but directly in Remix, tied to other features like loading messages, detect the locale, localize route segments or translate meta
Open questions
Prior Art
Beta Was this translation helpful? Give feedback.
All reactions