Merge pull request #2240 from zhaoweny/i18n

I18n: more string annotations (mostly tooltips)
This commit is contained in:
Ryan Holmes
2020-08-02 13:07:11 -04:00
committed by GitHub
10 changed files with 255 additions and 123 deletions

View File

@@ -42,10 +42,13 @@ from eos.saveddata.targetProfile import TargetProfile
from eos.utils.float import floatUnerr
from eos.utils.stats import DmgTypes, RRTypes
pyfalog = Logger(__name__)
def _t(x):
return x
class FitLite:
def __init__(self, id=None, name=None, shipID=None, shipName=None, shipNameShort=None):
@@ -395,16 +398,16 @@ class Fit:
@property
def scanType(self):
maxStr = -1
type = None
for scanType in ("Magnetometric", "Ladar", "Radar", "Gravimetric"):
type_ = None
for scanType in (_t("Magnetometric"), _t("Ladar"), _t("Radar"), _t("Gravimetric")):
currStr = self.ship.getModifiedItemAttr("scan%sStrength" % scanType)
if currStr > maxStr:
maxStr = currStr
type = scanType
type_ = scanType
elif currStr == maxStr:
type = "Multispectral"
type_ = _t("Multispectral")
return type
return type_
@property
def jamChance(self):
@@ -443,9 +446,9 @@ class Fit:
@validates("ID", "ownerID", "shipID")
def validator(self, key, val):
map = {
"ID" : lambda _val: isinstance(_val, int),
"ID": lambda _val: isinstance(_val, int),
"ownerID": lambda _val: isinstance(_val, int) or _val is None,
"shipID" : lambda _val: isinstance(_val, int) or _val is None
"shipID": lambda _val: isinstance(_val, int) or _val is None
}
if not map[key](val):
@@ -578,15 +581,15 @@ class Fit:
if warfareBuffID == 11: # Shield Burst: Active Shielding: Repair Duration/Capacitor
self.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill("Shield Operation") or
mod.item.requiresSkill("Shield Emission Systems") or
mod.item.requiresSkill("Capital Shield Emission Systems"),
"capacitorNeed", value)
lambda mod: mod.item.requiresSkill("Shield Operation") or
mod.item.requiresSkill("Shield Emission Systems") or
mod.item.requiresSkill("Capital Shield Emission Systems"),
"capacitorNeed", value)
self.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill("Shield Operation") or
mod.item.requiresSkill("Shield Emission Systems") or
mod.item.requiresSkill("Capital Shield Emission Systems"),
"duration", value)
lambda mod: mod.item.requiresSkill("Shield Operation") or
mod.item.requiresSkill("Shield Emission Systems") or
mod.item.requiresSkill("Capital Shield Emission Systems"),
"duration", value)
if warfareBuffID == 12: # Shield Burst: Shield Extension: Shield HP
self.ship.boostItemAttr("shieldCapacity", value, stackingPenalties=True)
@@ -597,15 +600,15 @@ class Fit:
if warfareBuffID == 14: # Armor Burst: Rapid Repair: Repair Duration/Capacitor
self.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems") or
mod.item.requiresSkill("Repair Systems") or
mod.item.requiresSkill("Capital Remote Armor Repair Systems"),
"capacitorNeed", value)
lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems") or
mod.item.requiresSkill("Repair Systems") or
mod.item.requiresSkill("Capital Remote Armor Repair Systems"),
"capacitorNeed", value)
self.modules.filteredItemBoost(
lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems") or
mod.item.requiresSkill("Repair Systems") or
mod.item.requiresSkill("Capital Remote Armor Repair Systems"),
"duration", value)
lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems") or
mod.item.requiresSkill("Repair Systems") or
mod.item.requiresSkill("Capital Remote Armor Repair Systems"),
"duration", value)
if warfareBuffID == 15: # Armor Burst: Armor Reinforcement: Armor HP
self.ship.boostItemAttr("armorHP", value, stackingPenalties=True)
@@ -980,14 +983,14 @@ class Fit:
for _ in range(projectionInfo.amount):
targetFit.register(item, origin=self)
item.calculateModifiedAttributes(
targetFit, runTime, forceProjected=True,
forcedProjRange=0)
targetFit, runTime, forceProjected=True,
forcedProjRange=0)
for mod in self.modules:
for _ in range(projectionInfo.amount):
targetFit.register(mod, origin=self)
mod.calculateModifiedAttributes(
targetFit, runTime, forceProjected=True,
forcedProjRange=projectionInfo.projectionRange)
targetFit, runTime, forceProjected=True,
forcedProjRange=projectionInfo.projectionRange)
def fill(self):
"""
@@ -1003,7 +1006,8 @@ class Fit:
# Look for any dummies of that type to remove
posToRemove = {}
for slotType in (FittingSlot.LOW.value, FittingSlot.MED.value, FittingSlot.HIGH.value, FittingSlot.RIG.value, FittingSlot.SUBSYSTEM.value, FittingSlot.SERVICE.value):
for slotType in (
FittingSlot.LOW.value, FittingSlot.MED.value, FittingSlot.HIGH.value, FittingSlot.RIG.value, FittingSlot.SUBSYSTEM.value, FittingSlot.SERVICE.value):
amount = self.getSlotsFree(slotType, True)
if amount > 0:
for _ in range(int(amount)):
@@ -1080,22 +1084,23 @@ class Fit:
for mod in chain(self.modules, self.fighters):
if mod.slot is type and (not getattr(mod, "isEmpty", False) or countDummies):
if type in (FittingSlot.F_HEAVY, FittingSlot.F_SUPPORT, FittingSlot.F_LIGHT, FittingSlot.FS_HEAVY, FittingSlot.FS_LIGHT, FittingSlot.FS_SUPPORT) and not mod.active:
if type in (FittingSlot.F_HEAVY, FittingSlot.F_SUPPORT, FittingSlot.F_LIGHT, FittingSlot.FS_HEAVY, FittingSlot.FS_LIGHT,
FittingSlot.FS_SUPPORT) and not mod.active:
continue
amount += 1
return amount
slots = {
FittingSlot.LOW : "lowSlots",
FittingSlot.MED : "medSlots",
FittingSlot.HIGH : "hiSlots",
FittingSlot.RIG : "rigSlots",
FittingSlot.LOW: "lowSlots",
FittingSlot.MED: "medSlots",
FittingSlot.HIGH: "hiSlots",
FittingSlot.RIG: "rigSlots",
FittingSlot.SUBSYSTEM: "maxSubSystems",
FittingSlot.SERVICE : "serviceSlots",
FittingSlot.F_LIGHT : "fighterLightSlots",
FittingSlot.SERVICE: "serviceSlots",
FittingSlot.F_LIGHT: "fighterLightSlots",
FittingSlot.F_SUPPORT: "fighterSupportSlots",
FittingSlot.F_HEAVY : "fighterHeavySlots",
FittingSlot.F_HEAVY: "fighterHeavySlots",
FittingSlot.FS_LIGHT: "fighterStandupLightSlots",
FittingSlot.FS_SUPPORT: "fighterStandupSupportSlots",
FittingSlot.FS_HEAVY: "fighterStandupHeavySlots",
@@ -1377,8 +1382,8 @@ class Fit:
"""Return how much cap regen do we gain from having this module"""
currentRegen = self.calculateCapRecharge()
nomodRegen = self.calculateCapRecharge(
capacity=self.ship.getModifiedItemAttrExtended("capacitorCapacity", ignoreAfflictors=[mod]),
rechargeRate=self.ship.getModifiedItemAttrExtended("rechargeRate", ignoreAfflictors=[mod]) / 1000.0)
capacity=self.ship.getModifiedItemAttrExtended("capacitorCapacity", ignoreAfflictors=[mod]),
rechargeRate=self.ship.getModifiedItemAttrExtended("rechargeRate", ignoreAfflictors=[mod]) / 1000.0)
return currentRegen - nomodRegen
def getRemoteReps(self, spoolOptions=None):
@@ -1422,7 +1427,8 @@ class Fit:
"armorRepair": self.extraAttributes["armorRepair"],
"armorRepairPreSpool": self.extraAttributes["armorRepairPreSpool"],
"armorRepairFullSpool": self.extraAttributes["armorRepairFullSpool"],
"hullRepair": self.extraAttributes["hullRepair"]}
"hullRepair": self.extraAttributes["hullRepair"]
}
return reps
@property
@@ -1462,7 +1468,8 @@ class Fit:
"armorRepair": self.extraAttributes["armorRepair"],
"armorRepairPreSpool": self.extraAttributes["armorRepairPreSpool"],
"armorRepairFullSpool": self.extraAttributes["armorRepairFullSpool"],
"hullRepair": self.extraAttributes["hullRepair"]}
"hullRepair": self.extraAttributes["hullRepair"]
}
if not self.capStable or self.factorReload:
# Map a local repairer type to the attribute it uses
groupAttrMap = {
@@ -1470,14 +1477,16 @@ class Fit:
"Ancillary Shield Booster": "shieldBonus",
"Armor Repair Unit": "armorDamageAmount",
"Ancillary Armor Repairer": "armorDamageAmount",
"Hull Repair Unit": "structureDamageAmount"}
"Hull Repair Unit": "structureDamageAmount"
}
# Map local repairer type to tank type
groupStoreMap = {
"Shield Booster": "shieldRepair",
"Ancillary Shield Booster": "shieldRepair",
"Armor Repair Unit": "armorRepair",
"Ancillary Armor Repairer": "armorRepair",
"Hull Repair Unit": "hullRepair"}
"Hull Repair Unit": "hullRepair"
}
repairers = []
localAdjustment = {"shieldRepair": 0, "armorRepair": 0, "hullRepair": 0}
capUsed = self.capUsed
@@ -1529,7 +1538,7 @@ class Fit:
# Sort repairers by efficiency. We want to use the most efficient repairers first
repairers.sort(key=lambda _mod: _mod.getModifiedItemAttr(
groupAttrMap[_mod.item.group.name]) * (_mod.getModifiedItemAttr(
groupAttrMap[_mod.item.group.name]) * (_mod.getModifiedItemAttr(
"chargedArmorDamageMultiplier") or 1) / _mod.getModifiedItemAttr("capacitorNeed"), reverse=True)
# Loop through every module until we're above peak recharge
@@ -1654,7 +1663,6 @@ class Fit:
secstatus = FitSystemSecurity.NULLSEC
return secstatus
def activeModulesIter(self):
for mod in self.modules:
if mod.state >= FittingModuleState.ACTIVE:

View File

@@ -22,6 +22,10 @@ from eos.utils.float import floatUnerr
from utils.repr import makeReprStr
def _t(x):
return x
class DmgTypes:
"""Container for damage data stats."""
@@ -116,7 +120,7 @@ class DmgTypes:
@staticmethod
def names(short=None, postProcessor=None):
value = ['em', 'th', 'kin', 'exp'] if short else ['em', 'thermal', 'kinetic', 'explosive']
value = [_t('em'), _t('th'), _t('kin'), _t('exp')] if short else [_t('em'), _t('thermal'), _t('kinetic'), _t('explosive')]
if postProcessor:
value = [postProcessor(x) for x in value]

View File

@@ -39,9 +39,9 @@ class RemoveItem(ContextMenuCombined):
return True
def getText(self, callingWindow, itmContext, mainItem, selection):
return _t('Remove {}{}').format(
itmContext if itmContext is not None else _t('Item'),
_t(' Stack') if self.srcContext in ('droneItem', 'projectedDrone', 'cargoItem', 'projectedFit') else '')
return _t('Remove {item}{stack}').format(
item=itmContext if itmContext is not None else _t('Item'),
stack=_t(' Stack') if self.srcContext in ('droneItem', 'projectedDrone', 'cargoItem', 'projectedFit') else '')
def activate(self, callingWindow, fullContext, mainItem, selection, i):
handlerMap = {

View File

@@ -136,10 +136,9 @@ class CapacitorViewFull(StatsView):
label.SetToolTip(wx.ToolTip("%.1f" % value))
if labelName == 'label%sCapacitorDelta' and (cap_recharge or cap_use):
lines = []
lines.append('Capacitor delta:')
lines.append(' +{} GJ/s'.format(formatAmount(cap_recharge, 3, 0, 3)))
lines.append(' -{} GJ/s'.format(formatAmount(cap_use, 3, 0, 3)))
lines = [_t('Capacitor delta:'),
' +{} GJ/s'.format(formatAmount(cap_recharge, 3, 0, 3)),
' -{} GJ/s'.format(formatAmount(cap_use, 3, 0, 3))]
delta = round(cap_recharge - cap_use, 3)
if delta > 0 and 0 < round(neut_res, 4) < 1:
lines.append('')
@@ -147,9 +146,9 @@ class CapacitorViewFull(StatsView):
lines.append(' +{} GJ/s'.format(formatAmount(delta / neut_res, 3, 0, 3)))
label.SetToolTip(wx.ToolTip('\n'.join(lines)))
if labelName == 'label%sCapacitorResist':
texts = ['Neutralizer resistance']
texts = [_t('Neutralizer resistance')]
if cap_amount > 0 and 0 < round(neut_res, 4) < 1:
texts.append('Effective capacity: {} GJ'.format(formatAmount(cap_amount / neut_res, 3, 0, 9)))
texts.append(_t('Effective capacity') + ': {} GJ'.format(formatAmount(cap_amount / neut_res, 3, 0, 9)))
label.SetToolTip(wx.ToolTip('\n'.join(texts)))
capState = fit.capState if fit is not None else 0

View File

@@ -166,20 +166,20 @@ class FirepowerViewFull(StatsView):
hasSpool = hasSpoolUp(preSpool, fullSpool)
lines = []
if hasSpool:
lines.append("Spool up: {}-{}".format(
formatAmount(preSpool.total, prec, lowest, highest),
formatAmount(fullSpool.total, prec, lowest, highest)))
lines.append(_t("Spool up") + ": {}-{}".format(
formatAmount(preSpool.total, prec, lowest, highest),
formatAmount(fullSpool.total, prec, lowest, highest)))
if getattr(normal, 'total', None):
if hasSpool:
lines.append("")
lines.append("Current: {}".format(formatAmount(normal.total, prec, lowest, highest)))
lines.append(_t("Current") + ": {}".format(formatAmount(normal.total, prec, lowest, highest)))
for dmgType in normal.names():
val = getattr(normal, dmgType, None)
if val:
lines.append("{}{}: {}%".format(
" " if hasSpool else "",
dmgType.capitalize(),
formatAmount(val / normal.total * 100, 3, 0, 0)))
" " if hasSpool else "",
_t(dmgType).capitalize(),
formatAmount(val / normal.total * 100, 3, 0, 0)))
return "\n".join(lines)
defaultSpoolValue = eos.config.settings['globalDefaultSpoolupPercentage']
@@ -218,8 +218,8 @@ class FirepowerViewFull(StatsView):
if self._cachedValues[counter] != val:
tooltipText = dpsToolTip(val, preSpoolVal, fullSpoolVal, prec, lowest, highest)
label.SetLabel(valueFormat.format(
formatAmount(0 if val is None else val.total, prec, lowest, highest),
"\u02e2" if hasSpoolUp(preSpoolVal, fullSpoolVal) else ""))
formatAmount(0 if val is None else val.total, prec, lowest, highest),
"\u02e2" if hasSpoolUp(preSpoolVal, fullSpoolVal) else ""))
label.SetToolTip(wx.ToolTip(tooltipText))
self._cachedValues[counter] = val
counter += 1

View File

@@ -29,25 +29,25 @@ _t = wx.GetTranslation
stats = [
(
"labelRemoteCapacitor", "Capacitor:", "{}{} GJ/s", "capacitorInfo", "Capacitor restored",
"labelRemoteCapacitor", "Capacitor:", "{}{} GJ/s", "capacitorInfo", _t("Capacitor restored"),
lambda fit, spool: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, spool, False)).capacitor,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 0, True)).capacitor,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 1, True)).capacitor,
3, 0, 0),
(
"labelRemoteShield", "Shield:", "{}{} HP/s", "shieldActive", "Shield restored",
"labelRemoteShield", "Shield:", "{}{} HP/s", "shieldActive", _t("Shield restored"),
lambda fit, spool: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, spool, False)).shield,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 0, True)).shield,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 1, True)).shield,
3, 0, 0),
(
"labelRemoteArmor", "Armor:", "{}{} HP/s", "armorActive", "Armor restored",
"labelRemoteArmor", "Armor:", "{}{} HP/s", "armorActive", _t("Armor restored"),
lambda fit, spool: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, spool, False)).armor,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 0, True)).armor,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 1, True)).armor,
3, 0, 0),
(
"labelRemoteHull", "Hull:", "{}{} HP/s", "hullActive", "Hull restored",
"labelRemoteHull", "Hull:", "{}{} HP/s", "hullActive", _t("Hull restored"),
lambda fit, spool: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, spool, False)).hull,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 0, True)).hull,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 1, True)).hull,

View File

@@ -28,25 +28,25 @@ _t = wx.GetTranslation
stats = [
(
"labelRemoteCapacitor", "Capacitor:", "{}{} GJ/s", "capacitorInfo", "Capacitor restored",
"labelRemoteCapacitor", "Capacitor:", "{}{} GJ/s", "capacitorInfo", _t("Capacitor restored"),
lambda fit, spool: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, spool, False)).capacitor,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 0, True)).capacitor,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 1, True)).capacitor,
3, 0, 0),
(
"labelRemoteShield", "Shield:", "{}{} HP/s", "shieldActive", "Shield restored",
"labelRemoteShield", "Shield:", "{}{} HP/s", "shieldActive", _t("Shield restored"),
lambda fit, spool: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, spool, False)).shield,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 0, True)).shield,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 1, True)).shield,
3, 0, 0),
(
"labelRemoteArmor", "Armor:", "{}{} HP/s", "armorActive", "Armor restored",
"labelRemoteArmor", "Armor:", "{}{} HP/s", "armorActive", _t("Armor restored"),
lambda fit, spool: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, spool, False)).armor,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 0, True)).armor,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 1, True)).armor,
3, 0, 0),
(
"labelRemoteHull", "Hull:", "{}{} HP/s", "hullActive", "Hull restored",
"labelRemoteHull", "Hull:", "{}{} HP/s", "hullActive", _t("Hull restored"),
lambda fit, spool: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, spool, False)).hull,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 0, True)).hull,
lambda fit: fit.getRemoteReps(spoolOptions=SpoolOptions(SpoolType.SPOOL_SCALE, 1, True)).hull,

View File

@@ -215,11 +215,11 @@ class TargetingMiscViewMinimal(StatsView):
ecmChance = otherValues["jamChance"]
ecmChance = round(ecmChance, 1)
if ecmChance > 0:
label.SetToolTip(wx.ToolTip(_t("Type: {0}\n").foramt(fit.scanType) +
label.SetToolTip(wx.ToolTip(_t("Type: {0}\n").foramt(_t(fit.scanType)) +
# xgettext:no-python-format,python-brace-format
_t("{}% chance to be jammed").format(formatAmount(ecmChance, 3, 0, 0))))
else:
label.SetToolTip(wx.ToolTip(_t("Type: {}").format(fit.scanType)))
label.SetToolTip(wx.ToolTip(_t("Type: {}").format(_t(fit.scanType))))
elif labelName == "labelFullAlignTime":
alignTime = _t("Align:\t%.3fs") % mainValue
mass = _t('Mass:\t{:,.0f}kg').format(fit.ship.getModifiedItemAttr("mass"))

View File

@@ -6,12 +6,12 @@ pyfa provides community-driven translations for a variety of languages. It is im
* Ship browser
* Item names, description, traits, attributes
If there is a tranlation issue in EVE data, you must submit a ticket to CCP instead.
If there is a translation issue in EVE data, you must submit a ticket to CCP instead.
## Getting Involved
Translations are done mainly through [Crowdin](https://crowdin.com/project/pyfa). This platform allows translations to be done by anyone without any real need to understand the project's internals. Simply sign up, join the project as a Translator, and start translating!
As a general rule of thumb, we consider translations community-driven. The pyfa team isn't going to
1) Maintain individual language packs as a part of general development work, or
@@ -42,13 +42,13 @@ msgstr "点击切换有效HP和原始HP"
[Poedit](https://poedit.net/) offers a nice GUI for updating translations.
##### To update PO file for existing translation
#### To update PO file for existing translation
1. open a existing `locale/ll_CC/LC_MESSAGES/lang.po`
2. *Catalog* -> *Update from POT file*
3. select pre-prepared `lang.pot` file
##### To translate and generate MO file
#### To translate and generate MO file
edit the translation and hit Save :)
@@ -59,7 +59,8 @@ A: This is probably one of two things:
1. Missing annotations in the source code. All text that needs to be translated needs to be wrapped with `_t()` to make it locale-aware
2. Out of date `.po` file. As pyfa development continues, the `.po` file may fall behind. See next question.
Q: How do I update the `.po` file for my language?<br />
A: See `Commands` section below for a number of useful commands
@@ -70,31 +71,32 @@ A: If you're running from source / your own method, this is because the `.mo` fi
Below is a summary of [GNU gettext](https://www.gnu.org/software/gettext/) manual, adapted for Pyfa i18n workflow.
[Poedit](https://poedit.net/) offers a nice GUI for same GNU gettext translation workflow.
## i18n with command line
Windows users can get these tools via Git for windows, Msys2 or Cygwin; or just use WSL / WSL2.
For Linux and macOS users these tools might be available out-of-box.
Windows users can get these tools via Git for windows, Msys2 or Cygwin; or just use WSL / WSL2. For Linux and macOS users these tools might be available out-of-box.
### To generate new template for translation:
```console
$ find gui/ *.py -name "*.py" | xgettext --from-code=UTF-8 -o locale/lang.pot -d lang -k_t -f - -s
$ find * -name "*.py" | xgettext --from-code=UTF-8 -o locale/lang.pot -d lang -k_t -k_t:1,2,3t -k_t:1,2c,2t -f - -s
```
explanation:
* `find gui/ *.py -name "*.py"`: collect all `.py` file path in `gui` folder and all sub-folders, write it to stdout
* `xgettext`: a utility looking for keyword and put string literals in a specific format for human translation
* `find * -name "*.py"`: collect all `.py` file path in current folder and all sub-folders, write it to stdout
* except those starts with `.`. E.g. `.env`, `.idea`, `.venv`.
* can also append `-not -path 'path/to/venv/*` to exclude `path/to/venv` recursively.
* `xgettext` ([doc](https://www.gnu.org/software/gettext/manual/gettext.html#Template)): a utility looking for keyword and put string literals in a specific format for human translation
* `--from-code=UTF-8`: designates encoding of files
* `-o locale/lang.pot`: let `xgettext` write to `locale/lang.pot`
* `-d lang`: default language domain is `lang`
* `-k_t`: besides default keyword (including `_`, see `info xgettext` for detail), also look for `_t`
* `-f -`: let `xgettext` to read from stdin, which is connected to `find` stdout
* `-k_t`: besides default keyword (including `_`, see `info xgettext` for detail), also look for `_t`,
where the string literal (`msgid`) will be the first argument of this function call
* `-k_t:1,2,3t`: look for `_t`, first arg is `msgid`, second arg is `msgid_plural`, 3 args in total
* `-k_t:1,2c,2t`: look for `_t`, first arg is `msgid`, second arg is `msgctxt`, 2 args in total
* `-f -`: let `xgettext` to read filenames from stdin, which is connected to `find` stdout
* `-s`: sort output according to `msgid`
this `locale/lang.pot` is called PO template, which is discarded once actual `ll_CC/LC_MESSAGES/lang.po` is ready for use.
this `locale/lang.pot` is called PO template, which is the source file for Crowdin translation.
### To initialize PO file for new language

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-07-17 11:42+0800\n"
"POT-Creation-Date: 2020-07-27 15:29+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,6 +16,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
#: gui/builtinStatsViews/firepowerViewFull.py:107
msgid " DPS: "
@@ -32,7 +33,9 @@ msgstr ""
#: gui/builtinItemStatsViews/itemProperties.py:98
#, python-format
msgid "%d attribute."
msgstr ""
msgid_plural "%d attributes."
msgstr[0] ""
msgstr[1] ""
#: gui/mainMenuBar.py:73
msgid "&Backup All Fittings"
@@ -276,6 +279,10 @@ msgstr ""
msgid "Add Fits"
msgstr ""
#: gui/builtinContextMenus/targetProfile/adder.py:29
msgid "Add Target Profile"
msgstr ""
#: gui/builtinContextMenus/cargoAddAmmo.py:28
#, python-brace-format
msgid "Add {0} to Cargo (x1000)"
@@ -370,7 +377,7 @@ msgstr ""
msgid "Angel Cartel"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:70
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:73
msgid "Animate gauges"
msgstr ""
@@ -420,6 +427,11 @@ msgstr ""
msgid "Armor resistance"
msgstr ""
#: gui/builtinStatsViews/outgoingViewFull.py:44
#: gui/builtinStatsViews/outgoingViewMinimal.py:43
msgid "Armor restored"
msgstr ""
#: gui/builtinStatsViews/resistancesViewFull.py:206
msgid "Armor: "
msgstr ""
@@ -462,6 +474,11 @@ msgstr ""
msgid "Auto"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:145
msgid ""
"Auto will use the same language pyfa uses if available, otherwise English"
msgstr ""
#: gui/builtinPreferenceViews/pyfaNetworkPreferences.py:87
msgid "Auto-detected proxy settings"
msgstr ""
@@ -622,6 +639,15 @@ msgstr ""
msgid "Capacitor"
msgstr ""
#: gui/builtinStatsViews/capacitorViewFull.py:139
msgid "Capacitor delta:"
msgstr ""
#: gui/builtinStatsViews/outgoingViewFull.py:32
#: gui/builtinStatsViews/outgoingViewMinimal.py:31
msgid "Capacitor restored"
msgstr ""
#: gui/builtinStatsViews/capacitorViewFull.py:57
msgid "Capacitor stability"
msgstr ""
@@ -678,7 +704,7 @@ msgstr ""
msgid "Change Skills"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:81
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:84
msgid "Change charge in all modules of the same type"
msgstr ""
@@ -761,7 +787,7 @@ msgstr ""
msgid "Client Secret:"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:51
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:54
msgid "Color fitting view by slot"
msgstr ""
@@ -785,7 +811,7 @@ msgstr ""
msgid "Command center hold"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:47
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:50
msgid "Compact skills needed tooltip"
msgstr ""
@@ -902,6 +928,10 @@ msgstr ""
msgid "Cruor (Blood Raiders)"
msgstr ""
#: gui/builtinStatsViews/firepowerViewFull.py:175
msgid "Current"
msgstr ""
#: gui/builtinItemStatsViews/itemAttributes.py:45
#: gui/builtinItemStatsViews/itemProperties.py:57
msgid "Current Value"
@@ -1131,7 +1161,7 @@ msgstr ""
msgid "Drag a fit to this area"
msgstr ""
#: gui/builtinAdditionPanes/projectedView.py:226
#: gui/builtinAdditionPanes/projectedView.py:224
msgid "Drag an item or fit, or use right-click menu for wormhole effects"
msgstr ""
@@ -1240,6 +1270,10 @@ msgstr ""
msgid "EVE API XML character files"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:127
msgid "EVE Data:"
msgstr ""
#: gui/builtinPreferenceViews/pyfaHTMLExportPreferences.py:49
msgid "EVE IGB HTML fitting file"
msgstr ""
@@ -1278,6 +1312,10 @@ msgstr ""
msgid "Effective HP: "
msgstr ""
#: gui/builtinStatsViews/capacitorViewFull.py:151
msgid "Effective capacity"
msgstr ""
#: graphs/data/fitDamageStats/graph.py:85
msgid "Effective damage inflicted"
msgstr ""
@@ -1558,7 +1596,7 @@ msgstr ""
msgid "Exporting skills needed..."
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:89
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:92
msgid "Extra info in Additions panel tab names"
msgstr ""
@@ -1758,7 +1796,7 @@ msgstr ""
msgid "Gas hold"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:17
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:20
msgid "General"
msgstr ""
@@ -1795,6 +1833,10 @@ msgstr ""
msgid "Graphs"
msgstr ""
#: eos/saveddata/fit.py:402
msgid "Gravimetric"
msgstr ""
#: graphs/style.py:53
msgid "Green"
msgstr ""
@@ -1861,6 +1903,11 @@ msgstr ""
msgid "Hull resistance"
msgstr ""
#: gui/builtinStatsViews/outgoingViewFull.py:50
#: gui/builtinStatsViews/outgoingViewMinimal.py:49
msgid "Hull restored"
msgstr ""
#: gui/builtinStatsViews/resistancesViewFull.py:206
msgid "Hull: "
msgstr ""
@@ -2025,6 +2072,10 @@ msgstr ""
msgid "Interceptor"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:122
msgid "Interested in helping with translations?"
msgstr ""
#: eos/saveddata/damagePattern.py:127 eos/saveddata/damagePattern.py:128
#: eos/saveddata/damagePattern.py:132 eos/saveddata/damagePattern.py:135
#: eos/saveddata/damagePattern.py:138 eos/saveddata/targetProfile.py:94
@@ -2092,8 +2143,12 @@ msgstr ""
msgid "Kinetic resistance"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:96
msgid "Language (restart required):"
#: eos/saveddata/fit.py:402
msgid "Ladar"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:97
msgid "Language (requires restart)"
msgstr ""
#: gui/builtinStatsViews/targetingMiscViewMinimal.py:120
@@ -2101,7 +2156,7 @@ msgid "Large ship hold"
msgstr ""
#: gui/builtinStatsViews/capacitorViewFull.py:77
#: gui/builtinStatsViews/capacitorViewFull.py:171
#: gui/builtinStatsViews/capacitorViewFull.py:170
msgid "Lasts "
msgstr ""
@@ -2208,6 +2263,10 @@ msgstr ""
msgid "Magenta"
msgstr ""
#: eos/saveddata/fit.py:402
msgid "Magnetometric"
msgstr ""
#: gui/builtinStatsViews/targetingMiscViewMinimal.py:114
msgid "Maintenance bay"
msgstr ""
@@ -2378,6 +2437,10 @@ msgstr ""
msgid "Multifrequency"
msgstr ""
#: eos/saveddata/fit.py:408
msgid "Multispectral"
msgstr ""
#: gui/copySelectDialog.py:54
msgid "Mutated Attributes"
msgstr ""
@@ -2497,6 +2560,10 @@ msgstr ""
msgid "Network"
msgstr ""
#: gui/builtinStatsViews/capacitorViewFull.py:149
msgid "Neutralizer resistance"
msgstr ""
#: graphs/data/fitEwarStats/graph.py:36
msgid "Neuts: cap per second"
msgstr ""
@@ -2540,7 +2607,7 @@ msgstr ""
msgid "No proxy"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:90
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:93
#: gui/builtinPreferenceViews/pyfaStatViewPreferences.py:42
#: gui/builtinPreferenceViews/pyfaStatViewPreferences.py:50
#: gui/builtinPreferenceViews/pyfaStatViewPreferences.py:58
@@ -2613,7 +2680,7 @@ msgstr ""
msgid "Open Widgets Inspect tool"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:73
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:76
msgid "Open fittings in a new page by default"
msgstr ""
@@ -2769,10 +2836,10 @@ msgstr ""
msgid "Projected"
msgstr ""
#: gui/builtinAdditionPanes/projectedView.py:306
#: gui/builtinAdditionPanes/projectedView.py:316
#: gui/builtinAdditionPanes/projectedView.py:321
#: gui/builtinAdditionPanes/projectedView.py:326
#: gui/builtinAdditionPanes/projectedView.py:304
#: gui/builtinAdditionPanes/projectedView.py:314
#: gui/builtinAdditionPanes/projectedView.py:319
#: gui/builtinAdditionPanes/projectedView.py:324
msgid "Projected Item"
msgstr ""
@@ -2832,14 +2899,18 @@ msgstr ""
msgid "Quafe hold"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:90
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:93
msgid "Quantity of active items"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:90
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:93
msgid "Quantity of all items"
msgstr ""
#: eos/saveddata/fit.py:402
msgid "Radar"
msgstr ""
#: eos/saveddata/damagePattern.py:45
msgid "Radio"
msgstr ""
@@ -2929,14 +3000,15 @@ msgid "Remove Overides for Item"
msgstr ""
#: gui/builtinContextMenus/itemRemove.py:42
msgid "Remove {}{}"
#, python-brace-format
msgid "Remove {item}{stack}"
msgstr ""
#: gui/builtinShipBrowser/fitItem.py:108
msgid "Rename"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:55
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:58
msgid "Reopen previous fits on startup"
msgstr ""
@@ -3040,6 +3112,10 @@ msgstr ""
msgid "Salvage hold"
msgstr ""
#: locale_test/getTextLocale.py:4
msgid "Sample Title Text English"
msgstr ""
#: eos/saveddata/damagePattern.py:156 eos/saveddata/targetProfile.py:80
#: gui/builtinContextMenus/envEffectAdd.py:112
msgid "Sansha Incursion"
@@ -3130,7 +3206,7 @@ msgstr ""
msgid "Sentinel"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:59
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:62
msgid "Separate Racks"
msgstr ""
@@ -3200,6 +3276,11 @@ msgstr ""
msgid "Shield resistance"
msgstr ""
#: gui/builtinStatsViews/outgoingViewFull.py:38
#: gui/builtinStatsViews/outgoingViewMinimal.py:37
msgid "Shield restored"
msgstr ""
#: gui/builtinPreferenceViews/pyfaStatViewPreferences.py:58
msgid "Shield/Armor Tank"
msgstr ""
@@ -3230,7 +3311,7 @@ msgstr ""
msgid "Short Range"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:63
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:66
msgid "Show Rack Labels"
msgstr ""
@@ -3238,7 +3319,7 @@ msgstr ""
msgid "Show empty ship groups"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:67
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:70
msgid "Show fitting tab tooltips"
msgstr ""
@@ -3250,7 +3331,7 @@ msgstr ""
msgid "Show market shortcuts"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:77
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:80
msgid "Show ship browser tooltip"
msgstr ""
@@ -3329,6 +3410,10 @@ msgstr ""
msgid "Split {} Stack"
msgstr ""
#: gui/builtinStatsViews/firepowerViewFull.py:169
msgid "Spool up"
msgstr ""
#: gui/builtinPreferenceViews/pyfaContextMenuPreferences.py:76
msgid "Spoolup"
msgstr ""
@@ -3337,7 +3422,7 @@ msgstr ""
msgid "Spoolup Cycles"
msgstr ""
#: gui/builtinStatsViews/capacitorViewFull.py:171
#: gui/builtinStatsViews/capacitorViewFull.py:170
msgid "Stable: "
msgstr ""
@@ -3768,15 +3853,15 @@ msgstr ""
msgid "Use capacitor simulator"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:39
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:42
msgid "Use character implants by default for new fits"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:35
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:38
msgid "Use global character"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:43
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:46
msgid "Use global damage pattern"
msgstr ""
@@ -3847,7 +3932,7 @@ msgid ""
"behavior)."
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:86
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:89
msgid ""
"When disabled, reloads charges just in selected modules. Action can be "
"reversed by holding Ctrl or Alt key while changing charge."
@@ -3971,6 +4056,26 @@ msgstr ""
msgid "[T2] Void"
msgstr ""
#: eos/utils/stats.py:123
msgid "em"
msgstr ""
#: eos/utils/stats.py:123
msgid "exp"
msgstr ""
#: eos/utils/stats.py:123
msgid "explosive"
msgstr ""
#: eos/utils/stats.py:123
msgid "kin"
msgstr ""
#: eos/utils/stats.py:123
msgid "kinetic"
msgstr ""
#: gui/builtinPreferenceViews/pyfaDatabasePreferences.py:38
msgid "pyfa User Path:"
msgstr ""
@@ -4004,6 +4109,18 @@ msgstr ""
msgid "pyfa.io"
msgstr ""
#: gui/builtinPreferenceViews/pyfaGeneralPreferences.py:102
msgid "pyfa:"
msgstr ""
#: eos/utils/stats.py:123
msgid "th"
msgstr ""
#: eos/utils/stats.py:123
msgid "thermal"
msgstr ""
#: gui/builtinContextMenus/itemMarketJump.py:44
#, python-brace-format
msgid "{0} Market Group"
@@ -4038,7 +4155,9 @@ msgstr ""
#: gui/builtinViewColumns/baseName.py:104
msgid "{} {} Slot"
msgstr ""
msgid_plural "{} {} Slots"
msgstr[0] ""
msgstr[1] ""
#: gui/builtinStatsViews/targetingMiscViewMinimal.py:220
#, no-python-format, python-brace-format