{"id":17415532,"url":"https://github.com/kevinresol/turnwing","last_synced_at":"2026-02-06T12:05:12.088Z","repository":{"id":73718826,"uuid":"99823618","full_name":"kevinresol/turnwing","owner":"kevinresol","description":"Type safe \u0026 hackable localization library for Haxe","archived":false,"fork":false,"pushed_at":"2021-08-13T04:30:04.000Z","size":128,"stargazers_count":40,"open_issues_count":1,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-27T23:28:26.442Z","etag":null,"topics":["haxe","localization"],"latest_commit_sha":null,"homepage":"","language":"Haxe","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kevinresol.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2017-08-09T15:27:08.000Z","updated_at":"2023-03-29T16:52:27.000Z","dependencies_parsed_at":"2023-07-09T13:15:32.310Z","dependency_job_id":null,"html_url":"https://github.com/kevinresol/turnwing","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/kevinresol/turnwing","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kevinresol%2Fturnwing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kevinresol%2Fturnwing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kevinresol%2Fturnwing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kevinresol%2Fturnwing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kevinresol","download_url":"https://codeload.github.com/kevinresol/turnwing/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kevinresol%2Fturnwing/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265898334,"owners_count":23845775,"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":["haxe","localization"],"created_at":"2024-10-17T01:43:24.900Z","updated_at":"2026-02-06T12:05:11.420Z","avatar_url":"https://github.com/kevinresol.png","language":"Haxe","funding_links":[],"categories":[],"sub_categories":[],"readme":"# turnwing\n\nHackable localization library for Haxe\n\n## What?\n\n### Type safety\n\nTranslations are done with interfaces. You will never mis-spell the translation key anymore.\n\nIn many existing localization libraries, the translation function looks like this:\n\n```haxe\nloc.translate('hello', {name: 'World'});\nloc.translate('orange', {number: 1});\n```\n\nThere is one and only one translation function and its type is `String-\u003eDynamic-\u003eString`.\nThat means it takes a String key, a Dynamic parameter object and returns a substituted string.\nSeveral things can go wrong here: wrong translation key, wrong param name or wrong param data type.\n\nWith turnwing, we have typed translators.\nEach of them is a user-defined function and typed specifically.\n\n```haxe\nloc.hello('World'); // String-\u003eString\nloc.orange(1); // Int-\u003eString\n```\n\n### Peace of mind\n\nThere is only one place where errors could happen, that is when the localization data is loaded.\n\nThis is because data are validated when they are loaded. The data provider does all the heavy lifting to make sure the loaded data includes all the needed translation keys and values. As a result, there is no chance for actual translation calls to fail.\n\n### Hackable\n\nUsers can plug in different implementations at various part of the library.\n\nFor example, `JsonProvider` uses JSON as the underlying localization format.\nOne can easily write a `XmlProvider` (perhaps with tink_xml).\n\nAlso, an `ErazorTemplate` may replace the default `HaxeTemplate` implementation.\n\n## Usage\n\n```haxe\nimport turnwing.*;\nimport turnwing.provider.*;\nimport turnwing.template.*;\n\ninterface MyLocale {\n\tfunction hello(name:String):String;\n\tfunction orange(number:Int):String;\n\tvar sub(get, never):SubLocale;\n}\n\ninterface SubLocale {\n\tfunction yo():String;\n}\n\nclass Main {\n\tstatic function main() {\n\t\tvar source = new ResourceStringSource(lang -\u003e '$lang.json');\n\t\tvar template = new HaxeTemplate();\n\t\tvar loc = new Manager\u003cMyLocale\u003e(new JsonProvider\u003cMyLocale\u003e(source, template));\n\t\tloc.get('en').handle(function(o) switch o {\n\t\t\tcase Success(localizer):\n\t\t\t\t// data prepared, we can now translate something\n\t\t\t\t$type(localizer); // MyLocale\n\t\t\t\ttrace(localizer.hello('World')); // \"Hello, World!\"\n\t\t\t\ttrace(localizer.orange(4)); // \"There are 4 orange(s)!\"\n\t\t\tcase Failure(e):\n\t\t\t\t// something went wrong when fetching the localization data\n\t\t\t\ttrace(e);\n\t\t});\n\t}\n}\n\n// and your json data looks like this:\n{\n\t\"hello\": \"Hello, ::name::!\",\n\t\"orange\": \"There are ::number:: orange(s)!\",\n\t\"sub\": {\n\t\t\"yo\": \"Yo!\"\n\t}\n}\n```\n\n## Providers\n\n#### JsonProvider\n\n`JsonProvider` is a provider for JSON sources.\nIts data validation is powered by `tink_json`,\nwhich generates the validation code with macro at compile time\naccording to the type information of the user-defined locale interface.\n\nRequires a templating engine to interpolate the parameters.\nThe interface is defined in `Template.hx`.\n`HaxeTemplate` is an implementation based on `haxe.Template` from the Haxe standard library.\n\nUsage:\n\n```haxe\nvar source = new ResourceStringSource(lang -\u003e '$lang.json');\nvar template = new HaxeTemplate();\nvar provider = new JsonProvider\u003cMyLocale\u003e(source, template);\n```\n\nTo use it, install `tink_json` and include it as dependency in your project\n\n#### FluentProvider (JS Only)\n\n`FluentProvider` is a provider for [Fluent](https://projectfluent.org/).\n\nMessages in the FTL file should be named the same as the Locale interface functions.\nNested interfaces should be delimited by a dash (`-`).\nPlease refer to the files in the `tests/data/ftl` folder as an example.\n\nAt the moment, the validation logic is incomplete and only performs a very rough check.\nSo, runtime error _may_ occur in a locale function call. This will be improved in the future.\n\nUsage:\n\n```haxe\nvar source = new ResourceStringSource(lang -\u003e '$lang.ftl');\nvar provider = new FluentProvider\u003cMyLocale\u003e(source);\n```\n\nTo use it, you have to install the npm package `@fluent/bundle`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkevinresol%2Fturnwing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkevinresol%2Fturnwing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkevinresol%2Fturnwing/lists"}