[mob[ Added doc for mobile translations + added 2 new source string… (#4040)

This is my first contribution and I wanted to start with something
'simple'. My goal is to further contribute to the translation of Ente
photos. I am trying to understand that process which is not yet entirely
clear to me, especially when it comes to which files must be (or do not
need to be) generated.

## Description
As a first (small) step, I have:
- created 2 new source strings ('collaboratorsSuccessfullyAdded' and
'viewersSuccessfullyAdded') that replace hardcoded text in the
"add_a_participant" page.
- Created draft of a documentation for translations on mobile app (based
on the doc for web app)

## Tests

Tested on my Pixel 6a

Built with :
- Flutter 3.24.3
- JDK 17.0.2
- Gradle 7.2

## Questions
- I have manually updated the `l10n.dart` file (using existing similar
strings ) but I guess it should be automatically generated from the
`intl_en.arb` file, correct? If so, is it something anyone can do and
can we add the step in the doc?
- Should the other languages be updated as well in that commit, or will
they only be updated via the Github Crowdin action ? Looking at the
existing PR, it seems like they might need to be updated as well in the
commit.
This commit is contained in:
Neeraj Gupta
2024-11-20 14:19:10 +05:30
committed by GitHub
4 changed files with 97 additions and 2 deletions

View File

@@ -0,0 +1,49 @@
# Translations
We use Crowdin for translations, and the `intl` package to load these at
runtime.
Within our project we have the _source_ strings - these are the key value pairs
in the `lib/l10n/intl_en.arb` file.
Volunteers can add a new _translation_ in their language corresponding to each
such source key-value to our
[Crowdin project](https://crowdin.com/project/ente-photos-app).
When a new source string is added, we run a [GitHub workflow](../../.github/workflows/mobile-crowdin-push.yml)
that
- Uploads sources to Crowdin - So any new key value pair we add in the source
`intl_en.arb` becomes available to translators to translate.
Every monday, we run a [GitHub workflow](../../.github/workflows/mobile-crowdin-sync.yml)
that
- Downloads translations from Crowdin - So any new translations that
translators have made on the Crowdin dashboard (for existing sources) will
be added to the corresponding `intl_XX.arb`.
The workflow also uploads existing translations and also downloads new sources
from Crowdin, but these two should be no-ops.
## Adding a new string
- Add a new entry in `lib/l10n/intl_en.arb` (the
**source `intl_en.arb`**).
- Use the new key in code with the `S` class
(`import "package:photos/generated/l10n.dart"`).
- During the next sync, the workflow will upload this source item to Crowdin's
dashboard, allowing translators to translate it.
## Updating an existing string
- Update the existing value for the key in the source `intl_en.arb`.
- During the next sync, the workflow will clear out all the existing
translations so that they can be translated afresh.
## Deleting an existing string
- Remove the key value pair from the source `intl_en.arb`.
- During the next sync, the workflow will delete that source item from all
existing translations (both in the Crowdin project and also from the
other `intl_XX.arb` files in the repository).

View File

@@ -9945,6 +9945,32 @@ class S {
args: [],
);
}
/// `{count, plural, =0 {Added 0 viewer} =1 {Added 1 viewer} other {Added {count} viewers}}`
String viewersSuccessfullyAdded(int count) {
return Intl.plural(
count,
zero: 'Added 0 viewer',
one: 'Added 1 viewer',
other: 'Added $count viewers',
name: 'viewersSuccessfullyAdded',
desc: 'Number of viewers that were successfully added to an album.',
args: [count],
);
}
/// `{count, plural, =0 {Added 0 collaborator} =1 {Added 1 collaborator} other {Added {count} collaborators}}`
String collaboratorsSuccessfullyAdded(int count) {
return Intl.plural(
count,
zero: 'Added 0 collaborator',
one: 'Added 1 collaborator',
other: 'Added $count collaborators',
name: 'collaboratorsSuccessfullyAdded',
desc: 'Number of collaborators that were successfully added to an album.',
args: [count],
);
}
}
class AppLocalizationDelegate extends LocalizationsDelegate<S> {

View File

@@ -1363,5 +1363,25 @@
"checkingModels": "Checking models...",
"enableMachineLearningBanner": "Enable machine learning for magic search and face recognition",
"searchDiscoverEmptySection": "Images will be shown here once processing is complete",
"searchPersonsEmptySection": "People will be shown here once processing is complete"
"searchPersonsEmptySection": "People will be shown here once processing is complete",
"viewersSuccessfullyAdded": "{count, plural, =0 {Added 0 viewer} =1 {Added 1 viewer} other {Added {count} viewers}}",
"@viewersSuccessfullyAdded": {
"placeholders": {
"count": {
"type": "int",
"example": "2"
}
},
"description": "Number of viewers that were successfully added to an album."
},
"collaboratorsSuccessfullyAdded": "{count, plural, =0 {Added 0 collaborator} =1 {Added 1 collaborator} other {Added {count} collaborators}}",
"@collaboratorsSuccessfullyAdded": {
"placeholders": {
"count": {
"type": "int",
"example": "2"
}
},
"description": "Number of collaborators that were successfully added to an album."
}
}

View File

@@ -239,7 +239,7 @@ class _AddParticipantPage extends State<AddParticipantPage> {
results.where((e) => e).length;
showToast(
context,
"Added $noOfSuccessfullAdds ${widget.isAddingViewer ? "viewers" : "collaborators"}",
widget.isAddingViewer ? S.of(context).viewersSuccessfullyAdded(noOfSuccessfullAdds) : S.of(context).collaboratorsSuccessfullyAdded(noOfSuccessfullAdds),
);
if (!results.any((e) => e == false) && mounted) {