477
views

Subtitling Freelancers in New Zealand|I will transcribe video or audio from 10 minutes and up, $5 = Transcription to up to 10 minutes of a video/audio file in a text document, proofreading, 1 speaker

MarketplaceSufiaannn wrote the post • 0 comments • 477 views • 2020-04-07 04:32 • added this tag no more than 24h

 

About This Item
 
You want to know every single word spoken on a video or audio file?

I'm just a click away, contact me and we will make something happen fast. A 5-star service and LEVEL ONE seller doing manual transcription, no software used.

Transcription services for:

❆ Interviews
❆ Podcasts
❆ Conference calls
❆ YouTube videos
❆ Webinars
❆ Voice recordings

The transcript will contain:

❆ Word document or any other wanted format
❆ Professional formatting and proofreading
❆ Timestamps
❆ Speakers noted

If the audio quality is poor I can fix it and let you know if it will be able for transcription.
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it. view all
 

About This Item
 
You want to know every single word spoken on a video or audio file?

I'm just a click away, contact me and we will make something happen fast. A 5-star service and LEVEL ONE seller doing manual transcription, no software used.

Transcription services for:

❆ Interviews
❆ Podcasts
❆ Conference calls
❆ YouTube videos
❆ Webinars
❆ Voice recordings

The transcript will contain:

❆ Word document or any other wanted format
❆ Professional formatting and proofreading
❆ Timestamps
❆ Speakers noted

If the audio quality is poor I can fix it and let you know if it will be able for transcription.
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
515
views

Closed Captioning Freelancer in auckland, nz|I will provide data entry administrations at low cost, $5= I will do data entry with high perfection, avoiding fallacy.

MarketplaceSufiaannn wrote the post • 0 comments • 515 views • 2020-04-07 04:23 • added this tag no more than 24h

 

 
About This Item:
 
I am a professional, and you will get expert-level data entry services at low cost

What you will get:

Fast typing speed up to 45 words per minute
Data entry in almost all formats e.g word, powerpoint, excel, etc.
100% accuracy
Lowest rates
High Quality work
No Fallacy
100% Money-back Guarantee

What I will need:

YOUR TRUST
 
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it. view all
 

 
About This Item:
 
I am a professional, and you will get expert-level data entry services at low cost

What you will get:

Fast typing speed up to 45 words per minute
Data entry in almost all formats e.g word, powerpoint, excel, etc.
100% accuracy
Lowest rates
High Quality work
No Fallacy
100% Money-back Guarantee

What I will need:

YOUR TRUST
 
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
506
views

Closed Captioning and Subtitling Freelancer in auckland, nz|I will do impressive photoshop to your images at low cost,$5= Skin retouch + Global adjustments +Background (recommended for Social Media)

MarketplaceSufiaannn wrote the post • 0 comments • 506 views • 2020-04-07 04:21 • added this tag no more than 24h

 
 
 
About This item                       
 
 
 I will give your photos an Awesome photoshop edit                

I will photoshop edit your photos that will amaze you and at the lowest price in the market ..!

                                            ✦✦✦✦✦✦✦✦✦✦✦✦✦✦✦✦✦✦✦✦

✦ Packages include:      ✔  Clothes edit
      ✔  Hair edit
      ✔  Body shape/size edit
      ✔  Background edit
      ✔  Global adjustments
      ✔  Skin touch up
      ✔  Pimple/Scars/Wrinkles edit
      ✔  High-Resolution Images
      ✔  Raw File
      ✔  Source File
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it. view all

 
 
 
About This item                       
 
 
 I will give your photos an Awesome photoshop edit                

I will photoshop edit your photos that will amaze you and at the lowest price in the market ..!

                                            ✦✦✦✦✦✦✦✦✦✦✦✦✦✦✦✦✦✦✦✦

✦ Packages include:      ✔  Clothes edit
      ✔  Hair edit
      ✔  Body shape/size edit
      ✔  Background edit
      ✔  Global adjustments
      ✔  Skin touch up
      ✔  Pimple/Scars/Wrinkles edit
      ✔  High-Resolution Images
      ✔  Raw File
      ✔  Source File
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
498
views

Closed Captioning and Subtitling Freelancer in auckland, nz|I will proofread your documents without fallacy, $5= I will proofread a document of 50 - 1000 words.

MarketplaceSufiaannn wrote the post • 0 comments • 498 views • 2020-04-07 04:18 • added this tag no more than 24h

 
About This item                                    
 
 I will proofread your documents without fallacy   

✷  What you will get :   
✓ Vocabulary correction

✓ Proofreading Up to 10,000 words

✓ Grammar check

✓ Fast Delivery

✓ Consistent language & formatting

✓ Punctuation correction

✓ Re-checked typing errors

✓ 100% customer satisfaction

✷ What I will need :

     YOUR TRUST
 
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.


My portfolios:
 

 

 
 
 
 

 
 
  view all

 
About This item                                    
 
 I will proofread your documents without fallacy   

✷  What you will get :   
✓ Vocabulary correction

✓ Proofreading Up to 10,000 words

✓ Grammar check

✓ Fast Delivery

✓ Consistent language & formatting

✓ Punctuation correction

✓ Re-checked typing errors

✓ 100% customer satisfaction

✷ What I will need :

     YOUR TRUST
 
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.


My portfolios:
 


 


 
 
 
 


 
 
 
508
views

Closed Captioning and Subtitling Freelancer in auckland ,NZ |I will make amazing 2d and 3d logo,$15 1 logo in 2000px X 2000px 400dpi + 10 hrs delivery + 5revisions

MarketplaceSufiaannn wrote the post • 0 comments • 508 views • 2020-04-07 04:11 • added this tag no more than 24h

 
 
About This Item                           
 
 
  I will make Awesome 2D and 3D logos   
 
I will design your logos professionally with unique ideas that will give you an eye-catching impression

                                         ✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻     

✻ Logo Package includes:
✔ Professionally designed 2D/3D logo
✔ High Quality up to 400dpi
✔ Up to 2550 x 3300 px
✔ Logo transparency
✔ Vector file
✔ Source file
✔ Commercial use
✔ On-time Delivery
✔ Unlimited revisions
                                            ✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻    
 
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.  view all

 
 
About This Item                           
 
 
  I will make Awesome 2D and 3D logos   
 
I will design your logos professionally with unique ideas that will give you an eye-catching impression

                                         ✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻     

✻ Logo Package includes:
✔ Professionally designed 2D/3D logo
✔ High Quality up to 400dpi
✔ Up to 2550 x 3300 px
✔ Logo transparency
✔ Vector file
✔ Source file
✔ Commercial use
✔ On-time Delivery
✔ Unlimited revisions
                                            ✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻✻    
 
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it. 
501
views

Freelance Captioner in NZ|I will make english subtitles or srt files for any audio or video. $10 =Make an accurate SRT file for your Video/Vlog/Movie without quality loss

MarketplaceSufiaannn wrote the post • 0 comments • 501 views • 2020-04-07 04:09 • added this tag no more than 24h

 

 
 
About This Item:
 
 
                                      Make subtitles or .srt files for any audio or video                                
                                                                   ✶✶✶✶✶✶
✶I can give you your required file in less than a day (charges apply) without any errors and of almost every accent such as English(US), English(UK), Newzealand, Australian and more.
✶I can also do a clear verbatim transcription at the lowest cost in the market..!                                                                   ✶✶✶✶✶✶

✔ Clear verbatim

✔ Fast delivery

✔ Proofreading

✔ Subtitle and Video merge

✔ 100% Accuracy

✔ Customer satisfaction

                                                                ✶✶✶✶✶✶

  ✶✶CONTACT ME FIRST IF THE AUDIO IS NOT CLEAR (FOR NEGOTIATIONS)✶✶
 
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it. view all
 

 
 
About This Item:
 
 
                                      Make subtitles or .srt files for any audio or video                                
                                                                   ✶✶✶✶✶✶
✶I can give you your required file in less than a day (charges apply) without any errors and of almost every accent such as English(US), English(UK), Newzealand, Australian and more.
✶I can also do a clear verbatim transcription at the lowest cost in the market..!                                                                   ✶✶✶✶✶✶

✔ Clear verbatim

✔ Fast delivery

✔ Proofreading

✔ Subtitle and Video merge

✔ 100% Accuracy

✔ Customer satisfaction

                                                                ✶✶✶✶✶✶

  ✶✶CONTACT ME FIRST IF THE AUDIO IS NOT CLEAR (FOR NEGOTIATIONS)✶✶
 
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
495
views

Freelance Captioner in NZ|I will do transcription for you with clear verbatim and timestamps, $5 = I will transcribe 10+2 mins Audio/Video. Fast Delivery + No fallacy

MarketplaceSufiaannn wrote the post • 0 comments • 495 views • 2020-04-07 04:06 • added this tag no more than 24h

 

 
 
About This item                                
 
 
 I will do transcription for you with clear verbatim                                  

✶I can give you your required file in less than a day without any errors and of almost every accent such as English(US), English(UK), Newzealand, Australian and more.
✶I can also do a clear verbatim transcription at the lowest cost in the market..!
                                                               ✶✶✶✶✶✶

✔ Clear verbatim

✔ Fast delivery

✔ Proofreading

✔ Time Reference

✔ 100% Accuracy

✔ Customer satisfaction

                                                                ✶✶✶✶✶✶

  ✶✶CONTACT ME FIRST IF THE AUDIO IS NOT CLEAR (FOR NEGOTIATIONS)✶✶
 
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it. view all
 

 
 
About This item                                
 
 
 I will do transcription for you with clear verbatim                                  

✶I can give you your required file in less than a day without any errors and of almost every accent such as English(US), English(UK), Newzealand, Australian and more.
✶I can also do a clear verbatim transcription at the lowest cost in the market..!
                                                               ✶✶✶✶✶✶

✔ Clear verbatim

✔ Fast delivery

✔ Proofreading

✔ Time Reference

✔ 100% Accuracy

✔ Customer satisfaction

                                                                ✶✶✶✶✶✶

  ✶✶CONTACT ME FIRST IF THE AUDIO IS NOT CLEAR (FOR NEGOTIATIONS)✶✶
 
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
465
views

Freelance Captioner in Auckland,NZ|I will edit your videos professionally,1 Day Delivery,$5

MarketplaceSufiaannn wrote the post • 0 comments • 465 views • 2020-04-07 04:03 • added this tag no more than 24h

 
About This Item:
 
The Process is Simple, Fast, and Easy!

Step 1: Contact me before ordering so we can discuss your needs. Your project is unique to YOU and YOUR needs. I'll ask a few simple questions so that I can give you the lowest possible price 

Step 2: Provide me with your footage and materials, or you can add-on to have me source footages.

Step 3: Post Production; I'll hit the studio and work tirelessly on your project. You sit back and relax. 

