npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@cepharum/vue3-i18n

v0.5.1

Published

a simple i18n library for Vue3 applications

Downloads

90

Readme

@cepharum/vue3-i18n

a simple i18n library for Vue3 applications

License

MIT

About

This library implements a component and helper functions for reactively mapping internationalized keys into localized strings based on hierarchical trees of translations per locale, each implemented as regular Javascript objects e.g. read from JSON files.

It supports data interpolation and some limited Markdown syntax for styling translations.

Due to its reactive approach, all translations get updated automatically e.g. on switching the locale and fetching its set of translations. The locale to use is read from current document or browser automatically. A custom locale can be selected explicitly to override locale read from document or browser.

Install

In a consuming Vue3 project, this library is installed using npm like this:

npm install @cepharum/vue3-i18n

Usage

A loader for your translations must be provided. It should be set up as early as possible, e.g. on mounting your project's root view in src/App.vue component.

<script setup>
import { useL10n } from "@cepharum/vue3-i18n";

useL10n().setLoader( locale => import(`./l10n/${locale}.json`) );
</script>

Create a folder src/l10n in your project and put a file name en.json there. It is going to provide all the translations like this:

{
  "COMMON": {
    "confirm": "Okay",
    "cancel": "Cancel"
  },
  "FEATURE": {
    "title": "Info",
    "text": "This is the feature!"
  }
}

Use this library's component <L10n> to render text:

<script setup>
import { L10n } from "@cepharum/vue3-i18n";
</script>

<template>
  <h1><L10n i18n="FEATURE.title" /></h1>
  <p><L10n i18n="FEATURE.text" /></p>
  <button><L10n i18n="COMMON.confirm" /></button>
</template>

VitePress

In VitePress, the default theme must be extended or a custom theme must be set up for registering vue3-i18n. In file .vitepress/theme/index.js, the method enhanceApp must be extended:

import { L10n, useL10n } from "@cepharum/vue3-i18n";

enhanceApp( ctx ) {
    const l10n = useL10n();

    // set up loader for fetching translations per locale
    l10n.setLoader( locale => import( ( `./l10n/${locale}.json` ) ) );
    
    // globally register L10n component for use in content pages
    ctx.app.component( "L10n", L10n );
}

Translation files per locale are expected to reside in folder .vitepress/theme/l10n here.

In versions prior to v0.5.0, an observer for the document's locale had to be set up explicitly. Starting with v0.5.0, the observer is set up automatically.

Plugins

Starting with v0.4.1, separate loaders can be registered to provide translations for dedicated namespaces. This enables internationalized plugins for a Vue3-based application providing their own subset of translations.

// in a plugin's setup code:
import { L10n, useL10n } from "@cepharum/vue3-i18n";

const l10n = useL10n();

// set up loader for fetching plugin's translations per locale
l10n.setNamespaceLoader( "@my-plugin", locale => import( ( `./l10n/${locale}.json` ) ) );

In this, a namespace is a non-empty string of non-whitespace characters prefixed with @. Keys of all translations fetched by a namespace's loader are automatically prefixed with that namespace. For the example given above, a translation file could look like this:

{
  "FOO": {
    "bar": "translated"
  }
}

For looking it up, the namespace must be prepended in plugin's code:

const translation = useL10n().lookup( "@my-plugin.FOO.bar" );

The regular loader selected via setLoader() isn't affected by this automatic prefixing. Thus, it is capable of providing custom translations for either namespace, too. For that, the regular loader is always processed last on compiling a locale's set of translations.

Interpolation

You can use additional markup in your translations to be replaced with values extracted from an additionally provided data object. Translations can look like this:

{
  "COMMON": {
    "confirm": "Okay",
    "cancel": "Cancel"
  },
  "FEATURE": {
    "title": "About {mode.label}",
    "text": "This is the feature!"
  }
}

<L10n> component supports another property data accepting some object with properties matching names wrapped in curly braces above:

<script setup>
import { ref } from "vue";
import { L10n } from "@cepharum/vue3-i18n";

const data = ref({
	mode: {
		label: "Interpolation",
	},
});
</script>

<template>
  <h1><L10n i18n="FEATURE.title" :data="data" /></h1>
  <p><L10n i18n="FEATURE.text" /></p>
  <button><L10n i18n="COMMON.confirm" /></button>
</template>

data of <L10n> accepts a function, too, which gets invoked on every update to fetch actual data:

<script setup>
import { L10n } from "@cepharum/vue3-i18n";

const data = () => ({
  mode: {
    label: "Interpolation",
  },
});
</script>

<template>
  <h1><L10n i18n="FEATURE.title" :data="data" /></h1>
  <p><L10n i18n="FEATURE.text" /></p>
  <button><L10n i18n="COMMON.confirm" /></button>
</template>

The component renders the resulting translation without any HTML element unless markdown support has been enabled. By setting optional property tag to the name of an HTML element, the translation is always wrapped in an element with that name. The following example results in same output as the previous one:

<script setup>
import { L10n } from "@cepharum/vue3-i18n";

const data = () => ({
  mode: {
    label: "Interpolation",
  },
});
</script>

