@yiiamee/multilinguist 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # Nuxt MultiLinguist module
2
+
3
+ [![npm version][npm-version-src]][npm-version-href]
4
+ [![npm downloads][npm-downloads-src]][npm-downloads-href]
5
+ [![License][license-src]][license-href]
6
+ [![Nuxt][nuxt-src]][nuxt-href]
7
+
8
+ This module is a simple, but smoothly working module for easy and seamless localization implementation in Nuxt 3.
9
+
10
+ ## Features
11
+
12
+ ## Quick Setup
13
+
14
+ Install the module to your Nuxt application with one command:
15
+
16
+ ```bash
17
+ npx nuxi module add @nuxtjs/multilinguist
18
+ ```
@@ -0,0 +1,5 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+
3
+ declare const _default: _nuxt_schema.NuxtModule<_nuxt_schema.ModuleOptions, _nuxt_schema.ModuleOptions, false>;
4
+
5
+ export { _default as default };
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "multilinguist",
3
+ "configKey": "multilinguist",
4
+ "version": "0.0.1",
5
+ "builder": {
6
+ "@nuxt/module-builder": "1.0.1",
7
+ "unbuild": "3.5.0"
8
+ }
9
+ }
@@ -0,0 +1,86 @@
1
+ import { defineNuxtModule, createResolver, addPlugin, addImportsDir, addTypeTemplate } from '@nuxt/kit';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+
5
+ function GenerateLocaleKeysPlugin(defaultLocaleFromConfig, localesPath, outPath) {
6
+ async function generateTypes() {
7
+ const defaultLocalePath = path.join(localesPath, `${defaultLocaleFromConfig}.json`);
8
+ if (!fs.existsSync(defaultLocalePath)) {
9
+ console?.error(`Default locale file not found: ${defaultLocalePath}`);
10
+ return;
11
+ }
12
+ const json = JSON.parse(fs.readFileSync(defaultLocalePath, "utf-8"));
13
+ const keys = Object.keys(json);
14
+ const output = [
15
+ `// AUTO-GENERATED FILE \u2014 DO NOT EDIT MANUALLY`,
16
+ `export interface TranslationMessages {`,
17
+ ...keys.map((key) => ` ${JSON.stringify(key)}: string;`),
18
+ `}`,
19
+ ``,
20
+ `export type LocaleKey = keyof TranslationMessages;`
21
+ ].join("\n");
22
+ fs.mkdirSync(path.dirname(outPath), { recursive: true });
23
+ fs.writeFileSync(outPath, output, "utf-8");
24
+ console?.warn(`Generated types/generated-locales.d.ts from ${defaultLocalePath}`);
25
+ }
26
+ return {
27
+ name: "vite-plugin-generate-locales-types",
28
+ async buildStart() {
29
+ await generateTypes();
30
+ },
31
+ async handleHotUpdate(ctx) {
32
+ if (ctx.file.endsWith(".json") && ctx.file.includes(localesPath)) {
33
+ await generateTypes();
34
+ }
35
+ }
36
+ };
37
+ }
38
+
39
+ const module = defineNuxtModule({
40
+ meta: {
41
+ name: "multilinguist",
42
+ configKey: "multilinguist",
43
+ version: "0.0.1"
44
+ },
45
+ setup(moduleOptions, nuxtApp) {
46
+ const resolver = createResolver(import.meta.url);
47
+ addPlugin(resolver.resolve("./runtime/plugin"));
48
+ addImportsDir(resolver.resolve("runtime/composables"));
49
+ addTypeTemplate({
50
+ filename: "types/multilinguist.d.ts",
51
+ getContents: () => `
52
+ import type { TranslationMessages } from './generated-locales'
53
+
54
+ declare module '#app' {
55
+ interface NuxtApp {
56
+ $t: (key: keyof TranslationMessages) => string
57
+ }
58
+ }
59
+
60
+ declare module 'vue' {
61
+ interface ComponentCustomProperties {
62
+ $t: (key: keyof TranslationMessages) => string
63
+ }
64
+ }
65
+ `
66
+ });
67
+ nuxtApp.hook("vite:extendConfig", (viteConfig) => {
68
+ viteConfig.plugins = viteConfig.plugins || [];
69
+ viteConfig.plugins.push(GenerateLocaleKeysPlugin(moduleOptions.defaultLocale, `${nuxtApp.options.rootDir}/public/locales`, resolver.resolve("./runtime/types/generated-locales.d.ts")));
70
+ });
71
+ nuxtApp.hook("prepare:types", ({ references }) => {
72
+ references.push({
73
+ path: resolver.resolve("./runtime/types/generated-locales.d.ts")
74
+ });
75
+ references.push({
76
+ path: resolver.resolve("./runtime/types/multilinguist.d.ts")
77
+ });
78
+ });
79
+ nuxtApp.options.runtimeConfig.public.multilinguist = {
80
+ defaultLocale: moduleOptions.defaultLocale,
81
+ supportedLanguages: moduleOptions.supportedLanguages
82
+ };
83
+ }
84
+ });
85
+
86
+ export { module as default };
@@ -0,0 +1,4 @@
1
+ import type { Locale, TranslationMap } from "./useLocalization.js";
2
+ export default function useLocale<const T extends TranslationMap>(supportedLanguages: T, defaultLocale: Locale<T>): {
3
+ locale: any;
4
+ };
@@ -0,0 +1,16 @@
1
+ export default function useLocale(supportedLanguages, defaultLocale) {
2
+ const locale = computed(() => {
3
+ if (import.meta.server) {
4
+ const headers = useRequestHeaders(["accept-language"]);
5
+ const locale2 = headers["accept-language"]?.split(",")[0]?.split("-")[0] || defaultLocale;
6
+ return supportedLanguages.includes(locale2) ? locale2 : defaultLocale;
7
+ } else if (import.meta.client) {
8
+ const locale2 = navigator.language || defaultLocale;
9
+ return supportedLanguages.includes(locale2) ? locale2 : defaultLocale;
10
+ }
11
+ return defaultLocale;
12
+ });
13
+ return {
14
+ locale
15
+ };
16
+ }
@@ -0,0 +1,11 @@
1
+ import type { LocaleKey } from "../types/generated-locales.js";
2
+ export type TranslationMap = readonly string[];
3
+ export type Locale<T extends TranslationMap> = T[number];
4
+ export type LocaleKeys<T extends TranslationMap> = T[keyof T];
5
+ export type TMultilinguistResponse<T extends TranslationMap> = {
6
+ t: (key: LocaleKey) => string;
7
+ setLocale: (locale: Locale<T>) => void;
8
+ initLocalization: () => Promise<void>;
9
+ locale: Ref<Locale<T>>;
10
+ };
11
+ export default function useLocalization<const T extends TranslationMap>(supportedLanguages: T, defaultLocale: Locale<T>): TMultilinguistResponse<T>;
@@ -0,0 +1,50 @@
1
+ import useLocale from "../composables/useLocale.js";
2
+ export default function useLocalization(supportedLanguages, defaultLocale) {
3
+ const userSelectedLocale = useCookie("multilinguist-locale", { default: () => defaultLocale });
4
+ const { locale: userBrowserLocale } = useLocale(supportedLanguages, defaultLocale);
5
+ const loadedLanguages = useState("loaded-languages", () => ({}));
6
+ const loadDefaultLocale = async () => {
7
+ if (!loadedLanguages.value[defaultLocale]) {
8
+ const messages = await import(`@/public/locales/${defaultLocale}.json`);
9
+ loadedLanguages.value[defaultLocale] = messages.default;
10
+ }
11
+ };
12
+ const userPrefferableLocale = computed(() => {
13
+ return userSelectedLocale.value ? userSelectedLocale.value : userBrowserLocale.value;
14
+ });
15
+ const locale = useState(() => {
16
+ return userPrefferableLocale.value || defaultLocale;
17
+ });
18
+ const t = (key) => {
19
+ const localeKeys = loadedLanguages.value[locale.value];
20
+ return String(localeKeys?.[key] || key);
21
+ };
22
+ const setLocale = async (newLocale) => {
23
+ if (!loadedLanguages.value[newLocale] && supportedLanguages.includes(newLocale)) {
24
+ const loadedLocale = await import(`@/public/locales/${newLocale}.json`).then(
25
+ (module) => module.default || module
26
+ );
27
+ loadedLanguages.value[newLocale] = loadedLocale;
28
+ }
29
+ userSelectedLocale.value = newLocale;
30
+ locale.value = newLocale;
31
+ };
32
+ const initLocalization = async () => {
33
+ await loadDefaultLocale();
34
+ await setLocale(userPrefferableLocale.value);
35
+ };
36
+ watch(
37
+ () => locale.value,
38
+ async (val) => {
39
+ if (val !== userSelectedLocale.value) {
40
+ userSelectedLocale.value = val;
41
+ }
42
+ }
43
+ );
44
+ return {
45
+ t,
46
+ setLocale,
47
+ initLocalization,
48
+ locale
49
+ };
50
+ }
@@ -0,0 +1,6 @@
1
+ export default function useMultilinguist(): {
2
+ t: (key: import("../types/generated-locales.js").LocaleKey) => string;
3
+ setLocale: (locale: string) => void;
4
+ initLocalization: () => Promise<void>;
5
+ locale: Ref<import("./useLocalization.js").Locale<T>>;
6
+ };
@@ -0,0 +1,8 @@
1
+ export default function useMultilinguist() {
2
+ const nuxtApp = useNuxtApp();
3
+ const localization = nuxtApp.$localization || nuxtApp._localization;
4
+ if (!localization) {
5
+ throw new Error("Localization plugin not initialized");
6
+ }
7
+ return { ...localization };
8
+ }
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,15 @@
1
+ import useLocalization from "../runtime/composables/useLocalization";
2
+ export default defineNuxtPlugin(async (nuxtApp) => {
3
+ const config = useRuntimeConfig().public.multilinguist || {
4
+ defaultLocale: "en",
5
+ supportedLanguages: ["en"]
6
+ };
7
+ const supportedLanguages = config.supportedLanguages;
8
+ const defaultLocale = config.defaultLocale;
9
+ const localization = useLocalization(supportedLanguages, defaultLocale);
10
+ await localization.initLocalization();
11
+ console.log("[multilinguist] is initialised", config.supportedLanguages, config.defaultLocale);
12
+ nuxtApp.provide("localization", localization);
13
+ nuxtApp.provide("t", localization.t);
14
+ nuxtApp._localization = localization;
15
+ });
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../../../.nuxt/tsconfig.server.json",
3
+ }
@@ -0,0 +1,7 @@
1
+ // AUTO-GENERATED FILE — DO NOT EDIT MANUALLY
2
+ export interface TranslationMessages {
3
+ "Hello, World": string;
4
+ "Switch Locale": string;
5
+ }
6
+
7
+ export type LocaleKey = keyof TranslationMessages;
@@ -0,0 +1,7 @@
1
+ import type { NuxtModule } from '@nuxt/schema'
2
+
3
+ import type { default as Module } from './module.mjs'
4
+
5
+ export type ModuleOptions = typeof Module extends NuxtModule<infer O> ? Partial<O> : Record<string, any>
6
+
7
+ export { default } from './module.mjs'
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@yiiamee/multilinguist",
3
+ "version": "1.0.0",
4
+ "description": "Nuxt 3 Multilinguist Localization module",
5
+ "repository": "yiiameeMich/multilinguist",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/types.d.mts",
11
+ "import": "./dist/module.mjs"
12
+ }
13
+ },
14
+ "main": "./dist/module.mjs",
15
+ "typesVersions": {
16
+ "*": {
17
+ ".": [
18
+ "./dist/types.d.mts"
19
+ ]
20
+ }
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "scripts": {
26
+ "prepack": "nuxt-module-build build",
27
+ "dev": "nuxi dev playground",
28
+ "dev:build": "nuxi build playground",
29
+ "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
30
+ "release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags",
31
+ "lint": "eslint .",
32
+ "test": "vitest run",
33
+ "test:watch": "vitest watch",
34
+ "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"
35
+ },
36
+ "dependencies": {
37
+ "@nuxt/kit": "^3.17.4"
38
+ },
39
+ "devDependencies": {
40
+ "@nuxt/devtools": "^2.4.1",
41
+ "@nuxt/eslint-config": "^1.4.1",
42
+ "@nuxt/module-builder": "^1.0.1",
43
+ "@nuxt/schema": "^3.17.4",
44
+ "@nuxt/test-utils": "^3.19.1",
45
+ "@types/node": "latest",
46
+ "changelogen": "^0.6.1",
47
+ "eslint": "^9.27.0",
48
+ "nuxt": "^3.17.4",
49
+ "typescript": "~5.8.3",
50
+ "vitest": "^3.1.4",
51
+ "vue-tsc": "^2.2.10"
52
+ }
53
+ }