Step 4: Delivery and Approval! You review and we make any necessary revisions (See FAQ's)

I'm a professional, full time editor, Music videos , Short films , Youtube videos , Commercials, Live Events, Photo Slideshows, Small Business Videos, and many more.

My services includeImpeccable Customer Service
Royalty free music, video and more
Color grades and corrections
Output and rendering in any file format
Highest possible quality including 4K
Film and Compositing Elements
and more!
 
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it. view all

 
About This Item:
 
The Process is Simple, Fast, and Easy!

Step 1: Contact me before ordering so we can discuss your needs. Your project is unique to YOU and YOUR needs. I'll ask a few simple questions so that I can give you the lowest possible price 

Step 2: Provide me with your footage and materials, or you can add-on to have me source footages.

Step 3: Post Production; I'll hit the studio and work tirelessly on your project. You sit back and relax. 

Step 4: Delivery and Approval! You review and we make any necessary revisions (See FAQ's)

I'm a professional, full time editor, Music videos , Short films , Youtube videos , Commercials, Live Events, Photo Slideshows, Small Business Videos, and many more.

My services includeImpeccable Customer Service
Royalty free music, video and more
Color grades and corrections
Output and rendering in any file format
Highest possible quality including 4K
Film and Compositing Elements
and more!
 
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
499
views

Freelance Captioner in NZ|I will create srt for closed caption or subtitles for your videos, 1 Day Delivery

MarketplaceSufiaannn wrote the post • 0 comments • 499 views • 2020-04-07 04:00 • added this tag no more than 24h

 
 
About This Item:

I will provide closed captions or subtitles files in any format of your choice, I can also embed subtitles into the video.
 
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it. view all

 
 
About This Item:

I will provide closed captions or subtitles files in any format of your choice, I can also embed subtitles into the video.
 
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
612
views

Subtitling Freelancers in New Zealand|I will remove unwanted objects from video person, logo, things

MarketplaceSufiaannn wrote the post • 0 comments • 612 views • 2020-04-07 03:58 • added this tag no more than 24h

 
 
About This Item:

hey, If you have a video and you want to completely remove unwanted objects from video such as a person, place, objects etc. I can remove these all objects.


EXAMPLES-

1. Sometimes you make a video at a party or on a tour and you see some unknown person or object in the Footage and you want that It should not here. So contact me I will disappear that object or person.

2. Any unwanted text in the video which you want to remove or replace I will do that too.

3. Remove a clock, pen, something on the table, etc in the video,

Please browse my portfolio for samples.

Thank you so much!

Regards,
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it. view all

 
 
About This Item:

hey, If you have a video and you want to completely remove unwanted objects from video such as a person, place, objects etc. I can remove these all objects.


EXAMPLES-

1. Sometimes you make a video at a party or on a tour and you see some unknown person or object in the Footage and you want that It should not here. So contact me I will disappear that object or person.

2. Any unwanted text in the video which you want to remove or replace I will do that too.

3. Remove a clock, pen, something on the table, etc in the video,

Please browse my portfolio for samples.

Thank you so much!

Regards,
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
536
views

Subtitling Freelancers in New Zealand|I will create subtitles srt, scc files for amazon prime , $10 =This is for videos ranging from 1-5 minutes.

MarketplaceSufiaannn wrote the post • 0 comments • 536 views • 2020-04-07 03:55 • added this tag no more than 24h

 

 
 
About This Item
 
 
You're submitting your videos to Amazon Prime and you're told you need captions and you don't know how to do that! 
From now on, it's never been easier. All you need to do is send me the video and I'll generate a perfectly timed .srt or .scc file for you.
My service follows all Amazon Prime's guidelines and instructions and it will be accepted from the first time. 
I have over 3 years of experience and delivered numerous files that were accepted with no problem from Amazon.
 
 
 About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
 
 
 
  view all
 

 
 
About This Item
 
 
You're submitting your videos to Amazon Prime and you're told you need captions and you don't know how to do that! 
From now on, it's never been easier. All you need to do is send me the video and I'll generate a perfectly timed .srt or .scc file for you.
My service follows all Amazon Prime's guidelines and instructions and it will be accepted from the first time. 
I have over 3 years of experience and delivered numerous files that were accepted with no problem from Amazon.
 
 
 About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
 
 
 
 
485
views

I will do professional video editing and post production, $20 = Basic Editing Based on the complexity and the length of the video

MarketplaceSufiaannn wrote the post • 0 comments • 485 views • 2020-04-07 03:51 • added this tag no more than 24h

 
PLEASE CONTACT ME BEFORE ORDERING TO AVOID CANCELLATION

Hello, I'm Sufiaannn, I'll be your video editor for the day.

Let's talk about what I can provide for your videos!

I can insert your intros or outros in the video.
I can insert your already made transitions or standard video transitions
I can insert short captions to make the video more impactful
I can insert lower thirds to introduce speakers and so on
I can change video dimensions into the new trending square videos or any other dimensions for different social media production
I can insert free royalty music
You can check the gig extra which I provide full closed captions to your videos in it!
and much more depending on your needs.
My Simple 4 Step Process:

Contact Me
Explain your project

Link your footage, logos, pictures, editing script etc (Dropbox or Google Drive preferred. Please have ALL your content ready before we start an order.)

I will send a custom offer. All packages listed are starting rates, and I will be able to tell you if your project meets the minimum or if it will cost more or even a little less in some instances. 

What are you waiting for! 
Contact me right away and let's start your project.
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it. view all

 
PLEASE CONTACT ME BEFORE ORDERING TO AVOID CANCELLATION

Hello, I'm Sufiaannn, I'll be your video editor for the day.

Let's talk about what I can provide for your videos!

I can insert your intros or outros in the video.
I can insert your already made transitions or standard video transitions
I can insert short captions to make the video more impactful
I can insert lower thirds to introduce speakers and so on
I can change video dimensions into the new trending square videos or any other dimensions for different social media production
I can insert free royalty music
You can check the gig extra which I provide full closed captions to your videos in it!
and much more depending on your needs.
My Simple 4 Step Process:

Contact Me
Explain your project

Link your footage, logos, pictures, editing script etc (Dropbox or Google Drive preferred. Please have ALL your content ready before we start an order.)

I will send a custom offer. All packages listed are starting rates, and I will be able to tell you if your project meets the minimum or if it will cost more or even a little less in some instances. 

What are you waiting for! 
Contact me right away and let's start your project.
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
562
views

top 10 subtitle freelancers|I will provide translation for documents or videos with subtitles or srt, translate 500 word or 5 min video =$5

MarketplaceSufiaannn wrote the post • 0 comments • 562 views • 2020-04-07 03:48 • added this tag no more than 24h

 
About This Service
 
This Service is for making an srt or subtitle file for your transcribed videos
I will take the transcription that you will provide and time it to the video with great precision and accuracy.

the delivered file will be in two formats

1. srt "can't be modified" standard file works with all platforms.
2. ASS can be modified and can control the font size and color.

you can ask for any Format you want and I'll make it.

My subtitles meet the ADA act.

In 99% You won't even need your revisions at all.

the generated srt file can be used in any platform like
YouTube videos
Facebook videos
Vimeo.
Witsia
Amazon
or any media player you want to play it on.

I provide subtitles in two languages English and Arabic.

Or you can save yourself the trouble and use the gig extra to embed your subtitles to the video in a fancy and pretty look, awesome right!

And that is my second part of the gig which is:

the other part of the gig is embedding the subtitle that I've made into the video instead of delivering the file, you will get your video with the subtitle burnt in it.
note: maximum size is 600 megabytes.
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it. view all

 
About This Service
 
This Service is for making an srt or subtitle file for your transcribed videos
I will take the transcription that you will provide and time it to the video with great precision and accuracy.

the delivered file will be in two formats

1. srt "can't be modified" standard file works with all platforms.
2. ASS can be modified and can control the font size and color.

you can ask for any Format you want and I'll make it.

My subtitles meet the ADA act.

In 99% You won't even need your revisions at all.

the generated srt file can be used in any platform like
YouTube videos
Facebook videos
Vimeo.
Witsia
Amazon
or any media player you want to play it on.

I provide subtitles in two languages English and Arabic.

Or you can save yourself the trouble and use the gig extra to embed your subtitles to the video in a fancy and pretty look, awesome right!

And that is my second part of the gig which is:

the other part of the gig is embedding the subtitle that I've made into the video instead of delivering the file, you will get your video with the subtitle burnt in it.
note: maximum size is 600 megabytes.
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
495
views

I will do transcription for your videos with closed captions or srt files,$5 =transcribe a 5 minutes video very accurately with no subtitle

MarketplaceSufiaannn wrote the post • 0 comments • 495 views • 2020-04-07 03:45 • added this tag no more than 24h

 

About This Item
 
So, you need someone to transcribe your videos or audios but you are afraid to hire someone who uses some lame bots.
 
Well, that problem won't bother you anymore, because you've found this gig. I'll do the transcription for you with the highest precision and accuracy you could wish for.

I have a commitment towards my work, I won't finish the order until my customer is 100% satisfied.

All the transcripts will be revised to the point you won't even need to use your revisions.

Well, now you have your transcripts for your videos, is there a better way to use them?

The answer is, of course, there is. Instead of having just the SCRIPT you could ask for SUBTITLES or CLOSED CAPTIONS represented in SRT files or embedded subtitles with cool styles straight in your videos.

So, what are you waiting for! hit the Big green button and get your work done right away.  
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it. view all
 

About This Item
 
So, you need someone to transcribe your videos or audios but you are afraid to hire someone who uses some lame bots.
 
Well, that problem won't bother you anymore, because you've found this gig. I'll do the transcription for you with the highest precision and accuracy you could wish for.

I have a commitment towards my work, I won't finish the order until my customer is 100% satisfied.

All the transcripts will be revised to the point you won't even need to use your revisions.

Well, now you have your transcripts for your videos, is there a better way to use them?

The answer is, of course, there is. Instead of having just the SCRIPT you could ask for SUBTITLES or CLOSED CAPTIONS represented in SRT files or embedded subtitles with cool styles straight in your videos.

So, what are you waiting for! hit the Big green button and get your work done right away.  
 
About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
536
views

closed caption freelancer in Auckland,NZ| I will burn or embed open captions on video,$5

MarketplaceSufiaannn wrote the post • 0 comments • 536 views • 2020-04-07 03:40 • added this tag no more than 24h

 
 
Hello,

Welcome to my Service!

In this gig, I will professionally burn-in/embed captions to your video at a very reasonable price.  Adobe premiere pro is my all time best friend for burning captions on your videos. Open captions are permanently added to the video, and cannot be turned off. Whereas closed captions can be turned on and off by the viewer.

All you need to do is:
Send me the source video in any common format (mp4, Avi, Mkv)
Subtitle script in any format (.srt, .ssa, .scc)
If you do not have the subtitle script ready. Check out gig packages.
You will get a professional burnt-in subtitled video, which will be perfectly synchronized.

If you have any custom requirement, please let me know before placing the order.
 
 
About me:
 
 
Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
 
My portfolios:
 

 
 

 
 
 
 
  view all

 
 
Hello,

Welcome to my Service!

In this gig, I will professionally burn-in/embed captions to your video at a very reasonable price.  Adobe premiere pro is my all time best friend for burning captions on your videos. Open captions are permanently added to the video, and cannot be turned off. Whereas closed captions can be turned on and off by the viewer.

All you need to do is:
Send me the source video in any common format (mp4, Avi, Mkv)
Subtitle script in any format (.srt, .ssa, .scc)
If you do not have the subtitle script ready. Check out gig packages.
You will get a professional burnt-in subtitled video, which will be perfectly synchronized.

If you have any custom requirement, please let me know before placing the order.
 
 
About me:
 
 
Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
 
My portfolios:
 


 
 


 
 
 
 
 
557
views

video Closed Captions freelancer in auckland,NZ|I will add subtitles or add closed captions, srt for your video. $5

MarketplaceSufiaannn wrote the post • 0 comments • 557 views • 2020-04-07 03:18 • added this tag no more than 24h

 

 
About This Service:
 
Welcome to my Service on captioning!

Always remember the overall benefit of adding accurate and perfectly synchronized subtitles or closed captions to your videos is that you will be able to reach a wider audience, gain popularity and rank high in search results (SEO). 

My captioning services include:

Closed captions or subtitles in SRT, WebVTT  e.t.c
Embedding subtitles permanently on video.
I handle videos for;
YouTube, Amazon Prime, Facebook, Instagram, Vimeo, Wistia, Netflix or other videos.

YOU will not be requested to send a transcript. I will personally prepare the transcript and perfectly synchronize closed captions to your video.

If YOU have the transcript ready and just need the subtitle or closed caption file, I will give you a decent discount.

If need be, I will convert captions to your desired formats. (WebVTT (.vtt), .sbv,  MCC .ssa)

Contact me for a custom offer in case of the following;
Embedding captions permanently on video
You have files longer than 60 minutes.

Making the client's problems mine is my business. 

Drop me a line and let us get started!

Good luck always,
 

About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
  view all
 

 
About This Service:
 
Welcome to my Service on captioning!

Always remember the overall benefit of adding accurate and perfectly synchronized subtitles or closed captions to your videos is that you will be able to reach a wider audience, gain popularity and rank high in search results (SEO). 

My captioning services include:

Closed captions or subtitles in SRT, WebVTT  e.t.c
Embedding subtitles permanently on video.
I handle videos for;
YouTube, Amazon Prime, Facebook, Instagram, Vimeo, Wistia, Netflix or other videos.

YOU will not be requested to send a transcript. I will personally prepare the transcript and perfectly synchronize closed captions to your video.

If YOU have the transcript ready and just need the subtitle or closed caption file, I will give you a decent discount.

If need be, I will convert captions to your desired formats. (WebVTT (.vtt), .sbv,  MCC .ssa)

Contact me for a custom offer in case of the following;
Embedding captions permanently on video
You have files longer than 60 minutes.

Making the client's problems mine is my business. 

Drop me a line and let us get started!

Good luck always,
 

About me:

Hey there I'm Sufiaannn, an electric engineer, I have the mind for it But my heart chose writing. From engineering, I took accuracy and precision and from writing, I took passion and creativity. So, hire me now and I promise you won't regret it.
 
493
views

website design in auckland|Our Studio front-end developer John share how to to use the preact-i18n library to add internationalization to your website. Let your website becomes multi-language site.

Marketplacefull stack developer Kevin wrote the post • 0 comments • 493 views • 2020-04-06 10:31 • added this tag no more than 24h

Hi ,I am john, a developer from website design in Auckland, NZ company local fern.
 In this article, you are going to use the preact-i18n library to add internationalization to your Preact application.

Step 1: Setup Preact CLI & Create new project

Side Note: If you are already familiar with Preact, you may skip to the next step.

If you haven't installed the Preact CLI on your machine, use the following command to install the CLI. Make sure you have Node.js 6.x or above installed.$ npm install -g preact-cli

Once the Preact CLI is installed, let's create a new project using the default template, and call it my-project.$ preact create default my-project

Start the development server with the command below:$ cd my-project && npm run start

Now, open your browser and go to http://localhost:8080, and you should see something like this on your screen:



Step 2: Add preact-i18n library
Install the preact-i18n library to your project using the command below:

$ npm install --save preact-i18n

preact-i18n is very easy to use, and most importantly, it's extremely small, around 1.3kb after gzipped. You can learn more about the library here: https://github.com/synacor/preact-i18n

Step 3: Create a definition file
Once you have the library installed, you will need to create a definition file, which you will store all the translate strings in a JSON file. 

In this case, you will need to save this file in src/i18n/zh-tw.json:{
"home": {
"title": "主頁",
"text": "這是個Home組件。"
}
}

Step 4: Import IntlProvider and definition file

Next, open the app.js file, which is located in the src/components folder. Then, import the IntlProvider and your definition file to the app.js file:import { IntlProvider } from 'preact-i18n';
import definition from '../i18n/zh-tw.json';

Step 5: Expose the definition via IntlProvider

After that, you will need to expose the definition file to the whole app via <IntlProvider>. By doing this, you will be able to read the definition file everywhere in the app.render() {
return(
<IntlProvider definition={definition}>
<div id="app" />
</IntlProvider>
);
}


At this moment, here's how your app.js file should looks like:import { h, Component } from 'preact';
import { Router } from 'preact-router';
import Header from './header';
import Home from '../routes/home';
import Profile from '../routes/profile';
// Import IntlProvider and the definition file.
import { IntlProvider } from 'preact-i18n';
import definition from '../i18n/zh-tw.json';
export default class App extends Component {

handleRoute = e => {
this.currentUrl = e.url;
};
render() {
return (
// Expose the definition to your whole app via <IntlProvider>
<IntlProvider definition={definition}>
<div id="app">
<Header />
<Router onChange={this.handleRoute}>
<Home path="/" />
<Profile path="/profile/" user="me" />
<Profile path="/profile/:user" />
</Router>
</div>
</IntlProvider>
);
}
}


Step 6: Use Text to translate string literals
 

You are almost done, now you just need to replace the text in the page with <Text>. In this case, you will need to update the content of the home page (src/routes/home/index.js) by adding the <Text> inside the <h1> and <p> tags.
import { Text } from 'preact-i18n';const Home = () => (
<div>
<h1>
<Text id="home.title">Home</Text>
</h1>
<p>
<Text id="home.text">This is the Home component.</Text>
</p>
</div>
);



export default Home;


Fallback Text
 

In order to prevent blank text being rendered in the page, you should set a fallback text to the <Text>. If you didn't include the definition for unknown.definition, the library will render any text contained within <Text>…</Text> as fallback text:
<Text id="unknown.definition">This is a fallback text.</Text>
// It will render this text: "This is a fallback text."

Localizer and MarkupText

If you want to translate the text of the HTML attribute's value (ie: placeholder="", title="", etc …), then you will need to use <Localizer> instead of <Text>.

However, if you want to include HTML markup in your rendered string, then you will need to use <MarkupText>. With this component, your text will be rendered in a <span> tag.

In the example below, you are going to add few more lines of code to your definition file. first_name and last_name will be used for the <Localizer>'s example, and link for the example for <MarkupText>.{
"first_name": "名",
"last_name": "姓",
"link": "這是個<a href='https://www.google.com'>連結</a>"
}


With this, you will able to use <Localizer> and <MarkupText> in the page. Please take note that you need to import Localizer and MarkupText to the src/routes/home/index.js file.import { Text, Localizer, MarkupText } from 'preact-i18n';
const Home = () => (
<div>
<Localizer>
<input placeholder={<Text id="first_name" />} />
</Localizer>
<Localizer>
<input placeholder={<Text id="last_name" />} />
</Localizer>
<MarkupText id="link">
This is a <a href="https://www.google.com">link</a>
</MarkupText>
</div>
);


export default Home;


Templating

If you want to inject a custom string or value into the definition, you could do it with the fields props.

First, you will need to update the definition file with the {{field}} placeholder. The placeholder will get replaced with the matched keys in an object you passed in the fields props.{
"page": "{{count}} / {{total}} 頁"
}

Next, you will need to add the fields attribute together with the value into the <Text />. As a result, your code should looks like this:import { Text } from 'preact-i18n';
const Home = () => (
<div>
<h2>
<Text id="page" fields={{ count: 5, total: 10 }}>
5 / 10 Pages
</Text>
</h2>
</div>
);


export default Home;


Pluralization

With preact-i18n, you have 3 ways to specific the pluralization values:"key": { "singular":"apple", "plural":"apples" }
"key": { "none":"no apples", "one":"apple", "many":"apples" }
"key": ["apples", "apple"]
For the next example, you will combine both pluralization and templating. First, you will need to update the definition file with the code below:
{
"apple": {
"singular": "Henry has {{count}} apple.",
"plural":"Henry has {{count}} apples."
}
}


Next, you will update the home page (src/routes/home/index.js) with the following code:import { Text } from 'preact-i18n';
const Home = () => (
<div>
<p>
<Text id="apple" plural={1} fields={{ count: 1 }} />
</p>
<p>
<Text id="apple" plural={100} fields={{ count: 100 }} />
</p>
</div>
);

export default Home;


With the method above, you will able to add pluralization and templating to your Preact application.

Dynamically import language definition file
In a real-world scenario, you would like to set the language site based on the user's choice, which is either based on the navigator.language or the user can change the site language on their own.

However, in order to prevent you from importing all the unnecessary definition files to the project, you can import the language definition file dynamically by using import(). By doing this, you can import the language definition file based on the user's choice.import { Component } from 'preact';
import { IntlProvider } from 'preact-i18n';
import defaultDefinition from '../i18n/zh-tw.json';
export default class App extends Component {
state = {
definition: defaultDefinition
}
changeLanguage = (lang) => {
// Call this function to change language
import(`../i18n/${lang}.json`)
.then(definition => this.setState({ definition }));
};
render({ }, { definition }) {
return (
<IntlProvider definition={definition}>
<div id="app" />
</IntlProvider>
);
}
}


In this case, you can call the this.changeLanguage('zh-TW') function to change the site language.

Who's using preact-i18n?
I am using preact-i18n for my side project: Remote for Slides.

Remote for Slides is a Progressive Web App + Chrome Extension that allows the user to control their Google Slides on any device, remotely, without the need of any extra hardware.

Remote for Slides Progressive Web App supports more than 8 languages, which includes: Català, English, Español, Euskera, Français, Polski, Traditional Chinese, and Simplified Chinese.

PS: if you looking for website design in Auckland, NZ. just leave a message to us.

In this side project, I am using the "dynamically import language definition file" method I mentioned earlier. This could prevent the web app from loading some unnecessary definition language files, thus this will improve the page performance.
  view all
Hi ,I am john, a developer from website design in Auckland, NZ company local fern.
 In this article, you are going to use the preact-i18n library to add internationalization to your Preact application.

Step 1: Setup Preact CLI & Create new project

Side Note: If you are already familiar with Preact, you may skip to the next step.

If you haven't installed the Preact CLI on your machine, use the following command to install the CLI. Make sure you have Node.js 6.x or above installed.
$ npm install -g preact-cli


Once the Preact CLI is installed, let's create a new project using the default template, and call it my-project.
$ preact create default my-project


Start the development server with the command below:
$ cd my-project && npm run start


Now, open your browser and go to http://localhost:8080, and you should see something like this on your screen:



Step 2: Add preact-i18n library
Install the preact-i18n library to your project using the command below:

$ npm install --save preact-i18n

preact-i18n is very easy to use, and most importantly, it's extremely small, around 1.3kb after gzipped. You can learn more about the library here: https://github.com/synacor/preact-i18n

Step 3: Create a definition file
Once you have the library installed, you will need to create a definition file, which you will store all the translate strings in a JSON file. 

In this case, you will need to save this file in src/i18n/zh-tw.json:
{ 
"home": {
"title": "主頁",
"text": "這是個Home組件。"
}
}


Step 4: Import IntlProvider and definition file

Next, open the app.js file, which is located in the src/components folder. Then, import the IntlProvider and your definition file to the app.js file:
import { IntlProvider } from 'preact-i18n';
import definition from '../i18n/zh-tw.json';


Step 5: Expose the definition via IntlProvider

After that, you will need to expose the definition file to the whole app via <IntlProvider>. By doing this, you will be able to read the definition file everywhere in the app.
render() {
return(
<IntlProvider definition={definition}>
<div id="app" />
</IntlProvider>
);
}



At this moment, here's how your app.js file should looks like:
import { h, Component } from 'preact';
import { Router } from 'preact-router';
import Header from './header';
import Home from '../routes/home';
import Profile from '../routes/profile';
// Import IntlProvider and the definition file.
import { IntlProvider } from 'preact-i18n';
import definition from '../i18n/zh-tw.json';
export default class App extends Component {

handleRoute = e => {
this.currentUrl = e.url;
};
render() {
return (
// Expose the definition to your whole app via <IntlProvider>
<IntlProvider definition={definition}>
<div id="app">
<Header />
<Router onChange={this.handleRoute}>
<Home path="/" />
<Profile path="/profile/" user="me" />
<Profile path="/profile/:user" />
</Router>
</div>
</IntlProvider>
);
}
}



Step 6: Use Text to translate string literals
 

You are almost done, now you just need to replace the text in the page with <Text>. In this case, you will need to update the content of the home page (src/routes/home/index.js) by adding the <Text> inside the <h1> and <p> tags.
import { Text } from 'preact-i18n';
const Home = () => ( 
<div>
<h1>
<Text id="home.title">Home</Text>
</h1>
<p>
<Text id="home.text">This is the Home component.</Text>
</p>
</div>
);




export default Home;


Fallback Text
 

In order to prevent blank text being rendered in the page, you should set a fallback text to the <Text>. If you didn't include the definition for unknown.definition, the library will render any text contained within <Text>…</Text> as fallback text:
<Text id="unknown.definition">This is a fallback text.</Text>
// It will render this text: "This is a fallback text."


Localizer and MarkupText

If you want to translate the text of the HTML attribute's value (ie: placeholder="", title="", etc …), then you will need to use <Localizer> instead of <Text>.

However, if you want to include HTML markup in your rendered string, then you will need to use <MarkupText>. With this component, your text will be rendered in a <span> tag.

In the example below, you are going to add few more lines of code to your definition file. first_name and last_name will be used for the <Localizer>'s example, and link for the example for <MarkupText>.
{ 
"first_name": "名",
"last_name": "姓",
"link": "這是個<a href='https://www.google.com'>連結</a>"
}



With this, you will able to use <Localizer> and <MarkupText> in the page. Please take note that you need to import Localizer and MarkupText to the src/routes/home/index.js file.
import { Text, Localizer, MarkupText } from 'preact-i18n';
const Home = () => (
<div>
<Localizer>
<input placeholder={<Text id="first_name" />} />
</Localizer>
<Localizer>
<input placeholder={<Text id="last_name" />} />
</Localizer>
<MarkupText id="link">
This is a <a href="https://www.google.com">link</a>
</MarkupText>
</div>
);



export default Home;


Templating

If you want to inject a custom string or value into the definition, you could do it with the fields props.

First, you will need to update the definition file with the {{field}} placeholder. The placeholder will get replaced with the matched keys in an object you passed in the fields props.
{
"page": "{{count}} / {{total}} 頁"
}


Next, you will need to add the fields attribute together with the value into the <Text />. As a result, your code should looks like this:
import { Text } from 'preact-i18n'; 
const Home = () => (
<div>
<h2>
<Text id="page" fields={{ count: 5, total: 10 }}>
5 / 10 Pages
</Text>
</h2>
</div>
);



export default Home;


Pluralization

With preact-i18n, you have 3 ways to specific the pluralization values:
"key": { "singular":"apple", "plural":"apples" }
"key": { "none":"no apples", "one":"apple", "many":"apples" }
"key": ["apples", "apple"]
For the next example, you will combine both pluralization and templating. First, you will need to update the definition file with the code below:
{
"apple": {
"singular": "Henry has {{count}} apple.",
"plural":"Henry has {{count}} apples."
}
}



Next, you will update the home page (src/routes/home/index.js) with the following code:
import { Text } from 'preact-i18n'; 
const Home = () => (
<div>
<p>
<Text id="apple" plural={1} fields={{ count: 1 }} />
</p>
<p>
<Text id="apple" plural={100} fields={{ count: 100 }} />
</p>
</div>
);


export default Home;


With the method above, you will able to add pluralization and templating to your Preact application.

Dynamically import language definition file
In a real-world scenario, you would like to set the language site based on the user's choice, which is either based on the navigator.language or the user can change the site language on their own.

However, in order to prevent you from importing all the unnecessary definition files to the project, you can import the language definition file dynamically by using import(). By doing this, you can import the language definition file based on the user's choice.
import { Component } from 'preact'; 
import { IntlProvider } from 'preact-i18n';
import defaultDefinition from '../i18n/zh-tw.json';
export default class App extends Component {
state = {
definition: defaultDefinition
}
changeLanguage = (lang) => {
// Call this function to change language
import(`../i18n/${lang}.json`)
.then(definition => this.setState({ definition }));
};
render({ }, { definition }) {
return (
<IntlProvider definition={definition}>
<div id="app" />
</IntlProvider>
);
}
}



In this case, you can call the this.changeLanguage('zh-TW') function to change the site language.

Who's using preact-i18n?
I am using preact-i18n for my side project: Remote for Slides.

Remote for Slides is a Progressive Web App + Chrome Extension that allows the user to control their Google Slides on any device, remotely, without the need of any extra hardware.

Remote for Slides Progressive Web App supports more than 8 languages, which includes: Català, English, Español, Euskera, Français, Polski, Traditional Chinese, and Simplified Chinese.

PS: if you looking for website design in Auckland, NZ. just leave a message to us.

In this side project, I am using the "dynamically import language definition file" method I mentioned earlier. This could prevent the web app from loading some unnecessary definition language files, thus this will improve the page performance.
 
539
views

奥克兰软件开发公司|我们的前端开发工程师John分享如何让如何國際化(i18n)您的网站,多语言的网站可以让新西兰西人和华人都能找得到

Marketplacefull stack developer Kevin wrote the post • 0 comments • 539 views • 2020-04-06 09:59 • added this tag no more than 24h

大家好,奥克兰软件开发公司local fern的前端开发工程师John~,在这篇文章中,我们将会使用preact-i18n来国际化您的react项目。多语言的网站可以让新西兰西人和华人都能找得到

步骤 1:设置Preact CLI, 并创建一个新的项目

注: 如果您已经熟悉Preact了,您可以跳到下一步。

如果您还没有将Preact CLI安装到您的电脑,请使用以下的命令来安装Preact CLI。这CLI需要Node.js 版本 6.x 或以上。$ npm install -g preact-cli

当您已经成功将Preact CLI安装到您的电脑中,我们将会使用以下的命令来创建一个名为my-project的项目。在这个项目中,我们将会使用default模板。$ preact create default my-project

之后呢,您可以使用以下的命令来启动本地测试服务器。$ cd my-project && npm run start

这个时候,我们需要打开我们的游览器,并前往http://localhost:8080, 你将会看到像这样类似的画面:




步骤 2:安装preact-18n

我们将会使用以下的命令来安装preact-i18n到您的项目中。$ npm install --save preact-i18n

preact-i18n是非常容易使用的。更重要的是, 这preact-i18n在gzip之后才占据不到1.3kb的大小。

步骤 3:创建definition文件

当你已将preact-i18n安装到您的项目之后,我们将会创建一个definition文件。我们将会把我们要翻译的文字和句子,储存在这个JSON文件中。

我们将会把这个definition文件储存在src/i18n/zh-tw.json。{
\"home\": {
\"title\": \"主页\",
\"text\": \"这是个Home组件。\"
}
}


步骤 4:导入IntlProvider及definition文件

接下来,我们将会从src/components中打开app.js。我们将会在这个文件中导入IntlProvider及definition文件。import { IntlProvider } from \'preact-i18n\';
import definition from \'../i18n/zh-tw.json\';


步骤 5:把IntlProvider放在项目中最高层级的组件

然后呢,我们将会在把<IntlProvider>放在项目中最高层级的组件,也就是我们的app.js。这样子,我们就能在这Preact项目中的任何一个组件中读取到definition文件。render() {
return(
<IntlProvider definition={definition}>
<div id=\"app\" />
</IntlProvider>
);
}


在这个时候,您的app.js文件的内容应该是要跟以下的例子类似:import { h, Component } from \'preact\';
import { Router } from \'preact-router\';
import Header from \'./header\';
import Home from \'../routes/home\';
import Profile from \'../routes/profile\';
// 导入 IntlProvider 及 definition 文件。
import { IntlProvider } from \'preact-i18n\';
import definition from \'../i18n/zh-tw.json\';
export default class App extends Component {

handleRoute = e => {
this.currentUrl = e.url;
};
render() {
return (
// 把 <IntlProvider> 放在项目中最高层级的组件
<IntlProvider definition={definition}>
<div id=\"app\">
<Header />
<Router onChange={this.handleRoute}>
<Home path=\"/\" />
<Profile path=\"/profile/\" user=\"me\" />
<Profile path=\"/profile/:user\" />
</Router>
</div>
</IntlProvider>
);
}
}



步骤 6:使用Text来显示翻译字符串文字
 

我们只差一步就成功了。在以下的例子中,我们将会翻译主页(src/routes/home/index.js)中所有的文字。现在,我们只需要把网页中的字改成<Text>。因此,我们将会把<Text>添加进<h1>和<p>里。import { Text } from \'preact-i18n\';
const Home = () => (
<div>
<h1>
<Text id=\"home.title\">Home</Text>
</h1>
<p>
<Text id=\"home.text\">This is the Home component.</Text>
</p>
</div>
);
export default Home;





 
 

后备文字
 

为了避免网页中出现空白,我们应该在<Text>中输入后备文字。 如果preact-i18n无法在您的definition中找到相关的文字或句子,那preact-i18n将会使用你刚才在 <Text>…</Text>输入的后备文字。<Text id=\"unknown.definition\">This is a fallback text.</Text>

