i18nya 0.2.4 → 0.2.5

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.
@@ -1,60 +0,0 @@
1
- {
2
- "name": "astro-i18nya",
3
- "version": "0.2.4",
4
- "description": "Astro integration for i18nya: i18n as small as a cat's paw",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "type": "module",
8
- "scripts": {
9
- "build": "tsc",
10
- "test": "jest"
11
- },
12
- "repository": {
13
- "type": "git",
14
- "url": "git+https://github.com/FyraLabs/i18nya.git"
15
- },
16
- "jest": {
17
- "testPathIgnorePatterns": [
18
- "<rootDir>/dist"
19
- ]
20
- },
21
- "keywords": [
22
- "astro",
23
- "astro-integration",
24
- "internationalization",
25
- "i18n",
26
- "translation",
27
- "localization",
28
- "l10n",
29
- "globalization"
30
- ],
31
- "author": "madonuko <mado@fyralabs.com>",
32
- "license": "MIT",
33
- "bugs": {
34
- "url": "https://github.com/FyraLabs/i18nya/issues"
35
- },
36
- "homepage": "https://github.com/FyraLabs/i18nya#readme",
37
- "devDependencies": {
38
- "@babel/core": "^7.28.5",
39
- "@babel/preset-env": "^7.28.5",
40
- "@babel/preset-react": "^7.28.5",
41
- "@babel/preset-typescript": "^7.28.5",
42
- "@testing-library/jest-dom": "^6.9.1",
43
- "@testing-library/react": "^16.3.0",
44
- "@types/jest": "^30.0.0",
45
- "@types/node": "^24.10.1",
46
- "babel-jest": "^30.2.0",
47
- "jest": "^30.2.0",
48
- "jest-environment-jsdom": "^30.2.0",
49
- "react-test-renderer": "^19.2.0",
50
- "typescript": "^5.9.3"
51
- },
52
- "peerDependencies": {
53
- "typescript": "^5"
54
- },
55
- "dependencies": {
56
- "astro": "^5.16.0",
57
- "i18nya": "^0.2.0",
58
- "react": "^19.2.0"
59
- }
60
- }
@@ -1,20 +0,0 @@
1
- import { render, screen } from "@testing-library/react";
2
- import "@testing-library/jest-dom";
3
- import Trans from "./Trans";
4
-
5
- describe("<Trans />", () => {
6
- it("renders nested elements according to translation string", () => {
7
- const translation = "Hello <1>user</1>, welcome to <2><1>my site</1></2>.";
8
- render(
9
- <Trans t={translation}>
10
- <b />
11
- <a href="https://example.com" />
12
- </Trans>,
13
- );
14
- expect(screen.getByText("my site")).toBeInTheDocument();
15
- const bold = screen.getByText("user");
16
- expect(bold.tagName).toBe("B");
17
- const link = screen.getByText("my site").closest("a");
18
- expect(link).toHaveAttribute("href", "https://example.com");
19
- });
20
- });
@@ -1,89 +0,0 @@
1
- //? https://react.i18next.com/latest/trans-component
2
- // do something similar to ↑
3
-
4
- import { Children, cloneElement, isValidElement } from "react";
5
- import type { FunctionComponent, ReactNode } from "react";
6
-
7
- type Props = {
8
- children: ReactNode;
9
- t: string;
10
- };
11
-
12
- /**
13
- * A fake version of `<Trans>` in `react-i18next` with *very different* behaviour.
14
- *
15
- * You feed in a list of empty elements in `<Trans>`. The structure will follow the translation strings.
16
- *
17
- * IMPORTANT: It is **HIGHLY RECOMMENDED** to use `experimentalReactChildren: true` for `@astrojs/react` in your astro config,
18
- * otherwise this will not work correctly outside of `.tsx` files.
19
- *
20
- * @example ```tsx
21
- * <Trans t={t("test", { user: "John" })}>
22
- * <b />
23
- * <a href="https://example.com" />
24
- * </Trans>
25
- * ```
26
- * With `"test": "Hello <1>{{user}}</1>, welcome to <2><1>my site</1></2>."`, the above element will become:
27
- * ```tsx
28
- * <b>Hello John</b>, welcome to <a href="https://example.com"><b>my site</b></a>.
29
- * ```
30
- *
31
- * @param children the list of tags.
32
- * @param t return value of t()
33
- * @returns ReactNode
34
- */
35
- export default (({ children, t }: Props) => {
36
- // find /<\/(\d+)>/g, where group 1 parse to int is largest
37
- const maxTagId = Math.max(
38
- ...t.match(/<\/(\d+)>/g).map((i) => parseInt(i.slice(2, -1))),
39
- );
40
- const inputs = Children.toArray(children).filter((c) => isValidElement(c));
41
- if ((maxTagId ?? 0) > inputs.length) {
42
- return t; // syntax error
43
- }
44
-
45
- const elms: ReactNode[] = []; // resulting list of elements
46
- const tagStack = [];
47
- for (let ch_idx = 0; ch_idx < t.length; ) {
48
- if (t.substring(ch_idx, ch_idx + 2) == "\\<") {
49
- elms.push("<");
50
- ch_idx += 2;
51
- continue;
52
- }
53
- if (t.substring(ch_idx, ch_idx + 2) == "</") {
54
- let j = 0;
55
- while (t[++j + ch_idx] != ">" && j + ch_idx < t.length);
56
- const tag = Number.parseInt(t.substring(++ch_idx + 1, (ch_idx += j)));
57
- if (Number.isNaN(tag)) {
58
- elms.push(t.substring(ch_idx - j - 1, ch_idx));
59
- continue;
60
- }
61
- let { p, l } = tagStack.pop();
62
- if (tag != p) {
63
- return t; // syntax error
64
- }
65
- elms.push(
66
- cloneElement(inputs[p - 1], {}, ...elms.splice(l, elms.length - l)),
67
- );
68
- continue;
69
- }
70
- if (t[ch_idx] == "<") {
71
- let j = 0;
72
- while (t[++j + ch_idx] != ">" && j + ch_idx < t.length);
73
- const tag = Number.parseInt(t.substring(++ch_idx, (ch_idx += j)));
74
- if (Number.isNaN(tag)) {
75
- elms.push(t.substring(ch_idx - j - 1, ch_idx));
76
- continue;
77
- }
78
- tagStack.push({ p: tag, l: elms.length });
79
- elms.push(""); // in order to splice later, contents inside a new tag element must start fresh
80
- continue;
81
- }
82
- if (typeof elms[elms.length - 1] === "string") {
83
- elms[elms.length - 1] += t[ch_idx++];
84
- } else {
85
- elms.push(t[ch_idx++]);
86
- }
87
- }
88
- return <>{elms}</>;
89
- }) satisfies FunctionComponent<Props>;
@@ -1,30 +0,0 @@
1
- import type { I18Nya } from "i18nya";
2
- import type { AstroIntegration } from "astro";
3
- import Trans from "./Trans.js";
4
- import { listLang, getLangName, makeGetStaticPaths } from "./util.js";
5
- export { Trans, listLang, getLangName, makeGetStaticPaths };
6
-
7
- export default function astroI18nya<T extends string | number | symbol>(
8
- i18nya: I18Nya<T>,
9
- ): AstroIntegration {
10
- return {
11
- name: "astro-i18nya",
12
- hooks: {
13
- "astro:config:setup": ({ updateConfig }) => {
14
- updateConfig({
15
- i18n: {
16
- defaultLocale: i18nya.config.defaultLang,
17
- locales: Object.keys(i18nya.translations),
18
- routing: {
19
- prefixDefaultLocale: false,
20
- redirectToDefaultLocale: true,
21
- fallbackType: "redirect",
22
- },
23
- },
24
- // required for <Trans>
25
- // integrations: [react({ experimentalReactChildren: true })],
26
- });
27
- },
28
- },
29
- };
30
- }
@@ -1,39 +0,0 @@
1
- import type { I18Nya } from "i18nya";
2
-
3
- /**
4
- * Obtain the language name.
5
- * @param lang the language locale
6
- * @param displayLang in what language should the name of the language be shown. By default, use native language names.
7
- * @returns language name
8
- */
9
- export const getLangName = (lang: string, displayLang?: string) =>
10
- new Intl.DisplayNames([displayLang ?? lang], {
11
- type: "language",
12
- style: "narrow",
13
- }).of(lang);
14
-
15
- /**
16
- * List out available languages.
17
- * @param i18nya return value of `init()` from `i18nya`
18
- * @param displayLang in what language should the name of the language be shown. By default, use native language names.
19
- * @returns a map of language locale → language name
20
- */
21
- export const listLang = <T extends string | number | symbol>(
22
- i18nya: I18Nya<T>,
23
- displayLang?: string,
24
- ) =>
25
- new Map(
26
- Object.keys(i18nya.translations).map((l) => [
27
- l,
28
- getLangName(l.replace("_", "-"), displayLang),
29
- ]),
30
- );
31
-
32
- export const makeGetStaticPaths =
33
- <T extends string | number | symbol>(i18nya: I18Nya<T>) =>
34
- async () =>
35
- Object.keys(i18nya.translations).map((lang) =>
36
- lang === i18nya.config.defaultLang
37
- ? { params: { lang: undefined } }
38
- : { params: { lang: lang } },
39
- );
@@ -1,47 +0,0 @@
1
- {
2
- "extends": "astro/tsconfigs/base",
3
- "exclude": ["./dist", "*.config.*", "**/*.test.*"],
4
- "compilerOptions": {
5
- "rootDir": "./src",
6
- "outDir": "./dist",
7
-
8
- // Environment setup & latest features
9
- "lib": ["ESNext", "DOM"],
10
- "target": "ESNext",
11
- "module": "Preserve",
12
- "moduleDetection": "force",
13
- "jsx": "react-jsx",
14
- "types": ["node"],
15
- "allowJs": true,
16
-
17
- // Output settings
18
- "sourceMap": true,
19
- "declaration": true,
20
- "declarationMap": true,
21
-
22
- // Module resolution
23
- // "moduleResolution": "node16",
24
- // "allowImportingTsExtensions": true,
25
- "noEmit": false,
26
- "allowImportingTsExtensions": false,
27
- "verbatimModuleSyntax": false,
28
- "isolatedModules": true,
29
- "resolveJsonModule": true,
30
- "esModuleInterop": true,
31
-
32
- // Best practices
33
- "strict": true,
34
- "skipLibCheck": true,
35
- "noFallthroughCasesInSwitch": true,
36
- "noUncheckedIndexedAccess": true,
37
- "strictNullChecks": false,
38
- // "exactOptionalPropertyTypes": true,
39
- "noImplicitOverride": true,
40
- "noUncheckedSideEffectImports": true,
41
-
42
- // Some stricter flags (disabled by default)
43
- "noUnusedLocals": false,
44
- "noUnusedParameters": false,
45
- "noPropertyAccessFromIndexSignature": false
46
- }
47
- }
package/babel.config.js DELETED
@@ -1,6 +0,0 @@
1
- module.exports = {
2
- presets: [
3
- ['@babel/preset-env', {targets: {node: 'current'}}],
4
- '@babel/preset-typescript',
5
- ],
6
- };
package/bun.lock DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "lockfileVersion": 1,
3
- "configVersion": 0,
4
- "workspaces": {
5
- "": {
6
- "name": "i18nya",
7
- "devDependencies": {
8
- "@types/node": "^24.10.1",
9
- "typescript": "^5.9.3",
10
- },
11
- },
12
- },
13
- "packages": {
14
- "@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="],
15
-
16
- "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
17
-
18
- "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
19
- }
20
- }
@@ -1,26 +0,0 @@
1
- import { init } from "../../../src/index";
2
- import path from "path";
3
- import type defaultTranslations from "../langs/en.json";
4
-
5
- describe("i18nya init and makeT", () => {
6
- it('should return correct value for "hello"', async () => {
7
- const langDir = path.resolve(__dirname, "../langs");
8
- const { makeT } = await init<keyof typeof defaultTranslations>({ defaultLang: "en", langDir });
9
-
10
- expect(makeT("en")("hello")).toBe("Hello, World!");
11
- });
12
-
13
- it("should return the key if translation is missing", async () => {
14
- const langDir = path.resolve(__dirname, "../langs");
15
- const { makeT } = await init({ defaultLang: "en", langDir });
16
-
17
- expect(makeT("en")("missing_key")).toBe("missing_key");
18
- });
19
-
20
- it("should interpolate variables in translation", async () => {
21
- const langDir = path.resolve(__dirname, "../langs");
22
- const { makeT } = await init({ defaultLang: "en", langDir });
23
-
24
- expect(makeT("en")("greet", { name: "Alice" })).toBe("Hello, Alice!");
25
- });
26
- });
@@ -1,4 +0,0 @@
1
- import { init } from '../../src/index';
2
- init({ defaultLang: 'en', langDir: './langs' }).then(({ makeT }) => {
3
- console.log(makeT("en")("hello"));
4
- });
@@ -1,4 +0,0 @@
1
- {
2
- "hello": "Hello, World!",
3
- "greet": "Hello, {{name}}!"
4
- }