README.md
· 1.5 KiB · Markdown
Raw
# i18n in Vanilla JavaScript - [[Playground](https://playpen.sudovanilla.org/#H4sIAAAAAAAAA51U3YrbRhS%2B91OcKsvuTJG1zZKLYlsOoT%2BUsqUhm%2BbGGHwsHUuzGc%2BoM6N1jNHFWlBS9qb0pvQFGkrpVehFoX0a3fQxysiO7d0mLVQCoZnz933fnDOD%2FAxSdNgV9z9UcVBgRt2cMBUqC4aD0%2Fxs2BkUhx5zshYz8sZi2BngoU0K9dxGVpcmoQByQ7M4uOc9cdjpDN7rduFx6UAoWOrSgKMXDrrdYWdgEyMKN%2BwAACRaWQd4hULiVNK5TlCShRhGJ6ROQji5LE7GB55y57Bqd%2F1Dqnew8s9tYj0IPGCP5BkqISXC53iFFy2MILwd%2BYZwD4KnubAgLCBYnBeSWgrR3YBWheAugta0laYHwTNBC7hol%2FCRTim45VztVtU%2B%2BWXxn6ya%2Brumvmnqnw%2F4NNevPNl%2FodWsf2vq1039Q1P%2F0tTfNOtfm%2FXvTf2yuX7VXP%2F4%2F%2Fg16z%2Bb%2Bg%2BfZ%2F3a%2F9TfNuvv%2F%2FrpplnfvJNqZ%2FMdnL7ph03PtKpbt%2FR6Y%2Bb1z8kQzLSBlOYaitIU2pINQThvVdqBIkopBXSAUrau7YE7DbNSJU5ote08n3bTeFOdLg84zdFkQvXg7EHxor%2FbnWLyPDO6VGkP7t1%2F4N%2B9MdFSmx4scuFovzvTynVnOBdy2QM0AmUIFpXtWjJi1u%2FsqeNB%2BX%2FmaoXZwN3o0jL6WFgHm4O%2BPUub6aD47iSNPhj3JTnAeCFUqheRwiuRodMmkqiyEjPqb2JdrGgBXz05vyA0Sf4YDc4t20b5sfMyRrY18igjxwKfIeB9d3x8t2wkVCLLlCxz%2FPiYYex4C0PG1H%2B3L3pfGSPfQkriVCflnJSLvi7JLC9IUuK0eSQlC0a7m2gc8FDF25thJMf9JJpp8wkmOWMUD1cb%2FuQxP3LOiGnpiAW78IBHtpDCsSAKeGQoLRNijFGIPB7SQxrhuKdKKXmo%2BE4rjObokpydrlj0%2FkNenWatDm5f2cXD1ZfTS0pcRMoZQZZR5ItacjyaCenIMMZGFMoxj4crMWOT1dGKqmoSx7HjzixXGGNkqJCYEJscrVw1Cf0hfbptajYx5EqjgB2tZMUnnHFeJS0u4m8LlryqOK84DykSSpH57OkX5zFWnPffrjQLcjeXXqFb2rUHH0re30%2Fv32IH%2FmNaBgAA)]
In your HTML elements, use the `data-i18n` attribute to apply a translation key:
```html
<p data-i18n="example"></p>
```
You can also use the `i18n.dist.js` file in production, as it's 36% smaller in file size compared to `i18n.js`.
i18n in Vanilla JavaScript - [Playground]
In your HTML elements, use the data-i18n attribute to apply a translation key:
<p data-i18n="example"></p>
You can also use the i18n.dist.js file in production, as it's 36% smaller in file size compared to i18n.js.
i18n.dist.js
· 631 B · JavaScript
Raw
const e=availableLocales[0];let a=window.navigator.language;const t=new URLSearchParams(window.location.search).get("lang");t&&availableLocales.includes(t)&&(a=t);let l=e;availableLocales.includes(a)&&(l=a);const c=document.querySelectorAll("[data-i18n]"),n=locales[l];c.forEach((e=>{let a=e.getAttribute("data-i18n").split(".").reduce(((e,a)=>e?e[a]:null),n);const t=a.match(/{(.*?)}/g);t&&t.forEach((t=>{Object.entries(e.dataset).filter((([e,l])=>{if(`{${e}}`===t)try{a=a.replace(`${t}`,new Function(`return (${l})`)())}catch(e){a=a.replace(`${t}`,l)}}))})),e.innerHTML=a}));document.querySelector("html").setAttribute("lang",l);
| 1 | const e=availableLocales[0];let a=window.navigator.language;const t=new URLSearchParams(window.location.search).get("lang");t&&availableLocales.includes(t)&&(a=t);let l=e;availableLocales.includes(a)&&(l=a);const c=document.querySelectorAll("[data-i18n]"),n=locales[l];c.forEach((e=>{let a=e.getAttribute("data-i18n").split(".").reduce(((e,a)=>e?e[a]:null),n);const t=a.match(/{(.*?)}/g);t&&t.forEach((t=>{Object.entries(e.dataset).filter((([e,l])=>{if(`{${e}}`===t)try{a=a.replace(`${t}`,new Function(`return (${l})`)())}catch(e){a=a.replace(`${t}`,l)}}))})),e.innerHTML=a}));document.querySelector("html").setAttribute("lang",l); |
i18n.js
· 1.2 KiB · JavaScript
Raw
const defaultLanguage = availableLocales[0]
let language = (window.navigator.language)
const urlParams = new URLSearchParams(window.location.search)
const langFromUrl = urlParams.get('lang')
if (langFromUrl && availableLocales.includes(langFromUrl)) {language = langFromUrl}
let pageLanguage = defaultLanguage
if (availableLocales.includes(language)) {pageLanguage = language}
const elements = document.querySelectorAll('[data-i18n]')
const json = locales[pageLanguage]
elements.forEach((element) => {
const key = element.getAttribute('data-i18n')
let text = key.split('.').reduce((obj, i) => (obj ? obj[i] : null), json)
const variables = text.match(/{(.*?)}/g)
if (variables) {
variables.forEach((variable) => {
Object.entries(element.dataset).filter(([key, value]) => {
if (`{${key}}` === variable) {
try {text = text.replace(`${variable}`, new Function(`return (${value})`)())}
catch (error) {text = text.replace(`${variable}`, value)}
}
})
})
}
element.innerHTML = text
})
const htmlElement = document.querySelector('html')
htmlElement.setAttribute('lang', pageLanguage)
| 1 | const defaultLanguage = availableLocales[0] |
| 2 | let language = (window.navigator.language) |
| 3 | const urlParams = new URLSearchParams(window.location.search) |
| 4 | const langFromUrl = urlParams.get('lang') |
| 5 | if (langFromUrl && availableLocales.includes(langFromUrl)) {language = langFromUrl} |
| 6 | let pageLanguage = defaultLanguage |
| 7 | if (availableLocales.includes(language)) {pageLanguage = language} |
| 8 | const elements = document.querySelectorAll('[data-i18n]') |
| 9 | const json = locales[pageLanguage] |
| 10 | elements.forEach((element) => { |
| 11 | const key = element.getAttribute('data-i18n') |
| 12 | let text = key.split('.').reduce((obj, i) => (obj ? obj[i] : null), json) |
| 13 | const variables = text.match(/{(.*?)}/g) |
| 14 | if (variables) { |
| 15 | variables.forEach((variable) => { |
| 16 | Object.entries(element.dataset).filter(([key, value]) => { |
| 17 | if (`{${key}}` === variable) { |
| 18 | try {text = text.replace(`${variable}`, new Function(`return (${value})`)())} |
| 19 | catch (error) {text = text.replace(`${variable}`, value)} |
| 20 | } |
| 21 | }) |
| 22 | }) |
| 23 | } |
| 24 | element.innerHTML = text |
| 25 | }) |
| 26 | const htmlElement = document.querySelector('html') |
| 27 | htmlElement.setAttribute('lang', pageLanguage) |
index.html
· 957 B · HTML
Raw
<h2 data-i18n="page-heading"></h2>
<p data-i18n="message"></p>
<a data-i18n="links.source" href="#"></a>
<script>
const availableLocales = ['en', 'jp']
const locales = {
en: {
"page-heading": "i18n in Vanilla JavaScript",
"message": "This is a sample text.",
"links": {
"source": "View Source Code"
}
},
jp: {
"page-heading": "バニラ JavaScriptでi18n",
"message": "サンプルテキストです.",
"links": {
"source": "ソースコードを見る"
}
}
}
</script>
<script src="./i18n.js"></script>
<!-- This style tag is here for demo purposes, it is not needed at all for i18n to function -->
<style>
body {
margin: 24px;
background: #141414;
color: white;
font-family: arial, sans-serif;
}
a {
color: white;
}
</style>
| 1 | <h2 data-i18n="page-heading"></h2> |
| 2 | <p data-i18n="message"></p> |
| 3 | <a data-i18n="links.source" href="#"></a> |
| 4 | |
| 5 | <script> |
| 6 | const availableLocales = ['en', 'jp'] |
| 7 | const locales = { |
| 8 | en: { |
| 9 | "page-heading": "i18n in Vanilla JavaScript", |
| 10 | "message": "This is a sample text.", |
| 11 | "links": { |
| 12 | "source": "View Source Code" |
| 13 | } |
| 14 | }, |
| 15 | jp: { |
| 16 | "page-heading": "バニラ JavaScriptでi18n", |
| 17 | "message": "サンプルテキストです.", |
| 18 | "links": { |
| 19 | "source": "ソースコードを見る" |
| 20 | } |
| 21 | } |
| 22 | } |
| 23 | </script> |
| 24 | <script src="./i18n.js"></script> |
| 25 | |
| 26 | |
| 27 | <!-- This style tag is here for demo purposes, it is not needed at all for i18n to function --> |
| 28 | <style> |
| 29 | body { |
| 30 | margin: 24px; |
| 31 | background: #141414; |
| 32 | color: white; |
| 33 | font-family: arial, sans-serif; |
| 34 | } |
| 35 | a { |
| 36 | color: white; |
| 37 | } |
| 38 | </style> |