// 这将会渲染: \"This is a fallback text.\"
Localizer 和 MarkupText
如果您是想要翻译HTML属性中的文字 (比如说 placeholder=\"\"或是title=\"\"等等),您应该使用<Localizer>,而并不是使用<Text>。

相反的,如果您是想要在您的翻译的文字或句子中使用HTML Markup, 您必须使用<MarkupText>。<MarkupText>将会把已翻译好的文字或句子渲染在一个<span>tag中。

在以下的例子中,我们将会在我们的definition文件中添加多几行的代码。first_name及last_name,将会使用在<Localizer>中的例子。 而我们会在<MarkupText>中的例子使用link。{
\"first_name\": \"名\",
\"last_name\": \"姓\",
\"link\": \"这是个<a href=\'https://www.google.com\'>连结</a>\"
}
在你更新主页(src/routes/home/index.js)中的内容之前,记得将Localizer和MarkupText导入到该页中:import { Text, Localizer, MarkupText } from \'preact-i18n\';
const Home = () => (
<div>
<Localizer>
<input placeholder={<Text id=\"first_name\" />} />
</Localizer>
<Localizer>
<input placeholder={<Text id=\"last_name\" />} />
</Localizer>
<MarkupText id=\"link\">
This is a <a href=\"https://www.google.com\">link</a>
</MarkupText>
</div>
);
export default Home;




模板 (Templating)
 

如果您想要在您的definition中注入一些自定义的字符串,您可以使用fields属性来实现。

首先呢,我们需要先更新我们的definition文件。在我们的definition文件中,我们需要将我们要被自定义的字符串替代的文字,更改成像{{count}}或者是{{total}}这样子的占位符。
{
  \"page\": \"{{count}} / {{total}} 页\"
}
之后呢,我们需要在我们的<Text />中加入fields属性。因此,您的代码应如下所示:import { Text } from \'preact-i18n\';
const Home = () => (
<div>
<h2>
<Text id=\"page\" fields={{ count: 5, total: 10 }}>
5 / 10 Pages
</Text>
</h2>
</div>
);
export default Home;






 
 

 
复数 (Pluralization)

如果您要翻译的语言有复数的话(比如说像英文:apple / apples),您可以使用以下其中一个方法,来把已翻译好的文字和句子放进您的definition文件里。

\"key\": { \"singular\":\"apple\", \"plural\":\"apples\" }
\"key\": { \"none\":\"no apples\", \"one\":\"apple\", \"many\":\"apples\" }
\"key\": [\"apples\", \"apple\"]
在以下的例子中,我们将会把模板和复数的例子结合在一起。但在那之前,我们需要更新我们的definition文件:{
\"apple\": {
\"singular\": \"Henry has {{count}} apple.\",
\"plural\":\"Henry has {{count}} apples.\"
}
}

接着,我们将会把以下的代码粘贴到src/routes/home/index.js中:import { Text } from \'preact-i18n\';
const Home = () => (
<div>
<p>
<Text id=\"apple\" plural={1} fields={{ count: 1 }} />
</p>
<p>
<Text id=\"apple\" plural={100} fields={{ count: 100 }} />
</p>
</div>
);
export default Home;





 

 
 根据以上的步骤,你就能在您的Preact项目中使用模板和复数。

动态导入definition文件
在现实情况中,您将会根据用户的选择来设定网页的语言。

您可以使用游览器的语言(通过navigator.language), 或者是让用户自己手动更换语言。

然而,为了避免我们将不必要的definition文件导入进去,我们可以使用import()来实现动态导入definition文件。这样一来,我们只会导入用户所选择的语言所需要的definition文件。import { Component } from \'preact\';
import { IntlProvider } from \'preact-i18n\';
import defaultDefinition from \'../i18n/zh-tw.json\';
export default class App extends Component {
state = {
definition: defaultDefinition
}
changeLanguage = (lang) => {
// 我们可以使用这个函数来更换语言
import(`../i18n/${lang}.json`)
.then(definition => this.setState({ definition }));
};
render({ }, { definition }) {
return (
<IntlProvider definition={definition}>
<div id=\"app\" />
</IntlProvider>
);
}
}


根据以上的例子,我们可以使用这函数:this.changeLanguage(\"zh-TW\") 来导入definition文件并更改网页的语言。

谁在使用preact-i18n?
我自己的业余项目: Remote for Slides,正在使用着preact-i18n。

Remote for Slides是一个渐进式网络应用程序(PWA) + Chrome 扩充器。这能让用户在任何设备上,远程遥控Google简报。是时候跟昂贵的翻页笔说再见了。

Remote for Slides 渐进式网络应用程序支持多达8个语言,包括了英文、繁体中文、简体中文、加泰罗尼亚文、西班牙文、 法文、波兰文、以及Euskera。

在这个项目中,我也使用了我在刚才提到的 \"动态导入definition文件\" 的方法。这可以避免应用程序导入一些没使用到的definition文件。这将会提升应用程序性能。

除此之外,Remote for Slides 渐进式网络应用程序也将会自动地设置语言。这应用程序将会根据游览器的语言(navigator.language)、或者是根据URL中的parameter (ie: s.limhenry.xyz/?hl=zh-tw)来更改语言。 当然,用户也可以从设置中更改语言。
 

  view all
大家好,奥克兰软件开发公司local fern的前端开发工程师John~,在这篇文章中,我们将会使用preact-i18n来国际化您的react项目。多语言的网站可以让新西兰西人和华人都能找得到

步骤 1:设置Preact CLI, 并创建一个新的项目

注: 如果您已经熟悉Preact了,您可以跳到下一步。

如果您还没有将Preact CLI安装到您的电脑,请使用以下的命令来安装Preact CLI。这CLI需要Node.js 版本 6.x 或以上。
$ npm install -g preact-cli


当您已经成功将Preact CLI安装到您的电脑中,我们将会使用以下的命令来创建一个名为my-project的项目。在这个项目中,我们将会使用default模板。
$ preact create default my-project


之后呢,您可以使用以下的命令来启动本地测试服务器。
$ cd my-project && npm run start


这个时候,我们需要打开我们的游览器,并前往http://localhost:8080, 你将会看到像这样类似的画面:




步骤 2:安装preact-18n

我们将会使用以下的命令来安装preact-i18n到您的项目中。
$ npm install --save preact-i18n


preact-i18n是非常容易使用的。更重要的是, 这preact-i18n在gzip之后才占据不到1.3kb的大小。

步骤 3:创建definition文件

当你已将preact-i18n安装到您的项目之后,我们将会创建一个definition文件。我们将会把我们要翻译的文字和句子,储存在这个JSON文件中。

我们将会把这个definition文件储存在src/i18n/zh-tw.json。
{ 
\"home\": {
\"title\": \"主页\",
\"text\": \"这是个Home组件。\"
}
}



步骤 4:导入IntlProvider及definition文件

接下来,我们将会从src/components中打开app.js。我们将会在这个文件中导入IntlProvider及definition文件。
import { IntlProvider } from \'preact-i18n\';
import definition from \'../i18n/zh-tw.json\';



步骤 5:把IntlProvider放在项目中最高层级的组件

然后呢,我们将会在把<IntlProvider>放在项目中最高层级的组件,也就是我们的app.js。这样子,我们就能在这Preact项目中的任何一个组件中读取到definition文件。
render() {
return(
<IntlProvider definition={definition}>
<div id=\"app\" />
</IntlProvider>
);
}



在这个时候,您的app.js文件的内容应该是要跟以下的例子类似:
import { h, Component } from \'preact\';
import { Router } from \'preact-router\';
import Header from \'./header\';
import Home from \'../routes/home\';
import Profile from \'../routes/profile\';
// 导入 IntlProvider 及 definition 文件。
import { IntlProvider } from \'preact-i18n\';
import definition from \'../i18n/zh-tw.json\';
export default class App extends Component {

handleRoute = e => {
this.currentUrl = e.url;
};
render() {
return (
// 把 <IntlProvider> 放在项目中最高层级的组件
<IntlProvider definition={definition}>
<div id=\"app\">
<Header />
<Router onChange={this.handleRoute}>
<Home path=\"/\" />
<Profile path=\"/profile/\" user=\"me\" />
<Profile path=\"/profile/:user\" />
</Router>
</div>
</IntlProvider>
);
}
}




步骤 6:使用Text来显示翻译字符串文字
 

我们只差一步就成功了。在以下的例子中,我们将会翻译主页(src/routes/home/index.js)中所有的文字。现在,我们只需要把网页中的字改成<Text>。因此,我们将会把<Text>添加进<h1>和<p>里。
import { Text } from \'preact-i18n\';
const Home = () => (
<div>
<h1>
<Text id=\"home.title\">Home</Text>
</h1>
<p>
<Text id=\"home.text\">This is the Home component.</Text>
</p>
</div>
);
export default Home;





 
 

后备文字
 

为了避免网页中出现空白,我们应该在<Text>中输入后备文字。 如果preact-i18n无法在您的definition中找到相关的文字或句子,那preact-i18n将会使用你刚才在 <Text>…</Text>输入的后备文字。
<Text id=\"unknown.definition\">This is a fallback text.</Text>


// 这将会渲染: \"This is a fallback text.\"
Localizer 和 MarkupText
如果您是想要翻译HTML属性中的文字 (比如说 placeholder=\"\"或是title=\"\"等等),您应该使用<Localizer>,而并不是使用<Text>。

相反的,如果您是想要在您的翻译的文字或句子中使用HTML Markup, 您必须使用<MarkupText>。<MarkupText>将会把已翻译好的文字或句子渲染在一个<span>tag中。

在以下的例子中,我们将会在我们的definition文件中添加多几行的代码。first_name及last_name,将会使用在<Localizer>中的例子。 而我们会在<MarkupText>中的例子使用link。
{ 
\"first_name\": \"名\",
\"last_name\": \"姓\",
\"link\": \"这是个<a href=\'https://www.google.com\'>连结</a>\"
}

在你更新主页(src/routes/home/index.js)中的内容之前,记得将Localizer和MarkupText导入到该页中:
import { Text, Localizer, MarkupText } from \'preact-i18n\';
const Home = () => (
<div>
<Localizer>
<input placeholder={<Text id=\"first_name\" />} />
</Localizer>
<Localizer>
<input placeholder={<Text id=\"last_name\" />} />
</Localizer>
<MarkupText id=\"link\">
This is a <a href=\"https://www.google.com\">link</a>
</MarkupText>
</div>
);
export default Home;





模板 (Templating)
 

如果您想要在您的definition中注入一些自定义的字符串,您可以使用fields属性来实现。

首先呢,我们需要先更新我们的definition文件。在我们的definition文件中,我们需要将我们要被自定义的字符串替代的文字,更改成像{{count}}或者是{{total}}这样子的占位符。
{
  \"page\": \"{{count}} / {{total}} 页\"
}
之后呢,我们需要在我们的<Text />中加入fields属性。因此,您的代码应如下所示:
import { Text } from \'preact-i18n\'; 
const Home = () => (
<div>
<h2>
<Text id=\"page\" fields={{ count: 5, total: 10 }}>
5 / 10 Pages
</Text>
</h2>
</div>
);
export default Home;






 
 

 
复数 (Pluralization)

如果您要翻译的语言有复数的话(比如说像英文:apple / apples),您可以使用以下其中一个方法,来把已翻译好的文字和句子放进您的definition文件里。

\"key\": { \"singular\":\"apple\", \"plural\":\"apples\" }
\"key\": { \"none\":\"no apples\", \"one\":\"apple\", \"many\":\"apples\" }
\"key\": [\"apples\", \"apple\"]
在以下的例子中,我们将会把模板和复数的例子结合在一起。但在那之前,我们需要更新我们的definition文件:
{
\"apple\": {
\"singular\": \"Henry has {{count}} apple.\",
\"plural\":\"Henry has {{count}} apples.\"
}
}


接着,我们将会把以下的代码粘贴到src/routes/home/index.js中:
import { Text } from \'preact-i18n\'; 
const Home = () => (
<div>
<p>
<Text id=\"apple\" plural={1} fields={{ count: 1 }} />
</p>
<p>
<Text id=\"apple\" plural={100} fields={{ count: 100 }} />
</p>
</div>
);
export default Home;





 

 
 根据以上的步骤,你就能在您的Preact项目中使用模板和复数。

动态导入definition文件
在现实情况中,您将会根据用户的选择来设定网页的语言。

您可以使用游览器的语言(通过navigator.language), 或者是让用户自己手动更换语言。

然而,为了避免我们将不必要的definition文件导入进去,我们可以使用import()来实现动态导入definition文件。这样一来,我们只会导入用户所选择的语言所需要的definition文件。
import { Component } from \'preact\'; 
import { IntlProvider } from \'preact-i18n\';
import defaultDefinition from \'../i18n/zh-tw.json\';
export default class App extends Component {
state = {
definition: defaultDefinition
}
changeLanguage = (lang) => {
// 我们可以使用这个函数来更换语言
import(`../i18n/${lang}.json`)
.then(definition => this.setState({ definition }));
};
render({ }, { definition }) {
return (
<IntlProvider definition={definition}>
<div id=\"app\" />
</IntlProvider>
);
}
}



根据以上的例子,我们可以使用这函数:this.changeLanguage(\"zh-TW\") 来导入definition文件并更改网页的语言。

谁在使用preact-i18n?
我自己的业余项目: Remote for Slides,正在使用着preact-i18n。

Remote for Slides是一个渐进式网络应用程序(PWA) + Chrome 扩充器。这能让用户在任何设备上,远程遥控Google简报。是时候跟昂贵的翻页笔说再见了。

Remote for Slides 渐进式网络应用程序支持多达8个语言,包括了英文、繁体中文、简体中文、加泰罗尼亚文、西班牙文、 法文、波兰文、以及Euskera。

在这个项目中,我也使用了我在刚才提到的 \"动态导入definition文件\" 的方法。这可以避免应用程序导入一些没使用到的definition文件。这将会提升应用程序性能。

除此之外,Remote for Slides 渐进式网络应用程序也将会自动地设置语言。这应用程序将会根据游览器的语言(navigator.language)、或者是根据URL中的parameter (ie: s.limhenry.xyz/?hl=zh-tw)来更改语言。 当然,用户也可以从设置中更改语言。
 

 
521
views

奥克兰网站建设公司|我们的developer Kevin分享如何让网站搭配最适合的字体,一键查看不同的字体组合在不同的网站主题模板上的外观

Marketplacefull stack developer Kevin wrote the post • 0 comments • 521 views • 2020-04-06 09:34 • added this tag no more than 24h

大家好,奥克兰网站建设公司local fern的developer Kevin~,做设计一定会用到字体,我们在用ps、sketch做网站、手机端、iPad端设计的时候,经常会选择不同的字体来看设计稿的呈现效果。

今天推荐的这个网站,可以一键查看不同的字体组合在不同的网站主题模板上的外观,让我们更直观的看到网站、手机端、iPad端显示的字体效果。

FontPairings.ByPeople
网站地址:https://fontpairings.bypeople.com



打开网站加载完字体资源以后,我们点击一下进入网站,可以看到左侧就是操作区,最直观的是可以直接选择提供的字体,然后右侧会显示出不同的字体效果。



左侧最顶部有一个选择网站主题模板的入口,我们可以不同的网站模板风格来搭配不同的字体,效果还不错噢。



网站模板的下面可以选择不同的设备,这里提供了手机、iPad、电脑端,可以选择不同的设备查看对应的效果,同时也提供了设置大标题的字体大小以及正文中的文字大小。



设备的下面我们可以选择大标题的字体样式和正文中的字体样式,提供的字体样式都是英文字体,种类也非常多。



如果你觉得哪个字体很不错,可以直接点击左侧底部的Download Fonts即可免费下载对应的字体资源,非常方便。



如果选好了网站模板、字体样式想全屏预览一下网站的效果,点击一下顶部的叉号图标即可全屏查看设置的效果。



最后

今天的内容就是这些,下期再见 view all
大家好,奥克兰网站建设公司local fern的developer Kevin~,做设计一定会用到字体,我们在用ps、sketch做网站、手机端、iPad端设计的时候,经常会选择不同的字体来看设计稿的呈现效果。

今天推荐的这个网站,可以一键查看不同的字体组合在不同的网站主题模板上的外观,让我们更直观的看到网站、手机端、iPad端显示的字体效果。

FontPairings.ByPeople
网站地址:https://fontpairings.bypeople.com



打开网站加载完字体资源以后,我们点击一下进入网站,可以看到左侧就是操作区,最直观的是可以直接选择提供的字体,然后右侧会显示出不同的字体效果。



左侧最顶部有一个选择网站主题模板的入口,我们可以不同的网站模板风格来搭配不同的字体,效果还不错噢。



网站模板的下面可以选择不同的设备,这里提供了手机、iPad、电脑端,可以选择不同的设备查看对应的效果,同时也提供了设置大标题的字体大小以及正文中的文字大小。



设备的下面我们可以选择大标题的字体样式和正文中的字体样式,提供的字体样式都是英文字体,种类也非常多。



如果你觉得哪个字体很不错,可以直接点击左侧底部的Download Fonts即可免费下载对应的字体资源,非常方便。



如果选好了网站模板、字体样式想全屏预览一下网站的效果,点击一下顶部的叉号图标即可全屏查看设置的效果。



最后

今天的内容就是这些,下期再见
614
views

奥克兰广告设计公司|我们的插画师Isabella分享日常工作常用的免费插画素材网站,可以免费用到自己的项目中,而且没有版权限制

Marketplacefull stack developer Kevin wrote the post • 0 comments • 614 views • 2020-04-06 09:22 • added this tag no more than 24h

大家好,奥克兰广告设计公司local fern插画师Isabella,今天推荐一个超多完全可自定义的免费插画素材网站,插画素材的格式有SVG和PNG两种格式,我们可以免费用到自己的项目中,而且没有版权限制。

这个网站其实不止有插画素材,还有网站模板、图标、图形、品牌推广等素材内容。

Delesign
网站地址:https://delesign.com/free-designs/graphics/



打开网站可以看默认显示的就是插画素材,输入Email地址可以订阅此网站,及时获取更新的设计内容,包含网站模板、社交媒体、图形插画等等。



我们可以点击右侧的选择颜色,自定义色值来确定插画的主色调,一旦我们确定了色值,整个网站的插画素材颜色都会改变,最终确定一个符合我们网站或移动端应用产品的颜色插画。



我们把鼠标移动到对应的插画素材上即可显示出下载入口,它支持SVG和PNG两种格式,同时插画左侧顶部会显示此插画的类别。



我们也可以直接点击选中的插画,弹框弹出显示此插画的大图,也同样提供了SVG和PNG两种格式,顶部显示插画的类别。



网站上的插画素材质量还不错,覆盖了很多类型的插画,插画人物有男有女有团队,还有物件、动物等类别。



我们也可以点击右侧的搜索入口,搜索你想要的种类,搜索出的内容除了插画素材可能还会包含网站模板、图示、品牌推广等内容。



点击一个网站模板,可以下载网站模板对应的源文件(psd或AI文件)以及源码,有的网站模板源码还在开发,提供一个邮箱会及时通知。

最后
今天的内容就分享到这里,如果你准备做一个设计,记得找我哦。 view all
大家好,奥克兰广告设计公司local fern插画师Isabella,今天推荐一个超多完全可自定义的免费插画素材网站,插画素材的格式有SVG和PNG两种格式,我们可以免费用到自己的项目中,而且没有版权限制。

这个网站其实不止有插画素材,还有网站模板、图标、图形、品牌推广等素材内容。


Delesign
网站地址:https://delesign.com/free-designs/graphics/



打开网站可以看默认显示的就是插画素材,输入Email地址可以订阅此网站,及时获取更新的设计内容,包含网站模板、社交媒体、图形插画等等。



我们可以点击右侧的选择颜色,自定义色值来确定插画的主色调,一旦我们确定了色值,整个网站的插画素材颜色都会改变,最终确定一个符合我们网站或移动端应用产品的颜色插画。



我们把鼠标移动到对应的插画素材上即可显示出下载入口,它支持SVG和PNG两种格式,同时插画左侧顶部会显示此插画的类别。



我们也可以直接点击选中的插画,弹框弹出显示此插画的大图,也同样提供了SVG和PNG两种格式,顶部显示插画的类别。



网站上的插画素材质量还不错,覆盖了很多类型的插画,插画人物有男有女有团队,还有物件、动物等类别。



我们也可以点击右侧的搜索入口,搜索你想要的种类,搜索出的内容除了插画素材可能还会包含网站模板、图示、品牌推广等内容。



点击一个网站模板,可以下载网站模板对应的源文件(psd或AI文件)以及源码,有的网站模板源码还在开发,提供一个邮箱会及时通知。

最后
今天的内容就分享到这里,如果你准备做一个设计,记得找我哦。
561
views

奥克兰广告设计公司|我们的插画师Isabella分享如何快速制作样机,只需要上传准备好的图片或视频即可在不同的设备上生成渲染后的高逼格作品

Marketplacefull stack developer Kevin wrote the post • 0 comments • 561 views • 2020-04-06 03:01 • added this tag no more than 24h

大家好,我是奥克兰local fern公司的插画师Isabella~今天给大家推荐一个高逼格样机工具MokupFrames,它是一款可以快速制作样机的客户端工具,支持Windows/Mac,只需要上传准备好的图片或视频即可在不同的设备上生成渲染后的高逼格作品,提供的设备类型有iPhone、Android、PC&Web,真是相当好用。


MokupFrames

网址:https://www.mokupframes.com

打开网站,可以看到样机展示的效果视频,上传图片或视频它可以一键创建令人赞叹的作品和视频。

只需要三步即可生成gif或视频,点击DownLoad进入下载客户端工具的页面,支持Windows和Mac平台。

下载安装完成后打开下载好的样机客户端,任意选择一个视频或图片即可看到渲染好的样机作品,这里提供了多种不同角度的样机素材,iPhone提供了主流的机型完全够用。

选择好一个样机模型后,我们可以修改样机的背景颜色,这里它提供了几种默认的渐变色,同时也可以去掉背景色,又或者选择一张图片来作为样机背景。

右侧提供了一些参数可以调整,选择了视频则可以导出MP4、MOV、GiF格式,选择图片默认导出的是PNG格式,同时还可以修改样机的颜色,不同的样机类型提供的颜色不一样,这里提供了三种灰、黑、白。

除了上面我们提到的可以修改默认的颜色以外,它还可以自己修改色值,调整样机的翻转方向以及图片适合的尺寸。

接着是Android的样机素材,这里提供了一些主流的机型,比如我选择一个一加的Android机型。

最后是PC&Web的样机素材,这里提供了Chrome、Safari浏览器以及Windows和Mac电脑的机型,这里我选择一个Safari的浏览器。

这里我又选择了一个iMac的机型,大家可以看到样机的效果,非常好看。

最后这个是MacbookPro的样机效果,最终选择一个满意的样机素材,点击Export导出的时候右侧给出了三种尺寸格式,有Dribbble、Instagram或者自定义一个尺寸。

最后

今天的内容就是这些,如果您有店铺需要设计招牌或者别的设计需求,请直接给我们在线留言 view all
大家好,我是奥克兰local fern公司的插画师Isabella~今天给大家推荐一个高逼格样机工具MokupFrames,它是一款可以快速制作样机的客户端工具,支持Windows/Mac,只需要上传准备好的图片或视频即可在不同的设备上生成渲染后的高逼格作品,提供的设备类型有iPhone、Android、PC&Web,真是相当好用。


MokupFrames

网址:https://www.mokupframes.com

打开网站,可以看到样机展示的效果视频,上传图片或视频它可以一键创建令人赞叹的作品和视频。

只需要三步即可生成gif或视频,点击DownLoad进入下载客户端工具的页面,支持Windows和Mac平台。

下载安装完成后打开下载好的样机客户端,任意选择一个视频或图片即可看到渲染好的样机作品,这里提供了多种不同角度的样机素材,iPhone提供了主流的机型完全够用。

选择好一个样机模型后,我们可以修改样机的背景颜色,这里它提供了几种默认的渐变色,同时也可以去掉背景色,又或者选择一张图片来作为样机背景。

右侧提供了一些参数可以调整,选择了视频则可以导出MP4、MOV、GiF格式,选择图片默认导出的是PNG格式,同时还可以修改样机的颜色,不同的样机类型提供的颜色不一样,这里提供了三种灰、黑、白。

除了上面我们提到的可以修改默认的颜色以外,它还可以自己修改色值,调整样机的翻转方向以及图片适合的尺寸。

接着是Android的样机素材,这里提供了一些主流的机型,比如我选择一个一加的Android机型。

最后是PC&Web的样机素材,这里提供了Chrome、Safari浏览器以及Windows和Mac电脑的机型,这里我选择一个Safari的浏览器。

这里我又选择了一个iMac的机型,大家可以看到样机的效果,非常好看。

最后这个是MacbookPro的样机效果,最终选择一个满意的样机素材,点击Export导出的时候右侧给出了三种尺寸格式,有Dribbble、Instagram或者自定义一个尺寸。

最后

今天的内容就是这些,如果您有店铺需要设计招牌或者别的设计需求,请直接给我们在线留言
893
views

ecommerce website design nz|I will design a smart ecommerce logo for website and online store,$20 = 3 Logo concepts +Free Source Vector file+Jpg+Png+3D mock up+Unlimited revisions

MarketplaceMichela F wrote the post • 0 comments • 893 views • 2020-04-06 02:46 • added this tag no more than 24h

 
Hello, Welcome to My this item!

I am Michela F. A Creative Graphic Designer with many years of working Experience, I Prefer High Quality Work.
Here i will Design a Smart ECOMMERCE and WEBSITE LOGO For Your BUSINESS. i will send you all standard files with Reasonable Price.

I will SEND You!

High Quality Logo concepts
Free Source file
Free Vector (Editable) file
Print resolution file
PNG (transparent)
Unlimited Revisions
100% Satisfaction
JPG
SVG
PDF
PSD
AI
EPS
I am Waiting for your order to star working with you! 
 
Check out my portfolios:
 

 
 
  view all

 
Hello, Welcome to My this item!

I am Michela F. A Creative Graphic Designer with many years of working Experience, I Prefer High Quality Work.
Here i will Design a Smart ECOMMERCE and WEBSITE LOGO For Your BUSINESS. i will send you all standard files with Reasonable Price.

I will SEND You!

High Quality Logo concepts
Free Source file
Free Vector (Editable) file
Print resolution file
PNG (transparent)
Unlimited Revisions
100% Satisfaction
JPG
SVG
PDF
PSD
AI
EPS
I am Waiting for your order to star working with you! 
 
Check out my portfolios:
 

 
 
 
466
views

ecommerce website design nz| Install and Configure Magento on your hosting account, $260, Delivery in 3 days.

MarketplaceMichela F wrote the post • 0 comments • 466 views • 2020-04-06 02:42 • added this tag no more than 24h

 

 
What you get with this Item
 
Magento, the most flexible eCommerce platform to power your business


For this Hourlie I will...

1) Install Magento
2) General Magento configuration
3) Install your theme
4) Setup taxes
5) Setup Shipping rules
6) Setup Currency
7) Configure Attributes
8) Configure Attribute sets
9) Configuure store email
10) Configure store postal address
11) Configure payment gateway (Paypal etc)
12) Configure Shipping
13) Setup 5 CMS pages from your content
14) Setup 5 products


