SlideShare a Scribd company logo
1 of 65
Download to read offline
i18n was the missing piece
ARISA FUKUZAKI
DevRel Engineer at Storyblok
Make your apps accessible to 70%+ of the users in the world
Arisa Fukuzaki
福﨑 有彩
Developer Relations Engineer
GirlCode Ambassador
GDE, Web Technologies
🥑
󰟲
@arisa_dev
3 takeaways
from my talk
→
@arisa_dev
Impact of i18n
i18n fundamental logics
→
→ How Remix i18n works
Notes ⚠
→
@arisa_dev
There’re still discussions going
on about Remix & i18n features
There’s still some improvements
→
→ Join discussions #2877
Internationalization (i18n)
18 characters
“Do you like to implement i18n logic?”
Maybe, their i18n DX is not good? 🤔
Seems it’s not the best DX 👀
Based on the i18n DX, let’s talk about
numbers & facts 📊
5.07 Billion
5.07 bn. users in the world use the internet
Source: https://www.statista.com/statistics/262946/share-of-the-most-common-languages-on-the-internet/
25.9%
English is used only 25.9% on the internet
Source: https://www.statista.com/statistics/262946/share-of-the-most-common-languages-on-the-internet/
74.1%
74.1% users access non-English content
Source: https://www.statista.com/statistics/262946/share-of-the-most-common-languages-on-the-internet/
China
China has the most internet users worldwide
Source: https://www.statista.com/statistics/262946/share-of-the-most-common-languages-on-the-internet/
Asia
Asia leads more than a half of global
internet users
Source: https://www.statista.com/statistics/262946/share-of-the-most-common-languages-on-the-internet/
Huge numbers to
ignore
Knowing different approaches with more
options will solve i18n DX🪄
Let’s talk about
fundamental logic
3 ways to
Determine
languages &
regions
→
@arisa_dev
Location from IP address
Accept-Language
header/Navigator.languages
→
→ Identifier in URL
We use 2
ways - hybrid
→
@arisa_dev
Location from IP address
Accept-Language
header/Navigator.languages
→
→ Identifier in URL
3 identifier URL
patterns
Differentiate by domains (Won’t
follow the same-origin policy󰢄)
→
@arisa_dev
hello.com
hello.es
Pattern 1
URL parameters (NOT user
friendly🙅)
→
@arisa_dev
hello.com?loc=de
hello.com?loc=nl-NL
Pattern 2
Localized sub-directories 👍
→
@arisa_dev
hello.com/ja
hello.com/nl-NL
Pattern 3
Let’s talk about
Frameworks & libs
@arisa_dev
Some frameworks & libs use i18n
frameworks.
Let’s see how it works
in Remix
2 approaches
to choose
→
@arisa_dev
remix-i18next
→ CMS
remix-i18next is a npm package for Remix
to use i18next.
remix-i18next example
Default and a preferred
language.
→
@arisa_dev
{
“greeting”: “Hello”
}
Create translation
files
public/locales/en/common.json
{
“greeting”: “こんにちは”
}
public/locales/ja/common.json
i18next config file.
→
@arisa_dev
export default {
supportedLngs: ['en', 'ja'],
fallbackLng: 'en',
// customize namespace here
defaultNS: 'common',
react: {useSuspense: false},
};
Create
app/i18n.js
app/i18n.js
@arisa_dev
@storyblok
i18next.server.js
import Backend from "i18next-fs-backend";
import { resolve } from "node:path";
import { RemixI18Next } from "remix-i18next";
import i18n from "~/i18n"; // i18next config file
import languageCookie from "~/cookie";
let i18next = new RemixI18Next({
detection: {
supportedLanguages: i18n.supportedLngs,
fallbackLanguage: i18n.fallbackLng,
cookie: languageCookie,
},
// This is the config for i18next & when translating messages server-side only
i18next: {
...i18n, // Iterate arr/strings from i18next config
backend: {
loadPath: resolve("./public/locales/{{lng}}/{{ns}}.json"), // Translation file paths
},
},
// Backend to load the translation
backend: Backend,
});
export default i18next;
Create
Client-side &
Server-side
config files
→
@arisa_dev
entry.client.jsx
→ entry.server.jsx
@arisa_dev
@storyblok
entry.client.jsx
import { RemixBrowser } from "@remix-run/react";
import { hydrateRoot } from "react-dom/client";
import i18next from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import Backend from "i18next-http-backend";
import { I18nextProvider, initReactI18next } from "react-i18next";
import { getInitialNamespaces } from "remix-i18next";
import i18n from "./i18n";
i18next
// … i18next init, client-side lang detector, backend & namespace configs, etc
.then(() => {
// After i18next init, hydrate the app
// Wait to ensure translations are loaded before the hydration → WHY? Next slide.
// Wrap RemixBrowser in I18nextProvider → WHY? Next slide.
hydrateRoot(
document,
<I18nextProvider i18n={i18next}>
<RemixBrowser /> // It’s used by React to hydrate html ← received from server
</I18nextProvider>
);
});
Why translation should be loaded before
hydration?
The app is not yet interactive
→
@arisa_dev
If translation is
NOT loaded before
hydration English 日本語 “Hello”
?
@arisa_dev
English 日本語 “こんにちは”
The app is interactive
→
If translation is
loaded before
hydration
Why wrapping RemixBrowser with
I18nextProvider?
@arisa_dev
@storyblok
i18nextProvider from react-i18next
import { createElement, useMemo } from 'react';
import { I18nContext } from './context';
export function I18nextProvider({ i18n, defaultNS, children }) {
const value = useMemo(
() => ({
i18n, // i18n config
defaultNS, // default namespace
}),
[i18n, defaultNS], // i18n & defaultNS are the same ? cache calc : re-render
);
return createElement(
// …
}
Identifying user’s preferred language &
redirecting them can be done on the
server.
That’s what server-side config file does.
→ remix-i18next
Let’s use configs in
action
@arisa_dev
@storyblok
app/root.jsx
// …
import { useChangeLanguage } from "remix-i18next";
import { useTranslation } from "react-i18next";
import i18next from "~/i18next.server";
export let loader = async ({ request }) => { // loader is Backend API
let locale = await i18next.getLocale(request);
return json({ locale });
};
export let handle = {
i18n: "common",
};
export default function App() {
let { locale } = useLoaderData(); // Get the locale from the loader func
let { i18n } = useTranslation();
// useChangeLanguage updates the i18n instance lang to the current locale from loader
// Locale will be updated & i18next loads the correct translation files
useChangeLanguage(locale);
return (
<html lang={locale} dir={i18n.dir()}>
// <head /><body /> etc…
</html>
);
}
@arisa_dev
@storyblok
any route
import { useTranslation } from
'react-i18next';
export default function Component() {
let { t } = useTranslation();
return <h1>{t("greeting")}</h1>;
}
I have 3 confessions.
1. I used URL param
2. Do we (devs) need to maintain
translation files…?
3. Did we translate slugs…?
We want to
achieve…
→
@arisa_dev
Localized URL (sub-directory)
→ No translation files in code
(Headless) CMS
example
Connect your
Remix app
with CMS
@arisa_dev
i.e. Remix & Storyblok 5 min tutorial:
https://www.storyblok.com/tp/headless-cms-remix
Choose
between 4
approaches →
@arisa_dev
Mix above
→ Space (project)-level translation
→ Field-level translation
→ Folder-level translation
Splats
@arisa_dev
@arisa_dev
@storyblok
app/routes/$.tsx
export default function Page() {
// useLoaderData returns JSON parsed data from loader func
let story = useLoaderData();
story = useStoryblokState(story, {
resolveRelations: ["featured-posts.posts", "selected-posts.posts"]
});
return <StoryblokComponent blok={story.content} />
};
// loader is Backend API & Wired up through useLoaderData
export const loader = async ({ params, preview = false }) => {
let slug = params["*"] ?? "home";
slug = slug.endsWith("/") ? slug.slice(0, -1) : slug;
let sbParams = {
version: "draft",
resolve_relations: ["featured-posts.posts", "selected-posts.posts"],
};
// …
let { data } = await getStoryblokApi().get(`cdn/stories/${slug}`,
sbParams);
return json(data?.story, preview);
};
Summary
● More than a half of the users in the
world access localized content
● Know more approaches to find
better DX for your case
● i18n is related to performance, UI
&UX
@arisa_dev
Thank you - ありがとう
@arisa_dev

More Related Content

Similar to i18n was the missing piece_ make your apps accessible to 70%+ of the users in the world.pdf

Psgi Plack Sfpm
Psgi Plack SfpmPsgi Plack Sfpm
Psgi Plack Sfpm
som_nangia
 
Psgi Plack Sfpm
Psgi Plack SfpmPsgi Plack Sfpm
Psgi Plack Sfpm
wilburlo
 

Similar to i18n was the missing piece_ make your apps accessible to 70%+ of the users in the world.pdf (20)

Tech Talk - Overview of Dash framework for building dashboards
Tech Talk - Overview of Dash framework for building dashboardsTech Talk - Overview of Dash framework for building dashboards
Tech Talk - Overview of Dash framework for building dashboards
 
Writing multi-language documentation using Sphinx
Writing multi-language documentation using SphinxWriting multi-language documentation using Sphinx
Writing multi-language documentation using Sphinx
 
The Ruby On Rails I18n Core Api
The Ruby On Rails I18n Core ApiThe Ruby On Rails I18n Core Api
The Ruby On Rails I18n Core Api
 
Psgi Plack Sfpm
Psgi Plack SfpmPsgi Plack Sfpm
Psgi Plack Sfpm
 
Psgi Plack Sfpm
Psgi Plack SfpmPsgi Plack Sfpm
Psgi Plack Sfpm
 
ColdBox i18N
ColdBox i18N ColdBox i18N
ColdBox i18N
 
Rails i18n
Rails i18nRails i18n
Rails i18n
 
Intro to PSGI and Plack
Intro to PSGI and PlackIntro to PSGI and Plack
Intro to PSGI and Plack
 
CGI.ppt
CGI.pptCGI.ppt
CGI.ppt
 
Shipping your product overseas!
Shipping your product overseas!Shipping your product overseas!
Shipping your product overseas!
 
SharePoint Conference 2018 - APIs, APIs everywhere!
SharePoint Conference 2018 - APIs, APIs everywhere!SharePoint Conference 2018 - APIs, APIs everywhere!
SharePoint Conference 2018 - APIs, APIs everywhere!
 
I18n in Rails2.2
I18n in Rails2.2I18n in Rails2.2
I18n in Rails2.2
 
SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!
SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!
SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!
 
APIs, APIs Everywhere!
APIs, APIs Everywhere!APIs, APIs Everywhere!
APIs, APIs Everywhere!
 
Formatting ForThe Masses
Formatting ForThe MassesFormatting ForThe Masses
Formatting ForThe Masses
 
Plack - LPW 2009
Plack - LPW 2009Plack - LPW 2009
Plack - LPW 2009
 
Having Fun with Play
Having Fun with PlayHaving Fun with Play
Having Fun with Play
 
XebiConFr 15 - Brace yourselves Angular 2 is coming
XebiConFr 15 - Brace yourselves Angular 2 is comingXebiConFr 15 - Brace yourselves Angular 2 is coming
XebiConFr 15 - Brace yourselves Angular 2 is coming
 
WCRI 2015 I18N L10N
WCRI 2015 I18N L10NWCRI 2015 I18N L10N
WCRI 2015 I18N L10N
 
PhoneGap JavaScript API vs Native Components
PhoneGap JavaScript API vs Native ComponentsPhoneGap JavaScript API vs Native Components
PhoneGap JavaScript API vs Native Components
 

Recently uploaded

Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo DiehlFuture Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Peter Udo Diehl
 

Recently uploaded (20)

A Business-Centric Approach to Design System Strategy
A Business-Centric Approach to Design System StrategyA Business-Centric Approach to Design System Strategy
A Business-Centric Approach to Design System Strategy
 
The UX of Automation by AJ King, Senior UX Researcher, Ocado
The UX of Automation by AJ King, Senior UX Researcher, OcadoThe UX of Automation by AJ King, Senior UX Researcher, Ocado
The UX of Automation by AJ King, Senior UX Researcher, Ocado
 
What's New in Teams Calling, Meetings and Devices April 2024
What's New in Teams Calling, Meetings and Devices April 2024What's New in Teams Calling, Meetings and Devices April 2024
What's New in Teams Calling, Meetings and Devices April 2024
 
Where to Learn More About FDO _ Richard at FIDO Alliance.pdf
Where to Learn More About FDO _ Richard at FIDO Alliance.pdfWhere to Learn More About FDO _ Richard at FIDO Alliance.pdf
Where to Learn More About FDO _ Richard at FIDO Alliance.pdf
 
SOQL 201 for Admins & Developers: Slice & Dice Your Org’s Data With Aggregate...
SOQL 201 for Admins & Developers: Slice & Dice Your Org’s Data With Aggregate...SOQL 201 for Admins & Developers: Slice & Dice Your Org’s Data With Aggregate...
SOQL 201 for Admins & Developers: Slice & Dice Your Org’s Data With Aggregate...
 
Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024Extensible Python: Robustness through Addition - PyCon 2024
Extensible Python: Robustness through Addition - PyCon 2024
 
WebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM PerformanceWebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM Performance
 
Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...
Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...
Behind the Scenes From the Manager's Chair: Decoding the Secrets of Successfu...
 
AI presentation and introduction - Retrieval Augmented Generation RAG 101
AI presentation and introduction - Retrieval Augmented Generation RAG 101AI presentation and introduction - Retrieval Augmented Generation RAG 101
AI presentation and introduction - Retrieval Augmented Generation RAG 101
 
IoT Analytics Company Presentation May 2024
IoT Analytics Company Presentation May 2024IoT Analytics Company Presentation May 2024
IoT Analytics Company Presentation May 2024
 
Top 10 Symfony Development Companies 2024
Top 10 Symfony Development Companies 2024Top 10 Symfony Development Companies 2024
Top 10 Symfony Development Companies 2024
 
Free and Effective: Making Flows Publicly Accessible, Yumi Ibrahimzade
Free and Effective: Making Flows Publicly Accessible, Yumi IbrahimzadeFree and Effective: Making Flows Publicly Accessible, Yumi Ibrahimzade
Free and Effective: Making Flows Publicly Accessible, Yumi Ibrahimzade
 
AI revolution and Salesforce, Jiří Karpíšek
AI revolution and Salesforce, Jiří KarpíšekAI revolution and Salesforce, Jiří Karpíšek
AI revolution and Salesforce, Jiří Karpíšek
 
Designing for Hardware Accessibility at Comcast
Designing for Hardware Accessibility at ComcastDesigning for Hardware Accessibility at Comcast
Designing for Hardware Accessibility at Comcast
 
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdfHow Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
How Red Hat Uses FDO in Device Lifecycle _ Costin and Vitaliy at Red Hat.pdf
 
Custom Approval Process: A New Perspective, Pavel Hrbacek & Anindya Halder
Custom Approval Process: A New Perspective, Pavel Hrbacek & Anindya HalderCustom Approval Process: A New Perspective, Pavel Hrbacek & Anindya Halder
Custom Approval Process: A New Perspective, Pavel Hrbacek & Anindya Halder
 
TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...
TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...
TEST BANK For, Information Technology Project Management 9th Edition Kathy Sc...
 
ECS 2024 Teams Premium - Pretty Secure
ECS 2024   Teams Premium - Pretty SecureECS 2024   Teams Premium - Pretty Secure
ECS 2024 Teams Premium - Pretty Secure
 
Simplified FDO Manufacturing Flow with TPMs _ Liam at Infineon.pdf
Simplified FDO Manufacturing Flow with TPMs _ Liam at Infineon.pdfSimplified FDO Manufacturing Flow with TPMs _ Liam at Infineon.pdf
Simplified FDO Manufacturing Flow with TPMs _ Liam at Infineon.pdf
 
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo DiehlFuture Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
 

i18n was the missing piece_ make your apps accessible to 70%+ of the users in the world.pdf