4

シナリオは次のとおりです。

  1. さまざまな国でリリースすることにした場合に備えて、NSLocalizedString を使用して iPhone アプリを作成します。
  2. フランスでアプリをリリースすることにしました。
  3. 翻訳者は私のものを受け取り、Localized.strings素晴らしい翻訳をしてくれます
  4. アプリを更新したので、さらに翻訳が必要です。

genstring を使用していて、翻訳者が行った優れた作業を上書きしてしまいます。アプリ バージョンで翻訳を管理する簡単な方法はありますか?

4

5 に答える 5

5

GitHub でこのプロジェクトをチェックしてください。このプロジェクトではgenstrings、少し賢くなる Python スクリプトが提供されています。

リンクのみの回答は好きではないので (リンクが切れる可能性があります)、Python スクリプトもここにドロップします (すべてのクレジットはリンクされたプロジェクトの作成者に与えられます)。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Localize.py - Incremental localization on XCode projects
# João Moreno 2009
# http://joaomoreno.com/

# Modified by Steve Streeting 2010 http://www.stevestreeting.com
# Changes
# - Use .strings files encoded as UTF-8
#   This is useful because Mercurial and Git treat UTF-16 as binary and can't
#   diff/merge them. For use on iPhone you can run an iconv script during build to
#   convert back to UTF-16 (Mac OS X will happily use UTF-8 .strings files).
# - Clean up .old and .new files once we're done

# Modified by Pierre Dulac 2012 http://friendcashapp.com
# Changes
# - use logging instead of print
# Adds
# - MIT Licence
# - the first parameter in the command line to specify the path of *.lproj directories
# - an optional paramter to control the debug level (set to info by default)
# Fixes
# - do not convert a file if it is already in utf-8
# - allow multiline translations generated by genstrings by modifing the re_translation regex
# - 

# MIT Licence
#
# Copyright (C) 2012 Pierre Dulac
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
# associated documentation files (the "Software"), to deal in the Software without restriction, 
# including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
# and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all copies or substantial 
# portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
# LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

from sys import argv
from codecs import open
from re import compile
from copy import copy
import os
import shutil
import optparse
import logging
logging.getLogger().level = logging.INFO

__version__ = "0.1"
__license__ = "MIT"

USAGE = "%prog [options] <url>"
VERSION = "%prog v" + __version__

re_translation = compile(r'^"((?:[^"]|\\")+)" = "((?:[^"]|\\")+)";(?:\n)?$')
re_comment_single = compile(r'^/\*.*\*/$')
re_comment_start = compile(r'^/\*.*$')
re_comment_end = compile(r'^.*\*/$')

class LocalizedString():
    def __init__(self, comments, translation):
        self.comments, self.translation = comments, translation
        self.key, self.value = re_translation.match(self.translation).groups()

    def __unicode__(self):
        return u'%s%s\n' % (u''.join(self.comments), self.translation)

class LocalizedFile():
    def __init__(self, fname=None, auto_read=False):
        self.fname = fname
        self.reset()

        if auto_read:
            self.read_from_file(fname)

    def reset(self):
        self.strings = []
        self.strings_d = {}

    def read_from_file(self, fname=None):
        self.reset()

        fname = self.fname if fname == None else fname
        try:
            #f = open(fname, encoding='utf_8', mode='r')
            f = open(fname, encoding='utf_8', mode='r')
        except:
            print 'File %s does not exist.' % fname
            exit(-1)

        try:
            line = f.readline()
            logging.debug(line)
        except:
            logging.error("Can't read line for file: %s" % fname)
            raise

        i = 1
        while line:
            comments = [line]

            if not re_comment_single.match(line):
                while line and not re_comment_end.match(line):
                    line = f.readline()
                    comments.append(line)

            line = f.readline()
            i += 1

            # handle multi lines
            while len(line) > 1 and line[-2] != u';':
                line += f.readline()
                i += 1

            logging.debug("%d %s" % (i, line.rstrip('\n')))
            if line and re_translation.match(line):
                translation = line
            else:
                logging.error("Line %d of file '%s' raising the exception: %s" % (i, self.fname, line))
                raise Exception('invalid file')

            line = f.readline()
            i += 1
            while line and line == u'\n':
                line = f.readline()
                i += 1

            string = LocalizedString(comments, translation)
            self.strings.append(string)
            self.strings_d[string.key] = string

        f.close()

    def save_to_file(self, fname=None):
        fname = self.fname if fname == None else fname
        try:
            f = open(fname, encoding='utf_8', mode='w')
        except:
            print 'Couldn\'t open file %s.' % fname
            exit(-1)

        # sort by key
        self.strings.sort(key=lambda item: item.key)

        for string in self.strings:
            f.write(string.__unicode__())

        f.close()

    def merge_with(self, new):
        merged = LocalizedFile()

        for string in new.strings:
            if self.strings_d.has_key(string.key):
                new_string = copy(self.strings_d[string.key])
                new_string.comments = string.comments
                string = new_string

            merged.strings.append(string)
            merged.strings_d[string.key] = string

        return merged

    def update_with(self, new):
        for string in new.strings:
            if not self.strings_d.has_key(string.key):
                self.strings.append(string)
                self.strings_d[string.key] = string

