{"id":20367887,"url":"https://github.com/ksoichiro/i18n-patch","last_synced_at":"2025-04-12T05:36:44.923Z","repository":{"id":57270388,"uuid":"55848942","full_name":"ksoichiro/i18n-patch","owner":"ksoichiro","description":"Replacing codes for i18n with patterns.","archived":false,"fork":false,"pushed_at":"2017-04-09T04:47:11.000Z","size":154,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-19T04:35:57.097Z","etag":null,"topics":["cli","i18n","node","translation","yaml"],"latest_commit_sha":null,"homepage":null,"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/ksoichiro.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}},"created_at":"2016-04-09T14:32:55.000Z","updated_at":"2018-10-16T07:53:35.000Z","dependencies_parsed_at":"2022-09-04T19:23:09.513Z","dependency_job_id":null,"html_url":"https://github.com/ksoichiro/i18n-patch","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ksoichiro%2Fi18n-patch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ksoichiro%2Fi18n-patch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ksoichiro%2Fi18n-patch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ksoichiro%2Fi18n-patch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ksoichiro","download_url":"https://codeload.github.com/ksoichiro/i18n-patch/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248524853,"owners_count":21118615,"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","i18n","node","translation","yaml"],"created_at":"2024-11-15T00:35:19.401Z","updated_at":"2025-04-12T05:36:44.877Z","avatar_url":"https://github.com/ksoichiro.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# i18n-patch\n\n\u003e Replacing codes for i18n with patterns.\n\n[![Travis master](https://img.shields.io/travis/ksoichiro/i18n-patch/master.svg?style=flat-square)](https://travis-ci.org/ksoichiro/i18n-patch)\n[![Coveralls master](https://img.shields.io/coveralls/ksoichiro/i18n-patch/master.svg?style=flat-square\u0026maxAge=2592000)](https://coveralls.io/github/ksoichiro/i18n-patch)\n[![npm](https://img.shields.io/npm/v/i18n-patch.svg?style=flat-square)](https://www.npmjs.com/package/i18n-patch)\n![npm](https://img.shields.io/npm/l/i18n-patch.svg?style=flat-square)\n\ni18n-patch is a tool to translate source code into your language(locale) for any software that does not provide i18n mechanisms.\n\nThis tool enables you to follow the upgrades of the target software:\nyou write translation points using regular expressions, write translations for each points,\nand execute this tool.\nThis method is better than modifying target source code directly.\n\n## Install\n\n```console\n$ npm install -g i18n-patch\n```\n\n## Usage\n\n```\n  Usage\n    $ i18n-patch \u003clocale\u003e \u003csrc\u003e [\u003cdest\u003e]\n\n  Options\n    --config      Base path for config files.\n                  i18n.yml and \u003clocale\u003e.yml is required.\n                  json is also available instead of yaml.\n                  'config' by default.\n    --statistics  Show statistics.\n    --condition   Condition value to limit patterns for specific versions.\n    --unmatched   Show unmatched lines to stderr.\n                  They are scanned and tried to be translated but\n                  no suitable translation is found in the config files.\n                  These lines indicates that they might\n                  have to be translated or they should be skipped.\n                  false by default.\n\n  Examples\n    $ i18n-patch --config example/config --statistics --condition \"version=1.1.0\" --unmatched -- ja example/src example/out 2\u003e unmatched.log\n```\n\n## Example\n\nYou need 2 configuration files: `i18n.yml` and `\u003clocale\u003e.yml` like `ja.yml` for Japanese.\n\n`i18n.yml` contains translation points that defines \"what should be translated\".\n\nThe tool reads the target source code and when the patterns in `i18n.yml` are found,\nit will convert \"keys\" in translation points and replace them to translations that are provied by `\u003clocale\u003e.yml`.\n\nLet's see a simple example below.\n\nThe following `example/i18n.yml` defines target source files and patterns to be translated.\n\n```yaml\ntranslations:\n- src: '**/*.js'\n  patterns:\n  - pattern: preview.text(\"Nothing to preview.\");\n    replace: preview.text(\"${nothingToPreview}\");\n  - pattern: preview.text(\"Loading...\");\n    replace: preview.text(\"${loading}\");\n```\n\n`example/ja.yml` provides translations for Japanese.  \nYou can see the keys (nothingToPreview, loading) in this file\nare used in `i18n.yml`.\n\n```yaml\nnothingToPreview: プレビューする内容がありません\nloading: 読み込み中...\n```\n\nAnd the target file `example/src/js/sample.js` is like this:\n\n```javascript\npreview.text(\"Nothing to preview.\");\npreview.text(\"Loading...\");\nconsole.log('other codes should be untouched.');\n```\n\nThen, by executing `i18n-patch ja src out` in `example` directory,  \n`example/out/js/sample.js` will be generated:\n\n```javascript\npreview.text(\"プレビューする内容がありません\");\npreview.text(\"読み込み中...\");\nconsole.log('other codes should be untouched.');\n```\n\nThis is a very simple example, but this tool can handle more complex expressions.  \n\nPlease check the [Configuration details](#configuration-details) section for further details.\n\nIf you want to try it by yourself, clone this repository and execute:\n\n```console\n$ npm run build\n$ npm start\n```\n\nThen you can confirm the result in `example/out` directory.\n\n## Why?\n\nThe main purpose of this project is to provide an external i18n system for any existent source code.\n\nI'm maintaining [gitlab-i18n-patch](https://github.com/ksoichiro/gitlab-i18n-patch) project\nto provide unofficial Japanese translation patch to GitLab.\n\nIn that project, when a new version of GitLab is released,\nI'm trying to merge big branch(tag) to translated branch.\n\nThis method has many problems:\n\n- Merge operation causes many many conflict files, which are hard to resolve.\n- When merging, some translations are lost\n  because some part of codes are moved into other files.\n  It's so hard to keep tracing these design changes.\n- It's very difficult to provide patches for other languages.\n- It's very difficult to get someone's contribution.\n- This method depends on `patch`, so one patch cannot be applied to any other versions.\n\nTherefore, I thought it's better to create a new external translation system\nfor providing i18n patch GitLab project without Git branch management.\n\n## Configuration details\n\n* [Basic](#basic)\n* [Arguments](#arguments)\n* [Sequence](#sequence)\n* [Code insertion](#code-insertion)\n* [Conditional insertion for all matching files](#conditional-insertion-for-all-matching-files)\n* [Named patterns](#named-patterns)\n* [Multiline](#multiline)\n* [Include/exclude locales](#includeexclude-locales)\n* [Add new files](#add-new-files)\n* [Skip patterns](#skip-patterns)\n* [Match once](#match-once)\n* [Complete pattern](#complete-pattern)\n* [Parallel groups](#parallel-groups)\n* [Split files with suffix](#split-files-with-suffix)\n* [Evaluate only when conditions are satisfied](#evaluate-only-when-conditions-are-satisfied)\n\n### Basic\n\nThe main configuration file is `i18n.yml` and looks like this:\n\n```yaml\ntranslations:\n- src: '**/*.coffee'\n  patterns:\n  - pattern: preview.text \"Nothing to preview.\"\n    replace: preview.text \"${nothingToPreview}\"\n```\n\n`translations.src` will be expanded using node-glob.  \nFor example, `src/a.coffee` and `src/b/c.coffee` will match this pattern,\nbut `src/d.js` will not match.\n\n`translations.patterns` is an array that includes elements which define target pattern and replacement for it.\nEach element of `patterns` that have `pattern` and `replace` will be used to replace source code.\n\n`pattern` is usually just a string value, but you can use regular expressions by js-yaml feature: `!!js/regexp /foo/`.\n\n`replace` defines the replacement for the `pattern`, and this can contain variable expression like `${nothingToPreview}`.\n\nYour locale file (like `ja.yml`) should map this key to a translation.\n\n```yaml\nnothingToPreview: プレビューする内容がありません\n```\n\nWith these configurations, the following code named `test.coffee`\n\n```coffee\npreview.text \"Nothing to preview.\"\n```\n\nwill be converted to this:\n\n```coffee\npreview.text \"プレビューする内容がありません\"\n```\n\nThe following `test.js` will not be changed because it does not match to `translation.src`.\n\n```javascript\n// preview.text \"Nothing to preview.\"\n```\n\n### Arguments\n\n`replace` elements can have arguments.\nIf you want to aggregate similar patterns, consider using arguments.\n\nFor example, you can configure translations for `Edit issue` and `Edit project` like this:\n\n```yaml\n# i18n.yml\ntranslations:\n- src: '**/*'\n  patterns:\n  - pattern: 'Edit issue'\n    replace: '${editIssue}'\n  - pattern: 'Edit project'\n    replace: '${editProject}'\n\n# ja.yml\neditIssue: 課題を編集\neditProject: プロジェクトを編集\n```\n\nBut you can also write them using arguments:\n\n```yaml\n# i18n.yml\ntranslations:\n- src: '**/*'\n  patterns:\n  - pattern: 'Edit issue'\n    replace: '${editSomething}'\n    args:\n    - 'issue'\n  - pattern: 'Edit project'\n    replace: '${editSomething}'\n    args:\n    - 'project'\n  - pattern: 'issue'\n    replace: '${issue}'\n  - pattern: 'project'\n    replace: '${project}'\n\n# en.yml\neditSomething: {0}を編集\nissue: 課題\nproject: プロジェクト\n```\n\nThis will be processed like this:\n\n1. When the expression `Edit issue` is found,\n   it's replaced into `${editSomething}`.\n1. `${NAME}` in the `replace` value is treated as a variable,\n   and in this case, `editSomething` is resolved to\n   `{0}を編集` using `ja.yml`.\n1. `{N}` in the translation key is an argument\n   and the values of `args` are passed to it.\n1. As a result, `{0}を編集` will be converted to `issueを編集`.\n1. Then the third pattern is applied; `issue` is translated to `課題` and the result will be `課題を編集`.\n\nThis is useful to write less translations and standardize the expressions.\n\n### Exclusion\n\nIf you want to exclude some patterns, even when the line matches to a pattern, you can use `exclude` to skip it.\n\n```yaml\n# i18n.yml\ntranslations:\n- src: '**/*'\n  patterns:\n  - pattern: ' user$'\n    replace: ' ${user}'\n    exclude: '- if'\n  - pattern: !!js/regexp /Edit (.*)/\n    replace: '${editSomething}'\n    args:\n    - '$1'\n\n# ja.yml\nuser: ユーザ\neditSomething: '{0}を編集'\n```\n\nIf the above configuration is given, then\n\n```haml\n- if user\n    Edit user\n```\n\nwill be translated into:\n\n```haml\n- if user\n    ユーザを編集\n```\n\n### Sequence\n\nPatterns are processed sequentially, so if you want to apply multiple translations to one line, please check the orders of the patterns are correct.\n\nFor example, if you want to translate `Edit issue` into `課題を編集` (Japanese), the following configurations won't work as expected.\n\n```yaml\n# i18n.yml\ntranslations:\n- src: '**/*'\n  patterns:\n  - pattern: 'issue'\n    replace: '${issue}'\n  - pattern: 'Edit issue'\n    replace: '${editSomething}'\n    args:\n    - 'issue'\n\n# ja.yml\neditSomething: '{0}を編集'\nissue: 課題\n```\n\nBecause `Edit issue` is translated to `Edit 課題` by the first pattern, it won't match to the second expression.\n\nTo fix this problem, you could write like this:\n\n```yaml\n# i18n.yml\ntranslations:\n- src: '**/*'\n  patterns:\n  - pattern: 'Edit issue'\n    replace: '${editSomething}'\n    args:\n    - 'issue'\n  - pattern: 'issue'\n    replace: '${issue}'\n\n# ja.yml\neditSomething: '{0}を編集'\nissue: 課題\n```\n\n\u003e Note: to tell you the truth, you can also solve this problem by using regular expressions (`!!js/regexp`):\n\u003e \n\u003e ```yaml\n\u003e # i18n.yml\n\u003e translations:\n\u003e - src: '**/*'\n\u003e   patterns:\n\u003e   - pattern: 'issue'\n\u003e     replace: '${issue}'\n\u003e   - pattern: !!js/regexp /Edit (.*)/\n\u003e     replace: '${editSomething}'\n\u003e     args:\n\u003e     - '$1'\n\u003e\n\u003e # ja.yml\n\u003e editSomething: '{0}を編集'\n\u003e issue: 課題\n\u003e ```\n\n### Code insertion\n\nIf you want to insert some code snippet into some files,\nyou can use `insert`.\n\nFor example, with the following config files\n\n```yaml\n# i18n.yml\n- src: 'foo.js'\n  patterns:\n  - insert:\n      at: end\n      value: bar\n\n# ja.yml\nbar: |\n     // baz\n     // qux\n```\n\nthe next source file will be like this:\n\n```javascript\nconsole.log('Hello, world');\n```\n\n```javascript\nconsole.log('Hello, world');\n// baz\n// qux\n```\n\nIf you want to insert code at the beginning of the file,\nyou should change the value of `insert.at` from `end` to `begin`.\n\nAs you can see, `insert.value` is treated as a translation key,\nso you must define the value of `insert.value`\nto your `\u003clocale\u003e.yml`.\n\n### Conditional insertion for all matching files\n\nIf you want to insert some code snippet into some files\n**only when they match some of the patterns**,\nthen you can use `conditionals` and `insert`.\n\n```yaml\n# i18n.yml\n- src: '**/*.rb'\n  conditionals:\n  - insert:\n      at: begin\n      value: foo\n  patterns:\n  - pattern: bar\n    replace: baz\n\n# ja.yml\nfoo: '// This file is edited by i18n-patch'\nbaz: qux\n```\n\nIn `i18n.yml`, you define what you want to insert when the files match some of the patterns.\n\n`conditionals` is an array, and can have children that have `insert` element.\n\n`insert` should have `at` and `value` children.\nIf you'd like to insert codes at the beginning of the file, set `begin` to `insert.at`, and set `end` if you want to insert them at the end of the file.\n\nSuppose you have files like below,\n\na.js:\n\n```javascript\nconsole.log('bar');\n```\n\nb.js:\n\n```javascript\nconsole.log('hello');\n```\n\nthen `a.js` matches `bar`, and `foo` will be inserted at the beginning of the file, and won't be inserted to `b.js`.\n\n```javascript\n// This file is edited by i18n-patch\nconsole.log('qux');\n```\n\n### Named patterns\n\nEven if you use arguments and regular expressions,  \nthere would be still many duplicate configurations.  \nWith named patterns, you can aggregate these configurations.\n\nLet's see a more complex example.\n\n```yaml\n# i18n.yml\ntranslations:\n- src: '**/*'\n  patterns:\n  - pattern: \"notice: 'Project was successfully created.'\"\n    replace: \"notice: '${projectWasSuccessfullyCreated}'\"\n  - pattern: \"notice: 'Project was successfully updated.'\"\n    replace: \"notice: '${projectWasSuccessfullyUpdated}'\"\n  - pattern: \"notice: 'Project was successfully deleted.'\"\n    replace: \"notice: '${projectWasSuccessfullyDeleted}'\"\n  - pattern: \"notice: 'Group was successfully created.'\"\n    replace: \"notice: '${groupWasSuccessfullyCreated}'\"\n  - pattern: \"notice: 'Group was successfully updated.'\"\n    replace: \"notice: '${groupWasSuccessfullyUpdated}'\"\n  - pattern: \"notice: 'Group was successfully deleted.'\"\n    replace: \"notice: '${groupWasSuccessfullyDeleted}'\"\n\n# ja.yml\nprojectWasSuccessfullyCreated: 'プロジェクトが作成されました'\nprojectWasSuccessfullyUpdated: 'プロジェクトが更新されました'\nprojectWasSuccessfullyDeleted: 'プロジェクトが削除されました'\ngroupWasSuccessfullyCreated: 'グループが作成されました'\ngroupWasSuccessfullyUpdated: 'グループが更新されました'\ngroupWasSuccessfullyDeleted: 'グループが削除されました'\n```\n\nThe above configurations have similar translations, so you could rewrite them using arguments like this:\n\n```yaml\n# i18n.yml\ntranslations:\n- src: '**/*'\n  patterns:\n  - pattern: \"notice: 'Project was successfully created.'\"\n    replace: \"notice: '${somethingWasSuccessfullyDone}'\"\n    args:\n    - '${project}'\n    - '${create}'\n  - pattern: \"notice: 'Project was successfully updated.'\"\n    replace: \"notice: '${somethingWasSuccessfullyDone}'\"\n    args:\n    - '${project}'\n    - '${update}'\n  - pattern: \"notice: 'Project was successfully deleted.'\"\n    replace: \"notice: '${somethingWasSuccessfullyDone}'\"\n    args:\n    - '${project}'\n    - '${delete}'\n  - pattern: \"notice: 'Group was successfully created.'\"\n    replace: \"notice: '${somethingWasSuccessfullyDone}'\"\n    args:\n    - '${group}'\n    - '${create}'\n  - pattern: \"notice: 'Group was successfully updated.'\"\n    replace: \"notice: '${somethingWasSuccessfullyDone}'\"\n    args:\n    - '${group}'\n    - '${update}'\n  - pattern: \"notice: 'Group was successfully deleted.'\"\n    replace: \"notice: '${somethingWasSuccessfullyDone}'\"\n    args:\n    - '${group}'\n    - '${delete}'\n\n# ja.yml\nsomethingWasSuccessfullyDone: '{0}が{1}されました'\nproject: プロジェクト\ngroup: グループ\ncreate: 作成\nupdate: 更新\ndelete: 削除\n```\n\n`ja.yml` is much improved - it doesn't contain any duplicate translations.  \nBut as you can see, `i18n.yml` is much longer than before.\n\nYou can use `named-patterns` to improve this.\n\nThe `named-patterns` pre-define `pattern`, `replace` and `args`\nlike \"function\" and you can call it with `name` with `params`:\n\n```yaml\n# i18n.yml\ntranslations:\n- src: '**/*'\n  named-patterns:\n  - name: somethingWasSuccessfullyDone\n    pattern: \"notice: '{obj} was successfully {done}\\\\.'\"\n    replace: \"notice: '${sthWasSuccessfullyDone}'\"\n    args:\n    - '${{objKey}}'\n    - '${{doneKey}}'\n    params: ['obj', 'objKey', 'done', 'doneKey']\n```\n\n\u003e Note: `pattern` in `named-patterns` are treated as regular expressions even if you don't write `!!js/regexp`.\n\nThe above configuration defines a pattern named `somethingWasSuccessfullyDone`.  \n`{obj}`, `{done}`, `{objKey}` and `{doneKey}` are parameters,\nand you can replace it to create a new concrete pattern.\n\nIn `patterns` section, you can write `name` to use this pattern instead of writing complex `pattern`, `replace` and `args`.  \nYou must also set `{obj}`, `{done}`, `{objKey}` and `{doneKey}` with `params` element.\n\n```yaml\n  patterns:\n  - name: somethingWasSuccessfullyDone\n    params:\n    - {obj: Project, objKey: project, done: created, doneKey: create}\n    - {obj: Project, objKey: project, done: updated, doneKey: update}\n    - {obj: Project, objKey: project, done: deleted, doneKey: delete}\n    - {obj: Project, objKey: project, done: created, doneKey: create}\n    - {obj: Project, objKey: project, done: created, doneKey: create}\n```\n\nIn the example above, this\n\n```yaml\n  patterns:\n  - name: somethingWasSuccessfullyDone\n    params:\n    - {obj: Project, objKey: project, done: created, doneKey: create}\n```\n\nis equivalent to this:\n\n```yaml\n  patterns:\n  - pattern: \"notice: 'Project was successfully created.'\"\n    replace: \"notice: '${somethingWasSuccessfullyDone}'\"\n    args:\n    - '${project}'\n    - '${create}'\n```\n\n### Multiline\n\nIf you want to use patterns that match two or more lines and change the order of the lines:\n\n```haml\n  %span.light History for\n  = link_to foobar\n```\n\n```haml\n  = link_to foobar\n  %span.light \u003ctranslation of history for\u003e\n```\n\nthen you can write like this:\n\n```yaml\ntranslations:\n- src: 'test.js'\n  patterns:\n  - pattern: !!js/regexp /^(.*)History for\\n([^\\n]*)$/m\n    replace: '${historyFor}'\n```\n\n```yaml\nhistoryFor: \"$2\\n$1の更新履歴\"\n```\n\nWhen `test.js` is like this,\n\n```haml\n  %span.light History for\n  = link_to foobar\n```\n\nthen the result will be:\n\n```haml\n  = link_to foobar\n  %span.light の更新履歴\n```\n\nYou must use `!!js/regexp` to pattern.  \nTo match a line, you must use `([^\\n]*)`, otherwise the tool cannot calculate the required lines.\n\n### Include/exclude locales\n\nYou can apply a translation config for specific locales using `locale.include` or `locale.exclude` option.\n\nFor example, when the following configuration is given,\n\n```yaml\n# i18n.yml\ntranslations:\n# translation1\n- src: 'test.js'\n  locale:\n    include: ['ja']\n  patterns:\n  - pattern: foo\n    replace: '${foo}'\n# translation2\n- src: 'test.js'\n  locale:\n    exclude: ['ja']\n  patterns:\n  - pattern: bar\n    replace: '${bar}'\n# translation3\n- src: 'test.js'\n  patterns:\n  - pattern: baz\n    replace: '${baz}'\n\n# ja.yml\nfoo: hoge\nbar: fuga\nbaz: piyo\n```\n\nthe following input file\n\n```\nfoo\nbar\nbaz\n```\n\nwill be converted into:\n\n```\nhoge\nbar\npiyo\n```\n\n`translation1` and `translation3` can be applied to `ja` locale (`foo` -\u003e `hoge`, `baz` -\u003e `piyo`), but `translation2` (`bar` -\u003e `fuga`) is not applied to `ja` config due to `locale.exclude`.\n\n### Add new files\n\nYou can add new files using `add` option.\n\n```yaml\n# i18n.yml\ntranslations:\n- add:\n    path: 'a/b/test.js'\n    value: testContent\n\n# ja.yml\ntestContent: |\n             // foo\n             // bar\n```\n\nThis will generate the following file `a/b/test.js`:\n\n```javascript\n// foo\n// bar\n```\n\n### Skip patterns\n\nIf you feel slow to process all files, consider using `skip-patterns` option.\nWhen the lines match these patterns, the subsequent pattern matching process will be skipped, which makes the entire processing faster in some cases.\n\nFor example, when the following configuration is given,\n\n```yaml\n# i18n.yml\ntranslations:\n- src: 'test.js'\n  skip-patterns:\n  - !!js/regexp /^$/\n  - !!js/regexp /secret/\n  patterns:\n  - pattern: 'foo'\n    replace: '${foo}'\n  \n# ja.yml\nfoo: bar\n```\n\nthe following input file\n\n```javascript\n/*\n\n  foo\n  foo secret\n*/\n```\n\nwill be converted into:\n\n```javascript\n/*\n\n  bar\n  foo secret\n*/\n```\n\nYou can see the line `  foo secret` is not translated.  \nThis is because it matches one of the `skip-patterns`: `!!js/regexp /secret/`.\n\n### Match once\n\nIf you specifies many files for a pattern and the pattern is aimed to\nmatch just one file, you can use `match-once` flag.\n\nIf `match-once: true` is set for a pattern,\nthen only the first file among all of the candidate files will be replaced,\nwhich will contribute to improve performance.\n\nFor example, if the following config is given,\n\n```yaml\n# i18n.yml\ntranslations:\n- src: 'src/*.js'\n  patterns:\n  - pattern: 'foo'\n    replace: '${foo}'\n    match-once: true\n\n# ja.yml\nfoo: bar\n```\n\nand if there are two files,\n\n```javascript\n// src/a.js\nconsole.log('hello, foo');\nconsole.log('good morning, foo');\n```\n\n```javascript\n// src/b.js\nconsole.log('hi, foo');\n```\n\nthen only the first matching expression in the first file (src/a.js)\nwill be replaced:\n\n```javascript\n// src/a.js\nconsole.log('hello, bar');\nconsole.log('good morning, foo');\n```\n\n```javascript\n// src/b.js\nconsole.log('hi, foo');\n```\n\nThis option can be used with `named-pattern`.\n\n### Complete pattern\n\nIf one of your patterns is complete pattern\nand don't require other translation, then you can set `complete-pattern: true` to skip other translations for the matched lines.\n\nThis will be useful when you have many patterns and\nthe translations take long time.\n\nFor example, if the following config is given,\n\n```yaml\n# i18n.yml\ntranslations:\n- src: 'test.js'\n  patterns:\n  - pattern: 'foo'\n    replace: '${foo}'\n    complete-pattern: true\n  - pattern: 'bar'\n    replace: '${bar}'\n\n# ja.yml\nfoo: FOO\nbar: BAR\n```\n\nand if there is a following file,\n\n```javascript\n/*\n  bar\n  foo bar\n  bar baz\n*/\n```\n\nthen the result will be like this:\n\n```javascript\n/*\n  BAR\n  FOO bar\n  BAR baz\n*/\n```\n\nThe line `foo bar` matches the pattern `foo`\nand it is defined with `complete-pattern: true`,\nso the line `foo bar` does not match the pattern `bar`.\n\n### Parallel groups\n\nWhen you want to process several `translation`s in parallel,  \nyou can use `parallel-group` option.\n\n```yaml\n# i18n.yml\ntranslations:\n- name: 'foo'\n  parallel-group: 'group1'\n- name: 'bar'\n  parallel-group: 'group1'\n- name: 'baz'\n```\n\nWith the above example, `foo` and `bar` will be processed in parallel because the same `parallel-group` value `group1` is given, and then `baz` will be processed.\n\n### Split files with suffix\n\n`i18n.yml` and `ja.yml` can be split into multiple files using suffix:\n\n```yaml\n# i18n.yml\ntranslations:\n- src: '*.md'\n  patterns:\n  - pattern: 'baz'\n    replace: '${baz}'\n\n# i18n-1.yml\ntranslations:\n- src: '*.js'\n  patterns:\n  - pattern: 'foo'\n    replace: '${foo}'\n\n# i18n-2.yml\ntranslations:\n- src: '*.html'\n  patterns:\n  - pattern: 'bar'\n    replace: '${bar}'\n```\n\nThese files will be merged into a single configuration:\n\n```yaml\ntranslations:\n- src: '*.md'\n  patterns:\n  - pattern: 'baz'\n    replace: '${baz}'\n- src: '*.js'\n  patterns:\n  - pattern: 'foo'\n    replace: '${foo}'\n- src: '*.html'\n  patterns:\n  - pattern: 'bar'\n    replace: '${bar}'\n```\n\n### Evaluate only when conditions are satisfied\n\nIf you have some translation for older versions of the target software and the recent versions don't require that translation, then you should use `evaluate-when` configuration.\n\n`evaluate-when` configuration is a JavaScript expression string to limit evaluation of the translation set.\n\nFor example, if you have patterns for versions older than 1.0.0, and the later versions does not need that patterns, then you can write your `i18n.yml` like this:\n\n```yaml\ntranslations:\n- name: 'example'\n  src: '*.js'\n  evaluate-when: \"semver.lt(version, '1.0.0')\"\n  patterns:\n  - pattern: 'foo'\n    replace: '${foo}'\n```\n\nThe value of `evaluate-when` uses [semver](https://github.com/npm/node-semver) to compare two versions.\n\nOne of the versions is given by command line option `--condition`.  \nIf you execute this tool like `i18n-patch --condition version=1.1.0`, then the expression would be evaluated as `false` and the translation `example` would be skipped.\nAnd if you execute this tool like `i18n-patch --condition version=0.9.2`, then the expression would be evaluated as `true` and the translation `example` would be evaluated and processed as usual.  \n`--condition` option can be used multiple times such as `i18n-patch --condition foo=1 --condition bar=2`.  \nThe value of `--condition` should be `key=value` format, and if you omit `key=` then it would be interpreted to `version=value`.\n\n`evaluate-when` is a JavaScript expression and the main use case is that a part of the target software is rewritten with other language from some version, so semver library can be used in this expression to compare two versions.\n\nThis configuration can be also applied to `pattern`s:\n\n```yaml\ntranslations:\n- name: 'example'\n  src: '*.js'\n  patterns:\n  - pattern: 'foo'\n    replace: '${foo}'\n    evaluate-when: \"semver.lt(version, '1.0.0')\"\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fksoichiro%2Fi18n-patch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fksoichiro%2Fi18n-patch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fksoichiro%2Fi18n-patch/lists"}