Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .badges.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"dir": ".github/badges",
"files": [
{
"fileName": "version.svg",
"label": "npm",
"status": "2.1.8",
"icon": "npm"
},
{
"fileName": "coverage.svg",
"label": "coverage",
"status": "95.64",
"icon": "vitest"
},
{
"fileName": "size.svg",
"label": "minzipped size",
"status": "20037",
"icon": "speed",
"color": "43b816"
},
{
"fileName": "maintainer.svg",
"label": "maintainer",
"status": "Localazy"
},
{
"fileName": "license.svg",
"label": "license",
"status": "MIT"
}
]
}
20 changes: 20 additions & 0 deletions .github/badges/coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions .github/badges/license.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions .github/badges/maintainer.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions .github/badges/size.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions .github/badges/version.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ jobs:
node-version-file: .nvmrc
app-id: ${{ secrets.AUTH_APP_ID }}
app-key: ${{ secrets.AUTH_APP_KEY }}
badges: true
badges-size: dist/browser/localazy-api-client.umd.min.js

publish:
name: Publish Release
Expand Down
29 changes: 12 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
<p align="center">
<a href="https://localazy.com">
<img src="https://localazy.com/directus9/assets/9fc36b9c-81b7-4dbf-bd82-b64cd984090f" width="285" height="50" alt="Localazy" >
</a>
</p>
<p align="center">
<a href="https://localazy.com/docs/api">
<img src="https://localazy.com/directus9/assets/20866781-e69b-4e01-9456-05437487b75c" width="50" height="50" alt="localazy-api">
</a>
</p>

<div align="center">
<a href="https://github.com/localazy/api-client"><img src="https://img.shields.io/badge/@localazy-ts--api-066fef?style=for-the-badge" height="22" alt="@localazy/api-client"></a>
<a href="https://npmjs.com/package/@localazy/api-client"><img src="https://img.shields.io/github/package-json/v/localazy/ts-api/main?style=for-the-badge&label=version&color=066fef" height="22" alt="npm"></a>
<a href="https://github.com/localazy/api-client/blob/main/LICENSE"><img src="https://img.shields.io/github/license/localazy/ts-api?style=for-the-badge&color=066fef" height="22" alt="license"></a>
</div>

# 📦 Localazy API Client
[<img src="https://localazy.com/directus9/assets/9fc36b9c-81b7-4dbf-bd82-b64cd984090f" width="285" height="50" alt="Localazy" >](https://localazy.com)

### 📦 `@localazy/api-client`

> Node.js module that allows you to easily interact with the [Localazy API](https://localazy.com/docs/api).
Node.js client for the [Localazy API](https://localazy.com/docs/api), providing a simple and type-safe way to integrate localization features into your JavaScript and TypeScript projects.

[![npm](.github/badges/version.svg)](https://www.npmjs.com/package/@localazy/api-client)
[![maintainer](.github/badges/maintainer.svg)](https://github.com/localazy)
[![license](.github/badges/license.svg)](https://github.com/localazy/api-client/blob/main/LICENSE)<br>
[![coverage](.github/badges/coverage.svg)](https://github.com/localazy/api-client/actions)
[![size](.github/badges/size.svg)](https://bundlephobia.com/package/@localazy/api-client)

</div>

## 🔧 Install

Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@localazy/api-client",
"version": "2.1.8",
"description": "Node.js module that allows you to easily interact with the Localazy API.",
"description": "Official Node.js client for the Localazy API, providing a simple and type-safe way to integrate localization features into your JavaScript and TypeScript projects.",
"keywords": [
"Localazy",
"Localazy API",
Expand Down Expand Up @@ -59,10 +59,11 @@
"prepare": "husky",
"prettier": "prettier --check --cache --cache-location .cache/prettier .",
"prettier:fix": "prettier --write .",
"test": "vitest",
"test": "vitest run",
"test:coverage": "vitest run --coverage",
"test:debug": "vitest --inspect-brk --no-file-parallelism",
"test:ui": "vitest --ui",
"test:watch": "vitest",
"typecheck": "tsc --noEmit"
},
"dependencies": {
Expand Down
35 changes: 23 additions & 12 deletions src/api/methods/api-export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,32 @@ export class ApiExport extends ApiBase {

protected static mapResult(keysList: Key[]): Json {
return keysList.reduce((acc: Json, cur: Key): Json => {
const keys: string[] = [...cur.key];
const parts: string[] = cur.key;

let key: string | undefined = keys.shift();
let path: string = key || '';

while (key) {
if (keys.length === 0) {
acc[path] = cur.value;
} else if (!acc[path]) {
acc[path] = {};
// Flat: single-item array key stays as-is, even if it contains dots
if (parts.length <= 1) {
const only = parts[0];
if (only !== undefined) {
acc[only] = cur.value;
}
return acc;
}

// Nested: array key → build nested objects by segments
let node: any = acc;
for (let i = 0; i < parts.length; i++) {
const seg = parts[i];
const isLast = i === parts.length - 1;

key = keys.shift();
if (key) {
path = `${path}.${key}`;
if (seg !== undefined) {
if (isLast) {
node[seg] = cur.value;
} else {
if (node[seg] === undefined) {
node[seg] = {};
}
node = node[seg];
}
}
}

Expand Down
11 changes: 11 additions & 0 deletions tests/specs/export.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ describe('Export', (): void => {
};
const jsonExport: I18nJson = await api.export.json(request);

// simple keys remain direct properties
expect(jsonExport.en.app_title).toBe('My Application');
expect(jsonExport.en.welcome_message).toBe('Welcome to My Application!');
expect(jsonExport.en.login_button).toBe('Log In');

// nested keys (array of segments) become nested objects
expect(jsonExport.en.headers.role).toBe('Project role');
expect(jsonExport.en.headers.email).toBe('User email');

// single-segment keys that contain dots remain flat (dot-notation key)
expect(jsonExport.en['table.actions.invite']).toBe('Invite user');
expect(jsonExport.en['table.actions.refresh']).toBe('Refresh data');
});
});