def merge(merged_fname, old_fname, new_fname):
    try:
        old = LocalizedFile(old_fname, auto_read=True)
        new = LocalizedFile(new_fname, auto_read=True)
        merged = old.merge_with(new)
        merged.save_to_file(merged_fname)
    except Exception, inst:
        logging.error('Error: input files have invalid format.')
        raise

STRINGS_FILE = 'Localizable.strings'

def localize(path, excluded_paths):
    languages = [os.path.join(path,name) for name in os.listdir(path) if name.endswith('.lproj') and os.path.isdir(os.path.join(path,name))]
    print "languages found", languages

    for language in languages:
        original = merged = language + os.path.sep + STRINGS_FILE
        old = original + '.old'
        new = original + '.new'

        if os.path.isfile(original):
            try:
                open(original, encoding='utf_8', mode='r').read()
                os.rename(original, old)
            except:
                os.system('iconv -f UTF-16 -t UTF-8 "%s" > "%s"' % (original, old))

            # gen
            os.system('find %s -name \*.m -not -path "%s" | xargs genstrings -q -o "%s"' % (path, excluded_paths, language))

            try:
                open(original, encoding='utf_8', mode='r').read()
                shutil.copy(original, new)
            except:
                os.system('iconv -f UTF-16 -t UTF-8 "%s" > "%s"' % (original, new))

            # merge  
            merge(merged, old, new)
            logging.info("Job done for language: %s" % language)
        else:
            os.system('genstrings -q -o "%s" `find %s -name "*.m" -not -path "%s"`' % (language, path, excluded_paths))
            os.rename(original, old)
            try:
                open(old, encoding='utf_8', mode='r').read()
            except:
                os.system('iconv -f UTF-16 -t UTF-8 "%s" > "%s"' % (old, original))

        if os.path.isfile(old):
            os.remove(old)
        if os.path.isfile(new):
            os.remove(new)

def parse_options():
    """parse_options() -> opts, args

    Parse any command-line options given returning both
    the parsed options and arguments.
    """

    parser = optparse.OptionParser(usage=USAGE, version=VERSION)

    parser.add_option("-d", "--debug",
            action="store_true", default=False, dest="debug",
            help="Set to DEBUG the logging level (default to INFO)")

    parser.add_option("-p", "--path",
            action="store", type="str", default=os.getcwd(), dest="path",
            help="Path (relative or absolute) to use for searching for *.lproj directories")

    parser.add_option("-e", "--exclude",
            action="store", type="str", default=None, dest="excluded_paths",
            help="Regex for paths to exclude ex. ``./Folder1/*``")

    opts, args = parser.parse_args()
    return opts, args

if __name__ == '__main__':
    opts, args = parse_options()
    if opts.debug:
        logging.getLogger().level = logging.DEBUG
    if opts.path:
        opts.path = os.path.realpath(opts.path)
    if opts.excluded_paths:
        opts.excluded_paths = os.path.realpath(opts.excluded_paths)
    logging.info("Running the script on path %s" % opts.path)
    localize(opts.path, opts.excluded_paths)
于 2013-06-27T11:35:08.717 に答える
3

私が使う:

http://www.loc-suite.com

新しい部分のみを翻訳するには

于 2013-06-27T12:08:53.120 に答える
0

私は同様の問題を抱えていました。私は自分の NSLocalizedString-macros の多くのキーを変更し、翻訳が欠落しているアプリを出荷することを恐れていました (アプリ全体を手動で実行して、すべてがそこにあるかどうかを確認したくありませんでした...)。

Gabriella Petronella が投稿した github プロジェクトを試してみましたが、あまり満足できなかったので、やりたいことを実現するために独自の Python モジュールを作成しました。(これはモジュール全体であり、1 つのスクリプトだけではないため、ここにコードを投稿するつもりはありません:D)

于 2015-10-07T12:30:21.950 に答える
0

実際にPhraseAppというツールを使い始めましたhttps://phraseapp.com/projects

アプリをローカライズする必要がある場合は、検討する価値があります。

于 2015-06-03T13:17:36.983 に答える
0

選択できるオプションは次のとおりです。

  • 最近翻訳された文字列を古いファイルに追加する際に、古いファイルを完全には書き換えない、上記のスクリプトのような手書きのソリューションを使用できます。
  • 持っているすべての文字列を含む追加のstrings.hファイルを作成することもできるので、常に1か所でそれらを書き換える必要はありません。したがって、ゲンストリングはもう必要ありません。ただし、これを使用することには短所があります。string.h ファイルが構造化されていないため、大規模なプロジェクトにはおそらく不向きです。

NSLocalizedString を使用したベストプラクティスに感謝

// In strings.h

 #define YOUR_STRING_KEY NSLocalizedString(@"Cancel", nil)

// Somewhere else in you code

NSLog(@"%@", YOUR_STRING_KEY);
于 2017-04-27T14:08:43.040 に答える