{"id":15413371,"url":"https://github.com/simonwep/li18nt","last_synced_at":"2025-04-18T21:51:14.517Z","repository":{"id":66334242,"uuid":"310067046","full_name":"simonwep/li18nt","owner":"simonwep","description":"🌎 Lint your i18n translation files. Detect conflicting properties, duplicates and make it more readable and easier to maintain by formatting it!","archived":false,"fork":false,"pushed_at":"2022-09-03T14:21:15.000Z","size":276,"stargazers_count":40,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-05T08:35:16.418Z","etag":null,"topics":["cli","cli-app","formatter","i18n","lint","linter","linting","prettify","prettify-library"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simonwep.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-04T17:08:10.000Z","updated_at":"2024-11-28T10:17:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"f506c9e8-d283-4a6b-a08d-2e878ad989d2","html_url":"https://github.com/simonwep/li18nt","commit_stats":{"total_commits":75,"total_committers":1,"mean_commits":75.0,"dds":0.0,"last_synced_commit":"ec40bc16c164fc0cfad5a8b679cda0488316f8a4"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonwep%2Fli18nt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonwep%2Fli18nt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonwep%2Fli18nt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonwep%2Fli18nt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simonwep","download_url":"https://codeload.github.com/simonwep/li18nt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249191203,"owners_count":21227518,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","cli-app","formatter","i18n","lint","linter","linting","prettify","prettify-library"],"created_at":"2024-10-01T16:56:47.821Z","updated_at":"2025-04-16T03:32:05.194Z","avatar_url":"https://github.com/simonwep.png","language":"TypeScript","funding_links":["https://github.com/sponsors/Simonwep"],"categories":[],"sub_categories":[],"readme":"\u003ch3 align=\"center\"\u003e\n    \u003cimg src=\"https://user-images.githubusercontent.com/30767528/98481604-b27d5c00-21fb-11eb-916a-d991207ae616.png\" alt=\"Logo\" height=\"250\"\u003e\n\u003c/h3\u003e\n\n\u003ch3 align=\"center\"\u003e\n    i18n translation files linter.\n\u003c/h3\u003e\n\n\n\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"gzip size\" src=\"https://img.badgesize.io/https://cdn.jsdelivr.net/npm/li18nt/lib/li18nt.min.mjs?compression=gzip\"\u003e\n  \u003cimg alt=\"brotli size\" src=\"https://img.badgesize.io/https://cdn.jsdelivr.net/npm/li18nt/lib/li18nt.min.mjs?compression=brotli\"\u003e\n  \u003ca href=\"https://github.com/Simonwep/li18nt/actions\"\u003e\u003cimg\n     alt=\"Build Status\"\n     src=\"https://github.com/Simonwep/li18nt/workflows/CI/badge.svg\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/li18nt\"\u003e\u003cimg\n     alt=\"Install count\"\n     src=\"https://img.shields.io/npm/dm/li18nt.svg\"\u003e\u003c/a\u003e\n  \u003cimg alt=\"No dependencies\" src=\"https://img.shields.io/badge/dependencies-none-27ae60.svg\"\u003e\n  \u003ca href=\"https://www.jsdelivr.com/package/npm/li18nt\"\u003e\u003cimg\n     alt=\"JSDelivr download count\"\n     src=\"https://img.shields.io/jsdelivr/npm/hm/li18nt\"\u003e\u003c/a\u003e\n  \u003cimg alt=\"Current version\"\n       src=\"https://img.shields.io/github/tag/Simonwep/li18nt.svg?color=3498DB\u0026label=version\"\u003e\n  \u003ca href=\"https://github.com/sponsors/Simonwep\"\u003e\u003cimg\n     alt=\"Support me\"\n     src=\"https://img.shields.io/badge/github-support-3498DB.svg\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003e Info: The README is always up-to-date with the latest commit, check out [releases](https://github.com/Simonwep/li18nt/releases) to see the docs for your version!\n\n\u003e Attention: As of v5 this package is ESM-Only!\n\nThis linter will do three major things:\n1. Finding conflicts: Comparing your files against each other to see if there are any properties with types not matching up.\n2. Finding duplicates: Finding duplicates to reduce redundancy and elimitate duplicate translations.\n3. Cleanup: Sorting all properties alphabetically which will make working with your file easier and maintain consistency across all your files.\n\nIt comes with a CLI and an API.\n\n\n### Gettings started\nInstall via npm:\n\n```sh\n$ npm install li18nt\n```\n\n... or using yarn:\n\n```sh\n$ yarn add li18nt\n```\n\n\n### CLI Usage\n\nInstalling it will add `li18nt` (and the alias `lint-i18n`) to your command line.\n\nExamples:\n```sh\n# Lint all json files in /locales\n$ li18nt locales/*.json\n\n# Lint all valid json files in /locales, print out only warnings and errors\n$ li18nt locales/*.json --skip-invalid --quiet\n\n# List all commands\n$ li18nt --help\nUsage: li18nt [files...] [options]\n\nLints your locales files, lint-i18n is an alias.\n\nOptions:\n  -v, --version    Output the current version\n  -q, --quiet      Print only errors and warnings\n  -d, --debug      Debug information\n  -f, --fix        Tries to fix existing errors\n  --config [path]  Configuration file path (it'll try to resolve one in the current directory)\n  --skip-invalid   Skip invalid files without exiting\n  --report         Print system information\n  -h, --help       Show this help text\n```\n\nLi18nt is configuration drive, you'll need to add a configuration. It'll try to resolve a  `.li18ntrc`, `.li18nt.json`,`.li18ntrc.json` or `li18nt.config.js`\nin the current directory. Use the `--config [path]` option to specify a different path.\n\n\u003e The Li18nt config file is usually located in locales/.li18nt or in your root folder.\n\n```json5\n{\n    // Override the --quiet cli option\n    \"quiet\": false,\n\n    // Override the --skip-invalid cli option\n    // If this is set to false it'll exit immediately after a file couldn't be parsed or read\n    \"skipInvalid\": false,\n\n    // List of rules\n    \"rules\": {\n\n        // Checks if your files are properly formatted,\n        // you can also just pass \"warn\" as value - 4 spaces are default\n        \"prettified\": [\"warn\", {\"indent\": \"tab\"}],\n\n        // Checks for conflicts\n        \"conflicts\": \"warn\",\n\n        // Validate property names\n        \"naming\": [\"warn\", {\n\n            // Specify a list of regular expressions to match keys against\n            \"patterns\": [\n                \"^[a-z]*$\",\n                \"[^r]$\"\n            ]\n        }],\n\n        // Check for duplicates\n        \"duplicates\": [\"warn\", {\n            \"ignore\": [\n                // You can also use the array-sytax e.g. [\"pages\", \"dashboard\", \"dashboard\"]\n                // If the specified target is an object it'll be skipped, e.g. you can ignore entire sub-trees\n                \"pages.dashboard.dashboard\",\n\n                // Use the * to match all properties in a tree\n                \"pages.*\"\n            ]\n        }]\n    }\n}\n```\n\nThe syntax for each option is:\n```ts\ntype Rule = Mode | [Mode, Options | undefined];\n```\n\nwhere `Mode` can be `off`, `warn` or `error`. `off` won't do anything, `error` will exit with a non-zero code in case of errors.\n\n### API Usage\nThis library comes in commonjs and ES6 format, you can include it directly:\n```html\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/li18nt/lib/li18nt.min.js\"\u003e\u003c/script\u003e\n```\n... or using es6 modules:\n\n```ts\nimport {...} from 'https://cdn.jsdelivr.net/npm/li18nt/lib/li18nt.min.mjs'\n```\n\nYou can use the exported `lint` function to lint a set of objects.\nOption- and result-types can be found [here](src/types.ts):\n\n```ts\nimport {lint} from 'li18nt';\n\nconst options = {\n    prettified: 4, // 4 spaces, use 'tab' for tabs\n    duplicates: true, // We want to analyze our translations for duplicates\n    conflicts: true // Find differences\n};\n\nconst objects = [\n    {a: 20, b: null, c: {x: 20}},\n    {a: 50, b: 'Hello', c: {x: 100, y: 20}},\n    {a: 'Five', b: 'Super', c: null}\n];\n\nconst result = lint(options, objects);\nconsole.log(result);\n```\n\n\n#### Utilities\n\nSometimes you may want to exclude certain properties from being linted, for that you can either specify a\nproperty path as array (e.g. `['foo', 'bar', 4]`), as a string (`foo.bar[4]`), or you can use the `propertyPath` utility function to convert a string to an array:\n\n```ts\nimport {lint, propertyPath} from 'li18nt';\n\nconst options = {\n    duplicates: {\n        ignore: [\n            // Info: This is normally not requried as strings in ignore will automatically be converted to an array!\n\n            /**\n             * Returns ['b', 'a'], but you can use any valid js-property-path e.g.\n             * foo[3].bar.baz['Hello \"world\"'].xy\n             * would give us ['foo', 3, 'bar', 'baz', 'Hello \"world\"'].xy\n             */\n            propertyPath('b.a')\n        ]\n    }\n};\n\nconst objects = [\n    {a: 20, b: {a: 20}, c: {a: 20}}\n];\n\nconst result = lint(options, objects);\n\n// Will log Map {'a' =\u003e [['a'], [ 'c', 'a']]}\n// The first element in the array will always be the first appereance of that property\nconsole.log(result.duplicates[0]);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonwep%2Fli18nt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimonwep%2Fli18nt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonwep%2Fli18nt/lists"}