Not included in this offer:
Theme, content, images, text, product details and images, hosting
  view all
 

 
What you get with this Item
 
Magento, the most flexible eCommerce platform to power your business


For this Hourlie I will...

1) Install Magento
2) General Magento configuration
3) Install your theme
4) Setup taxes
5) Setup Shipping rules
6) Setup Currency
7) Configure Attributes
8) Configure Attribute sets
9) Configuure store email
10) Configure store postal address
11) Configure payment gateway (Paypal etc)
12) Configure Shipping
13) Setup 5 CMS pages from your content
14) Setup 5 products


Not included in this offer:
Theme, content, images, text, product details and images, hosting
 
445
views

ecommerce website design nz|Design an outstanding eCommerce website for your business, Delivery in 5 days, $590

MarketplaceMichela F wrote the post • 0 comments • 445 views • 2020-04-06 01:50 • added this tag no more than 24h

 
What you get with this item
 
I am a Professional web developer with 13 years of experience. Here I am offering you an professional eCommerce website.This is your chance to have your very own online store designed and built.Expect your website to be completely responsive and to look great on all devices. I can design your site to your specification, which will include the latest technology along with the most up-to-date design. Once built, you have control of the content,Images,Color Theme!

What you will get with this hourlie
-----------------------------------------------

A set of standard options including:

Design and Development of your website
Home page image slider
wooCommerce integration
Payment Gateway integration
Product upload (upto 100)
News posts
Contact form
Social media links (linking to your Facebook, Twitter or Linkedin accounts)
Site search
Google location map
Google Analytics Code Integration
Yoast plugin setup
 
 

  view all

 
What you get with this item
 
I am a Professional web developer with 13 years of experience. Here I am offering you an professional eCommerce website.This is your chance to have your very own online store designed and built.Expect your website to be completely responsive and to look great on all devices. I can design your site to your specification, which will include the latest technology along with the most up-to-date design. Once built, you have control of the content,Images,Color Theme!

What you will get with this hourlie
-----------------------------------------------

A set of standard options including:

Design and Development of your website
Home page image slider
wooCommerce integration
Payment Gateway integration
Product upload (upto 100)
News posts
Contact form
Social media links (linking to your Facebook, Twitter or Linkedin accounts)
Site search
Google location map
Google Analytics Code Integration
Yoast plugin setup
 
 

 
477
views

ecommerce website design nz|I will create ecommerce website with woocommerce, $25, I will install and setup woocommerce on your site . 3 Days Delivery

MarketplaceMichela F wrote the post • 0 comments • 477 views • 2020-04-06 01:45 • added this tag no more than 24h

 
 
 
 
 
 
 
 
 
 
 
About This Service:

Hi Everyone!
In this item, i am offering my services to create awesome ecommerce website.
I will build your online store in Wordpress. I can install and customize any Ecommece theme.
Specially I will :

Install Ecommerce theme
Install Woocommerce plugin
Setting up your basic ecommerce pages
Give 100% responsive layout
Setup different shipping options. 
Setting up payment gateways as per requirements
Contact page with Google Map
and much more . . 

Ecommerce site will have the following features
Open Source Documentation
Product Reviews
Payment gateway integration
Unlimited Products
Order tracking
Ratings Product Variations
Wish list System Social Media
SEO Plugins Installation
Sales Reports
Multiple Currency Options
Input Multiple Tax Rates
Related Products
Shipping Weight Calculation
Discount Coupon System
Unlimited Module Instance
High Security Integration
EBay, Amazon Affiliate system 
Sales Reports
Error Logging
Unlimited Categories

If you want us to install premium theme or plugin in your site you have to provide it or you can pay us for this. Also product uploading is not included in my all 3 packages.


Note : Discuss your website plan before placing any customized order . Thank you!
 
  view all
 
 
 
 
 
 
 
 
 
 
 
About This Service:

Hi Everyone!
In this item, i am offering my services to create awesome ecommerce website.
I will build your online store in Wordpress. I can install and customize any Ecommece theme.
Specially I will :

Install Ecommerce theme
Install Woocommerce plugin
Setting up your basic ecommerce pages
Give 100% responsive layout
Setup different shipping options. 
Setting up payment gateways as per requirements
Contact page with Google Map
and much more . . 

Ecommerce site will have the following features
Open Source Documentation
Product Reviews
Payment gateway integration
Unlimited Products
Order tracking
Ratings Product Variations
Wish list System Social Media
SEO Plugins Installation
Sales Reports
Multiple Currency Options
Input Multiple Tax Rates
Related Products
Shipping Weight Calculation
Discount Coupon System
Unlimited Module Instance
High Security Integration
EBay, Amazon Affiliate system 
Sales Reports
Error Logging
Unlimited Categories

If you want us to install premium theme or plugin in your site you have to provide it or you can pay us for this. Also product uploading is not included in my all 3 packages.


Note : Discuss your website plan before placing any customized order . Thank you!
 
 
714
views

奥克兰广告设计公司|我们的插画师Isabella,分享如何创建漂亮的用户流原型和简约漂亮的思维导图,附带超全的在线流程图和图表制作工具

Marketplacefull stack developer Kevin wrote the post • 0 comments • 714 views • 2020-04-06 01:13 • added this tag no more than 24h

 
 


大家好,我是新西兰软件开发公司local fern的插画师Isabella,~今天给大家推荐几个新发现的流程图和图表制作工具,分别是Creately - 在线图表制作协作平台,Miro - 在线协作式的白板平台,VisualSitemaps - 在几秒钟内自动生成可视站点地图,FlowMapp - 可视站点和用户流程的在线工具,Lucidchart - 在线流程图绘制协作平台,Wireflow - 创建漂亮的用户流原型,Coggle - 简约漂亮的思维导图工具。



Creately
网址:https://creately.com



Creately是一款优秀的绘制产品图形的在线工具,绘制的图形更为丰富,支持UML图、Mindmap图、SWOT图、产品原型图、流程图等等数十种类型。



打开网站,用最简单的方法创建可视化视图,可以看到右侧提供的示例,提供了1000个专业的模板,实现团队和客户无缝协作。



当一个想法在你的脑海中越来越清晰的时候,你想要通过工具画出流程图、思维导图等等,这里提供了默认的主题模板,拖放对应的形状工具即可。



点击立开始绘制即可进入到创建文档的页面,这里提供了工程师、产品、IT、设计师、教育、HR等众多分类,右侧可以选择不同的模板供我们使用。



Miro
网址:https://miro.com



Miro是一个在线协作式的白板平台,在Miro网站上可以立即将数十个手写便笺转换为数字便笺,通过在Miro的协作式白板画布上进行组织和编辑,同时也提供了思维导图、故事版、关系图等模板。



VisualSitemaps
网址:https://visualsitemaps.com



VisualSitemaps在几秒钟内自动生成可视站点地图,只需输入一个URL,即可获得整个网站的基于缩略图的视觉架构,自动生成任何公共或私人网站的精美视觉站点地图+高分辨率屏幕截图。



自动生成漂亮的可视化站点地图,每张页面的截图都是高清分辨率,任何站点或web app都可以使用 VisualSitemaps 进行爬取。

FlowMapp
网址:https://flowmapp.com



FlowMapp是一个可视站点和用户流程的在线工具,是一个网站和APP的前期架构与地图(Sitemap)设计工具,提供网站地图、信息架构、内容架构的设计。

Wireflow
网址:https://flowmapp.com



Wireflow可创建漂亮的用户流原型,是一款免费开源软件,为简化项目计划和集思广益的早期流程而产生。

Coggle
网址:https://coggle.it



化繁为简,Coggle 是一款简约漂亮的思维导图工具,轻量级,需要 Google 账号,可导出 PDF、PNG、TXT 格式,支持多人协作,嵌入网页等等。

Lucidchart
网址:https://www.lucidchart.com



Lucidchart是一个基于Web的绘图软件,允许用户协作和实时携创建流程图、组织结构图、网站线框、UML设计、思维导图、软件原型和许多其他的图表类型。

最后
 
如果您正准备做一个店铺招牌,找不到好的设计师和插画师,记得找我。 view all
 
 


大家好,我是新西兰软件开发公司local fern的插画师Isabella,~今天给大家推荐几个新发现的流程图和图表制作工具,分别是Creately - 在线图表制作协作平台,Miro - 在线协作式的白板平台,VisualSitemaps - 在几秒钟内自动生成可视站点地图,FlowMapp - 可视站点和用户流程的在线工具,Lucidchart - 在线流程图绘制协作平台,Wireflow - 创建漂亮的用户流原型,Coggle - 简约漂亮的思维导图工具。



Creately
网址:https://creately.com



Creately是一款优秀的绘制产品图形的在线工具,绘制的图形更为丰富,支持UML图、Mindmap图、SWOT图、产品原型图、流程图等等数十种类型。



打开网站,用最简单的方法创建可视化视图,可以看到右侧提供的示例,提供了1000个专业的模板,实现团队和客户无缝协作。



当一个想法在你的脑海中越来越清晰的时候,你想要通过工具画出流程图、思维导图等等,这里提供了默认的主题模板,拖放对应的形状工具即可。



点击立开始绘制即可进入到创建文档的页面,这里提供了工程师、产品、IT、设计师、教育、HR等众多分类,右侧可以选择不同的模板供我们使用。



Miro
网址:https://miro.com



Miro是一个在线协作式的白板平台,在Miro网站上可以立即将数十个手写便笺转换为数字便笺,通过在Miro的协作式白板画布上进行组织和编辑,同时也提供了思维导图、故事版、关系图等模板。



VisualSitemaps
网址:https://visualsitemaps.com



VisualSitemaps在几秒钟内自动生成可视站点地图,只需输入一个URL,即可获得整个网站的基于缩略图的视觉架构,自动生成任何公共或私人网站的精美视觉站点地图+高分辨率屏幕截图。



自动生成漂亮的可视化站点地图,每张页面的截图都是高清分辨率,任何站点或web app都可以使用 VisualSitemaps 进行爬取。

FlowMapp
网址:https://flowmapp.com



FlowMapp是一个可视站点和用户流程的在线工具,是一个网站和APP的前期架构与地图(Sitemap)设计工具,提供网站地图、信息架构、内容架构的设计。

Wireflow
网址:https://flowmapp.com



Wireflow可创建漂亮的用户流原型,是一款免费开源软件,为简化项目计划和集思广益的早期流程而产生。

Coggle
网址:https://coggle.it



化繁为简,Coggle 是一款简约漂亮的思维导图工具,轻量级,需要 Google 账号,可导出 PDF、PNG、TXT 格式,支持多人协作,嵌入网页等等。

Lucidchart
网址:https://www.lucidchart.com



Lucidchart是一个基于Web的绘图软件,允许用户协作和实时携创建流程图、组织结构图、网站线框、UML设计、思维导图、软件原型和许多其他的图表类型。

最后
 
如果您正准备做一个店铺招牌,找不到好的设计师和插画师,记得找我。
480
views

ecommerce website design nz|I will design Responsive Magento2 eCommerce website online shop/Store. only $790,Delivery in 5 days

Marketplacefull stack developer Kevin wrote the post • 0 comments • 480 views • 2020-04-06 00:51 • added this tag no more than 24h

 
 
Hello!

I'm David, a professional Back-End Developer , based Auckland, NZ.

If you are looking for a unique website for your business, in which you can manage all the content, I can design and develop a fully responsive and interactive E-Commerce online store for you, using the best technologies for fast, Google-friendly and SEO optimised websites.

I am certified Web developer having 12+ years of quality experience in designing, developing, debugging, updating and publishing attractive, efficient and easy to navigate Responsive E-commerce Websites.

My prime focus is to Guide people to Live their Dreams. I will help in "How to think and not what to think", I will be able to provide solutions for your Design or UI/UX related challenges.

Also I have experience in developing custom plugins as per the requirements and can also assist you in customisation tasks as well.

One of the key success factors in building a professional E-Commerce Website, is modern design combined with user friendly architecture that functions properly on any device. If these factors are not executed effectively, your customers won't trust you.

With more than 12 years of experience, i am ready to dig deep into your goals and needs and provide you with full development support at each step of the way.

Don't give your business and sales to just any developer!
 
 
 
What we need:

1-Logo
2- Website Name and URL
3- Categories, Sub categories name and some nice images to create banners
4- About us, Payment, Shipping, Returns, Contact us etc pages content
5- Cpanel Details (Website Hosting login details with SSH access)


The Process of development-
- Send your initial design and brief that your specific business requires so we can create the website to match your aims and aspirations.
- To provide the best user experience, we use initial mock ups and UX designs to produce an overview of how the website will look.
- To provide customer satisfaction, we allow unlimited revisions of the design
- Then our amazing team converts the approved designs into a functional website that provides all the services which are required to produce the most efficient business available
- Finally, an overall review that allows for revisions to make sure that the website matches your standards and is fully operational for customers.
- Then we provide a full summary on how to use the website and it we be all yours to operate and manage
Report this OfferReviews (92) view all

 
 
Hello!

I'm David, a professional Back-End Developer , based Auckland, NZ.

If you are looking for a unique website for your business, in which you can manage all the content, I can design and develop a fully responsive and interactive E-Commerce online store for you, using the best technologies for fast, Google-friendly and SEO optimised websites.

I am certified Web developer having 12+ years of quality experience in designing, developing, debugging, updating and publishing attractive, efficient and easy to navigate Responsive E-commerce Websites.

My prime focus is to Guide people to Live their Dreams. I will help in "How to think and not what to think", I will be able to provide solutions for your Design or UI/UX related challenges.

Also I have experience in developing custom plugins as per the requirements and can also assist you in customisation tasks as well.

One of the key success factors in building a professional E-Commerce Website, is modern design combined with user friendly architecture that functions properly on any device. If these factors are not executed effectively, your customers won't trust you.

With more than 12 years of experience, i am ready to dig deep into your goals and needs and provide you with full development support at each step of the way.

Don't give your business and sales to just any developer!
 
 
 
What we need:

1-Logo
2- Website Name and URL
3- Categories, Sub categories name and some nice images to create banners
4- About us, Payment, Shipping, Returns, Contact us etc pages content
5- Cpanel Details (Website Hosting login details with SSH access)


The Process of development-
- Send your initial design and brief that your specific business requires so we can create the website to match your aims and aspirations.
- To provide the best user experience, we use initial mock ups and UX designs to produce an overview of how the website will look.
- To provide customer satisfaction, we allow unlimited revisions of the design
- Then our amazing team converts the approved designs into a functional website that provides all the services which are required to produce the most efficient business available
- Finally, an overall review that allows for revisions to make sure that the website matches your standards and is fully operational for customers.
- Then we provide a full summary on how to use the website and it we be all yours to operate and manage
Report this OfferReviews (92)
596
views

ecommerce website design nz|our back-end developer David shared a method today, how to build a payments system with React and Stripe to your own company website.

Marketplacefull stack developer Kevin wrote the post • 0 comments • 596 views • 2020-04-06 00:05 • added this tag no more than 24h

Hello, every one , I am David, from Auckland local fern website design studio. Stripe is a suite of APIs that makes it easy to set up online payment processing, and today, we’ll be leveraging it to create a bare-bones payment system using React.

Whether you’re implementing a subscription-based service, an e-commerce store, or a crowdfunding solution, Stripe offers the flexibility to get it done. We’re going to build a small proof-of-concept payments system to enable one-time purchases on a website.

By the end of this tutorial, you should be able to set up a backend and frontend for processing online payments in your React app.

Requirements to follow along
This tutorial requires that you have the following:

Node installed on your computer
A Stripe developer account
Basic knowledge of Express
Basic knowledge of React Hooks
If you do not have Node installed, you can get the latest version from the official website. All the code written in this tutorial can be accessed here.

Stripe setup
If you do not have a Stripe developer account, you can get started for free by signing up for an account here. After signing up, complete the following steps to get set up:

Select Developer integrations on the How do you want to get started? modal
Select Accept payments only on the next modal
Check the One-time payments option on the next modal
Finally, check Build a custom payment flow on the last modal
You should now have a base account set up. You can update the name of the account by clicking the Add a name link at the top left of the page.

You’ll need to copy your Publishable and Secret keys from the dashboard and store them somewhere, because we’ll need them very soon.
 
 
 
 
 
Building the payment server
Before we go ahead with building the React app, we’ll need to set up a server to handle payment requests.

We’ll need to set up a RESTful endpoint on an Express server, which will act as a middleman between our React code and the Stripe backend. If you’ve never built an API before, don’t worry, it’ll be pretty basic as we’re not implementing a production-ready backend here.

Let’s get started.

Create a new project folder and name it whatever you want (I’m going with react-stripe-payment)
Open your terminal in the folder and run npm init -y
Install the dependencies by running npm install express dotenv body-parser stripe
Create a folder src under the root folder by running mkdir src
server.js

Let’s create the server to listen for payment requests. Create a new file called server.js under the src folder and paste the following in it:const path = require('path')
const express = require('express')
const bodyParser = require('body-parser')
const postCharge = require('./stripe')
require('dotenv').config()

const app = express()
const router = express.Router()
const port = process.env.PORT || 7000

router.post('/stripe/charge', postCharge)
router.all('*', (_, res) =>
res.json({ message: 'please make a POST request to /stripe/charge' })
)
app.use((_, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
)
next()
})
app.use(bodyParser.json())
app.use('/api', router)
app.use(express.static(path.join(__dirname, '../build')))

app.get('*', (_, res) => {
res.sendFile(path.resolve(__dirname, '../build/index.html'))
})

app.listen(port, () => console.log(`server running on port ${port}`))
Let’s break down this file section by section.

const path = require('path')
const express = require('express')
const bodyParser = require('body-parser')
const postCharge = require('./stripe')
require('dotenv').config()
Here, we’re importing the required packages. You’ll notice that they are all third-party imports except for postCharge, which is being imported from a file called stripe. We’ll create that file later.

dotenv allows us to read sensitive information from the Node process so we don’t have to hardcode secret values in our code.const app = express()
const router = express.Router()
const port = process.env.PORT || 7000
We’re initializing a new Express instance into a variable called app. We then create a new Router instance and store it in a variable called router. This is what we’ll use to define the payment endpoint.

Finally, we initialize a new variable called port and assign it a value from the Node process (process.env.PORT), and if that is undefined, it is assigned 7000.router.post('/stripe/charge', postCharge)
router.all('*', (_, res) =>
res.json({ message: 'please make a POST request to /stripe/charge' })
)
app.use((_, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
)
next()
})
app.use(bodyParser.json())
app.use('/api', router)
app.use(express.static(path.join(__dirname, '../build')))
Remember the router we initialized earlier? On the first line, we set up an endpoint called /stripe/charge and assign postCharge to handle all POST requests to this route.

We then catch all other requests to the server and respond with a JSON object containing a message directing the user to the appropriate endpoint.

Next, we define a middleware on the app instance to enable CORS for all requests. On the next line, we attach another middleware that enables us to parse JSON objects from the request body.

Then we tell our app instance to use the router instance to handle all requests to the /api endpoint. Finally, we tell Express to serve up the /build folder. This folder will hold the transpiled code for the app’s frontend.app.get('*', (_, res) => {
res.sendFile(path.resolve(__dirname, '../build/index.html'))
})

app.listen(port, () => console.log(`server running on port ${port}`))
Here, we’re telling the app instance to handle all GET requests by serving the index.html file located in the /build folder. This is how we’ll serve the frontend in production.

Finally, we spin up the server on the port we defined earlier and log a message to the console on a successful startup.

stripe.js

We’ll then create the postCharge handler we required in server.js above. Under the src folder, create a new file, stripe.js, and paste the following in it:const stripe = require('stripe')(<your_secret_key>)

async function postCharge(req, res) {
try {
const { amount, source, receipt_email } = req.body

const charge = await stripe.charges.create({
amount,
currency: 'usd',
source,
receipt_email
})

if (!charge) throw new Error('charge unsuccessful')

res.status(200).json({
message: 'charge posted successfully',
charge
})
} catch (error) {
res.status(500).json({
message: error.message
})
}
}


module.exports = postCharge
Let’s break it down.const stripe = require('stripe')(<your_secret_key>)
Here, we initialize a new Stripe instance by requiring the stripe package and calling it with the secret key we copied earlier as a string. We save this instance in a variable called stripe.async function postCharge(req, res) {
try {
const { amount, source, receipt_email } = req.body

const charge = await stripe.charges.create({
amount,
currency: 'usd',
source,
receipt_email
})
We then create a new function called postCharge. This function is a request handler, so we have to take in two parameters: req and res.

We then open a try catch block inside this function. We destructure all the variables we’re expecting to be sent along with the request from the request object; in this case, those variables are amount, source, and receipt_email.

We then create a new variable called charge. This variable holds the result of an asynchronous call to the Stripe API to create a new charge (stripe.charges.create).if (!charge) throw new Error('charge unsuccessful')
If the result of the Stripe call is a falsy value — undefined, in this case — it means our payment request failed, and so we throw a new error with the message “charge unsuccessful.”

res.status(200).json({
message: 'charge posted successfully',
charge
})
Otherwise, we respond to the request with a 200 status code and a JSON object containing a message and the charge object.

} catch (error) {
res.status(500).json({
message: error.message
})
}
}

module.exports = postCharge
In the catch block, we intercept all other errors and send them to the client with a 500 status code and a message containing the error message.

At the end of the file, we export the postCharge function using module.exports.

That is all there is to the payment server. Of course, this isn’t production-ready and should not be used in a real application processing real payments, but it is enough for our current use case. Let’s move on to the frontend.

Building the frontend
Since we’re done building the payments server, it’s time to flesh out the frontend. It’s not going to be anything fancy since I’m trying to keep this tutorial bite-sized. Here are the different components of the app:

A router component
A products list component
A checkout form component
Let’s get started.

Run the following command to install the required packages:
npm install axios babel-polyfill history parcel parcel-bundler react react-dom react-router-dom react-stripe-elements
In the project root, run the following command:
mkdir public && touch public/index.html
This will create a folder called public and create an index.html file in this new folder. Open the index.html file and paste the following:<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="React + Stripe" />
<title>React and Stripe Payment</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="https://js.stripe.com/v3/"></script>
<script src="../src/index.js"></script>
</body>
</html>
If you’re already familiar with React, this should be nothing new; this is simply the entry point of our app. Also notice that we import the Stripe SDK in the first <script> tag — the Stripe SDK import must come before our own code.

Inside the src folder, run the following command:

touch src/index.js && touch src/products.js
Open index.js and paste the following:import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/App'
import 'babel-polyfill'

const rootNode = document.querySelector('#root')
ReactDOM.render(<App />, rootNode)
Now we need to get the list of products from somewhere. Usually, this would be from a database or some API, but for this simple use case, we can just hardcode two or three products in a JavaScript file. This is why we need products.js. Open it and paste the following:export const products = [
{
name: 'Rubber Duck',
desc: `Rubber ducks can lay as many eggs as the best chicken layers, and they
are fun to watch with their antics in your backyard, your barnyard, or
your pond.`,
price: 9.99,
img:
'https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcSqkN8wkHiAuT2FQ14AsJFgihZDzKmS6OHQ6eMiC63rW8CRDcbK',
id: 100
},
{
name: 'Chilli Sauce',
desc: `This Chilli Sauce goes well with some nice roast rubber duck. Flavored with
the best spices and the hottest chillis, you can rest assured of a tasty Sunday
rubber roast.`,
price: 12.99,
img:
'https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcRTREm1dEzdI__xc6O8eAz5-4s88SP-Gg9dWYMkBKltGMi84RW5',
id: 101
}
]
This is an array of products that are available for purchase. You can add as many as you like and then move on to creating the components.

Run the following command from the project root: mkdir src/components. This will create a new folder called components inside the src folder to hold our React components. Let’s go ahead and create the first component.

App.jsx
This is the root component and will be responsible for routing to the various pages we have in our app. Create a new file called App.jsx inside the components folder and paste in the following:import React, { useState } from 'react'
import { Router, Route, Switch } from 'react-router-dom'
import { createBrowserHistory } from 'history'
import Products from './Products'
import Checkout from './Checkout'
import { products } from '../products'

const history = createBrowserHistory()

const App = () => {
const [selectedProduct, setSelectedProduct] = useState(null)

return (
<Router history={history}>
<Switch>
<Route
exact
path="/"
render={() => (
<Products
products={products}
selectProduct={setSelectedProduct}
history={history}
/>
)}
/>
<Route
path="/checkout"
render={() => (
<Checkout
selectedProduct={selectedProduct}
history={history}
/>
)}
/>
</Switch>
</Router>
)
}

export default App
Let’s break it down.import React, { useState } from 'react'
import { Router, Route, Switch } from 'react-router-dom'
import { createBrowserHistory } from 'history'
import Products from './Products'
import Checkout from './Checkout'
import { products } from '../products'

const history = createBrowserHistory()
This first part is just a bunch of dependency imports. The first three imports are required for any single-page React application. The next two imports are custom components that we’ll write later on. The last import is the hardcoded products we created earlier. We’ll pass it down as a prop to the Products component.

Finally, we create a new history instance from the history package and save it in a variable aptly named history.const App = () => {
const [selectedProduct, setSelectedProduct] = useState(null)

return (
<Router history={history}>
<Switch>
<Route
exact
path="/"
render={() => (
<Products
products={products}
selectProduct={setSelectedProduct}
history={history}
/>
)}
/>
<Route
path="/checkout"
render={() => (
<Checkout
selectedProduct={selectedProduct}
history={history}
/>
)}
/>
</Switch>
</Router>
)
}


export default App
We then create a new functional component called App. App has a state variable called selectedProduct, which holds the product currently selected to be purchased.

We return a Router instance that defines all the routes and their respective components.

In the first route, /, we render the Products component and pass in three props: the list of hardcoded products, a function to set a product in the App state, and the history object to enable us to navigate to new pages without breaking the browser history.

In the second route, /checkout, we render the Checkout component and pass in a couple props: the currently selected product and the history object.

At the end of the file, we export the App component as the default export.

Products.jsx
This component is responsible for rendering the list of products to the DOM, and it’s fairly simple. Create a new file called Products.jsx in the components folder and paste in the following:import React from 'react'
import './Products.scss'

const Products = ({ products, selectProduct, history }) => {
const handlePurchase = prod => () => {
selectProduct(prod)
history.push('/checkout')
}

return products.map(prod => (
<div className="product" key={prod.id}>
<section>
<h2>{prod.name}</h2>
<p>{prod.desc}</p>
<h3>{'$' + prod.price}</h3>
<button type="button" onClick={handlePurchase(prod)}>
PURCHASE
</button>
</section>
<img src={prod.img} alt={prod.name} />
</div>
))
}

export default Products
Note: You can get the Products.scss contents from here.

Let’s break it down.const Products = ({ products, selectProduct, history }) => {
const handlePurchase = prod => () => {
selectProduct(prod)
history.push('/checkout')
}
We start off defining a functional component that takes in three props:

products
selectProduct
history
products is the array of products we hardcoded earlier. We’ll be mapping over this array later on to render the individual products to the DOM.

selectProduct is a function that takes in a single product object. It updates the App component’s state to hold this product so that the Checkout component can access it through its props.

history is the history object that will allow us to navigate to other routes safely.

Then we define the handlePurchase function, which will be called when a user wants to purchase a certain product. It takes in a single parameter, prod, and calls selectProduct with this parameter. After calling selectProduct, it then navigates to the /checkout route by calling history.push.return products.map(prod => (
<div className="product" key={prod.id}>
<section>
<h2>{prod.name}</h2>
<p>{prod.desc}</p>
<h3>{'$' + prod.price}</h3>
<button type="button" onClick={handlePurchase(prod)}>
PURCHASE
</button>
</section>
<img src={prod.img} alt={prod.name} />
</div>
))
}


export default Products
It’s time to render the products to the DOM. We map over the products array and, for each product in the array, return a bunch of JSX. The JSX should be pretty straightforward and will result in the following image being painted in the screen:
 
 
 
Checkout.jsx
Next, we want to create the checkout page where the user will be routed to when they click on the PURCHASE button on a product.

Create a Checkout.jsx file under the components folder and paste the following in it:import React, { useEffect } from 'react'
import { StripeProvider, Elements } from 'react-stripe-elements'
import CheckoutForm from './CheckoutForm'

const Checkout = ({ selectedProduct, history }) => {
useEffect(() => {
window.scrollTo(0, 0)
}, [])

return (
<StripeProvider apiKey="pk_test_UrBUzJWPNse3I03Bsaxh6WFX00r6rJ1YCq">
<Elements>
<CheckoutForm selectedProduct={selectedProduct} history={history} />
</Elements>
</StripeProvider>
)
}

export default Checkout

This is when we begin to bring Stripe into the mix. In the second line, we’re importing something called StripeProvider and another thing called Elements from the react-stripe-elements package we installed at the beginning of this section.

StripeProvider is required for our app to have access to the Stripe object, and any component that interacts with the Stripe object must be a child of StripeProvider.

Elements is a React component that wraps around the actual checkout form. It helps group the set of Stripe Elements (more on this in a bit) together and makes it easy to tokenize all the data from each Stripe Element.

The Checkout component itself is fairly simple. It takes in two props, selectedProduct and history, which it passes on to a CheckoutForm component we’ll create next.

There’s also a useEffect call that scrolls the document to the top when the page mounts for the first time. This is necessary because react-router-dom preserves the previous scroll state when you switch routes.

Also notice that we’re passing a prop, apiKey, to StripeProvider. This key is the publishable key you copied earlier when setting up Stripe. Note that this prop is required because it serves as a way to authenticate your application to the Stripe servers.

CheckoutForm.jsx

This is the last component we’ll be creating, and it’s also the most important. The CheckoutForm component will hold the inputs for getting the user’s card details as well as actually making a call to the backend to process the payment charge.

Create a new file called CheckoutForm.jsx inside the components directory. We’re going to go through the content of this file section by section.import React, { useState } from 'react'
import { Link } from 'react-router-dom'
import {
CardNumberElement,
CardExpiryElement,
CardCVCElement,
injectStripe
} from 'react-stripe-elements'
import axios from 'axios'
import './CheckoutForm.scss'
...to be continued below...
First, we import the required packages we’ll be working with into the file. Notice the imports from the react-stripe-elements package. This is a good time to talk more about Stripe Elements.

Stripe Elements are a set of prebuilt UI elements that allow you to collect your user’s card information without managing such sensitive information yourself.

The react-stripe-elements package is a wrapper for Stripe Elements that exposes these elements as React components you can just plug into your app — no need to create them from scratch.

We are importing some of these components into this file along with a HOC component, injectStripe.

injectStripe basically takes the Stripe object initialized in the StripeProvider component and “injects” the object into any component wrapped with it. This is how we’ll get access to the Stripe Object.

We then import a package called axios. Axios is just a promise-based HTTP client for the browser that we’re going to use to communicate with our payments server.

You can get the contents of CheckoutForm.scss from here.

...continued...const CheckoutForm = ({ selectedProduct, stripe, history }) => {
if (selectedProduct === null) history.push('/')

const [receiptUrl, setReceiptUrl] = useState('')

const handleSubmit = async event => {
event.preventDefault()

const { token } = await stripe.createToken()

const order = await axios.post('http://localhost:7000/api/stripe/charge', {
amount: selectedProduct.price.toString().replace('.', ''),
source: token.id,
receipt_email: '[email protected]'
})

setReceiptUrl(order.data.charge.receipt_url)
}
...to be continued...
Next up is the actual CheckoutForm component itself. It takes in three props:

selectedProduct
stripe
history
selectedProduct is the product the user clicked on to purchase. It’s coming from the root App component’s state and is being passed down as props.

stripe is the actual Stripe object that is being “injected” as a prop by the injectStripe HOC we imported. You already know what history does.

The first thing we do in the component is check whether selectedProduct actually exists. If it doesn’t, we route the user to the homepage. In a production-grade app, this would probably be handled by a route guard HOC.

We then define a new piece of state to hold the receipt URL for successful payments. It will initially be empty.

Next, we define a function called handleSubmit, which will be called when the checkout form is submitted (i.e., when the Pay button is clicked). Let’s go through this function.

Firstly, we prevent the default behavior of the form element so that the page doesn’t refresh.

Then we destructure a token value from the result of an async call to stripe.createToken. createToken tokenizes the card information from the form and sends it to the Stripe server. It then returns a token object, where you can get a token.id value as an alias for the actual card info. This ensures that you never actually send the user’s card details to your payment server.

Secondly, we make an HTTP POST request to localhost:7000/api/stripe/charge with a request body containing three things:

amount
source
receipt_email
amount is the price of the item being purchased. We have to convert it to a string and remove all special characters like “.” and “,”. This means that a cost of $9.99 will get sent to the payment server as 999.

source is where the payment will be charged. In our case, it will be the ID of the token we just generated.

receipt_email is where the receipt of the payment will be sent. It is usually the customer’s email address, but in our case, we’re just hardcoding it because, again, we’re not implementing authentication.

After the request is done, we grab the URL of the receipt from the response object and set it to state. This is assuming that there are no errors, so in a production-grade app, you would usually implement error handling.

...continued...if (receiptUrl) {
return (
<div className="success">
<h2>Payment Successful!</h2>
<a href={receiptUrl}>View Receipt</a>
<Link to="/">Home</Link>
</div>
)
}
...to be continued...
Immediately after the handleSubmit function, we have an if check to see if there’s a receiptUrl in the state. If there is, we want to render a div containing a success message and a link to view the receipt as well as a link back to the homepage.

...continued...
  return (
<div className="checkout-form">
<p>Amount: ${selectedProduct.price}</p>
<form onSubmit={handleSubmit}>
<label>
Card details
<CardNumberElement />
</label>
<label>
Expiration date
<CardExpiryElement />
</label>
<label>
CVC
<CardCVCElement />
</label>
<button type="submit" className="order-button">
Pay
</button>
</form>
</div>
)
}

export default injectStripe(CheckoutForm)
Otherwise, we’re going to render the actual checkout form. We’re using the prebuilt Elements components instead of recreating them from scratch and having to manage sensitive information.

At the end of this file, we wrap the CheckoutForm component in the injectStripe HOC so that we have access to the Stripe object we use in the component.

Testing our app
Let’s go through what we’ve accomplished so far.

We’ve created a payments server that communicates with Stripe
We’ve created a homepage to list our products
We’ve created a checkout page to capture the user’s payment details
We’ve created a handleSubmit function to send a request to the server to process a payment charge
We just about have everything set up, so it’s time to actually run our app and see if we’re able to purchase a Rubber Duck. We have to add our scripts first, so open the package.json file and replace the “scripts” section with the following:"scripts": {
"build": "parcel build public/index.html --out-dir build --no-source-maps",
"dev": "node src/server.js & parcel public/index.html",
"start": "node src/server.js"
},
Open your terminal and run npm run dev. This should start the payments server and expose the frontend on port 1234. Open your browser, navigate to http://localhost:1234, and follow the steps below:

Click on the PURCHASE button on any product
In the checkout page, fill in 4242 4242 4242 4242 for the Card details field
Fill in any expiration date and choose a random CVC value
Click on Pay
If everything goes well, you should see a Payment Successful message with links to view your receipt and go back to the homepage.

To confirm payment, log in to your Stripe dashboard, click on Payments, and you should see your payment there.
 
 

 
If your company website using  WooCommerce  codes , you can use WooCommerce Stripe Payment Gateway Plugin
 
Woocommerce Stripe payment gateway enables you to accept payments from customers directly onsite. Customers can purchase their items, select stripe as their checkout option, and be able to pay quite easily with their credit cards.

Stripe takes care of processing the payment (for a little fee) and securing the customer’s financial details, thus giving customers both ease of use and security.

This guide will show you all the steps you need to integrate Stripe with WooCommerce using the WooCommerce Stripe Payment Gateway plugin. We assume you already have a Stripe account. If not, create one, and then go on to activate it.

Also, if you want to avoid all the work, we can help you setup and test Stripe in your WooCommerce store. Simply request our service and we will get to work on it.

 
Step 1. Installing the WooCommerce Stripe Payment Gateway plugin

To install the plugin, login to your WordPress Dashboard and go to “Plugins > Add New”

Add New Plugin - WooCommerce Stripe Payment Integration

Type in “WooCommerce Stripe Payment Gateway” in the search bar. When the plugin appears, click Install Now and wait for the installation to complete. Next click Activate.

Note: Ensure you install the WooCommerce Stripe plugin designed by WooCommerce.

Install and activate WooCommerce Stripe Payment Gateway

After activating the plugin, go to WooCommerce > Settings.

Go to Settings - WooCommerce Stripe Payment Integration

Next, switch to the “Checkout” tab. If you have correctly activated the WooCommerce Stripe plugin, “Stripe” should now appear among the options. Click on it.

Step 2. Setting Up Stripe Payment Options

In this step, we are going to set up the various options needed to activate and configure stripe for your website.

First click “Enable Stripe” to activate this payment option.

Next, setup your Title and Description. These would determine what users see during checkout. The default values may be good enough, or you can adjust as you see fit.

Set the description - WooCommerce Stripe Payment Integration

Since we want to try it out in test mode first, tick the “Enable Test Mode” option. Next, login to your stripe account and click API.

Switch to test mode with the toggle button, and copy the test “Publishable” and “Secret” keys into the corresponding fields in your stripe plugin.

Copy test API keys - WooCommerce Stripe Payment Integration

In the Statement Descriptor input, enter a description that will appear in the transaction statement. In the example below, this is “FixRunner Web Services”.

Next, tick the “Capture Charge Immediately” option to ensure charges are processed and billed as soon as the customer checks out.

Enter settings - WooCommerce Stripe Payment Integration

Enabling Stripe Checkout
When the “Enable Stripe Checkout” option is ticked, users get a popup form requesting their financial details when they select stripe as payment method and click Continue To Payment. Enabling this option also gives you the ability to accept payments via Bitcoin.

To use this feature, tick “Enable Stripe Checkout”. Next, select your preferred language, and tick “Enable Bitcoin Currency” if you want to accept payments with Bitcoin.

If you want a custom image of your brand to appear on top of the Stripe checkout popup, enter the url of that image in the “Stripe Checkout Image” input box.

Enable Stripe Checkout - WooCommerce Stripe Payment Integration

When users opt to pay through Stripe, the payment popup will appear like this:

Payment with Stripe Checkout - WooCommerce Stripe Payment Integration

Enabling Apple Pay

Apple pay offers your customers a very simple way to checkout from their iOS devices. If you want to use this option, tick “Enable Apple Pay”

Next, select your button style, and enter the 2 letter code for the language you want Apple pay to be displayed in. You may leave it set to “en” for English, or click the link under that option to see the codes for other languages.

Apple pay settings - WooCommerce Stripe Payment Integration

Now go back to your stripe account and click Payments. In the payments page, select Apple Pay, and accept Apples terms of service.

Accept Apple Pay terms - WooCommerce Stripe Payment Integration

Next, click Add New Domain, and type in your domain name. Your WooCommerce Stripe plugin would take care of steps 2 and 3. Go on to click Add.

Add domain for Apple Pay - WooCommerce Stripe Payment Integration

Note: If you get an error that the file could not be found in your domain, go back, download the file in step 2, and upload it to the specified location in step 3. And then click Add.

After completing this step and saving the setting in your Plugin, Apple Pay would be seen in product, checkout, and other pages, when your site is accessed with a compatible iOS device.

Saving Details for Future Payments
If you would like to store customer financial details so you can use these for billing them in the future, tick the “Enable Payments Via Saved Cards” option.

Saving financial details - WooCommerce Stripe Payment Integration

Note that the financial details are not stored on your servers, but on Stripe’s servers, where all security measures are in place to protect this sensitive data.

For debugging purposes, you may also enable the “Log Debug Messages” option. This can be useful in finding out what went wrong if there are errors.

And that concludes your setup process. Click Save Changes to use the settings you have specified.

Step 3. Trying WooCommerce Stripe in Test Mode


In the setup above, we enabled test mode and used the test API details obtained from Stripe. This is useful to check if Stripe payment works properly before making it available to your customers.

Stripe provides test credit card details you can use for this purpose. In this example, we would be using the following details, and you should be able to use them too. If not, you can obtain other test card details.

Card number: 4242424242424242
Expiry: Any date after today
CVV: 789

Now, go to any of your products page, add the product to cart, and click View Cart. In the cart page, click Proceed to checkout.

Fill out the form with your information. At the bottom of the page, select “Stripe” as your payment method and click Continue to payment.

Next, enter the test financial details and click Pay #Amount.

Test payment - WooCommerce Stripe Payment Integration

You would be taken to an order confirmation page like the one below:

Payment confirmation - WooCommerce Stripe Payment Integration

Congratulations! Your WooCommerce Stripe payment option works!

The final step is to make this payment method available to customers.

Step 4. Activating Live Mode to begin processing real payments

To enable this payment method for your customers, you need to activate live mode.

In your WordPress dashboard, go to WooCommerce > Settings. Next, switch to the “Checkout” tab and click Stripe.

Uncheck the enable test mode option. When you do, the key input boxes will change to accept the live keys.

Switch to live mode - WooCommerce Stripe Payment Integration

Now login go to your stripe dashboard and click API. You should currently be in test mode.

Switch API to live - WooCommerce Stripe Payment Integration

To switch to live mode, click the Live/Test toggle switch. Next, copy your live Publishable and Secret keys into their input boxes in your WooCommerce Stripe Plugin.

Enter live keys - WooCommerce Stripe Payment Integration

Lastly, scroll down and click Save Changes. Customers can now make payments with Stripe on your website.

Note: To be able to activate live mode, you must have ssl in your server (i.e. your domain should start with https), and you must have enabled the “Force secure checkout” option found in WooCommerce > Settings > Checkout.

If you do not have ssl, have your host add it for you, and then go on to enable secure checkout, and then live mode.
 
 
 
 
 
 
 
 
 
 
  view all
Hello, every one , I am David, from Auckland local fern website design studio. Stripe is a suite of APIs that makes it easy to set up online payment processing, and today, we’ll be leveraging it to create a bare-bones payment system using React.

Whether you’re implementing a subscription-based service, an e-commerce store, or a crowdfunding solution, Stripe offers the flexibility to get it done. We’re going to build a small proof-of-concept payments system to enable one-time purchases on a website.

By the end of this tutorial, you should be able to set up a backend and frontend for processing online payments in your React app.

Requirements to follow along
This tutorial requires that you have the following:

Node installed on your computer
A Stripe developer account
Basic knowledge of Express
Basic knowledge of React Hooks
If you do not have Node installed, you can get the latest version from the official website. All the code written in this tutorial can be accessed here.

Stripe setup
If you do not have a Stripe developer account, you can get started for free by signing up for an account here. After signing up, complete the following steps to get set up:

Select Developer integrations on the How do you want to get started? modal
Select Accept payments only on the next modal
Check the One-time payments option on the next modal
Finally, check Build a custom payment flow on the last modal
You should now have a base account set up. You can update the name of the account by clicking the Add a name link at the top left of the page.

You’ll need to copy your Publishable and Secret keys from the dashboard and store them somewhere, because we’ll need them very soon.
 
 
 
 
 
Building the payment server
Before we go ahead with building the React app, we’ll need to set up a server to handle payment requests.

We’ll need to set up a RESTful endpoint on an Express server, which will act as a middleman between our React code and the Stripe backend. If you’ve never built an API before, don’t worry, it’ll be pretty basic as we’re not implementing a production-ready backend here.

Let’s get started.

Create a new project folder and name it whatever you want (I’m going with react-stripe-payment)
Open your terminal in the folder and run npm init -y
Install the dependencies by running npm install express dotenv body-parser stripe
Create a folder src under the root folder by running mkdir src
server.js

Let’s create the server to listen for payment requests. Create a new file called server.js under the src folder and paste the following in it:
const path = require('path')
const express = require('express')
const bodyParser = require('body-parser')
const postCharge = require('./stripe')
require('dotenv').config()

const app = express()
const router = express.Router()
const port = process.env.PORT || 7000

router.post('/stripe/charge', postCharge)
router.all('*', (_, res) =>
res.json({ message: 'please make a POST request to /stripe/charge' })
)
app.use((_, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
)
next()
})
app.use(bodyParser.json())
app.use('/api', router)
app.use(express.static(path.join(__dirname, '../build')))

app.get('*', (_, res) => {
res.sendFile(path.resolve(__dirname, '../build/index.html'))
})

app.listen(port, () => console.log(`server running on port ${port}`))
Let’s break down this file section by section.

const path = require('path')
const express = require('express')
const bodyParser = require('body-parser')
const postCharge = require('./stripe')
require('dotenv').config()

Here, we’re importing the required packages. You’ll notice that they are all third-party imports except for postCharge, which is being imported from a file called stripe. We’ll create that file later.

dotenv allows us to read sensitive information from the Node process so we don’t have to hardcode secret values in our code.
const app = express()
const router = express.Router()
const port = process.env.PORT || 7000

We’re initializing a new Express instance into a variable called app. We then create a new Router instance and store it in a variable called router. This is what we’ll use to define the payment endpoint.

Finally, we initialize a new variable called port and assign it a value from the Node process (process.env.PORT), and if that is undefined, it is assigned 7000.
router.post('/stripe/charge', postCharge)
router.all('*', (_, res) =>
res.json({ message: 'please make a POST request to /stripe/charge' })
)
app.use((_, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
)
next()
})
app.use(bodyParser.json())
app.use('/api', router)
app.use(express.static(path.join(__dirname, '../build')))

Remember the router we initialized earlier? On the first line, we set up an endpoint called /stripe/charge and assign postCharge to handle all POST requests to this route.

We then catch all other requests to the server and respond with a JSON object containing a message directing the user to the appropriate endpoint.

Next, we define a middleware on the app instance to enable CORS for all requests. On the next line, we attach another middleware that enables us to parse JSON objects from the request body.

Then we tell our app instance to use the router instance to handle all requests to the /api endpoint. Finally, we tell Express to serve up the /build folder. This folder will hold the transpiled code for the app’s frontend.
app.get('*', (_, res) => {
res.sendFile(path.resolve(__dirname, '../build/index.html'))
})

app.listen(port, () => console.log(`server running on port ${port}`))

Here, we’re telling the app instance to handle all GET requests by serving the index.html file located in the /build folder. This is how we’ll serve the frontend in production.

Finally, we spin up the server on the port we defined earlier and log a message to the console on a successful startup.

stripe.js

We’ll then create the postCharge handler we required in server.js above. Under the src folder, create a new file, stripe.js, and paste the following in it:
const stripe = require('stripe')(<your_secret_key>)

async function postCharge(req, res) {
try {
const { amount, source, receipt_email } = req.body

const charge = await stripe.charges.create({
amount,
currency: 'usd',
source,
receipt_email
})

if (!charge) throw new Error('charge unsuccessful')

res.status(200).json({
message: 'charge posted successfully',
charge
})
} catch (error) {
res.status(500).json({
message: error.message
})
}
}


module.exports = postCharge
Let’s break it down.
const stripe = require('stripe')(<your_secret_key>)

Here, we initialize a new Stripe instance by requiring the stripe package and calling it with the secret key we copied earlier as a string. We save this instance in a variable called stripe.
async function postCharge(req, res) {
try {
const { amount, source, receipt_email } = req.body

const charge = await stripe.charges.create({
amount,
currency: 'usd',
source,
receipt_email
})

We then create a new function called postCharge. This function is a request handler, so we have to take in two parameters: req and res.

We then open a try catch block inside this function. We destructure all the variables we’re expecting to be sent along with the request from the request object; in this case, those variables are amount, source, and receipt_email.

We then create a new variable called charge. This variable holds the result of an asynchronous call to the Stripe API to create a new charge (stripe.charges.create).
if (!charge) throw new Error('charge unsuccessful')
If the result of the Stripe call is a falsy value — undefined, in this case — it means our payment request failed, and so we throw a new error with the message “charge unsuccessful.”

res.status(200).json({
message: 'charge posted successfully',
charge
})
Otherwise, we respond to the request with a 200 status code and a JSON object containing a message and the charge object.

} catch (error) {
res.status(500).json({
message: error.message
})
}
}

module.exports = postCharge

In the catch block, we intercept all other errors and send them to the client with a 500 status code and a message containing the error message.

At the end of the file, we export the postCharge function using module.exports.

That is all there is to the payment server. Of course, this isn’t production-ready and should not be used in a real application processing real payments, but it is enough for our current use case. Let’s move on to the frontend.

Building the frontend
Since we’re done building the payments server, it’s time to flesh out the frontend. It’s not going to be anything fancy since I’m trying to keep this tutorial bite-sized. Here are the different components of the app:

A router component
A products list component
A checkout form component
Let’s get started.

Run the following command to install the required packages:
npm install axios babel-polyfill history parcel parcel-bundler react react-dom react-router-dom react-stripe-elements
In the project root, run the following command:
mkdir public && touch public/index.html
This will create a folder called public and create an index.html file in this new folder. Open the index.html file and paste the following:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="React + Stripe" />
<title>React and Stripe Payment</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="https://js.stripe.com/v3/"></script>
<script src="../src/index.js"></script>
</body>
</html>

If you’re already familiar with React, this should be nothing new; this is simply the entry point of our app. Also notice that we import the Stripe SDK in the first <script> tag — the Stripe SDK import must come before our own code.

Inside the src folder, run the following command:

touch src/index.js && touch src/products.js
Open index.js and paste the following:
import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/App'
import 'babel-polyfill'

const rootNode = document.querySelector('#root')
ReactDOM.render(<App />, rootNode)

Now we need to get the list of products from somewhere. Usually, this would be from a database or some API, but for this simple use case, we can just hardcode two or three products in a JavaScript file. This is why we need products.js. Open it and paste the following:
export const products = [
{
name: 'Rubber Duck',
desc: `Rubber ducks can lay as many eggs as the best chicken layers, and they
are fun to watch with their antics in your backyard, your barnyard, or
your pond.`,
price: 9.99,
img:
'https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcSqkN8wkHiAuT2FQ14AsJFgihZDzKmS6OHQ6eMiC63rW8CRDcbK',
id: 100
},
{
name: 'Chilli Sauce',
desc: `This Chilli Sauce goes well with some nice roast rubber duck. Flavored with
the best spices and the hottest chillis, you can rest assured of a tasty Sunday
rubber roast.`,
price: 12.99,
img:
'https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcRTREm1dEzdI__xc6O8eAz5-4s88SP-Gg9dWYMkBKltGMi84RW5',
id: 101
}
]

This is an array of products that are available for purchase. You can add as many as you like and then move on to creating the components.

Run the following command from the project root: mkdir src/components. This will create a new folder called components inside the src folder to hold our React components. Let’s go ahead and create the first component.

App.jsx
This is the root component and will be responsible for routing to the various pages we have in our app. Create a new file called App.jsx inside the components folder and paste in the following:
import React, { useState } from 'react'
import { Router, Route, Switch } from 'react-router-dom'
import { createBrowserHistory } from 'history'
import Products from './Products'
import Checkout from './Checkout'
import { products } from '../products'

const history = createBrowserHistory()

const App = () => {
const [selectedProduct, setSelectedProduct] = useState(null)

return (
<Router history={history}>
<Switch>
<Route
exact
path="/"
render={() => (
<Products
products={products}
selectProduct={setSelectedProduct}
history={history}
/>
)}
/>
<Route
path="/checkout"
render={() => (
<Checkout
selectedProduct={selectedProduct}
history={history}
/>
)}
/>
</Switch>
</Router>
)
}


export default App
Let’s break it down.
import React, { useState } from 'react'
import { Router, Route, Switch } from 'react-router-dom'
import { createBrowserHistory } from 'history'
import Products from './Products'
import Checkout from './Checkout'
import { products } from '../products'

const history = createBrowserHistory()

This first part is just a bunch of dependency imports. The first three imports are required for any single-page React application. The next two imports are custom components that we’ll write later on. The last import is the hardcoded products we created earlier. We’ll pass it down as a prop to the Products component.

Finally, we create a new history instance from the history package and save it in a variable aptly named history.
const App = () => {
const [selectedProduct, setSelectedProduct] = useState(null)

return (
<Router history={history}>
<Switch>
<Route
exact
path="/"
render={() => (
<Products
products={products}
selectProduct={setSelectedProduct}
history={history}
/>
)}
/>
<Route
path="/checkout"
render={() => (
<Checkout
selectedProduct={selectedProduct}
history={history}
/>
)}
/>
</Switch>
</Router>
)
}


export default App
We then create a new functional component called App. App has a state variable called selectedProduct, which holds the product currently selected to be purchased.

We return a Router instance that defines all the routes and their respective components.

In the first route, /, we render the Products component and pass in three props: the list of hardcoded products, a function to set a product in the App state, and the history object to enable us to navigate to new pages without breaking the browser history.

In the second route, /checkout, we render the Checkout component and pass in a couple props: the currently selected product and the history object.

At the end of the file, we export the App component as the default export.

Products.jsx
This component is responsible for rendering the list of products to the DOM, and it’s fairly simple. Create a new file called Products.jsx in the components folder and paste in the following:
import React from 'react'
import './Products.scss'

const Products = ({ products, selectProduct, history }) => {
const handlePurchase = prod => () => {
selectProduct(prod)
history.push('/checkout')
}

return products.map(prod => (
<div className="product" key={prod.id}>
<section>
<h2>{prod.name}</h2>
<p>{prod.desc}</p>
<h3>{'$' + prod.price}</h3>
<button type="button" onClick={handlePurchase(prod)}>
PURCHASE
</button>
</section>
<img src={prod.img} alt={prod.name} />
</div>
))
}


export default Products
Note: You can get the Products.scss contents from here.

Let’s break it down.
const Products = ({ products, selectProduct, history }) => {
const handlePurchase = prod => () => {
selectProduct(prod)
history.push('/checkout')
}

We start off defining a functional component that takes in three props:

products
selectProduct
history
products is the array of products we hardcoded earlier. We’ll be mapping over this array later on to render the individual products to the DOM.

selectProduct is a function that takes in a single product object. It updates the App component’s state to hold this product so that the Checkout component can access it through its props.

history is the history object that will allow us to navigate to other routes safely.

Then we define the handlePurchase function, which will be called when a user wants to purchase a certain product. It takes in a single parameter, prod, and calls selectProduct with this parameter. After calling selectProduct, it then navigates to the /checkout route by calling history.push.
return products.map(prod => (
<div className="product" key={prod.id}>
<section>
<h2>{prod.name}</h2>
<p>{prod.desc}</p>
<h3>{'$' + prod.price}</h3>
<button type="button" onClick={handlePurchase(prod)}>
PURCHASE
</button>
</section>
<img src={prod.img} alt={prod.name} />
</div>
))
}


export default Products
It’s time to render the products to the DOM. We map over the products array and, for each product in the array, return a bunch of JSX. The JSX should be pretty straightforward and will result in the following image being painted in the screen:
 
 
 
Checkout.jsx
Next, we want to create the checkout page where the user will be routed to when they click on the PURCHASE button on a product.

Create a Checkout.jsx file under the components folder and paste the following in it:
import React, { useEffect } from 'react'
import { StripeProvider, Elements } from 'react-stripe-elements'
import CheckoutForm from './CheckoutForm'

const Checkout = ({ selectedProduct, history }) => {
useEffect(() => {
window.scrollTo(0, 0)
}, [])

return (
<StripeProvider apiKey="pk_test_UrBUzJWPNse3I03Bsaxh6WFX00r6rJ1YCq">
<Elements>
<CheckoutForm selectedProduct={selectedProduct} history={history} />
</Elements>
</StripeProvider>
)
}


export default Checkout

This is when we begin to bring Stripe into the mix. In the second line, we’re importing something called StripeProvider and another thing called Elements from the react-stripe-elements package we installed at the beginning of this section.

StripeProvider is required for our app to have access to the Stripe object, and any component that interacts with the Stripe object must be a child of StripeProvider.

Elements is a React component that wraps around the actual checkout form. It helps group the set of Stripe Elements (more on this in a bit) together and makes it easy to tokenize all the data from each Stripe Element.

The Checkout component itself is fairly simple. It takes in two props, selectedProduct and history, which it passes on to a CheckoutForm component we’ll create next.

There’s also a useEffect call that scrolls the document to the top when the page mounts for the first time. This is necessary because react-router-dom preserves the previous scroll state when you switch routes.

Also notice that we’re passing a prop, apiKey, to StripeProvider. This key is the publishable key you copied earlier when setting up Stripe. Note that this prop is required because it serves as a way to authenticate your application to the Stripe servers.

CheckoutForm.jsx

This is the last component we’ll be creating, and it’s also the most important. The CheckoutForm component will hold the inputs for getting the user’s card details as well as actually making a call to the backend to process the payment charge.

Create a new file called CheckoutForm.jsx inside the components directory. We’re going to go through the content of this file section by section.
import React, { useState } from 'react'
import { Link } from 'react-router-dom'
import {
CardNumberElement,
CardExpiryElement,
CardCVCElement,
injectStripe
} from 'react-stripe-elements'
import axios from 'axios'
import './CheckoutForm.scss'

...to be continued below...
First, we import the required packages we’ll be working with into the file. Notice the imports from the react-stripe-elements package. This is a good time to talk more about Stripe Elements.

Stripe Elements are a set of prebuilt UI elements that allow you to collect your user’s card information without managing such sensitive information yourself.

The react-stripe-elements package is a wrapper for Stripe Elements that exposes these elements as React components you can just plug into your app — no need to create them from scratch.

We are importing some of these components into this file along with a HOC component, injectStripe.

injectStripe basically takes the Stripe object initialized in the StripeProvider component and “injects” the object into any component wrapped with it. This is how we’ll get access to the Stripe Object.

We then import a package called axios. Axios is just a promise-based HTTP client for the browser that we’re going to use to communicate with our payments server.

You can get the contents of CheckoutForm.scss from here.

...continued...
const CheckoutForm = ({ selectedProduct, stripe, history }) => {
if (selectedProduct === null) history.push('/')

const [receiptUrl, setReceiptUrl] = useState('')

const handleSubmit = async event => {
event.preventDefault()

const { token } = await stripe.createToken()

const order = await axios.post('http://localhost:7000/api/stripe/charge', {
amount: selectedProduct.price.toString().replace('.', ''),
source: token.id,
receipt_email: '[email protected]'
})

setReceiptUrl(order.data.charge.receipt_url)
}

...to be continued...
Next up is the actual CheckoutForm component itself. It takes in three props:

selectedProduct
stripe
history
selectedProduct is the product the user clicked on to purchase. It’s coming from the root App component’s state and is being passed down as props.

stripe is the actual Stripe object that is being “injected” as a prop by the injectStripe HOC we imported. You already know what history does.

The first thing we do in the component is check whether selectedProduct actually exists. If it doesn’t, we route the user to the homepage. In a production-grade app, this would probably be handled by a route guard HOC.

We then define a new piece of state to hold the receipt URL for successful payments. It will initially be empty.

Next, we define a function called handleSubmit, which will be called when the checkout form is submitted (i.e., when the Pay button is clicked). Let’s go through this function.

Firstly, we prevent the default behavior of the form element so that the page doesn’t refresh.

Then we destructure a token value from the result of an async call to stripe.createToken. createToken tokenizes the card information from the form and sends it to the Stripe server. It then returns a token object, where you can get a token.id value as an alias for the actual card info. This ensures that you never actually send the user’s card details to your payment server.

Secondly, we make an HTTP POST request to localhost:7000/api/stripe/charge with a request body containing three things:

amount
source
receipt_email
amount is the price of the item being purchased. We have to convert it to a string and remove all special characters like “.” and “,”. This means that a cost of $9.99 will get sent to the payment server as 999.

source is where the payment will be charged. In our case, it will be the ID of the token we just generated.

receipt_email is where the receipt of the payment will be sent. It is usually the customer’s email address, but in our case, we’re just hardcoding it because, again, we’re not implementing authentication.

After the request is done, we grab the URL of the receipt from the response object and set it to state. This is assuming that there are no errors, so in a production-grade app, you would usually implement error handling.

...continued...
if (receiptUrl) {
return (
<div className="success">
<h2>Payment Successful!</h2>
<a href={receiptUrl}>View Receipt</a>
<Link to="/">Home</Link>
</div>
)
}

...to be continued...
Immediately after the handleSubmit function, we have an if check to see if there’s a receiptUrl in the state. If there is, we want to render a div containing a success message and a link to view the receipt as well as a link back to the homepage.

...continued...
  
return (
<div className="checkout-form">
<p>Amount: ${selectedProduct.price}</p>
<form onSubmit={handleSubmit}>
<label>
Card details
<CardNumberElement />
</label>
<label>
Expiration date
<CardExpiryElement />
</label>
<label>
CVC
<CardCVCElement />
</label>
<button type="submit" className="order-button">
Pay
</button>
</form>
</div>
)
}

export default injectStripe(CheckoutForm)
Otherwise, we’re going to render the actual checkout form. We’re using the prebuilt Elements components instead of recreating them from scratch and having to manage sensitive information.

At the end of this file, we wrap the CheckoutForm component in the injectStripe HOC so that we have access to the Stripe object we use in the component.

Testing our app
Let’s go through what we’ve accomplished so far.

We’ve created a payments server that communicates with Stripe
We’ve created a homepage to list our products
We’ve created a checkout page to capture the user’s payment details
We’ve created a handleSubmit function to send a request to the server to process a payment charge
We just about have everything set up, so it’s time to actually run our app and see if we’re able to purchase a Rubber Duck. We have to add our scripts first, so open the package.json file and replace the “scripts” section with the following:
"scripts": {
"build": "parcel build public/index.html --out-dir build --no-source-maps",
"dev": "node src/server.js & parcel public/index.html",
"start": "node src/server.js"
},

Open your terminal and run npm run dev. This should start the payments server and expose the frontend on port 1234. Open your browser, navigate to http://localhost:1234, and follow the steps below:

Click on the PURCHASE button on any product
In the checkout page, fill in 4242 4242 4242 4242 for the Card details field
Fill in any expiration date and choose a random CVC value
Click on Pay
If everything goes well, you should see a Payment Successful message with links to view your receipt and go back to the homepage.

To confirm payment, log in to your Stripe dashboard, click on Payments, and you should see your payment there.
 
 

 
If your company website using  WooCommerce  codes , you can use WooCommerce Stripe Payment Gateway Plugin
 
Woocommerce Stripe payment gateway enables you to accept payments from customers directly onsite. Customers can purchase their items, select stripe as their checkout option, and be able to pay quite easily with their credit cards.

Stripe takes care of processing the payment (for a little fee) and securing the customer’s financial details, thus giving customers both ease of use and security.

This guide will show you all the steps you need to integrate Stripe with WooCommerce using the WooCommerce Stripe Payment Gateway plugin. We assume you already have a Stripe account. If not, create one, and then go on to activate it.

Also, if you want to avoid all the work, we can help you setup and test Stripe in your WooCommerce store. Simply request our service and we will get to work on it.

 
Step 1. Installing the WooCommerce Stripe Payment Gateway plugin

To install the plugin, login to your WordPress Dashboard and go to “Plugins > Add New”

Add New Plugin - WooCommerce Stripe Payment Integration

Type in “WooCommerce Stripe Payment Gateway” in the search bar. When the plugin appears, click Install Now and wait for the installation to complete. Next click Activate.

Note: Ensure you install the WooCommerce Stripe plugin designed by WooCommerce.

Install and activate WooCommerce Stripe Payment Gateway

After activating the plugin, go to WooCommerce > Settings.

Go to Settings - WooCommerce Stripe Payment Integration

Next, switch to the “Checkout” tab. If you have correctly activated the WooCommerce Stripe plugin, “Stripe” should now appear among the options. Click on it.

Step 2. Setting Up Stripe Payment Options

In this step, we are going to set up the various options needed to activate and configure stripe for your website.

First click “Enable Stripe” to activate this payment option.

Next, setup your Title and Description. These would determine what users see during checkout. The default values may be good enough, or you can adjust as you see fit.

Set the description - WooCommerce Stripe Payment Integration

Since we want to try it out in test mode first, tick the “Enable Test Mode” option. Next, login to your stripe account and click API.

Switch to test mode with the toggle button, and copy the test “Publishable” and “Secret” keys into the corresponding fields in your stripe plugin.

Copy test API keys - WooCommerce Stripe Payment Integration

In the Statement Descriptor input, enter a description that will appear in the transaction statement. In the example below, this is “FixRunner Web Services”.

Next, tick the “Capture Charge Immediately” option to ensure charges are processed and billed as soon as the customer checks out.

Enter settings - WooCommerce Stripe Payment Integration

Enabling Stripe Checkout
When the “Enable Stripe Checkout” option is ticked, users get a popup form requesting their financial details when they select stripe as payment method and click Continue To Payment. Enabling this option also gives you the ability to accept payments via Bitcoin.

To use this feature, tick “Enable Stripe Checkout”. Next, select your preferred language, and tick “Enable Bitcoin Currency” if you want to accept payments with Bitcoin.

If you want a custom image of your brand to appear on top of the Stripe checkout popup, enter the url of that image in the “Stripe Checkout Image” input box.

Enable Stripe Checkout - WooCommerce Stripe Payment Integration

When users opt to pay through Stripe, the payment popup will appear like this:

