{"id":34659994,"url":"https://github.com/liblxn/lxn","last_synced_at":"2026-05-29T14:31:15.690Z","repository":{"id":57502111,"uuid":"120356347","full_name":"liblxn/lxn","owner":"liblxn","description":"A localization toolkit with a simple translation format.","archived":false,"fork":false,"pushed_at":"2024-02-01T14:51:56.000Z","size":29,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-18T10:09:02.087Z","etag":null,"topics":["l10n","localization","lxn"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/liblxn.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}},"created_at":"2018-02-05T20:15:53.000Z","updated_at":"2024-04-09T14:10:07.000Z","dependencies_parsed_at":"2024-01-26T18:49:22.988Z","dependency_job_id":null,"html_url":"https://github.com/liblxn/lxn","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/liblxn/lxn","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liblxn%2Flxn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liblxn%2Flxn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liblxn%2Flxn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liblxn%2Flxn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/liblxn","download_url":"https://codeload.github.com/liblxn/lxn/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liblxn%2Flxn/sbom","scorecard":{"id":588008,"data":{"date":"2025-08-11","repo":{"name":"github.com/liblxn/lxn","commit":"287f9454d43cb8cb00d60cbd0ff025035e001a34"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":0,"reason":"Found 0/11 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-20T21:05:44.669Z","repository_id":57502111,"created_at":"2025-08-20T21:05:44.670Z","updated_at":"2025-08-20T21:05:44.670Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33657690,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["l10n","localization","lxn"],"created_at":"2025-12-24T18:51:52.573Z","updated_at":"2026-05-29T14:31:15.686Z","avatar_url":"https://github.com/liblxn.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# lxn\n`lxn` is a localization toolkit with its own simple translation format. The format itself represents a human-readable schema and is meant to be used by translators. This schema can then be converted into a binary catalog, which uses a compact representation of the schema and is ready to be used by the client libaries. To compile schemas into a binary catalogs, [`lxnc`](https://github.com/liblxn/lxnc) can be used.\n\n## Schema Definition\nThe human-readable schema consists of a dictionary, which contains all the translated messages for a specific language. It can be subdivided into sections in order to be able to cluster messages. To uniquely identify messages, each message has a key assigned to it. A message itself commonly contains static and variable parts. The static parts are just text in the specified language, whereas the variable parts will be replaced by a specific value during runtime.\n\n### Messages\n```\nmessage-key:\n    This is a text which can be translated\n    into the desired language.\n```\nA message has to be preceded by its key. A key always starts at the very beginning of the line (followed by a colon) and has to be unique within the current section. Afterwards the message text can be defined, which has to be indented. It is also possible for the text to span multiple lines, as long as the indentation is kept up. Furthermore, a message text can contain blank lines, too.\n\nWhen the text is rendered in the application, line breaks will be replaced by single spaces.\n\n### Variables\n```\n${name}\n${name.type}\n${name:type.option{option-params}}\n```\nVariables can be placed within a message and represent variable parts, that will be replaced during runtime. A variable consists of a name, a type, and options. The name is used to identify the variable during the runtime replacement. The type is used to let the client libraries know how to render the variable's value and is specified in a case-insensitive manner. The following types are currently supported:\n* [`string`](#string-variables)\n* [`number`](#numeric-variables)\n* [`percent`](#percentage-variables)\n* [`money`](#money-variables)\n* [`plural`](#plural-variables)\n* [`select`](#select-variables)\n\n#### String Variables\n```\n${name}\n${name:string}\n```\nA string variable is a simple replacement without any magic. The given value will not be modified or transformed when rendered to the final message. This type is the default, when no type is declared. String variables do not have any options, which can be applied.\n\n#### Numeric Variables\n```\n${name:number}\n```\nA number variable takes a numeric value and transforms it into a locale-dependent string representation. Here, things like the decimal separator, the digits, and grouping play a role. Numeric variables do not have any options, which can be applied.\n\n#### Percentage Variables\n```\n${name:percent}\n```\nA percentage variable takes a numeric value and transforms it into a locale-dependent string representation. Here things like the percentage sign, the digits, and the decimal separator play a role. Percentage variables do not have any options, which can be applied.\n\n#### Money Variables\n```\n${name:money\n    .currency{curr}\n}\n```\nA money variable takes a numeric value and a currency and transforms it into a locale-dependent string representation. Here things like the position of the currency sign, the digits, and the grouping play a role. Money variables take the required `.currency` option, which specifies the variable name of the currency symbol.\n\n#### Plural Variables\n```\n${name:plural\n    .ordinal\n    .zero{zero-message}\n    .one{one-message}\n    .two{two-message}\n    .few{few-message}\n    .many{many-message}\n    .other{other-message}\n    .[7]{seven-message}\n}\n```\nA plural variable takes a numeric value and conditionally transforms it into the corresponding sub-message. The nested sub-message can contain a whole message with all its static and dynamic parts (there is no difference from a top-level message). There are six standard plural categories: `.zero`, `.one`, `.two`, `.few`, `.many`, and `.other`. Each language has a predefined set of those plural categories, which the language is able to resolve and which should all be provided. To ensure there will always be a message to be resolved, the `.other` option is required.  With the Unicode's [Language Plural Rules](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html) a numeric value can then be mapped to its corresponding plural category.\n\nIf a certain numeric value shall be overriden, a fixed number can be provided with the `.[\u003cnumber\u003e]` option. In the resolving process, this number will always precede the Unicode's plural rules.\n\nA plural form can come in two flavors: cardinal and ordinal. This can be specified by the `.cardinal` and `.ordinal` option respectively, where cardinal is the default. Cardinal and ordinal plurals have a different set of rules assigned and can make a difference in the resolving step.\n\n#### Select Variables\n```\n${name:select\n    .default{case one}\n    .[case one]{case-one-message}\n    .[case two]{case-two-message}\n}\n```\nA select variable takes a string value and transforms it into a specific sub-message, depending on the value. It can be seen as a dictionary with string keys and message values. All sub-messages can contain a whole message with all its static and dynamic parts. If the string value does not match any given key, a default key can be specified using the `.default` option.\n\n\n### Sections\n```\n[[ section.name ]]\n```\nMessages can be subdivided into sections, which act as a kind of namespace. Sections are open, that means a section is extendible and different parts of a schema can define the whole section.\n\n## Example\n```\nwelcome-back:\n    Welcome back, ${username}. Your last visit was ${days-gone:plural\n        .zero{today}\n        .one{yesterday}\n        .other{${days-gone:number} days ago}\n        .[7]{a week ago}\n    }.\n\n[[ donation ]]\nmoney-sent:\n    You just sent ${amount:money.currency{curr}} to ${username}.\n    ${gender:select\n        .default{other}\n        .[female]{She}\n        .[male]{He}\n        .[other]{The other person}\n    } will receive the money within the next days.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliblxn%2Flxn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fliblxn%2Flxn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliblxn%2Flxn/lists"}