-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: introduce i18n framework #3036
feat: introduce i18n framework #3036
Conversation
✅ Deploy Preview for actualbudget ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
ceffa3c
to
4ee7d2b
Compare
Bundle Stats — desktop-clientHey there, this message comes from a GitHub action that helps you and reviewers to understand how these changes affect the size of this project's bundle. As this PR is updated, I'll keep you updated on how the bundle size is impacted. Total
Changeset
View detailed bundle breakdownAdded No assets were added Removed No assets were removed Bigger
Smaller No assets were smaller Unchanged
|
Bundle Stats — loot-coreHey there, this message comes from a GitHub action that helps you and reviewers to understand how these changes affect the size of this project's bundle. As this PR is updated, I'll keep you updated on how the bundle size is impacted. Total
Changeset No files were changed View detailed bundle breakdownAdded No assets were added Removed No assets were removed Bigger No assets were bigger Smaller No assets were smaller Unchanged
|
I think maybe this is where utilizing github-actions would be powerful. Some other projects implementing similar crowd-sourcing software had a separately maintained repo, and would download the latest release from the translations repo on build. see https://github.com/FOSSBilling/FOSSBilling/blob/72338356a543f1c68ec6be913fbb7c6ede63e09f/.github/workflows/release-build.yml#L48 the translations themselves never touch the main repo. the framework and all the translation calls are obviously in the main repo, but the translations only end up in built versions. when new strings are added to edge, github-actions could also push any new strings from any PRs to the language repo and/or the crowd-sourcing tool(see https://github.com/marketplace/actions/github-transifex-actions) and if translators are active they could update the translations before the PR ever makes it into a release, meaning for end users going from release-to-release, they would never see the untranslated strings. I set the appropriate key using devtools in brave browser, but it seemingly had the wrong namespace in the i18n.ts call; |
👋 Hi! It looks like this PR has not had any changes for a week now. Would you like someone to review this PR? If so - please remove the "[WIP]" prefix from the PR title. That will let the community know that this PR is open for a review. |
This comment was marked as spam.
This comment was marked as spam.
@ramielsawy it was clear that natural language keys are preferred by the project maintainers from reading the previous discussions: #249 (comment) , #497 (comment) I myself primarily use and prefer gettext in projecrs which heavily relies on natural language as well. You repeat yourself in your very one-sided arguments which sounds like you asked ChatGPT for some blurbs that heavily favor one side without giving one single thought to the alternative. Half of your AI-generated points are solved with proper tooling. I will agree that the i18next format is heavily lacking however. I specifically wrote I started work on this again precisely because the project owners don't want to have a maintenance overhead. I hoped this approach in this PR would alleviate these issues and FINALLY get i18n into Actual. I personally don't care which way it happens but if the approach two years ago went nowhere because of pointless neverending discussions Actual will never have a translated UI. Unfortunately it's a pain in the rear to retroactively prepare projects for translations but there needs to be some collective effort where we can all pull on the same end of the rope? |
@julianwachholz thanks for the call-out on AI. @ramielsawy lets keep AI out of this conversation please. |
@julianwachholz @MatissJanis I don't have the same grudge against AI, I am here already because I want (with my team) to build AI on top of Actual and contribute back with our paid time to the core of the project :) Also I don't generate the the content using AI, I write my comment first and then let AI reformat, so don't take offense. If we can get back to the subject, I'd like to point out that the comment here #205 (comment) gave the feeling that the PR was closed due to inactivity not because it's using keys. So my yes/no question is: are you open to building on top of #205 or are you stuck in using natural language keys? That will make us save money wasted on some code that you would reject anyways. |
Natural language is the way to go. But you can also think of "natural language" as space-separated keys. :) -- Looked through the code - everything looks good. Only one point I would like more clarity on:
Is this when building the source? Or would users of the app would need to make an external API call to weblate (or similar service)? If it's an external API calls for all users - lets not do that. We want the app to be usable offline + without all the trackers that the external 3rd party might add when you query it. Instead we can pull the translations on build time. Pull them in as JSONs (via HTTP or via github actions automatic sync or another method) and then publish all these JSONs in the final build. And then the user can lazy-load the specific language they use. |
Thank you for your time to look at this @MatissJanis!
I need to revise the original comment, I've since changed this to load the message catalogue with a dynamic import. It was loading from the /public folder before previously, not an external service. One big alternate solution that I saw was creating compiled translated sources for each locale, I think Paperless-ngx does this. With this they are able to leverage XLIFF translation files which enable richer translation source catalogues annotated with source location, comments etc. Loading and parsing a big XML file at runtime is a non-starter in my opinion though and compiling different source trees for each locale is a completely new can of worms. |
a9e2c89
to
663c33c
Compare
namespaceSeparator: false, | ||
defaultValue: (locale, ns, key, value) => { | ||
if (locale === 'en') { | ||
return value || key; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want to pre-fill the base en
language file with exactly the same content as in the source.
default: | ||
return `An unknown error occurred: ${error}`; | ||
return t(`An unknown error occurred: {{error}}`, { error }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basic interpolation example.
</Link>{' '} | ||
in a new tab for some guidance on what to do when you’ve set your | ||
password. | ||
<Trans> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Example using React components. The translatable string will contain placeholders like <2>our tour</2>
const [menuOpen, setMenuOpen] = useState(null); | ||
const triggerRef = useRef(null); | ||
|
||
if (selectedItems.size === 0) { | ||
return null; | ||
} | ||
|
||
const label = { | ||
transactions: t('{{count}} transactions', { count: selectedItems.size }), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Example with pluralization.
Using natural language keys requires the base en
translation catalogue to exist to be able to also use plural forms in English. Example
663c33c
to
f516d47
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice
There's a merge conflict, can you fix? @julianwachholz
3e10c20
c22e8fb
to
3e10c20
Compare
Let's re-start efforts to bring Actual Budgets to a broader audience by translating the app into different languages.
Previous work: #205
This PR introduces i18next as internationalization framework to lay the groundwork on getting Actual Budget translated into other languages. It features the following concepts:
t()
function or<Trans>
component.i18next-parser
into a baseen
JSON file. A shorthandyarn generate:i18n
was added to thepackage.json
.desktop-client
andloot-core
are extracted into the same single file located withindesktop-client
. This reduces complexity by not having to manage multiple namespaces.Other notes: