{"id":1323,"url":"https://github.com/metasmile/strsync","last_synced_at":"2025-08-02T04:30:57.241Z","repository":{"id":57471936,"uuid":"45332708","full_name":"metasmile/strsync","owner":"metasmile","description":"A CLI tool for localization resource management on Xcode. Built with Google Translator. ","archived":false,"fork":false,"pushed_at":"2020-12-20T16:17:00.000Z","size":4025,"stargazers_count":165,"open_issues_count":21,"forks_count":19,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-07-13T21:45:28.221Z","etag":null,"topics":["automatic-translation","i18n","language","synchronizer","translation","translation-management","verify"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/metasmile.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":"2015-11-01T09:08:17.000Z","updated_at":"2024-03-26T12:51:55.000Z","dependencies_parsed_at":"2022-08-30T13:52:12.746Z","dependency_job_id":null,"html_url":"https://github.com/metasmile/strsync","commit_stats":null,"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/metasmile/strsync","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metasmile%2Fstrsync","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metasmile%2Fstrsync/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metasmile%2Fstrsync/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metasmile%2Fstrsync/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/metasmile","download_url":"https://codeload.github.com/metasmile/strsync/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metasmile%2Fstrsync/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268334609,"owners_count":24233793,"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","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"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":["automatic-translation","i18n","language","synchronizer","translation","translation-management","verify"],"created_at":"2024-01-05T20:15:43.809Z","updated_at":"2025-08-02T04:30:56.753Z","avatar_url":"https://github.com/metasmile.png","language":"Python","funding_links":[],"categories":["Localization","工具","Python"],"sub_categories":["Other Hardware","Other free courses"],"readme":"![](https://cdn.rawgit.com/metasmile/strsync/master/logo_1_3.svg)\n\n[![Awesome](https://img.shields.io/badge/Awesome-iOS-red.svg)](https://github.com/vsouza/awesome-ios#localization)\n[![PyPI version](https://badge.fury.io/py/strsync.svg)](https://badge.fury.io/py/strsync)\n[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)\n\n\u003ca href=\"https://www.jetbrains.com/?from=strsync\"\u003e\u003cimg height=\"50\"  src=\"https://www.evernote.com/l/AEFsE9xH3YVI9aqky2n5PW-clj7Q5KPyaJIB/image.png\"\u003e\u003ca/\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\n  \u003ca href=\"https://www.jetbrains.com/opensource/\"\u003e\u003cimg height=\"54\"  src=\"https://www.evernote.com/l/AEF0Agt6EXBGbZmKyluiDEC7N6VUPbPBNU0B/image.png\"\u003e\u003ca/\u003e\n  \u003ca href=\"https://www.jetbrains.com/pycharm/\"\u003e\u003cimg height=\"54\"  src=\"https://www.evernote.com/l/AEGfypRW_sNDDaXWNhhhDwUajGDFcX3SR90B/image.png\"\u003e\u003c/a\u003e\n\n*Supported by Jetbrains Open Source License Program*\n\n\n\n----\n\n\n**Automatically translate and synchronize '.strings' files from the defined base language**\n\n\u003cimg src=\"https://gitcdn.xyz/cdn/metasmile/strsync/bccf2ff1cb4a4d5585460e8cfa5ffc9d9fd60b98/usage_sample.gif\"\u003e\n\nThe basic concept of this python CLI tool is straightforward file name based one-way synchronizer. If you are running, other localized resources will have the same key with automatically translated strings. Of course, string on the key that already exists will not be modified at all.\n\n![](https://github.com/metasmile/strsync/blob/master/structure.png)\n\n\n## Requirements\n### Install\n```\npip install strsync\n```\n\n#### Enable Google Cloud Translation Python API\n\nSet your account and authentication credentials up with Google's guide for local envirnment.\n\nhttps://cloud.google.com/translate/docs/reference/libraries#client-libraries-install-python\n\nIf you can't use Translation feature, use '-w' option to copy all items from Base language.\n```\n$ strsync ./myapp/Resources/Localizations -w\n```\n\n#### Update Python SSL packages if needed\n\nthis is not required for python-2.7.9+\n\n```shell\npip install requests[security]\n```\n\n## Usage\n\nNaturally, this tool follow [standard ISO639 1~2 codes](http://www.loc.gov/standards/iso639-2/php/English_list.php) or [apple's official document](https://developer.apple.com/library/ios/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html) or [this tsv table](https://github.com/metasmile/strsync/blob/master/strsync/lc_ios9.tsv)\n\n```\nusage: strsync-runner.py [-h] [-b BASE_LANG_NAME]\n                         [-x EXCLUDING_LANG_NAMES [EXCLUDING_LANG_NAMES ...]]\n                         [-f [FORCE_TRANSLATE_KEYS [FORCE_TRANSLATE_KEYS ...]]]\n                         [-o FOLLOWING_BASE_KEYS [FOLLOWING_BASE_KEYS ...]]\n                         [-w [FOLLOWING_BASE_IF_NOT_EXISTS [FOLLOWING_BASE_IF_NOT_EXISTS ...]]]\n                         [-l CUTTING_LENGTH_RATIO_WITH_BASE [CUTTING_LENGTH_RATIO_WITH_BASE ...]]\n                         [-c [IGNORE_COMMENTS [IGNORE_COMMENTS ...]]]\n                         [-v [VERIFY_RESULTS [VERIFY_RESULTS ...]]]\n                         [-s [INCLUDE_SECONDARY_LANGUAGES [INCLUDE_SECONDARY_LANGUAGES ...]]]\n                         [-i [IGNORE_UNVERIFIED_RESULTS [IGNORE_UNVERIFIED_RESULTS ...]]]\n                         [target path] [only for keys [only for keys ...]]\n\nAutomatically translate and synchronize .strings files from defined base\nlanguage.\n\npositional arguments:\n  target path           Target localization resource path. (root path of\n                        Base.lproj, default=./)\n  only for keys         Some specified keys for exclusive work. All operations\n                        will work for only that keys therefore other keys will\n                        be ignored. Not specified by default. (default=None)\n\noptional arguments:\n  -h, --help            show this help message and exit\n  -b BASE_LANG_NAME, --base-lang-name BASE_LANG_NAME\n                        A base(or source) localizable resource\n                        name.(default='Base'), (e.g. \"Base\" via 'Base.lproj',\n                        \"en\" via 'en.lproj')\n  -x EXCLUDING_LANG_NAMES [EXCLUDING_LANG_NAMES ...], --excluding-lang-names EXCLUDING_LANG_NAMES [EXCLUDING_LANG_NAMES ...]\n                        A localizable resource name that you want to exclude.\n                        (e.g. \"Base\" via 'Base.lproj', \"en\" via 'en.lproj')\n  -f [FORCE_TRANSLATE_KEYS [FORCE_TRANSLATE_KEYS ...]], --force-translate-keys [FORCE_TRANSLATE_KEYS [FORCE_TRANSLATE_KEYS ...]]\n                        Keys in the strings to update and translate by force.\n                        (input nothing for all keys.)\n  -o FOLLOWING_BASE_KEYS [FOLLOWING_BASE_KEYS ...], --following-base-keys FOLLOWING_BASE_KEYS [FOLLOWING_BASE_KEYS ...]\n                        Keys in the strings to follow from \"Base.\n  -w [FOLLOWING_BASE_IF_NOT_EXISTS [FOLLOWING_BASE_IF_NOT_EXISTS ...]], --following-base-if-not-exists [FOLLOWING_BASE_IF_NOT_EXISTS [FOLLOWING_BASE_IF_NOT_EXISTS ...]]\n                        With this option, all keys will be followed up with\n                        base values if they does not exist.\n  -l CUTTING_LENGTH_RATIO_WITH_BASE [CUTTING_LENGTH_RATIO_WITH_BASE ...], --cutting-length-ratio-with-base CUTTING_LENGTH_RATIO_WITH_BASE [CUTTING_LENGTH_RATIO_WITH_BASE ...]\n                        Keys in the float as the ratio to compare the length\n                        of \"Base\"\n  -c [IGNORE_COMMENTS [IGNORE_COMMENTS ...]], --ignore-comments [IGNORE_COMMENTS [IGNORE_COMMENTS ...]]\n                        Allows ignoring comment synchronization.\n  -v [VERIFY_RESULTS [VERIFY_RESULTS ...]], --verify-results [VERIFY_RESULTS [VERIFY_RESULTS ...]]\n                        Verify translated results via reversed results\n  -s [INCLUDE_SECONDARY_LANGUAGES [INCLUDE_SECONDARY_LANGUAGES ...]], --include-secondary-languages [INCLUDE_SECONDARY_LANGUAGES [INCLUDE_SECONDARY_LANGUAGES ...]]\n                        Include Additional Secondary Languages. (+63 language\n                        codes)\n  -i [IGNORE_UNVERIFIED_RESULTS [IGNORE_UNVERIFIED_RESULTS ...]], --ignore-unverified-results [IGNORE_UNVERIFIED_RESULTS [IGNORE_UNVERIFIED_RESULTS ...]]\n                        Allows ignoring unverified results when appending\n                        them.\n```\n\n### Examples to use\n```\n~/Documents/myapp/myapp/Resources/Localizations$ strsync\n~/Documents/myapp/myapp/Resources/Intents$ strsync\n```\n\nDefine specific path you want. A parent path of *.lproj(s).\n```\n$ strsync ./myapp/Resources/Localizations\n$ strsync ./myapp/Resources/Intents\n```\n\nCopy all items from Base language without translation.\n```\n$ strsync ./myapp/Resources/Localizations -w\n```\n\nAll operations will work for only keys \"exclusive key1\" \"exclusive key2\" \"exclusive key3\". Other keys will be ignored.\n```\n$ strsync ./myapp/Resources/Localizations \"exclusive key1\" \"exclusive key2\" \"exclusive key3\"\n```\n\nExcluding japanese, spanish, finnish\n```\n$ strsync ./myapp/Resources/Localizations -x ja es fi\n```\n\nForcefully translate and update by specific keys you want.\n```\n$ strsync -f Common.OK Common.Undo \"Key name which contains white space\"\n```\n\nForcefully translate and update by All keys.\n```\n$ strsync -f  (input nothing)\n```\n\nWhen you want to accept the values in the 'Base'.\n```\n$ strsync -o autoenhance flashmode\n\n#before\n\"flashmode\" = \"وضع الفلاش\";\n\"flashmode.auto\" = \"السيارات\";\n\"flashmode.on\" = \"على\";\n\"autoenhance\" = \"تعزيز السيارات\";\n\n#after\n\"flashmode\" = \"Flash Mode\";\n\"flashmode.auto\" = \"السيارات\";\n\"flashmode.on\" = \"على\";\n\"autoenhance\" = \"Auto-Enhance\";\n```\n\nIf you add an option **-v** or **--verify-results**,\nString similarity of the reversed translation result for each language will be displayed.\n\n```\n$ strsync (...) -v\n\nel\n  Hi: Hi -\u003e Γεια σου -\u003e Hi, Matched: 100%\nfr-CA\n  Hi: Hi -\u003e Salut -\u003e Hello, Matched: 50%\nid\n  Hi: Hi -\u003e Hai -\u003e Two, Matched: 0%\nfr\n  Hi: Hi -\u003e Salut -\u003e Hello, Matched: 50%\nuk\n  Hi: Hi -\u003e Привіт -\u003e Hi, Matched: 100%\nhr\n  Hi: Hi -\u003e Bok -\u003e Book, Matched: 0%\nda\n  Hi: Hi -\u003e Hej -\u003e Hi, Matched: 100%\nja\n  Hi: Hi -\u003e こんにちは -\u003e Hello, Matched: 50%\nhe\n  Hi: Hi -\u003e היי -\u003e Hey, Matched: 50%\nko\n  Hi: Hi -\u003e 안녕 -\u003e Hi, Matched: 100%\nsv\n  Hi: Hi -\u003e Hej -\u003e Hi, Matched: 100%\nes-MX\n  Hi: Hi -\u003e Hola -\u003e Hello, Matched: 50%\nsk\n  Hi: Hi -\u003e ahoj -\u003e Hi, Matched: 100%\nzh-CN\n  Hi: Hi -\u003e 你好 -\u003e How are you doing, Matched: 50%\n```\n\nor if you add **--ignore-unverified-results** *[Integer, Percentage (0~100) (default=0)]*,\nIf the similarity of each reversed translation result is under the given value, that string will be skipped(ignored).\n\nex)\n```\nstrings will be skipped if its text similarity from reversed translation result is under 50\n\n$ strsync (...) --ignore-unverified-results 50\n\nel\n  Hi: Hi -\u003e Γεια σου -\u003e Hi, Matched: 100%\nfr-CA\n  (Ignored) Hi: Hi -\u003e Salut -\u003e Hello, Matched: 50%\nid\n  (Ignored) Hi: Hi -\u003e Hai -\u003e Two, Matched: 0%\nfr\n  (Ignored) Hi: Hi -\u003e Salut -\u003e Hello, Matched: 50%\nuk\n  Hi: Hi -\u003e Привіт -\u003e Hi, Matched: 100%\nhr\n  (Ignored) Hi: Hi -\u003e Bok -\u003e Book, Matched: 0%\nda\n  Hi: Hi -\u003e Hej -\u003e Hi, Matched: 100%\nja\n  (Ignored) Hi: Hi -\u003e こんにちは -\u003e Hello, Matched: 50%\nhe\n  (Ignored) Hi: Hi -\u003e היי -\u003e Hey, Matched: 50%\nko\n  Hi: Hi -\u003e 안녕 -\u003e Hi, Matched: 100%\nsv\n  Hi: Hi -\u003e Hej -\u003e Hi, Matched: 100%\nes-MX\n  (Ignored) Hi: Hi -\u003e Hola -\u003e Hello, Matched: 50%\nsk\n  Hi: Hi -\u003e ahoj -\u003e Hi, Matched: 100%\nzh-CN\n  (Ignored) Hi: Hi -\u003e 你好 -\u003e How are you doing, Matched: 50%\n```\n\n\n## Utilities\n\nThere are some additional scripts to help your workflow with strsync.\n\nhttps://github.com/metasmile/strsync/tree/master/utils\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetasmile%2Fstrsync","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmetasmile%2Fstrsync","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetasmile%2Fstrsync/lists"}