• Stars
    star
    258
  • Rank 158,189 (Top 4 %)
  • Language
    JavaScript
  • License
    ISC License
  • Created over 3 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

I18n library for Svelte.js that analyzes your keys at build time for max performance and minimal footprint

Svelte Intl Precompile

Svelte-intl-precompile

This i18n library for Svelte.js has an API identical (or at least very similar) to https://github.com/kaisermann/svelte-i18n but has a different approach to processing translations.

Instead of doing all the work in the client, much like Svelte.js acts as a compiler for your app, this library acts as a compiler for your translations.

Check the documentation page, it's better than this Readme

Go to https://svelte-intl-precompile.com

Still, there you have the rest of the Readme.

Why would I want to use it? How does it work?

This approach is different than the taken by libraries like intl-messageformat or format-message, which do all the work in the browser. The approach taken by those libraries is more flexible as you can just load json files with translations in plain text and that's it, but it also means the library needs to ship a parser for the ICU message syntax, and it always has to have ship code for all the features that the ICU syntax supports, even features you might not use, making those libraries several times bigger.

This process spares the browser of the burden of doing the same process in the user's devices, resulting in smaller and faster apps.

For instance if an app has the following set of translations:

{
  "plain": "Some text without interpolations",
  "interpolated": "A text where I interpolate {count} times",
  "time": "Now is {now, time}",
  "number": "My favorite number is {n, number}",
  "pluralized": "I have {count, plural,=0 {no cats} =1 {one cat} other {{count} cats}}",
  "pluralized-with-hash": "I have {count, plural, zero {no cats} one {just # cat} other {# cats}}",
  "selected": "{gender, select, male {He is a good boy} female {She is a good girl} other {They are good fellas}}",
  "numberSkeleton": "Your account balance is {n, number, ::currency/CAD sign-always}",
  "installProgress": "{progress, number, ::percent scale/100 .##} completed"
}

The babel plugin will analyze and understand the strings in the ICU message syntax and transform them into something like:

import { __interpolate, __number, __plural, __select, __time } from "precompile-intl-runtime";
export default {
  plain: "Some text without interpolations",
  interpolated: count => `A text where I interpolate ${__interpolate(count)} times`,
  time: now => `Now is ${__time(now)}`,
  number: n => `My favorite number is ${__number(n)}`,
  pluralized: count => `I have ${__plural(count, { 0: "no cats", 1: "one cat", h: `${__interpolate(count)} cats`})}`,
  "pluralized-with-hash": count => `I have ${__plural(count, { z: "no cats", o: `just ${count} cat`, h: `${count} cats`})}`,
  selected: gender => __select(gender, { male: "He is a good boy", female: "She is a good girl", other: "They are good fellas"}),
  numberSkeleton: n => `Your account balance is ${__number(n, { style: 'currency', currency: 'CAD', signDisplay: 'always' })}`,
  installProgress: progress => `${__number(progress / 100, { style: 'percent', maximumFractionDigits: 2 })} completed`
}

Now the translations are either strings or functions that take some arguments and generate strings using some utility helpers. Those utility helpers are very small and use the native Intl API available in all modern browsers and in node. Also, unused helpers are tree-shaken by rollup.

When the above code is minified it will results in an output that compact that often is shorter than the original ICU string:

"pluralized-with-hash": "I have {count, plural, zero {no cats} one {just # cat} other {# cats}}",
--------------------------------------------------------------------------------------------------
"pluralized-with-hash":t=>`I have ${jt(t,{z:"no cats",o:`just ${t} cat`,h:`${t} cats`})}`

The combination of a very small and treeshakeable runtime with moving the parsing into the build step results in an extremely small footprint and extremely fast performance.

How small, you may ask? Usually adds less than 2kb to your final build size after compression and minification, when compared with nearly 15kb that alternatives with a runtime ICU-message parser like svelte-i18n add.

How fast, you may also ask? When rendering a key that has also been rendered before around 25% faster. For initial rendering or rendering a keys that haven't been rendered before, around 400% faster.

Setup

First of all, you can find a working sveltekit app configured to use svelte-intl-precompile in https://github.com/cibernox/sample-app-svelte-intl-precompile. If you struggle with any of the following steps you can always use that app to compare it with yours:

  1. Install svelte-intl-precompile as a runtime dependency.

  2. Create a folder to put your translations. I like to use a /messages or /locales folder on the root. On that folder, create en.json, es.json (you can also create JS files exporting objects with the translations) and as many files as languages you want. On each file, export an object with your translations:

{
  "recent.aria": "Find recently viewed tides",
  "menu": "Menu",
  "foot": "{count} {count, plural, =1 {foot} other {feet}}",
}
  1. In your svelte.config.js import the function exported by svelte-intl-precompile/sveltekit-plugin and invoke with the folder where you've placed your translation files it to your list of Vite plugins:
import precompileIntl from "svelte-intl-precompile/sveltekit-plugin";

/** @type {import('@sveltejs/kit').Config} */
module.exports = {
  kit: {
    target: '#svelte',
    vite: {
      plugins: [
        // if your translations are defined in /locales/[lang].js
        precompileIntl('locales')
        // precompileIntl('locales', '$myprefix') // also you can change import path prefix for json files ($locales by default)
      ]
    }
  }
};

If you are using CommonJS, you can instead use const precompileIntl = require("svelte-intl-precompile/sveltekit-plugin");.

From this step onward the library almost identical to use and configure to the popular svelte-i18n. It has the same features and only the import path is different. You can check the docs of svelte-i18n for examples and details in the configuration options.

  1. Now you need some initialization code to register your locales and configure your preferences. You can import your languages statically (which will add them to your bundle) or register loaders that will load the translations lazily. The best place to put this configuration is inside a <script context="module"> on your src/$layout.svelte
<script>
  import { addMessages, init, getLocaleFromNavigator /*, register */ } from 'svelte-intl-precompile';
  import en from '$locales/en.js';  // If using typescript you can also use the .ts extension.
  import es from '$locales/es.js'   // load from $myprefix/es.js you configured a custom import path.
  // if you put your translations in js files, import then usin the relative path. E.g. `import en from '../../locales/en.js'`
  // @ts-ignore
  addMessages('en', en);
  addMessages('es', es);
  // register('es', () => import('$locales/es.js')); <-- use this approach if you want locales to be load lazily

  init({
    fallbackLocale: 'en',
    initialLocale: getLocaleFromNavigator()
  });
</script>

<script>
  import '../app.css';
</script>

<slot />
  1. Now on your .svelte files you start translating using the t store exported from svelte-intl-precompile:
<script>
	import { t } from 'svelte-intl-precompile'
</script>
<footer class="l-footer">
	<p class="t-footer">{$t("hightide")} {$t("footer.cta")}</p>
</footer>

Note for automatic browser locale detection when server side rendering

If you want to automatically detect your user's locale from the browser using getLocaleFromNavigator() but you are server side rendering your app (which sveltekit does by default), you need to take some extra steps for the locale used when SSR matches the locale when hydrating the app which would cause texts to change.

You can pass to getLocaleFromNavigator an optional argument which is the locale to use when SSR'ing your app. How you get that value depends on how you run your app, but for instance using sveltekit you can extract it from the accept-language HTTP header of the request, using Hooks

You can use getSession to extract the preferred locale from the request headers and store it in the session object, which is made available to the client:

// src/hooks.js
export function getSession(request) {
  let acceptedLanguage = request.headers["accept-language"] && request.headers["accept-language"].split(',')[0];`
  return { acceptedLanguage };
}

Then you can use the session store to pass it to the init function:

<!-- __layout.svelte -->
<script context="module">
  import { register, init, waitLocale, getLocaleFromNavigator } from 'svelte-intl-precompile';
  register('en', () => import('$locales/en-us'));
  register('en-US', () => import('$locales/en-US'));
  register('es-GB', () => import('$locales/es-GB'));	
	
  export async function load({session}) {
    init({
      fallbackLocale: 'en',
      initialLocale: session.acceptedLanguage || getLocaleFromNavigator(),
    });
    await waitLocale(); // awaits for initialLocale language pack to finish loading;
    return {};
  }
</script>

If you have a lot of languages or want to register all available languages, you can use the registerAll function:

<!-- __layout.svelte -->
<script context="module">
  import { register, init, waitLocale, getLocaleFromNavigator } from 'svelte-intl-precompile';
  import { registerAll } from '$locales';

  // Equivalent to a `register("lang", () => import('$locales/lang'))` fro each lang file in localesRoot.
  registerAll();

  export async function load({session}) {
    init({
      fallbackLocale: 'en',
      initialLocale: session.acceptedLanguage || getLocaleFromNavigator(),
    });
    await waitLocale(); // awaits for initialLocale language pack to finish loading;
    return {};
  }
</script>

More Repositories

1

ember-power-select

The extensible select component built for ember.
JavaScript
540
star
2

ember-cpm

ComputedProperty Macros for Ember
JavaScript
275
star
3

ember-power-calendar

Powerful and customizable calendar component for Ember
JavaScript
207
star
4

ember-native-dom-helpers

Test helpers for your integration tests that fire native events
JavaScript
186
star
5

ember-basic-dropdown

The basic dropdown you ember app needs
JavaScript
148
star
6

svelte-media

Svelte.js util to easily observe media queries as a reactive store
TypeScript
58
star
7

ember-cli-yuidoc

EmberCLI addon for generate documentation from YUIDoc coments
JavaScript
55
star
8

ember-power-datepicker

An extensible datepicker for Ember
JavaScript
50
star
9

ember-power-select-with-create

Ember-power-select addon with an `Add ${term}` option in the first position
JavaScript
50
star
10

ember-ast-helpers

Utility belt to level-up your Ember AST transforms
TypeScript
40
star
11

ember-text-measurer

Simple Ember Service to measure the width of a string in a performant way
JavaScript
38
star
12

ember-power-select-typeahead

Typeahead component built on top of ember-power-select
JavaScript
36
star
13

storyteller

Storyteller application built with Exilir and Dynamo. Is a concurrent storyteller.
Elixir
34
star
14

rubytapas_downloader

Simple ruby script that downloads the latest rubytapas episodes.
Ruby
26
star
15

mobile-patterns

Showcase of mobile UI patterns implemented in Ember.js
JavaScript
21
star
16

ember-hash-helper-polyfill

Polyfill for the new Ember hash helper
JavaScript
15
star
17

precompile-intl-runtime

Runtime helpers to be used in translations precompiled by babel-plugin-precompile-intl
TypeScript
10
star
18

ember-power-select-with-fallback

Ember Power Select that fallbacks to a native select when certain criteria are met
JavaScript
10
star
19

rollup-plugin-precompile-intl

Rollup plugin to precompile translations in the ICU message syntax
JavaScript
9
star
20

ember-power-calendar-moment

Internal utils of Ember Power Calendar built on top of Moment.js
JavaScript
9
star
21

ember-power-select-blockless

Blockless version of ember-power-select
JavaScript
8
star
22

git-repo-version

Calculates the version of a repo based on the package.json and the current SHA
JavaScript
8
star
23

ember-disable-proxy-controllers

Disables ObjectController/ArrayController for autogenerated controllers
JavaScript
7
star
24

babel-plugin-precompile-intl

Compile translations in ICU message format to invocable functions at build time
TypeScript
7
star
25

ember-power-select-places

Ember Power Select โค๏ธGoogle Places
JavaScript
6
star
26

ember-power-select-sortable

Ember-power-select <3 Ember-sortable
JavaScript
6
star
27

DahuaDoorbell2MQTT

Node.js script that connects to a Dahua Video Doorbell and broadcasts to MQTT events fired by it.
JavaScript
6
star
28

ember-power-select-collection

Ember-power-select component that {{vertical-collection}} for performance
JavaScript
5
star
29

ember-basic-dropdown-hover

Variation of ember-basic-dropdown that opens on hover
JavaScript
5
star
30

ember-k-codemod

Removes all usages of Ember.K
JavaScript
5
star
31

ember-assign-helper

Simple {{assign}} helper for Ember
JavaScript
5
star
32

ember-code-example-component

Small component to show code snippets (hbs + js + css + evaluated-result)
JavaScript
5
star
33

homeassistant-poolstation

HomeAssistant custom component for integrating the Poolstation platform.
Python
4
star
34

ember-power-calendar-luxon

Internal utils of Ember Power Calendar built on top of Luxon
JavaScript
3
star
35

marvel-api-ember-sample-app

Sample Ember.js app using marvel API
JavaScript
3
star
36

vite-plugin-svelte-inline-components

Allows you to define your components inline in tests using tagged templates
JavaScript
3
star
37

ember-simple-i18n

Simple i18n library for ember.js apps
JavaScript
3
star
38

cibernox.github.io

JavaScript
3
star
39

space-crops

JavaScript
2
star
40

home-assistant-addons

Repository with unofficial addons for home assistant
Shell
2
star
41

spanish_ccc_validator

Simple validator for spanish bank account numbers
Ruby
2
star
42

sample-app-svelte-intl-precompile

Sample app that uses svelte-intl-precompile, to use as a doc
Svelte
2
star
43

web_experiments

Web experiments using pure HTML5 and CSS3 and Javascript
JavaScript
2
star
44

sparkles-ember-basic-dropdown

Just testing sparkles-component
JavaScript
2
star
45

svelte-intl-precompile-docs

Documentation page for Svelte-intl-precompile
JavaScript
2
star
46

ember-proxy-controllers

Ember.ObjectController and Ember.ArrayController extracted as an standalone addon
JavaScript
2
star
47

ember-cli-google-libphonenumber-shim

Ember-cli addon that imports google-libphonenumber and provides shims for it
JavaScript
2
star
48

ember-i18n-errors

Extension to ember-i18n for translating error messages within the route hierarchy
JavaScript
2
star
49

sveltekit-bug-with-plugin

Repro
Svelte
1
star
50

PyPoolstation

Python library to interact the the Poolstation platform
Python
1
star
51

pinkmine

A redmine-inspired project management web app
Ruby
1
star
52

angular-football-experiment

Sample app for learn angular.
CoffeeScript
1
star
53

bencher

Simplest benchmarking library for ruby
Ruby
1
star
54

my-mu-app

Sample ember app with module unification layour
JavaScript
1
star
55

my-mu-addon

First addon ever created with the addon MU blueprint
JavaScript
1
star