Payment with Stripe Checkout - WooCommerce Stripe Payment Integration

Enabling Apple Pay

Apple pay offers your customers a very simple way to checkout from their iOS devices. If you want to use this option, tick “Enable Apple Pay”

Next, select your button style, and enter the 2 letter code for the language you want Apple pay to be displayed in. You may leave it set to “en” for English, or click the link under that option to see the codes for other languages.

Apple pay settings - WooCommerce Stripe Payment Integration

Now go back to your stripe account and click Payments. In the payments page, select Apple Pay, and accept Apples terms of service.

Accept Apple Pay terms - WooCommerce Stripe Payment Integration

Next, click Add New Domain, and type in your domain name. Your WooCommerce Stripe plugin would take care of steps 2 and 3. Go on to click Add.

Add domain for Apple Pay - WooCommerce Stripe Payment Integration

Note: If you get an error that the file could not be found in your domain, go back, download the file in step 2, and upload it to the specified location in step 3. And then click Add.

After completing this step and saving the setting in your Plugin, Apple Pay would be seen in product, checkout, and other pages, when your site is accessed with a compatible iOS device.

Saving Details for Future Payments
If you would like to store customer financial details so you can use these for billing them in the future, tick the “Enable Payments Via Saved Cards” option.

Saving financial details - WooCommerce Stripe Payment Integration

Note that the financial details are not stored on your servers, but on Stripe’s servers, where all security measures are in place to protect this sensitive data.

For debugging purposes, you may also enable the “Log Debug Messages” option. This can be useful in finding out what went wrong if there are errors.

And that concludes your setup process. Click Save Changes to use the settings you have specified.

Step 3. Trying WooCommerce Stripe in Test Mode


In the setup above, we enabled test mode and used the test API details obtained from Stripe. This is useful to check if Stripe payment works properly before making it available to your customers.

Stripe provides test credit card details you can use for this purpose. In this example, we would be using the following details, and you should be able to use them too. If not, you can obtain other test card details.

Card number: 4242424242424242
Expiry: Any date after today
CVV: 789

Now, go to any of your products page, add the product to cart, and click View Cart. In the cart page, click Proceed to checkout.

Fill out the form with your information. At the bottom of the page, select “Stripe” as your payment method and click Continue to payment.

Next, enter the test financial details and click Pay #Amount.

Test payment - WooCommerce Stripe Payment Integration

You would be taken to an order confirmation page like the one below:

Payment confirmation - WooCommerce Stripe Payment Integration

Congratulations! Your WooCommerce Stripe payment option works!

The final step is to make this payment method available to customers.

Step 4. Activating Live Mode to begin processing real payments

To enable this payment method for your customers, you need to activate live mode.

In your WordPress dashboard, go to WooCommerce > Settings. Next, switch to the “Checkout” tab and click Stripe.

Uncheck the enable test mode option. When you do, the key input boxes will change to accept the live keys.

Switch to live mode - WooCommerce Stripe Payment Integration

Now login go to your stripe dashboard and click API. You should currently be in test mode.

Switch API to live - WooCommerce Stripe Payment Integration

To switch to live mode, click the Live/Test toggle switch. Next, copy your live Publishable and Secret keys into their input boxes in your WooCommerce Stripe Plugin.

Enter live keys - WooCommerce Stripe Payment Integration

Lastly, scroll down and click Save Changes. Customers can now make payments with Stripe on your website.

Note: To be able to activate live mode, you must have ssl in your server (i.e. your domain should start with https), and you must have enabled the “Force secure checkout” option found in WooCommerce > Settings > Checkout.

If you do not have ssl, have your host add it for you, and then go on to enable secure checkout, and then live mode.
 
 
 
 
 
 
 
 
 
 
 
499
views

新西兰华人网页设计公司|我们的后端工程师David总结的静态站点加速访问经验,通过 Google CDN 加速,如何让你的网站在一秒钟内打开

Marketplacefull stack developer Kevin wrote the post • 0 comments • 499 views • 2020-04-05 13:33 • added this tag no more than 24h

大家好,我是新西兰软件开发公司local fern的程序员David,最近因工作需要,需要将客户的网站提高访问速度,用到了 Google Cloud Platform的cdn。
 
如果更近一步,除了新西兰本地外,想要让大陆地区访问速度更加快一些的话,我们可以考虑将站点内容放在 Google Cloud Platform 的 Storage 中,并且使用 Google CDN 进行全网加速(主要是因为国内大部分线路可以不绕路使用到香港边缘节点).

本文假设:

你有 Google Cloud Platform 账户,并懂得一些基本操作
在自己的机器上安装了 Google Cloud SDK,如果没有的话,参考 《挂载 Google Storage 到 VPS 文件系统》
账户中已经验证好了自己的域名,如果没有的话,参考 Domain ownership verification
获取 SSL 证书
除非希望托管一个 HTTP 的网站,否则一个证书是必不可少的,Google 不会帮你自动完成这一步。

有多种方式可以获取一个 SSL 证书,如果目前手头没有的话,我们通过 Let’s Encrypt 申请一个好了,首先获取 certbot:$ git clone https://github.com/certbot/certbot.git
$ cd certbot
由于我自己的一些原因(在迁移前域名解析到 GitHub Pages 上的,不能通过改变解析的方式验证,否则会造成博客访问中断),这里我使用了 DNS 的方式进行获取:$ ./certbot-auto certonly --manual  --preferred-challenges=dns  --email [email protected] --server https://acme-v02.api.letsencrypt.org/directory --agree-tos -d nova.moe
之后会看到一个修改域名 TXT 记录的要求,类似如下:
 

Please deploy a DNS TXT record under the name _acme-challenge.nova.moe with the following value: J50GNXkhGmKCfn-0LQJcknVGtPEAQ_U_WajcLXgqWqo
 
 
 
此时我们只需要做一个 _acme-challenge 的 TXT 解析,内容为上述的 J50G...qo 即可。

如果没有遇到的问题的话我们就可以看到生成好的证书信息,类似如下:
 IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/nova.moe/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/nova.moe/privkey.pem
 
此时通过任何你喜欢的方式把 fullchain.pem 和 privkey.pem 下载到自己本地。

创建 Storage 桶,配置权限,导入文件
创建 Storage 桶

新建一个 Storage 容器,名称就是你希望的域名
 
 

 
 
 
配置权限

由于是对外提供内容的网站,我们需要把 Public Access 设置为 Public 并且为网站配置优化,具体方法如下:

 
 
 
 
 
 
点击最右边的选项,选择 Edit bucket permissions,添加一个 allUsers 账户,权限为 Storage Object Viewer

还是那个选项,选择 Edit website configuration,按照如下填入 index.html 和你的站点 404 页面(比如我的就是 404.html)
 
 

 
 
 
 
导入文件

注意,这里不要参考 《挂载 Google Storage 到 VPS 文件系统》,挂载到本地目录后上传,因为这样会导致文件的 meta 信息错误,导致本来该渲染为图片的地方变成了 octec-stream,本来该是网页的地方变成了 octec-stream ,本来… 然后访问任何页面都是弹出一个下载框了。

正确方法是使用 gsutil 来上传,语法如下:$ gsutil cp -r dir gs://my-bucket其中 dir 就是源目录,假设我的博客放在 /var/www/nova.moe/ 目录下 ,my-bucket 是目标 Storage 桶地址,比如我的就是 gs://nova.moe,整理一下就是:$ gsutil /var/www/nova.moe/* -r dir gs://www.yourdomain.com
可能有同学想到这里如果用 gsutil rsync 的话会不会更好一些,毕竟有增量同步之类的。

不是这样的,这样做的话即不能保留 meta 信息,也不会增量同步,相关描述如下:

Note that by default, the gsutil rsync command does not copy the ACLs of objects being synchronized and instead will use the default bucket ACL (see gsutil help defacl).

The gsutil rsync command copies changed files in their entirety and does not employ the rsync delta-transfer algorithm to transfer portions of a changed file. This is because cloud objects are immutable and no facility exists to read partial cloud object checksums or perform partial overwrites.
 
 
 
设置 Load Balancer

创建一个 HTTP/HTTPS 的 Load Balancer,Backend 创建一个 Backend Bucket,选择刚刚创建的 Storage 桶并勾选 Enable Cloud CDN:

 
 
 
Frontend 那一块选择 HTTPS:
 

 
 
然后导入 SSL 证书,其中 Public Key 和 Chain 全部上传 fullchain.pem, Private Key 就上传 privkey.pem :
 

 
 
 
创建好了之后有一个 Overview,类似如下:
 

 
 
延迟对比

GitHub Pages

 
 
Google Cloud Platform + Google CDN
 

 
 
已知问题 / 缺陷

这样子做的话,每次更新站点的同步也是一个问题,尤其是对于像我这样的 Hexo 用户而言,本地不想安装 SDK,传完文件后手动上服务器 gsutil cp 会很麻烦。

Google Cloud Platform 的 Load Balancer 并不能做 Force SSL,也就是说如果在 HTTPS 只选择了 443 端口的话,用户未添加 https:// 前缀的情况下访问的返回会是 404,如果同时也添加了 80 端口的话,直接访问也不会自动跳转到 https 上面。

一个比较大众化的解决方案是开一个 Compute instance 监听 80 端口专门用来做 SSL 重定向,但这样便失去了便捷性同时也会导致价格无意义地升高(无脑猜测 Google 团队到现在还不提供这个功能是有一定动机的,关于这个的 issue tracker:Redirect all HTTP traffic to HTTPS when using the HTTP(S) Load Balancer 从 15 年到现在还没有一个正式的答复),另一个思路是将域名加入 Preload List,但是现在的网站结构似乎并不能上 List,目前我正在寻找一个更加可靠的解决方案并不定期更新本文,相关更新会优先在 Twitter 上通知,欢迎关注。

2018-08-16 更新:最终我还是选择了新建一个 Compute instance 的方式解决(可以参考:利用 GCE 建立一个 Anycast 网络,超快的香港节点,Google Cloud CDN),Nginx 配置中稍微需要注意一下,Google CDN 会给后端传一个 X-Forwarded-Proto ,鉴于 Google CDN 的 SSL 只到边缘服务器就截止了(其实还是一个 Half-baked SSL),所以后端 Nginx 还是监听在 80 端口的,如果需要 SSL 重定向的话,需要加入以下内容:
 if ($http_x_forwarded_proto = "http") {
return 301 https://$host$request_uri;
}
 Google Load Balancer

我们知道,业界 Load Balancer 一般有以下实现方案:

一个 Anycast IP(比如 Google LB)
一个普通 IP(比如 Ucloud LB)
一个 CNAME 分区解析(比如 AWS ELB)

且不讨论 CNAME 那个看上去像是一个没钱 Anycast 的解决方案,而且如果用给 APEX 解析的话,在没有特殊加成(APEX FLATTEN)的情况会把 MX 记录炸穿(然后你就无法收邮件了),前者看上去是一个比较用户友好的方式,因为你只需要 A 记录到一个 IP 就可以了,绿色无害。

GFE

在了解 Google LB 之前,我们需要了解一个名词——GFE,感谢 Snowden 的 PPT,我们可以有一个直观的图示:

 

 
 
 
所有到 Google 的流量会在 GFE 上 SSL Offload(应该叫 SSL 卸载?),并且后端全部是在 Google 内网内以 HTTP 的方式进行传输。

在 Google Infrastructure Security Design Overview 中,我们也可以看到:

When a service wants to make itself available on the Internet, it can register itself with an infrastructure service called the Google Front End (GFE). The GFE ensures that all TLS connections are terminated using correct certificates and following best practices such as supporting perfect forward secrecy.


Google LB 也是一样,使用 GFE 作为面相用户的前端,将 SSL 流量在 GFE 上终结,然后以 HTTP 的方式回到后端的 Service 上。

使用一个统一的入口好处有很多,比如 GCP 就提供了一个统一的位置修改 SSL Policy:
 

 
可以自己选择心水的 Cipher Suite 和最低 TLS 版本等,和 Cloudflare 差不多(但是要让 Ucloud LB 做到这一点似乎就太困难了,他们基于 HAProxy 搞的 ULB 到本文发布时还不支持 TLS 1.3,而且要改 Cipher Suite 需要提工单)。

Premium IP

GCP 上的 IP 分为两种,一种是 Premium ,一种是 Standard,默认是前者,Google LB 也只能用 Premium。

Premium 使用的是冷土豆路由,所发送的数据包会保持在 Google 的内网内,并且在尽可能靠近用户的 PoP 离开。
 

 
 
 
  view all
大家好,我是新西兰软件开发公司local fern的程序员David,最近因工作需要,需要将客户的网站提高访问速度,用到了 Google Cloud Platform的cdn。
 
如果更近一步,除了新西兰本地外,想要让大陆地区访问速度更加快一些的话,我们可以考虑将站点内容放在 Google Cloud Platform 的 Storage 中,并且使用 Google CDN 进行全网加速(主要是因为国内大部分线路可以不绕路使用到香港边缘节点).

本文假设:

你有 Google Cloud Platform 账户,并懂得一些基本操作
在自己的机器上安装了 Google Cloud SDK,如果没有的话,参考 《挂载 Google Storage 到 VPS 文件系统》
账户中已经验证好了自己的域名,如果没有的话,参考 Domain ownership verification
获取 SSL 证书
除非希望托管一个 HTTP 的网站,否则一个证书是必不可少的,Google 不会帮你自动完成这一步。

有多种方式可以获取一个 SSL 证书,如果目前手头没有的话,我们通过 Let’s Encrypt 申请一个好了,首先获取 certbot:
$ git clone https://github.com/certbot/certbot.git
$ cd certbot

由于我自己的一些原因(在迁移前域名解析到 GitHub Pages 上的,不能通过改变解析的方式验证,否则会造成博客访问中断),这里我使用了 DNS 的方式进行获取:
$ ./certbot-auto certonly --manual  --preferred-challenges=dns  --email [email protected] --server https://acme-v02.api.letsencrypt.org/directory --agree-tos -d nova.moe

之后会看到一个修改域名 TXT 记录的要求,类似如下:
 

Please deploy a DNS TXT record under the name _acme-challenge.nova.moe with the following value: J50GNXkhGmKCfn-0LQJcknVGtPEAQ_U_WajcLXgqWqo
 
 
 
此时我们只需要做一个 _acme-challenge 的 TXT 解析,内容为上述的 J50G...qo 即可。

如果没有遇到的问题的话我们就可以看到生成好的证书信息,类似如下:
 
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/nova.moe/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/nova.moe/privkey.pem

 
此时通过任何你喜欢的方式把 fullchain.pem 和 privkey.pem 下载到自己本地。

创建 Storage 桶,配置权限,导入文件
创建 Storage 桶

新建一个 Storage 容器,名称就是你希望的域名
 
 

 
 
 
配置权限

由于是对外提供内容的网站,我们需要把 Public Access 设置为 Public 并且为网站配置优化,具体方法如下:

 
 
 
 
 
 
点击最右边的选项,选择 Edit bucket permissions,添加一个 allUsers 账户,权限为 Storage Object Viewer

还是那个选项,选择 Edit website configuration,按照如下填入 index.html 和你的站点 404 页面(比如我的就是 404.html)
 
 

 
 
 
 
导入文件

注意,这里不要参考 《挂载 Google Storage 到 VPS 文件系统》,挂载到本地目录后上传,因为这样会导致文件的 meta 信息错误,导致本来该渲染为图片的地方变成了 octec-stream,本来该是网页的地方变成了 octec-stream ,本来… 然后访问任何页面都是弹出一个下载框了。