<template>
  <L10n i18n="FEATURE.title" :data="data" tag="h1" />
  <L10n i18n="FEATURE.text" tag="p"/>
  <L10n i18n="COMMON.confirm" tag="button" />
</template>

Markdown

There is support for some basic Markdown in translations.

{
  "COMMON": {
    "confirm": "Okay",
    "cancel": "Cancel"
  },
  "FEATURE": {
    "title": "About",
    "text": "This is **the** feature!"
  }
}

<L10n> ignores any Markdown by default. By setting markdown property, supported Markdown is converted to HTML, though. But any HTML additionally found in translations is escaped.

<script setup>
import { L10n } from "@cepharum/vue3-i18n";
</script>

<template>
  <h1><L10n i18n="FEATURE.title" markdown /></h1>
  <p><L10n i18n="FEATURE.text" /></p>
  <button><L10n i18n="COMMON.confirm" /></button>
</template>

Additional API features

The context fetched with useL10n() exposes additional properties and actions:

  • locale reactively provides current locale as string, e.g. en or de. It is derived from browser's locale by default.

    • The locale of current document is preferred.
    • If locale of document is missing or if there is no document, the locale of current browser as exposed in navigator.language is used.
    • If locale of browser is missing or there is no browser, a default locale is used as fallback which is en initially.
  • Method setLocale( locale ) selects a custom locale to prefer as current locale over any locale read from other sources as described above. It causes that locale's translations to be fetched and all currently used <L10n> components to be updated.

    <script setup>
    import { useL10n } from "@cepharum/vue3-i18n";
        
    useL10n().setLocale( "fr" );
    </script>

    The method setLocale() can be used to drop any previously selected custom locale and to reinstate the discovery of current locale as described above.

    <script setup>
    import { useL10n } from "@cepharum/vue3-i18n";
        
    useL10n().setLocale();
    </script>
  • defaultLocale reactively exposes the fallback locale used in last step described above. The method setDefaultLocale() can be used to adjust it.

    <script setup>
    import { useL10n } from "@cepharum/vue3-i18n";
      
    useL10n().setDefaultLocale( "de" );
    </script>
  • In addition to serving as a fallback on discovering a current locale, this default locale is considered on looking up a translation for an i18n key when there is no translation provided for the current locale.

  • You can fetch reactive translations using method lookup().

    <script setup>
    import { useL10n } from "@cepharum/vue3-i18n";
      
    const translation = useL10n().lookup( "SOME.KEY.FOR.firstField" );
    </script>

    The resulting translation isn't interpolated, but extracted from fetched translations as-is. Provided key may address a whole thread of translations, too.

  • Moreover, you can fetch multiple reactive translations using method translate() with optional interpolation and Markdown support.

    <script setup>
    import { ref } from "@vue/reactivity";
    import { useL10n } from "@cepharum/vue3-i18n";
      
    const { translate } = useL10n();
      
    const data = ref( { count: 23, foo: "test" } );
      
    // translates and interpolates single string supporting Markdown, too
    const single = translate( "SOME.KEY.FOR.firstField", data, true );
      
    // translates multiple strings at once and returns object with
    // same properties each providing related key's translation
    const multi = translate( {
      first: "SOME.KEY.FOR.firstField",
      second: "SOME.KEY.FOR.secondField",
    }, data );
    </script>
  • By default, translations are looked up for current locale selected as described above. However, a custom locale can be chosen explicitly to look up translations for that particular locale with lookup() and translate().

    <script setup>
    import { ref } from "@vue/reactivity";
    import { useL10n } from "@cepharum/vue3-i18n";
      
    const { translate, lookup } = useL10n();
      
    const data = ref( { count: 23, foo: "test" } );
      
    // translates single string to French explicitly
    const translation = lookup( "SOME.KEY.FOR.firstField", null, "fr" );
      
    // translates multiple strings at once to French
    const multi = translate( {
      first: "SOME.KEY.FOR.firstField",
      second: "SOME.KEY.FOR.secondField",
    }, data, false, "fr" );
    </script>

    Same works with locale property of L10n component.

  • Considering a document's language can be disabled. (Prior to v0.5.0, this has been the default and discovery of current local has been working in a simpler way.)

    import { useL10n } from "@cepharum/vue3-i18n";
      
    useL10n().unobserveDocument();
    </script>

    Considering document's language can be re-enabled later:

    import { useL10n } from "@cepharum/vue3-i18n";
      
    useL10n().observeDocument();
    </script>

    Additional documents can be observed, too. However, it is controlling custom locale usually selected with

    import { useL10n } from "@cepharum/vue3-i18n";
      
    useL10n().observeDocument( customDocument );
    </script>

    However, this isn't replacing the monitoring of current document's locale, but selects given document's locale as custom locale just like invoking setLocale( locale ) method every time that given document's locale is changing. Thus, observing multiple additional documents is possible, but does not make much sense.

    Stopping observation of an additional document works accordingly:

    import { useL10n } from "@cepharum/vue3-i18n";
      
    useL10n().unobserveDocument( customDocument );
    </script>

    This will reinstate the process of discovering current locale as described in first item above. Any selected custom locale gets dropped.