正确方法是使用 gsutil 来上传,语法如下:
$ gsutil cp -r dir gs://my-bucket
其中 dir 就是源目录,假设我的博客放在 /var/www/nova.moe/ 目录下 ,my-bucket 是目标 Storage 桶地址,比如我的就是 gs://nova.moe,整理一下就是:
$ gsutil /var/www/nova.moe/* -r dir gs://www.yourdomain.com

可能有同学想到这里如果用 gsutil rsync 的话会不会更好一些,毕竟有增量同步之类的。

不是这样的,这样做的话即不能保留 meta 信息,也不会增量同步,相关描述如下:

Note that by default, the gsutil rsync command does not copy the ACLs of objects being synchronized and instead will use the default bucket ACL (see gsutil help defacl).

The gsutil rsync command copies changed files in their entirety and does not employ the rsync delta-transfer algorithm to transfer portions of a changed file. This is because cloud objects are immutable and no facility exists to read partial cloud object checksums or perform partial overwrites.
 
 
 
设置 Load Balancer

创建一个 HTTP/HTTPS 的 Load Balancer,Backend 创建一个 Backend Bucket,选择刚刚创建的 Storage 桶并勾选 Enable Cloud CDN:

 
 
 
Frontend 那一块选择 HTTPS:
 

 
 
然后导入 SSL 证书,其中 Public Key 和 Chain 全部上传 fullchain.pem, Private Key 就上传 privkey.pem :
 

 
 
 
创建好了之后有一个 Overview,类似如下:
 

 
 
延迟对比

GitHub Pages

 
 
Google Cloud Platform + Google CDN
 

 
 
已知问题 / 缺陷

这样子做的话,每次更新站点的同步也是一个问题,尤其是对于像我这样的 Hexo 用户而言,本地不想安装 SDK,传完文件后手动上服务器 gsutil cp 会很麻烦。

Google Cloud Platform 的 Load Balancer 并不能做 Force SSL,也就是说如果在 HTTPS 只选择了 443 端口的话,用户未添加 https:// 前缀的情况下访问的返回会是 404,如果同时也添加了 80 端口的话,直接访问也不会自动跳转到 https 上面。

一个比较大众化的解决方案是开一个 Compute instance 监听 80 端口专门用来做 SSL 重定向,但这样便失去了便捷性同时也会导致价格无意义地升高(无脑猜测 Google 团队到现在还不提供这个功能是有一定动机的,关于这个的 issue tracker:Redirect all HTTP traffic to HTTPS when using the HTTP(S) Load Balancer 从 15 年到现在还没有一个正式的答复),另一个思路是将域名加入 Preload List,但是现在的网站结构似乎并不能上 List,目前我正在寻找一个更加可靠的解决方案并不定期更新本文,相关更新会优先在 Twitter 上通知,欢迎关注。

2018-08-16 更新:最终我还是选择了新建一个 Compute instance 的方式解决(可以参考:利用 GCE 建立一个 Anycast 网络,超快的香港节点,Google Cloud CDN),Nginx 配置中稍微需要注意一下,Google CDN 会给后端传一个 X-Forwarded-Proto ,鉴于 Google CDN 的 SSL 只到边缘服务器就截止了(其实还是一个 Half-baked SSL),所以后端 Nginx 还是监听在 80 端口的,如果需要 SSL 重定向的话,需要加入以下内容:
 
if ($http_x_forwarded_proto = "http") {
return 301 https://$host$request_uri;
}

 Google Load Balancer

我们知道,业界 Load Balancer 一般有以下实现方案:

一个 Anycast IP(比如 Google LB)
一个普通 IP(比如 Ucloud LB)
一个 CNAME 分区解析(比如 AWS ELB)

且不讨论 CNAME 那个看上去像是一个没钱 Anycast 的解决方案,而且如果用给 APEX 解析的话,在没有特殊加成(APEX FLATTEN)的情况会把 MX 记录炸穿(然后你就无法收邮件了),前者看上去是一个比较用户友好的方式,因为你只需要 A 记录到一个 IP 就可以了,绿色无害。

GFE

在了解 Google LB 之前,我们需要了解一个名词——GFE,感谢 Snowden 的 PPT,我们可以有一个直观的图示:

 

 
 
 
所有到 Google 的流量会在 GFE 上 SSL Offload(应该叫 SSL 卸载?),并且后端全部是在 Google 内网内以 HTTP 的方式进行传输。

在 Google Infrastructure Security Design Overview 中,我们也可以看到:


When a service wants to make itself available on the Internet, it can register itself with an infrastructure service called the Google Front End (GFE). The GFE ensures that all TLS connections are terminated using correct certificates and following best practices such as supporting perfect forward secrecy.



Google LB 也是一样,使用 GFE 作为面相用户的前端,将 SSL 流量在 GFE 上终结,然后以 HTTP 的方式回到后端的 Service 上。

使用一个统一的入口好处有很多,比如 GCP 就提供了一个统一的位置修改 SSL Policy:
 

 
可以自己选择心水的 Cipher Suite 和最低 TLS 版本等,和 Cloudflare 差不多(但是要让 Ucloud LB 做到这一点似乎就太困难了,他们基于 HAProxy 搞的 ULB 到本文发布时还不支持 TLS 1.3,而且要改 Cipher Suite 需要提工单)。

Premium IP

GCP 上的 IP 分为两种,一种是 Premium ,一种是 Standard,默认是前者,Google LB 也只能用 Premium。

Premium 使用的是冷土豆路由,所发送的数据包会保持在 Google 的内网内,并且在尽可能靠近用户的 PoP 离开。
 

 
 
 
 
596
views

新西兰电商网站开发公司|我们的后端工程师David总结的独立电商购物网站整合支付接口的经验,如何让大陆的买家在你的网站上通过微信支付和支付宝付款

Marketplacefull stack developer Kevin wrote the post • 0 comments • 596 views • 2020-04-05 12:56 • added this tag no more than 24h

大家好,我是新西兰软件开发公司local fern的程序员David,最近因工作需要,有机会接触到 Stripe 的工作流程,事情很简单,对于优秀的服务,我们应该付出使用他们的成本(这样他们可以继续提供优质的服务),对于商户来说收钱就是一个比较有意思的部分了,鉴于大多数网友都是付钱,本文决定分享一下 Stripe 整合支付宝来收钱的方法,且本文不是网上很多出现的那种引用 checkout.js 的过期的方法(许多人都互相转来转去,看了一圈下来都是这个),而是使用 Stripe.js 来完成。
 

Stripe 目前收款方式有两种,简单来说,我们分为 Easy 难度和 Hard 难度,前者只支持信用卡,储蓄卡和 Apple Pay,而后者则支持多种支付方式,最终的效果图如下:


Easy 模式——使用 「Checkout」
Easy 模式即使用他们写好的页面,被称为「Checkout」,对于商户来说需要在后台定义好产品(Products),生成 sku 后写一个按钮出发脚本自动跳转过去,页面上需要写的内容如下:<!-- Load Stripe.js on your website. -->
<script src="https://js.stripe.com/v3"></script>
<!-- Create a button that your customers click to complete their purchase. Customize the styling to suit your branding. -->
<button
style="background-color:#6772E5;color:#FFF;padding:8px 12px;border:0;border-radius:4px;font-size:1em"
id="checkout-button-sku_xxxxxxxxxxx"
role="link"
>
Checkout
</button>
<div id="error-message"></div>
<script>
(function() {
var stripe = Stripe('pk_test_xxxxxxxxxxxx');
var checkoutButton = document.getElementById('checkout-button-sku_G40GQYkIX4a8c4');
checkoutButton.addEventListener('click', function () {
// When the customer clicks on the button, redirect
// them to Checkout.
stripe.redirectToCheckout({
items: [{sku: 'sku_xxxxxxxxxxx', quantity: 1}],
// Do not rely on the redirect to the successUrl for fulfilling
// purchases, customers may not always reach the success_url after
// a successful payment.
// Instead use one of the strategies described in
// https://stripe.com/docs/paymen ... lment
successUrl: 'https://xxx.xxx.xx/success',
cancelUrl: 'https://xxx.xxx.xx/canceled',
})
.then(function (result) {
if (result.error) {
// If `redirectToCheckout` fails due to a browser or network
// error, display the localized error message to your customer.
var displayError = document.getElementById('error-message');
displayError.textContent = result.error.message;
}
});
});
})();
</script>

这样在用户点了按钮之后就会出现一个 Stripe 的支付页面:


这样就可以用了,用户在付款完成之后就会跳转回到 successUrl,同时 Stripe 可以给你预先定义好的接口(WebHook)发一个 POST 请求告知,大致逻辑如下(其实官方有示范):\Stripe\Stripe::setApiKey('sk_test_xxxxxxxxxxxxxx');

// You can find your endpoint's secret in your webhook settings
$endpoint_secret = 'whsec_xxxxxxxxxxxxxxx';

$payload = @file_get_contents('php://input');
$sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'];
$event = null;

try {
$event = \Stripe\Webhook::constructEvent(
$payload, $sig_header, $endpoint_secret
);
} catch(\UnexpectedValueException $e) {
// Invalid payload
http_response_code(400);
exit();
} catch(\Stripe\Exception\SignatureVerificationException $e) {
// Invalid signature
http_response_code(400);
exit();
}

// Handle the checkout.session.completed event
if ($event->type == 'checkout.session.completed') {
$session = $event->data->object;
// 授权用户
$target_customer = \Stripe\Customer::retrieve($session['customer']);
$target_email = $target_customer['email'];
// 然后这里自己根据 email 找到对应用户完成接下来的步骤,比如把文件通过邮件发给用户,给用户头像加个 Buff 啥的~
}


这样就可以获取到用户的信息并且给用户提供/升级服务了,很方便是不是?
不过呢,「Checkout」只支持卡和 Apple Pay,对于喜欢见到付钱就想扫一扫的用户来说并不友好,所以我们需要使用一些别的方法。
Hard 模式——使用「STRIPE ELEMENTS」
为了照顾没有信用卡,遇见码就开始掏手机准备打开或绿或蓝应用准备开始扫一扫的用户来说,我们需要加入支付宝的支持功能。
首先确认你的账户中 Alipay 是连接上并且处于激活状态的,没有这一点等于没戏(也就不用继续往下看了)。


如果你的 Stripe 已经连接上了支付宝,接下来我们就可以开始整合了。
首先我们明白一下对于商户来说,逻辑是怎么样的:


首先由于 Stripe 并不是原生支持支付宝,所以所有这种非信用卡交易都被挂了称为「Source」的东西下,可以理解为一个插件或者一个临时的钱包,以下一段是具体的逻辑,请仔细阅读:
当用户需要付款的时候,用户会先通过 JS 创建一个 「Source」对象,并指定类型为「Alipay」,这个时候 Stripe.js 会带领用户去支付宝的付款页面进行支付,如果付款成功了,那么这个「Source」的状态会从 charge.pending 变成 source.chargeable ,可以理解为用户给临时钱包付了钱,在有了这个状态之后我们可以调用 Stripe 对这个 Source 扣款(Charge),把临时钱包的钱扣到自己 Stripe 账户上,然后就完成了付款的过程。
用户逻辑
我们先来看用户的逻辑部分:
用户的逻辑是,在对应的购买页面上应该有一个 Button,上面写上「立即购买」,这样用户只要一摸那个按钮,就可以看到支付宝的付款页面了,为了满足这个需要,我们需要这么做,在对应的页面上放个 Button:<button id="checkout-button">
立即购买
</button>

然后引用 stripe.js 并写一点 JS 来完成接下来的事情:<script src="https://js.stripe.com/v3/"></script>
<script type="text/javascript">
(function() {
var stripe = Stripe('pk_xxxxxxxxxxxxxx');
var checkout-button = document.getElementById('checkout-button');
checkout-button.addEventListener('click', function () {
stripe.createSource({
type: 'alipay',
amount: 1988,
currency: 'hkd',
// 这里你需要渲染出一些用户的信息,不然后期没法知道是谁在付钱
owner: {
email: '{$user_email}',
},
redirect: {
return_url: 'https://xxx.xxx.xx/buy',
},
}).then(function(result) {
window.location.replace(result.source.redirect.url);
});
});
})();
</script>
其中,owner 和 owner 下的 email 建议填写,不然付款后可能不好找到究竟是哪个用户付了钱,如果正巧你们不用 email 来标识用户,那也可以写点别的,对于 owner 来说有以下字段可供选择:
  "owner": {
"address": null,
"email": "[email protected]",
"name": null,
"phone": null,
"verified_address": null,
"verified_email": null,
"verified_name": null,
"verified_phone": null
},
此外,如果你还希望在 Source 中包含一些其他的内容的话,可以自由地使用 metadata ,并在内部包含一系列键值对。由于 createSource 执行完成后会返回一个包含 Source 对象,类似如下:{
"id": "src_16xhynE8WzK49JbAs9M21jaR",
"object": "source",
"amount": 1099,
"client_secret": "src_client_secret_UfwvW2WHpZ0s3QEn9g5x7waU",
"created": 1445277809,
"currency": "usd",
"flow": "redirect",
"livemode": true,
"owner": {
"address": null,
"email": null,
"name": "null",
"phone": null,
"verified_address": null,
"verified_email": null,
"verified_name": "null",
"verified_phone": null
},
"redirect": {
"return_url": "https://shop.example.com/crtA6B28E1",
"status": "pending",
"url": "https://hooks.stripe.com/redir ... ot%3B
},
"statement_descriptor": null,
"status": "pending",
"type": "alipay",
"usage": "single_use",
"alipay": {
"statement_descriptor": null,
"native_url": null
}
}
其中的 redirect 只要访问了就会自动被 Stripe 跳转到支付宝家的支付页面上,所以我们最后会有一行:
window.location.replace(result.source.redirect.url);
将用户跳转过去,然后用户扫码付钱:


用户这边的事情就结束了。
服务器逻辑
用户的事情结束了,服务器端就需要开始处理用户的请求了,一个简单的方法如下,在用户付款完成后 Stripe 会跳转回我们 JS 中定义的 return_url 并附带一些参数,类似如下:https://xxx.xxx.xx/buy?client_secret=src_client_secret_xxxxxxxxx&source=src_xxxxxxxxx

这个时候我们可以通过服务端来解析 src_xxxxxxxxx 得知是谁在付钱,并完成后续的操作:\Stripe\Stripe::setApiKey('sk_xxxxxxxxxxxxxx');

// 获取 URL 中 source 字段
$source_id = filter_input(INPUT_GET, 'source', FILTER_SANITIZE_URL);
$source_object = \Stripe\Source::retrieve($source_id);

// 先确认一下用户付了钱,别有 Object 就直接开始整...
$status = $source_object->redirect->status;
if($status == "failed")
{
// 如果用户没有付钱,我们该怎么做?
}
else {
// 从临时钱包从把钱扣了~
\Stripe\Charge::create([
'amount' => 1988,
'currency' => 'hkd',
'source' => $source_id,
]);
// 有了 Object 之后我们可以提取出对应的用户邮件地址或者别的信息,比如邮件地址可以这样提取
$user_email = $source_object->owner->email;
// 然后这里自己根据 email 找到对应用户完成接下来的步骤,比如把文件通过邮件发给用户,给用户头像加个 Buff 啥的~
}
顺便可以登录 Stripe 后台看看~


微信实现

其实也非常的简单,只需要将上一步的type改为wechat,同时返回source中的source.wechat.qr_code_url转为二维码就好了
 
var wechatCallback = function (source) {
generateQRCode(source.wechat.qr_code_url);
}
function generateQRCode(value) {
var qrEle = document.getElementById("qrcode");
var qrcode = new QRCode(qrEle, {
width: 100,
height: 100
});
qrcode.makeCode(value);
qrEle.style.display = 'inline-block';
}二维码出来后, 扫码就会得到如下结果
 

 
不过这种方法只是说可以用而已,最好的方法可以参考 Best Practices for Using Sources 来接受 Webhook 多次验证,但这个就不在本文的范围内了。

由于是第一次接触支付领域,上述步骤中可能还是会有不少坑或者啥的(所以别直接在生产环境照抄,写完之后一定要多 Review 几遍逻辑漏洞),不过这个至少是一个可用最小模型了,还有不少可以改进的地方,比如浏览器端的函数其实可以异步拉起,这样可以在网页上弄一个 Modal 弹窗,看上去更加用户友好一些。
 
 
补充说明(04/06/2020):
 
关于注册 Stripe 账号

和注册支付宝账号一个道理,首先注册账号,然后绑定自己银行卡,BUT, 就像前面提到的,不支持中国,所以就算注册成功,也没法激活,也就没法收款。

 
 
 
对于中国商家怎么办呢,我能想到的就只有这3个办法:

自己去支持国家去办理张银行卡
使用国外的朋友银行卡
使用Atlas

对于James来说,因为他是新西兰kiwi,所以他可以创建他的主账号,然后添加我的stripe账号到他team memeber账号列表中,这样我就可以访问他账户下所有开发者需要的权限。邀请成功后,Dashboard页面

 

 
Stripe.js & Elements

当然对于如果你觉得Checkout的方式集成度太高,不够灵活,那Stripe.js是你最好的选择。

Stripe.js其实就是客户端的一个JS核心类库,Elements是它的UI类库,其实上面的Checkout代码就是Stripe使用两者给我们封装好了的,避免我们直接接触敏感信息,但是其实质都是一样的,都是用来创建source。这里就直接贴出客户端的代码了(这里没有用到Elements做UI,因为就是一个按钮支付,太简单,所以没用到):var stripe = Stripe('pk_live_xxxx');

function alipay(amount) {
showLoading();
stripe.createSource({
type: 'alipay',
amount: parseInt(amount),
currency: 'gbp', // usd, eur,
redirect: {
return_url: 'https://xxx.eu/pay/result.html'
},
}).then(function (response) {
hideLoading();
if (response.error) {
alert(response.error.message);
}
else {
processStripeResponse(response.source);
}
});
}

function processStripeResponse(source) {
window.location.href = source.redirect.url;
}





  view all
大家好,我是新西兰软件开发公司local fern的程序员David,最近因工作需要,有机会接触到 Stripe 的工作流程,事情很简单,对于优秀的服务,我们应该付出使用他们的成本(这样他们可以继续提供优质的服务),对于商户来说收钱就是一个比较有意思的部分了,鉴于大多数网友都是付钱,本文决定分享一下 Stripe 整合支付宝来收钱的方法,且本文不是网上很多出现的那种引用 checkout.js 的过期的方法(许多人都互相转来转去,看了一圈下来都是这个),而是使用 Stripe.js 来完成。
 

Stripe 目前收款方式有两种,简单来说,我们分为 Easy 难度和 Hard 难度,前者只支持信用卡,储蓄卡和 Apple Pay,而后者则支持多种支付方式,最终的效果图如下:


Easy 模式——使用 「Checkout」
Easy 模式即使用他们写好的页面,被称为「Checkout」,对于商户来说需要在后台定义好产品(Products),生成 sku 后写一个按钮出发脚本自动跳转过去,页面上需要写的内容如下:
<!-- Load Stripe.js on your website. -->
<script src="https://js.stripe.com/v3"></script>
<!-- Create a button that your customers click to complete their purchase. Customize the styling to suit your branding. -->
<button
style="background-color:#6772E5;color:#FFF;padding:8px 12px;border:0;border-radius:4px;font-size:1em"
id="checkout-button-sku_xxxxxxxxxxx"
role="link"
>
Checkout
</button>
<div id="error-message"></div>
<script>
(function() {
var stripe = Stripe('pk_test_xxxxxxxxxxxx');
var checkoutButton = document.getElementById('checkout-button-sku_G40GQYkIX4a8c4');
checkoutButton.addEventListener('click', function () {
// When the customer clicks on the button, redirect
// them to Checkout.
stripe.redirectToCheckout({
items: [{sku: 'sku_xxxxxxxxxxx', quantity: 1}],
// Do not rely on the redirect to the successUrl for fulfilling
// purchases, customers may not always reach the success_url after
// a successful payment.
// Instead use one of the strategies described in
// https://stripe.com/docs/paymen ... lment
successUrl: 'https://xxx.xxx.xx/success',
cancelUrl: 'https://xxx.xxx.xx/canceled',
})
.then(function (result) {
if (result.error) {
// If `redirectToCheckout` fails due to a browser or network
// error, display the localized error message to your customer.
var displayError = document.getElementById('error-message');
displayError.textContent = result.error.message;
}
});
});
})();
</script>


这样在用户点了按钮之后就会出现一个 Stripe 的支付页面:


这样就可以用了,用户在付款完成之后就会跳转回到 successUrl,同时 Stripe 可以给你预先定义好的接口(WebHook)发一个 POST 请求告知,大致逻辑如下(其实官方有示范):
\Stripe\Stripe::setApiKey('sk_test_xxxxxxxxxxxxxx');

// You can find your endpoint's secret in your webhook settings
$endpoint_secret = 'whsec_xxxxxxxxxxxxxxx';

$payload = @file_get_contents('php://input');
$sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'];
$event = null;

try {
$event = \Stripe\Webhook::constructEvent(
$payload, $sig_header, $endpoint_secret
);
} catch(\UnexpectedValueException $e) {
// Invalid payload
http_response_code(400);
exit();
} catch(\Stripe\Exception\SignatureVerificationException $e) {
// Invalid signature
http_response_code(400);
exit();
}

// Handle the checkout.session.completed event
if ($event->type == 'checkout.session.completed') {
$session = $event->data->object;
// 授权用户
$target_customer = \Stripe\Customer::retrieve($session['customer']);
$target_email = $target_customer['email'];
// 然后这里自己根据 email 找到对应用户完成接下来的步骤,比如把文件通过邮件发给用户,给用户头像加个 Buff 啥的~
}



这样就可以获取到用户的信息并且给用户提供/升级服务了,很方便是不是?
不过呢,「Checkout」只支持卡和 Apple Pay,对于喜欢见到付钱就想扫一扫的用户来说并不友好,所以我们需要使用一些别的方法。
Hard 模式——使用「STRIPE ELEMENTS」
为了照顾没有信用卡,遇见码就开始掏手机准备打开或绿或蓝应用准备开始扫一扫的用户来说,我们需要加入支付宝的支持功能。
首先确认你的账户中 Alipay 是连接上并且处于激活状态的,没有这一点等于没戏(也就不用继续往下看了)。


如果你的 Stripe 已经连接上了支付宝,接下来我们就可以开始整合了。
首先我们明白一下对于商户来说,逻辑是怎么样的:


首先由于 Stripe 并不是原生支持支付宝,所以所有这种非信用卡交易都被挂了称为「Source」的东西下,可以理解为一个插件或者一个临时的钱包,以下一段是具体的逻辑,请仔细阅读:
当用户需要付款的时候,用户会先通过 JS 创建一个 「Source」对象,并指定类型为「Alipay」,这个时候 Stripe.js 会带领用户去支付宝的付款页面进行支付,如果付款成功了,那么这个「Source」的状态会从 charge.pending 变成 source.chargeable ,可以理解为用户给临时钱包付了钱,在有了这个状态之后我们可以调用 Stripe 对这个 Source 扣款(Charge),把临时钱包的钱扣到自己 Stripe 账户上,然后就完成了付款的过程。
用户逻辑
我们先来看用户的逻辑部分:
用户的逻辑是,在对应的购买页面上应该有一个 Button,上面写上「立即购买」,这样用户只要一摸那个按钮,就可以看到支付宝的付款页面了,为了满足这个需要,我们需要这么做,在对应的页面上放个 Button:
<button id="checkout-button">
立即购买
</button>


然后引用 stripe.js 并写一点 JS 来完成接下来的事情:
<script src="https://js.stripe.com/v3/"></script>
<script type="text/javascript">
(function() {
var stripe = Stripe('pk_xxxxxxxxxxxxxx');
var checkout-button = document.getElementById('checkout-button');
checkout-button.addEventListener('click', function () {
stripe.createSource({
type: 'alipay',
amount: 1988,
currency: 'hkd',
// 这里你需要渲染出一些用户的信息,不然后期没法知道是谁在付钱
owner: {
email: '{$user_email}',
},
redirect: {
return_url: 'https://xxx.xxx.xx/buy',
},
}).then(function(result) {
window.location.replace(result.source.redirect.url);
});
});
})();
</script>

其中,owner 和 owner 下的 email 建议填写,不然付款后可能不好找到究竟是哪个用户付了钱,如果正巧你们不用 email 来标识用户,那也可以写点别的,对于 owner 来说有以下字段可供选择:
  
"owner": {
"address": null,
"email": "[email protected]",
"name": null,
"phone": null,
"verified_address": null,
"verified_email": null,
"verified_name": null,
"verified_phone": null
},

此外,如果你还希望在 Source 中包含一些其他的内容的话,可以自由地使用 metadata ,并在内部包含一系列键值对。由于 createSource 执行完成后会返回一个包含 Source 对象,类似如下:
{
"id": "src_16xhynE8WzK49JbAs9M21jaR",
"object": "source",
"amount": 1099,
"client_secret": "src_client_secret_UfwvW2WHpZ0s3QEn9g5x7waU",
"created": 1445277809,
"currency": "usd",
"flow": "redirect",
"livemode": true,
"owner": {
"address": null,
"email": null,
"name": "null",
"phone": null,
"verified_address": null,
"verified_email": null,
"verified_name": "null",
"verified_phone": null
},
"redirect": {
"return_url": "https://shop.example.com/crtA6B28E1",
"status": "pending",
"url": "https://hooks.stripe.com/redir ... ot%3B
},
"statement_descriptor": null,
"status": "pending",
"type": "alipay",
"usage": "single_use",
"alipay": {
"statement_descriptor": null,
"native_url": null
}
}

其中的 redirect 只要访问了就会自动被 Stripe 跳转到支付宝家的支付页面上,所以我们最后会有一行:
window.location.replace(result.source.redirect.url);
将用户跳转过去,然后用户扫码付钱:


用户这边的事情就结束了。
服务器逻辑
用户的事情结束了,服务器端就需要开始处理用户的请求了,一个简单的方法如下,在用户付款完成后 Stripe 会跳转回我们 JS 中定义的 return_url 并附带一些参数,类似如下:
https://xxx.xxx.xx/buy?client_secret=src_client_secret_xxxxxxxxx&source=src_xxxxxxxxx


这个时候我们可以通过服务端来解析 src_xxxxxxxxx 得知是谁在付钱,并完成后续的操作:
\Stripe\Stripe::setApiKey('sk_xxxxxxxxxxxxxx');

// 获取 URL 中 source 字段
$source_id = filter_input(INPUT_GET, 'source', FILTER_SANITIZE_URL);
$source_object = \Stripe\Source::retrieve($source_id);

// 先确认一下用户付了钱,别有 Object 就直接开始整...
$status = $source_object->redirect->status;
if($status == "failed")
{
// 如果用户没有付钱,我们该怎么做?
}
else {
// 从临时钱包从把钱扣了~
\Stripe\Charge::create([
'amount' => 1988,
'currency' => 'hkd',
'source' => $source_id,
]);
// 有了 Object 之后我们可以提取出对应的用户邮件地址或者别的信息,比如邮件地址可以这样提取
$user_email = $source_object->owner->email;
// 然后这里自己根据 email 找到对应用户完成接下来的步骤,比如把文件通过邮件发给用户,给用户头像加个 Buff 啥的~
}

顺便可以登录 Stripe 后台看看~


微信实现

其实也非常的简单,只需要将上一步的type改为wechat,同时返回source中的source.wechat.qr_code_url转为二维码就好了
 

var wechatCallback = function (source) {
generateQRCode(source.wechat.qr_code_url);
}
function generateQRCode(value) {
var qrEle = document.getElementById("qrcode");
var qrcode = new QRCode(qrEle, {
width: 100,
height: 100
});
qrcode.makeCode(value);
qrEle.style.display = 'inline-block';
}
二维码出来后, 扫码就会得到如下结果
 

 
不过这种方法只是说可以用而已,最好的方法可以参考 Best Practices for Using Sources 来接受 Webhook 多次验证,但这个就不在本文的范围内了。

由于是第一次接触支付领域,上述步骤中可能还是会有不少坑或者啥的(所以别直接在生产环境照抄,写完之后一定要多 Review 几遍逻辑漏洞),不过这个至少是一个可用最小模型了,还有不少可以改进的地方,比如浏览器端的函数其实可以异步拉起,这样可以在网页上弄一个 Modal 弹窗,看上去更加用户友好一些。
 
 
补充说明(04/06/2020):
 
关于注册 Stripe 账号

和注册支付宝账号一个道理,首先注册账号,然后绑定自己银行卡,BUT, 就像前面提到的,不支持中国,所以就算注册成功,也没法激活,也就没法收款。

 
 
 
对于中国商家怎么办呢,我能想到的就只有这3个办法:

自己去支持国家去办理张银行卡
使用国外的朋友银行卡
使用Atlas

对于James来说,因为他是新西兰kiwi,所以他可以创建他的主账号,然后添加我的stripe账号到他team memeber账号列表中,这样我就可以访问他账户下所有开发者需要的权限。邀请成功后,Dashboard页面

 

 
Stripe.js & Elements

当然对于如果你觉得Checkout的方式集成度太高,不够灵活,那Stripe.js是你最好的选择。

Stripe.js其实就是客户端的一个JS核心类库,Elements是它的UI类库,其实上面的Checkout代码就是Stripe使用两者给我们封装好了的,避免我们直接接触敏感信息,但是其实质都是一样的,都是用来创建source。这里就直接贴出客户端的代码了(这里没有用到Elements做UI,因为就是一个按钮支付,太简单,所以没用到):
var stripe = Stripe('pk_live_xxxx');

function alipay(amount) {
showLoading();
stripe.createSource({
type: 'alipay',
amount: parseInt(amount),
currency: 'gbp', // usd, eur,
redirect: {
return_url: 'https://xxx.eu/pay/result.html'
},
}).then(function (response) {
hideLoading();
if (response.error) {
alert(response.error.message);
}
else {
processStripeResponse(response.source);
}
});
}

function processStripeResponse(source) {
window.location.href = source.redirect.url;
}